Skip to main content

Simple dependency injection for Python.

Project description

PyJudo

Overview

PyJudo is a python library to support the dependency injection (DI) pattern. It facilitates the registration of services, resolves dependencies, and manages the lifecycle of services throughout your application. By decoupling service creation from business logic, PyJudo promotes cleaner, more maintainable, and testable codebases.

The goal of PyJudo is to provide a lightweight, easy-to-use and simple mechanism to let developers employ a dependency injection pattern into their application's implementation. It takes inspiration from the Microsoft .NET Dependency Injection library of providing a container for services.

It's as simple as:

  • Define what a service does (e.g. with an abstract class) - this is the "interface"
  • Create a service container
  • Create a concrete implementation of the interface
  • Register the concrete implementation against the interface with the container
  • Retrieve an instance of the interface from the container
  • (or specify the interface in another service's constructor)

Installation

PyJudo is available on PyPi; install using:

pip install pyjudo

Features

  • Services container:

    • Provides a container to register and resolve dependencies.
  • Service dependency injection:

    • Automatically resolves and injects dependencies for service (classes) retrieved from the service container.
  • Callable dependency injection:

    • Automatically resolve dependencies for callables (functions, methods, class methods & static methods), decorated with @container.inject
  • Service lifetimes:

    • Singleton: A single instance created and shared across the container.
    • Scoped: A single instance created and shared within a scope.
    • Transient: A new instance created every time the service is retrieved.
  • Disposable services:

    • Automatically disposes of services that implement the Disposable protocol when a scope ends.
    • Provides an IDisposable abstract to safeguard against the use of "disposed" instances.
  • Factories:

    • Registering services with factories, just register the callable.
    • Add dependencies as factories using Factory[MyService] in the constructor.
  • Circular dependencies:

    • Detects and prevents circular dependencies during service resolution.
  • Thread safety:

    • Ensures safe use in multi-threaded environments by managing scopes and service resolutions per thread.
  • Context management

    • Supports the use of context managers (i.e. with ...) to manage service scopes and their respective service lifetimes.

Quick Start

The quick start example below gives a brief overview of using PyJudo; for a more in-depth guide, please see the Examples.

1. Define Interfaces and Implementations

Start by defining service interfaces (abstract classes) and their concrete implementations:

from abc import ABC, abstractmethod
from pyjudo import ServiceContainer

# Define service interfaces
class IDatabaseConnection(ABC):
    @abstractmethod
    def query(self, sql: str) -> Any: ...

class IDatabaseURIBuilder(ABC):
    @abstractmethod
    def get_uri(self) -> str: ...


# Implement the services
class DatabaseConnection(IDatabaseConnection):
    def __init__(self, uri_builder: IDatabaseURIBuilder, table_name="default"):
        self.connection_string = uri_builder.get_uri()
        self.table_name = table_name
        self.connected = True
        print(f"Connected to database: {self.connection_string}")

    def query(self, sql: str) -> Any:
        if not self.connected:
            raise Exception("Not connected to the database.")
        print(f"Executing query: {sql} FROM {self.table_name}")
        return {"result": "data"}

    def dispose(self) -> None:
        if self.connected:
            self.connected = False
            print(f"Disconnected from database: {self.connection_string}")

class TestDatabaseURIBuilder(IDatabaseURIBuilder):
    def get_uri(self):
        return "connect.to.me"

2. Register Services

Create an instance of the ServiceContainer and register your services with appropriate lifetimes:

# Create the service container
services = ServiceContainer()

# Register services
services.add_transient(IDatabaseURIBuilder, TestDatabaseURIBuilder)
services.add_scoped(IDatabaseConnection, DatabaseConnection)

3. Resolve Services

Retrieve and utilise services from the ServiceCollection. When retrieving services from the ServiceContainer, services referenced in constructors (__init__) will be automatically resolved.

You can also overwrite any constructor arguments when retrieving services:

with services.create_scope() as service_scope:
    db = service_scope[IDatabaseConnection](table_name="foobar")
    result = db.query("SELECT *")
print(result)


@services.inject
def print_connection_str(db_uri_builder: IDatabaseURIBuilder):
    print("Database connection string:", db_uri_builder.get_uri())

print_connection_str()
# Output:
"""
Connected to database: connect.to.me
Executing query: SELECT * FROM foobar
Disconnected from database: connect.to.me
{'result': 'data'}
Database connection string: connect.to.me
"""

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

pyjudo-0.6.1.tar.gz (67.1 kB view details)

Uploaded Source

Built Distribution

pyjudo-0.6.1-py3-none-any.whl (14.0 kB view details)

Uploaded Python 3

File details

Details for the file pyjudo-0.6.1.tar.gz.

File metadata

  • Download URL: pyjudo-0.6.1.tar.gz
  • Upload date:
  • Size: 67.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.1.1 CPython/3.12.7

File hashes

Hashes for pyjudo-0.6.1.tar.gz
Algorithm Hash digest
SHA256 43088dc80dc5b0fdc90bf9d71fa9be5d47c7bda0049ca9d3abf2554040d5cd8f
MD5 3ccdaf307a53774a72d06aafa16e3107
BLAKE2b-256 1446f461f9f23bdbf38274328e96209c5c28d91082bac4cc97d42225e74673b1

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjudo-0.6.1.tar.gz:

Publisher: publish-to-pypi.yml on NixonInnes/pyjudo

Attestations:

File details

Details for the file pyjudo-0.6.1-py3-none-any.whl.

File metadata

  • Download URL: pyjudo-0.6.1-py3-none-any.whl
  • Upload date:
  • Size: 14.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.1.1 CPython/3.12.7

File hashes

Hashes for pyjudo-0.6.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1260e0ddf532b96a11a904ebe34f322b809762751772a0a852d5600c8f5291ef
MD5 eeed853c7ca90047a4627cd8cfc178c5
BLAKE2b-256 bfa4a98bc8c3a86c0b0f38ae5157a28d53c057092e995017da2c514e802f4b3e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyjudo-0.6.1-py3-none-any.whl:

Publisher: publish-to-pypi.yml on NixonInnes/pyjudo

Attestations:

Supported by

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