Skip to main content

Spring style dependency injection for python

Project description

AppCtx

Spring-style dependency injection for Python

Python Version License PyPI Version

Overview

AppCtx is a lightweight dependency injection container inspired by the Spring Framework, providing a clean and elegant dependency management solution for Python applications. It makes it easy to manage dependencies and create maintainable, testable code.

Version: 0.1.0
Python Requirements: 3.8+
License: MIT

Features

  • 🚀 Easy to Use - Register and inject dependencies with simple decorators
  • 🔄 Auto-wiring - Automatic dependency resolution based on type annotations
  • 🏗️ Flexible Configuration - Support for both function and class bean definitions
  • 📦 Lightweight - Minimal dependencies, focused on core functionality
  • 🐍 Pythonic - API design that follows Python conventions
  • 🔧 Python 3.8+ - Compatible with Python 3.8, 3.9, 3.10, and 3.11
  • 🎯 Decorator-based bean registration - Simple @bean decorator for registration
  • 🔍 Circular dependency detection - Detects and reports circular dependencies

Installation

pip install appctx

Development Installation

For development, clone the repository and install with development dependencies:

git clone https://github.com/wssccc/appctx.git
cd appctx
pip install -e .[dev]

This will install the following development tools:

  • pytest>=7.0 - Testing framework
  • pytest-cov>=4.0 - Coverage reporting
  • black>=22.0 - Code formatting
  • flake8>=5.0 - Linting
  • mypy>=1.0 - Type checking
  • isort>=5.0 - Import sorting

Basic Concepts

AppCtx provides a simple way to manage dependencies in your Python applications:

  • Beans: Objects managed by the container
  • Container: The ApplicationContext that manages beans
  • Dependency Injection: Automatic wiring of dependencies based on type annotations

Quick Start

Basic Usage

from appctx import bean, get_bean, refresh

# Define service classes
class DatabaseService:
    def __init__(self, connection_string: str = "sqlite:///default.db"):
        self.connection_string = connection_string
    
    def connect(self):
        return f"Connected to {self.connection_string}"

class UserService:
    def __init__(self, db: DatabaseService):
        self.db = db
    
    def get_user(self, user_id: int):
        connection = self.db.connect()
        return f"User {user_id} from {connection}"

# Register beans using decorators
@bean
def database_service():
    return DatabaseService("postgresql://localhost/myapp")

@bean
def user_service(db: DatabaseService):  # Auto-inject DatabaseService
    return UserService(db)

# Initialize the container
refresh()

# Get and use beans
user_svc = get_bean(UserService)
print(user_svc.get_user(123))

Class Decorator Usage

from appctx import bean, get_bean, refresh

@bean
class EmailService:
    def __init__(self):
        self.server = "smtp.example.com"
    
    def send_email(self, to: str, subject: str):
        return f"Email sent to {to} via {self.server}"

@bean
class NotificationService:
    def __init__(self, email: EmailService):
        self.email = email
    
    def notify(self, user: str, message: str):
        return self.email.send_email(user, "Notification", message)

refresh()

notification_svc = get_bean(NotificationService)
print(notification_svc.notify("user@example.com", "Hello World!"))

How It Works

  1. Bean Registration: Use the @bean decorator to register functions that create beans
  2. Type Annotations: Use type annotations to declare dependencies
  3. Container Initialization: Call refresh() to initialize the container and resolve dependencies
  4. Bean Retrieval: Use get_bean() to retrieve beans by type or name

Advanced Usage

Custom Application Context

from appctx import ApplicationContext

# Create custom context
ctx = ApplicationContext()

@ctx.bean
def my_service():
    return MyService()

ctx.refresh()
service = ctx.get_bean(MyService)

Multiple Beans of Same Type

@bean
def primary_db():
    return DatabaseService("primary://db")

@bean
def secondary_db():
    return DatabaseService("secondary://db")

refresh()

# Get all database services
dbs = get_beans(DatabaseService)
print(f"Found {len(dbs)} database services")

# Get all beans of a specific type
databases = get_beans(DatabaseService)
print(len(databases))  # 2

Named Bean Retrieval

@bean
def database_service():
    return DatabaseService("app.db")

refresh()

# Get bean by name (function name)
db = get_bean("database_service")

API Reference

