anydi 0.48.2__py3-none-any.whl → 0.52.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
anydi/_async.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import functools
2
+ from collections.abc import Callable
2
3
  from types import TracebackType
3
- from typing import Any, Callable, TypeVar
4
+ from typing import Any, TypeVar
4
5
 
5
6
  import anyio.to_thread
6
7
  from typing_extensions import ParamSpec, Self
anydi/_container.py CHANGED
@@ -9,11 +9,11 @@ import logging
9
9
  import types
10
10
  import uuid
11
11
  from collections import defaultdict
12
- from collections.abc import AsyncIterator, Iterable, Iterator
12
+ from collections.abc import AsyncIterator, Callable, Iterable, Iterator
13
13
  from contextvars import ContextVar
14
- from typing import Annotated, Any, Callable, TypeVar, cast, overload
14
+ from typing import Annotated, Any, TypeVar, cast, get_args, get_origin, overload
15
15
 
16
- from typing_extensions import ParamSpec, Self, get_args, get_origin
16
+ from typing_extensions import ParamSpec, Self, type_repr
17
17
 
18
18
  from ._async import run_sync
19
19
  from ._context import InstanceContext
@@ -33,7 +33,6 @@ from ._typing import (
33
33
  is_inject_marker,
34
34
  is_iterator_type,
35
35
  is_none_type,
36
- type_repr,
37
36
  )
38
37
 
39
38
  T = TypeVar("T", bound=Any)
@@ -808,7 +807,10 @@ class Container:
808
807
  marker = metadata[-1]
809
808
  new_metadata = metadata[:-1]
810
809
  if new_metadata:
811
- new_annotation = Annotated.__class_getitem__((origin, *new_metadata)) # type: ignore
810
+ if hasattr(Annotated, "__getitem__"):
811
+ new_annotation = Annotated.__getitem__((origin, *new_metadata)) # type: ignore
812
+ else:
813
+ new_annotation = Annotated.__class_getitem__((origin, *new_metadata)) # type: ignore
812
814
  else:
813
815
  new_annotation = origin
814
816
  return parameter.replace(annotation=new_annotation, default=marker)
