Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    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