From 0bb30f91efcf9a1e8530e5ca86e7b8051fc5e3ae Mon Sep 17 00:00:00 2001 From: Roman Mogylatov Date: Tue, 1 Sep 2020 16:04:48 -0400 Subject: [PATCH] Singleton docs update (#288) * Update docblocks of factory provider examples * Edit singleton docs --- docs/images/providers/singleton.png | Bin 11318 -> 0 bytes docs/providers/factory.rst | 8 +- docs/providers/singleton.rst | 159 ++++++++---------- examples/providers/factory.py | 2 +- examples/providers/factory_delegation.py | 2 +- examples/providers/factory_init_injections.py | 2 +- .../factory_init_injections_underlying.py | 2 +- examples/providers/singleton.py | 23 ++- examples/providers/singleton_provided_type.py | 35 ---- examples/providers/singleton_resetting.py | 28 ++- examples/providers/singleton_scoped.py | 32 ++++ examples/providers/singleton_thread_locals.py | 37 ++-- 12 files changed, 150 insertions(+), 180 deletions(-) delete mode 100644 docs/images/providers/singleton.png delete mode 100644 examples/providers/singleton_provided_type.py create mode 100644 examples/providers/singleton_scoped.py diff --git a/docs/images/providers/singleton.png b/docs/images/providers/singleton.png deleted file mode 100644 index 06e8996f29b682a08c052004a3fe6279afb2662c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11318 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 PU*rm4RZ!*YcOU-);*CA| diff --git a/docs/providers/factory.rst b/docs/providers/factory.rst index 7708f25e..6050b530 100644 --- a/docs/providers/factory.rst +++ b/docs/providers/factory.rst @@ -1,5 +1,7 @@ +.. _factory-provider: + Factory provider ----------------- +================ .. meta:: :keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Factory,Abstract Factory, @@ -100,6 +102,8 @@ attribute of the provider that you're going to inject. .. note:: Any provider has a ``.provider`` attribute. +.. _factory-specialize-provided-type: + Specializing the provided type ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -112,6 +116,8 @@ class attribute. :lines: 3- :emphasize-lines: 12-14 +.. _abstract-factory: + Abstract factory ~~~~~~~~~~~~~~~~ diff --git a/docs/providers/singleton.rst b/docs/providers/singleton.rst index f479770f..e8fe4452 100644 --- a/docs/providers/singleton.rst +++ b/docs/providers/singleton.rst @@ -1,111 +1,100 @@ -Singleton providers -------------------- +Singleton provider +------------------ + +.. meta:: + :keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Singleton,Pattern,Example, + Threads,Multithreading,Scoped + :description: Singleton provider helps to provide a single object. This page + demonstrates how to use a Singleton provider. It also provides the example + of using a singleton and thread locals singleton in the multi-threaded + environment. .. currentmodule:: dependency_injector.providers -:py:class:`Singleton` provider creates new instance of specified class on -first call and returns same instance on every next call. - -Example: - -.. image:: /images/providers/singleton.png - :width: 80% - :align: center +:py:class:`Singleton` provider provides single object. It memorizes the first created object and +returns it on the rest of the calls. .. literalinclude:: ../../examples/providers/singleton.py :language: python + :lines: 3- -Singleton providers resetting -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Created and memorized by :py:class:`Singleton` instance can be reset. Reset of -:py:class:`Singleton`'s memorized instance is done by clearing reference to -it. Further lifecycle of memorized instance is out of :py:class:`Singleton` -provider's control and depends on garbage collection strategy. - -Example: - -.. literalinclude:: ../../examples/providers/singleton_resetting.py - :language: python - -Singleton providers and injections -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:py:class:`Singleton` provider has same interface as :py:class:`Factory` -provider, so, all of the rules about injections are the same, as for -:py:class:`Factory` provider. +``Singleton`` provider handles an injection of the dependencies the same way like a +:ref:`factory-provider`. .. note:: - Due that :py:class:`Singleton` provider creates specified class instance - only on the first call, all injections are done once, during the first - call. Every next call, while instance has been already created - and memorized, no injections are done, :py:class:`Singleton` provider just - returns memorized earlier instance. + ``Singleton`` provider does dependencies injection only when creates the object. When the object + is created and memorized ``Singleton`` provider just returns it without applying the injections. - This may cause some problems, for example, in case of trying to bind - :py:class:`Factory` provider with :py:class:`Singleton` provider (provided - by dependent :py:class:`Factory` instance will be injected only once, - during the first call). Be aware that such behaviour was made with opened - eyes and is not a bug. +Specialization of the provided type and abstract singletons work the same like like for the +factories: - By the way, in such case, :py:class:`Delegate` or - :py:class:`DelegatedSingleton` provider can be useful - . It makes possible to inject providers *as is*. Please check out - `Singleton providers delegation`_ section. +- :ref:`factory-specialize-provided-type` +- :ref:`abstract-factory` -Singleton providers delegation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Resetting memorized object +~~~~~~~~~~~~~~~~~~~~~~~~~~ -:py:class:`Singleton` provider could be delegated to any other provider via -any kind of injection. +To reset a memorized object you need to call the ``.reset()`` method of the ``Singleton`` +provider. -Delegation of :py:class:`Singleton` providers is the same as -:py:class:`Factory` providers delegation, please follow -:ref:`factory_providers_delegation` section for examples (with exception -of using :py:class:`DelegatedSingleton` instead of -:py:class:`DelegatedFactory`). +.. literalinclude:: ../../examples/providers/singleton_resetting.py + :language: python + :lines: 3- + :emphasize-lines: 14 -Singleton providers specialization -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. note:: + Resetting of the memorized object clears the reference to it. Further object's lifecycle is + managed by the garbage collector. -:py:class:`Singleton` provider could be specialized for any kind of needs via -declaring its subclasses. +Using singleton with multiple threads +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Specialization of :py:class:`Singleton` providers is the same as -:py:class:`Factory` providers specialization, please follow -:ref:`factory_providers_specialization` section for examples. +``Singleton`` provider is NOT thread-safe. You need to explicitly establish a synchronization for +using the ``Singleton`` provider in the multi-threading application. Otherwise you could trap +into the race condition problem: ``Singleton`` will create multiple objects. -Abstract singleton providers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +There are two thread-safe singleton implementations out of the box: -:py:class:`AbstractSingleton` provider is a :py:class:`Singleton` provider that -must be explicitly overridden before calling. - -Behaviour of :py:class:`AbstractSingleton` providers is the same as of -:py:class:`AbstractFactory`, please follow :ref:`abstract_factory_providers` -section for examples (with exception of using :py:class:`AbstractSingleton` -provider instead of :py:class:`AbstractFactory`). - -Singleton providers and multi-threading -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:py:class:`Singleton` provider is NOT thread-safe and should be used in -multi-threading applications with manually controlled locking. - -:py:class:`ThreadSafeSingleton` is a thread-safe version of -:py:class:`Singleton` and could be used in multi-threading applications -without any additional locking. - -Also there could be a need to use thread-scoped singletons and there is a -special provider for such case - :py:class:`ThreadLocalSingleton`. -:py:class:`ThreadLocalSingleton` provider creates instance once for each -thread and returns it on every call. - -Example: ++ :py:class:`ThreadSafeSingleton` - is a thread-safe version of a ``Singleton`` provider. You can use + in multi-threading applications without additional synchronization. ++ :py:class:`ThreadLocalSingleton` - is a singleton provider that uses thread-locals as a storage. + This type of singleton will manage multiple objects - the one object for the one thread. .. literalinclude:: ../../examples/providers/singleton_thread_locals.py :language: python + :lines: 3- + :emphasize-lines: 11,12 +Implementing scopes +~~~~~~~~~~~~~~~~~~~ + +To implement a scoped singleton provider use a ``Singleton`` provider and reset its scope when +needed. + +.. literalinclude:: ../../examples/providers/singleton_scoped.py + :language: python + :lines: 3- + +The output should look like this (each request a ``Service`` object has a different address): + +.. code-block:: + + * Serving Flask app "singleton_scoped" (lazy loading) + * Environment: production + WARNING: This is a development server. Do not use it in a production deployment. + Use a production WSGI server instead. + * Debug mode: off + * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) + <__main__.Service object at 0x1099a9d90> + 127.0.0.1 - - [25/Aug/2020 17:33:11] "GET / HTTP/1.1" 200 - + <__main__.Service object at 0x1099a9cd0> + 127.0.0.1 - - [25/Aug/2020 17:33:17] "GET / HTTP/1.1" 200 - + <__main__.Service object at 0x1099a9d00> + 127.0.0.1 - - [25/Aug/2020 17:33:18] "GET / HTTP/1.1" 200 - + <__main__.Service object at 0x1099a9e50> + 127.0.0.1 - - [25/Aug/2020 17:33:18] "GET / HTTP/1.1" 200 - + <__main__.Service object at 0x1099a9d90> + 127.0.0.1 - - [25/Aug/2020 17:33:18] "GET / HTTP/1.1" 200 - .. disqus:: diff --git a/examples/providers/factory.py b/examples/providers/factory.py index 33453dd3..c83ded02 100644 --- a/examples/providers/factory.py +++ b/examples/providers/factory.py @@ -1,4 +1,4 @@ -"""`Factory` providers example.""" +"""`Factory` provider example.""" from dependency_injector import providers diff --git a/examples/providers/factory_delegation.py b/examples/providers/factory_delegation.py index f6bc02d1..00f3fec5 100644 --- a/examples/providers/factory_delegation.py +++ b/examples/providers/factory_delegation.py @@ -1,4 +1,4 @@ -"""`Factory` providers delegation example.""" +"""`Factory` provider delegation example.""" from typing import Callable, List diff --git a/examples/providers/factory_init_injections.py b/examples/providers/factory_init_injections.py index 682ace80..d720edb6 100644 --- a/examples/providers/factory_init_injections.py +++ b/examples/providers/factory_init_injections.py @@ -1,4 +1,4 @@ -"""`Factory` providers init injections example.""" +"""`Factory` provider init injections example.""" from dependency_injector import providers diff --git a/examples/providers/factory_init_injections_underlying.py b/examples/providers/factory_init_injections_underlying.py index cf49388e..5c9f196f 100644 --- a/examples/providers/factory_init_injections_underlying.py +++ b/examples/providers/factory_init_injections_underlying.py @@ -1,4 +1,4 @@ -"""`Factory` providers - building a complex object graph with deep init injections example.""" +"""`Factory` provider - passing injections to the underlying providers example.""" from dependency_injector import providers diff --git a/examples/providers/singleton.py b/examples/providers/singleton.py index 97fe5c02..9e94b76c 100644 --- a/examples/providers/singleton.py +++ b/examples/providers/singleton.py @@ -1,19 +1,16 @@ -"""`Singleton` providers example.""" +"""`Singleton` provider example.""" -import collections - -import dependency_injector.providers as providers +from dependency_injector import providers -UsersService = collections.namedtuple('UsersService', []) +class UserService: + ... -# Singleton provider creates new instance of specified class on first call -# and returns same instance on every next call. -users_service_provider = providers.Singleton(UsersService) -# Retrieving several UserService objects: -users_service1 = users_service_provider() -users_service2 = users_service_provider() +user_service_provider = providers.Singleton(UserService) -# Making some asserts: -assert users_service1 is users_service2 + +if __name__ == '__main__': + user_service1 = user_service_provider() + user_service2 = user_service_provider() + assert user_service1 is user_service2 diff --git a/examples/providers/singleton_provided_type.py b/examples/providers/singleton_provided_type.py deleted file mode 100644 index 1402fd5c..00000000 --- a/examples/providers/singleton_provided_type.py +++ /dev/null @@ -1,35 +0,0 @@ -"""`Singleton` specialization for limitation to provided type example.""" - -import dependency_injector.providers as providers -import dependency_injector.errors as errors - - -class BaseService: - """Base service class.""" - - -class UsersService(BaseService): - """Users service.""" - - -class PhotosService(BaseService): - """Photos service.""" - - -class ServiceProvider(providers.Singleton): - """Service provider.""" - - provided_type = BaseService - - -# Creating several service providers with BaseService instances: -users_service_provider = ServiceProvider(UsersService) -photos_service_provider = ServiceProvider(PhotosService) - -# Trying to create service provider with not a BaseService instance: -try: - some_service_provider = ServiceProvider(object) -except errors.Error as exception: - print(exception) - # can provide only - # instances diff --git a/examples/providers/singleton_resetting.py b/examples/providers/singleton_resetting.py index 8fe2f5a7..edec0594 100644 --- a/examples/providers/singleton_resetting.py +++ b/examples/providers/singleton_resetting.py @@ -1,27 +1,19 @@ -"""`Singleton` providers resetting example.""" +"""`Singleton` provider resetting example.""" -import collections - -import dependency_injector.providers as providers +from dependency_injector import providers -UsersService = collections.namedtuple('UsersService', []) +class UserService: + ... -# Users service singleton provider: -users_service_provider = providers.Singleton(UsersService) -# Retrieving several UsersService objects: -users_service1 = users_service_provider() -users_service2 = users_service_provider() +user_service_provider = providers.Singleton(UserService) -# Making some asserts: -assert users_service1 is users_service2 -# Resetting of memorized instance: -users_service_provider.reset() +if __name__ == '__main__': + user_service1 = user_service_provider() -# Retrieving one more UserService object: -users_service3 = users_service_provider() + user_service_provider.reset() -# Making some asserts: -assert users_service3 is not users_service1 + users_service2 = user_service_provider() + assert users_service2 is not user_service1 diff --git a/examples/providers/singleton_scoped.py b/examples/providers/singleton_scoped.py new file mode 100644 index 00000000..3ab27beb --- /dev/null +++ b/examples/providers/singleton_scoped.py @@ -0,0 +1,32 @@ +"""`Singleton` - flask request scope example.""" + +from dependency_injector import providers +from flask import Flask + + +class Service: + ... + + +service_provider = providers.Singleton(Service) + + +def index_view(): + service_1 = service_provider() + service_2 = service_provider() + assert service_1 is service_2 + print(service_1) + return 'Hello World!' + + +def teardown_context(request): + service_provider.reset() + return request + + +app = Flask(__name__) +app.add_url_rule('/', 'index', view_func=index_view) +app.after_request(teardown_context) + +if __name__ == '__main__': + app.run() diff --git a/examples/providers/singleton_thread_locals.py b/examples/providers/singleton_thread_locals.py index 7c1a0aa3..83325559 100644 --- a/examples/providers/singleton_thread_locals.py +++ b/examples/providers/singleton_thread_locals.py @@ -1,53 +1,42 @@ -"""`ThreadLocalSingleton` providers example.""" +"""`ThreadLocalSingleton` provider example.""" import threading import queue -import dependency_injector.providers as providers +from dependency_injector import providers -def example(example_object, queue_object): - """Put provided object in the provided queue.""" +def put_in_queue(example_object, queue_object): queue_object.put(example_object) -# Create thread-local singleton provider for some object (main thread): thread_local_object = providers.ThreadLocalSingleton(object) - -# Create singleton provider for thread-safe queue: -queue_factory = providers.ThreadSafeSingleton(queue.Queue) - -# Create callable provider for example(), inject dependencies: -example = providers.DelegatedCallable( - example, +queue_provider = providers.ThreadSafeSingleton(queue.Queue) +put_in_queue = providers.Callable( + put_in_queue, example_object=thread_local_object, - queue_object=queue_factory, + queue_object=queue_provider, +) +thread_factory = providers.Factory( + threading.Thread, + target=put_in_queue.provider, ) -# Create factory for threads that are targeted to execute example(): -thread_factory = providers.Factory(threading.Thread, target=example) if __name__ == '__main__': - # Create 10 threads for concurrent execution of example(): threads = [] for thread_number in range(10): threads.append( thread_factory(name='Thread{0}'.format(thread_number)), ) - - # Start execution of all created threads: for thread in threads: thread.start() - - # Wait while threads would complete their work: for thread in threads: thread.join() - # Making some asserts (main thread): all_objects = set() - - while not queue_factory().empty(): - all_objects.add(queue_factory().get()) + while not queue_provider().empty(): + all_objects.add(queue_provider().get()) assert len(all_objects) == len(threads) # Queue contains same number of objects as number of threads where