anydi/_decorators.py CHANGED
@@ -1,8 +1,7 @@
1
- from collections.abc import Iterable
1
+ from collections.abc import Callable, Iterable
2
2
  from typing import (
3
3
  TYPE_CHECKING,
4
4
  Any,
5
- Callable,
6
5
  Concatenate,
7
6
  ParamSpec,
8
7
  Protocol,
anydi/_module.py CHANGED
@@ -2,7 +2,8 @@ from __future__ import annotations
2
2
 
3
3
  import importlib
4
4
  import inspect
5
- from typing import TYPE_CHECKING, Any, Callable
5
+ from collections.abc import Callable
6
+ from typing import TYPE_CHECKING, Any
6
7
 
7
8
  from ._decorators import ProviderMetadata, is_provider
8
9
 
anydi/_provider.py CHANGED
@@ -2,9 +2,10 @@ from __future__ import annotations
2
2
 
3
3
  import enum
4
4
  import inspect
5
+ from collections.abc import Callable
5
6
  from dataclasses import dataclass
6
7
  from functools import cached_property
7
- from typing import Any, Callable, NamedTuple
8
+ from typing import Any, NamedTuple
8
9
 
9
10
  from ._scope import Scope
10
11
  from ._typing import NOT_SET
anydi/_scan.py CHANGED
@@ -3,10 +3,10 @@ from __future__ import annotations
3
3
  import importlib
4
4
  import inspect
5
5
  import pkgutil
6
- from collections.abc import Iterable
6
+ from collections.abc import Callable, Iterable
7
7
  from dataclasses import dataclass
8
8
  from types import ModuleType
9
- from typing import TYPE_CHECKING, Any, Callable, Union
9
+ from typing import TYPE_CHECKING, Any
10
10
 
11
11
  from ._decorators import is_injectable
12
12
  from ._typing import get_typed_parameters, is_inject_marker
@@ -14,8 +14,8 @@ from ._typing import get_typed_parameters, is_inject_marker
14
14
  if TYPE_CHECKING:
15
15
  from ._container import Container
16
16
 
17
- Package = Union[ModuleType, str]
18
- PackageOrIterable = Union[Package, Iterable[Package]]
17
+ Package = ModuleType | str
18
+ PackageOrIterable = Package | Iterable[Package]
19
19
 
20
20
 
21
21
  @dataclass(kw_only=True)
anydi/_typing.py CHANGED
@@ -3,44 +3,9 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import inspect
6
- import re
7
- import sys
8
- from collections.abc import AsyncIterator, Iterator
9
- from typing import Any, Callable, ForwardRef, TypeVar
10
-
11
- from typing_extensions import get_args, get_origin
12
-
13
- try:
14
- from types import NoneType
15
- except ImportError:
16
- NoneType = type(None)
17
-
18
-
19
- T = TypeVar("T")
20
-
21
-
22
- def type_repr(obj: Any) -> str:
23
- """Get a string representation of a type or object."""
24
- if isinstance(obj, str):
25
- return obj
26
-
27
- # Get module and qualname with defaults to handle non-types directly
28
- module = getattr(obj, "__module__", type(obj).__module__)
29
- qualname = getattr(obj, "__qualname__", type(obj).__qualname__)
30
-
31
- origin = get_origin(obj)
32
- # If origin exists, handle generics recursively
33
- if origin:
34
- args = ", ".join(type_repr(arg) for arg in get_args(obj))
35
- return f"{type_repr(origin)}[{args}]"
36
-
37
- # Substitute standard library prefixes for clarity
38
- full_qualname = f"{module}.{qualname}"
39
- return re.sub(
40
- r"\b(builtins|typing|typing_extensions|collections\.abc|types)\.",
41
- "",
42
- full_qualname,
43
- )
6
+ from collections.abc import AsyncIterator, Callable, Iterator
7
+ from types import NoneType
8
+ from typing import Any, ForwardRef
44
9
 
45
10
 
46
11
  def is_context_manager(obj: Any) -> bool:
@@ -68,11 +33,8 @@ def get_typed_annotation(
68
33
  ) -> Any:
69
34
  """Get the typed annotation of a callable object."""
70
35
  if isinstance(annotation, str):
71
- if sys.version_info >= (3, 10):
72
- ref = ForwardRef(annotation, module=module)
73
- else:
74
- ref = ForwardRef(annotation)
75
- annotation = ref._evaluate(globalns, globalns, recursive_guard=frozenset()) # noqa
36
+ ref = ForwardRef(annotation, module=module)
37
+ annotation = ref._evaluate(globalns, globalns, recursive_guard=frozenset()) # type: ignore[reportDeprecated]
76
38
  return annotation
77
39
 
78
40
 
@@ -1,9 +1,8 @@
1
- from ._container import container
2
- from ._utils import inject_urlpatterns, register_components, register_settings
3
-
4
- __all__ = [
5
- "container",
6
- "register_components",
7
- "register_settings",
8
- "inject_urlpatterns",
9
- ]
1
+ raise ImportError(
2
+ "The Django extension requires additional dependencies.\n\n"
3
+ "Install one of the following extras:\n"
4
+ " pip install 'anydi-django' # for Django\n"
5
+ " pip install 'anydi-django[ninja]' # for Django Ninja\n\n"
6
+ "Then, instead of importing from 'anydi.ext.django', import directly from:\n"
7
+ " import anydi_django\n"
8
+ )
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- from collections.abc import Iterable
4
- from typing import Annotated, Any, Callable
3
+ from collections.abc import Callable, Iterable
4
+ from typing import Annotated, Any
5
5
 
6
6
  from pydantic.fields import ComputedFieldInfo, FieldInfo # noqa
7
7
  from pydantic_settings import BaseSettings
@@ -2,8 +2,8 @@ from __future__ import annotations
2
2
 
3
3
  import inspect
4
4
  import logging
5
- from collections.abc import Iterator
6
- from typing import Any, Callable, cast
5
+ from collections.abc import Callable, Iterator
6
+ from typing import Any, cast
7
7
 
8
8
  import pytest
9
9
  from anyio.pytest_plugin import extract_backend_and_options, get_runner
anydi/testing.py CHANGED
@@ -5,14 +5,13 @@ from collections.abc import Iterable, Iterator, Sequence
5
5
  from typing import Any, TypeVar
6
6
 
7
7
  import wrapt # type: ignore
8
- from typing_extensions import Self
8
+ from typing_extensions import Self, type_repr
9
9
 
10
10
  from ._container import Container
11
11
  from ._context import InstanceContext
12
12
  from ._module import ModuleDef
13
13
  from ._provider import Provider, ProviderDef
14
14
  from ._scope import Scope
15
- from ._typing import type_repr
16
15
 
17
16
  T = TypeVar("T")
18
17
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: anydi
3
- Version: 0.48.2
3
+ Version: 0.52.0
4
4
  Summary: Dependency Injection library
5
5
  Keywords: dependency injection,dependencies,di,async,asyncio,application
6
6
  Author: Anton Ruhlov
@@ -20,16 +20,16 @@ Classifier: Environment :: Web Environment
20
20
  Classifier: Intended Audience :: Developers
21
21
  Classifier: License :: OSI Approved :: MIT License
22
22
  Classifier: Programming Language :: Python :: 3
23
- Classifier: Programming Language :: Python :: 3.9
24
23
  Classifier: Programming Language :: Python :: 3.10
25
24
  Classifier: Programming Language :: Python :: 3.11
26
25
  Classifier: Programming Language :: Python :: 3.12
27
26
  Classifier: Programming Language :: Python :: 3.13
27
+ Classifier: Programming Language :: Python :: 3.14
28
28
  Classifier: Programming Language :: Python :: 3 :: Only
29
29
  Requires-Dist: typing-extensions>=4.15.0,<5
30
30
  Requires-Dist: anyio>=3.7.1
31
31
  Requires-Dist: wrapt>=1.17.0,<2
32
- Requires-Python: >=3.9.0, <3.14
32
+ Requires-Python: >=3.10.0, <3.15
33
33
  Project-URL: Repository, https://github.com/antonrh/anydi
34
34
  Description-Content-Type: text/markdown
35
35
 
@@ -58,7 +58,7 @@ http://anydi.readthedocs.io/
58
58
 
59
59
  ---
60
60
 
61
- `AnyDI` is a modern, lightweight Dependency Injection library suitable for any synchronous or asynchronous applications with Python 3.9+, based on type annotations ([PEP 484](https://peps.python.org/pep-0484/)).
61
+ `AnyDI` is a modern, lightweight Dependency Injection library suitable for any synchronous or asynchronous applications with Python 3.10+, based on type annotations ([PEP 484](https://peps.python.org/pep-0484/)).
62
62
 
63
63
  The key features are:
64
64
 
@@ -140,6 +140,12 @@ anydi.ext.fastapi.install(app, container)
140
140
 
141
141
  ## Django Ninja Example
142
142
 
143
+ ### Install
144
+
145
+ ```sh
146
+ pip install 'anydi-django[ninja]'
147
+ ```
148
+
143
149
  *container.py*
144
150
 
145
151
  ```python
@@ -161,7 +167,7 @@ def get_container() -> Container:
161
167
  ```python
162
168
  INSTALLED_APPS = [
163
169
  ...
164
- "anydi.ext.django",
170
+ "anydi_django",
165
171
  ]
166
172
 
167
173
  ANYDI = {
@@ -0,0 +1,24 @@
1
+ anydi/__init__.py,sha256=KjjYm-1yAFxiPYaMs1WRJMtxE0q_vdX7ZRLQR1fFGs8,567
2
+ anydi/_async.py,sha256=lrKTrqMC81POFbea3kaC9KkY3sp0DaenuVPvwOg88xA,1472
3
+ anydi/_container.py,sha256=t-5BcjsuKnaJ8Wmk9ZXXQN90NQhrVl41bLjObG0wYTY,31940
4
+ anydi/_context.py,sha256=_Xy8cTpRskb4cxTd-Fe-5NnIZyBe1DnovkofhdeUfmw,3020
5
+ anydi/_decorators.py,sha256=yxY876_2fzC30UIb4-4mR-J5ToQN3BH61E2cFH-iX8Y,2809
6
+ anydi/_module.py,sha256=2kN5uEXLd2Dsc58gz5IWK43wJewr_QgIVGSO3iWp798,2609
7
+ anydi/_provider.py,sha256=BWW4nXJ5r-0tCgS91kLWzYbrGv1v1oIm8BSt1cyYkDc,2150
8
+ anydi/_scan.py,sha256=SoB9uugaZVqBIW2IMKQGbu9YGaWHT3BhKWrDpiQaINE,3634
9
+ anydi/_scope.py,sha256=PFHjPb2-n0vhRo9mvD_craTFfoJBzR3y-N3_0apL5Q0,258
10
+ anydi/_typing.py,sha256=LXOmWua-UimL9te8Ye3u3MCLiA7EzNhDuacw4kgnxP4,2877
11
+ anydi/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ anydi/ext/django/__init__.py,sha256=Ve8lncLU9dPY_Vjt4zihPgsSxwAtFHACn0XvBM5JG8k,367
13
+ anydi/ext/fastapi.py,sha256=L9VGPHGy23se1sflmJqTE7LNfQuElVdYEogoT1f5-4A,2324
14
+ anydi/ext/faststream.py,sha256=Dy81Vf34CP6pEIbZ-41vh_-Dn6Qc-rcf14U5poebjxI,1905
15
+ anydi/ext/pydantic_settings.py,sha256=0GQjw7QpQlT5p6GxFClXYdtc6J42PClmAnRWPEzMjvY,1488
16
+ anydi/ext/pytest_plugin.py,sha256=yqaFPzYD88HEmqc2URsBtp2FUktORhUxWfs0hJja1IU,4732
17
+ anydi/ext/starlette/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ anydi/ext/starlette/middleware.py,sha256=MxnzshAs-CMvjJp0r457k52MzBL8O4KAuClnF6exBdU,803
19
+ anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ anydi/testing.py,sha256=gbQnJ6qFaQ5qbUwFWfSJ67SKhxLuPzwLGidistsmHk8,5519
21
+ anydi-0.52.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
22
+ anydi-0.52.0.dist-info/entry_points.txt,sha256=AgOcQYM5KyS4D37QcYb00tiid0QA-pD1VrjHHq4QAps,44
23
+ anydi-0.52.0.dist-info/METADATA,sha256=GvHhlEF-L72OAvA-6fuFzjUnvOlvM16T8MpZXT1vSbA,5022
24
+ anydi-0.52.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.8.17
2
+ Generator: uv 0.8.24
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,18 +0,0 @@
1
- from typing import cast
2
-
3
- from django.apps.registry import apps
4
- from django.utils.functional import SimpleLazyObject
5
-
6
- import anydi
7
-
8
- from .apps import ContainerConfig
9
-
10
- __all__ = ["container"]
11
-
12
-
13
- def _get_container() -> anydi.Container:
14
- app_config = cast(ContainerConfig, apps.get_app_config(ContainerConfig.label))
15
- return app_config.container
16
-
17
-
18
- container = cast(anydi.Container, SimpleLazyObject(_get_container))
@@ -1,37 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from collections.abc import Sequence
4
-
5
- from django.conf import settings
6
- from typing_extensions import TypedDict
7
-
8
-
9
- class Settings(TypedDict):
10
- CONTAINER_FACTORY: str | None
11
- REGISTER_SETTINGS: bool
12
- REGISTER_COMPONENTS: bool
13
- INJECT_URLCONF: str | Sequence[str] | None
14
- MODULES: Sequence[str]
15
- SCAN_PACKAGES: Sequence[str]
16
- PATCH_NINJA: bool
17
-
18
-
19
- DEFAULTS = Settings(
20
- CONTAINER_FACTORY=None,
21
- REGISTER_SETTINGS=False,
22
- REGISTER_COMPONENTS=False,
23
- MODULES=[],
24
- PATCH_NINJA=False,
25
- INJECT_URLCONF=None,
26
- SCAN_PACKAGES=[],
27
- )
28
-
29
-
30
- def get_settings() -> Settings:
31
- """Get the AnyDI settings from the Django settings."""
32
- return Settings(
33
- **{
34
- **DEFAULTS,
35
- **getattr(settings, "ANYDI", {}),
36
- }
37
- )
@@ -1,89 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from collections.abc import Iterator
4
- from typing import Annotated, Any
5
-
6
- from django.conf import settings
7
- from django.core.cache import BaseCache, caches
8
- from django.db import connections
9
- from django.db.backends.base.base import BaseDatabaseWrapper
10
- from django.urls import URLPattern, URLResolver, get_resolver
11
-
12
- from anydi import Container
13
-
14
-
15
- def register_settings(
16
- container: Container, prefix: str = "django.conf.settings."
17
- ) -> None:
18
- """Register Django settings into the container."""
19
-
20
- # Ensure prefix ends with a dot
21
- if prefix[-1] != ".":
22
- prefix += "."
23
-
24
- for setting_name in dir(settings):
25
- setting_value = getattr(settings, setting_name)
26
- if not setting_name.isupper():
27
- continue
28
-
29
- container.register(
30
- Annotated[type(setting_value), f"{prefix}{setting_name}"],
31
- _get_setting_value(setting_value),
32
- scope="singleton",
33
- )
34
-
35
-
36
- def register_components(container: Container) -> None:
37
- """Register Django components into the container."""
38
-
39
- # Register caches
40
- def _get_cache(cache_name: str) -> Any:
41
- return lambda: caches[cache_name]
42
-
43
- for cache_name in caches:
44
- container.register(
45
- Annotated[BaseCache, cache_name],
46
- _get_cache(cache_name),
47
- scope="singleton",
48
- )
49
-
50
- # Register database connections
51
- def _get_connection(alias: str) -> Any:
52
- return lambda: connections[alias]
53
-
54
- for alias in connections:
55
- container.register(
56
- Annotated[BaseDatabaseWrapper, alias],
57
- _get_connection(alias),
58
- scope="singleton",
59
- )
60
-
61
-
62
- def inject_urlpatterns(container: Container, *, urlconf: str) -> None:
63
- """Auto-inject the container into views."""
64
- resolver = get_resolver(urlconf)
65
- injected_urlpatterns = []
66
- for pattern in iter_urlpatterns(resolver.url_patterns):
67
- # Skip already injected views
68
- if pattern.lookup_str in injected_urlpatterns:
69
- continue
70
- # Skip django-ninja views
71
- if pattern.lookup_str.startswith("ninja."):
72
- continue # pragma: no cover
73
- pattern.callback = container.inject(pattern.callback)
74
- injected_urlpatterns.append(pattern.lookup_str)
75
-
76
-
77
- def iter_urlpatterns(
78
- urlpatterns: list[URLPattern | URLResolver],
79
- ) -> Iterator[URLPattern]:
80
- """Iterate over all views in urlpatterns."""
81
- for url_pattern in urlpatterns:
82
- if isinstance(url_pattern, URLResolver):
83
- yield from iter_urlpatterns(url_pattern.url_patterns)
84
- else:
85
- yield url_pattern
86
-
87
-
88
- def _get_setting_value(value: Any) -> Any:
89
- return lambda: value
anydi/ext/django/apps.py DELETED
@@ -1,88 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import types
4
- from typing import Callable, cast
5
-
6
- from django.apps import AppConfig
7
- from django.conf import settings
8
- from django.core.exceptions import ImproperlyConfigured
9
- from django.utils.module_loading import import_string
10
-
11
- import anydi
12
- from anydi.testing import TestContainer
13
-
14
- from ._settings import get_settings
15
- from ._utils import inject_urlpatterns, register_components, register_settings
16
-
17
-
18
- class ContainerConfig(AppConfig):
19
- name = "anydi.ext.django"
20
- label = "anydi_django"
21
-
22
- def __init__(self, app_name: str, app_module: types.ModuleType | None) -> None:
23
- super().__init__(app_name, app_module)
24
- self.settings = get_settings()
25
- # Create a container
26
- container_factory_path = self.settings["CONTAINER_FACTORY"]
27
- if container_factory_path:
28
- try:
29
- container_factory = cast(
30
- Callable[[], anydi.Container], import_string(container_factory_path)
31
- )
32
- except ImportError as exc:
33
- raise ImproperlyConfigured(
34
- f"Cannot import container factory '{container_factory_path}'."
35
- ) from exc
36
- container = container_factory()
37
- else:
38
- container = anydi.Container()
39
-
40
- # Use test container
41
- testing = getattr(settings, "ANYDI_TESTING", False)
42
- if testing:
43
- container = TestContainer.from_container(container)
44
-
45
- self.container = container
46
-
47
- def ready(self) -> None: # noqa: C901
48
- # Register Django settings
49
- if self.settings["REGISTER_SETTINGS"]:
50
- register_settings(
51
- self.container,
52
- prefix=getattr(
53
- settings,
54
- "ANYDI_SETTINGS_PREFIX",
55
- "django.conf.settings.",
56
- ),
57
- )
58
-
59
- # Register Django components
60
- if self.settings["REGISTER_COMPONENTS"]:
61
- register_components(self.container)
62
-
63
- # Register modules
64
- for module_path in self.settings["MODULES"]:
65
- try:
66
- module_cls = import_string(module_path)
67
- except ImportError as exc:
68
- raise ImproperlyConfigured(
69
- f"Cannot import module '{module_path}'."
70
- ) from exc
71
- self.container.register_module(module_cls)
72
-
73
- # Patching the django-ninja framework if it installed
74
- if self.settings["PATCH_NINJA"]:
75
- from .ninja import patch_ninja
76
-
77
- patch_ninja()
78
-
79
- # Auto-injecting the container into views
80
- if urlconf := self.settings["INJECT_URLCONF"]:
81
- if isinstance(urlconf, str):
82
- urlconf = [urlconf]
83
- for u in urlconf:
84
- inject_urlpatterns(self.container, urlconf=u)
85
-
86
- # Scan packages
87
- for scan_package in self.settings["SCAN_PACKAGES"]:
88
- self.container.scan(scan_package)
@@ -1,28 +0,0 @@
1
- from typing import Any, Callable
2
-
3
- from asgiref.sync import iscoroutinefunction
4
- from django.http import HttpRequest
5
- from django.utils.decorators import sync_and_async_middleware
6
-
7
- from ._container import container
8
-
9
-
10
- @sync_and_async_middleware
11
- def request_scoped_middleware(
12
- get_response: Callable[..., Any],
13
- ) -> Callable[..., Any]:
14
- if iscoroutinefunction(get_response):
15
-
16
- async def async_middleware(request: HttpRequest) -> Any:
17
- async with container.arequest_context() as context:
18
- context.set(HttpRequest, request)
19
- return await get_response(request)
20
-
21
- return async_middleware
22
-
23
- def middleware(request: HttpRequest) -> Any:
24
- with container.request_context() as context:
25
- context.set(HttpRequest, request)
26
- return get_response(request)
27
-
28
- return middleware
@@ -1,16 +0,0 @@
1
- try:
2
- from ninja import operation
3
- except ImportError as exc: # pragma: no cover
4
- raise ImportError(
5
- "'django-ninja' is not installed. "
6
- "Please install it using 'pip install django-ninja'."
7
- ) from exc
8
-
9
- from ._operation import AsyncOperation, Operation
10
- from ._signature import ViewSignature
11
-
12
-
13
- def patch_ninja() -> None:
14
- operation.ViewSignature = ViewSignature # type: ignore
15
- operation.Operation = Operation # type: ignore
16
- operation.AsyncOperation = AsyncOperation # type: ignore
@@ -1,75 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import Any
4
-
5
- from django.http import HttpRequest, HttpResponseBase
6
- from ninja.operation import (
7
- AsyncOperation as BaseAsyncOperation, # noqa
8
- Operation as BaseOperation,
9
- )
10
-
11
- from anydi.ext.django import container
12
-
13
- from ._signature import ViewSignature
14
-
15
-
16
- def _update_exc_args(exc: Exception) -> None:
17
- if isinstance(exc, TypeError) and "required positional argument" in str(exc):
18
- msg = "Did you fail to use functools.wraps() in a decorator?"
19
- msg = f"{exc.args[0]}: {msg}" if exc.args else msg
20
- exc.args = (msg,) + exc.args[1:]
21
-
22
-
23
- class Operation(BaseOperation):
24
- signature: ViewSignature
25
-
26
- def __init__(self, *args: Any, **kwargs: Any) -> None:
27
- super().__init__(*args, **kwargs)
28
- self.dependencies = self.signature.dependencies
29
-
30
- def run(self, request: HttpRequest, **kw: Any) -> HttpResponseBase:
31
- error = self._run_checks(request)
32
- if error:
33
- return error
34
- try:
35
- temporal_response = self.api.create_temporal_response(request)
36
- values = self._get_values(request, kw, temporal_response)
37
- values.update(self._get_dependencies())
38
- result = self.view_func(request, **values)
39
- return self._result_to_response(request, result, temporal_response)
40
- except Exception as e:
41
- _update_exc_args(e)
42
- return self.api.on_exception(request, e)
43
-
44
- def _get_dependencies(self) -> dict[str, Any]:
45
- return {
46
- name: container.resolve(interface) for name, interface in self.dependencies
47
- }
48
-
49
-
50
- class AsyncOperation(BaseAsyncOperation):
51
- signature: ViewSignature
52
-
53
- def __init__(self, *args: Any, **kwargs: Any) -> None:
54
- super().__init__(*args, **kwargs)
55
- self.dependencies = self.signature.dependencies
56
-
57
- async def run(self, request: HttpRequest, **kw: Any) -> HttpResponseBase:
58
- error = await self._run_checks(request)
59
- if error:
60
- return error
61
- try:
62
- temporal_response = self.api.create_temporal_response(request)
63
- values = self._get_values(request, kw, temporal_response)
64
- values.update(await self._get_dependencies())
65
- result = await self.view_func(request, **values)
66
- return self._result_to_response(request, result, temporal_response)
67
- except Exception as e:
68
- _update_exc_args(e)
69
- return self.api.on_exception(request, e)
70
-
71
- async def _get_dependencies(self) -> dict[str, Any]:
72
- return {
73
- name: await container.aresolve(interface)
74
- for name, interface in self.dependencies
75
- }
@@ -1,68 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import inspect
4
- from collections.abc import Callable
5
- from typing import Any
6
-
7
- from django.http import HttpResponse
8
- from ninja.signature.details import (
9
- FuncParam, # noqa
10
- ViewSignature as BaseViewSignature,
11
- )
12
- from ninja.signature.utils import get_path_param_names, get_typed_signature
13
-
14
- from anydi._typing import is_inject_marker # noqa
15
- from anydi.ext.django import container
16
-
17
-
18
- class ViewSignature(BaseViewSignature):
19
- def __init__(self, path: str, view_func: Callable[..., Any]) -> None:
20
- self.view_func = view_func
21
- self.signature = get_typed_signature(self.view_func)
22
- self.path = path
23
- self.path_params_names = get_path_param_names(path)
24
- self.docstring = inspect.cleandoc(view_func.__doc__ or "")
25
- self.has_kwargs = False
26
- self.dependencies = []
27
-
28
- self.params = []
29
- for name, arg in self.signature.parameters.items():
30
- if name == "request":
31
- # TODO: maybe better assert that 1st param is request or check by type?
32
- # maybe even have attribute like `has_request`
33
- # so that users can ignore passing request if not needed
34
- continue
35
-
36
- if arg.kind == arg.VAR_KEYWORD:
37
- # Skipping **kwargs
38
- self.has_kwargs = True
39
- continue
40
-
41
- if arg.kind == arg.VAR_POSITIONAL:
42
- # Skipping *args
43
- continue
44
-
45
- if arg.annotation is HttpResponse:
46
- self.response_arg = name
47
- continue
48
-
49
- interface, should_inject = container.validate_injected_parameter(
50
- arg, call=self.view_func
51
- )
52
- if should_inject:
53
- self.dependencies.append((name, interface))
54
- continue
55
-
56
- func_param = self._get_param_type(name, arg)
57
- self.params.append(func_param)
58
-
59
- ninja_contribute_args = getattr(view_func, "_ninja_contribute_args", None)
60
- if ninja_contribute_args is not None:
61
- for p_name, p_type, p_source in ninja_contribute_args:
62
- self.params.append(
63
- FuncParam(p_name, p_source.alias or p_name, p_source, p_type, False)
64
- )
65
-
66
- self.models = self._create_models()
67
-
68
- self._validate_view_path_params()
@@ -1,32 +0,0 @@
1
- anydi/__init__.py,sha256=KjjYm-1yAFxiPYaMs1WRJMtxE0q_vdX7ZRLQR1fFGs8,567
2
- anydi/_async.py,sha256=KhRd3RmZFcwNDzrMm8ctA1gwrg-6m_7laECTYsZdF5k,1445
3
- anydi/_container.py,sha256=_Qa1FwCYZesVF6TuJtdNrp6GaJvDUraUcylA3himk9M,31776
4
- anydi/_context.py,sha256=_Xy8cTpRskb4cxTd-Fe-5NnIZyBe1DnovkofhdeUfmw,3020
5
- anydi/_decorators.py,sha256=F3yBeGQSz1EsulZaEvYn3cd6FEjJRMoyA6u1QCbEwcs,2813
6
- anydi/_module.py,sha256=QPvP27JndZkwl-FYUZWscJm6yfkNzjwoFGURyDhb6Pc,2582
7
- anydi/_provider.py,sha256=ig2ecn-STmFGcpkLE5A5OM35XHtU2NsxFVrGp2CvuvM,2123
8
- anydi/_scan.py,sha256=nOpspmceVucdwf8nUv1QVFsz2sRVWCVUb0QTH9EbWr4,3653
9
- anydi/_scope.py,sha256=PFHjPb2-n0vhRo9mvD_craTFfoJBzR3y-N3_0apL5Q0,258
10
- anydi/_typing.py,sha256=cYsEnv_QpI8B1DIZ8zPZwywEmZjtx0otJjj6vTLLk_E,3895
11
- anydi/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- anydi/ext/django/__init__.py,sha256=QI1IABCVgSDTUoh7M9WMECKXwB3xvh04HfQ9TOWw1Mk,223
13
- anydi/ext/django/_container.py,sha256=cxVoYQG16WP0S_Yv4TnLwuaaT7NVEOhLWO-YdALJUb4,418
14
- anydi/ext/django/_settings.py,sha256=NsYbFBeslqw_tcXCn2b2gKnSp7eb64DM4dRc4tn_eiw,808
15
- anydi/ext/django/_utils.py,sha256=sYfUgBV9azddWYB4vNaZadDXcv_MiU-wSfVKV-TZDrE,2695
16
- anydi/ext/django/apps.py,sha256=kGqTUZK55OPtaG5lktavSr88_quDm9GNFUE94eQh6zQ,2965
17
- anydi/ext/django/middleware.py,sha256=5OUdp0OWRozyW338Sq04BDhacaFlyUTTOduS_7EwCTA,854
18
- anydi/ext/django/ninja/__init__.py,sha256=4J0zoHPK9itbTVrjjvLX6Ftrsb2ND8bITqNDIJzEhks,520
19
- anydi/ext/django/ninja/_operation.py,sha256=wk5EOjLY3KVIHk9jMCGsFsja9-dQmMOpLpHXciqxQdk,2680
20
- anydi/ext/django/ninja/_signature.py,sha256=p7JtyMdFhX4fWQOvAhvZNss6iURNERcdsTsQADTHkMY,2358
21
- anydi/ext/fastapi.py,sha256=L9VGPHGy23se1sflmJqTE7LNfQuElVdYEogoT1f5-4A,2324
22
- anydi/ext/faststream.py,sha256=Dy81Vf34CP6pEIbZ-41vh_-Dn6Qc-rcf14U5poebjxI,1905
23
- anydi/ext/pydantic_settings.py,sha256=8IXXLuG_OvKbvKlBkBRQUHcXgbTpgQUxeWyoMcRIUQM,1488
24
- anydi/ext/pytest_plugin.py,sha256=IoP6XKuGLGLd2Xlpfttc3mI4pxCm2WQLE7x_a7asbv4,4732
25
- anydi/ext/starlette/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
- anydi/ext/starlette/middleware.py,sha256=MxnzshAs-CMvjJp0r457k52MzBL8O4KAuClnF6exBdU,803
27
- anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- anydi/testing.py,sha256=waz0nO-MnfPGQLnPuDT0bdEdfqfmgkbsuFuxWfct6kw,5539
29
- anydi-0.48.2.dist-info/WHEEL,sha256=Pi5uDq5Fdo_Rr-HD5h9BiPn9Et29Y9Sh8NhcJNnFU1c,79
30
- anydi-0.48.2.dist-info/entry_points.txt,sha256=AgOcQYM5KyS4D37QcYb00tiid0QA-pD1VrjHHq4QAps,44
31
- anydi-0.48.2.dist-info/METADATA,sha256=ZGCaMB2v_gf8AAyTwTOwgU_IprmiSWOnWL1-a-5Ahsg,4965
32
- anydi-0.48.2.dist-info/RECORD,,