fastapi-injected 0.3.0__tar.gz → 0.3.1__tar.gz
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.
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/PKG-INFO +14 -2
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/README.md +13 -1
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/__init__.py +3 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/_bind.py +3 -2
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/_given.py +1 -2
- fastapi_injected-0.3.1/fastapi_injected/_params.py +19 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/deps.py +2 -1
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/types.py +2 -1
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/pyproject.toml +1 -1
- fastapi_injected-0.3.1/tests/_typing/params.py +30 -0
- fastapi_injected-0.3.1/tests/test_params.py +78 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/uv.lock +4 -4
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/.github/dependabot.yml +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/.github/workflows/automerge.yml +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/.github/workflows/lint.yml +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/.github/workflows/publish.yml +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/.github/workflows/test.yml +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/.gitignore +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/.pre-commit-config.yaml +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/LICENSE +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/_cache.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/_dataclass.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/_deps_tp.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/_fastapi_lifecycle.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/_injected.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/_overrides.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/_rlock.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/inject.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/overrides.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/resolve.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/scope.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/fastapi_injected/sign.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/__init__.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/__init__.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/annotations.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/arg.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/bind.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/dataclass.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/deps.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/errors.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/given.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/inject.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/injected.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/integration.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/markers.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/overrides.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/resolve.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/_typing/scope.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/deps.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/ext/__init__.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/ext/test_pydantic_ai.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/test_bind.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/test_cache.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/test_concurrency.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/test_dataclass.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/test_dependant_cache.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/test_errors.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/test_fastapi.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/test_given.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/test_inject.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/test_injected.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/test_overrides.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/test_resolve.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/test_rlock.py +0 -0
- {fastapi_injected-0.3.0 → fastapi_injected-0.3.1}/tests/test_scope.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: fastapi-injected
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Yet another library to reuse fastapi dependency injection
|
|
5
5
|
Project-URL: Repository, https://github.com/uriyyo/fastapi-injected
|
|
6
6
|
Author-email: Yurii Karabas <1998uriyyo@gmail.com>
|
|
@@ -253,6 +253,18 @@ class Config(MakeDataclass, frozen=True, kw_only=True):
|
|
|
253
253
|
retries: int = 3
|
|
254
254
|
```
|
|
255
255
|
|
|
256
|
+
The same is true of what holds a dependency. FastAPI's `Depends` and `Security` are frozen dataclasses, so they hash by field — and `Security(get_user, scopes=["items:read"])`, the documented spelling, holds a list, which makes the whole annotation unhashable and fails as a bare `TypeError` from `typing`. `fastapi_injected` ships both as `MakeDataclass` subclasses, which is the same class in every way that matters to FastAPI, and one that can be cached:
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
from fastapi_injected import Security, resolve
|
|
260
|
+
|
|
261
|
+
type CurrentUser = Annotated[User, Security(get_user, scopes=["items:read"])]
|
|
262
|
+
|
|
263
|
+
await resolve(CurrentUser)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Scopes are kept as a tuple, so the same scopes written as another list stay one dependency. Everything the package builds internally is held this way too, so a dependency object that cannot be hashed by fields no longer decides whether the annotation around it can be.
|
|
267
|
+
|
|
256
268
|
### When resolution fails
|
|
257
269
|
|
|
258
270
|
A dependency can fail to resolve for the same reasons it would in a route — a missing header, a query parameter that does not validate. `DependencyResolutionError` carries those errors in the shape pydantic produced them, and turns into the response FastAPI would have returned:
|
|
@@ -357,7 +369,7 @@ Everything the package supports is importable from `fastapi_injected` itself, an
|
|
|
357
369
|
|
|
358
370
|
| | |
|
|
359
371
|
| --- | --- |
|
|
360
|
-
| Markers | `Dep`, `DepFactory`, `DepOf`, `Arg`, `Given`, `Injected` |
|
|
372
|
+
| Markers | `Dep`, `DepFactory`, `DepOf`, `Arg`, `Given`, `Injected`, `Depends`, `Security` |
|
|
361
373
|
| Resolving | `inject`, `resolve`, `bind_deps`, `signature_with_deps`, `remap_dep_args`, `clear_dependant_cache` |
|
|
362
374
|
| Scopes and overrides | `InjectScope`, `push_inject_scope`, `inside_inject_scope`, `push_overrides`, `Overrides`, `OverridesProvider`, `ValueOverride`, `FactoryOverride` |
|
|
363
375
|
| Building on top | `MakeDataclass`, `MakeInjected`, `HasDependsHook`, `ArgMarker`, `is_arg`, `is_dep`, `unwrap_dep_tp`, `unwrap_dep_dependency` |
|
|
@@ -232,6 +232,18 @@ class Config(MakeDataclass, frozen=True, kw_only=True):
|
|
|
232
232
|
retries: int = 3
|
|
233
233
|
```
|
|
234
234
|
|
|
235
|
+
The same is true of what holds a dependency. FastAPI's `Depends` and `Security` are frozen dataclasses, so they hash by field — and `Security(get_user, scopes=["items:read"])`, the documented spelling, holds a list, which makes the whole annotation unhashable and fails as a bare `TypeError` from `typing`. `fastapi_injected` ships both as `MakeDataclass` subclasses, which is the same class in every way that matters to FastAPI, and one that can be cached:
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
from fastapi_injected import Security, resolve
|
|
239
|
+
|
|
240
|
+
type CurrentUser = Annotated[User, Security(get_user, scopes=["items:read"])]
|
|
241
|
+
|
|
242
|
+
await resolve(CurrentUser)
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Scopes are kept as a tuple, so the same scopes written as another list stay one dependency. Everything the package builds internally is held this way too, so a dependency object that cannot be hashed by fields no longer decides whether the annotation around it can be.
|
|
246
|
+
|
|
235
247
|
### When resolution fails
|
|
236
248
|
|
|
237
249
|
A dependency can fail to resolve for the same reasons it would in a route — a missing header, a query parameter that does not validate. `DependencyResolutionError` carries those errors in the shape pydantic produced them, and turns into the response FastAPI would have returned:
|
|
@@ -336,7 +348,7 @@ Everything the package supports is importable from `fastapi_injected` itself, an
|
|
|
336
348
|
|
|
337
349
|
| | |
|
|
338
350
|
| --- | --- |
|
|
339
|
-
| Markers | `Dep`, `DepFactory`, `DepOf`, `Arg`, `Given`, `Injected` |
|
|
351
|
+
| Markers | `Dep`, `DepFactory`, `DepOf`, `Arg`, `Given`, `Injected`, `Depends`, `Security` |
|
|
340
352
|
| Resolving | `inject`, `resolve`, `bind_deps`, `signature_with_deps`, `remap_dep_args`, `clear_dependant_cache` |
|
|
341
353
|
| Scopes and overrides | `InjectScope`, `push_inject_scope`, `inside_inject_scope`, `push_overrides`, `Overrides`, `OverridesProvider`, `ValueOverride`, `FactoryOverride` |
|
|
342
354
|
| Building on top | `MakeDataclass`, `MakeInjected`, `HasDependsHook`, `ArgMarker`, `is_arg`, `is_dep`, `unwrap_dep_tp`, `unwrap_dep_dependency` |
|
|
@@ -4,6 +4,7 @@ from ._deps_tp import is_arg, is_dep, unwrap_dep_dependency, unwrap_dep_tp
|
|
|
4
4
|
from ._fastapi_lifecycle import MissingDependencyCacheError, add_injected_scope, init_inject_scope
|
|
5
5
|
from ._given import Given
|
|
6
6
|
from ._injected import MakeInjected
|
|
7
|
+
from ._params import Depends, Security
|
|
7
8
|
from .deps import (
|
|
8
9
|
DependencyResolutionError,
|
|
9
10
|
HasDependsHook,
|
|
@@ -24,6 +25,7 @@ __all__ = [
|
|
|
24
25
|
"DepFactory",
|
|
25
26
|
"DepOf",
|
|
26
27
|
"DependencyResolutionError",
|
|
28
|
+
"Depends",
|
|
27
29
|
"FactoryOverride",
|
|
28
30
|
"Given",
|
|
29
31
|
"HasDependsHook",
|
|
@@ -36,6 +38,7 @@ __all__ = [
|
|
|
36
38
|
"NotADependencyError",
|
|
37
39
|
"Overrides",
|
|
38
40
|
"OverridesProvider",
|
|
41
|
+
"Security",
|
|
39
42
|
"UnboundDepArgsError",
|
|
40
43
|
"UnboundScopeError",
|
|
41
44
|
"ValueOverride",
|
|
@@ -3,10 +3,11 @@ from collections.abc import Callable, Sequence
|
|
|
3
3
|
from functools import wraps
|
|
4
4
|
from typing import Annotated, Any, Concatenate, overload
|
|
5
5
|
|
|
6
|
+
from fastapi import params
|
|
6
7
|
from fastapi.dependencies.utils import get_typed_signature
|
|
7
|
-
from fastapi.params import Depends
|
|
8
8
|
|
|
9
9
|
from ._deps_tp import is_dep
|
|
10
|
+
from ._params import Depends
|
|
10
11
|
from .sign import update_func_sign
|
|
11
12
|
from .types import AsyncFunc, DepOf, Func
|
|
12
13
|
|
|
@@ -34,7 +35,7 @@ def _dep_arg_index(name: str, /) -> int | None:
|
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
def _dep_annotation(dep: DepOf[Any] | Callable[..., Any], /) -> Any:
|
|
37
|
-
if isinstance(dep, Depends):
|
|
38
|
+
if isinstance(dep, params.Depends):
|
|
38
39
|
return Annotated[Any, dep]
|
|
39
40
|
|
|
40
41
|
# a marker is an annotation already, while a callable is a dependency the same way
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from fastapi import params
|
|
2
|
+
|
|
3
|
+
from ._dataclass import MakeDataclass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Depends(MakeDataclass, params.Depends, frozen=True):
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Security(Depends, params.Security, frozen=True):
|
|
11
|
+
def __post_init__(self) -> None:
|
|
12
|
+
if self.scopes is not None:
|
|
13
|
+
object.__setattr__(self, "scopes", tuple(self.scopes))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"Depends",
|
|
18
|
+
"Security",
|
|
19
|
+
]
|
|
@@ -4,12 +4,13 @@ from contextlib import AsyncExitStack
|
|
|
4
4
|
from functools import lru_cache, wraps
|
|
5
5
|
from typing import Annotated, Any, Literal, Protocol, cast, overload, runtime_checkable
|
|
6
6
|
|
|
7
|
-
from fastapi import
|
|
7
|
+
from fastapi import params
|
|
8
8
|
from fastapi.dependencies.models import Dependant
|
|
9
9
|
from fastapi.dependencies.utils import get_dependant, get_typed_signature, solve_dependencies
|
|
10
10
|
from fastapi.exceptions import RequestValidationError
|
|
11
11
|
|
|
12
12
|
from ._deps_tp import is_dep, unwrap_tp
|
|
13
|
+
from ._params import Depends
|
|
13
14
|
from .scope import InjectScope
|
|
14
15
|
from .sign import prepare_sign, update_func_sign
|
|
15
16
|
from .types import Coro, DependencyCache, HasSignature
|
|
@@ -2,10 +2,11 @@ import inspect
|
|
|
2
2
|
from collections.abc import AsyncIterator, Callable, Coroutine, Iterator, Mapping
|
|
3
3
|
from typing import TYPE_CHECKING, Annotated, Any, Protocol, TypeVar, runtime_checkable
|
|
4
4
|
|
|
5
|
-
from fastapi import Depends
|
|
6
5
|
from fastapi.types import DependencyCacheKey
|
|
7
6
|
from typing_extensions import TypeForm, sentinel
|
|
8
7
|
|
|
8
|
+
from ._params import Depends
|
|
9
|
+
|
|
9
10
|
if TYPE_CHECKING:
|
|
10
11
|
Injected: Any = object()
|
|
11
12
|
else:
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
from fastapi import params
|
|
4
|
+
|
|
5
|
+
from fastapi_injected import Depends, Security
|
|
6
|
+
|
|
7
|
+
from .deps import (
|
|
8
|
+
ContextState,
|
|
9
|
+
ctx_dep,
|
|
10
|
+
is_assignable_to,
|
|
11
|
+
is_subtype_of,
|
|
12
|
+
static_assert,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# they are the fastapi params they wrap, so anything taking one takes these
|
|
16
|
+
static_assert(is_subtype_of(Depends, params.Depends))
|
|
17
|
+
static_assert(is_subtype_of(Security, params.Security))
|
|
18
|
+
static_assert(is_subtype_of(Security, Depends))
|
|
19
|
+
static_assert(is_assignable_to(Annotated[ContextState, Security(ctx_dep, scopes=["me"])], ContextState))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _params() -> None:
|
|
23
|
+
Depends()
|
|
24
|
+
Depends(ctx_dep, use_cache=False)
|
|
25
|
+
Security(ctx_dep, scopes=["me"], use_cache=False)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _negatives() -> None:
|
|
29
|
+
Depends(use_cache="yes") # type: ignore[ty:invalid-argument-type]
|
|
30
|
+
Security(ctx_dep, scopes=1) # type: ignore[ty:invalid-argument-type]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from fastapi import params
|
|
5
|
+
from fastapi.security import SecurityScopes
|
|
6
|
+
|
|
7
|
+
from fastapi_injected import Depends, Security, is_dep, push_inject_scope, resolve
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
async def scopes_dep(scopes: SecurityScopes) -> list[str]:
|
|
11
|
+
return scopes.scopes
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Unhashable:
|
|
15
|
+
__hash__ = None # type: ignore[ty:invalid-assignment]
|
|
16
|
+
|
|
17
|
+
async def __call__(self) -> str:
|
|
18
|
+
return "value"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_they_are_fastapi_params():
|
|
22
|
+
assert isinstance(Depends(scopes_dep), params.Depends)
|
|
23
|
+
assert isinstance(Security(scopes_dep), params.Security)
|
|
24
|
+
assert isinstance(Security(scopes_dep), params.Depends)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_scopes_are_written_as_documented():
|
|
28
|
+
security = Security(scopes_dep, scopes=["items:read"])
|
|
29
|
+
|
|
30
|
+
assert security.scopes == ("items:read",)
|
|
31
|
+
assert is_dep(Annotated[list[str], security])
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_equal_params_hash_equally():
|
|
35
|
+
assert hash(Depends(scopes_dep)) == hash(Depends(scopes_dep))
|
|
36
|
+
assert Security(scopes_dep, scopes=["me"]) == Security(scopes_dep, scopes=["me"])
|
|
37
|
+
assert hash(Security(scopes_dep, scopes=["me"])) == hash(Security(scopes_dep, scopes=("me",)))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_a_scoped_annotation_can_be_hashed():
|
|
41
|
+
# the annotation is the key a dependant is cached by, and a list of scopes used to break it
|
|
42
|
+
assert hash(Annotated[list[str], Security(scopes_dep, scopes=["items:read", "me"])])
|
|
43
|
+
|
|
44
|
+
with pytest.raises(TypeError, match="unhashable type: 'list'"):
|
|
45
|
+
hash(Annotated[list[str], params.Security(scopes_dep, scopes=["items:read", "me"])])
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_unhashable_dependencies_fall_back_to_identity():
|
|
49
|
+
depends = Depends(Unhashable())
|
|
50
|
+
|
|
51
|
+
assert hash(depends) == object.__hash__(depends)
|
|
52
|
+
assert hash(Annotated[str, depends])
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@pytest.mark.asyncio
|
|
56
|
+
async def test_a_scoped_dependency_resolves():
|
|
57
|
+
scoped = Annotated[list[str], Security(scopes_dep, scopes=["items:read", "me"])]
|
|
58
|
+
|
|
59
|
+
assert await resolve(scoped) == ["items:read", "me"]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@pytest.mark.asyncio
|
|
63
|
+
async def test_equal_params_are_one_dependency():
|
|
64
|
+
calls = 0
|
|
65
|
+
|
|
66
|
+
async def counted() -> int:
|
|
67
|
+
nonlocal calls
|
|
68
|
+
calls += 1
|
|
69
|
+
return calls
|
|
70
|
+
|
|
71
|
+
async with push_inject_scope():
|
|
72
|
+
assert await resolve(Annotated[int, Security(counted, scopes=["me"])]) == 1
|
|
73
|
+
# the same scopes written as another list are the same dependency, so it is cached
|
|
74
|
+
assert await resolve(Annotated[int, Security(counted, scopes=["me"])]) == 1
|
|
75
|
+
# different scopes are not
|
|
76
|
+
assert await resolve(Annotated[int, Security(counted, scopes=["other"])]) == 2
|
|
77
|
+
|
|
78
|
+
assert calls == 2
|
|
@@ -186,7 +186,7 @@ wheels = [
|
|
|
186
186
|
|
|
187
187
|
[[package]]
|
|
188
188
|
name = "fastapi-injected"
|
|
189
|
-
version = "0.3.
|
|
189
|
+
version = "0.3.1"
|
|
190
190
|
source = { editable = "." }
|
|
191
191
|
dependencies = [
|
|
192
192
|
{ name = "fastapi" },
|
|
@@ -249,11 +249,11 @@ wheels = [
|
|
|
249
249
|
|
|
250
250
|
[[package]]
|
|
251
251
|
name = "griffelib"
|
|
252
|
-
version = "2.
|
|
252
|
+
version = "2.2.0"
|
|
253
253
|
source = { registry = "https://pypi.org/simple" }
|
|
254
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
254
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f0/b4/a767e91c606deefc447a96eaf59edd77397960b1d677dffd833ee8449831/griffelib-2.2.0.tar.gz", hash = "sha256:e1bc36fe9cd21d4b6b659b456346755e4cfdc5676c0a5214083126ee12612b3c", size = 227048, upload-time = "2026-08-16T14:04:58.383Z" }
|
|
255
255
|
wheels = [
|
|
256
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
256
|
+
{ url = "https://files.pythonhosted.org/packages/f6/b6/f65ac785d4ac90dcf7c831ac6256f5dd4a19780f4e1575b2c0d6eeebe319/griffelib-2.2.0-py3-none-any.whl", hash = "sha256:d71c3bc2bbed9f958488634fe788b843a9f705d6d2838ca32cd6c25eeb64dfc4", size = 166779, upload-time = "2026-08-16T14:04:54.365Z" },
|
|
257
257
|
]
|
|
258
258
|
|
|
259
259
|
[[package]]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|