Skip to main content

Simple yet powerful dependency injection framework!

Project description

Snake DI

test pypi python

Source Code: https://github.com/lionsoon/snake_di
Features:

  • Lightweight - no external dependencies (only typing_extensions)
  • Based on type hints - no configuration required, less boilerplate
  • Pytest integration - writing unit tests was never so easy!
  • yeild powered - just yeild your component and then write closing steps
  • async support - work with async resources

Install

pip install snake-di

Example

Let's assume we have following services.py file, witch contains components we want to build.
For example to be more "real-world" we will use httpx and sqlalchemy packages:

# services.py
import ...

@dataclass
class Settings:
    db_uri: str

@dataclass
class Database:
    engine: AsyncEngine

@dataclass
class Application:
    client: httpx.AsyncClient
    database: Database
    
    async def run(self): ...

The main concept of snake_di is Provider (and AsyncProvider if we need async).
Providers consist of factories - callables that build components. Factories are included to the provider using provider.include_factory method.
All factory arguments should be annotated. And return type should be specified either by return annotation, or by service_type argument (see example below).

Let's create an AsyncProvider for our services in provider.py file:

# provider.py
import httpx
from snake_di import AsyncProvider
from sqlalchemy.ext.asyncio import create_async_engine, AsyncEngine

from services import Settings, Database, Application

provider = AsyncProvider()


@provider.include_factory
def provide_settings() -> Settings:
    return Settings(db_uri="sqlite://...")


@provider.include_factory(service_type=AsyncEngine)
async def provide_engine(settings: Settings):
    engine = create_async_engine(settings.db_uri)
    yield engine
    await engine.dispose()


provider.include_factory(Database, service_type=Database)
provider.include_factory(Application, service_type=Application)

Now in main.py we can use provider.build_async method to construct Container in this way:

async with provider.build_async() as container:
    application = container[Application]

Container is dict-like object that maps service types to service values. After leaving async with context all services in Container will be closed (for example await engine.dispose() will be run on AsyncEngine).
Container also has container.partial_solve method that works similar to functools.partial and solves those arguments whose types container contains.
Full example:

# main.py
from provider import provider
from services import Database, Application

async def do_some_work(database: Database, some_data):
    ...

async def main():
    async with provider.build_async() as container:
        partial_solved_do_some_work = container.partial_solve(do_some_work)
        await partial_solved_do_some_work(some_data="some_data")
        
        await container[Application].run()

Test

Let's write some tests using same example and pytest

from snake_di.pytest import pytest_provide_async

from provider import provider
from services import Database
from main import do_some_work


@Provider.from_factory(service_type=Database)
def mock_database():
    return ...


@pytest_provide_async(provider | mock_database)
@pytest.mark.asyncio
async def test_do_some_work(mocked_database: Database, any_usual_fixture):
    await do_some_work(mocked_database, some_data="some_data")
    assert mocked_database.something_to_assert()

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

snake-di-0.0.1.tar.gz (13.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

snake_di-0.0.1-py3-none-any.whl (10.2 kB view details)

Uploaded Python 3

File details

Details for the file snake-di-0.0.1.tar.gz.

File metadata

  • Download URL: snake-di-0.0.1.tar.gz
  • Upload date:
  • Size: 13.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-requests/2.28.2

File hashes

Hashes for snake-di-0.0.1.tar.gz
Algorithm Hash digest
SHA256 8ec5d7052e4dc6473980469bec4f4579d92ffa5210fa7b6b39281adb6b1aad8d
MD5 3b031f49f2087bde96947a3c991a8a96
BLAKE2b-256 bf9f5ea065fc014ffc776345aacd63df985801bc21b9228fb70b4d1c8292e08d

See more details on using hashes here.

File details

Details for the file snake_di-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: snake_di-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 10.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-requests/2.28.2

File hashes

Hashes for snake_di-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 762b161f463e4df455fba120ddfbf7da72689e76fe0922c0f014c0990f6df634
MD5 31c683e97c484cbabd9e439add73dd03
BLAKE2b-256 6d20bb3516ca19694352ca6fb3b334ded0d1105bd64c4c092423af5c74dabd7a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page