omlish 0.0.0.dev433__py3-none-any.whl → 0.0.0.dev435__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.
Files changed (54) hide show
  1. omlish/__about__.py +2 -2
  2. omlish/asyncs/all.py +0 -13
  3. omlish/concurrent/__init__.py +0 -17
  4. omlish/concurrent/all.py +17 -0
  5. omlish/configs/types.py +1 -1
  6. omlish/daemons/__init__.py +70 -0
  7. omlish/dataclasses/errors.py +1 -1
  8. omlish/formats/json/stream/lexing.py +12 -6
  9. omlish/formats/json/stream/utils.py +28 -2
  10. omlish/formats/json5/stream.py +82 -0
  11. omlish/funcs/genmachine.py +1 -1
  12. omlish/http/coro/server/server.py +1 -1
  13. omlish/inject/__init__.py +152 -126
  14. omlish/inject/binder.py +7 -4
  15. omlish/inject/impl/elements.py +6 -8
  16. omlish/inject/impl/injector.py +58 -32
  17. omlish/inject/impl/inspect.py +1 -0
  18. omlish/inject/impl/maysync.py +44 -0
  19. omlish/inject/impl/multis.py +5 -5
  20. omlish/inject/impl/privates.py +8 -8
  21. omlish/inject/impl/providers.py +24 -31
  22. omlish/inject/impl/providers2.py +43 -0
  23. omlish/inject/impl/scopes.py +19 -25
  24. omlish/inject/impl/sync.py +42 -0
  25. omlish/inject/injector.py +9 -11
  26. omlish/inject/inspect.py +1 -3
  27. omlish/inject/listeners.py +4 -4
  28. omlish/inject/managed.py +52 -20
  29. omlish/inject/maysync.py +27 -0
  30. omlish/inject/providers.py +6 -0
  31. omlish/inject/scopes.py +38 -10
  32. omlish/inject/sync.py +46 -0
  33. omlish/lang/__init__.py +12 -3
  34. omlish/lang/asyncs.py +18 -0
  35. omlish/lang/contextmanagers.py +23 -0
  36. omlish/lite/asyncs.py +21 -0
  37. omlish/lite/attrops.py +1 -1
  38. omlish/lite/inject.py +4 -4
  39. omlish/lite/maysync.py +21 -0
  40. omlish/marshal/__init__.py +20 -8
  41. omlish/os/atomics.py +1 -1
  42. omlish/reflect/ops.py +9 -0
  43. omlish/reflect/types.py +19 -6
  44. omlish/sockets/addresses.py +1 -1
  45. omlish/sql/queries/params.py +1 -1
  46. {omlish-0.0.0.dev433.dist-info → omlish-0.0.0.dev435.dist-info}/METADATA +1 -4
  47. {omlish-0.0.0.dev433.dist-info → omlish-0.0.0.dev435.dist-info}/RECORD +51 -47
  48. omlish/asyncs/bridge.py +0 -359
  49. omlish/asyncs/utils.py +0 -18
  50. omlish/formats/json5/streams.py +0 -22
  51. {omlish-0.0.0.dev433.dist-info → omlish-0.0.0.dev435.dist-info}/WHEEL +0 -0
  52. {omlish-0.0.0.dev433.dist-info → omlish-0.0.0.dev435.dist-info}/entry_points.txt +0 -0
  53. {omlish-0.0.0.dev433.dist-info → omlish-0.0.0.dev435.dist-info}/licenses/LICENSE +0 -0
  54. {omlish-0.0.0.dev433.dist-info → omlish-0.0.0.dev435.dist-info}/top_level.txt +0 -0
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev433'
2
- __revision__ = '8b1520428b44d4d75317513a61d17c5e6f0c7711'
1
+ __version__ = '0.0.0.dev435'
2
+ __revision__ = 'deaaa1ce6258184eff437ebf09b0eea7fc2ca758'
3
3
 
4
4
 
5
5
  #
