<div align="center">
<h1>Wireup</h1>
<p>Modern Dependency Injection for Python.</p>
[![GitHub](https://img.shields.io/github/license/maldoinc/wireup)](https://github.com/maldoinc/wireup)
[![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/maldoinc/wireup/run_all.yml)](https://github.com/maldoinc/wireup)
[![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/maldoinc/wireup?label=Code+Climate)](https://codeclimate.com/github/maldoinc/wireup)
[![Coverage](https://img.shields.io/codeclimate/coverage/maldoinc/wireup?label=Coverage)](https://codeclimate.com/github/maldoinc/wireup)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/wireup)](https://pypi.org/project/wireup/)
[![PyPI - Version](https://img.shields.io/pypi/v/wireup)](https://pypi.org/project/wireup/)
<p>Wireup is a performant, concise, and easy-to-use dependency injection container for Python 3.8+.</p>
<p><a target="_blank" href="https://maldoinc.github.io/wireup">📚 Documentation</a> | <a target="_blank" href="https://github.com/maldoinc/wireup-demo">🎮 Demo Application</a></p>
</div>
---
## ⚡ Key Features
* Inject services and configuration.
* Interfaces and abstract classes.
* Factory pattern.
* Singleton and transient dependencies.
* Framework-agnostic.
* Apply the container as a decorator.
* Service Locator.
* Simplified use with [Django](https://maldoinc.github.io/wireup/latest/integrations/django/),
[Flask](https://maldoinc.github.io/wireup/latest/integrations/flask/), and
[FastAPI](https://maldoinc.github.io/wireup/latest/integrations/fastapi/).
* Share service layer between cli and api.
## 📋 Quickstart
**1. Set up**
```python
import wireup
container = wireup.create_container(
# Parameters serve as application/service configuration.
parameters={
"redis_url": os.environ["APP_REDIS_URL"],
"weather_api_key": os.environ["APP_WEATHER_API_KEY"]
},
# Top-level modules containing service registrations.
service_modules=[services]
)
```
**2. Declare services**
Use a declarative syntax to describe services, and let the container handle the rest.
```python
from wireup import service, Inject
@service # ⬅️ Decorator tells the container this is a service.
class KeyValueStore:
# Inject the value of the parameter during creation. ⬇️
def __init__(self, dsn: Annotated[str, Inject(param="redis_url")]):
self.client = redis.from_url(dsn)
def get(self, key: str) -> Any: ...
def set(self, key: str, value: Any): ...
@service
@dataclass # Can be used alongside dataclasses to simplify init boilerplate.
class WeatherService:
# Inject the value of the parameter to this field. ⬇️
api_key: Annotated[str, Inject(param="weather_api_key")]
kv_store: KeyValueStore # ⬅️ This will be injected automatically.
def get_forecast(self, lat: float, lon: float) -> WeatherForecast:
...
```
Use factories (sync and async) if service requires special initialization or cleanup.
```python
@service
async def make_db(dsn: Annotated[str, Inject(param="db_dsn")]) -> AsyncIterator[Connection]:
async with Connection(dsn) as conn:
yield conn
```
*Note*: If you use generator factories, call `container.{close,aclose}` on termination for the necessary cleanup to take place.
**3. Use**
Use the container as a service locator or apply it as a decorator to have it perform injection.
```python
weather_service = container.get(WeatherService)
```
```python
@app.get("/weather/forecast")
# ⬇️ Decorate functions to perform Dependency Injection.
# No longer required when using the provided integrations.
@container.autowire
def get_weather_forecast_view(weather_service: WeatherService, request):
return weather_service.get_forecast(request.lat, request.lon)
```
**4. Test**
Wireup does not patch your services which means they can be instantiated and tested independently of the container.
To substitute dependencies on autowired targets such as views in a web application you can override dependencies with new ones on the fly.
```python
with container.override.service(WeatherService, new=test_weather_service):
response = client.get("/weather/forecast")
```
Requests to inject `WeatherService` during the lifetime of the context manager
will result in `test_weather_service` being injected instead.
## Share service layer betwen app/api and cli
Many projects have a web application as well as a cli in the same project which
provides useful commands.
Wireup makes it extremely easy to share the service layer between them without
code duplication. For examples refer to [maldoinc/wireup-demo](https://github.com/maldoinc/wireup-demo).
## Installation
```bash
# Install using poetry:
poetry add wireup
# Install using pip:
pip install wireup
```
## 📚 Documentation
For more information [check out the documentation](https://maldoinc.github.io/wireup)
## 🎮 Demo application
A demo flask application is available at [maldoinc/wireup-demo](https://github.com/maldoinc/wireup-demo)
Raw data
{
"_id": null,
"home_page": "https://github.com/maldoinc/wireup",
"name": "wireup",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.8",
"maintainer_email": null,
"keywords": "flask, django, injector, dependency injection, dependency injection container, dependency injector",
"author": "Aldo Mateli",
"author_email": "aldo.mateli@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/8c/01/647595a28272524c5ffc9c766e0c9e061df3f1677ed607ff4202ea957fcc/wireup-0.12.0.tar.gz",
"platform": null,
"description": "<div align=\"center\">\n<h1>Wireup</h1>\n<p>Modern Dependency Injection for Python.</p>\n\n[![GitHub](https://img.shields.io/github/license/maldoinc/wireup)](https://github.com/maldoinc/wireup)\n[![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/maldoinc/wireup/run_all.yml)](https://github.com/maldoinc/wireup)\n[![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/maldoinc/wireup?label=Code+Climate)](https://codeclimate.com/github/maldoinc/wireup)\n[![Coverage](https://img.shields.io/codeclimate/coverage/maldoinc/wireup?label=Coverage)](https://codeclimate.com/github/maldoinc/wireup)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/wireup)](https://pypi.org/project/wireup/)\n[![PyPI - Version](https://img.shields.io/pypi/v/wireup)](https://pypi.org/project/wireup/)\n\n<p>Wireup is a performant, concise, and easy-to-use dependency injection container for Python 3.8+.</p>\n<p><a target=\"_blank\" href=\"https://maldoinc.github.io/wireup\">\ud83d\udcda Documentation</a> | <a target=\"_blank\" href=\"https://github.com/maldoinc/wireup-demo\">\ud83c\udfae Demo Application</a></p>\n</div>\n\n---\n\n## \u26a1 Key Features\n* Inject services and configuration.\n* Interfaces and abstract classes.\n* Factory pattern.\n* Singleton and transient dependencies.\n* Framework-agnostic.\n* Apply the container as a decorator.\n* Service Locator.\n* Simplified use with [Django](https://maldoinc.github.io/wireup/latest/integrations/django/),\n[Flask](https://maldoinc.github.io/wireup/latest/integrations/flask/), and \n[FastAPI](https://maldoinc.github.io/wireup/latest/integrations/fastapi/).\n* Share service layer between cli and api.\n\n## \ud83d\udccb Quickstart\n\n**1. Set up**\n\n```python\nimport wireup\n\ncontainer = wireup.create_container(\n # Parameters serve as application/service configuration.\n parameters={\n \"redis_url\": os.environ[\"APP_REDIS_URL\"],\n \"weather_api_key\": os.environ[\"APP_WEATHER_API_KEY\"]\n },\n # Top-level modules containing service registrations.\n service_modules=[services]\n)\n```\n\n**2. Declare services**\n\nUse a declarative syntax to describe services, and let the container handle the rest.\n\n```python\nfrom wireup import service, Inject\n\n@service # \u2b05\ufe0f Decorator tells the container this is a service.\nclass KeyValueStore:\n # Inject the value of the parameter during creation. \u2b07\ufe0f \n def __init__(self, dsn: Annotated[str, Inject(param=\"redis_url\")]):\n self.client = redis.from_url(dsn)\n\n def get(self, key: str) -> Any: ...\n def set(self, key: str, value: Any): ...\n\n\n@service\n@dataclass # Can be used alongside dataclasses to simplify init boilerplate.\nclass WeatherService:\n # Inject the value of the parameter to this field. \u2b07\ufe0f\n api_key: Annotated[str, Inject(param=\"weather_api_key\")]\n kv_store: KeyValueStore # \u2b05\ufe0f This will be injected automatically.\n\n def get_forecast(self, lat: float, lon: float) -> WeatherForecast:\n ...\n```\n\nUse factories (sync and async) if service requires special initialization or cleanup.\n\n```python\n@service\nasync def make_db(dsn: Annotated[str, Inject(param=\"db_dsn\")]) -> AsyncIterator[Connection]:\n async with Connection(dsn) as conn:\n yield conn\n```\n\n*Note*: If you use generator factories, call `container.{close,aclose}` on termination for the necessary cleanup to take place.\n\n\n**3. Use**\n\nUse the container as a service locator or apply it as a decorator to have it perform injection.\n\n```python\nweather_service = container.get(WeatherService)\n```\n\n```python\n@app.get(\"/weather/forecast\")\n# \u2b07\ufe0f Decorate functions to perform Dependency Injection.\n# No longer required when using the provided integrations.\n@container.autowire\ndef get_weather_forecast_view(weather_service: WeatherService, request):\n return weather_service.get_forecast(request.lat, request.lon)\n```\n\n**4. Test**\n\nWireup does not patch your services which means they can be instantiated and tested independently of the container.\n\nTo substitute dependencies on autowired targets such as views in a web application you can override dependencies with new ones on the fly.\n\n```python\nwith container.override.service(WeatherService, new=test_weather_service):\n response = client.get(\"/weather/forecast\")\n```\n\nRequests to inject `WeatherService` during the lifetime of the context manager \nwill result in `test_weather_service` being injected instead.\n\n## Share service layer betwen app/api and cli\n\nMany projects have a web application as well as a cli in the same project which\nprovides useful commands.\n\nWireup makes it extremely easy to share the service layer between them without\ncode duplication. For examples refer to [maldoinc/wireup-demo](https://github.com/maldoinc/wireup-demo).\n\n## Installation\n\n```bash\n# Install using poetry:\npoetry add wireup\n\n# Install using pip:\npip install wireup\n```\n\n## \ud83d\udcda Documentation\n\nFor more information [check out the documentation](https://maldoinc.github.io/wireup)\n\n## \ud83c\udfae Demo application\n\nA demo flask application is available at [maldoinc/wireup-demo](https://github.com/maldoinc/wireup-demo)\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Python Dependency Injection Library",
"version": "0.12.0",
"project_urls": {
"Homepage": "https://github.com/maldoinc/wireup"
},
"split_keywords": [
"flask",
" django",
" injector",
" dependency injection",
" dependency injection container",
" dependency injector"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "fb6fd82c8600884d710efd269d30a6a189a09d1c76e3434b2033d9525fc81b9f",
"md5": "9a0479c98733116e9ea9eb59cc1febc9",
"sha256": "1e01c0dd59f6b28fa4a3fec3f6750c1fae812451bb0c8031f240c0ca6c254b5f"
},
"downloads": -1,
"filename": "wireup-0.12.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "9a0479c98733116e9ea9eb59cc1febc9",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.8",
"size": 29883,
"upload_time": "2024-10-27T19:38:14",
"upload_time_iso_8601": "2024-10-27T19:38:14.325482Z",
"url": "https://files.pythonhosted.org/packages/fb/6f/d82c8600884d710efd269d30a6a189a09d1c76e3434b2033d9525fc81b9f/wireup-0.12.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "8c01647595a28272524c5ffc9c766e0c9e061df3f1677ed607ff4202ea957fcc",
"md5": "75ff4fa436e32327e9bb53ee6b35f1eb",
"sha256": "9500946139aba07f741d19ad0c14b58fff48397811c9656f086bceff31df176e"
},
"downloads": -1,
"filename": "wireup-0.12.0.tar.gz",
"has_sig": false,
"md5_digest": "75ff4fa436e32327e9bb53ee6b35f1eb",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.8",
"size": 24289,
"upload_time": "2024-10-27T19:38:16",
"upload_time_iso_8601": "2024-10-27T19:38:16.172939Z",
"url": "https://files.pythonhosted.org/packages/8c/01/647595a28272524c5ffc9c766e0c9e061df3f1677ed607ff4202ea957fcc/wireup-0.12.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-27 19:38:16",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "maldoinc",
"github_project": "wireup",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "wireup"
}