{ "info": { "author": "Tomas Aparicio", "author_email": "", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Lisp", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": ".. image:: http://i.imgur.com/sbWr5Xv.png\n :width: 100%\n :alt: siringa logo\n :align: center\n\n\n|Build Status| |PyPI| |Coverage Status| |Documentation Status| |Stability| |Versions| |SayThanks|\n\nAbout\n-----\n\n``siringa`` (meaning ``syringe`` in Italian) is a minimalist, idiomatic `dependency injection`_ and `inversion of control`_ library\nfor Python_, implemented in Hy_, a homoiconic Lisp dialect for Python.\n\nTo get started, take a look to the `documentation`_, `API`_, `tutorial`_ and `examples`_.\n\nFeatures\n--------\n\n- Simple, idiomatic and versatile `programmatic API`_.\n- Annotation based dependency injection that is `PEP 3017`_ and `PEP 0484`_ friendly.\n- First-class decorator driven dependency injection and registering.\n- Ability to create multiple dependency containers.\n- Hierarchical dependency containers based on inheritance.\n- Dependency inference based on pattern-matching techniques.\n- First-class support for dependency mocking for better testing.\n- Detects cyclic dependencies (work in progress).\n- Small and (almost) dependency-free library.\n- Works with CPython 3+.\n\nDesign philosophy\n-----------------\n\n- Code instrumentation should be non-intrusive and idiomatic.\n- Explicitness over implicitness: dependencies and injections much be explicitly defined.\n- Python idiomatic: embrace decorators and type annotations.\n- Minimalism: less enables more.\n- Uniformity: there is only one way to declare and consume dependencies.\n- Predictability: developer intentions must persist based on explicitly defined intention.\n- Domain agnostic: do not enforce any domain-specific pattern.\n\nInstallation\n------------\n\nUsing ``pip`` package manager:\n\n.. code-block:: bash\n\n pip install --upgrade siringa\n\nOr install the latest sources from Github:\n\n.. code-block:: bash\n\n pip install -e git+git://github.com/h2non/siringa.git#egg=siringa\n\n\nTutorial\n--------\n\nImporting siringa\n^^^^^^^^^^^^^^^^^\n\n.. code-block:: python\n\n import siringa\n\nInstrumenting dependencies\n^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``siringa`` embraces type hints/arguments annotation Python syntax for\ndependency inference and pattern matching.\n\n.. code-block:: python\n\n @siringa.inject\n def task(x, y, logger: '!Logger'):\n logger.info('task called with arguments: {}, {}'.format(x, y))\n return x * y\n\n\nYou can optionally annotate dependencies via ``siringa`` type annotations:\n\n.. code-block:: python\n\n from siringa import A\n\n @siringa.inject\n def task(x, y, logger: A('Logger')):\n logger.info('task called with arguments: {}, {}'.format(x, y))\n return x * y\n\n\nFinally, for a DRYer approach you can simply annotate dependencies with ``!`` annotation flag.\n\nIn this case, the argument name expression will be used for dependency inference.\n\n.. code-block:: python\n\n from siringa import A\n\n @siringa.inject\n def task(x, y, Logger: '!'):\n Logger.info('task called with arguments: {}, {}'.format(x, y))\n return x * y\n\n\nRegistering dependencies\n^^^^^^^^^^^^^^^^^^^^^^^^\n\n``siringa`` allows you to rely on decorators for idiomatic dependencies registering.\n\nDependency name is dynamically inferred at registration time based on ``class`` or ``function`` name.\n\n.. code-block:: python\n\n @siringa.register\n class Logger(object):\n logger = logging.getLogger('siringa')\n\n @staticmethod\n def info(msg, *args, **kw):\n logger.info(msg, *args, **kw)\n\n\nHowever, you can define a custom dependency name by simply passing a ``string`` as first argument:\n\n.. code-block:: python\n\n @siringa.register('MyCustomLogger')\n class Logger(object):\n ...\n\nFinally, you can register dependencies with a traditional function call, such as:\n\n.. code-block:: python\n\n class Logger(object):\n pass\n\n siringa.register('MyCustomLogger', Logger)\n\n class compute(x, y):\n return x * y\n\n siringa.register('multiply', compute)\n\n\nInvocation\n^^^^^^^^^^\n\n``siringa`` wraps callable object in the transparent and frictionless way abstracting things for developers.\n\nYou can invoke or instantiate any dependency injection instrumented object\nas you do traditionally in raw Python code and ``siringa`` will do the rest for you inferring and pattern-matching\nrequired dependencies accordingly for you.\n\nBelow is an example of how simple it is:\n\n.. code-block:: python\n\n # Call our previously declared function in this tutorial.\n # Here, siringa will transparently inject required dependencies accordingly,\n # respecting the invokation arguments and order.\n task(2, 2) # => 4\n\nLet's demostrate this with a featured example:\n\n.. code-block:: python\n\n import siringa\n\n @siringa.register\n def mul(x, y):\n return x * y\n\n @siringa.register\n def mul2(x, mul: '!mul'):\n return mul(x, 2)\n\n @siringa.register\n def pow2(x):\n return x ** 2\n\n @siringa.inject\n def compute(x, pow: '!pow2', mul: '!mul2'):\n return pow(mul(x))\n\n compute(2) # => 16\n\n\nYou can also use the invocation API in case that the target object\nwas not properly instrumented as dependency:\n\n.. code-block:: python\n\n @siringa.register\n def mul2(x):\n return x * 2\n\n # Note that the function was not instrumented yet!\n def compute(x, mul: '!mul2'):\n return mul(x)\n\n siringa.invoke(compute, 2)\n\n\nCreate a new dependency container\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``siringa`` provides a built-in global dependency container for usability purposes,\nbut you can create as much containers as you want.\n\nIn the ``siringa`` idioms, this means creating a new dependency layer which provides its\nown container and dependency injection API, pretty much as the global package API.\n\nYou can create a new dependencies ``layer`` such as:\n\n.. code-block:: python\n\n layer = siringa.Layer('app')\n\n # Then you can use the standard API\n layer.register('print', print)\n\n # Then you can use the standard API\n @layer.inject\n def mul2(x, print: '!'):\n print('Argument:', x)\n return x * 2\n\n mul2(x)\n\nA dependency layer can inherit from a parent dependency layer.\n\nThis is particularly useful in order to create a hierarchy of dependency layers\nwhere you can consume and inject dependencies from a parent container.\n\n.. code-block:: python\n\n parent = siringa.Layer('parent')\n child = siringa.Layer('child', parent)\n\n # Register a sample dependency within parent\n @parent.register\n def mul2(x):\n return x * 2\n\n # Verify that the dependency is injectable from child layer\n parent.is_injectable('mul2') # True\n child.is_injectable('mul2') # True\n\n @child.inject\n def compute(x, mul: '!mul2'):\n return mul(x)\n\n compute(2) # => 2\n\nMocking dependencies\n^^^^^^^^^^^^^^^^^^^^\n\n``siringa`` allows you to define mocks for dependencies, which is particularly useful during testing:\n\n.. code-block:: python\n\n @siringa.register\n class DB(object):\n def query(self, sql):\n return ['john', 'mike']\n\n @siringa.mock('DB')\n class DBMock(object):\n def query(self, sql):\n return ['foo', 'bar']\n\n @siringa.inject\n def run(sql, db: '!DB'):\n return db().query(sql)\n\n # Test mock call\n assert run('SELECT name FROM foo') == ['foo', 'bar']\n\n # Once done, clear all the mocks\n siringa.unregister_mock('DB')\n\n # Or alternatively clear all the registed mocks within the container\n siringa.clear_mocks()\n\n # Test read call\n assert run('SELECT name FROM foo') == ['john', 'mike']\n\n\n.. _Python: http://python.org\n.. _Hy: http://docs.hylang.org/en/latest/\n.. _`dependency injection`: https://en.wikipedia.org/wiki/Dependency_injection\n.. _`inversion of control`: https://en.wikipedia.org/wiki/Inversion_of_control\n.. _`documentation`: http://siringa.readthedocs.io\n.. _`examples`: http://siringa.readthedocs.io/en/latest/examples.html\n.. _`API`: http://siringa.readthedocs.io/en/latest/api.html\n.. _`programmatic API`: http://siringa.readthedocs.io/en/latest/api.html\n.. _`tutorial`: http://siringa.readthedocs.io/en/latest/index.html#tutorial\n.. _`PEP 3017`: https://www.python.org/dev/peps/pep-3107/\n.. _`PEP 0484`: https://www.python.org/dev/peps/pep-0484/\n\n.. |Build Status| image:: https://travis-ci.org/h2non/siringa.svg?branch=master\n :target: https://travis-ci.org/h2non/siringa\n.. |PyPI| image:: https://img.shields.io/pypi/v/siringa.svg?maxAge=2592000?style=flat-square\n :target: https://pypi.python.org/pypi/siringa\n.. |Coverage Status| image:: https://coveralls.io/repos/github/h2non/siringa/badge.svg?branch=master\n :target: https://coveralls.io/github/h2non/siringa?branch=master\n.. |Documentation Status| image:: https://readthedocs.org/projects/siringa/badge/?version=latest\n :target: http://siringa.readthedocs.io/en/latest/?badge=latest\n.. |Stability| image:: https://img.shields.io/pypi/status/siringa.svg\n :target: https://pypi.python.org/pypi/siringa\n :alt: Stability\n.. |Versions| image:: https://img.shields.io/pypi/pyversions/siringa.svg\n :target: https://pypi.python.org/pypi/siringa\n :alt: Python Versions\n.. |SayThanks| image:: https://img.shields.io/badge/Say%20Thanks!-%F0%9F%A6%89-1EAEDB.svg\n :target: https://saythanks.io/to/h2non\n :alt: Say Thanks\n\n\nHistory\n=======\n\nv0.1.3 / 2017-04-25\n-------------------\n\n * fix(invoke): missing export symbol at public level\n * refactor(docs): update disclaimer note\n * fix(docs): remove unused tutorial.rst file\n * refactor(Makefile): use --commit when bumping version\n\nv0.1.2 / 2017-04-25\n-------------------\n\n * feat(examples): add inject flag example\n * fix(injector): process inject flag \"!\" based annotations accordingly\n * fix(register): return decorated injectable callable object, if needed\n * fix(register): return decorated injectable callable object, if needed\n * refactor(analyzer): use method access notation\n * refactor(docs): typo in design philosophy section\n * fix(docs): typo in rst syntax\n * fix(examples): type on mocking example comment\n\nv0.1.1 / 2017-04-24\n-------------------\n\n * fix(core): handle not present __init__ member in classes. feat(examples): add mocking example\n * fix(docs): type in about section\n * fix(setup.py): package description\n\nv0.1.0 (2017-04-23)\n-------------------\n\n* First version (beta).\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/h2non/siringa", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "siringa", "package_url": "https://pypi.org/project/siringa/", "platform": "any", "project_url": "https://pypi.org/project/siringa/", "project_urls": { "Homepage": "https://github.com/h2non/siringa" }, "release_url": "https://pypi.org/project/siringa/0.1.3/", "requires_dist": null, "requires_python": "", "summary": "Minimalist and idiomatic dependency injection library", "version": "0.1.3" }, "last_serial": 2828878, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "533f5756f38ea7ce492ffe6ec42d81a5", "sha256": "a839fa6a5048723535ddd0bdf695ea609542b670794dfcfb5c6d7a9ce09c8717" }, "downloads": -1, "filename": "siringa-0.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "533f5756f38ea7ce492ffe6ec42d81a5", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 15994, "upload_time": "2017-04-23T22:26:56", "url": "https://files.pythonhosted.org/packages/7b/41/44912158191263a16912d802d8d9fe58362e33e2c28c7f3a2ff84f09f833/siringa-0.1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "35d731f5b0a90c687ba5c688d811ccbe", "sha256": "02604ed0f4a4b24e8c5d828be2e6d46befbc44ace5cd5cea1feb06b8a604df8a" }, "downloads": -1, "filename": "siringa-0.1.0.tar.gz", "has_sig": false, "md5_digest": "35d731f5b0a90c687ba5c688d811ccbe", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8202, "upload_time": "2017-04-23T22:26:51", "url": "https://files.pythonhosted.org/packages/93/47/eff26a4e620297ba606519f56193935d58d9f7b3ee066e72b50a44aa4b09/siringa-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "1a3609a550635477822872321583b46b", "sha256": "e25cd0b18eb58d26322ea6fa26a4984e5f42f1ee669a4e34cce3de93ac4ee183" }, "downloads": -1, "filename": "siringa-0.1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "1a3609a550635477822872321583b46b", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 16321, "upload_time": "2017-04-23T23:18:36", "url": "https://files.pythonhosted.org/packages/6f/45/b59dc61905956372eaa0778c484b5b8fe7011aa8d654f4033a34d49d26c8/siringa-0.1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7b7b6414b0763d9cbe52251759679cb1", "sha256": "6677c87af125f9628110be7ecb08b4c1720d0137ca91c802ac3866f9a344883a" }, "downloads": -1, "filename": "siringa-0.1.1.tar.gz", "has_sig": false, "md5_digest": "7b7b6414b0763d9cbe52251759679cb1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8494, "upload_time": "2017-04-23T23:18:31", "url": "https://files.pythonhosted.org/packages/7a/ad/b9c3229ab245b872d85e87b5eb775875422fb11a4b987e26579e8e7d41c5/siringa-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "87ab5fdbf64a46b1c9f4f44991e68a9f", "sha256": "5885754dae4759f3125fd7b88a9547371c34d195c84ed2bb63e819822c4c32a0" }, "downloads": -1, "filename": "siringa-0.1.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "87ab5fdbf64a46b1c9f4f44991e68a9f", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 16668, "upload_time": "2017-04-25T10:29:41", "url": "https://files.pythonhosted.org/packages/39/e1/7e0a0d59443d666791900c9758d97c88349b62392e75458ed50ae3e60ee4/siringa-0.1.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4e0f52effcddc1df0600e7bd46cc0d04", "sha256": "41b36dc9eb1da814f2500e2a428eb97e047a0e0b40fbe59ba1d5ff679ccf3fe5" }, "downloads": -1, "filename": "siringa-0.1.2.tar.gz", "has_sig": false, "md5_digest": "4e0f52effcddc1df0600e7bd46cc0d04", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8778, "upload_time": "2017-04-25T10:29:36", "url": "https://files.pythonhosted.org/packages/25/c4/96901b9bb633408ac44ae5f1c1516f046cfc5ccd728eed73049139fff4c3/siringa-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "a5a1b5379aabedb9caf613f29634844e", "sha256": "698c9951885cdf4b99970dd702232a2a6c34293d1a1d23c02774d609d8d5733d" }, "downloads": -1, "filename": "siringa-0.1.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a5a1b5379aabedb9caf613f29634844e", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 16774, "upload_time": "2017-04-25T13:46:38", "url": "https://files.pythonhosted.org/packages/96/01/3f44bbcf82cb6fdbb4a8b49077301455775e1dea04f62999e4c0228a77bd/siringa-0.1.3-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "fe8aa5afd9534b89272752e38bb1e79c", "sha256": "54f40ce7c3722fcf96d128b2c4e99b8f91124c8cee41b4d2321d1715238e6fb7" }, "downloads": -1, "filename": "siringa-0.1.3.tar.gz", "has_sig": false, "md5_digest": "fe8aa5afd9534b89272752e38bb1e79c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8934, "upload_time": "2017-04-25T13:46:34", "url": "https://files.pythonhosted.org/packages/b6/94/8d5c6f3855ce0848d6cff7a555ed50bbd0099937c09ae1bfe4a6729c2f06/siringa-0.1.3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "a5a1b5379aabedb9caf613f29634844e", "sha256": "698c9951885cdf4b99970dd702232a2a6c34293d1a1d23c02774d609d8d5733d" }, "downloads": -1, "filename": "siringa-0.1.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a5a1b5379aabedb9caf613f29634844e", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 16774, "upload_time": "2017-04-25T13:46:38", "url": "https://files.pythonhosted.org/packages/96/01/3f44bbcf82cb6fdbb4a8b49077301455775e1dea04f62999e4c0228a77bd/siringa-0.1.3-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "fe8aa5afd9534b89272752e38bb1e79c", "sha256": "54f40ce7c3722fcf96d128b2c4e99b8f91124c8cee41b4d2321d1715238e6fb7" }, "downloads": -1, "filename": "siringa-0.1.3.tar.gz", "has_sig": false, "md5_digest": "fe8aa5afd9534b89272752e38bb1e79c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8934, "upload_time": "2017-04-25T13:46:34", "url": "https://files.pythonhosted.org/packages/b6/94/8d5c6f3855ce0848d6cff7a555ed50bbd0099937c09ae1bfe4a6729c2f06/siringa-0.1.3.tar.gz" } ] }