Skip to main content

PyDIT (Python Dependency Injection with Typing)

Description

With PyDit you can use ABC and Protocol to make interfaces and use the power of Dependency Inversion Principle.

PyDit allow your code to depend only abstract things, not the real implementation.

Install

With poetry

poetry add python-pydit

With pip

pip install python-pydit

Usage

Create the PyDit instance:

app/configs/di.py

from pydit import PyDit

pydit = PyDit()

Import the pydit instance and register your project's dependencies:

app/configs/dependencies.py

from typing import Any
from app.configs.di import pydit
from app.adapters.repositories.sqlalchemy.user_repository import SqlalchemyUserRepository
from app.configs.database import get_db_config


def setup_dependencies():
  """
  This is only a suggestion, you're free to configure it like you want
  """

  dependencies: list[dict[str, Any]] = [
    {
      "dependency": SqlalchemyUserRepository,
      "token": "sqlalchemy_user_repository"
    },
    {
      "dependency": get_db_config,
      "token": "database_config",
    },
    {
      "dependency": "HELLO WORLD",
      "token": "test"
    }
  ]

  for dependency in dependencies:
    pydit.add_dependency(dependency["dependency"], dependency.get("token"))

Call the setup_dependencies in the main file

app/main.py

from app.config.di import setup_dependencies()

setup_dependencies()

Injecting dependencies

Inject by property

Pydit supports python's @property decorator.

app/domain/user/services/create.py

from typing import cast, Any
from app.configs.di import pydit
# This class can be a Protocol or a clas that inherits from ABC
from app.adapters.repositories.interfaces.user_repositgory import IUserRepository

class CreateUserService:
  @pydit.inject()
  def user_repository(self) -> IUserRepository:
    return cast(IUserRepository, None)

  @pydit.inject(token="test")
  def other_property(self) -> str:
    return ""

  def execute(self, data: dict[str, Any]):
    self.user_repository.create(data)

    # Prints HELLO WORLD
    print(self.other_property)

How you can see, we're depending on the intarface IUserRepository, not the real SqlalchemyUserRepository implementation.

Inject dependencies by constuctor

PyDIT needs that each parameter of class/function have default value to be resolved

app/domain/user/services/create.py

from pydit import FunctionInject
from app.adapters.repositories.interfaces.user_repositgory import IUserRepository

class CreateUserService:
  def __init__(
    self,
    user_repository: IUserRepository = FunctionInject(),
    other_property: str = FunctionInject(token="test")
  ):
    self.user_repository = user_repository

  def execute(self, data):
    self.user_repository.create(data)

    # Prints HELLO WORLD
    print(other_property)

Inject dependencies by function

PyDIT can handle user defined functions too.

app/domain/user/services/create.py

from typing import Any
from pydit import FunctionInject
from app.adapters.repositories.interfaces.user_repositgory import IUserRepository

def create_user(user_data: dict[str, Any], repository: IUserRepository = FunctionInject()):
  repository.create(user_data)

app/config/dependencies.py

from app.configs.di import pydit
from app.domain.user.services.create import create_user

def setup_dependencies():
  pydit.add_dependency(create_user, "create_user")

app/routers/v1/user.py

from fastapi import APIRouter
from app.configs.di import pydit
from app.domain.user.dto.create import CreateUserDTO


router = APIRouter(prefix="/users", tags=["Users"])

@router.post("")
def create(data: CreateUserDTO):
  create_service = pydit.get_value(token="create_user")
  create_service(data.dict())

  return "OK"

Singleton

To use singleton approach, pass true to singleton parameter in inject fn.

from typing import cast, Any
from app.configs.di import pydit
# This class can be a Protocol or a clas that inherits from ABC
from app.adapters.repositories.interfaces.user_repositgory import IUserRepository

class CreateUserService:
  @pydit.inject(singleton=True)
  def user_repository(self) -> IUserRepository:
    return cast(IUserRepository, None)

  @pydit.inject(token="test")
  def other_property(self) -> str:
    return ""

  def execute(self, data: dict[str, Any]):
    self.user_repository.create(data)

    # Prints HELLO WORLD
    print(self.other_property)

Features:

  • Inject values based on type signature
  • Inject values based on inheritance
  • Inject values via token
  • Resolves function dependencies, calling and injecting the call result
  • Singleton support
  • Inject values in function calls or class constructor __init__ based on the arguments' signatures
  • Add support for kwargs when inject values in functions

Metadata

Release files for python-pydit 1.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for python-pydit 1.0.2
File Size Uploaded Provenance
python_pydit-1.0.2.tar.gz 12.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for python-pydit 1.0.2
File Interpreter ABI Platform
python_pydit-1.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 30.2 kB

Release files / python_pydit-1.0.2.tar.gz

Download URL python_pydit-1.0.2.tar.gz
Size 12.6 kB
Tags Source
SHA-256 checksum
How to use checksums
3db007fcf18854452cc973583ccb53584ec392545016fff41986d4ebfa2b943f
BLAKE2b-256 checksum
How to use checksums
649930113c50a65742c2273d38fea1c4f3d7360e25f2769299b34434e9321a67
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.5 CPython/3.12.3 Linux/6.17.0-14-generic

Release files / python_pydit-1.0.2-py3-none-any.whl

Download URL python_pydit-1.0.2-py3-none-any.whl
Size 17.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aba395974969163e533e6e430ea0d25571ced07987b312297a822a4c973b9194
BLAKE2b-256 checksum
How to use checksums
7a7e281ece458830f341d06cc268d59109c190727b09f9aa06dcc81a18a03fbc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.5 CPython/3.12.3 Linux/6.17.0-14-generic

Security for python-pydit 1.0.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page