omlish/asyncs/all.py CHANGED
@@ -1,12 +1,3 @@
1
- from .bridge import ( # noqa
2
- a_to_s,
3
- is_in_bridge,
4
- s_to_a,
5
- s_to_a_await,
6
- trivial_a_to_s,
7
- trivial_s_to_a,
8
- )
9
-
10
1
  from .flavors import ( # noqa
11
2
  ContextManagerAdapter,
12
3
  Flavor,
@@ -25,7 +16,3 @@ from .flavors import ( # noqa
25
16
  mark_trio,
26
17
  with_adapter_loop,
27
18
  )
28
-
29
- from .utils import ( # noqa
30
- call_with_async_exit_stack,
31
- )
@@ -1,17 +0,0 @@
1
- from .. import lang as _lang
2
-
3
-
4
- with _lang.auto_proxy_init(globals()):
5
- ##
6
-
7
- from .executors import ( # noqa
8
- ImmediateExecutor,
9
- new_executor,
10
- )
11
-
12
- from .futures import ( # noqa
13
- FutureError,
14
- FutureTimeoutError,
15
- wait_futures,
16
- wait_dependent_futures,
17
- )
@@ -0,0 +1,17 @@
1
+ from .. import lang as _lang
2
+
3
+
4
+ with _lang.auto_proxy_init(globals()):
5
+ ##
6
+
7
+ from .executors import ( # noqa
8
+ ImmediateExecutor,
9
+ new_executor,
10
+ )
11
+
12
+ from .futures import ( # noqa
13
+ FutureError,
14
+ FutureTimeoutError,
15
+ wait_futures,
16
+ wait_dependent_futures,
17
+ )
omlish/configs/types.py CHANGED
@@ -3,7 +3,7 @@
3
3
  import typing as ta
4
4
 
5
5
 
6
- ConfigMap = ta.Mapping[str, ta.Any]
6
+ ConfigMap = ta.Mapping[str, ta.Any] # ta.TypeAlias
7
7
 
8
8
 
9
9
  ##
@@ -0,0 +1,70 @@
1
+ from .. import lang as _lang # noqa
2
+
3
+
4
+ with _lang.auto_proxy_init(globals()):
5
+ ##
6
+
7
+ from .daemon import ( # noqa
8
+ Daemon,
9
+ )
10
+
11
+ from .launching import ( # noqa
12
+ Launcher,
13
+ )
14
+
15
+ from .services import ( # noqa
16
+ Service,
17
+
18
+ ServiceTarget,
19
+ ServiceTargetRunner,
20
+
21
+ ServiceConfigTarget,
22
+ ServiceConfigTargetRunner,
23
+ )
24
+
25
+ from .spawning import ( # noqa
26
+ Spawning,
27
+ Spawn,
28
+ Spawner,
29
+ InProcessSpawner,
30
+ spawner_for,
31
+
32
+ MultiprocessingSpawning,
33
+ MultiprocessingSpawner,
34
+
35
+ ForkSpawning,
36
+ ForkSpawner,
37
+
38
+ ThreadSpawning,
39
+ ThreadSpawner,
40
+ )
41
+
42
+ from .targets import ( # noqa
43
+ Target,
44
+ TargetRunner,
45
+ target_runner_for,
46
+
47
+ FnTarget,
48
+ FnTargetRunner,
49
+
50
+ NameTarget,
51
+ NameTargetRunner,
52
+
53
+ ExecTarget,
54
+ ExecTargetRunner,
55
+ )
56
+
57
+ from .waiting import ( # noqa
58
+ Wait,
59
+ Waiter,
60
+ waiter_for,
61
+
62
+ SequentialWait,
63
+ SequentialWaiter,
64
+
65
+ FnWait,
66
+ FnWaiter,
67
+
68
+ ConnectWait,
69
+ ConnectWaiter,
70
+ )
@@ -6,7 +6,7 @@ import typing as ta
6
6
 
7
7
 
8
8
  def _hands_off_repr(obj: ta.Any) -> str:
9
- return f'{obj.__class__.__qualname__}@{hex(id(obj))[2:]}'
9
+ return f'{obj.__class__.__qualname__}@{id(obj):x}'
10
10
 
11
11
 
12
12
  def _fn_repr(fn: ta.Callable) -> str:
@@ -122,11 +122,17 @@ class JsonStreamLexer(GenMachine[str, Token]):
122
122
  include_space: bool = False,
123
123
  allow_comments: bool = False,
124
124
  include_comments: bool = False,
125
+ allow_single_quotes: bool = False,
126
+ string_literal_parser: ta.Callable[[str], str] | None = None,
125
127
  ) -> None:
126
128
  self._include_raw = include_raw
127
129
  self._include_space = include_space
