<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/1c/d0/7918e9d8d9e0f646117641e0a34006ce9aaa1ee2205308fcd7db13f62629/wireup-0.13.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.13.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": "308f2e6e8bc4f0b432b0198042d482275207b83fe17847d908824c6eda2160cb",
"md5": "932e97b5e4114c4fd89205c1ac2cef43",
"sha256": "5c261dbc089836485b7ebf7ef94366f952832bccecac66d3502dd912ff3cf5ba"
},
"downloads": -1,
"filename": "wireup-0.13.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "932e97b5e4114c4fd89205c1ac2cef43",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.8",
"size": 30379,
"upload_time": "2024-11-16T13:13:28",
"upload_time_iso_8601": "2024-11-16T13:13:28.771079Z",
"url": "https://files.pythonhosted.org/packages/30/8f/2e6e8bc4f0b432b0198042d482275207b83fe17847d908824c6eda2160cb/wireup-0.13.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "1cd07918e9d8d9e0f646117641e0a34006ce9aaa1ee2205308fcd7db13f62629",
"md5": "d7a8a069c6444e929ee38b342ac46814",
"sha256": "2d61247039d819a5bfba2d490761344b56fa81ff7d3ee80c4fc53213cb0f9e31"
},
"downloads": -1,
"filename": "wireup-0.13.0.tar.gz",
"has_sig": false,
"md5_digest": "d7a8a069c6444e929ee38b342ac46814",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.8",
"size": 24651,
"upload_time": "2024-11-16T13:13:30",
"upload_time_iso_8601": "2024-11-16T13:13:30.432653Z",
"url": "https://files.pythonhosted.org/packages/1c/d0/7918e9d8d9e0f646117641e0a34006ce9aaa1ee2205308fcd7db13f62629/wireup-0.13.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-11-16 13:13:30",
"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"
}