Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Basic inheritance not works while using dependency_injector library DeclarativeContainer in Python. Why?

It is known the Python have ability to create child classes and add methods into them. However when I inherit class from DeclarativeContainer it fails and I cannot understand why. This code works fine if I inherit from different classes. Please help to understand why inheritance not works as I expect in this case.

from dependency_injector import containers

class Container(containers.DeclarativeContainer):
    def printContainer(self):
        print(f'Hello from container!')

if __name__ == "__main__":
    container = Container()
    container.printContainer() # error here

The error, surprisingly, says my code dealing with DynamicContainer class, however i not use it but DeclarativeContainer. Actually I expected method to be called on a Container class:

AttributeError: 'DynamicContainer' object has no attribute 'printContainer'

Here some context. I am trying to make use of dependency_injector library instead of manually injecting dependencies. I got some errors and confusions and made as as simple as possible code example to understand what is going on.

like image 286
Pavlo Morozov Avatar asked Mar 25 '26 15:03

Pavlo Morozov


1 Answers

Please note that the dependency_injector documentation states:

The declarative container can not have any methods or any other attributes then providers.


Now let's find out the reason for the confusing error. According to the source code of dependency_injector, DeclarativeContainer.__new__ returns container which is an instance of the DynamicContainer class.

@six.add_metaclass(DeclarativeContainerMetaClass)
class DeclarativeContainer(Container):

    # omitted code

    instance_type = DynamicContainer
    """Type of container that is returned on instantiating declarative
    container.
    :type: type
    """

    # omitted code

    def __new__(cls, **overriding_providers):
        """Constructor.
        :return: Dynamic container with copy of all providers.
        :rtype: :py:class:`DynamicContainer`
        """
        container = cls.instance_type()

        # omitted code

        return container

Thus, when you create your Container object, you receive a DynamicContainer instance. You can verify it by checking the type and attributes of the object.

from dependency_injector import containers

class Container(containers.DeclarativeContainer):
    def printContainer(self):
        print(f'Hello from container!')

if __name__ == "__main__":
    container = Container()
    print(type(container))
    print(dir(container))

Outputs:

<class 'dependency_injector.containers.DynamicContainer'>
['__IS_CONTAINER__', '__class__', '__deepcopy__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'apply_container_providers_overridings', 'assign_parent', 'check_dependencies', 'declarative_parent', 'dependencies', 'from_json_schema', 'from_schema', 'from_yaml_schema', 'init_resources', 'is_auto_wiring_enabled', 'load_config', 'overridden', 'override', 'override_providers', 'parent', 'parent_name', 'provider_type', 'providers', 'reset_last_overriding', 'reset_override', 'reset_singletons', 'resolve_provider_name', 'set_provider', 'set_providers', 'shutdown_resources', 'traverse', 'unwire', 'wire', 'wired_to_modules', 'wired_to_packages', 'wiring_config']

It explains why you encounter AttributeError when trying to execute container.printContainer().

like image 145
qwermike Avatar answered Mar 28 '26 23:03

qwermike



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!