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

pantsbuild / pants / 25037732008

28 Apr 2026 06:33AM UTC coverage: 92.955% (-0.003%) from 92.958%
25037732008

push

github

web-flow
perf: Remove python coroutine/trampoline overhead in awaits for ~22% faster `dependencies` goal (#23268)

```console
 ➜  ✗ hyperfine --warmup 1 --command-name 'branch' 'PYENV_VERSION=pants@3.14.3                                     
  PANTS_SOURCE=<redacted>/code/pants pants --no-pantsd dependencies ::' --command-name 'main' 'PYENV_VERSION=pants@3.14.3 PANTS_SOURCE=/tmp/pants-main pants --no-pantsd dependencies ::'    
  Benchmark 1: branch                                                                                                                                                                          
    Time (mean ± σ):     25.094 s ±  0.306 s    [User: 30.610 s, System: 8.516 s]                                                                                                              
    Range (min … max):   24.775 s … 25.564 s    10 runs                                                                                                                                        
                                                                                                                                                                                               
  Benchmark 2: main                                                                                                                                                                            
    Time (mean ± σ):     32.304 s ±  0.183 s    [User: 37.097 s, System: 11.844 s]                                                                                                             
    Range (min … max):   32.008 s … 32.614 s    10 runs                                                                                                                                        
                                                                                                                                                                                               
  Summary                 ... (continued)

34 of 40 new or added lines in 4 files covered. (85.0%)

4 existing lines in 2 files now uncovered.

91823 of 98782 relevant lines covered (92.96%)

3.72 hits per line

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

73.53
/src/python/pants/engine/internals/selectors.py
1
# Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
11✔
5

6
import itertools
11✔
7
from collections.abc import Coroutine, Iterable
11✔
8
from dataclasses import dataclass
11✔
9
from typing import Any, TypeVar, overload
11✔
10

11
from pants.engine.internals.native_engine import Call as Call  # noqa: F401
11✔
12
from pants.engine.internals.native_engine import _Concurrently
11✔
13
from pants.util.strutil import softwrap
11✔
14

15
_Output = TypeVar("_Output")
11✔
16

17

18
@dataclass(frozen=True)
11✔
19
class AwaitableConstraints:
11✔
20
    rule_id: str
11✔
21
    output_type: type
11✔
22
    # The number of explicit positional arguments passed to a call-by-name awaitable.
23
    explicit_args_arity: int
11✔
24
    input_types: tuple[type, ...]
11✔
25

26
    def __repr__(self) -> str:
11✔
27
        inputs = ", ".join(f"{t.__name__}" for t in self.input_types)
2✔
28
        return f"{self.rule_id}({inputs}) -> {self.output_type.__name__}"
2✔
29

30
    def __str__(self) -> str:
11✔
31
        return repr(self)
2✔
32

33

34
# These type variables are used to parametrize from 1 to 10 args when used in a tuple-style
35
# concurrently() call.
36

37
_Out0 = TypeVar("_Out0")
11✔
38
_Out1 = TypeVar("_Out1")
11✔
39
_Out2 = TypeVar("_Out2")
11✔
40
_Out3 = TypeVar("_Out3")
11✔
41
_Out4 = TypeVar("_Out4")
11✔
42
_Out5 = TypeVar("_Out5")
11✔
43
_Out6 = TypeVar("_Out6")
11✔
44
_Out7 = TypeVar("_Out7")
11✔
45
_Out8 = TypeVar("_Out8")
11✔
46
_Out9 = TypeVar("_Out9")
11✔
47

48

49
@overload
50
def Concurrently(
51
    __gets: Iterable[Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output]],
52
) -> _Concurrently[tuple[_Output, ...]]: ...
53

54

55
@overload
56
def Concurrently(
57
    __get0: Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output],
58
    __get1: Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output],
59
    __get2: Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output],
60
    __get3: Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output],
61
    __get4: Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output],
62
    __get5: Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output],
63
    __get6: Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output],
64
    __get7: Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output],
65
    __get8: Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output],
66
    __get9: Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output],
67
    __get10: Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output],
68
    *__gets: Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output],
69
) -> _Concurrently[tuple[_Output, ...]]: ...
70

71

72
@overload
73
def Concurrently(
74
    __get0: Coroutine[Any, Any, _Out0] | Call[_Out0] | _Concurrently[_Out0],
75
    __get1: Coroutine[Any, Any, _Out1] | Call[_Out1] | _Concurrently[_Out1],
76
    __get2: Coroutine[Any, Any, _Out2] | Call[_Out2] | _Concurrently[_Out2],
77
    __get3: Coroutine[Any, Any, _Out3] | Call[_Out3] | _Concurrently[_Out3],
78
    __get4: Coroutine[Any, Any, _Out4] | Call[_Out4] | _Concurrently[_Out4],
79
    __get5: Coroutine[Any, Any, _Out5] | Call[_Out5] | _Concurrently[_Out5],
80
    __get6: Coroutine[Any, Any, _Out6] | Call[_Out6] | _Concurrently[_Out6],
81
    __get7: Coroutine[Any, Any, _Out7] | Call[_Out7] | _Concurrently[_Out7],
82
    __get8: Coroutine[Any, Any, _Out8] | Call[_Out8] | _Concurrently[_Out8],
83
    __get9: Coroutine[Any, Any, _Out9] | Call[_Out9] | _Concurrently[_Out9],
84
) -> _Concurrently[tuple[_Out0, _Out1, _Out2, _Out3, _Out4, _Out5, _Out6, _Out7, _Out8, _Out9]]: ...
85

86

87
@overload
88
def Concurrently(
89
    __get0: Coroutine[Any, Any, _Out0] | Call[_Out0] | _Concurrently[_Out0],
90
    __get1: Coroutine[Any, Any, _Out1] | Call[_Out1] | _Concurrently[_Out1],
91
    __get2: Coroutine[Any, Any, _Out2] | Call[_Out2] | _Concurrently[_Out2],
92
    __get3: Coroutine[Any, Any, _Out3] | Call[_Out3] | _Concurrently[_Out3],
93
    __get4: Coroutine[Any, Any, _Out4] | Call[_Out4] | _Concurrently[_Out4],
94
    __get5: Coroutine[Any, Any, _Out5] | Call[_Out5] | _Concurrently[_Out5],
95
    __get6: Coroutine[Any, Any, _Out6] | Call[_Out6] | _Concurrently[_Out6],
96
    __get7: Coroutine[Any, Any, _Out7] | Call[_Out7] | _Concurrently[_Out7],
97
    __get8: Coroutine[Any, Any, _Out8] | Call[_Out8] | _Concurrently[_Out8],
98
) -> _Concurrently[tuple[_Out0, _Out1, _Out2, _Out3, _Out4, _Out5, _Out6, _Out7, _Out8]]: ...
99

100

101
@overload
102
def Concurrently(
103
    __get0: Coroutine[Any, Any, _Out0] | Call[_Out0] | _Concurrently[_Out0],
104
    __get1: Coroutine[Any, Any, _Out1] | Call[_Out1] | _Concurrently[_Out1],
105
    __get2: Coroutine[Any, Any, _Out2] | Call[_Out2] | _Concurrently[_Out2],
106
    __get3: Coroutine[Any, Any, _Out3] | Call[_Out3] | _Concurrently[_Out3],
107
    __get4: Coroutine[Any, Any, _Out4] | Call[_Out4] | _Concurrently[_Out4],
108
    __get5: Coroutine[Any, Any, _Out5] | Call[_Out5] | _Concurrently[_Out5],
109
    __get6: Coroutine[Any, Any, _Out6] | Call[_Out6] | _Concurrently[_Out6],
110
    __get7: Coroutine[Any, Any, _Out7] | Call[_Out7] | _Concurrently[_Out7],
111
) -> _Concurrently[tuple[_Out0, _Out1, _Out2, _Out3, _Out4, _Out5, _Out6, _Out7]]: ...
112

113

114
@overload
115
def Concurrently(
116
    __get0: Coroutine[Any, Any, _Out0] | Call[_Out0] | _Concurrently[_Out0],
117
    __get1: Coroutine[Any, Any, _Out1] | Call[_Out1] | _Concurrently[_Out1],
118
    __get2: Coroutine[Any, Any, _Out2] | Call[_Out2] | _Concurrently[_Out2],
119
    __get3: Coroutine[Any, Any, _Out3] | Call[_Out3] | _Concurrently[_Out3],
120
    __get4: Coroutine[Any, Any, _Out4] | Call[_Out4] | _Concurrently[_Out4],
121
    __get5: Coroutine[Any, Any, _Out5] | Call[_Out5] | _Concurrently[_Out5],
122
    __get6: Coroutine[Any, Any, _Out6] | Call[_Out6] | _Concurrently[_Out6],
123
) -> _Concurrently[tuple[_Out0, _Out1, _Out2, _Out3, _Out4, _Out5, _Out6]]: ...
124

125

126
@overload
127
def Concurrently(
128
    __get0: Coroutine[Any, Any, _Out0] | Call[_Out0] | _Concurrently[_Out0],
129
    __get1: Coroutine[Any, Any, _Out1] | Call[_Out1] | _Concurrently[_Out1],
130
    __get2: Coroutine[Any, Any, _Out2] | Call[_Out2] | _Concurrently[_Out2],
131
    __get3: Coroutine[Any, Any, _Out3] | Call[_Out3] | _Concurrently[_Out3],
132
    __get4: Coroutine[Any, Any, _Out4] | Call[_Out4] | _Concurrently[_Out4],
133
    __get5: Coroutine[Any, Any, _Out5] | Call[_Out5] | _Concurrently[_Out5],
134
) -> _Concurrently[tuple[_Out0, _Out1, _Out2, _Out3, _Out4, _Out5]]: ...
135

136

137
@overload
138
def Concurrently(
139
    __get0: Coroutine[Any, Any, _Out0] | Call[_Out0] | _Concurrently[_Out0],
140
    __get1: Coroutine[Any, Any, _Out1] | Call[_Out1] | _Concurrently[_Out1],
141
    __get2: Coroutine[Any, Any, _Out2] | Call[_Out2] | _Concurrently[_Out2],
142
    __get3: Coroutine[Any, Any, _Out3] | Call[_Out3] | _Concurrently[_Out3],
143
    __get4: Coroutine[Any, Any, _Out4] | Call[_Out4] | _Concurrently[_Out4],
144
) -> _Concurrently[tuple[_Out0, _Out1, _Out2, _Out3, _Out4]]: ...
145

146

147
@overload
148
def Concurrently(
149
    __get0: Coroutine[Any, Any, _Out0] | Call[_Out0] | _Concurrently[_Out0],
150
    __get1: Coroutine[Any, Any, _Out1] | Call[_Out1] | _Concurrently[_Out1],
151
    __get2: Coroutine[Any, Any, _Out2] | Call[_Out2] | _Concurrently[_Out2],
152
    __get3: Coroutine[Any, Any, _Out3] | Call[_Out3] | _Concurrently[_Out3],
153
) -> _Concurrently[tuple[_Out0, _Out1, _Out2, _Out3]]: ...
154

155

156
@overload
157
def Concurrently(
158
    __get0: Coroutine[Any, Any, _Out0] | Call[_Out0] | _Concurrently[_Out0],
159
    __get1: Coroutine[Any, Any, _Out1] | Call[_Out1] | _Concurrently[_Out1],
160
    __get2: Coroutine[Any, Any, _Out2] | Call[_Out2] | _Concurrently[_Out2],
161
) -> _Concurrently[tuple[_Out0, _Out1, _Out2]]: ...
162

163

164
@overload
165
def Concurrently(
166
    __get0: Coroutine[Any, Any, _Out0] | Call[_Out0] | _Concurrently[_Out0],
167
    __get1: Coroutine[Any, Any, _Out1] | Call[_Out1] | _Concurrently[_Out1],
168
) -> _Concurrently[tuple[_Out0, _Out1]]: ...
169

170

171
def Concurrently(
11✔
172
    __arg0: (
173
        Iterable[Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output]]
174
        | Coroutine[Any, Any, _Out0]
175
        | Call[_Out0]
176
        | _Concurrently[_Out0]
177
    ),
178
    __arg1: Coroutine[Any, Any, _Out1] | Call[_Out1] | _Concurrently[_Out1] | None = None,
179
    __arg2: Coroutine[Any, Any, _Out2] | Call[_Out2] | _Concurrently[_Out2] | None = None,
180
    __arg3: Coroutine[Any, Any, _Out3] | Call[_Out3] | _Concurrently[_Out3] | None = None,
181
    __arg4: Coroutine[Any, Any, _Out4] | Call[_Out4] | _Concurrently[_Out4] | None = None,
182
    __arg5: Coroutine[Any, Any, _Out5] | Call[_Out5] | _Concurrently[_Out5] | None = None,
183
    __arg6: Coroutine[Any, Any, _Out6] | Call[_Out6] | _Concurrently[_Out6] | None = None,
184
    __arg7: Coroutine[Any, Any, _Out7] | Call[_Out7] | _Concurrently[_Out7] | None = None,
185
    __arg8: Coroutine[Any, Any, _Out8] | Call[_Out8] | _Concurrently[_Out8] | None = None,
186
    __arg9: Coroutine[Any, Any, _Out9] | Call[_Out9] | _Concurrently[_Out9] | None = None,
187
    *__args: Coroutine[Any, Any, _Output] | Call[_Output] | _Concurrently[_Output],
188
) -> _Concurrently[
189
    tuple[_Output, ...]
190
    | tuple[_Out0, _Out1, _Out2, _Out3, _Out4, _Out5, _Out6, _Out7, _Out8, _Out9]
191
    | tuple[_Out0, _Out1, _Out2, _Out3, _Out4, _Out5, _Out6, _Out7, _Out8]
192
    | tuple[_Out0, _Out1, _Out2, _Out3, _Out4, _Out5, _Out6, _Out7]
193
    | tuple[_Out0, _Out1, _Out2, _Out3, _Out4, _Out5, _Out6]
194
    | tuple[_Out0, _Out1, _Out2, _Out3, _Out4, _Out5]
195
    | tuple[_Out0, _Out1, _Out2, _Out3, _Out4]
196
    | tuple[_Out0, _Out1, _Out2, _Out3]
197
    | tuple[_Out0, _Out1, _Out2]
198
    | tuple[_Out0, _Out1]
199
    | tuple[_Out0]
200
]:
201
    """Yield a tuple of Coroutine instances all at once.
202

203
    The `yield`ed value `self.calls` is interpreted by the engine within
204
    `generator_send()`. This class will yield a tuple of Coroutine instances,
205
    which is converted into `PyGeneratorResponse::GetMulti`.
206

207
    The engine will fulfill these coroutines in parallel, and return a tuple of _Output
208
    instances to this method, which then returns this tuple to the `@rule` which called
209
    `await concurrently(...) for ... in ...)`.
210
    """
211
    if (
11✔
212
        isinstance(__arg0, Iterable)
213
        and __arg1 is None
214
        and __arg2 is None
215
        and __arg3 is None
216
        and __arg4 is None
217
        and __arg5 is None
218
        and __arg6 is None
219
        and __arg7 is None
220
        and __arg8 is None
221
        and __arg9 is None
222
        and not __args
223
    ):
224
        return _Concurrently(tuple(__arg0))
11✔
225

226
    if (
11✔
227
        isinstance(__arg0, (Coroutine, Call, _Concurrently))
228
        and __arg1 is None
229
        and __arg2 is None
230
        and __arg3 is None
231
        and __arg4 is None
232
        and __arg5 is None
233
        and __arg6 is None
234
        and __arg7 is None
235
        and __arg8 is None
236
        and __arg9 is None
237
        and not __args
238
    ):
NEW
239
        return _Concurrently((__arg0,))
×
240

241
    if (
11✔
242
        isinstance(__arg0, (Coroutine, Call, _Concurrently))
243
        and isinstance(__arg1, (Coroutine, Call, _Concurrently))
244
        and __arg2 is None
245
        and __arg3 is None
246
        and __arg4 is None
247
        and __arg5 is None
248
        and __arg6 is None
249
        and __arg7 is None
250
        and __arg8 is None
251
        and __arg9 is None
252
        and not __args
253
    ):
254
        return _Concurrently((__arg0, __arg1))
11✔
255

256
    if (
11✔
257
        isinstance(__arg0, (Coroutine, Call, _Concurrently))
258
        and isinstance(__arg1, (Coroutine, Call, _Concurrently))
259
        and isinstance(__arg2, (Coroutine, Call, _Concurrently))
260
        and __arg3 is None
261
        and __arg4 is None
262
        and __arg5 is None
263
        and __arg6 is None
264
        and __arg7 is None
265
        and __arg8 is None
266
        and __arg9 is None
267
        and not __args
268
    ):
269
        return _Concurrently((__arg0, __arg1, __arg2))
11✔
270

271
    if (
11✔
272
        isinstance(__arg0, (Coroutine, Call, _Concurrently))
273
        and isinstance(__arg1, (Coroutine, Call, _Concurrently))
274
        and isinstance(__arg2, (Coroutine, Call, _Concurrently))
275
        and isinstance(__arg3, (Coroutine, Call, _Concurrently))
276
        and __arg4 is None
277
        and __arg5 is None
278
        and __arg6 is None
279
        and __arg7 is None
280
        and __arg8 is None
281
        and __arg9 is None
282
        and not __args
283
    ):
284
        return _Concurrently((__arg0, __arg1, __arg2, __arg3))
11✔
285

286
    if (
6✔
287
        isinstance(__arg0, (Coroutine, Call, _Concurrently))
288
        and isinstance(__arg1, (Coroutine, Call, _Concurrently))
289
        and isinstance(__arg2, (Coroutine, Call, _Concurrently))
290
        and isinstance(__arg3, (Coroutine, Call, _Concurrently))
291
        and isinstance(__arg4, (Coroutine, Call, _Concurrently))
292
        and __arg5 is None
293
        and __arg6 is None
294
        and __arg7 is None
295
        and __arg8 is None
296
        and __arg9 is None
297
        and not __args
298
    ):
299
        return _Concurrently((__arg0, __arg1, __arg2, __arg3, __arg4))
4✔
300

301
    if (
3✔
302
        isinstance(__arg0, (Coroutine, Call, _Concurrently))
303
        and isinstance(__arg1, (Coroutine, Call, _Concurrently))
304
        and isinstance(__arg2, (Coroutine, Call, _Concurrently))
305
        and isinstance(__arg3, (Coroutine, Call, _Concurrently))
306
        and isinstance(__arg4, (Coroutine, Call, _Concurrently))
307
        and isinstance(__arg5, (Coroutine, Call, _Concurrently))
308
        and __arg6 is None
309
        and __arg7 is None
310
        and __arg8 is None
311
        and __arg9 is None
312
        and not __args
313
    ):
314
        return _Concurrently((__arg0, __arg1, __arg2, __arg3, __arg4, __arg5))
3✔
315

316
    if (
×
317
        isinstance(__arg0, (Coroutine, Call, _Concurrently))
318
        and isinstance(__arg1, (Coroutine, Call, _Concurrently))
319
        and isinstance(__arg2, (Coroutine, Call, _Concurrently))
320
        and isinstance(__arg3, (Coroutine, Call, _Concurrently))
321
        and isinstance(__arg4, (Coroutine, Call, _Concurrently))
322
        and isinstance(__arg5, (Coroutine, Call, _Concurrently))
323
        and isinstance(__arg6, (Coroutine, Call, _Concurrently))
324
        and __arg7 is None
325
        and __arg8 is None
326
        and __arg9 is None
327
        and not __args
328
    ):
NEW
329
        return _Concurrently((__arg0, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6))
×
330

331
    if (
×
332
        isinstance(__arg0, (Coroutine, Call, _Concurrently))
333
        and isinstance(__arg1, (Coroutine, Call, _Concurrently))
334
        and isinstance(__arg2, (Coroutine, Call, _Concurrently))
335
        and isinstance(__arg3, (Coroutine, Call, _Concurrently))
336
        and isinstance(__arg4, (Coroutine, Call, _Concurrently))
337
        and isinstance(__arg5, (Coroutine, Call, _Concurrently))
338
        and isinstance(__arg6, (Coroutine, Call, _Concurrently))
339
        and isinstance(__arg7, (Coroutine, Call, _Concurrently))
340
        and __arg8 is None
341
        and __arg9 is None
342
        and not __args
343
    ):
NEW
344
        return _Concurrently((__arg0, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7))
×
345

346
    if (
×
347
        isinstance(__arg0, (Coroutine, Call, _Concurrently))
348
        and isinstance(__arg1, (Coroutine, Call, _Concurrently))
349
        and isinstance(__arg2, (Coroutine, Call, _Concurrently))
350
        and isinstance(__arg3, (Coroutine, Call, _Concurrently))
351
        and isinstance(__arg4, (Coroutine, Call, _Concurrently))
352
        and isinstance(__arg5, (Coroutine, Call, _Concurrently))
353
        and isinstance(__arg6, (Coroutine, Call, _Concurrently))
354
        and isinstance(__arg7, (Coroutine, Call, _Concurrently))
355
        and isinstance(__arg8, (Coroutine, Call, _Concurrently))
356
        and __arg9 is None
357
        and not __args
358
    ):
NEW
359
        return _Concurrently(
×
360
            (__arg0, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7, __arg8)
361
        )
362

363
    if (
×
364
        isinstance(__arg0, (Coroutine, Call, _Concurrently))
365
        and isinstance(__arg1, (Coroutine, Call, _Concurrently))
366
        and isinstance(__arg2, (Coroutine, Call, _Concurrently))
367
        and isinstance(__arg3, (Coroutine, Call, _Concurrently))
368
        and isinstance(__arg4, (Coroutine, Call, _Concurrently))
369
        and isinstance(__arg5, (Coroutine, Call, _Concurrently))
370
        and isinstance(__arg6, (Coroutine, Call, _Concurrently))
371
        and isinstance(__arg7, (Coroutine, Call, _Concurrently))
372
        and isinstance(__arg8, (Coroutine, Call, _Concurrently))
373
        and isinstance(__arg9, (Coroutine, Call, _Concurrently))
374
        and all(isinstance(arg, (Coroutine, Call, _Concurrently)) for arg in __args)
375
    ):
NEW
376
        return _Concurrently(
×
377
            (
378
                __arg0,
379
                __arg1,
380
                __arg2,
381
                __arg3,
382
                __arg4,
383
                __arg5,
384
                __arg6,
385
                __arg7,
386
                __arg8,
387
                __arg9,
388
                *__args,
389
            )
390
        )
391

392
    args = __arg0, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7, __arg8, __arg9, *__args
×
393

394
    def render_arg(arg: Any) -> str | None:
×
395
        if arg is None:
×
396
            return None
×
397
        return repr(arg)
×
398

399
    likely_args_explicitly_passed = tuple(
×
400
        reversed(
401
            [
402
                render_arg(arg)
403
                for arg in itertools.dropwhile(lambda arg: arg is None, reversed(args))
404
            ]
405
        )
406
    )
407
    if any(arg is None for arg in likely_args_explicitly_passed):
×
408
        raise ValueError(
×
409
            softwrap(
410
                f"""
411
                Unexpected concurrently() None arguments: {
412
                    ", ".join(map(str, likely_args_explicitly_passed))
413
                }
414

415
                When calling concurrently() on individual rule calls, all leading arguments must be
416
                awaitables.
417
                """
418
            )
419
        )
420

421
    raise TypeError(
×
422
        softwrap(
423
            f"""
424
            Unexpected concurrently() argument types: {", ".join(map(str, likely_args_explicitly_passed))}
425

426
            `concurrently` can be used in two ways:
427
              1. concurrently(Iterable[awaitable[T]]) -> Tuple[T]
428
              2. concurrently(awaitable[T1]], ...) -> Tuple[T1, T2, ...]
429

430
            The 1st form is intended for homogenous collections of rule calls and emulates an
431
            async `for ...` comprehension used to iterate over the collection in parallel and
432
            collect the results in a homogenous tuple when all are complete.
433

434
            The 2nd form supports executing heterogeneous rule calls in parallel and collecting
435
            them in a heterogeneous tuple when all are complete. Currently up to 10 heterogeneous
436
            rule calls can be passed while still tracking their output types for type-checking by
437
            MyPy and similar type checkers. If more than 10 rule calls are passed, type checking
438
            will enforce that they are homogeneous.
439
            """
440
        )
441
    )
442

443

444
concurrently = Concurrently
11✔
445

446

447
@dataclass(frozen=True)
11✔
448
class Params:
11✔
449
    """A set of values with distinct types.
450

451
    Distinct types are enforced at consumption time by the rust type of the same name.
452
    """
453

454
    params: tuple[Any, ...]
11✔
455

456
    def __init__(self, *args: Any) -> None:
11✔
457
        object.__setattr__(self, "params", tuple(args))
11✔
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

© 2026 Coveralls, Inc