{"id":20819991,"url":"https://github.com/joeblackwaslike/quart-depends","last_synced_at":"2026-07-16T09:02:19.779Z","repository":{"id":206286558,"uuid":"716292643","full_name":"joeblackwaslike/quart-depends","owner":"joeblackwaslike","description":"Quart Depends | FastAPI like Dependency injection as a Quart extension for those locked into a legace monolith","archived":false,"fork":false,"pushed_at":"2023-11-09T17:24:27.000Z","size":23,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-01T01:14:28.152Z","etag":null,"topics":["dependency-injection","di","ioc","ioccontainer","quart"],"latest_commit_sha":null,"homepage":"","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/joeblackwaslike.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-11-08T20:42:37.000Z","updated_at":"2025-07-30T15:53:48.000Z","dependencies_parsed_at":"2023-11-10T01:09:13.308Z","dependency_job_id":"0974b9ec-d3bc-40ae-b4fc-abb8370f876e","html_url":"https://github.com/joeblackwaslike/quart-depends","commit_stats":null,"previous_names":["joeblackwaslike/quart-depends"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/joeblackwaslike/quart-depends","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joeblackwaslike%2Fquart-depends","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joeblackwaslike%2Fquart-depends/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joeblackwaslike%2Fquart-depends/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joeblackwaslike%2Fquart-depends/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joeblackwaslike","download_url":"https://codeload.github.com/joeblackwaslike/quart-depends/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joeblackwaslike%2Fquart-depends/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273588000,"owners_count":25132849,"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","status":"online","status_checked_at":"2025-09-04T02:00:08.968Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","ioc","ioccontainer","quart"],"created_at":"2024-11-17T22:08:02.354Z","updated_at":"2025-10-26T00:05:59.697Z","avatar_url":"https://github.com/joeblackwaslike.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# quart-depends\n\n[![PyPI - Version](https://img.shields.io/pypi/v/quart-depends.svg)](https://pypi.org/project/quart-depends)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/quart-depends.svg)](https://pypi.org/project/quart-depends)\n\n-----\n\n**Table of Contents**\n\n- [quart-depends](#quart-depends)\n  - [Installation](#installation)\n  - [Usage](#usage)\n    - [Manual wiring](#manual-wiring)\n    - [Autowiring](#autowiring)\n    - [Nested dependencies](#nested-dependencies)\n    - [Async support](#async-support)\n    - [Generator style dependencies](#generator-style-dependencies)\n      - [SQLAlchemy example](#sqlalchemy-example)\n      - [Httpx AsyncClient example](#httpx-asyncclient-example)\n    - [Annotated form](#annotated-form)\n    - [Defining reusable dependencies](#defining-reusable-dependencies)\n    - [Overriding dependencies](#overriding-dependencies)\n    - [Binders](#binders)\n      - [Learn more](#learn-more)\n    - [Related documentation](#related-documentation)\n  - [License](#license)\n\n## Installation\n\n```console\npip install quart-depends\n```\n\n## Usage\n### Manual wiring\nThis default mode of operation requires the developer to opt in wherever they want dependency\ninjection by applying the `inject`` decorator.\n```python\nfrom quart import Quart\n\nfrom quart_depends import QuartDepends, Depends, inject\n\napp = Quart(__name__)\ndepends = QuartDepends(app)\n\ndef get_db():\n    with Session() as session:\n        yield session\n\n@app.route(\"/\", methods=[\"POST\"])\n@inject\ndef index(session: Session = Depends(get_db)):\n    statement = select(User).where(User.id == 1)\n    obj = session.execute(statement).one()\n    return dict(status=\"ok\", data=obj.to_dict())\n\napp.run(port=8080)\n```\n\n### Autowiring\nIf you prefer to have the inject decorator applied automatically to all views, hooks, and callbacks\nyou can enable auto wiring via the Quart config mechanism.  You'll want to set the key\n`QUART_DEPENDS_AUTO_WIRE` to `True` as shown below.  When doing this, you'll want to delay app\ninitialization by not passing it to the QuartDepends constructor.  After all the views and\ncallbacks have been defined and registered, call init_app(app) on the extension object.\n\n```python\nfrom quart import Quart\n\nfrom quart_depends import QuartDepends, Depends, inject\n\napp = Quart(__name__)\napp.config['QUART_DEPENDS_AUTO_WIRE'] = True\ndepends = QuartDepends()\n\ndef get_db():\n    with Session() as session:\n        yield session\n\n@app.route(\"/\", methods=[\"POST\"])\ndef index(session: Session = Depends(get_db)):\n    statement = select(User).where(User.id == 1)\n    obj = session.execute(statement).one()\n    return dict(status=\"ok\", data=obj.to_dict())\n\n\ndepends.init_app(app)\napp.run(port=8080)\n```\n\n### Nested dependencies\nDependencies can be nested as deeply as you like, lookup will be resolved automatically and and wherever dependencies appear more than once in the graph, they will be resolved only once and the value shared among all dependents.\n\n### Async support\nIf you're using an async first framework such as quart, you probably want to leverage async dependencies as well as sync dependencies.  Luckily this extension will analyze each callable to see whether its async or blocking, and automatically wrap blocking calls that occur alongside async ones.  No need to apply `run_wait`!\n\n```python\nfrom quart import Quart\n\nfrom quart_depends import QuartDepends, Depends, inject\n\napp = Quart(__name__)\napp.config['QUART_DEPENDS_AUTO_WIRE'] = True\ndepends = QuartDepends()\n\ndef get_db():\n    async with AsyncSession() as session:\n        yield session\n\n@app.route(\"/\", methods=[\"POST\"])\nasync def index(session: AsyncSession = Depends(get_db)):\n    statement = select(User).where(User.id == 1)\n    obj = (await session.execute(statement)).one()\n    return dict(status=\"ok\", data=obj.to_dict())\n\n\ndepends.init_app(app)\napp.run(port=8080)\n```\n\n**Remember this important caveat:**  With async code we can use sync and async dependencies both, but with sync runtime only sync dependencies are available.\n\n### Generator style dependencies\nA common pattern when dealing with external IO such as databases, caches, connection pools, etc is for a set of calls to be wrapped in a context manager that handles the lifecycle of the underlying connection pool.  Some examples of this are SQLAlchemy's Connection, Session, and Transactions, Httx's async connection pooling, and even for instance, a redis pipeline execution.\n\n#### SQLAlchemy example\n```python\nimport sqlalchemy as sa\n\nengine = sa.create_engine(\"sqlite://\")\nmetadata = sa.MetaData(bind=engine)\nSession = sa.orm.sessionmaker()\n\nuser = sa.Table('user', metadata, ...)\n\nwith engine.connect() as connection:\n    with Session(bind=connection) as session:\n        with session.begin():\n            session.add(sa.insert(user).values(name=\"Joe\"))\n        # when this context closes, the session will have flush() and commit() called on it automatically\n    # when this context closes, the Session will have close() called on it automaticaly\n# When this context closes, the connection will have close() called on it automatically.\n```\n\n#### Httpx AsyncClient example\n```python\nimport httpx\n\nasync with httpx.AsyncClient() as client:\n    r = await client.post('https://github.com', json=dict(job=1, now=True))\n# connection pool will be closed automatically\n```\n\nThis is the most natural style to manage such dependencies using QuartDepends.  Just like we do with pytest fixtures, we'll open any necessary context managers, and within that nesting yield the dependency.  This will be the value injected by this Depends value at runtime.  However the framework will automatically take care of opening the context before and closing the context afterwards.  This works equally for both sync and async workflows.\n\n```python\ndef get_db():\n    async with AsyncSession() as session:\n        yield session\n\n@app.route(\"/\", methods=[\"POST\"])\nasync def index(session: AsyncSession = Depends(get_db)):\n    statement = select(User).where(User.id == 1)\n    obj = (await session.execute(statement)).one()\n    return dict(status=\"ok\", data=obj.to_dict())\n```\n\n### Annotated form\nLeveraging the power of typing.Annotated, many advanced patterns can be developed and cleanly packaged preserving type safety in most IDEs while remaining succinct and readable.  A popular pattern is to Wrap the Depends object along with the expected type using Annotated and assigning that a friendly, reusable name.\n```python\nfrom fast_depends import Depends, inject\nfrom pydantic import BaseModel, PositiveInt\n\nclass User(BaseModel):\n    user_id: PositiveInt\n\ndef get_user(user: id) -\u003e User:\n    return User(user_id=user)\n\n@inject\ndef do_smth_with_user(user: User = Depends(get_user)):\n    ...\n```\nbecomes\n```python\nfrom typing import Annotated\nfrom fast_depends import Depends, inject\nfrom pydantic import BaseModel, PositiveInt\n\nclass User(BaseModel):\n    user_id: PositiveInt\n\ndef get_user(user: id) -\u003e User:\n    return User(user_id=user)\n\nCurrentUser = Annotated[User, Depends(get_user)]\n\n@inject\ndef do_smth_with_user(user: CurrentUser):\n```\n\nThe caveat to using this is ensuring the correct ordering of argument types in callables.  Since `do_smth_with_user(user: CurrentUser)` no longer has a default value, it must appear before keyword only arguments in the signature of the callable.  You can address this by either assigning a default value of None or using Annotated with all arguments (where possible).  Nearly any argument can be converted to Annotated style using `pydantic.Field` and the following form:\n```python\ndef func(number):\n    ...\n```\nbecomes\n```python\ndef func(number: Annotated[int, Field(...)]):\n    ...\n```\nAnd you get pydantic style validation of any arguments for free.  Note this even be combined with the Annotated + Depends style for ultimate control!\n\n\n### Defining reusable dependencies\nWhether the @inject decorator is applied explicitely or automatically, its important to understand the scope for caching resolved dependencies.  The lifetime is scoped to a single call of the @inject decoratoed function/method.  This can often involve many deeply nested branches whenever a decorated view function is called and regardless of how deep, two dependencies of the same Depends will receive the same value shared amongst them.\n\n### Overriding dependencies\nFor testing purposes, its common to want to override a dependency to replace something with a mock, spy, etc.  It's recommended to turn QuartDepends.provider into a pytest fixture and use the methods override and clear for dependency overrides.  To override a dependency you want to provide an alternative callable to be swapped in for the original.\n\n```python\nfrom quart import Quart\nimport pytest\n\nfrom quart_depends import QuartDepends, Depends, inject\n\napp = Quart(__name__)\napp.config['QUART_DEPENDS_AUTO_WIRE'] = True\ndepends = QuartDepends()\n\nasync def get_db():\n    async with AsyncSession() as session:\n        yield session\n\n@app.route(\"/\", methods=[\"POST\"])\nasync def index(session: AsyncSession = Depends(get_db)):\n    statement = select(User).where(User.id == 1)\n    obj = (await session.execute(statement)).one()\n    return dict(status=\"ok\", data=obj.to_dict())\n\ndepends.init_app(app)\n\n\n@pytest.fixture\ndef dependency_provider():\n    return depends.provider\n\n\nasync def test_the_db(dependency_provider)\n    async def new_db():\n        yield MagicMock()\n\n    dependency_provider.override(get_db, new_db)\n\n    test_client = app.test_client()\n\n    resp = await test_client.post(\"/\")\n\n    dependency_provider.clear()\n    \n    ...\n```\n\n### Binders\nBinders are classes allowing important bits of a request to be extracted and type coerced, sometimes even into pydantic models using a very succinct syntax that doesn't require defining functions that parse the request object.\n\n```python\nclass CommonQuery(BaseModel):\n    q: t.Optional[str] = None\n    skip: int = 0\n    limit: int = 100\n \n\n@app.route(uri, methods=[\"GET\"])\nasync def view(\n    paging: FromQueryData[CommonQuery] = None,\n    sort: FromQueryField[t.Literal[\"asc\", \"desc\"]] = None,\n):\n    return dict(paging=paging.dict(), sort=sort)\n```\n\n```python\nclass ReqPayload(BaseModel):\n    name: str = \"\"\n    age: int = 0\n\n\n@app.route(\"/use/\u003cstring:label\u003e\", methods=[\"POST\"])\nasync def view(\n    accept: FromHeader[str] = None,\n    q: FromQueryField[str] = None,\n    label: FromPath[str] = None,\n    payload: FromJson[ReqPayload] = None,\n    cookie: FromCookie[str] = None,\n):\n    assert isinstance(request, QuartRequest)\n    assert payload.dict() == jsondict\n\n    return dict(\n        body=body,\n        accept=accept,\n        q=str(q),\n        label=label,\n        payload=payload.dict(),\n        common=common.dict(),\n        cookie=cookie,\n    )\n```\n\n#### Learn more\n* [Checkout more examples in the test suite.](tests/integration/test_custom_fields.py)\n* [FastDepends docs for CustomField](https://lancetnik.github.io/FastDepends/advanced/)\n\n\n### Related documentation\n* [FastDepends Docs](https://lancetnik.github.io/FastDepends/)\n* [FastAPI Dependencies Docs](https://fastapi.tiangolo.com/tutorial/dependencies/)\n* [FastAPI Advanced Dependencies Docs](https://fastapi.tiangolo.com/advanced/advanced-dependencies/)\n\n## License\n`quart-depends` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoeblackwaslike%2Fquart-depends","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoeblackwaslike%2Fquart-depends","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoeblackwaslike%2Fquart-depends/lists"}