mirror of
				https://github.com/ets-labs/python-dependency-injector.git
				synced 2025-11-04 09:57:37 +03:00 
			
		
		
		
	Merge branch 'release/3.38.0' into master
This commit is contained in:
		
						commit
						4ec3cce1d0
					
				
							
								
								
									
										53
									
								
								README.rst
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								README.rst
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -57,14 +57,25 @@ It helps implementing the dependency injection principle.
 | 
			
		|||
What is dependency injection?
 | 
			
		||||
-----------------------------
 | 
			
		||||
 | 
			
		||||
Dependency injection is a principle that helps to decrease coupling and increase cohesion. Your
 | 
			
		||||
code becomes more flexible, clear and it is easier to test it.
 | 
			
		||||
Dependency injection is a principle that helps to decrease coupling and increase cohesion.
 | 
			
		||||
 | 
			
		||||
What is coupling and cohesion?
 | 
			
		||||
 | 
			
		||||
Coupling and cohesion are about how tough the components are tied.
 | 
			
		||||
 | 
			
		||||
- **High coupling**. If the coupling is high it's like using a superglue or welding. No easy way
 | 
			
		||||
  to disassemble.
 | 
			
		||||
- **High cohesion**. High cohesion is like using the screws. Very easy to disassemble and
 | 
			
		||||
  assemble back or assemble a different way. It is an alternative to high coupling.
 | 
			
		||||
 | 
			
		||||
When the cohesion is high the coupling is low.
 | 
			
		||||
 | 
			
		||||
High cohesion brings the flexibility. Your code becomes easier to change and test.
 | 
			
		||||
 | 
			
		||||
How to implement dependency injection?
 | 
			
		||||
--------------------------------------
 | 
			
		||||
 | 
			
		||||
Objects do not create each other anymore. They provide a way to inject the needed dependencies
 | 
			
		||||
instead.
 | 
			
		||||
Objects do not create each other anymore. They provide a way to inject the dependencies instead.
 | 
			
		||||
 | 
			
		||||
Before:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -76,14 +87,14 @@ Before:
 | 
			
		|||
   class ApiClient:
 | 
			
		||||
 | 
			
		||||
       def __init__(self):
 | 
			
		||||
           self.api_key = os.getenv('API_KEY')
 | 
			
		||||
           self.timeout = os.getenv('TIMEOUT')
 | 
			
		||||
           self.api_key = os.getenv('API_KEY')  # <-- the dependency
 | 
			
		||||
           self.timeout = os.getenv('TIMEOUT')  # <-- the dependency
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   class Service:
 | 
			
		||||
 | 
			
		||||
       def __init__(self):
 | 
			
		||||
           self.api_client = ApiClient()
 | 
			
		||||
           self.api_client = ApiClient()  # <-- the dependency
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   if __name__ == '__main__':
 | 
			
		||||
| 
						 | 
				
			
			@ -100,28 +111,36 @@ After:
 | 
			
		|||
   class ApiClient:
 | 
			
		||||
 | 
			
		||||
       def __init__(self, api_key: str, timeout: int):
 | 
			
		||||
           self.api_key = api_key
 | 
			
		||||
           self.timeout = timeout
 | 
			
		||||
           self.api_key = api_key  # <-- the dependency is injected
 | 
			
		||||
           self.timeout = timeout  # <-- the dependency is injected
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   class Service:
 | 
			
		||||
 | 
			
		||||
       def __init__(self, api_client: ApiClient):
 | 
			
		||||
           self.api_client = api_client
 | 
			
		||||
           self.api_client = api_client  # <-- the dependency is injected
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   if __name__ == '__main__':
 | 
			
		||||
       service = Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT')))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Flexibility comes with a price: now you need to assemble your objects like this
 | 
			
		||||
``ApiClient`` is decoupled from knowing where the options come from. You can read a key and a
 | 
			
		||||
timeout from a configuration file or even get them from a database.
 | 
			
		||||
 | 
			
		||||
``Service`` is decoupled from the ``ApiClient``. It does not create it anymore. You can provide a
 | 
			
		||||
