From 3123574cf644e528ef6805bdef05f14d68de24bb Mon Sep 17 00:00:00 2001 From: Roman Mogilatov Date: Wed, 10 Jun 2015 09:53:15 +0300 Subject: [PATCH] Changing provider docs structure --- docs/{providers.rst => _providers.rst} | 13 +- docs/index.rst | 2 +- docs/providers/factory.rst | 348 +++++++++++++++++++++++++ docs/providers/index.rst | 12 + 4 files changed, 370 insertions(+), 5 deletions(-) rename docs/{providers.rst => _providers.rst} (98%) create mode 100644 docs/providers/factory.rst create mode 100644 docs/providers/index.rst diff --git a/docs/providers.rst b/docs/_providers.rst similarity index 98% rename from docs/providers.rst rename to docs/_providers.rst index 55f665a9..a316d4dd 100644 --- a/docs/providers.rst +++ b/docs/_providers.rst @@ -72,7 +72,7 @@ Example below shows how to create ``Factory`` of particular class with ``__init__`` keyword argument injections which injectable values are also provided by another factories: -.. image:: images/factory_init_injections.png +.. image:: ../images/factory_init_injections.png .. code-block:: python @@ -127,7 +127,7 @@ passes positional context arguments to class's ``__init__`` method, but keyword context arguments have priority on ``KwArg`` injections (this could be useful for testing). So, please, follow the example below: -.. image:: images/factory_init_injections_and_contexts.png +.. image:: ../images/factory_init_injections_and_contexts.png .. code-block:: python @@ -219,7 +219,7 @@ Example below shows how to create ``Factory`` of particular class with attribute injections. Those injections are done by setting specified attributes with injectable values right after object's creation. -.. image:: images/factory_attribute_injections.png +.. image:: ../images/factory_attribute_injections.png .. code-block:: python @@ -289,7 +289,7 @@ Method injections are not very popular in Python due Python best practices (usage of public attributes instead of setter methods), but it may appear in some cases. -.. image:: images/factory_method_injections.png +.. image:: ../images/factory_method_injections.png .. code-block:: python @@ -355,6 +355,11 @@ some cases. assert user1.credit_card is not user2.credit_card +Singleton providers +------------------- + +``Singleton`` provider creates new instance of specified class on first call +and returns same instance on every next call. Instance providers & Injections ------------------------------- diff --git a/docs/index.rst b/docs/index.rst index ad7a2c2b..c35ee4de 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -38,7 +38,7 @@ Contents introduction installation - providers + providers/index injections catalogs decorators diff --git a/docs/providers/factory.rst b/docs/providers/factory.rst new file mode 100644 index 00000000..0388cc5b --- /dev/null +++ b/docs/providers/factory.rst @@ -0,0 +1,348 @@ +Factory providers +----------------- + +``Factory`` provider creates new instance of specified class on every call. + +Nothing could be better than brief example: + +.. code-block:: python + + """`Factory` providers example.""" + + from objects.providers import Factory + + + class User(object): + + """Example class User.""" + + + # Factory provider creates new instance of specified class on every call. + users_factory = Factory(User) + + user1 = users_factory() + user2 = users_factory() + + assert user1 is not user2 + assert isinstance(user1, User) and isinstance(user2, User) + + +Factory providers and injections +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Objects can take dependencies in different forms. Some objects take init +arguments, other are using attributes setting or method calls to be +initialized. It affects how such objects need to be created and initialized, +and that is the place where ``objects.injections`` need to be used. + +``Factory`` provider takes various number of positional arguments, that define +what kind of dependency injections need to be done. + +All of those instructions are defined in ``objects.injections`` module and are +subclasses of ``objects.injections.Injection``. There are several types of +injections that are used by ``Factory`` provider: + + - ``KwArg`` - injection is done by passing injectable value in object's + ``__init__()`` method in time of object's creation via keyword argument. + Takes keyword name of ``__init__()`` argument and injectable value. + - ``Attribute`` - injection is done by setting specified attribute with + injectable value right after object's creation. Takes attribute name and + injectable value. + - ``Method`` - injection is done by calling of specified method with + injectable value right after object's creation and attribute injections + are done. Takes method name and injectable value. + +All ``Injection``'s injectable values are provided *"as is"*, except of +providers. Providers will be called every time, when injection needs to be +done. + + +Factory providers and __init__ injections +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Example below shows how to create ``Factory`` of particular class with +``__init__`` keyword argument injections which injectable values are also +provided by another factories: + +.. image:: /images/factory_init_injections.png + +.. code-block:: python + + """`Factory` providers with init injections example.""" + + from objects.providers import Factory + from objects.injections import KwArg + + + class User(object): + + """Example class User.""" + + def __init__(self, main_photo): + """Initializer. + + :param main_photo: Photo + :return: + """ + self.main_photo = main_photo + super(User, self).__init__() + + + class Photo(object): + + """Example class Photo.""" + + + # User and Photo factories: + photos_factory = Factory(Photo) + users_factory = Factory(User, + KwArg('main_photo', photos_factory)) + + # Creating several User objects: + user1 = users_factory() # Same as: user1 = User(main_photo=Photo()) + user2 = users_factory() # Same as: user2 = User(main_photo=Photo()) + + # Making some asserts: + assert isinstance(user1, User) + assert isinstance(user1.main_photo, Photo) + + assert isinstance(user2, User) + assert isinstance(user2.main_photo, Photo) + + assert user1 is not user2 + assert user1.main_photo is not user2.main_photo + + +Next example shows how ``Factory`` provider deals with positional and keyword +``__init__`` context arguments. In few words, ``Factory`` provider fully +passes positional context arguments to class's ``__init__`` method, but +keyword context arguments have priority on ``KwArg`` injections (this could be +useful for testing). So, please, follow the example below: + +.. image:: /images/factory_init_injections_and_contexts.png + +.. code-block:: python + + """`Factory` providers with init injections and context arguments example.""" + + from objects.providers import Factory + from objects.injections import KwArg + + + class User(object): + + """Example class User. + + Class User has to be provided with user id. + + Also Class User has dependencies on class Photo and class CreditCard + objects. + + All of the dependencies have to be provided like __init__ arguments. + """ + + def __init__(self, id, main_photo, credit_card): + """Initializer. + + :param id: int + :param main_photo: Photo + :param credit_card: CreditCard + :return: + """ + self.id = id + self.main_photo = main_photo + self.credit_card = credit_card + super(User, self).__init__() + + + class Photo(object): + + """Example class Photo.""" + + + class CreditCard(object): + + """Example class CreditCard.""" + + + # User, Photo and CreditCard factories: + credit_cards_factory = Factory(CreditCard) + photos_factory = Factory(Photo) + users_factory = Factory(User, + KwArg('main_photo', photos_factory), + KwArg('credit_card', credit_cards_factory)) + + # Creating several User objects: + user1 = users_factory(1) # Same as: user1 = User(1, + # main_photo=Photo(), + # credit_card=CreditCard()) + user2 = users_factory(2) # Same as: user2 = User(2, + # main_photo=Photo(), + # credit_card=CreditCard()) + + # Making some asserts: + assert user1.id == 1 + assert isinstance(user1.main_photo, Photo) + assert isinstance(user1.credit_card, CreditCard) + + assert user2.id == 2 + assert isinstance(user2.main_photo, Photo) + assert isinstance(user2.credit_card, CreditCard) + + assert user1.main_photo is not user2.main_photo + assert user1.credit_card is not user2.credit_card + + # Context keyword arguments have priority on KwArg injections priority: + main_photo_mock = Photo() + credit_card_mock = CreditCard() + + user3 = users_factory(3, main_photo=main_photo_mock, + credit_card=credit_card_mock) + + assert user3.id == 3 + assert user3.main_photo is main_photo_mock + assert user3.credit_card is credit_card_mock + + +Factory providers and attribute injections +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Example below shows how to create ``Factory`` of particular class with +attribute injections. Those injections are done by setting specified attributes +with injectable values right after object's creation. + +.. image:: /images/factory_attribute_injections.png + +.. code-block:: python + + """`Factory` providers with attribute injections example.""" + + from objects.providers import Factory + from objects.injections import Attribute + + + class User(object): + + """Example class User.""" + + def __init__(self): + """Initializer.""" + self.main_photo = None + self.credit_card = None + + + class Photo(object): + + """Example class Photo.""" + + + class CreditCard(object): + + """Example class CreditCard.""" + + + # User, Photo and CreditCard factories: + credit_cards_factory = Factory(CreditCard) + photos_factory = Factory(Photo) + users_factory = Factory(User, + Attribute('main_photo', photos_factory), + Attribute('credit_card', credit_cards_factory)) + + # Creating several User objects: + user1 = users_factory() # Same as: user1 = User() + # user1.main_photo = Photo() + # user1.credit_card = CreditCard() + user2 = users_factory() # Same as: user2 = User() + # user2.main_photo = Photo() + # user2.credit_card = CreditCard() + + # Making some asserts: + assert user1 is not user2 + + assert isinstance(user1.main_photo, Photo) + assert isinstance(user1.credit_card, CreditCard) + + assert isinstance(user2.main_photo, Photo) + assert isinstance(user2.credit_card, CreditCard) + + assert user1.main_photo is not user2.main_photo + assert user1.credit_card is not user2.credit_card + + +Factory providers and method injections +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Current example shows how to create ``Factory`` of particular class with +method injections. Those injections are done by calling of specified method +with injectable value right after object's creation and attribute injections +are done. + +Method injections are not very popular in Python due Python best practices +(usage of public attributes instead of setter methods), but it may appear in +some cases. + +.. image:: /images/factory_method_injections.png + +.. code-block:: python + + """`Factory` providers with method injections example.""" + + from objects.providers import Factory + from objects.injections import Method + + + class User(object): + + """Example class User.""" + + def __init__(self): + """Initializer.""" + self.main_photo = None + self.credit_card = None + + def set_main_photo(self, photo): + """Set user's main photo.""" + self.main_photo = photo + + def set_credit_card(self, credit_card): + """Set user's credit card.""" + self.credit_card = credit_card + + + class Photo(object): + + """Example class Photo.""" + + + class CreditCard(object): + + """Example class CreditCard.""" + + + # User, Photo and CreditCard factories: + credit_cards_factory = Factory(CreditCard) + photos_factory = Factory(Photo) + users_factory = Factory(User, + Method('set_main_photo', photos_factory), + Method('set_credit_card', credit_cards_factory)) + + # Creating several User objects: + user1 = users_factory() # Same as: user1 = User() + # user1.set_main_photo(Photo()) + # user1.set_credit_card(CreditCard()) + user2 = users_factory() # Same as: user2 = User() + # user2.set_main_photo(Photo()) + # user2.set_credit_card(CreditCard()) + + # Making some asserts: + assert user1 is not user2 + + assert isinstance(user1.main_photo, Photo) + assert isinstance(user1.credit_card, CreditCard) + + assert isinstance(user2.main_photo, Photo) + assert isinstance(user2.credit_card, CreditCard) + + assert user1.main_photo is not user2.main_photo + assert user1.credit_card is not user2.credit_card + diff --git a/docs/providers/index.rst b/docs/providers/index.rst new file mode 100644 index 00000000..92a9a0d1 --- /dev/null +++ b/docs/providers/index.rst @@ -0,0 +1,12 @@ +Providers +========= + +Providers are strategies of accessing objects. + +All providers are callable. They describe how particular objects are provided. + +.. toctree:: + :maxdepth: 2 + :glob: + + *