{ "info": { "author": "fcracker79", "author_email": "fcracker79@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Software Development" ], "description": "|build status| |Pypi|\n\nYADI\n====\n\nYet Another Dependency Injection framework\n\nYADI is a dependency injection framework. It supports both classes and\nfunction in a declarative fashion.\n\nInstallation\n------------\n\n.. code:: sh\n\n pip install yadi-framework\n\nBasic examples\n--------------\n\nThis is a simple injection example:\n\n.. code:: python\n\n from yadi.context_impl import DEFAULT_CONTEXT\n from yadi.decorators import inject\n from yadi.types import Yadi\n\n\n @inject()\n class Component1:\n pass\n\n\n @inject()\n class Component2:\n def __init__(self, c1: Yadi[Component1]):\n self.c1 = c1\n\n\n @inject()\n class Component3:\n def __init__(self, c1: Yadi[Component1]):\n self.c1 = c1\n\n\n c2 = DEFAULT_CONTEXT.get_bean(Component2) # type: Component2\n c3 = DEFAULT_CONTEXT.get_bean(Component3) # type: Component3\n print(Component1 is type(c2.c1)) # True\n print(c2.c1 is c3.c1) # True\n\nHere it is an example of how to inject functions:\n\n.. code:: python\n\n from yadi.context_impl import DEFAULT_CONTEXT\n from yadi.decorators import inject\n from yadi.types import Yadi\n\n\n @inject()\n class Component:\n pass\n\n\n @inject(name='another_function')\n def h(x, y, z=None):\n assert isinstance(x, Component)\n print('Function h:', type(x))\n\n\n @inject(name='my_function')\n def f(a: Yadi[Component], b, c: Yadi['another_function'] = None, d: str = None):\n c(a, b, z=d)\n\n\n DEFAULT_CONTEXT.get_bean('my_function')(23, d=5) # Function h: \n\nScopes\n------\n\nBy default, all the beans are saved as Singleton. Each singleton is\nstored in its context, that is, there is a single instance *for each\ncontext instance*.\n\nAlternatively, it is possible to save beans as Prototypes, that is, a\ndifferent instance is generated whenever the bean is referred to.\n\n.. code:: python\n\n from yadi import context\n from yadi import types\n from yadi.context_impl import DEFAULT_CONTEXT\n from yadi.decorators import inject\n\n\n @inject(scope=context.PROTOTYPE, name='a component 1')\n class Component1:\n pass\n\n\n @inject(name='a component 2')\n class Component2:\n def __init__(\n self,\n f1: types.Yadi[Component1],\n f2: types.Yadi['a component 1']):\n self.f1, self.f2 = f1, f2\n\n\n @inject(name='a component 3')\n class Component3:\n def __init__(\n self,\n f1: types.Yadi[Component1],\n f2: types.Yadi['a component 1']):\n self.f1, self.f2 = f1, f2\n\n\n c2 = DEFAULT_CONTEXT.get_bean('a component 2') # type: Component2\n c3 = DEFAULT_CONTEXT.get_bean('a component 3') # type: Component3\n\n print(isinstance(c2.f1, Component1)) # True\n print(isinstance(c2.f2, Component1)) # True\n\n print(isinstance(c3.f1, Component1)) # True\n print(isinstance(c3.f2, Component1)) # True\n\n print(c2.f1 == c2.f2) # False\n print(c3.f1 == c3.f2) # False\n print(c2.f1 == c3.f1) # False\n print(c2.f1 == c3.f2) # False\n print(c2.f2 == c3.f1) # False\n print(c2.f2 == c3.f2) # False\n\nIt is also possible to define custom scopes and add them to a context.\n\nHere it is an example of thread-local scope:\n\n.. code:: python\n\n import threading\n\n from yadi.context import Scope\n from yadi.context_impl import DEFAULT_CONTEXT\n from yadi.decorators import inject\n\n\n class ThreadLocalScope(Scope):\n def __init__(self):\n self._tl = threading.local()\n\n def get(self, key: str):\n return getattr(self._tl, key, None)\n\n def set(self, key: str, obj: object):\n setattr(self._tl, key, obj)\n\n @property\n def name(self):\n return 'threadlocal'\n\n @property\n def level(self):\n return 100\n\n\n DEFAULT_CONTEXT.add_scope(ThreadLocalScope())\n\n\n @inject(scope='threadlocal', name='a component 1')\n class Component1:\n pass\n\n\n c1 = DEFAULT_CONTEXT.get_bean('a component 1')\n c1_2 = DEFAULT_CONTEXT.get_bean('a component 1')\n\n thread_c1 = []\n c1_t = None\n\n\n def _f():\n global c1_t\n c1_t = DEFAULT_CONTEXT.get_bean('a component 1')\n print(c1_t == DEFAULT_CONTEXT.get_bean('a component 1')) # True\n thread_c1.append(c1_t)\n\n\n t = threading.Thread(target=_f)\n t.start()\n t.join()\n\n print(c1 == c1_2) # True\n print(c1 == c1_t) # False\n\n**Scoped proxies**\n\nLet's suppose to inject a thread-local scoped bean in a singleton. As a\nresult, different thread sharing the same singleton should not share the\nsame thread local bean, which is not possible.\n\nIn order to solve this issue, YADI creates a proxy around the injected\nbean that delegates any access to the current bean in the context.\n\nMore in general, scopes have a ``level`` attribute: if the injected bean\nhas a higher scope level than the container bean, the injected bean is\nwrapped into a scoped proxy.\n\nHere it is an example of scoped proxies (don't worry, you do not have to\ndo anything to make it work).\n\n.. code:: python\n\n import random\n import threading\n\n from yadi.bean_factories import _ScopedProxy\n from yadi.context import Scope\n from yadi.context_impl import DEFAULT_CONTEXT\n from yadi.decorators import inject\n from yadi.types import Yadi\n\n\n class ThreadLocalScope(Scope):\n def __init__(self):\n self._tl = threading.local()\n\n def get(self, key: str):\n return getattr(self._tl, key, None)\n\n def set(self, key: str, obj: object):\n setattr(self._tl, key, obj)\n\n @property\n def name(self):\n return 'threadlocal'\n\n @property\n def level(self):\n return 100\n\n\n DEFAULT_CONTEXT.add_scope(ThreadLocalScope())\n\n\n @inject(scope='threadlocal')\n class Component1:\n def __init__(self):\n self.object_id = random.randint(0, 1000000)\n\n\n @inject(name='a component')\n class Component2:\n def __init__(self, f1: Yadi[Component1]):\n self.f1 = f1\n\n\n component = DEFAULT_CONTEXT.get_bean('a component')\n component_thread_id = []\n print('Main thread, scoped proxy type', type(component.f1) == _ScopedProxy) # Main thread, scoped proxy type True\n\n\n def _f():\n component_thread = DEFAULT_CONTEXT.get_bean('a component')\n print('Subthread, scoped proxy type', type(component_thread.f1) == _ScopedProxy)\n component_thread_id.append(component_thread.f1.object_id)\n print(\n 'Subthread, bean id',\n component_thread.f1.object_id == DEFAULT_CONTEXT.get_bean('a component').f1.object_id)\n\n\n t = threading.Thread(target=_f)\n t.start()\n t.join() # Subthread, scoped proxy type True\n # Subthread, bean id True\n\n print('Main thread, bean id', component.f1.object_id == component_thread_id[0]) # Main thread, bean id False\n\nContexts\n--------\n\nAll the components are kept in a context.\n\nBy default, the ``inject`` decorator keeps the beans instances in\n``yadi.context_impl.DEFAULT_CONTEXT``.\n\nYou might want to instantiate a new context and pass it as a ``context``\nkeyword argument of ``inject`` decorator.\n\nLife cycle\n----------\n\nIt is possible to trigger beans whenever one of them is created. In\norder to define the method(s) to trigger, it is necessary to decorated\nthem with ``post_create``, as follows:\n\n.. code:: python\n\n from yadi.context_impl import DEFAULT_CONTEXT\n from yadi.decorators import inject, post_create\n from yadi.types import Yadi\n\n\n @inject()\n class Component1:\n pass\n\n @inject()\n class Component2:\n def __init__(self, c1: Yadi[Component1]):\n self.c1 = c1\n self.invoked_post_create = 0\n\n @post_create\n def finished_creating(self):\n print('Component 1:', self.c1) # Component 1: <__main__.Component1 object at 0x7f42e90d2e48>\n self.invoked_post_create += 1\n\n\n component_2 = DEFAULT_CONTEXT.get_bean(Component2) # type: Component2\n print('post_create invokations:', component_2.invoked_post_create) # post_create invokations: 1\n DEFAULT_CONTEXT.get_bean(Component2)\n print('post_create invokations:', component_2.invoked_post_create) # post_create invokations: 1\n\n.. |build status| image:: https://img.shields.io/travis/fcracker79/yadi/master.svg?style=flat-square\n :target: https://travis-ci.org/fcracker79/yadi\n.. |Pypi| image:: https://img.shields.io/pypi/v/yadi-framework.svg\n :target: https://img.shields.io/pypi/v/yadi-framework.svg", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/fcracker79/yadi", "keywords": "dependency injection", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "yadi-framework", "package_url": "https://pypi.org/project/yadi-framework/", "platform": "", "project_url": "https://pypi.org/project/yadi-framework/", "project_urls": { "Homepage": "https://github.com/fcracker79/yadi" }, "release_url": "https://pypi.org/project/yadi-framework/0.0.6/", "requires_dist": null, "requires_python": "", "summary": "YADI - Yet another dependency injection framework", "version": "0.0.6" }, "last_serial": 3663448, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "8d5eb06e5d083b4e41329f53c93d58e8", "sha256": "1b9a1832fe9f5e2ad29b8f0b6dac2b804afd6863956b3a9740699503e67b2f2c" }, "downloads": -1, "filename": "yadi-framework-0.0.1.tar.gz", "has_sig": false, "md5_digest": "8d5eb06e5d083b4e41329f53c93d58e8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4072, "upload_time": "2018-03-10T09:49:19", "url": "https://files.pythonhosted.org/packages/6c/3e/6c36531a4994daafa0e6db15137f9af9a856048ffc9638b8beecbe6a2ebb/yadi-framework-0.0.1.tar.gz" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "2cf3c2bd624d7c20c8d676e23389b92f", "sha256": "e496f0dbed01de2c251653c7b4b147e815010a8fe5c7917ce7b23e2104d7c2a1" }, "downloads": -1, "filename": "yadi-framework-0.0.2.tar.gz", "has_sig": false, "md5_digest": "2cf3c2bd624d7c20c8d676e23389b92f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4585, "upload_time": "2018-03-10T17:32:02", "url": "https://files.pythonhosted.org/packages/c2/64/9d94152ed5d07aaf9428562d65d6dc8dd610b460c318095e65f92cbac981/yadi-framework-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "f2b8834c288c9ce91f2691c7b3b36d04", "sha256": "9df581e6feb26f0589fe87e2a2f57e9f0d02317de3c6bf3e01cc63897c27ba69" }, "downloads": -1, "filename": "yadi-framework-0.0.3.tar.gz", "has_sig": false, "md5_digest": "f2b8834c288c9ce91f2691c7b3b36d04", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6005, "upload_time": "2018-03-11T14:43:05", "url": "https://files.pythonhosted.org/packages/49/11/2a178cabfc9644408afed742159a1bd221c2bd91fa0a65b2234cd674c09a/yadi-framework-0.0.3.tar.gz" } ], "0.0.4": [ { "comment_text": "", "digests": { "md5": "cc44d1b8a001ab525addc76a9b511a96", "sha256": "64efec51b0ab2637ac4ef7cde73188b38ce16da68a943b56969a215352a37ece" }, "downloads": -1, "filename": "yadi-framework-0.0.4.tar.gz", "has_sig": false, "md5_digest": "cc44d1b8a001ab525addc76a9b511a96", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5997, "upload_time": "2018-03-11T15:43:12", "url": "https://files.pythonhosted.org/packages/ee/dc/09d103cba36a1b94ab264df672f503306d25e54697b432d26bbf73dbcf9f/yadi-framework-0.0.4.tar.gz" } ], "0.0.6": [ { "comment_text": "", "digests": { "md5": "6e7877817d5054a17834bc4b8d5e0ce8", "sha256": "5993b66b90f90beda6c4ef1793c692aa6f755d4ff047f26364aafa072c6cb891" }, "downloads": -1, "filename": "yadi-framework-0.0.6.tar.gz", "has_sig": false, "md5_digest": "6e7877817d5054a17834bc4b8d5e0ce8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8313, "upload_time": "2018-03-12T22:21:57", "url": "https://files.pythonhosted.org/packages/ec/94/3fe1e7705820c74a773846602e191cf983ddbde23b1650c75a045bb7edff/yadi-framework-0.0.6.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "6e7877817d5054a17834bc4b8d5e0ce8", "sha256": "5993b66b90f90beda6c4ef1793c692aa6f755d4ff047f26364aafa072c6cb891" }, "downloads": -1, "filename": "yadi-framework-0.0.6.tar.gz", "has_sig": false, "md5_digest": "6e7877817d5054a17834bc4b8d5e0ce8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8313, "upload_time": "2018-03-12T22:21:57", "url": "https://files.pythonhosted.org/packages/ec/94/3fe1e7705820c74a773846602e191cf983ddbde23b1650c75a045bb7edff/yadi-framework-0.0.6.tar.gz" } ] }