stub or other compatible object.
 | 
			
		||||
 | 
			
		||||
Flexibility comes with a price.
 | 
			
		||||
 | 
			
		||||
Now you need to assemble your objects like this
 | 
			
		||||
``Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT')))``. The assembly code might get
 | 
			
		||||
duplicated and it'll become harder to change the application structure.
 | 
			
		||||
 | 
			
		||||
What does Dependency Injector do?
 | 
			
		||||
---------------------------------
 | 
			
		||||
 | 
			
		||||
``Dependency Injector`` helps you assemble the objects.
 | 
			
		||||
``Dependency Injector`` helps to assemble the objects.
 | 
			
		||||
 | 
			
		||||
It provides you the container and the providers that help you describe objects assembly. When you
 | 
			
		||||
need an object you get it from the container. The rest of the assembly work is done by the
 | 
			
		||||
| 
						 | 
				
			
			@ -170,8 +189,11 @@ framework:
 | 
			
		|||
 | 
			
		||||
Retrieving of the ``Service`` instance now is done like this ``container.service()``.
 | 
			
		||||
 | 
			
		||||
Also ``Dependency Injector`` provides a bonus in overriding any of the providers with the
 | 
			
		||||
``.override()`` method:
 | 
			
		||||
The responsibility of assembling the object is consolidated in the container. When you need to
 | 
			
		||||
make a change you do it in one place.
 | 
			
		||||
 | 
			
		||||
When doing the testing you call the ``container.api_client.override()`` to replace the real API
 | 
			
		||||
client with a mock:
 | 
			
		||||
 | 
			
		||||
.. code-block:: python
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -180,7 +202,6 @@ Also ``Dependency Injector`` provides a bonus in overriding any of the providers
 | 
			
		|||
 | 
			
		||||
   with container.api_client.override(mock.Mock()):
 | 
			
		||||
       service = container.service()
 | 
			
		||||
       assert isinstance(service.api_client, mock.Mock)
 | 
			
		||||
 | 
			
		||||
It helps in a testing. Also you can use it for configuring project for the different environments:
 | 
			
		||||
replace an API client with a stub on the dev or stage.
 | 
			
		||||
| 
						 | 
				
			
			@ -217,7 +238,7 @@ Concept
 | 
			
		|||
- Explicit is better than implicit (PEP20).
 | 
			
		||||
- Do no magic to your code.
 | 
			
		||||
 | 
			
		||||
How does it different from the other frameworks?
 | 
			
		||||
How is it different from the other frameworks?
 | 
			
		||||
 | 
			
		||||
- **No autowiring.** The framework does NOT do any autowiring / autoresolving of the dependencies. You need to specify everything explicitly. Because *"Explicit is better than implicit" (PEP20)*.
 | 
			
		||||
- **Does not pollute your code.** Your application does NOT know and does NOT depend on the framework. No ``@inject`` decorators, annotations, patching or any other magic tricks.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										
											BIN
										
									
								
								docs/introduction/images/coupling-cohesion.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/introduction/images/coupling-cohesion.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 8.2 KiB  | 
| 
						 | 
				
			
			@ -1,125 +1,190 @@
 | 
			
		|||
What is dependency injection and inversion of control?
 | 
			
		||||
------------------------------------------------------
 | 
			
		||||
What is dependency injection?
 | 
			
		||||
-----------------------------
 | 
			
		||||
 | 
			
		||||
.. meta::
 | 
			
		||||
   :keywords: Python,DI,Dependency injection,IoC,Inversion of Control
 | 
			
		||||
   :description: This article provides definition of dependency injection, 
 | 
			
		||||
                 inversion of control and dependency inversion. It contains 
 | 
			
		||||
                 example code in Python that is refactored to be following 
 | 
			
		||||
                 inversion of control principle.
 | 
			
		||||
   :keywords: Python,DI,Dependency injection,Low coupling,High cohesion
 | 
			
		||||
   :description: This page provides a Python example of what is dependency injection. It tells
 | 
			
		||||
                 about benefits of coupling and high cohesion.
 | 
			
		||||
 | 
			
		||||
