aiogram-dependency


Nameaiogram-dependency JSON
Version 1.0.3 PyPI version JSON
download
home_pageNone
SummaryA FastAPI-style dependency injection system for aiogram Telegram bots. This library brings clean, type-safe dependency injection to your aiogram handlers, making your code more modular, testable, and maintainable.
upload_time2025-08-01 11:43:36
maintainerNone
docs_urlNone
authorVladyslav Chaliuk
requires_python>=3.11
licenseNone
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Aiogram Dependency Injection

A FastAPI-style dependency injection system for aiogram Telegram bots. This library brings clean, type-safe dependency injection to your aiogram handlers, making your code more modular, testable, and maintainable.

[![PyPI Downloads](https://static.pepy.tech/badge/aiogram-dependency)](https://pepy.tech/projects/aiogram-dependency)
## Features

- ๐Ÿš€ **FastAPI-style syntax** - Familiar `Depends()` decorator
- ๐Ÿ”„ **Multiple dependency scopes** - Singleton, Request, and Transient
- ๐Ÿ—๏ธ **Nested dependencies** - Dependencies can depend on other dependencies
- โšก **Async support** - Both sync and async dependency functions
- ๐Ÿ›ก๏ธ **Circular dependency detection** - Prevents infinite loops
- ๐Ÿงช **Type-safe** - Full type hints support
- ๐Ÿ’พ **Smart caching** - Efficient resource management

## Installation

```bash
pip install aiogram-dependency
```

Or install from source:

```bash
git clone https://github.com/AstralMortem/aiogram-dependency
cd aiogram-dependency
pip install -e .
```

## Quick Start

```python
import asyncio
from aiogram import Bot, Dispatcher, F
from aiogram.types import Message

from aiogram_dependency import Depends, setup_dependency, Scope

# Define your dependencies
class DatabaseConnection:
    def __init__(self, connection_string: str):
        self.connection_string = connection_string
    
    async def query(self, sql: str):
        # Your database logic here
        return f"Result for: {sql}"

class UserService:
    def __init__(self, db: DatabaseConnection):
        self.db = db
    
    async def get_user_profile(self, user_id: int):
        return await self.db.query(f"SELECT * FROM users WHERE id = {user_id}")

# Dependency factories
async def get_database() -> DatabaseConnection:
    return DatabaseConnection("postgresql://localhost/mydb")

async def get_user_service(
    db: DatabaseConnection = Depends(get_database, scope=Scope.SINGLETON)
) -> UserService:
    return UserService(db)

# Handler with dependency injection
async def profile_handler(
    message: Message,
    user_service: UserService = Depends(get_user_service)
):
    if not message.from_user:
        await message.answer("User not found")
        return
    
    profile = await user_service.get_user_profile(message.from_user.id)
    await message.answer(f"Your profile: {profile}")

# Setup bot (ORDER MATER!)
async def main():
    bot = Bot(token="YOUR_BOT_TOKEN")
    dp = Dispatcher()
    
    # Register handlers
    dp.message.register(profile_handler, F.text == "/profile")

    # Register dependency injection 
    setup_dependency(dp)
    
    await dp.start_polling(bot)

if __name__ == "__main__":
    asyncio.run(main())
```

## Dependency Scopes

### Singleton
Created once and shared across all requests globally.

```python
async def get_database() -> DatabaseConnection:
    return DatabaseConnection("connection_string")

async def handler(
    message: Message,
    db: DatabaseConnection = Depends(get_database, scope=Scope.SINGLETON)
):
    # Same database instance for all users
    pass
```

### Request (Default)
Created once per user/chat and cached for subsequent calls in the same context.

```python
async def get_user_service() -> UserService:
    return UserService()

async def handler(
    message: Message,
    service: UserService = Depends(get_user_service, scope=Scope.REQUEST)
):
    # Same service instance for this user, different for other users
    pass
```

### Transient
Created fresh every time it's requested.

```python
async def get_timestamp() -> float:
    return time.time()

async def handler(
    message: Message,
    timestamp: float = Depends(get_timestamp, scope=Scope.TRANSIENT)
):
    # New timestamp every time
    pass
```

## Advanced Usage

### Annotated

You can use Annotated type to make it more readable.
```python
from typing import Annotated
from aiogram_dependency import Depends
from aiogram import Dispatcher,filters,types

async def get_database() -> DatabaseConnection:
    return DatabaseConnection("postgresql://localhost/db")

DatabaseDep = Annotated[DatabaseConnection, Depends(get_database)]

async def get_user(db: DatabaseDep):
    return db.execute('SQL')

UserDep = Annotated[dict, Depends(get_user)]

dp = Dispatcher()

@dp.message(filters.CommandStart())
async def start(message:types.Message, user: UserDep):
    return await message.answer(user['username'])


```


### Nested Dependencies

Dependencies can depend on other dependencies:

```python
async def get_database() -> DatabaseConnection:
    return DatabaseConnection("postgresql://localhost/db")

async def get_user_repository(
    db: DatabaseConnection = Depends(get_database)
) -> UserRepository:
    return UserRepository(db)

async def get_user_service(
    user_repo: UserRepository = Depends(get_user_repository),
    notification_service: NotificationService = Depends(get_notification_service)
) -> UserService:
    return UserService(user_repo, notification_service)
```

### Using Event Data in Dependencies

Dependencies can access the current event and handler data:

```python
async def get_current_user(event: Message) -> Optional[User]:
    return event.from_user

async def get_user_permissions(
    event: Message,
    data: dict,
    current_user: User = Depends(get_current_user)
) -> List[str]:
    # Access event, data, and other dependencies
    if current_user and current_user.id in data.get('admins', []):
        return ['admin', 'user']
    return ['user']

async def admin_handler(
    message: Message,
    permissions: List[str] = Depends(get_user_permissions)
):
    if 'admin' not in permissions:
        await message.answer("Access denied")
        return
    
    await message.answer("Welcome, admin!")
```

### Custom Registry and Resolver

For advanced use cases, you can customize the dependency system:

```python
from aiogram_dependency.registry import DependencyRegistry
from aiogram_dependency.resolver import DependencyResolver
from aiogram_dependency.middleware import DependencyMiddleware
from aiogram_dependency import Scope

# Create custom registry
registry = DependencyRegistry()

db_dep = Depends(get_database, scope=Scope.SINGLETON)

# Pre-populate with some dependencies
registry.set_dependency(
    db_dep,
    DatabaseConnection("custom://connection"),
    "global"
)

# Use custom middleware
middleware = DependencyMiddleware(registry)
dp.message.middleware(middleware)
```

## Testing

The library is fully testable. Here's an example:


Run the full test suite:

```bash
# Install test dependencies
pip install pytest pytest-asyncio

# Run tests
pytest tests/ -v

# Run with coverage
pytest tests/ --cov=aiogram_dependency --cov-report=html
```



## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.


## Related Projects

- [aiogram](https://github.com/aiogram/aiogram) - Modern and fully asynchronous framework for Telegram Bot API
- [FastAPI](https://github.com/tiangolo/fastapi) - Modern, fast web framework for building APIs with Python


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "aiogram-dependency",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.11",
    "maintainer_email": null,
    "keywords": null,
    "author": "Vladyslav Chaliuk",
    "author_email": "chaliukvladyslav@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/fb/b7/930dd4d7e3cfd8049c3c55b511552801f019c291ca63ab7ac0ada5a743fc/aiogram_dependency-1.0.3.tar.gz",
    "platform": null,
    "description": "# Aiogram Dependency Injection\n\nA FastAPI-style dependency injection system for aiogram Telegram bots. This library brings clean, type-safe dependency injection to your aiogram handlers, making your code more modular, testable, and maintainable.\n\n[![PyPI Downloads](https://static.pepy.tech/badge/aiogram-dependency)](https://pepy.tech/projects/aiogram-dependency)\n## Features\n\n- \ud83d\ude80 **FastAPI-style syntax** - Familiar `Depends()` decorator\n- \ud83d\udd04 **Multiple dependency scopes** - Singleton, Request, and Transient\n- \ud83c\udfd7\ufe0f **Nested dependencies** - Dependencies can depend on other dependencies\n- \u26a1 **Async support** - Both sync and async dependency functions\n- \ud83d\udee1\ufe0f **Circular dependency detection** - Prevents infinite loops\n- \ud83e\uddea **Type-safe** - Full type hints support\n- \ud83d\udcbe **Smart caching** - Efficient resource management\n\n## Installation\n\n```bash\npip install aiogram-dependency\n```\n\nOr install from source:\n\n```bash\ngit clone https://github.com/AstralMortem/aiogram-dependency\ncd aiogram-dependency\npip install -e .\n```\n\n## Quick Start\n\n```python\nimport asyncio\nfrom aiogram import Bot, Dispatcher, F\nfrom aiogram.types import Message\n\nfrom aiogram_dependency import Depends, setup_dependency, Scope\n\n# Define your dependencies\nclass DatabaseConnection:\n    def __init__(self, connection_string: str):\n        self.connection_string = connection_string\n    \n    async def query(self, sql: str):\n        # Your database logic here\n        return f\"Result for: {sql}\"\n\nclass UserService:\n    def __init__(self, db: DatabaseConnection):\n        self.db = db\n    \n    async def get_user_profile(self, user_id: int):\n        return await self.db.query(f\"SELECT * FROM users WHERE id = {user_id}\")\n\n# Dependency factories\nasync def get_database() -> DatabaseConnection:\n    return DatabaseConnection(\"postgresql://localhost/mydb\")\n\nasync def get_user_service(\n    db: DatabaseConnection = Depends(get_database, scope=Scope.SINGLETON)\n) -> UserService:\n    return UserService(db)\n\n# Handler with dependency injection\nasync def profile_handler(\n    message: Message,\n    user_service: UserService = Depends(get_user_service)\n):\n    if not message.from_user:\n        await message.answer(\"User not found\")\n        return\n    \n    profile = await user_service.get_user_profile(message.from_user.id)\n    await message.answer(f\"Your profile: {profile}\")\n\n# Setup bot (ORDER MATER!)\nasync def main():\n    bot = Bot(token=\"YOUR_BOT_TOKEN\")\n    dp = Dispatcher()\n    \n    # Register handlers\n    dp.message.register(profile_handler, F.text == \"/profile\")\n\n    # Register dependency injection \n    setup_dependency(dp)\n    \n    await dp.start_polling(bot)\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\n## Dependency Scopes\n\n### Singleton\nCreated once and shared across all requests globally.\n\n```python\nasync def get_database() -> DatabaseConnection:\n    return DatabaseConnection(\"connection_string\")\n\nasync def handler(\n    message: Message,\n    db: DatabaseConnection = Depends(get_database, scope=Scope.SINGLETON)\n):\n    # Same database instance for all users\n    pass\n```\n\n### Request (Default)\nCreated once per user/chat and cached for subsequent calls in the same context.\n\n```python\nasync def get_user_service() -> UserService:\n    return UserService()\n\nasync def handler(\n    message: Message,\n    service: UserService = Depends(get_user_service, scope=Scope.REQUEST)\n):\n    # Same service instance for this user, different for other users\n    pass\n```\n\n### Transient\nCreated fresh every time it's requested.\n\n```python\nasync def get_timestamp() -> float:\n    return time.time()\n\nasync def handler(\n    message: Message,\n    timestamp: float = Depends(get_timestamp, scope=Scope.TRANSIENT)\n):\n    # New timestamp every time\n    pass\n```\n\n## Advanced Usage\n\n### Annotated\n\nYou can use Annotated type to make it more readable.\n```python\nfrom typing import Annotated\nfrom aiogram_dependency import Depends\nfrom aiogram import Dispatcher,filters,types\n\nasync def get_database() -> DatabaseConnection:\n    return DatabaseConnection(\"postgresql://localhost/db\")\n\nDatabaseDep = Annotated[DatabaseConnection, Depends(get_database)]\n\nasync def get_user(db: DatabaseDep):\n    return db.execute('SQL')\n\nUserDep = Annotated[dict, Depends(get_user)]\n\ndp = Dispatcher()\n\n@dp.message(filters.CommandStart())\nasync def start(message:types.Message, user: UserDep):\n    return await message.answer(user['username'])\n\n\n```\n\n\n### Nested Dependencies\n\nDependencies can depend on other dependencies:\n\n```python\nasync def get_database() -> DatabaseConnection:\n    return DatabaseConnection(\"postgresql://localhost/db\")\n\nasync def get_user_repository(\n    db: DatabaseConnection = Depends(get_database)\n) -> UserRepository:\n    return UserRepository(db)\n\nasync def get_user_service(\n    user_repo: UserRepository = Depends(get_user_repository),\n    notification_service: NotificationService = Depends(get_notification_service)\n) -> UserService:\n    return UserService(user_repo, notification_service)\n```\n\n### Using Event Data in Dependencies\n\nDependencies can access the current event and handler data:\n\n```python\nasync def get_current_user(event: Message) -> Optional[User]:\n    return event.from_user\n\nasync def get_user_permissions(\n    event: Message,\n    data: dict,\n    current_user: User = Depends(get_current_user)\n) -> List[str]:\n    # Access event, data, and other dependencies\n    if current_user and current_user.id in data.get('admins', []):\n        return ['admin', 'user']\n    return ['user']\n\nasync def admin_handler(\n    message: Message,\n    permissions: List[str] = Depends(get_user_permissions)\n):\n    if 'admin' not in permissions:\n        await message.answer(\"Access denied\")\n        return\n    \n    await message.answer(\"Welcome, admin!\")\n```\n\n### Custom Registry and Resolver\n\nFor advanced use cases, you can customize the dependency system:\n\n```python\nfrom aiogram_dependency.registry import DependencyRegistry\nfrom aiogram_dependency.resolver import DependencyResolver\nfrom aiogram_dependency.middleware import DependencyMiddleware\nfrom aiogram_dependency import Scope\n\n# Create custom registry\nregistry = DependencyRegistry()\n\ndb_dep = Depends(get_database, scope=Scope.SINGLETON)\n\n# Pre-populate with some dependencies\nregistry.set_dependency(\n    db_dep,\n    DatabaseConnection(\"custom://connection\"),\n    \"global\"\n)\n\n# Use custom middleware\nmiddleware = DependencyMiddleware(registry)\ndp.message.middleware(middleware)\n```\n\n## Testing\n\nThe library is fully testable. Here's an example:\n\n\nRun the full test suite:\n\n```bash\n# Install test dependencies\npip install pytest pytest-asyncio\n\n# Run tests\npytest tests/ -v\n\n# Run with coverage\npytest tests/ --cov=aiogram_dependency --cov-report=html\n```\n\n\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n\n## Related Projects\n\n- [aiogram](https://github.com/aiogram/aiogram) - Modern and fully asynchronous framework for Telegram Bot API\n- [FastAPI](https://github.com/tiangolo/fastapi) - Modern, fast web framework for building APIs with Python\n\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "A FastAPI-style dependency injection system for aiogram Telegram bots. This library brings clean, type-safe dependency injection to your aiogram handlers, making your code more modular, testable, and maintainable.",
    "version": "1.0.3",
    "project_urls": null,
    "split_keywords": [],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "8f48f093065397f83293855a78baac5deb5ea8278a86afd7fd708c98c902bfbc",
                "md5": "c5c3d19c6930259724dddbe97287e524",
                "sha256": "3ed8567aec9b4ef81b0e8166a7746ab1ecf6f90943be061af46937c99d26df7f"
            },
            "downloads": -1,
            "filename": "aiogram_dependency-1.0.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "c5c3d19c6930259724dddbe97287e524",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.11",
            "size": 9164,
            "upload_time": "2025-08-01T11:43:35",
            "upload_time_iso_8601": "2025-08-01T11:43:35.433358Z",
            "url": "https://files.pythonhosted.org/packages/8f/48/f093065397f83293855a78baac5deb5ea8278a86afd7fd708c98c902bfbc/aiogram_dependency-1.0.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "fbb7930dd4d7e3cfd8049c3c55b511552801f019c291ca63ab7ac0ada5a743fc",
                "md5": "133c316659c4315a5618349f6be21f45",
                "sha256": "92aa5a9dff946bd25d4876a219675c220ae15393ec697a6f5214fe8e51c31bc2"
            },
            "downloads": -1,
            "filename": "aiogram_dependency-1.0.3.tar.gz",
            "has_sig": false,
            "md5_digest": "133c316659c4315a5618349f6be21f45",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.11",
            "size": 6644,
            "upload_time": "2025-08-01T11:43:36",
            "upload_time_iso_8601": "2025-08-01T11:43:36.999270Z",
            "url": "https://files.pythonhosted.org/packages/fb/b7/930dd4d7e3cfd8049c3c55b511552801f019c291ca63ab7ac0ada5a743fc/aiogram_dependency-1.0.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-01 11:43:36",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "aiogram-dependency"
}
        
Elapsed time: 2.84094s