python-injection 0.18.8__py3-none-any.whl → 0.18.9__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.
injection/__init__.pyi CHANGED
@@ -35,12 +35,14 @@ def adefine_scope(
35
35
  name: str,
36
36
  /,
37
37
  kind: ScopeKind | ScopeKindStr = ...,
38
+ threadsafe: bool = ...,
38
39
  ) -> AsyncIterator[Scope]: ...
39
40
  @contextmanager
40
41
  def define_scope(
41
42
  name: str,
42
43
  /,
43
44
  kind: ScopeKind | ScopeKindStr = ...,
45
+ threadsafe: bool = ...,
44
46
  ) -> Iterator[Scope]: ...
45
47
  def mod(name: str = ..., /) -> Module:
46
48
  """
injection/_core/module.py CHANGED
@@ -996,7 +996,7 @@ class InjectMetadata[**P, T](Caller[P, T], EventListener):
996
996
 
997
997
  def __init__(self, wrapped: Callable[P, T], /, threadsafe: bool) -> None:
998
998
  self.__dependencies = Dependencies.empty()
999
- self.__lock = threading.Lock() if threadsafe else nullcontext()
999
+ self.__lock = threading.RLock() if threadsafe else nullcontext()
1000
1000
  self.__owner = None
1001
1001
  self.__tasks = deque()
1002
1002
  self.__wrapped = wrapped
injection/_core/scope.py CHANGED
@@ -1,10 +1,17 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import itertools
4
+ import threading
4
5
  from abc import ABC, abstractmethod
5
6
  from collections import defaultdict
6
7
  from collections.abc import AsyncIterator, Iterator, Mapping, MutableMapping
7
- from contextlib import AsyncExitStack, ExitStack, asynccontextmanager, contextmanager
8
+ from contextlib import (
9
+ AsyncExitStack,
10
+ ExitStack,
11
+ asynccontextmanager,
12
+ contextmanager,
13
+ nullcontext,
14
+ )
8
15
  from contextvars import ContextVar
9
16
  from dataclasses import dataclass, field
10
17
  from enum import StrEnum
@@ -129,9 +136,10 @@ async def adefine_scope(
129
136
  name: str,
130
137
  /,
131
138
  kind: ScopeKind | ScopeKindStr = ScopeKind.get_default(),
139
+ threadsafe: bool = False,
132
140
  ) -> AsyncIterator[ScopeFacade]:
133
141
  async with AsyncScope() as scope:
134
- with _bind_scope(name, scope, kind) as facade:
142
+ with _bind_scope(name, scope, kind, threadsafe) as facade:
135
143
  yield facade
136
144
 
137
145
 
@@ -140,9 +148,10 @@ def define_scope(
140
148
  name: str,
141
149
  /,
142
150
  kind: ScopeKind | ScopeKindStr = ScopeKind.get_default(),
151
+ threadsafe: bool = False,
143
152
  ) -> Iterator[ScopeFacade]:
144
153
  with SyncScope() as scope:
145
- with _bind_scope(name, scope, kind) as facade:
154
+ with _bind_scope(name, scope, kind, threadsafe) as facade:
146
155
  yield facade
147
156
 
148
157
 
@@ -191,27 +200,39 @@ def _bind_scope(
191
200
  name: str,
192
201
  scope: Scope,
193
202
  kind: ScopeKind | ScopeKindStr,
203
+ threadsafe: bool,
194
204
  ) -> Iterator[ScopeFacade]:
195
- match ScopeKind(kind):
196
- case ScopeKind.CONTEXTUAL:
197
- is_already_defined = bool(get_scope(name, default=None))
198
- states = __CONTEXTUAL_SCOPES
205
+ lock = threading.RLock() if threadsafe else nullcontext()
199
206
 
200
- case ScopeKind.SHARED:
201
- is_already_defined = bool(get_active_scopes(name))
202
- states = __SHARED_SCOPES
207
+ with lock:
208
+ match ScopeKind(kind):
209
+ case ScopeKind.CONTEXTUAL:
210
+ is_already_defined = bool(get_scope(name, default=None))
211
+ states = __CONTEXTUAL_SCOPES
203
212
 
204
- case _:
205
- raise NotImplementedError
213
+ case ScopeKind.SHARED:
214
+ is_already_defined = bool(get_active_scopes(name))
215
+ states = __SHARED_SCOPES
206
216
 
207
- if is_already_defined:
208
- raise ScopeAlreadyDefinedError(
209
- f"Scope `{name}` is already defined in the current context."
210
- )
217
+ case _:
218
+ raise NotImplementedError
219
+
220
+ if is_already_defined:
221
+ raise ScopeAlreadyDefinedError(
222
+ f"Scope `{name}` is already defined in the current context."
223
+ )
211
224
 
212
- with states[name].bind(scope):
225
+ stack = ExitStack()
226
+ binder = states[name].bind(scope)
227
+ stack.enter_context(binder)
228
+
229
+ try:
213
230
  yield _UserScope(scope)
214
231
 
232
+ finally:
233
+ with lock:
234
+ stack.close()
235
+
215
236
 
216
237
  @runtime_checkable
217
238
  class Scope(Protocol):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-injection
3
- Version: 0.18.8
3
+ Version: 0.18.9
4
4
  Summary: Fast and easy dependency injection framework.
5
5
  Project-URL: Repository, https://github.com/100nm/python-injection
6
6
  Author: remimd
@@ -1,5 +1,5 @@
1
1
  injection/__init__.py,sha256=7ZRUlO5EEPWO7IlbYHD-8DOX-cg4Np4nYq5fpw-U56o,1259
2
- injection/__init__.pyi,sha256=8UOL1ewTqS6_pyvoCRfdOEHI0kYAZOCHkvqOIwQUOPE,10662
2
+ injection/__init__.pyi,sha256=aV1Ebgb7zdCs6b4K-aVzm0JX6W3x0fGp8vtFmWe2U_o,10718
3
3
  injection/entrypoint.py,sha256=12b0_zHAFxHCerAoJTIHkhqi3mLkgheECYAaCUZv_DU,4751
4
4
  injection/exceptions.py,sha256=v57yMujiq6H_zwwn30A8UYEZX9R9k-bY8FnsdaimPM4,1025
5
5
  injection/loaders.py,sha256=6TjVz9yaQDCVIPIIhjeC6GSXm9rn3oUU2b5KjfOYlsM,6568
@@ -7,8 +7,8 @@ injection/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  injection/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  injection/_core/descriptors.py,sha256=jH0pyIlPurMmU4yXr-HKS_7BJ-9d0XUvEx4pQre3QeI,704
9
9
  injection/_core/injectables.py,sha256=Rg1nxDkbcpeX4ELohrNVMguPhN36SNQuD0JKfyfL6bI,6192
10
- injection/_core/module.py,sha256=pZ_g_rSn5upHJV1MqF87hkxNfgUAzDc1miV-Qca28hg,32015
11
- injection/_core/scope.py,sha256=OBzVY1mUApryqIZKQtwHz7wiuY13MfouyaHp50DpWeQ,8300
10
+ injection/_core/module.py,sha256=4WqrDti98A5CrIWaHlld1GYYm4K-8XkKltchJoyXUTU,32016
11
+ injection/_core/scope.py,sha256=6EKhwbXMwx8ZvqQ5TKzfVtg_JWHhZj_qkHACiDqs6h0,8731
12
12
  injection/_core/slots.py,sha256=g9TG6CbqRzCsjg01iPyfRtTTUCJnnJOwcj9mJabH0dc,37
13
13
  injection/_core/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  injection/_core/common/asynchronous.py,sha256=QeS2Lc4gEBFvTA_snOWfme5mTL4BFZWqZ8EzJwOdVos,1816
@@ -22,7 +22,7 @@ injection/ext/fastapi.py,sha256=layUUer5IWiZX6Mmx1_RCYDLNCtEHtpya5ZL6TTBOkY,968
22
22
  injection/ext/fastapi.pyi,sha256=8OZEUjHFB9n7QXv_dtXdDuXW-r2huQEFsJ03gJOOvwQ,125
23
23
  injection/testing/__init__.py,sha256=bJ7WXBXrw4rHc91AFVFnOwFLWOlpvX9Oh2SnRQ_NESo,919
24
24
  injection/testing/__init__.pyi,sha256=raGsGlxwbz3jkzJwA_5oCIE1emWINjT2UuwzbnqRb-0,577
25
- python_injection-0.18.8.dist-info/METADATA,sha256=LC0vhC-mInR1kvwJ6ul9haTlAhtBKWNRaV6knJP-5z8,3397
26
- python_injection-0.18.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
27
- python_injection-0.18.8.dist-info/licenses/LICENSE,sha256=oC77BOa9kaaQni5rW-Z-ytz3E5h4EVg248BHg9UFgyg,1063
28
- python_injection-0.18.8.dist-info/RECORD,,
25
+ python_injection-0.18.9.dist-info/METADATA,sha256=ReK9ZuwTqgR5Pv9RI-o2p-j33O2GgGz0Fq_WUpxBkZU,3397
26
+ python_injection-0.18.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
27
+ python_injection-0.18.9.dist-info/licenses/LICENSE,sha256=oC77BOa9kaaQni5rW-Z-ytz3E5h4EVg248BHg9UFgyg,1063
28
+ python_injection-0.18.9.dist-info/RECORD,,