Skip to main content

pyre-injector

Python Zero dependencies License DI

轻量级 Python 依赖注入框架:依据类型注解自动装配、管理作用域与延迟初始化。 核心零依赖(仅标准库),统一通过 container. 注册与获取依赖。

✨ 特点

  • 🚀 轻量 — 只用标准库,无任何第三方依赖。
  • 🧩 自动解析 — 依据构造函数 / 工厂函数的类型注解递归装配依赖,不用手写工厂。
  • 🎯 统一 API — container.inject() 注册、container.provider() 获取,装饰器写法完全等价。
  • ♻️ 作用域管理 — singleton(默认)与 prototype 一行切换。
  • ⏳ 延迟初始化 — lazy_init=True 时首次使用才构建,避免启动期无谓开销。
  • 🏭 工厂函数 — 模块级工厂与类内工厂方法都支持,参数同样参与注入。
  • 🧷 手动注入实例 — 已构造好的配置、连接池、logger 可直接交给容器。
  • 🧭 精确异常定位 — 报出异常发生位置与依赖定义位置,并检测循环依赖。
  • 📦 零必需依赖 — 只用标准库。

📦 安装

pip install pyre-injector

💡 一个简单的例子

from pyre_injector import DependencyContainer

container = DependencyContainer()


class DatabaseConfig:
    def __init__(self):
        self.host = 'localhost'


class UserRepository:
    def __init__(self, config: DatabaseConfig):
        self.config = config


container.inject(DatabaseConfig)
container.inject(UserRepository)

container.provider(DatabaseConfig).host      # 'localhost'
container.provider(UserRepository).config    # DatabaseConfig 实例(自动注入)

👩‍💻 目录结构

pyre-injector
├── pyre_injector
│   ├── __init__.py    # 对外导出
│   ├── container.py   # 容器:注册、解析、作用域
│   ├── constants.py   # 作用域等常量
│   └── globals.py     # 激活容器
├── examples/          # 可运行示例
├── tests/             # 单元测试
└── setup.py

🚀 快速开始

注册依赖

推荐统一使用 container.inject(...):

from pyre_injector import DependencyContainer

container = DependencyContainer()

container.inject(Logger)                              # 按类注册
container.inject(Cache, scope='prototype')            # 带作用域
container.inject(Mailer, depend_name='mailer')        # 自定义名称
container.inject(LazyClient, lazy_init=True)          # 延迟初始化

@container.inject                                     # 也可以当装饰器
class Metrics:
    ...

@inject 是等价的模块级写法,适合在模块导入时声明:

from pyre_injector import inject

@inject
class Logger:
    ...

@inject(scope='prototype', lazy_init=True)
class Cache:
    ...

获取依赖

container.provider(Logger)        # 按类型
container.provider('mailer')      # 按名称

init_dependency_container() 会激活容器并立即构建所有非延迟依赖, 此后即可在任意位置用模块级 autowired(...) / provider(...) 取用:

container.init_dependency_container()

from pyre_injector import autowired, provider

autowired(Logger)      # 从活动容器按类型获取
provider('mailer')     # provider 是 autowired 的别名

♻️ 作用域

作用域 说明
singleton 默认。整个容器生命周期内只有一个实例。
prototype 每次 provider() 都创建新实例。
container.inject(Config)                          # singleton
container.inject(RequestContext, scope='prototype')

container.provider(Config) is container.provider(Config)                              # True
container.provider(RequestContext) is not container.provider(RequestContext)          # True

⏳ 延迟初始化

非延迟依赖会在 init_dependency_container() 时按依赖顺序构建; lazy_init=True 的依赖推迟到首次 provider() 时才构建。

container.inject(HeavyClient, lazy_init=True)
container.init_dependency_container()   # 此时 HeavyClient 尚未构建

client = container.provider(HeavyClient)  # 这一行才真正构建

🏭 工厂函数

工厂函数需要返回类型注解,用它来确定依赖类型;工厂参数同样参与注入。

from pyre_injector import inject

@inject(depend_name='connection')
def create_connection(config: DatabaseConfig) -> Connection:
    return Connection(config.host, config.port)

container.provider('connection')

类内工厂方法会把方法所属的类实例作为 self 注入:

@inject
class SessionFactory:
    def __init__(self):
        self.counter = 0

    @inject(depend_name='session')
    def create_session(self) -> Session:
        self.counter += 1
        return Session(f'session-{self.counter}')

没有返回类型注解时可用 return_type 显式指定:

container.inject(create_thing, return_type=Thing, depend_name='thing')

🧷 手动注入实例

已经构造好的对象可以直接交给容器,供其它依赖自动注入:

container.inject(app)                       # 名称默认取 instance.__class__.__name__
container.inject('pyre_flask', app)         # 也可以显式指定名称
container.inject('app_config', AppConfig())

传类 / 工厂函数走注册,传实例走手动注入,二者共用 container.inject(...)。

🏷 自定义名称

container.inject(UserService, depend_name='user_service')

container.provider('user_service') is container.provider(UserService)   # True

🧭 错误定位

初始化失败时,异常信息会同时给出依赖定义位置和异常实际发生位置:

