{"id":13458934,"url":"https://github.com/yakimka/picodi","last_synced_at":"2026-03-14T22:02:42.380Z","repository":{"id":235535657,"uuid":"789864755","full_name":"yakimka/picodi","owner":"yakimka","description":"Simple Dependency Injection library for Python. Supports both synchronous and asynchronous contexts and offers features like resource lifecycle management.","archived":false,"fork":false,"pushed_at":"2024-07-03T17:47:37.000Z","size":441,"stargazers_count":18,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-07-14T09:30:57.543Z","etag":null,"topics":["dependency-injection","di","fastapi","library","python","zero-dependencies"],"latest_commit_sha":null,"homepage":"https://picodi.readthedocs.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yakimka.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-04-21T18:58:44.000Z","updated_at":"2024-07-31T09:10:06.710Z","dependencies_parsed_at":"2024-05-20T20:38:31.703Z","dependency_job_id":"0b2b30de-14e6-4f4b-af79-3261a1b60096","html_url":"https://github.com/yakimka/picodi","commit_stats":null,"previous_names":["yakimka/picodi"],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yakimka%2Fpicodi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yakimka%2Fpicodi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yakimka%2Fpicodi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yakimka%2Fpicodi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yakimka","download_url":"https://codeload.github.com/yakimka/picodi/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221667347,"owners_count":16860604,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dependency-injection","di","fastapi","library","python","zero-dependencies"],"created_at":"2024-07-31T09:00:59.952Z","updated_at":"2026-03-14T22:02:42.374Z","avatar_url":"https://github.com/yakimka.png","language":"Python","funding_links":[],"categories":["Software"],"sub_categories":["DI Frameworks / Containers"],"readme":"# Picodi - Python DI (Dependency Injection) Library\n\n[![Build Status](https://github.com/yakimka/picodi/actions/workflows/workflow-ci.yml/badge.svg?branch=main\u0026event=push)](https://github.com/yakimka/picodi/actions/workflows/workflow-ci.yml)\n[![Codecov](https://codecov.io/gh/yakimka/picodi/branch/main/graph/badge.svg)](https://codecov.io/gh/yakimka/picodi)\n[![PyPI - Version](https://img.shields.io/pypi/v/picodi.svg)](https://pypi.org/project/picodi/)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/picodi)](https://pypi.org/project/picodi/)\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/picodi)](https://pypi.org/project/picodi/)\n[![Documentation Status](https://readthedocs.org/projects/picodi/badge/?version=stable)](https://picodi.readthedocs.io/en/stable/?badge=stable)\n\n[Documentation](https://picodi.readthedocs.io/)\n\nPicodi simplifies Dependency Injection (DI) for Python applications.\n[DI](https://en.wikipedia.org/wiki/Dependency_injection) is a design pattern\nthat allows objects to receive their dependencies from\nan external source rather than creating them internally.\nThis library supports both synchronous and asynchronous contexts,\nand offers features like lifecycle management.\n\n## Table of Contents\n\n- [Status](#status)\n- [Installation](#installation)\n- [Features](#features)\n- [Quick Start](#quick-start)\n- [FastAPI Example Project](#fastapi-example-project)\n- [License](#license)\n- [Contributing](#contributing)\n- [Credits](#credits)\n\n## Status\n\nPicodi is currently in the experimental stage.\nPublic APIs may change without notice until the library reaches a 1.x.x version.\n\n## Installation\n\n```bash\npip install picodi\n```\n\n## Features\n\n- 🌟 Simple and lightweight\n- 📦 Zero dependencies\n- ⏱️ Supports both sync and async contexts\n- 🔄 Lifecycle management\n- 🔍 Type hints support\n- 🐍 Python \u0026 PyPy 3.10+ support\n- 🚀 Works well with [FastAPI](https://fastapi.tiangolo.com/)\n- 🧪 Integration with [pytest](https://docs.pytest.org/)\n\n## Quick Start\n\n```python\nimport asyncio\nfrom collections.abc import Callable\nfrom datetime import date\nfrom typing import Any\n\nimport httpx\n\nfrom picodi import (\n    Provide,\n    inject,\n    registry,\n    SingletonScope,\n)\nfrom picodi.helpers import get_value\n\n\n# Regular functions without required arguments can be used as a dependency\ndef get_settings() -\u003e dict:\n    return {\n        \"nasa_api\": {\n            \"api_key\": \"DEMO_KEY\",\n            \"base_url\": \"https://api.nasa.gov\",\n            \"timeout\": 10,\n        }\n    }\n\n\n# Helper function to get a setting from the settings dictionary.\n# We can use this function to inject specific settings, not the whole settings object.\n@inject\ndef get_setting(path: str, settings: dict = Provide(get_settings)) -\u003e Callable[[], Any]:\n    value = get_value(path, settings)\n    return lambda: value\n\n\n# We want to reuse the same client for all requests, so we declare a dependency\n#   with `SingletonScope` that provides an httpx.AsyncClient instance\n#   with the correct settings.\n@registry.set_scope(\n    scope_class=SingletonScope,\n    auto_init=True,\n)\n@inject\nasync def get_nasa_client(\n    api_key: str = Provide(get_setting(\"nasa_api.api_key\")),\n    base_url: str = Provide(get_setting(\"nasa_api.base_url\")),\n    timeout: int = Provide(get_setting(\"nasa_api.timeout\")),\n) -\u003e httpx.AsyncClient:\n    async with httpx.AsyncClient(\n        base_url=base_url, params={\"api_key\": api_key}, timeout=timeout\n    ) as client:\n        yield client\n\n\n@inject\nasync def get_apod(\n    date: date, client: httpx.AsyncClient = Provide(get_nasa_client)\n) -\u003e dict[str, Any]:\n    # Printing the client ID to show that the same client is reused for all requests.\n    print(\"Client ID:\", id(client))\n    response = await client.get(\"/planetary/apod\", params={\"date\": date.isoformat()})\n    response.raise_for_status()\n    return response.json()\n\n\n@inject\n# Note that asynchronous `get_nasa_client` is injected\n#  in synchronous `print_client_info` function.\ndef print_client_info(client: httpx.AsyncClient = Provide(get_nasa_client)):\n    print(\"Client ID:\", id(client))\n    print(\"Client Base URL:\", client.base_url)\n    print(\"Client Params:\", client.params)\n    print(\"Client Timeout:\", client.timeout)\n\n\n# `lifespan` will initialize dependencies on the application startup.\n#   This will create the\n#   httpx.AsyncClient instance and cache it for later use. Thereby, the same\n#   client will be reused for all requests. This is important for connection\n#   pooling and performance. Because it's created on app startup,\n#   it will allow to pass asynchronous `get_nasa_client` into synchronous functions.\n# And closing all inited dependencies after the function execution.\n@registry.alifespan()\nasync def main():\n    print_client_info()\n\n    apod_data = await get_apod(date(2011, 7, 19))\n    print(\"Title:\", apod_data[\"title\"])\n\n    apod_data = await get_apod(date(2011, 7, 26))\n    print(\"Title:\", apod_data[\"title\"])\n\n\nasyncio.run(main())\n# Client ID: 4334576784\n# Client Base URL: https://api.nasa.gov\n# Client Params: api_key=DEMO_KEY\n# Client Timeout: Timeout(timeout=10)\n#\n# Client ID: 4334576784\n# Title: Vesta Vista\n#\n# Client ID: 4334576784\n# Title: Galaxy NGC 474: Cosmic Blender\n```\n\n## FastAPI Example Project\n\nHere is an example of a FastAPI application\nthat uses Picodi for dependency injection:\n\n[Picodi FastAPI Example](https://github.com/yakimka/picodi-fastapi-example)\n\n## License\n\n[MIT](https://github.com/yakimka/picodi/blob/main/LICENSE)\n\n## Contributing\n\nContributions are welcome!\nPlease read the [CONTRIBUTING.md](https://github.com/yakimka/picodi/blob/main/CONTRIBUTING.md) file for more information.\n\n## Credits\n\nThis project was generated with [`yakimka/cookiecutter-pyproject`](https://github.com/yakimka/cookiecutter-pyproject).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyakimka%2Fpicodi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyakimka%2Fpicodi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyakimka%2Fpicodi/lists"}