Core Decorators

@bean

Register a function or class as a bean.

@bean
def my_service():
    return MyService()

@bean
class MyComponent:
    def __init__(self, dependency: SomeDependency):
        self.dependency = dependency

Container Operations

refresh()

Initialize the container and instantiate all beans. Must be called before getting beans.

refresh()

get_bean(key)

Get a bean by type or name.

# Get by type
service = get_bean(MyService)

# Get by name
service = get_bean("my_service")

get_beans(type)

Get all beans of a specific type.

services = get_beans(MyService)

Dependency Resolution

AppCtx uses the following rules to resolve dependencies:

  1. Type Annotation Priority - If a parameter has type annotation, find bean by type
  2. Name Matching - If no type annotation, find bean by parameter name
  3. Auto-wiring - Container automatically resolves and injects dependencies
  4. Circular Dependency Detection - Detects and reports circular dependency issues

Error Handling

Common Errors

# Bean not found
try:
    service = get_bean(UnknownService)
except KeyError as e:
    print(f"Bean not found: {e}")

# Multiple beans of same type conflict
try:
    refresh()
except RuntimeError as e:
    print(f"Bean instantiation failed: {e}")

# Circular dependency
try:
    refresh()
except RuntimeError as e:
    print(f"Circular dependency detected: {e}")

Best Practices

  1. Use Type Annotations - Specify dependency types clearly for better code readability
  2. Single Responsibility - Each bean should have a clear responsibility
  3. Interface Abstraction - Use abstract base classes to define service interfaces
  4. Configuration Separation - Centralize bean configuration management
  5. Test-Friendly - Design beans that are easy to test

Development

Requirements

  • Python 3.8 or higher
  • pip

Running Tests

pytest tests/

Running Tests with Coverage

pytest --cov=src/appctx tests/

Code Formatting

Format code with Black (line length: 88):

black src/ tests/

Import Sorting

Sort imports with isort (Black profile):

isort src/ tests/

Linting

Check code quality with flake8:

flake8 src/ tests/

Type Checking

Run type checking with mypy:

mypy src/

Run All Quality Checks

# Format code
black src/ tests/
isort src/ tests/

# Run linting and type checking
flake8 src/ tests/
mypy src/

# Run tests with coverage
pytest --cov=src/appctx tests/

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

We welcome contributions! Please see our contributing guidelines below.

Development Setup

  1. Fork the project
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Create a Pull Request

Running Tests

# Run all tests
pytest

# Run tests with coverage
pytest --cov=appctx

# Run linting
black --check src/ tests/
flake8 src/ tests/
mypy src/

Release Process

For maintainers, see RELEASE.md for detailed release instructions.

Links

Changelog

v0.1.0

  • Initial release
  • Basic dependency injection functionality
  • Decorator API
  • Auto-wiring support
  • Python 3.8+ support

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

appctx-0.1.0.tar.gz (10.4 kB view details)

Uploaded Source

Built Distribution

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

appctx-0.1.0-py3-none-any.whl (6.7 kB view details)

Uploaded Python 3

File details

Details for the file appctx-0.1.0.tar.gz.

File metadata

  • Download URL: appctx-0.1.0.tar.gz
  • Upload date:
  • Size: 10.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for appctx-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b75b51f1b2dcd8779bee88b33dd18e8fa64bf7a9bb0ac586abb0e19593e9b809
MD5 cdfa33314757b7fcc81fcd9c18d451ca
BLAKE2b-256 86a720d520b6489bf1a3a8dec3588c2608505fe88b913b43f454ede42a82ddf4

See more details on using hashes here.

Provenance

The following attestation bundles were made for appctx-0.1.0.tar.gz:

Publisher: publish.yml on wssccc/appctx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file appctx-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: appctx-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 6.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for appctx-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d4ea22e38ecce4f3f867ebfbf76346536e6f4d9a0cf3dd65ef7a694c7a6554e9
MD5 08ac9330eac4bddd322dfeb1a752b4e7
BLAKE2b-256 b146cde37be4d3a95c85acb6b475547f936aaa175cf821a1936516802eebef4b

See more details on using hashes here.

Provenance

The following attestation bundles were made for appctx-0.1.0-py3-none-any.whl:

Publisher: publish.yml on wssccc/appctx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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