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

ets-labs / python-dependency-injector / 15404729357

02 Jun 2025 11:12PM UTC coverage: 94.672% (+0.1%) from 94.557%
15404729357

push

github

ZipFile
Add support for async generator injections

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.no_gc
15
cdef class KWPair:
16
    cdef str name
17
    cdef object value
18

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

23

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

27

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

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

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

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

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

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

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

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

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

66
        return to_await
1✔
67

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

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

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

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

84
        return to_await
1✔
85

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

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

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

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

103

104
cdef bint _isawaitable(object instance):
1✔
105
    """Return true if object can be passed to an ``await`` expression."""
106
    return (isinstance(instance, CoroutineType) or
1✔
107
            isinstance(instance, GeneratorType) and
1✔
NEW
108
            bool(instance.gi_code.co_flags & CO_ITERABLE_COROUTINE) or
×
109
            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