DependencyInitError: Failed to initialize dependency 'BrokenService'. 初始化依赖 'BrokenService' 失败。
	└─ defined at: __main__.BrokenService (examples/errors.py:19)
	└─ origin    : examples/errors.py:21 (in __init__)
	ValueError: 数据库连接失败
  • defined at — 依赖在哪里定义/注册(模块.类名 + 文件:行号)。
  • origin — 异常实际抛出的位置(最内层用户代码帧),原始异常通过 __cause__ 保留。
  • DependencyInitError.origin 与 .depend_name 两个属性可直接读取,便于上报与断言。

异常类型

异常 触发场景
DependencyInitError 构造函数 / 工厂函数抛出异常(含 origin 定位)。
DependencyNotRegisteredError 参数声明的类型未注册,或按名称/类型查不到定义。
DependencyAnnotationError 参数缺少类型注解,且无默认值。
DependencyCycleError 检测到循环依赖,消息中给出完整链路。
DependencyAlreadyRegisteredError 同名依赖重复注册 / 重复注入(可用 replace=True 覆盖)。
DependencyNotInitializedError 从活动容器取值但容器未激活,或名称未注册。

全部异常都继承自 DependencyError,而 DependencyError 继承自 RuntimeError。

from pyre_injector import DependencyContainer, DependencyInitError

try:
    container.provider(BrokenService)
except DependencyInitError as error:
    print(error.origin)       # 'app/services.py:21 (in __init__)'
    print(error.__cause__)    # 原始异常

🔌 与 Web 框架集成

pyre-injector 不依赖任何 Web 框架。框架侧通常按下面三步接入:

  1. 创建 DependencyContainer;
  2. 用 container.inject(...) 注册服务,把 app / config / logger / db 等实例手动注入;
  3. 调用 container.init_dependency_container() 激活容器,之后框架反射注入时统一用 autowired(...) 取值。
container = DependencyContainer()
container.inject(app)
container.inject(app_config)
container.inject(logger)
container.inject(DatabaseConfig)
container.init_dependency_container()

框架里的服务基类也可以走等价的类方法式注册:

from pyre_injector import DependencyContainer, DependencyDefinition, autowired


class BaseService:
    def __init_subclass__(cls, **kwargs):
        definition = DependencyDefinition.parse_dependency(cls)
        if cls.__name__ not in DependencyContainer.dependency_definitions:
            DependencyContainer.register_dependency_definition(cls.__name__, definition)
        return super().__init_subclass__(**kwargs)

    def autowired(self, name):
        return autowired(name)

📖 API 参考

名称 说明
DependencyContainer 容器。inject / provider / inject_instance / init_dependency_container / active / clear / is_registered / register_dependency_definition / get_dependency_definition / solve_depend_init
DependencyDefinition 依赖定义。parse_dependency() / depend_class / depend_func / scope / lazy_init / depends_on
inject 模块级注册装饰器,等价于 container.inject。
autowired / provider 从活动容器按类型或名称获取依赖(两者等价)。
DependencyError 所有异常基类(RuntimeError 子类)。
DependencyInitError 初始化失败,带 origin / depend_name。
DependencyNotRegisteredError / DependencyAnnotationError / DependencyCycleError / DependencyAlreadyRegisteredError / DependencyNotInitializedError 具体错误类型。

container.inject

container.inject(
    target=None,               # 类 / 工厂函数(注册)或实例(手动注入)
    depend_instance=None,
    *,
    name=None,                 # 手动注入时的名称
    depend_name=None,          # 注册时使用的名称,默认取类名
    scope=None,                # 'singleton' | 'prototype'
    lazy_init=None,            # 是否延迟初始化
    return_type=None,          # 工厂函数的返回类型
    solve_init=True,           # 注册后若容器已就绪是否立即构建
    replace=False,             # 是否覆盖同名定义
)

container.provider

container.provider(name)       # name: 类 / 工厂函数 / 字符串名称

🛠 开发

pip install -e . pytest
pytest tests -q

示例位于 examples/:

python examples/basic.py          # 最小可用
python examples/container_api.py  # 推荐用法:container.inject / provider
python examples/scopes.py         # 作用域与延迟初始化
python examples/factory.py        # 工厂函数 / 工厂方法
python examples/errors.py         # 异常与定位信息

📄 许可

本项目基于 MIT 许可开源。

Metadata

Release files for pyre-injector 1.0.0

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

Source distribution (sdist)

Source distribution for pyre-injector 1.0.0
File Size Uploaded Provenance
pyre_injector-1.0.0.tar.gz 24.7 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pyre-injector 1.0.0
File Interpreter ABI Platform
pyre_injector-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 40.7 kB

Release files / pyre_injector-1.0.0.tar.gz

Download URL pyre_injector-1.0.0.tar.gz
Size 24.7 kB
Tags Source
SHA-256 checksum
How to use checksums
8e99d068ede8cb5e670256d4b849adbb2d5bd4de442750979baa89cde9d3b397
BLAKE2b-256 checksum
How to use checksums
b6a37e203d90a614d780725db85bc83f0f53f3858095ece8495e847d520587dd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / pyre_injector-1.0.0-py3-none-any.whl

Download URL pyre_injector-1.0.0-py3-none-any.whl
Size 16.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8a9cc39e8d07f0f9fd7ddad3dba39aa23ec99d7f677064f02c784c727bad3960
BLAKE2b-256 checksum
How to use checksums
03040992e99cf4297513628f1842383321d36729219ddbe974bcb52ba479aac7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Security for pyre-injector 1.0.0

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.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files No provenance

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