Skip to content

Commit c05e323

Browse files
authored
refactoring: ♻️ Remove Scoped type annotation
1 parent 6c51321 commit c05e323

7 files changed

Lines changed: 52 additions & 53 deletions

File tree

documentation/integrations/fastapi.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ from dataclasses import dataclass
2929
from enum import StrEnum, auto
3030

3131
from fastapi import Depends, FastAPI, Request
32-
from injection import MappedScope, Scoped, adefine_scope
32+
from injection import MappedScope, adefine_scope
3333

3434
class InjectionScope(StrEnum):
3535
LIFESPAN = auto()
@@ -42,7 +42,7 @@ async def lifespan(_: FastAPI) -> AsyncIterator[None]:
4242

4343
@dataclass
4444
class FastAPIRequestBindings:
45-
request: Scoped[Request]
45+
request: Request
4646

4747
scope = MappedScope(InjectionScope.REQUEST)
4848

documentation/scoped-dependencies.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ def main() -> None:
4343

4444
## MappedScope
4545

46-
`MappedScope` allows you to open a dependency injection scope and register values annotated with `Scoped[...]` so they
47-
can be retrieved by other dependencies within that scope.
46+
`MappedScope` allows you to open a dependency injection scope and register values with type annotation so they can be
47+
retrieved by other dependencies within that scope.
4848

4949
### How it works
5050

51-
1. **Define bindings**: Create a class with fields annotated with `Scoped`.
51+
1. **Define bindings**: Create a class with type annotated fields.
5252
2. **Create scope**: Instantiate `MappedScope` with a scope name.
5353
3. **Open scope**: Use `define` or `adefine` context manager to register the scoped values.
5454
4. **Access dependencies**: Other dependencies can now inject these scoped values within the context.
@@ -60,13 +60,13 @@ Example:
6060

6161
```python
6262
from dataclasses import dataclass
63-
from injection import MappedScope, Scoped
63+
from injection import MappedScope
6464

6565
class Request: ...
6666

6767
@dataclass
6868
class RequestBindings:
69-
request: Scoped[Request]
69+
request: Request
7070

7171
scope = MappedScope("request")
7272

injection/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from ._core.asfunction import asfunction
2-
from ._core.descriptors import LazyInstance, MappedScope, Scoped
2+
from ._core.descriptors import LazyInstance, MappedScope
33
from ._core.injectables import Injectable
44
from ._core.module import Mode, Module, Priority, mod
55
from ._core.scope import ScopeFacade as Scope
@@ -14,7 +14,6 @@
1414
"Module",
1515
"Priority",
1616
"Scope",
17-
"Scoped",
1817
"ScopeKind",
1918
"SlotKey",
2019
"adefine_scope",

injection/__init__.pyi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ from ._core.module import InjectableFactory as _InjectableFactory
1313
from ._core.module import ModeStr, PriorityStr
1414
from ._core.scope import ScopeKindStr
1515

16-
type Scoped[T] = T
1716
type _Decorator[T] = Callable[[T], T]
1817

1918
__MODULE: Final[Module] = ...

injection/_core/descriptors.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,14 @@
44
from contextlib import asynccontextmanager, contextmanager
55
from dataclasses import dataclass
66
from types import MappingProxyType
7-
from typing import Any, Self, get_args, get_origin, get_type_hints
7+
from typing import Any, Self, get_type_hints
88

99
from injection._core.common.invertible import Invertible
1010
from injection._core.common.type import InputType
1111
from injection._core.module import Module, mod
1212
from injection._core.scope import ScopeKind, ScopeKindStr, adefine_scope, define_scope
1313
from injection._core.slots import SlotKey
1414

15-
type Scoped[T] = T
16-
1715

1816
class MappedScope:
1917
__slots__ = ("__keys", "__module", "__name", "__owner")
@@ -43,16 +41,19 @@ def __set_name__(self, owner: type, name: str) -> None:
4341
if self.__owner:
4442
raise TypeError(f"`{self}` owner is already defined.")
4543

46-
self.__keys = MappingProxyType(dict(self.__generate_keys(owner)))
44+
self.__keys = MappingProxyType(dict(self.__generate_keys(owner, name)))
4745
self.__owner = owner
4846

49-
def __generate_keys(self, cls: type) -> Iterator[tuple[str, SlotKey[Any]]]:
47+
def __generate_keys(
48+
self,
49+
cls: type,
50+
descriptor_name: str,
51+
) -> Iterator[tuple[str, SlotKey[Any]]]:
5052
for name, hint in get_type_hints(cls).items():
51-
if get_origin(hint) is not Scoped:
53+
if name == descriptor_name:
5254
continue
5355

54-
annotation = get_args(hint)[0]
55-
key = self.__module.reserve_scoped_slot(annotation, scope_name=self.__name)
56+
key = self.__module.reserve_scoped_slot(hint, scope_name=self.__name)
5657
yield name, key
5758

5859
def __mapping_from(self, instance: object) -> dict[SlotKey[Any], Any]:

tests/core/test_descriptors.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from dataclasses import dataclass
2+
from typing import ClassVar
23

34
import pytest
45

5-
from injection import LazyInstance, MappedScope, Scoped, injectable
6+
from injection import LazyInstance, MappedScope, injectable
67

78

89
class _RawData: ...
@@ -18,12 +19,12 @@ class BindingsA:
1819
class BindingsB:
1920
scope = BindingsA.scope
2021

21-
async def test_aopen_with_success(self, module):
22+
async def test_adefine_with_success(self, module):
2223
@dataclass
2324
class Bindings:
24-
data: Scoped[_RawData]
25+
data: _RawData
2526

26-
scope = MappedScope("some_scope", module=module)
27+
scope: ClassVar[MappedScope] = MappedScope("some_scope", module)
2728

2829
data = _RawData()
2930
context = Bindings(data)
@@ -35,16 +36,15 @@ class Bindings:
3536

3637
assert module.get_instance(_RawData) is NotImplemented
3738

38-
def test_open_with_success(self, module):
39+
def test_define_with_success(self, module):
3940
@dataclass
4041
class Bindings:
41-
data: Scoped[_RawData]
42-
unscoped_data: int
42+
data: _RawData
4343

44-
scope = MappedScope("some_scope", module=module)
44+
scope: ClassVar[MappedScope] = MappedScope("some_scope", module)
4545

4646
data = _RawData()
47-
context = Bindings(data, 2)
47+
context = Bindings(data)
4848

4949
assert module.get_instance(_RawData) is NotImplemented
5050

@@ -54,13 +54,13 @@ class Bindings:
5454

5555
assert module.get_instance(_RawData) is NotImplemented
5656

57-
def test_open_with_optional_types(self, module):
57+
def test_define_with_optional_types(self, module):
5858
@dataclass
5959
class Bindings:
60-
data: Scoped[_RawData | None] = None
61-
name: Scoped[str | None] = None
60+
data: _RawData | None = None
61+
name: str | None = None
6262

63-
scope = MappedScope("some_scope", module=module)
63+
scope: ClassVar[MappedScope] = MappedScope("some_scope", module)
6464

6565
data = _RawData()
6666
context = Bindings(data)

uv.lock

Lines changed: 22 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)