{ "info": { "author": "Ilya Lebedev", "author_email": "lebedev.games.mail@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8" ], "description": "# Botox\n\nBotox Injector is a dependency injection implementation based on Python type annotations.\nIt helps deliver the configured functional objects, decreasing coupling between a class and its dependencies.\n\n### Delivery \n\nGlobal variables? Proxy objects? Application context?\n\nThere should be one (and preferably only one) obvious way to do it.\n\nBotox helps you isolate a class from the impact of different design changes and defects. \nMeaning that, instead of thinking about interdependence between application modules\nyou will now find yourself spending your time having to focus a class on the task it is designed for.\n\n### Configuration\n\nMonkey-patching? Decorators?\n\nExplicit is better than implicit.\n\nBotox allows a class the flexibility of being configurable.\nThe class rely on dependencies interface that he expect.\nExplicit configurations can be written separately for different\nsituations that require different implementations of dependencies.\n\n### Usage\n\nNow is better than never.\n\nBotox doesn\u2019t require any change in code behavior it can be applied to legacy code as a refactoring.\n\n## Installation\n\nInstall and update using [pip](https://pip.pypa.io/en/stable/quickstart/):\n\n```bash\npip install -U botox-di\n```\n\n## Examples\n\n### Class Injection\n\nCan be used to reduce boilerplate code in the application classes since \nall work to initialize or set up dependencies is handled separately.\n\n```python\nfrom botox import Injector\n\nclass PaymentService:\n ...\n\nclass BillingService:\n ...\n\nclass SalesService:\n\n def __init__(self, payment_service: PaymentService, billing_service: BillingService):\n self.payment_service = payment_service\n self.billing_service = billing_service\n\ninjector = Injector()\ninjector.prepare(PaymentService)\ninjector.prepare(BillingService)\ninjector.prepare(SalesService)\n\nsales = injector.deliver(SalesService)\n\nassert isinstance(sales.payment_service, PaymentService)\nassert isinstance(sales.billing_service, BillingService)\n```\n\nThe result is class that is easier to unit test in \nisolation using stubs or mock objects that simulate other objects.\n\n```python\ninjector.prepare(PaymentService, PaymentServiceStub)\n```\n\n### Value Injection\n\nCan be used when exactly one object is needed to coordinate actions across the system.\n\n```python\nfrom botox import Injector\n\nclass AppSettings:\n ...\n\nsettings = AppSettings()\n\ninjector = Injector()\ninjector.prepare(AppSettings, settings)\n\nassert injector.deliver(AppSettings) is settings\n```\n\n### Lambda Injection\n\nCan be used to wrap Proxy objects in legacy code as refactoring.\n\n```python\nfrom botox import Injector\nfrom flask import g\nfrom sqlalchemy.orm import Session\n\ninjector = Injector()\ninjector.prepare(Session, lambda: g.session)\n```\n\n### Function Injection\n\nCan be used to make factory functions with dependencies.\n\n```python\nfrom botox import Injector\n\ndef create_api_client(settings: Settings):\n return ApiClient(settings.base_url, settings.key)\n\ninjector = Injector()\ninjector.prepare(Settings)\ninjector.prepare(ApiClient, create_api_client)\n```\n\n### Sequence Injection\n\nCan be used to provide collection of dependencies.\n\n```python\nclass PaymentService(metaclass=ABCMeta):\n name: str\n\nclass GooglePayService(PaymentService):\n ...\n\nclass ApplePayService(PaymentService):\n ...\n\nclass FlowService:\n\n def __init__(self, payment_services: List[PaymentService]):\n self.payment_services = payment_services\n\n def get_available_payment_methods(self):\n for payment_service in self.payment_services:\n yield payment_service.name\n\ninjector = Injector()\ninjector.prepare(GooglePayService)\ninjector.prepare(ApplePayService)\ninjector.prepare(List[PaymentService], [GooglePayService, ApplePayService])\ninjector.prepare(FlowService)\n\n```\n\n### Celery\n\nYou can define a different application base task class to deliver dependencies into a task call.\n\n```python\nfrom celery import Celery, Task\nfrom botox import Injector\n\nclass Calculator:\n def add(self, x, y):\n return x + y\n\nclass AppTask(Task):\n def __call__(self, *args, **kwargs):\n run = self.app.injector.inject(self.run, skip=len(args))\n return run(*args, **kwargs)\n\napp = Celery('tasks', broker='pyamqp://guest@localhost//', task_cls=AppTask)\napp.injector = Injector()\napp.injector.prepare(Calculator)\n\n@app.task\ndef add(x, y, calculator: Calculator):\n return calculator.add(x, y)\n```\n\n### aiohttp\n\nYou can use a middleware to deliver dependencies into a request handler. Asynchronous functions also supported.\n\n```python\nfrom aiohttp import web\nfrom botox import Injector\n\nclass HelloService:\n def get_hello_message(self, name):\n return f'Hello, {name}!'\n\nasync def handle(request, service: HelloService):\n name = request.match_info.get('name', 'Anonymous')\n text = service.get_hello_message(name)\n return web.Response(text=text)\n\n@web.middleware\nasync def dependency_injection(request, handler):\n handler = request.app.injector.inject(handler, skip=1)\n return await handler(request)\n\napp = web.Application(middlewares=[dependency_injection])\napp.injector = Injector()\napp.injector.prepare(HelloService)\napp.add_routes([\n web.get('/', handle),\n web.get('/{name}', handle)\n])\n\nweb.run_app(app)\n```\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://gitlab.com/lebedev.games/botox-di", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "botox-di", "package_url": "https://pypi.org/project/botox-di/", "platform": "any", "project_url": "https://pypi.org/project/botox-di/", "project_urls": { "Code": "https://gitlab.com/lebedev.games/botox-di", "Homepage": "https://gitlab.com/lebedev.games/botox-di", "Issue tracker": "https://gitlab.com/lebedev.games/botox-di/issues" }, "release_url": "https://pypi.org/project/botox-di/1.5.0/", "requires_dist": null, "requires_python": ">=3.6", "summary": "Botox is a dependency injection implementation based on Python type annotations.", "version": "1.5.0" }, "last_serial": 5002393, "releases": { "1.2.0": [ { "comment_text": "", "digests": { "md5": "14ac7fd1597171f88820d8f3238ecc88", "sha256": "5821a3849f050eb317ee19e0eb84cdcbeb7e5d250dc04af4562a0e32e2cfec88" }, "downloads": -1, "filename": "botox_di-1.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "14ac7fd1597171f88820d8f3238ecc88", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 1958, "upload_time": "2018-07-26T18:57:14", "url": "https://files.pythonhosted.org/packages/e6/4d/8b65d80fb418ab5b71bb862c2fd68112c7cf8d51977488e59d99ad865578/botox_di-1.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1f51a9a499d97fa55622d461937d69be", "sha256": "22eaf2948b773cb940dc4b22cdd526374d69d686ddc2174c04c06ff1f0973b8b" }, "downloads": -1, "filename": "botox-di-1.2.0.tar.gz", "has_sig": false, "md5_digest": "1f51a9a499d97fa55622d461937d69be", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1352, "upload_time": "2018-07-26T18:57:15", "url": "https://files.pythonhosted.org/packages/93/50/e0f201c739bccfce98ddbe04cd5a83dc9fa5f5dd9f72bd1de4c2243060a0/botox-di-1.2.0.tar.gz" } ], "1.3.0": [ { "comment_text": "", "digests": { "md5": "0db48e1bb51de44f34827ddc923e0935", "sha256": "363b69427dc1948f74615832a3923a21714ad6ad7daea4814356f41330c8c6fd" }, "downloads": -1, "filename": "botox_di-1.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "0db48e1bb51de44f34827ddc923e0935", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 1997, "upload_time": "2018-08-01T11:44:45", "url": "https://files.pythonhosted.org/packages/15/42/10fd22dbcb72f09e99fbc771f42624e42744f19f690196854f925a487db8/botox_di-1.3.0-py3-none-any.whl" } ], "1.4.0": [ { "comment_text": "", "digests": { "md5": "93f71d0f37a75f23866f89fb3ee7e963", "sha256": "efe1622455a38cea3a53f8fb1ab590ad25a262bbf0fd90652c88681d5da239a1" }, "downloads": -1, "filename": "botox_di-1.4.0-py3-none-any.whl", "has_sig": false, "md5_digest": "93f71d0f37a75f23866f89fb3ee7e963", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 4354, "upload_time": "2018-09-21T12:11:27", "url": "https://files.pythonhosted.org/packages/00/90/5614648cfa2b381c630962ed3127bdf9e0afa89d7dd0358c0ea1c5f77f5a/botox_di-1.4.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "449bdc43bd13069f3f5da68f1a14b34c", "sha256": "ded50a2c5eccc13d811e662dbf9f2920d4341d188c24fee9cc5f157c4d0817d4" }, "downloads": -1, "filename": "botox-di-1.4.0.tar.gz", "has_sig": false, "md5_digest": "449bdc43bd13069f3f5da68f1a14b34c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4374, "upload_time": "2018-09-21T12:11:28", "url": "https://files.pythonhosted.org/packages/76/5e/f661443d65efc43b763e6b32b75c5fafee15883678fd26f20c6bf0ef4fc9/botox-di-1.4.0.tar.gz" } ], "1.4.1": [ { "comment_text": "", "digests": { "md5": "047f128752d8a564f87dabe8d5371138", "sha256": "47d549b081420e5ba1e7ff946571b66c95361ec8a03808b5d2d05331d7a81f7f" }, "downloads": -1, "filename": "botox_di-1.4.1-py3-none-any.whl", "has_sig": false, "md5_digest": "047f128752d8a564f87dabe8d5371138", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 4411, "upload_time": "2018-09-28T09:48:59", "url": "https://files.pythonhosted.org/packages/17/06/cd418e639957325f1f93f4df811d88524183c12105a097791083f1f55448/botox_di-1.4.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c361326d7881f6fe67506818b19dbf5d", "sha256": "683b07b9aa4254d362d1fcfa8ad75031df25231542d02c4a89c5d8acf5428ce5" }, "downloads": -1, "filename": "botox-di-1.4.1.tar.gz", "has_sig": false, "md5_digest": "c361326d7881f6fe67506818b19dbf5d", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 4473, "upload_time": "2018-09-28T09:49:00", "url": "https://files.pythonhosted.org/packages/f2/eb/4017a9dcf0a5b2d9888c167ed5cbdd945b86278c45070d917c1af3318de1/botox-di-1.4.1.tar.gz" } ], "1.4.2": [ { "comment_text": "", "digests": { "md5": "5a5c90fc10580a8badb5b2367c616d39", "sha256": "2d00933fc24794a7c3f6c346081cfb4224ddee6ab953f9c70662b4d256353f61" }, "downloads": -1, "filename": "botox_di-1.4.2-py3-none-any.whl", "has_sig": false, "md5_digest": "5a5c90fc10580a8badb5b2367c616d39", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 4700, "upload_time": "2018-09-28T13:53:53", "url": "https://files.pythonhosted.org/packages/58/af/54e87f6f255b8c4c859ee532ceccfa195f8856164364058203563f6242a8/botox_di-1.4.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "19aa6d82389acb2c2c6a443f399bf5b2", "sha256": "00662a07e73d61c726c9f4f88baba68c249bca9f2daf3b839edefb79c81eb513" }, "downloads": -1, "filename": "botox-di-1.4.2.tar.gz", "has_sig": false, "md5_digest": "19aa6d82389acb2c2c6a443f399bf5b2", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 4767, "upload_time": "2018-09-28T13:53:54", "url": "https://files.pythonhosted.org/packages/8d/48/a6225e84f65db8be640d376ea02b334fb9bec0d59b5f7b606c858ad0acf9/botox-di-1.4.2.tar.gz" } ], "1.4.3": [ { "comment_text": "", "digests": { "md5": "07b648d862a3bc5522c93ff03825c52e", "sha256": "136a9db13077f83dcff0ee326c1f5200adfc8aaf4cf4631fc02fcecff1948852" }, "downloads": -1, "filename": "botox_di-1.4.3-py3-none-any.whl", "has_sig": false, "md5_digest": "07b648d862a3bc5522c93ff03825c52e", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 5817, "upload_time": "2018-10-03T07:51:49", "url": "https://files.pythonhosted.org/packages/41/36/f4aefa659572c4de5b666897c2db80740e42aa4c98b3d0c263bacdb3394e/botox_di-1.4.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a12e3bde497582fac7cea4b5f792160c", "sha256": "3c11883dbed67396f0c8a627906c45f12cd37fcf7d2c7b3b984081db892ddfd4" }, "downloads": -1, "filename": "botox-di-1.4.3.tar.gz", "has_sig": false, "md5_digest": "a12e3bde497582fac7cea4b5f792160c", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 5113, "upload_time": "2018-10-03T07:51:50", "url": "https://files.pythonhosted.org/packages/5e/13/379c3824a38383214c9e6995bbca5f2d57f1cb8b8958bd3f10be9e33b761/botox-di-1.4.3.tar.gz" } ], "1.4.4": [ { "comment_text": "", "digests": { "md5": "d3c4a4c803957dd4f3719f937cdbfc73", "sha256": "9e8ec2ecf6272fbf1c94ed50993abfb1aaab7867d2d3445b9164c9538bfb263d" }, "downloads": -1, "filename": "botox_di-1.4.4-py3-none-any.whl", "has_sig": false, "md5_digest": "d3c4a4c803957dd4f3719f937cdbfc73", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 5983, "upload_time": "2018-11-27T14:22:07", "url": "https://files.pythonhosted.org/packages/54/33/36c61475bb716e11ae214c935c0eca7bbf7d8f77778b5b538386b870b1a1/botox_di-1.4.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "5d0da4b6ee2a06382bdca17f52c5f2e5", "sha256": "e96ecaa55dfc3eae64a1542129fe14e0c12beeb29571035971834a039ab6d92b" }, "downloads": -1, "filename": "botox-di-1.4.4.tar.gz", "has_sig": false, "md5_digest": "5d0da4b6ee2a06382bdca17f52c5f2e5", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 5314, "upload_time": "2018-11-27T14:22:10", "url": "https://files.pythonhosted.org/packages/01/32/d83aa0f6e60324933f747abd0a4ea062a7303d38b41e2afc8cfb6a4191ba/botox-di-1.4.4.tar.gz" } ], "1.5.0": [ { "comment_text": "", "digests": { "md5": "cdbb82948afa5c01e6731ae740f7f947", "sha256": "9b79dc84614f438bf693f142b10c6766eddca205760249594276963ed6110f8e" }, "downloads": -1, "filename": "botox_di-1.5.0-py3-none-any.whl", "has_sig": false, "md5_digest": "cdbb82948afa5c01e6731ae740f7f947", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 6200, "upload_time": "2019-03-29T09:52:47", "url": "https://files.pythonhosted.org/packages/a3/1b/a6af27122568fe35217309c3d91665227bddd8fc2cfdbcb5c454d5d6f872/botox_di-1.5.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "82a8f09759d06bba6e3171bd0879e0af", "sha256": "0213e6c284ff7b9bceeac452336bd059d15a21b12bb134f5205788ef015de31e" }, "downloads": -1, "filename": "botox-di-1.5.0.tar.gz", "has_sig": false, "md5_digest": "82a8f09759d06bba6e3171bd0879e0af", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 5601, "upload_time": "2019-03-29T09:52:48", "url": "https://files.pythonhosted.org/packages/1f/a8/8db70c72cbd4c893b354d23d13a250f0d3c88dbb99f0faad60a0ed363487/botox-di-1.5.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "cdbb82948afa5c01e6731ae740f7f947", "sha256": "9b79dc84614f438bf693f142b10c6766eddca205760249594276963ed6110f8e" }, "downloads": -1, "filename": "botox_di-1.5.0-py3-none-any.whl", "has_sig": false, "md5_digest": "cdbb82948afa5c01e6731ae740f7f947", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 6200, "upload_time": "2019-03-29T09:52:47", "url": "https://files.pythonhosted.org/packages/a3/1b/a6af27122568fe35217309c3d91665227bddd8fc2cfdbcb5c454d5d6f872/botox_di-1.5.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "82a8f09759d06bba6e3171bd0879e0af", "sha256": "0213e6c284ff7b9bceeac452336bd059d15a21b12bb134f5205788ef015de31e" }, "downloads": -1, "filename": "botox-di-1.5.0.tar.gz", "has_sig": false, "md5_digest": "82a8f09759d06bba6e3171bd0879e0af", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 5601, "upload_time": "2019-03-29T09:52:48", "url": "https://files.pythonhosted.org/packages/1f/a8/8db70c72cbd4c893b354d23d13a250f0d3c88dbb99f0faad60a0ed363487/botox-di-1.5.0.tar.gz" } ] }