Definition
 | 
			
		||||
~~~~~~~~~~
 | 
			
		||||
Dependency injection is a principle that helps to decrease coupling and increase cohesion.
 | 
			
		||||
 | 
			
		||||
Wikipedia provides quite good definitions of dependency injection pattern
 | 
			
		||||
and related principles:
 | 
			
		||||
.. image:: images/coupling-cohesion.png
 | 
			
		||||
 | 
			
		||||
.. glossary::
 | 
			
		||||
What is coupling and cohesion?
 | 
			
		||||
 | 
			
		||||
    `Dependency injection`_
 | 
			
		||||
        In software engineering, dependency injection is a software design 
 | 
			
		||||
        pattern that implements inversion of control for resolving 
 | 
			
		||||
        dependencies. A dependency is an object that can be used (a service). 
 | 
			
		||||
        An injection is the passing of a dependency to a dependent object (a 
 | 
			
		||||
        client) that would use it. The service is made part of the client's 
 | 
			
		||||
        state. Passing the service to the client, rather than allowing a 
 | 
			
		||||
        client to build or find the service, is the fundamental requirement of 
 | 
			
		||||
        the pattern.
 | 
			
		||||
Coupling and cohesion are about how tough the components are tied.
 | 
			
		||||
 | 
			
		||||
        Dependency injection allows a program design to follow the dependency 
 | 
			
		||||
        inversion principle. The client delegates to external code (the 
 | 
			
		||||
        injector) the responsibility of providing its dependencies. The client 
 | 
			
		||||
        is not allowed to call the injector code. It is the injecting code 
 | 
			
		||||
        that constructs the services and calls the client to inject them. This 
 | 
			
		||||
        means the client code does not need to know about the injecting code. 
 | 
			
		||||
        The client does not need to know how to construct the services. The 
 | 
			
		||||
        client does not need to know which actual services it is using. The 
 | 
			
		||||
        client only needs to know about the intrinsic interfaces of the 
 | 
			
		||||
        services because these define how the client may use the services. 
 | 
			
		||||
        This separates the responsibilities of use and construction.
 | 
			
		||||
- **High coupling**. If the coupling is high it's like using a superglue or welding. No easy way
 | 
			
		||||
  to disassemble.
 | 
			
		||||
- **High cohesion**. High cohesion is like using the screws. Very easy to disassemble and
 | 
			
		||||
  assemble back or assemble a different way. It is an alternative to high coupling.
 | 
			
		||||
 | 
			
		||||
    `Inversion of control`_
 | 
			
		||||
        In software engineering, inversion of control (IoC) describes a design 
 | 
			
		||||
        in which custom-written portions of a computer program receive the 
 | 
			
		||||
        flow of control from a generic, reusable library. A software 
 | 
			
		||||
        architecture with this design inverts control as compared to 
 | 
			
		||||
        traditional procedural programming: in traditional programming, the 
 | 
			
		||||
        custom code that expresses the purpose of the program calls into 
 | 
			
		||||
        reusable libraries to take care of generic tasks, but with inversion 
 | 
			
		||||
        of control, it is the reusable code that calls into the custom, or 
 | 
			
		||||
        task-specific, code.
 | 
			
		||||
When the cohesion is high the coupling is low.
 | 
			
		||||
 | 
			
		||||
        Inversion of control is used to increase modularity of the program and 
 | 
			
		||||
        make it extensible, and has applications in object-oriented 
 | 
			
		||||
        programming and other programming paradigms. The term was popularized 
 | 
			
		||||
        by Robert C. Martin and Martin Fowler.
 | 
			
		||||
High cohesion brings the flexibility. Your code becomes easier to change and test.
 | 
			
		||||
 | 
			
		||||
        The term is related to, but different from, the dependency inversion 
 | 
			
		||||
        principle, which concerns itself with decoupling dependencies between 
 | 
			
		||||
        high-level and low-level layers through shared abstractions.
 | 
			
		||||
The example
 | 
			
		||||
