{ "info": { "author": "Asaf Semo, Dmitry Voronenkov", "author_email": "asafsemo@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": "# Inversion of control (IoC) for Humans - written in Python\n[Inversion of control](https://en.wikipedia.org/wiki/Inversion_of_control)\n\n## How to use it\npip install flying-ioc\n\n``` {.sourceCode .python}\nfrom flying_ioc import *\n\nioc = IocManager()\n\nioc.set_class(cls=HelperWrapper, singleton=True)\nioc.set_class(cls=GRHelperService, singleton=True)\nioc.set_class(name='api', cls=GRApiClient, singleton=True, thread_local=True)\n\ngr_service: GRHelperService = ioc.GRHelperService\ngr_service.start()\n```\n\n## Features\n* Support getting an object as an attribute of IoC manager\n* Initializing a class argument by the argument's class name and if not present by the argument name\n* Support for inheritance - initializing arguments needed by parent classes\n* Support mapping of values, classes, factories\n* Support configuration of mapping like singleton, class per thread\n* Support for @NotInject decorator\n\n## Attribute\n``` {.sourceCode .python}\ngr_service: GRHelperService = ioc.GRHelperService\ngr_service.start()\n```\n### Initializing a class\n``` {.sourceCode .python}\nclass ClassA:\n pass\n\nclass ClassB:\n pass\n\nclass ClassC:\n pass\n\nclass ExampleClass:\n def __init__(self, arg1: ClassA, arg2, arg3: ClassC):\n assert arg1.__class__ == ClassA\n assert arg2.__class__ == ClassB\n assert arg3.__class__ == ClassC\n\n\ndef test_arguments():\n ioc = IocManager()\n ioc.set_class(cls=ClassA)\n ioc.set_class(name='arg2', cls=ClassB)\n ioc.set_class(name='arg3', cls=ClassC)\n\n ioc.set_class(cls=ExampleClass)\n\n assert ioc.ExampleClass.__class__ == ExampleClass\n```\n\n## Support for inheritance\n``` {.sourceCode .python}\nclass ClassA:\n pass\n\nclass ClassB:\n pass\n\nclass ClassC:\n pass\n\nclass ParentD:\n def __init__(self, arg1: ClassA, **kwargs):\n self._arg1 = arg1\n\nclass ParentE(ParentD):\n def __init__(self, arg2: ClassB, **kwargs):\n super().__init__(**kwargs)\n self._arg2 = arg2\n\nclass ExampleClass(ParentE):\n def __init__(self, arg3: ClassC, **kwargs):\n super().__init__(**kwargs)\n assert self._arg1.__class__ == ClassA\n assert self._arg2.__class__ == ClassB\n assert arg3.__class__ == ClassC\n\ndef test_arguments():\n ioc = IocManager()\n ioc.set_class(cls=ClassA)\n ioc.set_class(cls=ClassB)\n ioc.set_class(cls=ClassC)\n\n ioc.set_class(cls=ExampleClass)\n\n assert ioc.ExampleClass.__class__ == ExampleClass\n```\n\n## Values\n``` {.sourceCode .python}\nclass ClassA:\n pass\n\n\nclass ExampleClass:\n def __init__(self, value_text, value_class):\n assert value_text == 'Some text'\n assert value_class.__class__ == ClassA\n\n\ndef test_arguments():\n ioc = IocManager()\n ioc.set_value(name='value_text', value='Some text')\n ioc.set_value(name='value_class', value=ClassA())\n\n ioc.set_class(cls=ExampleClass)\n\n assert ioc.ExampleClass.__class__ == ExampleClass\n```\n\n## Factory\n``` {.sourceCode .python}\nclass ClassA:\n pass\n\nclass ClassB:\n pass\n\nclass ClassC:\n pass\n\nclass Factory(IocFactory):\n @staticmethod\n def get_instance(ioc_manager: IocManager, name: str, frame_info: inspect.FrameInfo):\n if frame_info.function == 'test_factory_1':\n return ioc_manager.ClassA\n\n if name == 'factory1':\n return ioc_manager.ClassB\n\n return ioc_manager.ClassC\n\nioc = IocManager()\nioc.set_class(cls=ClassA)\nioc.set_class(cls=ClassB)\nioc.set_class(cls=ClassC)\nioc.set_factory(name='factory1', cls=Factory)\nioc.set_factory(name='factory2', cls=Factory)\n\ndef test_factory_1():\n assert ioc.factory1.__class__ == ClassA\n assert ioc.factory2.__class__ == ClassA\n\ndef test_factory_2():\n assert ioc.factory1.__class__ == ClassB\n assert ioc.factory2.__class__ == ClassC\n```\n## Singleton\n``` {.sourceCode .python}\nclass ClassA:\n pass\n\nclass ClassB:\n pass\n\ndef test_singleton():\n ioc = IocManager()\n ioc.set_class(cls=ClassA)\n ioc.set_class(cls=ClassB, singleton=True)\n\n assert ioc.ClassA != ioc.ClassA\n assert ioc.ClassB == ioc.ClassB\n```\n## Class per thread\n``` {.sourceCode .python}\nclass ClassA:\n pass\n\ndef _set_vars(ioc: IocManager, storage: dict):\n def wrapped():\n storage['singleton1'] = ioc.singleton1\n storage['singleton2'] = ioc.singleton2\n\n return wrapped\n\ndef test_class_per_thread():\n ioc = IocManager()\n\n ioc.set_class(name='singleton1', cls=ClassA, singleton=True)\n ioc.set_class(name='singleton2', cls=ClassA, singleton=True, thread_local=True)\n\n assert ioc.singleton1 == ioc.singleton1\n assert ioc.singleton2 == ioc.singleton2\n\n thread_storage = {}\n thread = threading.Thread(target=_set_vars(ioc, thread_storage))\n thread.start()\n thread.join()\n\n assert ioc.singleton1 == thread_storage['singleton1']\n assert ioc.singleton2 != thread_storage['singleton2']\n```\n## @NotInject decorator\nIn the following example, the @NotInject decorator prevents the IoC manager from adding arg1 to the kwargs argument when it initializes the ExampleClass, arg1 argument is needed by the parent class.\n\nRemoving the @NotInject decorator in this example will result in an exception.\n\nThe @NonInject decorator takes a list of argument names to skip in the initializing process.\n``` {.sourceCode .python}\nclass ClassA:\n pass\n\nclass ClassB:\n pass\n\nclass Parent:\n def __init__(self, arg1: ClassA, **kwargs):\n super().__init__(**kwargs)\n self._arg1 = arg1\n\n@NotInject(['arg1'])\nclass ExampleClass(Parent):\n def __init__(self, arg2: ClassB, **kwargs):\n arg1 = ClassA()\n super().__init__(arg1, **kwargs)\n assert self._arg1 == arg1\n assert arg2.__class__ == ClassB\n\ndef test_not_inject():\n ioc = IocManager()\n ioc.set_class(cls=ClassA)\n ioc.set_class(cls=ClassB)\n\n ioc.set_class(cls=ExampleClass)\n\n assert ioc.ExampleClass.__class__ == ExampleClass\n```\n## Exceptions\nIoC Manager raises two types of exceptions:\n* AttributeError - when trying to get an undefined attribute from the IoC Manager\n* TypeError - in the following cases:\n * IoC Manager is missing a container definition needed by the initialization of a\n class or it parent class \n * While initializing a class, multiple instances of the same argument are provided \n to it's parent class - by the user and also injected by IoC Manager. This issue \n can be resolve using the @NotInject decorator \n\n``` {.sourceCode .python}\nclass ClassA:\n pass\n\nclass ClassB:\n pass\n\nclass ClassC:\n pass\n\nclass Parent:\n def __init__(self, arg1: ClassA, **kwargs):\n super().__init__(**kwargs)\n self._arg1 = arg1\n\nclass ExampleClass1(Parent):\n def __init__(self, arg2: ClassB, **kwargs):\n arg1 = ClassA()\n super().__init__(arg1, **kwargs)\n assert self._arg1 == arg1\n assert arg2.__class__ == ClassB\n\nclass ExampleClass2:\n def __init__(self, arg1: ClassC):\n pass\n\nclass ExampleClass3(ExampleClass2):\n def __init__(self, **kwargs):\n super().__init__(**kwargs)\n\nioc = IocManager()\nioc.set_class(cls=ClassA)\nioc.set_class(cls=ClassB)\n\ndef test_exception_container_not_defined():\n with pytest.raises(AttributeError) as e:\n ioc.NotExists\n assert e.value.args[0] == \"Name 'NotExists' does not exist\"\n\ndef test_exception_missing_not_inject():\n with pytest.raises(TypeError) as e:\n ioc.set_class(cls=ExampleClass1)\n ioc.ExampleClass1\n assert e.value.args[0] == \"__init__() got multiple values for argument 'arg1'\"\n\ndef test_exception_arg_is_not_defined():\n with pytest.raises(TypeError) as e:\n ioc.set_class(cls=ExampleClass2)\n ioc.ExampleClass2\n assert e.value.args[0].args[0] == \"Can't get a container neither by class name ClassC, neither by arg name arg1\"\n\ndef test_exception_arg_for_parent_is_not_defined():\n with pytest.raises(TypeError) as e:\n ioc.set_class(cls=ExampleClass3)\n ioc.ExampleClass3\n assert e.value.args[0] == \"__init__() missing 1 required positional argument: 'arg1'\"\n```\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/ClanPlay/Python_IoC", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "flying-ioc", "package_url": "https://pypi.org/project/flying-ioc/", "platform": "", "project_url": "https://pypi.org/project/flying-ioc/", "project_urls": { "Homepage": "https://github.com/ClanPlay/Python_IoC" }, "release_url": "https://pypi.org/project/flying-ioc/1.0.3/", "requires_dist": null, "requires_python": "", "summary": "IoC for Humans", "version": "1.0.3" }, "last_serial": 4845750, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "0016d23e17a0fa29b71ab375103da5b6", "sha256": "c80c9279e17a4de4bb6bc2ab614345abf2b5719b82caa86cb54e811c13618d06" }, "downloads": -1, "filename": "flying_ioc-1.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "0016d23e17a0fa29b71ab375103da5b6", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 4971, "upload_time": "2019-02-20T12:25:19", "url": "https://files.pythonhosted.org/packages/a9/b7/ad804b3c4f982bd9f9439c735569386925d9c332644ba3c293d10332b35c/flying_ioc-1.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "bd8fb590b636fd6097dbadc877170e05", "sha256": "9cbd31fde2f83f57407181f7d71898523153ce839cd6c2556b0bf2641cb9b9a3" }, "downloads": -1, "filename": "flying_ioc-1.0.0.tar.gz", "has_sig": false, "md5_digest": "bd8fb590b636fd6097dbadc877170e05", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4038, "upload_time": "2019-02-20T12:25:22", "url": "https://files.pythonhosted.org/packages/71/90/670e1a31f942908cff6ac4b4f6c55f1217d22cb6abcbdb2ef31ade9b3ad9/flying_ioc-1.0.0.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "17e85e09ba42f8a301056de83f21b66d", "sha256": "33a75a4cf94293ae38ba969ab516b53d3e0297fcf4cc10f3b60661c582830d62" }, "downloads": -1, "filename": "flying_ioc-1.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "17e85e09ba42f8a301056de83f21b66d", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7944, "upload_time": "2019-02-20T12:49:47", "url": "https://files.pythonhosted.org/packages/f2/e0/c4bfd1fe8e7da34719cbfde0f31f9b735f26749c305c81ae02b640ea6d2a/flying_ioc-1.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "0be44aec228df8dea4c984ddc524f0d3", "sha256": "893007456859763e9c547c9be3e91951851d1776f9a4fd1eba2aac0791adde7f" }, "downloads": -1, "filename": "flying_ioc-1.0.1.tar.gz", "has_sig": false, "md5_digest": "0be44aec228df8dea4c984ddc524f0d3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6053, "upload_time": "2019-02-20T12:49:49", "url": "https://files.pythonhosted.org/packages/2d/59/d9097ad57c0adce42080d33a7e037aad2492bd6a4a4b9a372caf36f05888/flying_ioc-1.0.1.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "45115a907716d29a09d08f27f09a1a4b", "sha256": "fd5bf1692a299017a6f3c57d882482bdeab8354f4aeb3554cdf340dbfaba2dd4" }, "downloads": -1, "filename": "flying_ioc-1.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "45115a907716d29a09d08f27f09a1a4b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7868, "upload_time": "2019-02-20T13:16:21", "url": "https://files.pythonhosted.org/packages/f0/99/b799f7b5905e55b6c32a90188fd10760f2307992e5bc62caa957c170106e/flying_ioc-1.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b3f3fed0b2874a2744acb03ff0b5b58f", "sha256": "4141ef0ebf7165d57a7a507d62cf9588e0549c9eeebe89f0303b0155d2fac55b" }, "downloads": -1, "filename": "flying_ioc-1.0.2.tar.gz", "has_sig": false, "md5_digest": "b3f3fed0b2874a2744acb03ff0b5b58f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5953, "upload_time": "2019-02-20T13:16:22", "url": "https://files.pythonhosted.org/packages/69/fc/7a15055ca11d573dae5fe5d824e9048ee82b9df997f091571385f0a182c3/flying_ioc-1.0.2.tar.gz" } ], "1.0.3": [ { "comment_text": "", "digests": { "md5": "2191fedbdb2a40c37b5b9622c47e6646", "sha256": "e984ea521bbfaf7bf10ece1e28a01861c3820b4330a4a130d0ac4750aec4bf24" }, "downloads": -1, "filename": "flying_ioc-1.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "2191fedbdb2a40c37b5b9622c47e6646", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 8085, "upload_time": "2019-02-20T14:25:03", "url": "https://files.pythonhosted.org/packages/bc/db/5fc3c9079da2dc73221da0fc8033acf8eb3fd6e69173a150dd3873c641b7/flying_ioc-1.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "fea5d7543ea37f5a284972cb9056e490", "sha256": "dfc1edb464ca4ff7546512a0c4984555fc752508c9a32cde40598d283023e632" }, "downloads": -1, "filename": "flying_ioc-1.0.3.tar.gz", "has_sig": false, "md5_digest": "fea5d7543ea37f5a284972cb9056e490", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6248, "upload_time": "2019-02-20T14:25:04", "url": "https://files.pythonhosted.org/packages/19/2c/eccef2c59c7af6028737414362b39c0372397571bb49aeff88c23312403c/flying_ioc-1.0.3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "2191fedbdb2a40c37b5b9622c47e6646", "sha256": "e984ea521bbfaf7bf10ece1e28a01861c3820b4330a4a130d0ac4750aec4bf24" }, "downloads": -1, "filename": "flying_ioc-1.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "2191fedbdb2a40c37b5b9622c47e6646", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 8085, "upload_time": "2019-02-20T14:25:03", "url": "https://files.pythonhosted.org/packages/bc/db/5fc3c9079da2dc73221da0fc8033acf8eb3fd6e69173a150dd3873c641b7/flying_ioc-1.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "fea5d7543ea37f5a284972cb9056e490", "sha256": "dfc1edb464ca4ff7546512a0c4984555fc752508c9a32cde40598d283023e632" }, "downloads": -1, "filename": "flying_ioc-1.0.3.tar.gz", "has_sig": false, "md5_digest": "fea5d7543ea37f5a284972cb9056e490", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6248, "upload_time": "2019-02-20T14:25:04", "url": "https://files.pythonhosted.org/packages/19/2c/eccef2c59c7af6028737414362b39c0372397571bb49aeff88c23312403c/flying_ioc-1.0.3.tar.gz" } ] }