# pyautowire ![PyPI](https://img.shields.io/pypi/v/pyautowire) ![Linting and Tests](https://github.com/twaslowski/py-autowire/actions/workflows/test.yml/badge.svg)
Lightweight dependency injection for Python that autowires into _anything_.
## The Quick Pitch
Do you love `pytest` fixtures? Do you wish you could have the flexibility of fixtures without actually having to worry
about the complications of using Dependency Injection? Then `pyautowire` is for you!
## The Longer Version
Dependency Inversion is a common design pattern across a variety of languages. It most often occurs in object-oriented
programming languages, where you can choose from a variety of flavours, such as constructor injection, setter injection,
or interface injection [[1]](https://martinfowler.com/articles/injection.html#FormsOfDependencyInjection).
The most popular dependency injection library in Python is the aptly named `Dependency Injector`
[[2]](https://github.com/ets-labs/python-dependency-injector), which comes with a massive variety of configuration
options.
I personally primarily use Python for medium-sized pet projects, and I found those configuration options to be a bit
too complex for my usecase. Specifically, there are cases where I don't necessarily want to turn everything into a
class to inject dependencies into; sometimes I just want a lightweight function that I can inject values into.
Enter `pyautowire`, for all of your _good enough™️_ dependency injection needs.
## Installation
You can install `pyautowire` via pip:
```bash
pip install pyautowire
```
or via Poetry:
```bash
poetry add pyautowire
```
It is compatible with Python3.7 and above.
## Usage
To use `pyautowire`, you need to have your injectable classes inherit from the `Injectable` class and use the
`@autowire` decorator on the methods you want to inject values into. For example:
```python
from pyautowire import Injectable, autowire
class Configuration(Injectable):
def __init__(self, config_value: str):
self.config_value = config_value
@autowire('configuration')
def my_function(configuration: Configuration):
print(configuration.config_value)
if __name__ == '__main__':
configuration = Configuration('Hello, World!').register()
my_function()
```
You can see that you can call `my_function` without passing in any arguments; `pyautowire` will automatically inject them.
Admittedly, this is a rather silly example, since you could have just passed the configuration value as an argument to `my_function`.
However, imagine you can use the `configuration` object across your entire application without ever using an `import`,
having to store a global configuration object somewhere, or pass it around as an argument.
Note that you **have** to call `register()` on your `Injectable` objects before you can use them.
You also **have** to specify all the arguments you would like to inject into your function in the `@autowire` decorator.
Given enough time, I might come up with a smarter solution to automatically handle that, but for now, this works fine.
## Constructor Injection
`pyautowire` _technically_ supports constructor injection. I'll be honest: This is a hack at the moment. But if you
really want to do it, it works:
```python
class MyDatabase(Injectable):
@autowire('configuration')
def __init__(self, configuration: Configuration):
self.db_url = configuration.db_url
self.db_user = configuration.db_user
self.db_password = configuration.db_password
```
# Should I use this?
As a rule of thumb: For small projects where you want to avoid the complexity of a full-blown dependency injection library,
while getting all of its benefits: sure. It is genuinely fun to work with, and it'll accelerate your workflow in rapid prototyping.
For larger projects, I would recommend using a more established library like `Dependency Injector`. The amount of complexity
this library can handle is very limited.
Raw data
{
"_id": null,
"home_page": "https://github.com/twaslowski/py-autowire",
"name": "pyautowire",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.7",
"maintainer_email": null,
"keywords": "dependency injection, autowire, fixture",
"author": "Tobias Waslowski",
"author_email": "tobias.waslowski@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/7b/84/19c3521597a77216e8b04f8c1496097a48a8b7e14b211d236c8cbf4cdca8/pyautowire-0.3.1.tar.gz",
"platform": null,
"description": "# pyautowire ![PyPI](https://img.shields.io/pypi/v/pyautowire) ![Linting and Tests](https://github.com/twaslowski/py-autowire/actions/workflows/test.yml/badge.svg)\n\nLightweight dependency injection for Python that autowires into _anything_.\n\n## The Quick Pitch\n\nDo you love `pytest` fixtures? Do you wish you could have the flexibility of fixtures without actually having to worry\nabout the complications of using Dependency Injection? Then `pyautowire` is for you!\n\n## The Longer Version\n\nDependency Inversion is a common design pattern across a variety of languages. It most often occurs in object-oriented\nprogramming languages, where you can choose from a variety of flavours, such as constructor injection, setter injection,\nor interface injection [[1]](https://martinfowler.com/articles/injection.html#FormsOfDependencyInjection).\n\nThe most popular dependency injection library in Python is the aptly named `Dependency Injector`\n[[2]](https://github.com/ets-labs/python-dependency-injector), which comes with a massive variety of configuration\noptions.\n\nI personally primarily use Python for medium-sized pet projects, and I found those configuration options to be a bit\ntoo complex for my usecase. Specifically, there are cases where I don't necessarily want to turn everything into a\nclass to inject dependencies into; sometimes I just want a lightweight function that I can inject values into.\nEnter `pyautowire`, for all of your _good enough\u2122\ufe0f_ dependency injection needs.\n\n## Installation\n\nYou can install `pyautowire` via pip:\n\n```bash\npip install pyautowire\n```\n\nor via Poetry:\n\n```bash\npoetry add pyautowire\n```\n\nIt is compatible with Python3.7 and above.\n\n## Usage\n\nTo use `pyautowire`, you need to have your injectable classes inherit from the `Injectable` class and use the\n`@autowire` decorator on the methods you want to inject values into. For example:\n\n```python\nfrom pyautowire import Injectable, autowire\n\nclass Configuration(Injectable):\n def __init__(self, config_value: str):\n self.config_value = config_value\n\n@autowire('configuration')\ndef my_function(configuration: Configuration):\n print(configuration.config_value)\n\nif __name__ == '__main__':\n configuration = Configuration('Hello, World!').register()\n my_function()\n```\n\nYou can see that you can call `my_function` without passing in any arguments; `pyautowire` will automatically inject them.\n\nAdmittedly, this is a rather silly example, since you could have just passed the configuration value as an argument to `my_function`.\nHowever, imagine you can use the `configuration` object across your entire application without ever using an `import`,\nhaving to store a global configuration object somewhere, or pass it around as an argument.\n\nNote that you **have** to call `register()` on your `Injectable` objects before you can use them.\nYou also **have** to specify all the arguments you would like to inject into your function in the `@autowire` decorator.\nGiven enough time, I might come up with a smarter solution to automatically handle that, but for now, this works fine.\n\n## Constructor Injection\n\n`pyautowire` _technically_ supports constructor injection. I'll be honest: This is a hack at the moment. But if you\nreally want to do it, it works:\n\n```python\nclass MyDatabase(Injectable):\n @autowire('configuration')\n def __init__(self, configuration: Configuration):\n self.db_url = configuration.db_url\n self.db_user = configuration.db_user\n self.db_password = configuration.db_password\n```\n\n# Should I use this?\n\nAs a rule of thumb: For small projects where you want to avoid the complexity of a full-blown dependency injection library,\nwhile getting all of its benefits: sure. It is genuinely fun to work with, and it'll accelerate your workflow in rapid prototyping.\n\nFor larger projects, I would recommend using a more established library like `Dependency Injector`. The amount of complexity\nthis library can handle is very limited.\n",
"bugtrack_url": null,
"license": "gpl3",
"summary": "Good enough autowiring for Python",
"version": "0.3.1",
"project_urls": {
"Documentation": "https://github.com/twaslowski/py-autowire",
"Homepage": "https://github.com/twaslowski/py-autowire",
"Repository": "https://github.com/twaslowski/py-autowire"
},
"split_keywords": [
"dependency injection",
" autowire",
" fixture"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "bebd7b06475c63a31d74db3bfa4a379e511b4d92a655af248d3a4fdf7e2fce9a",
"md5": "cf08dcf24b0ed84f2149bdcfbbf792cb",
"sha256": "a19452733e082e5788a83e67730ec30de2b26d8a42063ca1df101b63c8990f67"
},
"downloads": -1,
"filename": "pyautowire-0.3.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "cf08dcf24b0ed84f2149bdcfbbf792cb",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.7",
"size": 17861,
"upload_time": "2024-04-09T07:39:48",
"upload_time_iso_8601": "2024-04-09T07:39:48.114534Z",
"url": "https://files.pythonhosted.org/packages/be/bd/7b06475c63a31d74db3bfa4a379e511b4d92a655af248d3a4fdf7e2fce9a/pyautowire-0.3.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "7b8419c3521597a77216e8b04f8c1496097a48a8b7e14b211d236c8cbf4cdca8",
"md5": "04ed53e0c1881ca6236da9e142f809f0",
"sha256": "6d0a6e4a2887e74a363aec16f95c040b4d780092be9fcdf8d6cc31d0f1ac6375"
},
"downloads": -1,
"filename": "pyautowire-0.3.1.tar.gz",
"has_sig": false,
"md5_digest": "04ed53e0c1881ca6236da9e142f809f0",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.7",
"size": 16509,
"upload_time": "2024-04-09T07:39:49",
"upload_time_iso_8601": "2024-04-09T07:39:49.285262Z",
"url": "https://files.pythonhosted.org/packages/7b/84/19c3521597a77216e8b04f8c1496097a48a8b7e14b211d236c8cbf4cdca8/pyautowire-0.3.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-04-09 07:39:49",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "twaslowski",
"github_project": "py-autowire",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "pyautowire"
}