Changeset 724257c in sasmodels


Ignore:
Timestamp:
Jun 29, 2017 9:55:24 AM (7 years ago)
Author:
Paul Kienzle <pkienzle@…>
Branches:
master, core_shell_microgels, costrafo411, magnetic_model, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
Children:
c11d09f, b139ee6, f2cbeb7, 997c9ca, 7cb1c36
Parents:
c935936
Message:

don't reload custom models in sasview unless the timestamp on the file has changed

Location:
sasmodels
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/modelinfo.py

    rbb4b509 r724257c  
    722722    parameters = make_parameter_table(getattr(kernel_module, 'parameters', [])) 
    723723    demo = expand_pars(parameters, getattr(kernel_module, 'demo', None)) 
    724     filename = abspath(kernel_module.__file__) 
     724    filename = abspath(kernel_module.__file__).replace('.pyc', '.py') 
    725725    kernel_id = splitext(basename(filename))[0] 
    726726    name = getattr(kernel_module, 'name', None) 
     
    729729 
    730730    info.id = kernel_id  # string used to load the kernel 
    731     info.filename = abspath(kernel_module.__file__) 
     731    info.filename = filename 
    732732    info.name = name 
    733733    info.title = getattr(kernel_module, 'title', name+" model") 
  • sasmodels/sasview_model.py

    r749a7d4 r724257c  
    1515import traceback 
    1616import logging 
    17 from os.path import basename, splitext 
     17from os.path import basename, splitext, abspath, getmtime 
    1818import thread 
    1919 
     
    4040    pass 
    4141 
     42logger = logging.getLogger(__name__) 
     43 
    4244calculation_lock = thread.allocate_lock() 
    4345 
     46#: True if pre-existing plugins, with the old names and parameters, should 
     47#: continue to be supported. 
    4448SUPPORT_OLD_STYLE_PLUGINS = True 
     49 
     50# TODO: separate x_axis_label from multiplicity info 
     51MultiplicityInfo = collections.namedtuple( 
     52    'MultiplicityInfo', 
     53    ["number", "control", "choices", "x_axis_label"], 
     54) 
     55 
     56#: set of defined models (standard and custom) 
     57MODELS = {}  # type: Dict[str, SasviewModelType] 
     58#: custom model {path: model} mapping so we can check timestamps 
     59MODEL_BY_PATH = {}  # type: Dict[str, SasviewModelType] 
     60 
     61def find_model(modelname): 
     62    # type: (str) -> SasviewModelType 
     63    """ 
     64    Find a model by name.  If the model name ends in py, try loading it from 
     65    custom models, otherwise look for it in the list of builtin models. 
     66    """ 
     67    # TODO: used by sum/product model to load an existing model 
     68    # TODO: doesn't handle custom models properly 
     69    if modelname.endswith('.py'): 
     70        return load_custom_model(modelname) 
     71    elif modelname in MODELS: 
     72        return MODELS[modelname] 
     73    else: 
     74        raise ValueError("unknown model %r"%modelname) 
     75 
     76 
     77# TODO: figure out how to say that the return type is a subclass 
     78def load_standard_models(): 
     79    # type: () -> List[SasviewModelType] 
     80    """ 
     81    Load and return the list of predefined models. 
     82 
     83    If there is an error loading a model, then a traceback is logged and the 
     84    model is not returned. 
     85    """ 
     86    for name in core.list_models(): 
     87        try: 
     88            MODELS[name] = _make_standard_model(name) 
     89        except Exception: 
     90            logger.error(traceback.format_exc()) 
     91    if SUPPORT_OLD_STYLE_PLUGINS: 
     92        _register_old_models() 
     93 
     94    return list(MODELS.values()) 
     95 
     96 
     97def load_custom_model(path): 
     98    # type: (str) -> SasviewModelType 
     99    """ 
     100    Load a custom model given the model path. 
     101    """ 
     102    model = MODEL_BY_PATH.get(path, None) 
     103    if model is not None and model.timestamp == getmtime(path): 
     104        #logger.info("Model already loaded %s", path) 
     105        return model 
     106 
     107    #logger.info("Loading model %s", path) 
     108    kernel_module = custom.load_custom_kernel_module(path) 
     109    if hasattr(kernel_module, 'Model'): 
     110        model = kernel_module.Model 
     111        # Old style models do not set the name in the class attributes, so 
     112        # set it here; this name will be overridden when the object is created 
     113        # with an instance variable that has the same value. 
     114        if model.name == "": 
     115            model.name = splitext(basename(path))[0] 
     116        if not hasattr(model, 'filename'): 
     117            model.filename = abspath(kernel_module.__file__).replace('.pyc', '.py') 
     118        if not hasattr(model, 'id'): 
     119            model.id = splitext(basename(model.filename))[0] 
     120    else: 
     121        model_info = modelinfo.make_model_info(kernel_module) 
     122        model = _make_model_from_info(model_info) 
     123    model.timestamp = getmtime(path) 
     124 
     125    # If a model name already exists and we are loading a different model, 
     126    # use the model file name as the model name. 
     127    if model.name in MODELS and not model.filename == MODELS[model.name].filename: 
     128        _previous_name = model.name 
     129        model.name = model.id 
     130 
     131        # If the new model name is still in the model list (for instance, 
     132        # if we put a cylinder.py in our plug-in directory), then append 
     133        # an identifier. 
     134        if model.name in MODELS and not model.filename == MODELS[model.name].filename: 
     135            model.name = model.id + '_user' 
     136        logger.info("Model %s already exists: using %s [%s]", 
     137                    _previous_name, model.name, model.filename) 
     138 
     139    MODELS[model.name] = model 
     140    MODEL_BY_PATH[path] = model 
     141    return model 
     142 
     143 
     144def _make_standard_model(name): 
     145    # type: (str) -> SasviewModelType 
     146    """ 
     147    Load the sasview model defined by *name*. 
     148 
     149    *name* can be a standard model name or a path to a custom model. 
     150 
     151    Returns a class that can be used directly as a sasview model. 
     152    """ 
     153    kernel_module = generate.load_kernel_module(name) 
     154    model_info = modelinfo.make_model_info(kernel_module) 
     155    return _make_model_from_info(model_info) 
     156 
    45157 
    46158def _register_old_models(): 
     
    60172    import sas.models 
    61173    from sasmodels.conversion_table import CONVERSION_TABLE 
    62     for new_name, conversion in CONVERSION_TABLE.get((3,1,2), {}).items(): 
     174    for new_name, conversion in CONVERSION_TABLE.get((3, 1, 2), {}).items(): 
    63175        # CoreShellEllipsoidModel => core_shell_ellipsoid:1 
    64176        new_name = new_name.split(':')[0] 
     
    69181        setattr(sas.models, old_path, ConstructedModule) 
    70182        sys.modules[old_path] = ConstructedModule 
    71  
    72  
    73 # TODO: separate x_axis_label from multiplicity info 
    74 MultiplicityInfo = collections.namedtuple( 
    75     'MultiplicityInfo', 
    76     ["number", "control", "choices", "x_axis_label"], 
    77 ) 
    78  
    79 MODELS = {} 
    80 def find_model(modelname): 
    81     # type: (str) -> SasviewModelType 
    82     """ 
    83     Find a model by name.  If the model name ends in py, try loading it from 
    84     custom models, otherwise look for it in the list of builtin models. 
    85     """ 
    86     # TODO: used by sum/product model to load an existing model 
    87     # TODO: doesn't handle custom models properly 
    88     if modelname.endswith('.py'): 
    89         return load_custom_model(modelname) 
    90     elif modelname in MODELS: 
    91         return MODELS[modelname] 
    92     else: 
    93         raise ValueError("unknown model %r"%modelname) 
    94  
    95  
    96 # TODO: figure out how to say that the return type is a subclass 
    97 def load_standard_models(): 
    98     # type: () -> List[SasviewModelType] 
    99     """ 
    100     Load and return the list of predefined models. 
    101  
    102     If there is an error loading a model, then a traceback is logged and the 
    103     model is not returned. 
    104     """ 
    105     models = [] 
    106     for name in core.list_models(): 
    107         try: 
    108             MODELS[name] = _make_standard_model(name) 
    109             models.append(MODELS[name]) 
    110         except Exception: 
    111             logging.error(traceback.format_exc()) 
    112     if SUPPORT_OLD_STYLE_PLUGINS: 
    113         _register_old_models() 
    114  
    115     return models 
    116  
    117  
    118 def load_custom_model(path): 
    119     # type: (str) -> SasviewModelType 
    120     """ 
    121     Load a custom model given the model path. 
    122     """ 
    123     kernel_module = custom.load_custom_kernel_module(path) 
    124     try: 
    125         model = kernel_module.Model 
    126         # Old style models do not set the name in the class attributes, so 
    127         # set it here; this name will be overridden when the object is created 
    128         # with an instance variable that has the same value. 
    129         if model.name == "": 
    130             model.name = splitext(basename(path))[0] 
    131         if not hasattr(model, 'filename'): 
    132             model.filename = kernel_module.__file__ 
    133             # For old models, treat .pyc and .py files interchangeably. 
    134             # This is needed because of the Sum|Multi(p1,p2) types of models 
    135             # and the convoluted way in which they are created. 
    136             if model.filename.endswith(".py"): 
    137                 logging.info("Loading %s as .pyc", model.filename) 
    138                 model.filename = model.filename+'c' 
    139         if not hasattr(model, 'id'): 
    140             model.id = splitext(basename(model.filename))[0] 
    141     except AttributeError: 
    142         model_info = modelinfo.make_model_info(kernel_module) 
    143         model = _make_model_from_info(model_info) 
    144  
    145     # If a model name already exists and we are loading a different model, 
    146     # use the model file name as the model name. 
    147     if model.name in MODELS and not model.filename == MODELS[model.name].filename: 
    148         _previous_name = model.name 
    149         model.name = model.id 
    150          
    151         # If the new model name is still in the model list (for instance, 
    152         # if we put a cylinder.py in our plug-in directory), then append 
    153         # an identifier. 
    154         if model.name in MODELS and not model.filename == MODELS[model.name].filename: 
    155             model.name = model.id + '_user' 
    156         logging.info("Model %s already exists: using %s [%s]", _previous_name, model.name, model.filename) 
    157  
    158     MODELS[model.name] = model 
    159     return model 
    160  
    161  
    162 def _make_standard_model(name): 
    163     # type: (str) -> SasviewModelType 
    164     """ 
    165     Load the sasview model defined by *name*. 
    166  
    167     *name* can be a standard model name or a path to a custom model. 
    168  
    169     Returns a class that can be used directly as a sasview model. 
    170     """ 
    171     kernel_module = generate.load_kernel_module(name) 
    172     model_info = modelinfo.make_model_info(kernel_module) 
    173     return _make_model_from_info(model_info) 
    174183 
    175184 
     
    283292 
    284293    #: names of the orientation parameters in the order they appear 
    285     orientation_params = None # type: Sequence[str] 
     294    orientation_params = None # type: List[str] 
    286295    #: names of the magnetic parameters in the order they appear 
    287     magnetic_params = None    # type: Sequence[str] 
     296    magnetic_params = None    # type: List[str] 
    288297    #: names of the fittable parameters 
    289     fixed = None              # type: Sequence[str] 
     298    fixed = None              # type: List[str] 
    290299    # TODO: the attribute fixed is ill-named 
    291300 
     
    611620        ## to calculate_Iq 
    612621        #if calculation_lock.locked(): 
    613         #    logging.info("calculation waiting for another thread to complete") 
    614         #    logging.info("\n".join(traceback.format_stack())) 
     622        #    logger.info("calculation waiting for another thread to complete") 
     623        #    logger.info("\n".join(traceback.format_stack())) 
    615624 
    616625        with calculation_lock: 
Note: See TracChangeset for help on using the changeset viewer.