code: def add_model(self, propname, model, regen_mode='normal', **kwargs):
          r
          if propname in kwargs.values():  # Prevent infinite loops of look-ups
              raise Exception(propname+' can\'t be both dependency and propname')
          # Add model and regen_mode to kwargs dictionary
          kwargs.update({'model': model, 'regen_mode': regen_mode})
          # Insepct model to extract arguments and default values
          if model.__defaults__:
              vals = list(inspect.getfullargspec(model).defaults)
              keys = inspect.getfullargspec(model).args[-len(vals):]
              for k, v in zip(keys, vals):  # Put defaults into kwargs
                  if k not in kwargs:  # Skip if argument was given in kwargs
                      kwargs.update({k: v})
          self.models[propname] = kwargs  # Store all keyword argumnents in model
          # Regenerate model values if necessary
          if regen_mode not in ['deferred']:
              self._regen(propname)
docs: r"""
          Adds a new model to the models dictionary (``object.models``)
  
          Parameters
          ----------
          propname : string
              The name of the property to be calculated by the model.
  
          model : function
              A reference (handle) to the function to be used.
  
          regen_mode : string
              Controls how/when the model is run (See Notes for more details).
              Options are:
  
              *'normal'* : The model is run directly upon being assiged, and
              also run every time ``regenerate_models`` is called.
  
              *'constant'* : The model is run directly upon being assigned, but
              is not called again, thus making it's data act like a constant.
              If, however, the data is deleted from the object it will be
              regenerated again.
  
              *'deferred'* Is not run upon being assigned, but is run the first
              time that ``regenerate_models`` is called.