Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion injection/common/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from typing import ContextManager
from weakref import WeakSet

from injection.common.tools.threading import frozen_collection

__all__ = ("Event", "EventChannel", "EventListener")


Expand All @@ -26,7 +28,7 @@ class EventChannel:
@contextmanager
def dispatch(self, event: Event) -> ContextManager | ContextDecorator:
with ExitStack() as stack:
for listener in tuple(self.__listeners):
for listener in frozen_collection(self.__listeners):
context_manager = listener.on_event(event)

if context_manager is None:
Expand Down
6 changes: 3 additions & 3 deletions injection/common/lazy.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from collections.abc import Callable, Iterator, Mapping
from threading import RLock
from types import MappingProxyType
from typing import Any, Generic, TypeVar

from injection.common.tools.threading import thread_lock

__all__ = ("Lazy", "LazyMapping")

_sentinel = object()
_thread_lock = RLock()

_T = TypeVar("_T")
_K = TypeVar("_K")
Expand All @@ -22,7 +22,7 @@ def __init__(self, factory: Callable[[], _T]):

def __invert__(self) -> _T:
if not self.is_set:
with _thread_lock:
with thread_lock:
self.__value = self.__factory()
self.__factory = _sentinel

Expand Down
1 change: 0 additions & 1 deletion injection/common/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
from ._type import *
28 changes: 28 additions & 0 deletions injection/common/tools/threading.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from collections.abc import Callable, Collection, Iterator
from functools import wraps
from threading import RLock
from typing import Any, TypeVar

__all__ = ("frozen_collection", "synchronized", "thread_lock")

_T = TypeVar("_T")
thread_lock = RLock()


def synchronized(function: Callable[..., Any] = None, /):
def decorator(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
with thread_lock:
return fn(*args, **kwargs)

return wrapper

return decorator(function) if function else decorator


def frozen_collection(collection: Collection[_T]) -> Iterator[_T]:
with thread_lock:
t = tuple(collection)

yield from t
File renamed without changes.
27 changes: 16 additions & 11 deletions injection/core/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from enum import Enum, auto
from functools import partialmethod, singledispatchmethod, wraps
from inspect import Signature, isclass
from threading import RLock
from types import MappingProxyType, UnionType
from typing import (
Any,
Expand All @@ -33,7 +32,12 @@

from injection.common.event import Event, EventChannel, EventListener
from injection.common.lazy import Lazy, LazyMapping
from injection.common.tools import find_types, format_type, get_origins
from injection.common.tools.threading import (
frozen_collection,
synchronized,
thread_lock,
)
from injection.common.tools.type import find_types, format_type, get_origins
from injection.exceptions import (
InjectionError,
ModuleError,
Expand All @@ -45,7 +49,6 @@
__all__ = ("Injectable", "Module", "ModulePriority")

_logger = logging.getLogger(__name__)
_thread_lock = RLock()

_T = TypeVar("_T")
Types = Iterable[type] | UnionType
Expand Down Expand Up @@ -183,7 +186,7 @@ def get_instance(self) -> _T:
with suppress(KeyError):
return self.cache[self.__INSTANCE_KEY]

with _thread_lock:
with thread_lock:
instance = self.factory()
self.cache[self.__INSTANCE_KEY] = instance

Expand Down Expand Up @@ -263,7 +266,7 @@ def __injectables(self) -> frozenset[Injectable]:
def update(self, classes: Iterable[type], injectable: Injectable, override: bool):
classes = frozenset(get_origins(*classes))

with _thread_lock:
with thread_lock:
if not injectable:
classes -= self.__classes
override = True
Expand All @@ -279,6 +282,7 @@ def update(self, classes: Iterable[type], injectable: Injectable, override: bool

return self

@synchronized
def unlock(self):
for injectable in self.__injectables:
injectable.unlock()
Expand Down Expand Up @@ -349,7 +353,7 @@ def is_locked(self) -> bool:

@property
def __brokers(self) -> Iterator[Broker]:
yield from tuple(self.__modules)
yield from frozen_collection(self.__modules)
yield self.__container

def injectable(
Expand Down Expand Up @@ -492,6 +496,7 @@ def change_priority(self, module: Module, priority: ModulePriority):

return self

@synchronized
def unlock(self):
for broker in self.__brokers:
broker.unlock()
Expand Down Expand Up @@ -544,13 +549,13 @@ def __new_binder(self, target: Callable[..., Any]) -> Binder:

@dataclass(repr=False, frozen=True, slots=True)
class Dependencies:
__mapping: MappingProxyType[str, Injectable]
mapping: MappingProxyType[str, Injectable]

def __bool__(self) -> bool:
return bool(self.__mapping)
return bool(self.mapping)

def __iter__(self) -> Iterator[tuple[str, Any]]:
for name, injectable in self.__mapping.items():
for name, injectable in self.mapping.items():
yield name, injectable.get_instance()

@property
Expand All @@ -559,7 +564,7 @@ def arguments(self) -> OrderedDict[str, Any]:

@classmethod
def from_mapping(cls, mapping: Mapping[str, Injectable]):
return cls(MappingProxyType(mapping))
return cls(mapping=MappingProxyType(mapping))

@classmethod
def empty(cls):
Expand Down Expand Up @@ -620,7 +625,7 @@ def bind(
return Arguments(bound.args, bound.kwargs)

def update(self, module: Module):
with _thread_lock:
with thread_lock:
self.__dependencies = Dependencies.resolve(self.__signature, module)

return self
Expand Down
2 changes: 1 addition & 1 deletion injection/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from injection.common.tools import format_type
from injection.common.tools.type import format_type

__all__ = (
"InjectionError",
Expand Down
63 changes: 31 additions & 32 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.