~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
    `Dependency inversion`_
 | 
			
		||||
        In object-oriented programming, the dependency inversion principle 
 | 
			
		||||
        refers to a specific form of decoupling software modules. When 
 | 
			
		||||
        following this principle, the conventional dependency relationships 
 | 
			
		||||
        established from high-level, policy-setting modules to low-level, 
 | 
			
		||||
        dependency modules are reversed, thus rendering high-level modules 
 | 
			
		||||
        independent of the low-level module implementation details. The 
 | 
			
		||||
        principle states:
 | 
			
		||||
How does dependency injection helps to achieve high cohesion?
 | 
			
		||||
 | 
			
		||||
            + High-level modules should not depend on low-level modules. 
 | 
			
		||||
              Both should depend on abstractions.
 | 
			
		||||
            + Abstractions should not depend on details. 
 | 
			
		||||
              Details should depend on abstractions.
 | 
			
		||||
Objects do not create each other anymore. They provide a way to inject the dependencies instead.
 | 
			
		||||
 | 
			
		||||
        The principle inverts the way some people may think about 
 | 
			
		||||
        object-oriented design, dictating that both high- and low-level 
 | 
			
		||||
        objects must depend on the same abstraction. 
 | 
			
		||||
Before:
 | 
			
		||||
 | 
			
		||||
Example
 | 
			
		||||
~~~~~~~
 | 
			
		||||
.. code-block:: python
 | 
			
		||||
 | 
			
		||||
Let's go through the code of ``example.py``:
 | 
			
		||||
   import os
 | 
			
		||||
 | 
			
		||||
.. literalinclude:: ../../examples/di_demo/example.py
 | 
			
		||||
   :language: python
 | 
			
		||||
 | 
			
		||||
At some point, things defined above mean, that the code from ``example.py``,
 | 
			
		||||
could look different, like in ``example_di.py``:
 | 
			
		||||
   class ApiClient:
 | 
			
		||||
 | 
			
		||||
.. literalinclude:: ../../examples/di_demo/example_di.py
 | 
			
		||||
   :language: python
 | 
			
		||||
       def __init__(self):
 | 
			
		||||
           self.api_key = os.getenv('API_KEY')  # <-- the dependency
 | 
			
		||||
           self.timeout = os.getenv('TIMEOUT')  # <-- the dependency
 | 
			
		||||
 | 
			
		||||
Best explanation, ever
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Some times ago `user198313`_ posted awesome `question`_ about dependency 
 | 
			
		||||
injection on `StackOverflow`_:
 | 
			
		||||
   class Service:
 | 
			
		||||
 | 
			
		||||
.. note:: 
 | 
			
		||||
       def __init__(self):
 | 
			
		||||
           self.api_client = ApiClient()  # <-- the dependency
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   if __name__ == '__main__':
 | 
			
		||||
       service = Service()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
After:
 | 
			
		||||
 | 
			
		||||
.. code-block:: python
 | 
			
		||||
 | 
			
		||||
   import os
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   class ApiClient:
 | 
			
		||||
 | 
			
		||||
       def __init__(self, api_key: str, timeout: int):
 | 
			
		||||
           self.api_key = api_key  # <-- the dependency is injected
 | 
			
		||||
           self.timeout = timeout  # <-- the dependency is injected
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   class Service:
 | 
			
		||||
 | 
			
		||||
       def __init__(self, api_client: ApiClient):
 | 
			
		||||
           self.api_client = api_client  # <-- the dependency is injected
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   if __name__ == '__main__':
 | 
			
		||||
       service = Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT')))
 | 
			
		||||
 | 
			
		||||
``ApiClient`` is decoupled from knowing where the options come from. You can read a key and a
 | 
			
		||||
timeout from a configuration file or even get them from a database.
 | 
			
		||||
 | 
			
		||||
``Service`` is decoupled from the ``ApiClient``. It does not create it anymore. You can provide a
 | 
			
		||||
stub or other compatible object.
 | 
			
		||||
 | 
			
		||||
Flexibility comes with a price.
 | 
			
		||||
 | 
			
		||||
