def _build_model_new(cls, pool, cr): """ Instantiate a given model in the registry. This method creates or extends a "registry" class for the given model. This "registry" class carries inferred model metadata, and inherits (in the Python sense) from all classes that define the model, and possibly other registry classes. """ # Keep links to non-inherited constraints in cls; this is useful for # instance when exporting translations cls._local_constraints = cls.__dict__.get('_constraints', []) cls._local_sql_constraints = cls.__dict__.get('_sql_constraints', []) # determine inherited models parents = inherit_workflow_manager(cr, cls) parents = [parents] if isinstance(parents, str) else (parents or []) # determine the model's name name = cls._name or (len(parents) == 1 and parents[0]) or cls.__name__ # all models except 'base' implicitly inherit from 'base' if name != 'base': parents = list(parents) + ['base'] # create or retrieve the model's class if name in parents: if name not in pool: raise TypeError("Model %r does not exist in registry." % name) ModelClass = pool[name] ModelClass._build_model_check_base(cls) check_parent = ModelClass._build_model_check_parent else: ModelClass = type( name, (BaseModel, ), { '_name': name, '_register': False, '_original_module': cls._module, '_inherit_children': OrderedSet(), # names of children models '_inherits_children': set(), # names of children models '_fields': {}, # populated in _setup_base() }) check_parent = cls._build_model_check_parent # determine all the classes the model should inherit from bases = LastOrderedSet([cls]) for parent in parents: if parent not in pool: raise TypeError("Model %r inherits from non-existing model %r." % (name, parent)) parent_class = pool[parent] if parent == name: for base in parent_class.__bases__: bases.add(base) else: check_parent(cls, parent_class) bases.add(parent_class) parent_class._inherit_children.add(name) ModelClass.__bases__ = tuple(bases) # determine the attributes of the model's class ModelClass._build_model_attributes(pool) check_pg_name(ModelClass._table) # Transience if ModelClass._transient: assert ModelClass._log_access, \ "TransientModels must have log_access turned on, " \ "in order to implement their access rights policy" # link the class to the registry, and update the registry ModelClass.pool = pool pool[name] = ModelClass # backward compatibility: instantiate the model, and initialize it model = object.__new__(ModelClass) model.__init__(pool, cr) return ModelClass
def _build_component(cls, registry): """ Instantiate a given Component in the components registry. This method is called at the end of the Odoo's registry build. The caller is :meth:`component.builder.ComponentBuilder.load_components`. It generates new classes, which will be the Component classes we will be using. The new classes are generated following the inheritance of ``_inherit``. It ensures that the ``__bases__`` of the generated Component classes follow the ``_inherit`` chain. Once a Component class is created, it adds it in the Component Registry (:class:`ComponentRegistry`), so it will be available for lookups. At the end of new class creation, a hook method :meth:`_complete_component_build` is called, so you can customize further the created components. An example can be found in :meth:`odoo.addons.connector.components.mapper.Mapper._complete_component_build` The following code is roughly the same than the Odoo's one for building Models. """ # In the simplest case, the component's registry class inherits from # cls and the other classes that define the component in a flat # hierarchy. The registry contains the instance ``component`` (on the # left). Its class, ``ComponentClass``, carries inferred metadata that # is shared between all the component's instances for this registry # only. # # class A1(Component): Component # _name = 'a' / | \ # A3 A2 A1 # class A2(Component): \ | / # _inherit = 'a' ComponentClass # # class A3(Component): # _inherit = 'a' # # When a component is extended by '_inherit', its base classes are # modified to include the current class and the other inherited # component classes. # Note that we actually inherit from other ``ComponentClass``, so that # extensions to an inherited component are immediately visible in the # current component class, like in the following example: # # class A1(Component): # _name = 'a' Component # / / \ \ # class B1(Component): / A2 A1 \ # _name = 'b' / \ / \ # B2 ComponentA B1 # class B2(Component): \ | / # _name = 'b' \ | / # _inherit = ['b', 'a'] \ | / # ComponentB # class A2(Component): # _inherit = 'a' # determine inherited components parents = cls._inherit if isinstance(parents, str): parents = [parents] elif parents is None: parents = [] if cls._name in registry and not parents: raise TypeError("Component %r (in class %r) already exists. " "Consider using _inherit instead of _name " "or using a different _name." % (cls._name, cls)) # determine the component's name name = cls._name or (len(parents) == 1 and parents[0]) if not name: raise TypeError("Component %r must have a _name" % cls) # all components except 'base' implicitly inherit from 'base' if name != "base": parents = list(parents) + ["base"] # create or retrieve the component's class if name in parents: if name not in registry: raise TypeError("Component %r does not exist in registry." % name) ComponentClass = registry[name] ComponentClass._build_component_check_base(cls) check_parent = ComponentClass._build_component_check_parent else: ComponentClass = type( name, (AbstractComponent, ), { "_name": name, "_register": False, # names of children component "_inherit_children": OrderedSet(), }, ) check_parent = cls._build_component_check_parent # determine all the classes the component should inherit from bases = LastOrderedSet([cls]) for parent in parents: if parent not in registry: raise TypeError( "Component %r inherits from non-existing component %r." % (name, parent)) parent_class = registry[parent] if parent == name: for base in parent_class.__bases__: bases.add(base) else: check_parent(cls, parent_class) bases.add(parent_class) parent_class._inherit_children.add(name) ComponentClass.__bases__ = tuple(bases) ComponentClass._complete_component_build() registry[name] = ComponentClass return ComponentClass
def _build_datamodel(cls, registry): """Instantiate a given Datamodel in the datamodels registry. This method is called at the end of the Odoo's registry build. The caller is :meth:`datamodel.builder.DatamodelBuilder.load_datamodels`. It generates new classes, which will be the Datamodel classes we will be using. The new classes are generated following the inheritance of ``_inherit``. It ensures that the ``__bases__`` of the generated Datamodel classes follow the ``_inherit`` chain. Once a Datamodel class is created, it adds it in the Datamodel Registry (:class:`DatamodelRegistry`), so it will be available for lookups. At the end of new class creation, a hook method :meth:`_complete_datamodel_build` is called, so you can customize further the created datamodels. The following code is roughly the same than the Odoo's one for building Models. """ # In the simplest case, the datamodel's registry class inherits from # cls and the other classes that define the datamodel in a flat # hierarchy. The registry contains the instance ``datamodel`` (on the # left). Its class, ``DatamodelClass``, carries inferred metadata that # is shared between all the datamodel's instances for this registry # only. # # class A1(Datamodel): Datamodel # _name = 'a' / | \ # A3 A2 A1 # class A2(Datamodel): \ | / # _inherit = 'a' DatamodelClass # # class A3(Datamodel): # _inherit = 'a' # # When a datamodel is extended by '_inherit', its base classes are # modified to include the current class and the other inherited # datamodel classes. # Note that we actually inherit from other ``DatamodelClass``, so that # extensions to an inherited datamodel are immediately visible in the # current datamodel class, like in the following example: # # class A1(Datamodel): # _name = 'a' Datamodel # / / \ \ # class B1(Datamodel): / A2 A1 \ # _name = 'b' / \ / \ # B2 DatamodelA B1 # class B2(Datamodel): \ | / # _name = 'b' \ | / # _inherit = ['b', 'a'] \ | / # DatamodelB # class A2(Datamodel): # _inherit = 'a' # determine inherited datamodels parents = cls._inherit if isinstance(parents, str): parents = [parents] elif parents is None: parents = [] if cls._name in registry and not parents: raise TypeError("Datamodel %r (in class %r) already exists. " "Consider using _inherit instead of _name " "or using a different _name." % (cls._name, cls)) # determine the datamodel's name name = cls._name or (len(parents) == 1 and parents[0]) if not name: raise TypeError("Datamodel %r must have a _name" % cls) # all datamodels except 'base' implicitly inherit from 'base' if name != "base": parents = list(parents) + ["base"] # create or retrieve the datamodel's class if name in parents: if name not in registry: raise TypeError("Datamodel %r does not exist in registry." % name) # determine all the classes the datamodel should inherit from bases = LastOrderedSet([cls]) for parent in parents: if parent not in registry: raise TypeError( "Datamodel %r inherits from non-existing datamodel %r." % (name, parent)) parent_class = registry[parent] if parent == name: for base in parent_class.__bases__: bases.add(base) else: bases.add(parent_class) parent_class._inherit_children.add(name) if name in parents: DatamodelClass = registry[name] # Add the new bases to the existing model since the class into # the registry could already be used into an inherit DatamodelClass.__bases__ = tuple(bases) # We must update the marshmallow schema on the existing datamodel # class to include those inherited parent_schemas = [] for parent in bases: if issubclass(parent, MarshmallowModel): parent_schemas.append(parent.__schema_class__) schema_class = type(name + "Schema", tuple(parent_schemas), {}) DatamodelClass.__schema_class__ = schema_class else: attrs = { "_name": name, "_register": False, # names of children datamodel "_inherit_children": OrderedSet(), } if name == "base": attrs["_registry"] = registry DatamodelClass = type(name, tuple(bases), attrs) setattr(DatamodelClass.__schema_class__, "_registry", registry) # noqa: B010 setattr(DatamodelClass.__schema_class__, "_datamodel_name", name) # noqa: B010 setattr(DatamodelClass.__schema_class__, "__make_object__", __make_object__) # noqa: B010 DatamodelClass._complete_datamodel_build() registry[name] = DatamodelClass return DatamodelClass