• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ets-labs / python-dependency-injector / 15425325914

03 Jun 2025 06:45PM UTC coverage: 94.672% (+0.1%) from 94.557%
15425325914

push

github

web-flow
Add support for async generator injections (#900)

56 of 57 new or added lines in 1 file covered. (98.25%)

36 existing lines in 1 file now uncovered.

3376 of 3566 relevant lines covered (94.67%)

0.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.33
/src/dependency_injector/_cwiring.pyx
1
"""Wiring optimizations module."""
1✔
2

3
from asyncio import gather
1✔
4
from collections.abc import Awaitable
1✔
5
from inspect import CO_ITERABLE_COROUTINE
1✔
6
from types import CoroutineType, GeneratorType
1✔
7

8
from .providers cimport Provider, Resource, NULL_AWAITABLE
9
from .wiring import _Marker
1✔
10

11
cimport cython
12

13

14
@cython.internal
15
@cython.no_gc
16
cdef class KWPair:
17
    cdef str name
18
    cdef object value
19

20
    def __cinit__(self, str name, object value, /):
21
        self.name = name
1✔
22
        self.value = value
1✔
23

24

25
cdef inline bint _is_injectable(dict kwargs, str name):
1✔
26
    return name not in kwargs or isinstance(kwargs[name], _Marker)
1✔
27

28

29
cdef class DependencyResolver:
30
    cdef dict kwargs
31
    cdef dict to_inject
32
    cdef dict injections
33
    cdef dict closings
34

35
    def __init__(self, dict kwargs, dict injections, dict closings, /):
36
        self.kwargs = kwargs
1✔
37
        self.to_inject = kwargs.copy()
1✔
38
        self.injections = injections
1✔
39
        self.closings = closings
1✔
40

41
    async def _await_injection(self, kw_pair: KWPair, /) -> None:
1✔
42
        self.to_inject[kw_pair.name] = await kw_pair.value
1✔
43

44
    cdef object _await_injections(self, to_await: list):
1✔
45
        return gather(*map(self._await_injection, to_await))
1✔
46

47
    cdef void _handle_injections_sync(self):
1✔
48
        cdef Provider provider
49

50
        for name, provider in self.injections.items():
1✔
51
            if _is_injectable(self.kwargs, name):
1✔
52
                self.to_inject[name] = provider()
1✔
53

54
    cdef list _handle_injections_async(self):
1✔
55
        cdef list to_await = []
1✔
56
        cdef Provider provider
57

58
        for name, provider in self.injections.items():
1✔
59
            if _is_injectable(self.kwargs, name):
1✔
60
                provide = provider()
1✔
61

62
                if provider.is_async_mode_enabled() or _isawaitable(provide):
1✔
63
                    to_await.append(KWPair(name, provide))
1✔
64
                else:
65
                    self.to_inject[name] = provide
1✔
66

67
        return to_await
1✔
68

69
    cdef void _handle_closings_sync(self):
1✔
70
        cdef Provider provider
71

72
        for name, provider in self.closings.items():
1✔
73
            if _is_injectable(self.kwargs, name) and isinstance(provider, Resource):
1✔
74
                provider.shutdown()
1✔
75

76
    cdef list _handle_closings_async(self):
1✔
77
        cdef list to_await = []
1✔
78
        cdef Provider provider
79

80
        for name, provider in self.closings.items():
1✔
81
            if _is_injectable(self.kwargs, name) and isinstance(provider, Resource):
1✔
82
                if _isawaitable(shutdown := provider.shutdown()):
1✔
83
                    to_await.append(shutdown)
1✔
84

85
        return to_await
1✔
86

87
    def __enter__(self):
1✔
88
        self._handle_injections_sync()
1✔
89
        return self.to_inject
1✔
90

91
    def __exit__(self, *_):
1✔
92
        self._handle_closings_sync()
1✔
93

94
    async def __aenter__(self):
1✔
95
        if to_await := self._handle_injections_async():
1✔
96
            await self._await_injections(to_await)
1✔
97
        return self.to_inject
1✔
98

99
    def __aexit__(self, *_):
1✔
100
        if to_await := self._handle_closings_async():
1✔
101
            return gather(*to_await)
1✔
102
        return NULL_AWAITABLE
1✔
103

104

105
cdef bint _isawaitable(object instance):
1✔
106
    """Return true if object can be passed to an ``await`` expression."""
107
    return (isinstance(instance, CoroutineType) or
1✔
108
            isinstance(instance, GeneratorType) and
1✔
NEW
109
            bool(instance.gi_code.co_flags & CO_ITERABLE_COROUTINE) or
×
110
            isinstance(instance, Awaitable))
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc