From 2ada44f4da3b4df50ac9c2aa893e37fdc053125d Mon Sep 17 00:00:00 2001 From: Roman Mogilatov Date: Sun, 29 Jan 2017 23:30:38 +0200 Subject: [PATCH] Update readme --- README.rst | 54 ++++++++++++++++++++++++++++++++++++-- docs/images/internals.png | Bin 8378 -> 8260 bytes 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 81974839..da5b9cbb 100644 --- a/README.rst +++ b/README.rst @@ -213,8 +213,58 @@ using *Dependency Injector*: diesel_car = Cars.diesel() electro_car = Cars.electro() -Dependency injection in action ------------------------------- +Dependency Injector structure +----------------------------- + +Dependency Injector is a microframework and has a very simple structure. + +There are 2 main entities: providers & containers. + +.. image:: https://raw.githubusercontent.com/wiki/ets-labs/python-dependency-injector/img/internals.png + :width: 100% + :align: center + +Providers +~~~~~~~~~ + +Providers are strategies of accessing objects. They define how particular +objects are provided. + +- **Provider** - base provider class. +- **Callable** - provider that calls wrapped callable on every call. Supports + positional & keyword argument injections. +- **Factory** - provider that creates new instance of specified class on every + call. Supports positional & keyword argument injections, as well as + attribute injections. +- **Singleton** - provider that creates new instance of specified class on first + call and returns same instance on every next call. Supports positional & + keyword argument injections, as well as attribute injections. +- **Object** - provider that returns provided instance "as is". +- **ExternalDependency** - provider that can be useful for development of + self-sufficient libraries / modules / applications that has required + external dependencies. +- **Configuration** - provider that helps with implementing late static binding + of configuration options - use first, define later. + +Containers +~~~~~~~~~~ + +Containers are collections of providers. Main purpose of containers is to +group providers. + +- **DeclarativeContainer** - is inversion of control container that could be + defined in declarative manner. It should cover most of the cases when list + of providers that would be included in container is deterministic + (container will not change its structure in runtime). +- **DynamicContainer** - is an inversion of control container with dynamic + structure. It should cover most of the cases when list of providers that + would be included in container is non-deterministic and depends on + application's flow or its configuration (container's structure could be + determined just after application will be started and will do some initial + work, like parsing list of container’s providers from the configuration). + +Dependency Injector in action +----------------------------- Brief example below is a simplified version of inversion of control containters from one of the real-life applications. This example demonstrates diff --git a/docs/images/internals.png b/docs/images/internals.png index 35b99dcbbc45888b98378c3da9f8808bc8a004ef..f49ecc8db6710bd13aebd91cc7d13a665671b343 100644 GIT binary patch literal 8260 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 literal 8378 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