From 9e41cafd3f29a3bfa411302c9f343e62428163a8 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 27 Mar 2024 12:22:10 +0200 Subject: [PATCH 01/13] Extras required for local development --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f8d1f93..f134805 100644 --- a/README.md +++ b/README.md @@ -332,7 +332,7 @@ def client(injector: DependencyInjector, service_mock: Service): * Create a virtual environment and install the dependencies ```sh -poetry install +poetry install --all-extras ``` * Activate the virtual environment From 4b56b8494c4f5d941d992a9c2fbc0f6883f82c7d Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 27 Mar 2024 12:24:12 +0200 Subject: [PATCH 02/13] Add changelog entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f436d9..e39b33f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,3 +4,5 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +### Changed +- Initial version From 1bf0f7d3705bd0c0a62044a9c267b681ca097e61 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 27 Mar 2024 12:29:01 +0200 Subject: [PATCH 03/13] Use Wolt in LICENCE --- LICENCE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENCE b/LICENCE index 690a230..ccaa05d 100644 --- a/LICENCE +++ b/LICENCE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2021 Nikita Zavadin +Copyright (c) 2024 Wolt Enterprises Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in From db96222b045c074ec1fd9f1c6e9dda36b6b10074 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 27 Mar 2024 12:32:51 +0200 Subject: [PATCH 04/13] Fix GitHub username --- .cruft.json | 2 +- README.md | 8 ++++---- pyproject.toml | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.cruft.json b/.cruft.json index 090f177..4569f3c 100644 --- a/.cruft.json +++ b/.cruft.json @@ -6,7 +6,7 @@ "cookiecutter": { "author_name": "Nikita Zavadin", "author_email": "nikita.zavadin@wolt.com", - "github_username": "RB387", + "github_username": "woltapp", "project_name": "magic-di", "project_slug": "magic-di", "package_name": "magic_di", diff --git a/README.md b/README.md index f134805..0cbab46 100644 --- a/README.md +++ b/README.md @@ -349,17 +349,17 @@ pytest ### Documentation -The documentation is automatically generated from the content of the [docs directory](https://github.com/RB387/magic-di/tree/master/docs) and from the docstrings +The documentation is automatically generated from the content of the [docs directory](https://github.com/woltapp/magic-di/tree/master/docs) and from the docstrings of the public signatures of the source code. The documentation is updated and published as a [Github Pages page](https://pages.github.com/) automatically as part each release. ### Releasing -Trigger the [Draft release workflow](https://github.com/RB387/magic-di/actions/workflows/draft_release.yml) +Trigger the [Draft release workflow](https://github.com/woltapp/magic-di/actions/workflows/draft_release.yml) (press _Run workflow_). This will update the changelog & version and create a GitHub release which is in _Draft_ state. Find the draft release from the -[GitHub releases](https://github.com/RB387/magic-di/releases) and publish it. When - a release is published, it'll trigger [release](https://github.com/RB387/magic-di/blob/master/.github/workflows/release.yml) workflow which creates PyPI +[GitHub releases](https://github.com/woltapp/magic-di/releases) and publish it. When + a release is published, it'll trigger [release](https://github.com/woltapp/magic-di/blob/master/.github/workflows/release.yml) workflow which creates PyPI release and deploys updated documentation. ### Pre-commit diff --git a/pyproject.toml b/pyproject.toml index 69bd7cf..9cee89b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,9 +8,9 @@ authors = [ license = "MIT" readme = "README.md" -documentation = "https://RB387.github.io/magic-di" -homepage = "https://RB387.github.io/magic-di" -repository = "https://github.com/RB387/magic-di" +documentation = "https://woltapp.github.io/magic-di" +homepage = "https://woltapp.github.io/magic-di" +repository = "https://github.com/woltapp/magic-di" classifiers = [ "Development Status :: 4 - Beta", From d2d8af112b3d3f6f6558080128a85060acf93bf6 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 27 Mar 2024 13:04:48 +0200 Subject: [PATCH 05/13] Add alternatives section --- README.md | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 0cbab46..577a829 100644 --- a/README.md +++ b/README.md @@ -16,19 +16,10 @@ --- -Dependency Injector that makes your life easier with built-in support of FastAPI, Celery (and it can be integrated with everything) - -What are the problems with FastAPI’s dependency injector? -1) It forces you to use global variables. -2) You need to write an endless number of fabrics with startup logic -3) It makes your project highly dependent on FastAPI’s injector by using “Depends” everywhere. - -To solve these problems, you can use this dead-simple Dependency Injector that will make development so much easier. - -__Q: But why not to use [python-dependency-injector](https://github.com/ets-labs/python-dependency-injector) or other libs?__ - -A: The goal of this Dependency Injector is to __reduce the amount of code as much as possible__ and get rid of enterprise code with millions of configs, containers, and fabrics. That’s why python-dependency-injector and similar libraries are overkill. The philosophy of this injector is that clients know how to configure themselves and perform all startup routines. +Dependency Injector with minimal boilerplate code, built-in support for FastAPI and Celery, and seamless integration to basically anything. +## Contents +* [Alternatives](#alternatives) * [Install](#install) * [Getting Started](#getting-started) * [Clients Configuration](#clients-configuration) @@ -44,6 +35,22 @@ A: The goal of this Dependency Injector is to __reduce the amount of code as muc * [Development](#development) +## Alternatives + +### [FastAPI's built-in dependency injection](https://fastapi.tiangolo.com/tutorial/dependencies/) + +FastAPI's built-in DI is great, but it makes the project (and its business logic) dependent on FastAPI, `fastapi.Depends` specifically. + +`magic-di` decouples DI from other dependencies while still offering seamless integration to FastAPI, for example. + +### [python-dependency-injector](https://github.com/ets-labs/python-dependency-injector) + +[python-dependency-injector](https://github.com/ets-labs/python-dependency-injector) is great, but it requires a notable amount of boilerplate code. + +The goal of `magic-di` is to __reduce the amount of code as much as possible__ and get rid of enterprise code with countless configs, containers, and fabrics. +The philosophy of `magic-di` is that clients know how to configure themselves and perform all startup routines. + + ## Install ```bash pip install 'magic-di[fastapi]' From eff5fac65d790964145108d3a22f9cbb3fd34bda Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 27 Mar 2024 13:06:06 +0200 Subject: [PATCH 06/13] Move alternatives lower --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 577a829..02b24d1 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,6 @@ Dependency Injector with minimal boilerplate code, built-in support for FastAPI and Celery, and seamless integration to basically anything. ## Contents -* [Alternatives](#alternatives) * [Install](#install) * [Getting Started](#getting-started) * [Clients Configuration](#clients-configuration) @@ -32,25 +31,10 @@ Dependency Injector with minimal boilerplate code, built-in support for FastAPI * [Testing](#testing) * [Default simple mock](#default-simple-mock) * [Custom mocks](#custom-mocks) +* [Alternatives](#alternatives) * [Development](#development) -## Alternatives - -### [FastAPI's built-in dependency injection](https://fastapi.tiangolo.com/tutorial/dependencies/) - -FastAPI's built-in DI is great, but it makes the project (and its business logic) dependent on FastAPI, `fastapi.Depends` specifically. - -`magic-di` decouples DI from other dependencies while still offering seamless integration to FastAPI, for example. - -### [python-dependency-injector](https://github.com/ets-labs/python-dependency-injector) - -[python-dependency-injector](https://github.com/ets-labs/python-dependency-injector) is great, but it requires a notable amount of boilerplate code. - -The goal of `magic-di` is to __reduce the amount of code as much as possible__ and get rid of enterprise code with countless configs, containers, and fabrics. -The philosophy of `magic-di` is that clients know how to configure themselves and perform all startup routines. - - ## Install ```bash pip install 'magic-di[fastapi]' @@ -330,6 +314,22 @@ def client(injector: DependencyInjector, service_mock: Service): yield client ``` +## Alternatives + +### [FastAPI's built-in dependency injection](https://fastapi.tiangolo.com/tutorial/dependencies/) + +FastAPI's built-in DI is great, but it makes the project (and its business logic) dependent on FastAPI, `fastapi.Depends` specifically. + +`magic-di` decouples DI from other dependencies while still offering seamless integration to FastAPI, for example. + +### [python-dependency-injector](https://github.com/ets-labs/python-dependency-injector) + +[python-dependency-injector](https://github.com/ets-labs/python-dependency-injector) is great, but it requires a notable amount of boilerplate code. + +The goal of `magic-di` is to __reduce the amount of code as much as possible__ and get rid of enterprise code with countless configs, containers, and fabrics. +The philosophy of `magic-di` is that clients know how to configure themselves and perform all startup routines. + + ## Development * Clone this repository From 6fe6ba691587955f4455e74f1f42bbbe1c5090c4 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 27 Mar 2024 13:07:58 +0200 Subject: [PATCH 07/13] Use 3.10 as target for Ruff --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9cee89b..b2b1467 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" [tool.ruff] -target-version = "py38" # The lowest supported version +target-version = "py10" # The lowest supported version line-length = 100 [tool.ruff.lint] From de4f1f0007e58e26fd58673a58800d7ce3c44d2b Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 27 Mar 2024 13:08:10 +0200 Subject: [PATCH 08/13] 3.8+ -> 3.10+ --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02b24d1..3504c42 100644 --- a/README.md +++ b/README.md @@ -335,7 +335,7 @@ The philosophy of `magic-di` is that clients know how to configure themselves an * Clone this repository * Requirements: * [Poetry](https://python-poetry.org/) - * Python 3.8+ + * Python 3.10+ * Create a virtual environment and install the dependencies ```sh From b4056f7b28c2300a586d6124844bed313ea3d443 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 27 Mar 2024 13:11:05 +0200 Subject: [PATCH 09/13] Add mention about extras --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 3504c42..070a010 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,19 @@ Dependency Injector with minimal boilerplate code, built-in support for FastAPI ## Install ```bash +pip install magic-di +``` + +With FastAPI integration: +```bash pip install 'magic-di[fastapi]' ``` +With Celery integration: +```bash +pip install 'magic-di[celery]' +``` + ## Getting Started ```python From c26da0e6e2ff395f20c6ed8fe3dc12dc8a1900aa Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 27 Mar 2024 13:17:14 +0200 Subject: [PATCH 10/13] Fix target version for Ruff --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b2b1467..38beb6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" [tool.ruff] -target-version = "py10" # The lowest supported version +target-version = "py310" # The lowest supported version line-length = 100 [tool.ruff.lint] From 4f3d58fd25c01ba7c677beeb1613c0353284e550 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 27 Mar 2024 13:25:49 +0200 Subject: [PATCH 11/13] Remove redundant comment --- .pre-commit-config.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 05e14ab..a9d26fb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,7 +23,6 @@ repos: types: [ python ] - id: ruff name: ruff - # Add --fix, in case you want it to autofix when this hook runs entry: poetry run ruff check --fix --force-exclude require_serial: true language: system From f798237ae404e8b33e2a9b51e87caa527447b7a1 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 27 Mar 2024 13:26:37 +0200 Subject: [PATCH 12/13] Let Ruff fix things to be happy with 3.10+ --- src/magic_di/_container.py | 3 ++- src/magic_di/_injector.py | 4 +--- src/magic_di/celery/_async_utils.py | 3 ++- src/magic_di/celery/_loader.py | 3 ++- src/magic_di/celery/_task.py | 3 ++- src/magic_di/exceptions.py | 3 ++- src/magic_di/fastapi/_app.py | 4 +--- src/magic_di/utils.py | 3 ++- tests/test_app.py | 8 ++++---- tests/test_celery.py | 17 +++++++++-------- 10 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/magic_di/_container.py b/src/magic_di/_container.py index 3cce013..8506f45 100644 --- a/src/magic_di/_container.py +++ b/src/magic_di/_container.py @@ -2,9 +2,10 @@ import functools import inspect +from collections.abc import Iterable from dataclasses import dataclass from threading import Lock -from typing import TYPE_CHECKING, Any, Generic, Iterable, TypeVar, cast +from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast if TYPE_CHECKING: from magic_di import ConnectableProtocol diff --git a/src/magic_di/_injector.py b/src/magic_di/_injector.py index 4dbe6dc..322e0d0 100644 --- a/src/magic_di/_injector.py +++ b/src/magic_di/_injector.py @@ -2,15 +2,13 @@ import inspect import logging +from collections.abc import Callable, Iterable, Iterator from contextlib import contextmanager from threading import Lock from typing import ( TYPE_CHECKING, Annotated, Any, - Callable, - Iterable, - Iterator, TypeVar, cast, get_origin, diff --git a/src/magic_di/celery/_async_utils.py b/src/magic_di/celery/_async_utils.py index 80f5f0e..d835c1e 100644 --- a/src/magic_di/celery/_async_utils.py +++ b/src/magic_di/celery/_async_utils.py @@ -2,8 +2,9 @@ import asyncio import threading +from collections.abc import Coroutine from dataclasses import dataclass -from typing import Any, Coroutine, TypeVar +from typing import Any, TypeVar R = TypeVar("R") diff --git a/src/magic_di/celery/_loader.py b/src/magic_di/celery/_loader.py index 472fedb..5257002 100644 --- a/src/magic_di/celery/_loader.py +++ b/src/magic_di/celery/_loader.py @@ -3,7 +3,8 @@ import asyncio import os import threading -from typing import TYPE_CHECKING, Any, Callable, Protocol, runtime_checkable +from collections.abc import Callable +from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable from celery import signals from celery.loaders.app import AppLoader # type: ignore[import-untyped] diff --git a/src/magic_di/celery/_task.py b/src/magic_di/celery/_task.py index e039e92..62c7389 100644 --- a/src/magic_di/celery/_task.py +++ b/src/magic_di/celery/_task.py @@ -1,8 +1,9 @@ from __future__ import annotations import inspect +from collections.abc import Callable from functools import wraps -from typing import Any, Callable, cast, get_type_hints +from typing import Any, cast, get_type_hints from celery.app.task import Task diff --git a/src/magic_di/exceptions.py b/src/magic_di/exceptions.py index aa7d13f..a82db10 100644 --- a/src/magic_di/exceptions.py +++ b/src/magic_di/exceptions.py @@ -1,5 +1,6 @@ import inspect -from typing import Any, Callable +from collections.abc import Callable +from typing import Any from magic_di._signature import Signature from magic_di._utils import get_type_hints diff --git a/src/magic_di/fastapi/_app.py b/src/magic_di/fastapi/_app.py index 4cefd8c..a8ff81e 100644 --- a/src/magic_di/fastapi/_app.py +++ b/src/magic_di/fastapi/_app.py @@ -1,14 +1,12 @@ from __future__ import annotations import inspect +from collections.abc import AsyncIterator, Callable, Iterator from contextlib import asynccontextmanager from typing import ( TYPE_CHECKING, Annotated, Any, - AsyncIterator, - Callable, - Iterator, Protocol, get_origin, runtime_checkable, diff --git a/src/magic_di/utils.py b/src/magic_di/utils.py index 0c87902..f893efa 100644 --- a/src/magic_di/utils.py +++ b/src/magic_di/utils.py @@ -2,7 +2,8 @@ import asyncio import inspect -from typing import TYPE_CHECKING, Awaitable, TypeVar, overload +from collections.abc import Awaitable +from typing import TYPE_CHECKING, TypeVar, overload from magic_di import DependencyInjector diff --git a/tests/test_app.py b/tests/test_app.py index 3bbaa55..f21f637 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -14,7 +14,7 @@ def test_app_injection(injector: DependencyInjector) -> None: app = inject_app(FastAPI(), injector=injector) @app.get(path="/hello-world") - def hello_world(service: Provide[Service], some_query: str) -> dict[str, str | bool]: # noqa: FA102 + def hello_world(service: Provide[Service], some_query: str) -> dict[str, str | bool]: assert isinstance(service, Service) return {"query": some_query, "is_alive": service.is_alive()} @@ -42,7 +42,7 @@ def global_dependency(dep: Provide[GlobalConnect]) -> None: class MiddlewareNonConnectable: creds: str = "secret_creds" - def get_creds(self, value: str | None = None) -> str: # noqa: FA102 + def get_creds(self, value: str | None = None) -> str: return value or self.creds class AnotherDatabase(Database): ... @@ -65,7 +65,7 @@ def get_creds( def hello_world( service: Provide[Service], creds: Annotated[str, Depends(get_creds)], - ) -> dict[str, str | bool]: # noqa: FA102 + ) -> dict[str, str | bool]: assert isinstance(service, Service) return {"creds": creds, "is_alive": service.is_alive()} @@ -90,7 +90,7 @@ def test_app_injection_clients_connect( router = APIRouter() @router.get(path="/hello-world") - def hello_world(service: Provide[Service]) -> dict[str, bool]: # noqa: FA102 + def hello_world(service: Provide[Service]) -> dict[str, bool]: assert service.workers return { diff --git a/tests/test_celery.py b/tests/test_celery.py index 20430b4..a309f87 100644 --- a/tests/test_celery.py +++ b/tests/test_celery.py @@ -1,9 +1,10 @@ import contextlib import tempfile +from collections.abc import Iterator from contextlib import contextmanager from dataclasses import dataclass from threading import Thread -from typing import Any, Iterator, cast +from typing import Any, cast from unittest.mock import MagicMock, call import pytest @@ -57,7 +58,7 @@ async def service_ping( arg1: int, arg2: str, service: Service = PROVIDE, - ) -> tuple[int, str, bool]: # noqa: FA102 + ) -> tuple[int, str, bool]: return arg1, arg2, service.is_alive() return cast(InjectableCeleryTask, service_ping) @@ -70,7 +71,7 @@ def service_ping_sync( arg1: int, arg2: str, service: Service = PROVIDE, - ) -> tuple[int, str, bool]: # noqa: FA102 + ) -> tuple[int, str, bool]: return arg1, arg2, service.is_alive() return cast(InjectableCeleryTask, service_ping_sync) @@ -85,7 +86,7 @@ class Deps(BaseCeleryConnectableDeps): class SyncServicePingTask(InjectableCeleryTask): deps: Deps - async def run(self, arg1: int, arg2: str) -> tuple[int, str, bool]: # noqa: FA102 + async def run(self, arg1: int, arg2: str) -> tuple[int, str, bool]: return arg1, arg2, self.deps.db.connected return SyncServicePingTask() @@ -100,7 +101,7 @@ class Deps(BaseCeleryConnectableDeps): class ServicePingTask(InjectableCeleryTask): deps: Deps - def run(self, arg1: int, arg2: str) -> tuple[int, str, bool]: # noqa: FA102 + def run(self, arg1: int, arg2: str) -> tuple[int, str, bool]: return arg1, arg2, self.deps.db.connected return ServicePingTask() @@ -266,7 +267,7 @@ async def test_async_function_based_tasks_inside_event_loop( *, task_always_eager: bool, use_broker_and_backend: bool, - expected_mock_calls: list[Any], # noqa: FA102 + expected_mock_calls: list[Any], ) -> None: injector = DependencyInjector() @@ -280,14 +281,14 @@ async def ping_task( arg1: int, arg2: str, service: Service = PROVIDE, - ) -> tuple[int, str, bool]: # noqa: FA102 + ) -> tuple[int, str, bool]: mock() return arg1, arg2, service.is_alive() fastapi_app = FastAPI() @fastapi_app.get("/") - async def handler() -> dict[str, bool]: # noqa: FA102 + async def handler() -> dict[str, bool]: ping_task.apply_async(args=(1337, "leet")) ping_task.apply(args=(1337, "leet-2")) return {"ok": True} From 7fe09ec1efdf78ad6048b2d04ed42df634ce5276 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 27 Mar 2024 13:37:20 +0200 Subject: [PATCH 13/13] Fix Ruff / mypy issues --- src/magic_di/_container.py | 3 ++- src/magic_di/_injector.py | 3 ++- src/magic_di/_utils.py | 8 ++++---- src/magic_di/celery/_async_utils.py | 6 ++++-- src/magic_di/celery/_loader.py | 3 ++- src/magic_di/celery/_task.py | 6 ++++-- src/magic_di/fastapi/_app.py | 3 ++- src/magic_di/utils.py | 3 +-- 8 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/magic_di/_container.py b/src/magic_di/_container.py index 8506f45..ddc8843 100644 --- a/src/magic_di/_container.py +++ b/src/magic_di/_container.py @@ -2,12 +2,13 @@ import functools import inspect -from collections.abc import Iterable from dataclasses import dataclass from threading import Lock from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast if TYPE_CHECKING: + from collections.abc import Iterable + from magic_di import ConnectableProtocol T = TypeVar("T") diff --git a/src/magic_di/_injector.py b/src/magic_di/_injector.py index 322e0d0..59878e0 100644 --- a/src/magic_di/_injector.py +++ b/src/magic_di/_injector.py @@ -2,7 +2,6 @@ import inspect import logging -from collections.abc import Callable, Iterable, Iterator from contextlib import contextmanager from threading import Lock from typing import ( @@ -25,6 +24,8 @@ from magic_di.exceptions import InjectionError, InspectionError if TYPE_CHECKING: + from collections.abc import Callable, Iterable, Iterator + from magic_di._connectable import ConnectableProtocol # flag to use in typing.Annotated diff --git a/src/magic_di/_utils.py b/src/magic_di/_utils.py index a4b8e56..63825f5 100644 --- a/src/magic_di/_utils.py +++ b/src/magic_di/_utils.py @@ -1,16 +1,16 @@ from __future__ import annotations -from typing import Any, TypeVar, Union, cast, get_args +from typing import Any, TypeVar, cast, get_args from typing import get_type_hints as _get_type_hints from magic_di import ConnectableProtocol -LegacyUnionType = type(Union[object, None]) +LegacyUnionType = type(object | None) try: from types import UnionType # type: ignore[import-error,unused-ignore] except ImportError: - UnionType = LegacyUnionType # type: ignore[misc, assignment] + UnionType = LegacyUnionType # type: ignore[misc] T = TypeVar("T") @@ -40,7 +40,7 @@ def get_cls_from_optional(cls: T) -> T: Returns: T: Extracted class """ - if not isinstance(cls, (UnionType, LegacyUnionType)): + if not isinstance(cls, UnionType | LegacyUnionType): return cls args = get_args(cls) diff --git a/src/magic_di/celery/_async_utils.py b/src/magic_di/celery/_async_utils.py index d835c1e..1a7fc22 100644 --- a/src/magic_di/celery/_async_utils.py +++ b/src/magic_di/celery/_async_utils.py @@ -2,9 +2,11 @@ import asyncio import threading -from collections.abc import Coroutine from dataclasses import dataclass -from typing import Any, TypeVar +from typing import TYPE_CHECKING, Any, TypeVar + +if TYPE_CHECKING: + from collections.abc import Coroutine R = TypeVar("R") diff --git a/src/magic_di/celery/_loader.py b/src/magic_di/celery/_loader.py index 5257002..68e95a4 100644 --- a/src/magic_di/celery/_loader.py +++ b/src/magic_di/celery/_loader.py @@ -3,7 +3,6 @@ import asyncio import os import threading -from collections.abc import Callable from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable from celery import signals @@ -13,6 +12,8 @@ from magic_di.celery._async_utils import EventLoop, EventLoopGetter, run_in_event_loop if TYPE_CHECKING: + from collections.abc import Callable + from celery.loaders.base import BaseLoader diff --git a/src/magic_di/celery/_task.py b/src/magic_di/celery/_task.py index 62c7389..1ec1d3f 100644 --- a/src/magic_di/celery/_task.py +++ b/src/magic_di/celery/_task.py @@ -1,9 +1,8 @@ from __future__ import annotations import inspect -from collections.abc import Callable from functools import wraps -from typing import Any, cast, get_type_hints +from typing import TYPE_CHECKING, Any, cast, get_type_hints from celery.app.task import Task @@ -11,6 +10,9 @@ from magic_di.celery._async_utils import EventLoop, run_in_event_loop from magic_di.celery._loader import InjectedCeleryLoaderProtocol +if TYPE_CHECKING: + from collections.abc import Callable + class BaseCeleryConnectableDeps(Connectable): ... diff --git a/src/magic_di/fastapi/_app.py b/src/magic_di/fastapi/_app.py index a8ff81e..cd20d92 100644 --- a/src/magic_di/fastapi/_app.py +++ b/src/magic_di/fastapi/_app.py @@ -1,7 +1,6 @@ from __future__ import annotations import inspect -from collections.abc import AsyncIterator, Callable, Iterator from contextlib import asynccontextmanager from typing import ( TYPE_CHECKING, @@ -17,6 +16,8 @@ from magic_di._injector import DependencyInjector if TYPE_CHECKING: + from collections.abc import AsyncIterator, Callable, Iterator + from fastapi import FastAPI, routing diff --git a/src/magic_di/utils.py b/src/magic_di/utils.py index f893efa..72c481f 100644 --- a/src/magic_di/utils.py +++ b/src/magic_di/utils.py @@ -2,13 +2,12 @@ import asyncio import inspect -from collections.abc import Awaitable from typing import TYPE_CHECKING, TypeVar, overload from magic_di import DependencyInjector if TYPE_CHECKING: - from collections.abc import Callable + from collections.abc import Awaitable, Callable T = TypeVar("T")