128
130
  self._allow_comments = allow_comments
129
131
  self._include_comments = include_comments
132
+ self._allow_single_quotes = allow_single_quotes
133
+ if string_literal_parser is None:
134
+ string_literal_parser = json.loads
135
+ self._string_literal_parser = string_literal_parser
130
136
 
131
137
  self._ofs = 0
132
138
  self._line = 1
@@ -202,8 +208,8 @@ class JsonStreamLexer(GenMachine[str, Token]):
202
208
  yield self._make_tok(CONTROL_TOKENS[c], c, c, self.pos)
203
209
  continue
204
210
 
205
- if c == '"':
206
- return self._do_string()
211
+ if c == '"' or (self._allow_single_quotes and c == "'"):
212
+ return self._do_string(c)
207
213
 
208
214
  if c.isdigit() or c == '-':
209
215
  return self._do_number(c)
@@ -217,9 +223,9 @@ class JsonStreamLexer(GenMachine[str, Token]):
217
223
 
218
224
  self._raise(f'Unexpected character: {c}')
219
225
 
220
- def _do_string(self):
226
+ def _do_string(self, q: str):
221
227
  check.state(self._buf.tell() == 0)
222
- self._buf.write('"')
228
+ self._buf.write(q)
223
229
 
224
230
  pos = self.pos
225
231
 
@@ -234,13 +240,13 @@ class JsonStreamLexer(GenMachine[str, Token]):
234
240
  self._raise(f'Unterminated string literal: {self._buf.getvalue()}')
235
241
 
236
242
  self._buf.write(c)
237
- if c == '"' and last != '\\':
243
+ if c == q and last != '\\':
238
244
  break
239
245
  last = c
240
246
 
241
247
  raw = self._flip_buf()
242
248
  try:
243
- sv = json.loads(raw)
249
+ sv = self._string_literal_parser(raw)
244
250
  except json.JSONDecodeError as e:
245
251
  self._raise(f'Invalid string literal: {raw!r}', e)
246
252
 
@@ -1,3 +1,28 @@
1
+ r"""
2
+ TODO:
3
+ - gson switches
4
+ - Strictness.LEGACY_STRICT
5
+ - JsonReader allows the literals true, false and null to have any capitalization, for example fAlSe or NULL
6
+ - JsonReader supports the escape sequence \', representing a ' (single-quote)
7
+ - JsonReader supports the escape sequence \LF (with LF being the Unicode character U+000A), resulting in a LF within
8
+ the read JSON string
9
+ - JsonReader allows unescaped control characters (U+0000 through U+001F)
10
+ - Strictness.LENIENT
11
+ - In lenient mode, all input that is accepted in legacy strict mode is accepted in addition to the following
12
+ departures from RFC 8259:
13
+ - Streams that start with the non-execute prefix, ")]'\n"}
14
+ - Streams that include multiple top-level values. With legacy strict or strict parsing, each stream must contain
15
+ exactly one top-level value.
16
+ - Numbers may be NaNs or infinities represented by NaN and (-)Infinity respectively.
17
+ - End of line comments starting with // or # and ending with a newline character.
18
+ - C-style comments starting with /* and ending with */. Such comments may not be nested.
19
+ - Names that are unquoted or 'single quoted'.
20
+ - Strings that are unquoted or 'single quoted'.
21
+ - Array elements separated by ; instead of ,.
22
+ - Unnecessary array separators. These are interpreted as if null was the omitted value.
23
+ - Names and values separated by = or => instead of :.
24
+ - Name/value pairs separated by ; instead of ,.
25
+ """
1
26
  import dataclasses as dc
2
27
  import typing as ta
3
28
 
@@ -15,7 +40,7 @@ class JsonStreamValueParser(lang.ExitStacked):
15
40
  include_raw: bool = False
16
41
  yield_object_lists: bool = False
17
42
 
18
- allow_comments: bool = False
43
+ json5: bool = False
19
44
 
20
45
  #
21
46
 
@@ -26,7 +51,8 @@ class JsonStreamValueParser(lang.ExitStacked):
26
51
  def _enter_contexts(self) -> None:
27
52
  self._lex = JsonStreamLexer(
28
53
  include_raw=self.include_raw,
29
- allow_comments=self.allow_comments,
54
+ allow_comments=self.json5,
55
+ allow_single_quotes=self.json5,
30
56
  )