Now you need to assemble your objects like this
 | 
			
		||||
``Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT')))``. The assembly code might get
 | 
			
		||||
duplicated and it'll become harder to change the application structure.
 | 
			
		||||
 | 
			
		||||
Here comes the ``Dependency Injector``.
 | 
			
		||||
 | 
			
		||||
``Dependency Injector`` helps to assemble the objects.
 | 
			
		||||
 | 
			
		||||
It provides you the container and the providers that help you describe objects assembly. When you
 | 
			
		||||
need an object you get it from the container. The rest of the assembly work is done by the
 | 
			
		||||
framework:
 | 
			
		||||
 | 
			
		||||
.. code-block:: python
 | 
			
		||||
 | 
			
		||||
   from dependency_injector import containers, providers
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   class ApiClient:
 | 
			
		||||
 | 
			
		||||
       def __init__(self, api_key: str, timeout: int):
 | 
			
		||||
           self.api_key = api_key
 | 
			
		||||
           self.timeout = timeout
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   class Service:
 | 
			
		||||
 | 
			
		||||
       def __init__(self, api_client: ApiClient):
 | 
			
		||||
           self.api_client = api_client
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   class Container(containers.DeclarativeContainer):
 | 
			
		||||
 | 
			
		||||
       config = providers.Configuration()
 | 
			
		||||
 | 
			
		||||
       api_client = providers.Singleton(
 | 
			
		||||
           ApiClient,
 | 
			
		||||
           api_key=config.api_key,
 | 
			
		||||
           timeout=config.timeout.as_int(),
 | 
			
		||||
       )
 | 
			
		||||
 | 
			
		||||
       service = providers.Factory(
 | 
			
		||||
           Service,
 | 
			
		||||
           api_client=api_client,
 | 
			
		||||
       )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   if __name__ == '__main__':
 | 
			
		||||
       container = Container()
 | 
			
		||||
       container.config.api_key.from_env('API_KEY')
 | 
			
		||||
       container.config.timeout.from_env('TIMEOUT')
 | 
			
		||||
 | 
			
		||||
       service = container.service()
 | 
			
		||||
 | 
			
		||||
Retrieving of the ``Service`` instance now is done like this ``container.service()``.
 | 
			
		||||
 | 
			
		||||
Objects assembling is consolidated in the container. When you need to make a change you do it in
 | 
			
		||||
one place.
 | 
			
		||||
 | 
			
		||||
When doing the testing you call the ``container.api_client.override()`` to replace the real API
 | 
			
		||||
client with a mock:
 | 
			
		||||
 | 
			
		||||
.. code-block:: python
 | 
			
		||||
 | 
			
		||||
   from unittest import mock
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   with container.api_client.override(mock.Mock()):
 | 
			
		||||
       service = container.service()
 | 
			
		||||
 | 
			
		||||
How to explain dependency injection to a 5-year-old?
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
And `John Munsch`_ provided absolutely Great answer:
 | 
			
		||||
Some time ago `user198313`_ posted this `question`_ on the `StackOverflow`_.
 | 
			
		||||
 | 
			
		||||
.. note:: 
 | 
			
		||||
`John Munsch`_ provided a great answer:
 | 
			
		||||
 | 
			
		||||
    When you go and get things out of the refrigerator for yourself, you can 
 | 
			
		||||
    *When you go and get things out of the refrigerator for yourself, you can
 | 
			
		||||
    cause problems. You might leave the door open, you might get something 
 | 
			
		||||
    Mommy or Daddy doesn't want you to have. You might even be looking for 
 | 
			
		||||
    something we don't even have or which has expired.
 | 
			
		||||
    something we don't even have or which has expired.*
 | 
			
		||||
 | 
			
		||||
    What you should be doing is stating a need, "I need something to drink 
 | 
			
		||||
    *What you should be doing is stating a need, "I need something to drink
 | 
			
		||||
    with lunch," and then we will make sure you have something when you sit 
 | 
			
		||||
    down to eat.
 | 
			
		||||
    down to eat.*
 | 
			
		||||
 | 
			
		||||
