mirror of
				https://github.com/ets-labs/python-dependency-injector.git
				synced 2025-11-01 00:17:55 +03:00 
			
		
		
		
	Update DI in Python page
This commit is contained in:
		
							parent
							
								
									65c883ad57
								
							
						
					
					
						commit
						f7d3ada92f
					
				|  | @ -77,10 +77,14 @@ Before: | |||
|            self.api_client = ApiClient()  # <-- the dependency | ||||
| 
 | ||||
| 
 | ||||
|    if __name__ == '__main__': | ||||
|        service = Service() | ||||
|    def main() -> None: | ||||
|        service = Service()  # <-- the dependency | ||||
|        ... | ||||
| 
 | ||||
| 
 | ||||
|    if __name__ == '__main__': | ||||
|        main() | ||||
| 
 | ||||
| After: | ||||
| 
 | ||||
| .. code-block:: python | ||||
|  | @ -101,8 +105,19 @@ After: | |||
|            self.api_client = api_client  # <-- the dependency is injected | ||||
| 
 | ||||
| 
 | ||||
|    def main(service: Service):  # <-- the dependency is injected | ||||
|        ... | ||||
| 
 | ||||
| 
 | ||||
|    if __name__ == '__main__': | ||||
|        service = Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT'))) | ||||
|        main( | ||||
|            service=Service( | ||||
|                api_client=ApiClient( | ||||
|                    api_key=os.getenv('API_KEY'), | ||||
|                    timeout=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. | ||||
|  | @ -110,11 +125,22 @@ 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. | ||||
| 
 | ||||
| Function ``main()`` is decoupled from ``Service``. It receives it as an argument. | ||||
| 
 | ||||
| Flexibility comes with a price. | ||||
| 
 | ||||
| Now you need to assemble the objects like this:: | ||||
| Now you need to assemble and inject the objects like this: | ||||
| 
 | ||||
|     service = Service(ApiClient(os.getenv('API_KEY'), os.getenv('TIMEOUT'))) | ||||
| .. code-block:: python | ||||
| 
 | ||||
|    main( | ||||
|        service=Service( | ||||
|            api_client=ApiClient( | ||||
|                api_key=os.getenv('API_KEY'), | ||||
|                timeout=os.getenv('TIMEOUT'), | ||||
|            ), | ||||
|        ), | ||||
|    ) | ||||
| 
 | ||||
| The assembly code might get duplicated and it'll become harder to change the application structure. | ||||
| 
 | ||||
|  | @ -123,18 +149,20 @@ Here comes the ``Dependency Injector``. | |||
| What does the Dependency Injector do? | ||||
| ------------------------------------- | ||||
| 
 | ||||
| With the dependency injection pattern objects loose the responsibility of assembling the | ||||
| dependencies. The ``Dependency Injector`` absorbs that responsibility. | ||||
| With the dependency injection pattern objects loose the responsibility of assembling | ||||
| the dependencies. The ``Dependency Injector`` absorbs that responsibilities. | ||||
| 
 | ||||
| ``Dependency Injector`` helps to assemble the objects. | ||||
| ``Dependency Injector`` helps to assemble and inject the dependencies. | ||||
| 
 | ||||
| It provides a container and providers that help you with the objects assembly. When you | ||||
| need an object you get it from the container. The rest of the assembly work is done by the | ||||
| framework: | ||||
| It provides a container and providers that help you with the objects assembly. | ||||
| When you need an object you place a ``Provide`` marker as a default value of a | ||||
| function argument. When you call this function framework assembles and injects | ||||
| the dependency. | ||||
| 
 | ||||
| .. code-block:: python | ||||
| 
 | ||||
|    from dependency_injector import containers, providers | ||||
|    from dependency_injector.wiring import Provide | ||||
| 
 | ||||
| 
 | ||||
|    class Container(containers.DeclarativeContainer): | ||||
|  | @ -153,22 +181,29 @@ framework: | |||
|        ) | ||||
| 
 | ||||
| 
 | ||||
|    def main(service: Service = Provide[Container.service]): | ||||
|        ... | ||||
| 
 | ||||
| 
 | ||||
|    if __name__ == '__main__': | ||||
|        container = Container() | ||||
| 
 | ||||
|        container.config.api_key.from_env('API_KEY') | ||||
|        container.config.timeout.from_env('TIMEOUT') | ||||
| 
 | ||||
|        service = container.service() | ||||
|        container.wire(modules=[sys.modules[__name__]]) | ||||
| 
 | ||||
| Retrieving of the ``Service`` instance now is done like this:: | ||||
|        main() | ||||
| 
 | ||||
|     service = container.service() | ||||
| When you call ``main()`` function the ``Service`` dependency is assembled and injected:: | ||||
| 
 | ||||
|     main() | ||||
| 
 | ||||
| Objects assembling is consolidated in the container. When you need to make a change you do it in | ||||
| one place. | ||||
| 
 | ||||
| When doing a testing you call the ``container.api_client.override()`` to replace the real API | ||||
| client with a mock: | ||||
| client with a mock. When you call ``main()`` the mock is injected: | ||||
| 
 | ||||
| .. code-block:: python | ||||
| 
 | ||||
|  | @ -176,7 +211,7 @@ client with a mock: | |||
| 
 | ||||
| 
 | ||||
|    with container.api_client.override(mock.Mock()): | ||||
|        service = container.service() | ||||
|        main() | ||||
| 
 | ||||
| You can override any provider with another provider. | ||||
| 
 | ||||
|  | @ -261,6 +296,7 @@ Choose one of the following as a next step: | |||
|     - :ref:`cli-tutorial` | ||||
| - Know more about the ``Dependency Injector`` :ref:`key-features` | ||||
| - Know more about the :ref:`providers` | ||||
| - Know more about the :ref:`wiring` | ||||
| - Go to the :ref:`contents` | ||||
| 
 | ||||
| Useful links | ||||
|  |  | |||
							
								
								
									
										29
									
								
								examples/demo/after.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								examples/demo/after.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | |||
| 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 | ||||
| 
 | ||||
| 
 | ||||
| def main(service: Service):  # <-- the dependency is injected | ||||
|     ... | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     main( | ||||
|         service=Service( | ||||
|             api_client=ApiClient( | ||||
|                 api_key=os.getenv('API_KEY'), | ||||
|                 timeout=os.getenv('TIMEOUT'), | ||||
|             ), | ||||
|         ), | ||||
|     ) | ||||
							
								
								
									
										23
									
								
								examples/demo/before.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								examples/demo/before.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | |||
| import os | ||||
| 
 | ||||
| 
 | ||||
| class ApiClient: | ||||
| 
 | ||||
|     def __init__(self): | ||||
|         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()  # <-- the dependency | ||||
| 
 | ||||
| 
 | ||||
| def main() -> None: | ||||
|     service = Service()  # <-- the dependency | ||||
|     ... | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
|  | @ -1,28 +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 | ||||
| 
 | ||||
| 
 | ||||
| def main() -> None: | ||||
|     service = Service( | ||||
|         api_client=ApiClient( | ||||
|             api_key=os.getenv('API_KEY'), | ||||
|             timeout=os.getenv('TIMEOUT'), | ||||
|         ), | ||||
|     ) | ||||
|     ... | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
|  | @ -1,23 +0,0 @@ | |||
| import os | ||||
| 
 | ||||
| 
 | ||||
| class ApiClient: | ||||
| 
 | ||||
|     def __init__(self): | ||||
|         self.api_key = os.getenv('API_KEY') | ||||
|         self.timeout = os.getenv('TIMEOUT') | ||||
| 
 | ||||
| 
 | ||||
| class Service: | ||||
| 
 | ||||
|     def __init__(self): | ||||
|         self.api_client = ApiClient() | ||||
| 
 | ||||
| 
 | ||||
| def main() -> None: | ||||
|     service = Service() | ||||
|     ... | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
|  | @ -4,7 +4,7 @@ from unittest import mock | |||
| from dependency_injector import containers, providers | ||||
| from dependency_injector.wiring import Provide | ||||
| 
 | ||||
| from di import ApiClient, Service | ||||
| from after import ApiClient, Service | ||||
| 
 | ||||
| 
 | ||||
| class Container(containers.DeclarativeContainer): | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user