31
57
 
32
58
  self._parse = JsonStreamParser()
@@ -0,0 +1,82 @@
1
+ """
2
+ TODO:
3
+
4
+ Objects:
5
+ - Object keys may be an ECMAScript 5.1 IdentifierName.
6
+ - Objects may have a single trailing comma.
7
+ Arrays:
8
+ - Arrays may have a single trailing comma.
9
+ Strings:
10
+ - Strings may be single quoted.
11
+ - Strings may span multiple lines by escaping new line characters.
12
+ - Strings may include character escapes.
13
+ Numbers:
14
+ - Numbers may be hexadecimal.
15
+ - Numbers may have a leading or trailing decimal point.
16
+ - Numbers may be IEEE 754 positive infinity, negative infinity, and NaN.
17
+ - Numbers may begin with an explicit plus sign.
18
+ Comments:
19
+ + Single and multi-line comments are allowed.
20
+ White Space:
21
+ - Additional white space characters are allowed.
22
+ """
23
+ import dataclasses as dc
24
+ import typing as ta
25
+
26
+ from ... import lang
27
+ from ..json.stream.building import JsonValueBuilder
28
+ from ..json.stream.lexing import JsonStreamLexer
29
+ from ..json.stream.parsing import JsonStreamParser
30
+ from .literals import parse_string_literal
31
+
32
+
33
+ ##
34
+
35
+
36
+ @dc.dataclass(kw_only=True)
37
+ class JsonStreamValueParser(lang.ExitStacked):
38
+ include_raw: bool = False
39
+ yield_object_lists: bool = False
40
+
41
+ #
42
+
43
+ _lex: JsonStreamLexer = dc.field(init=False)
44
+ _parse: JsonStreamParser = dc.field(init=False)
45
+ _build: JsonValueBuilder = dc.field(init=False)
46
+
47
+ def _enter_contexts(self) -> None:
48
+ self._lex = JsonStreamLexer(
49
+ include_raw=self.include_raw,
50
+ allow_comments=True,
51
+ allow_single_quotes=True,
52
+ string_literal_parser=parse_string_literal,
53
+ )
54
+
55
+ self._parse = JsonStreamParser()
56
+
57
+ self._build = JsonValueBuilder(
58
+ yield_object_lists=self.yield_object_lists,
59
+ )
60
+
61
+ def feed(self, i: ta.Iterable[str]) -> ta.Iterator[ta.Any]:
62
+ for c in i:
63
+ for t in self._lex(c):
64
+ for e in self._parse(t):
65
+ for v in self._build(e): # noqa
66
+ yield v
67
+
68
+
69
+ def stream_parse_values(
70
+ i: ta.Iterable[str],
71
+ **kwargs: ta.Any,
72
+ ) -> ta.Generator[ta.Any]:
73
+ with JsonStreamValueParser(**kwargs) as p:
74
+ yield from p.feed(i)
75
+
76
+
77
+ def stream_parse_one_value(
78
+ i: ta.Iterable[str],
79
+ **kwargs: ta.Any,
80
+ ) -> ta.Any:
81
+ with JsonStreamValueParser(**kwargs) as p:
82
+ return next(p.feed(i))
@@ -45,7 +45,7 @@ class GenMachine(ta.Generic[I, O]):
45
45
  _gen: MachineGen | None
46
46
 
47
47
  def __repr__(self) -> str:
48
- return f'{self.__class__.__name__}@{hex(id(self))[2:]}<{self.state}>'
48
+ return f'{self.__class__.__name__}@{id(self):x}<{self.state}>'
49
49
 
50
50
  #
51
51
 
@@ -77,7 +77,7 @@ from ...versions import HttpProtocolVersion
77
77
  from ...versions import HttpProtocolVersions
78
78
 
79
79
 
80
- CoroHttpServerFactory = ta.Callable[[SocketAddress], 'CoroHttpServer']
80
+ CoroHttpServerFactory = ta.Callable[[SocketAddress], 'CoroHttpServer'] # ta.TypeAlias
81
81
 
82
82
 
83
83
  ##