What's next?
 | 
			
		||||
~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Choose one of the following as a next step:
 | 
			
		||||
 | 
			
		||||
+ Pass one of the tutorials:
 | 
			
		||||
    + :ref:`cli-tutorial`
 | 
			
		||||
    + :ref:`flask-tutorial`
 | 
			
		||||
    + :ref:`aiohttp-tutorial`
 | 
			
		||||
    + :ref:`asyncio-daemon-tutorial`
 | 
			
		||||
+ Know more about the :ref:`providers`
 | 
			
		||||
+ Go to the :ref:`contents`
 | 
			
		||||
 | 
			
		||||
.. disqus::
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.. _Dependency injection: http://en.wikipedia.org/wiki/Dependency_injection
 | 
			
		||||
.. _Inversion of control: https://en.wikipedia.org/wiki/Inversion_of_control
 | 
			
		||||
.. _Dependency inversion: https://en.wikipedia.org/wiki/Dependency_inversion_principle
 | 
			
		||||
.. _StackOverflow: http://stackoverflow.com/
 | 
			
		||||
.. _question: http://stackoverflow.com/questions/1638919/how-to-explain-dependency-injection-to-a-5-year-old/1639186
 | 
			
		||||
.. _user198313: http://stackoverflow.com/users/198313/user198313
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,12 @@ that were made in every particular version.
 | 
			
		|||
From version 0.7.6 *Dependency Injector* framework strictly 
 | 
			
		||||
follows `Semantic versioning`_
 | 
			
		||||
 | 
			
		||||
3.38.0
 | 
			
		||||
------
 | 
			
		||||
- Update "What is What is dependency injection?" documentation page.
 | 
			
		||||
- Update README.
 | 
			
		||||
- Fix a bunch of typos.
 | 
			
		||||
 | 
			
		||||
3.37.0
 | 
			
		||||
------
 | 
			
		||||
- Update index documentation page.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,17 +0,0 @@
 | 
			
		|||
"""The Code."""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Service:
 | 
			
		||||
    """The Service."""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Client:
 | 
			
		||||
    """The Client that uses the Service."""
 | 
			
		||||
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        """Initialize the Client."""
 | 
			
		||||
        self.service = Service()  # The Service is created by the Client
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    client = Client()  # Application creates the Client
 | 
			
		||||
| 
						 | 
				
			
			@ -1,18 +1,18 @@
 | 
			
		|||
"""The Code that demonstrates dependency injection pattern."""
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ApiClient:
 | 
			
		||||
 | 
			
		||||
    def __init__(self, api_key: str, timeout: int):
 | 
			
		||||
        self.api_key = api_key
 | 
			
		||||
        self.timeout = timeout
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Service:
 | 
			
		||||
    """The Service."""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Client:
 | 
			
		||||
    """The Client that uses the Service."""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, service):  # The Service is injected into the Client
 | 
			
		||||
        """Initialize the Client."""
 | 
			
		||||
        self.service = service
 | 
			
		||||
    def __init__(self, api_client: ApiClient):
 | 
			
		||||
        self.api_client = api_client
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    service = Service()       # Application creates the Service
 | 
			
		||||
    client = Client(service)  # and inject the Service into the Client
 | 
			
		||||
    service = Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT')))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,18 +0,0 @@
 | 
			
		|||
import os
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ApiClient:
 | 
			
		||||
 | 
			
		||||
    def __init__(self, api_key: str, timeout: int):
 | 
			
		||||
        self.api_key = api_key
 | 
			
		||||
        self.timeout = timeout
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Service:
 | 
			
		||||
 | 
			
		||||
    def __init__(self, api_client: ApiClient):
 | 
			
		||||
        self.api_client = api_client
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    service = Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT')))
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
"""Dependency injector top-level package."""
 | 
			
		||||
 | 
			
		||||
__version__ = '3.37.0'
 | 
			
		||||
__version__ = '3.38.0'
 | 
			
		||||
"""Version number that follows semantic versioning.
 | 
			
		||||
 | 
			
		||||
:type: str
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user