wireup


Namewireup JSON
Version 0.13.0 PyPI version JSON
download
home_pagehttps://github.com/maldoinc/wireup
SummaryPython Dependency Injection Library
upload_time2024-11-16 13:13:30
maintainerNone
docs_urlNone
authorAldo Mateli
requires_python<4.0,>=3.8
licenseMIT
keywords flask django injector dependency injection dependency injection container dependency injector
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <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"
}
        
Elapsed time: 0.37189s