omlish/inject/__init__.py CHANGED
@@ -13,129 +13,155 @@ _dc.init_package(
13
13
  ##
14
14
 
15
15
 
16
- from .binder import ( # noqa
17
- bind,
18
- bind_as_fn,
19
- bind_map_entry_const,
20
- bind_set_entry_const,
21
- )
22
-
23
- from .bindings import ( # noqa
24
- Binding,
25
- )
26
-
27
- from .eagers import ( # noqa
28
- Eager,
29
- )
30
-
31
- from .elements import ( # noqa
32
- Element,
33
- Elemental,
34
- Elements,
35
- as_elements,
36
- )
37
-
38
- from .errors import ( # noqa
39
- BaseKeyError,
40
- ConflictingKeyError,
41
- CyclicDependencyError,
42
- ScopeAlreadyOpenError,
43
- ScopeError,
44
- ScopeNotOpenError,
45
- UnboundKeyError,
46
- )
47
-
48
- from .injector import ( # noqa
49
- create_injector,
50
- Injector,
51
- )
52
-
53
- from .inspect import ( # noqa
54
- Kwarg,
55
- KwargsTarget,
56
- build_kwargs_target,
57
- tag,
58
- )
59
-
60
- from .keys import ( # noqa
61
- Key,
62
- as_key,
63
- )
64
-
65
- from .listeners import ( # noqa
66
- ProvisionListener,
67
- ProvisionListenerBinding,
68
- bind_provision_listener,
69
- )
70
-
71
- from .managed import ( # noqa
72
- create_async_managed_injector,
73
- create_managed_injector,
74
- make_async_managed_provider,
75
- make_managed_provider,
76
- )
77
-
78
- from .multis import ( # noqa
79
- MapBinding,
80
- MapProvider,
81
- SetBinding,
82
- SetProvider,
83
- MapBinder,
84
- SetBinder,
85
-
86
- MapBinder as map_binder, # noqa
87
- SetBinder as set_binder, # noqa
88
- )
89
-
90
-
91
- from .overrides import ( # noqa
92
- Overrides,
93
- override,
94
- )
95
-
96
- from .origins import ( # noqa
97
- HasOrigins,
98
- Origin,
99
- Origins,
100
- )
101
-
102
- from .privates import ( # noqa
103
- Expose,
104
- Private,
105
- private,
106
-
107
- Expose as expose, # noqa
108
- )
109
-
110
- from .providers import ( # noqa
111
- ConstProvider,
112
- CtorProvider,
113
- FnProvider,
114
- LinkProvider,
115
- Provider,
116
- )
117
-
118
- from .scopes import ( # noqa
119
- ScopeBinding,
120
- ScopeSeededProvider,
121
- SeededScope,
122
- Singleton,
123
- ThreadScope,
124
- bind_scope,
125
- bind_scope_seed,
126
- enter_seeded_scope,
127
- )
128
-
129
- from .tags import ( # noqa
130
- Id,
131
- )
132
-
133
- from .types import ( # noqa
134
- Scope,
135
- Tag,
136
- Unscoped,
137
- )
138
-
139
- from .utils import ( # noqa
140
- ConstFn,
141
- )
16
+ from .. import lang as _lang # noqa
17
+
18
+
19
+ with _lang.auto_proxy_init(globals()):
20
+ ##
21
+
22
+ from .binder import ( # noqa
23
+ bind,
24
+ bind_as_fn,
25
+ bind_map_entry_const,
26
+ bind_set_entry_const,
27
+ )
28
+
29
+ from .bindings import ( # noqa
30
+ Binding,
31
+ )
32
+
33
+ from .eagers import ( # noqa
34
+ Eager,
35
+ )
36
+
37
+ from .elements import ( # noqa
38
+ Element,
39
+ Elemental,
40
+ Elements,
41
+ as_elements,
42
+ )
43
+
44
+ from .errors import ( # noqa
45
+ BaseKeyError,
46
+ ConflictingKeyError,
47
+ CyclicDependencyError,
48
+ ScopeAlreadyOpenError,
49
+ ScopeError,
50
+ ScopeNotOpenError,
51
+ UnboundKeyError,
52
+ )
53
+
54
+ from .injector import ( # noqa
55
+ AsyncInjector,
56
+ create_async_injector,
57
+ )
58
+
59
+ from .inspect import ( # noqa
60
+ Kwarg,
61
+ KwargsTarget,
62
+ build_kwargs_target,
63
+ tag,
64
+ )
65
+
66
+ from .keys import ( # noqa
67
+ Key,
68
+ as_key,
69
+ )
70
+
71
+ from .listeners import ( # noqa
72
+ ProvisionListener,
73
+ ProvisionListenerBinding,
74
+ bind_provision_listener,
75
+ )
76
+
77
+ from .managed import ( # noqa
78
+ create_async_managed_injector,
79
+ make_async_managed_provider,
80
+
81
+ create_managed_injector,
82
+ make_managed_provider,
83
+
84
+ create_maysync_managed_injector,
85
+ make_maysync_managed_provider,
86
+ )
87
+
88
+ from .maysync import ( # noqa
89
+ MaysyncInjector,
90
+ create_maysync_injector,
91
+ )
92
+
93
+ from .multis import ( # noqa
94
+ MapBinding,
95
+ MapProvider,
96
+ SetBinding,
97
+ SetProvider,
98
+ MapBinder,
99
+ SetBinder,
100
+
101
+ MapBinder as map_binder, # noqa
102
+ SetBinder as set_binder, # noqa
103
+ )
104
+
105
+
106
+ from .overrides import ( # noqa
107
+ Overrides,
108
+ override,
109
+ )
110
+
111
+ from .origins import ( # noqa
112
+ HasOrigins,
113
+ Origin,
114
+ Origins,
115
+ )
116
+
117
+ from .privates import ( # noqa
118
+ Expose,
119
+ Private,
120
+ private,
121
+
122
+ Expose as expose, # noqa
123
+ )
124
+
125
+ from .providers import ( # noqa
126
+ ConstProvider,
127
+ CtorProvider,
128
+ FnProvider,
129
+ LinkProvider,
130
+ Provider,
131
+ )
132
+
133
+ from .scopes import ( # noqa
134
+ ScopeBinding,
135
+ bind_scope,
136
+
137
+ Singleton,
138
+
139
+ ThreadScope,
140
+
141
+ SeededScope,
142
+ ScopeSeededProvider,
143
+ bind_scope_seed,
144
+
145
+ async_enter_seeded_scope,
146
+ enter_seeded_scope,
147
+ maysync_enter_seeded_scope,
148
+ )
149
+
150
+ from .sync import ( # noqa
151
+ Injector,
152
+ create_injector,
153
+ )
154
+
155
+ from .tags import ( # noqa
156
+ Id,
157
+ )
158
+
159
+ from .types import ( # noqa
160
+ Scope,
161
+ Tag,
162
+ Unscoped,
163
+ )
164
+
165
+ from .utils import ( # noqa
166
+ ConstFn,
167
+ )
omlish/inject/binder.py CHANGED
@@ -19,6 +19,7 @@ from .multis import SetBinding
19
19
  from .multis import is_map_multi_key
20
20
  from .multis import is_set_multi_key
21
21
  from .privates import Expose
22
+ from .providers import AsyncFnProvider
22
23
  from .providers import ConstProvider
23
24
  from .providers import CtorProvider
24
25
  from .providers import FnProvider
@@ -31,10 +32,8 @@ from .types import Scope
31
32
  from .types import Unscoped
32
33
 
33
34
 
34
- if ta.TYPE_CHECKING:
35
- from .impl.inspect import inspect as _inspect
36
- else:
37
- _inspect = lang.proxy_import('.impl.inspect', __package__)
35
+ with lang.auto_proxy_import(globals()):
36
+ from .impl import inspect as _inspect
38
37
 
39
38
 
40
39
  T = ta.TypeVar('T')
@@ -83,6 +82,7 @@ def bind(
83
82
  *,
84
83
  tag: ta.Any = None,
85
84
 
85
+ to_async_fn: ta.Any = None,
86
86
  to_fn: ta.Any = None,
87
87
  to_ctor: ta.Any = None,
88
88
  to_const: ta.Any = None,
@@ -102,6 +102,7 @@ def bind(
102
102
  ##
103
103
 
104
104
  has_to = (
105
+ to_async_fn is not None or
105
106
  to_fn is not None or
106
107
  to_ctor is not None or
107
108
  to_const is not None or
@@ -137,6 +138,8 @@ def bind(
137
138
  ##
138
139
 
139
140
  providers: list[Provider] = []
141
+ if to_async_fn is not None:
142
+ providers.append(AsyncFnProvider(to_async_fn))
140
143
  if to_fn is not None:
141
144
  providers.append(FnProvider(to_fn))
142
145
  if to_ctor is not None: