prefect-client 3.1.5__py3-none-any.whl → 3.1.6__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.
- prefect/__init__.py +3 -0
- prefect/_internal/compatibility/migration.py +1 -1
- prefect/_internal/concurrency/api.py +52 -52
- prefect/_internal/concurrency/calls.py +59 -35
- prefect/_internal/concurrency/cancellation.py +34 -18
- prefect/_internal/concurrency/event_loop.py +7 -6
- prefect/_internal/concurrency/threads.py +41 -33
- prefect/_internal/concurrency/waiters.py +28 -21
- prefect/_internal/pydantic/v1_schema.py +2 -2
- prefect/_internal/pydantic/v2_schema.py +10 -9
- prefect/_internal/schemas/bases.py +9 -7
- prefect/_internal/schemas/validators.py +2 -1
- prefect/_version.py +3 -3
- prefect/automations.py +53 -47
- prefect/blocks/abstract.py +12 -10
- prefect/blocks/core.py +4 -2
- prefect/cache_policies.py +11 -11
- prefect/client/__init__.py +3 -1
- prefect/client/base.py +36 -37
- prefect/client/cloud.py +26 -19
- prefect/client/collections.py +2 -2
- prefect/client/orchestration.py +342 -273
- prefect/client/schemas/__init__.py +24 -0
- prefect/client/schemas/actions.py +123 -116
- prefect/client/schemas/objects.py +110 -81
- prefect/client/schemas/responses.py +18 -18
- prefect/client/schemas/schedules.py +136 -93
- prefect/client/subscriptions.py +28 -14
- prefect/client/utilities.py +32 -36
- prefect/concurrency/asyncio.py +6 -9
- prefect/concurrency/sync.py +35 -5
- prefect/context.py +39 -31
- prefect/deployments/flow_runs.py +3 -5
- prefect/docker/__init__.py +1 -1
- prefect/events/schemas/events.py +25 -20
- prefect/events/utilities.py +1 -2
- prefect/filesystems.py +3 -3
- prefect/flow_engine.py +61 -21
- prefect/flow_runs.py +3 -3
- prefect/flows.py +214 -170
- prefect/logging/configuration.py +1 -1
- prefect/logging/highlighters.py +1 -2
- prefect/logging/loggers.py +30 -20
- prefect/main.py +17 -24
- prefect/runner/runner.py +43 -21
- prefect/runner/server.py +30 -32
- prefect/runner/submit.py +3 -6
- prefect/runner/utils.py +6 -6
- prefect/runtime/flow_run.py +7 -0
- prefect/settings/constants.py +2 -2
- prefect/settings/legacy.py +1 -1
- prefect/settings/models/server/events.py +10 -0
- prefect/task_engine.py +72 -19
- prefect/task_runners.py +2 -2
- prefect/tasks.py +46 -33
- prefect/telemetry/bootstrap.py +15 -2
- prefect/telemetry/run_telemetry.py +107 -0
- prefect/transactions.py +14 -14
- prefect/types/__init__.py +1 -4
- prefect/utilities/_engine.py +96 -0
- prefect/utilities/annotations.py +25 -18
- prefect/utilities/asyncutils.py +126 -140
- prefect/utilities/callables.py +87 -78
- prefect/utilities/collections.py +278 -117
- prefect/utilities/compat.py +13 -21
- prefect/utilities/context.py +6 -5
- prefect/utilities/dispatch.py +23 -12
- prefect/utilities/dockerutils.py +33 -32
- prefect/utilities/engine.py +126 -239
- prefect/utilities/filesystem.py +18 -15
- prefect/utilities/hashing.py +10 -11
- prefect/utilities/importtools.py +40 -27
- prefect/utilities/math.py +9 -5
- prefect/utilities/names.py +3 -3
- prefect/utilities/processutils.py +121 -57
- prefect/utilities/pydantic.py +41 -36
- prefect/utilities/render_swagger.py +22 -12
- prefect/utilities/schema_tools/__init__.py +2 -1
- prefect/utilities/schema_tools/hydration.py +50 -43
- prefect/utilities/schema_tools/validation.py +52 -42
- prefect/utilities/services.py +13 -12
- prefect/utilities/templating.py +45 -45
- prefect/utilities/text.py +2 -1
- prefect/utilities/timeout.py +4 -4
- prefect/utilities/urls.py +9 -4
- prefect/utilities/visualization.py +46 -24
- prefect/variables.py +9 -8
- prefect/workers/base.py +15 -8
- {prefect_client-3.1.5.dist-info → prefect_client-3.1.6.dist-info}/METADATA +4 -2
- {prefect_client-3.1.5.dist-info → prefect_client-3.1.6.dist-info}/RECORD +93 -91
- {prefect_client-3.1.5.dist-info → prefect_client-3.1.6.dist-info}/LICENSE +0 -0
- {prefect_client-3.1.5.dist-info → prefect_client-3.1.6.dist-info}/WHEEL +0 -0
- {prefect_client-3.1.5.dist-info → prefect_client-3.1.6.dist-info}/top_level.txt +0 -0
prefect/utilities/callables.py
CHANGED
@@ -6,14 +6,17 @@ import ast
|
|
6
6
|
import importlib.util
|
7
7
|
import inspect
|
8
8
|
import warnings
|
9
|
+
from collections import OrderedDict
|
10
|
+
from collections.abc import Iterable
|
9
11
|
from functools import partial
|
12
|
+
from logging import Logger
|
10
13
|
from pathlib import Path
|
11
|
-
from typing import Any, Callable,
|
14
|
+
from typing import Any, Callable, Optional, Union, cast
|
12
15
|
|
13
|
-
import cloudpickle
|
16
|
+
import cloudpickle # type: ignore # no stubs available
|
14
17
|
import pydantic
|
15
18
|
from griffe import Docstring, DocstringSectionKind, Parser, parse
|
16
|
-
from typing_extensions import Literal
|
19
|
+
from typing_extensions import Literal, TypeVar
|
17
20
|
|
18
21
|
from prefect._internal.pydantic.v1_schema import has_v1_type_as_param
|
19
22
|
from prefect._internal.pydantic.v2_schema import (
|
@@ -32,15 +35,17 @@ from prefect.utilities.annotations import allow_failure, quote, unmapped
|
|
32
35
|
from prefect.utilities.collections import isiterable
|
33
36
|
from prefect.utilities.importtools import safe_load_namespace
|
34
37
|
|
35
|
-
logger = get_logger(__name__)
|
38
|
+
logger: Logger = get_logger(__name__)
|
39
|
+
|
40
|
+
R = TypeVar("R", infer_variance=True)
|
36
41
|
|
37
42
|
|
38
43
|
def get_call_parameters(
|
39
|
-
fn: Callable,
|
40
|
-
call_args:
|
41
|
-
call_kwargs:
|
44
|
+
fn: Callable[..., Any],
|
45
|
+
call_args: tuple[Any, ...],
|
46
|
+
call_kwargs: dict[str, Any],
|
42
47
|
apply_defaults: bool = True,
|
43
|
-
) ->
|
48
|
+
) -> dict[str, Any]:
|
44
49
|
"""
|
45
50
|
Bind a call to a function to get parameter/value mapping. Default values on
|
46
51
|
the signature will be included if not overridden.
|
@@ -57,7 +62,7 @@ def get_call_parameters(
|
|
57
62
|
function
|
58
63
|
"""
|
59
64
|
if hasattr(fn, "__prefect_self__"):
|
60
|
-
call_args = (fn
|
65
|
+
call_args = (getattr(fn, "__prefect_self__"), *call_args)
|
61
66
|
|
62
67
|
try:
|
63
68
|
bound_signature = inspect.signature(fn).bind(*call_args, **call_kwargs)
|
@@ -74,14 +79,14 @@ def get_call_parameters(
|
|
74
79
|
|
75
80
|
|
76
81
|
def get_parameter_defaults(
|
77
|
-
fn: Callable,
|
78
|
-
) ->
|
82
|
+
fn: Callable[..., Any],
|
83
|
+
) -> dict[str, Any]:
|
79
84
|
"""
|
80
85
|
Get default parameter values for a callable.
|
81
86
|
"""
|
82
87
|
signature = inspect.signature(fn)
|
83
88
|
|
84
|
-
parameter_defaults = {}
|
89
|
+
parameter_defaults: dict[str, Any] = {}
|
85
90
|
|
86
91
|
for name, param in signature.parameters.items():
|
87
92
|
if param.default is not signature.empty:
|
@@ -91,8 +96,8 @@ def get_parameter_defaults(
|
|
91
96
|
|
92
97
|
|
93
98
|
def explode_variadic_parameter(
|
94
|
-
fn: Callable, parameters:
|
95
|
-
) ->
|
99
|
+
fn: Callable[..., Any], parameters: dict[str, Any]
|
100
|
+
) -> dict[str, Any]:
|
96
101
|
"""
|
97
102
|
Given a parameter dictionary, move any parameters stored in a variadic keyword
|
98
103
|
argument parameter (i.e. **kwargs) into the top level.
|
@@ -125,8 +130,8 @@ def explode_variadic_parameter(
|
|
125
130
|
|
126
131
|
|
127
132
|
def collapse_variadic_parameters(
|
128
|
-
fn: Callable, parameters:
|
129
|
-
) ->
|
133
|
+
fn: Callable[..., Any], parameters: dict[str, Any]
|
134
|
+
) -> dict[str, Any]:
|
130
135
|
"""
|
131
136
|
Given a parameter dictionary, move any parameters stored not present in the
|
132
137
|
signature into the variadic keyword argument.
|
@@ -151,50 +156,47 @@ def collapse_variadic_parameters(
|
|
151
156
|
|
152
157
|
missing_parameters = set(parameters.keys()) - set(signature_parameters.keys())
|
153
158
|
|
154
|
-
if not
|
159
|
+
if not missing_parameters:
|
160
|
+
# no missing parameters, return parameters unchanged
|
161
|
+
return parameters
|
162
|
+
|
163
|
+
if not variadic_key:
|
155
164
|
raise ValueError(
|
156
165
|
f"Signature for {fn} does not include any variadic keyword argument "
|
157
166
|
"but parameters were given that are not present in the signature."
|
158
167
|
)
|
159
168
|
|
160
|
-
if variadic_key and not missing_parameters:
|
161
|
-
# variadic key is present but no missing parameters, return parameters unchanged
|
162
|
-
return parameters
|
163
|
-
|
164
169
|
new_parameters = parameters.copy()
|
165
|
-
|
166
|
-
new_parameters
|
167
|
-
|
168
|
-
for key in missing_parameters:
|
169
|
-
new_parameters[variadic_key][key] = new_parameters.pop(key)
|
170
|
-
|
170
|
+
new_parameters[variadic_key] = {
|
171
|
+
key: new_parameters.pop(key) for key in missing_parameters
|
172
|
+
}
|
171
173
|
return new_parameters
|
172
174
|
|
173
175
|
|
174
176
|
def parameters_to_args_kwargs(
|
175
|
-
fn: Callable,
|
176
|
-
parameters:
|
177
|
-
) ->
|
177
|
+
fn: Callable[..., Any],
|
178
|
+
parameters: dict[str, Any],
|
179
|
+
) -> tuple[tuple[Any, ...], dict[str, Any]]:
|
178
180
|
"""
|
179
181
|
Convert a `parameters` dictionary to positional and keyword arguments
|
180
182
|
|
181
183
|
The function _must_ have an identical signature to the original function or this
|
182
184
|
will return an empty tuple and dict.
|
183
185
|
"""
|
184
|
-
function_params =
|
186
|
+
function_params = inspect.signature(fn).parameters.keys()
|
185
187
|
# Check for parameters that are not present in the function signature
|
186
188
|
unknown_params = parameters.keys() - function_params
|
187
189
|
if unknown_params:
|
188
190
|
raise SignatureMismatchError.from_bad_params(
|
189
|
-
list(function_params), list(parameters
|
191
|
+
list(function_params), list(parameters)
|
190
192
|
)
|
191
193
|
bound_signature = inspect.signature(fn).bind_partial()
|
192
|
-
bound_signature.arguments = parameters
|
194
|
+
bound_signature.arguments = OrderedDict(parameters)
|
193
195
|
|
194
196
|
return bound_signature.args, bound_signature.kwargs
|
195
197
|
|
196
198
|
|
197
|
-
def call_with_parameters(fn: Callable, parameters:
|
199
|
+
def call_with_parameters(fn: Callable[..., R], parameters: dict[str, Any]) -> R:
|
198
200
|
"""
|
199
201
|
Call a function with parameters extracted with `get_call_parameters`
|
200
202
|
|
@@ -207,7 +209,7 @@ def call_with_parameters(fn: Callable, parameters: Dict[str, Any]):
|
|
207
209
|
|
208
210
|
|
209
211
|
def cloudpickle_wrapped_call(
|
210
|
-
__fn: Callable, *args: Any, **kwargs: Any
|
212
|
+
__fn: Callable[..., Any], *args: Any, **kwargs: Any
|
211
213
|
) -> Callable[[], bytes]:
|
212
214
|
"""
|
213
215
|
Serializes a function call using cloudpickle then returns a callable which will
|
@@ -217,18 +219,18 @@ def cloudpickle_wrapped_call(
|
|
217
219
|
built-in pickler (e.g. `anyio.to_process` and `multiprocessing`) but may require
|
218
220
|
a wider range of pickling support.
|
219
221
|
"""
|
220
|
-
payload = cloudpickle.dumps((__fn, args, kwargs))
|
222
|
+
payload = cloudpickle.dumps((__fn, args, kwargs)) # type: ignore # no stubs available
|
221
223
|
return partial(_run_serialized_call, payload)
|
222
224
|
|
223
225
|
|
224
|
-
def _run_serialized_call(payload) -> bytes:
|
226
|
+
def _run_serialized_call(payload: bytes) -> bytes:
|
225
227
|
"""
|
226
228
|
Defined at the top-level so it can be pickled by the Python pickler.
|
227
229
|
Used by `cloudpickle_wrapped_call`.
|
228
230
|
"""
|
229
231
|
fn, args, kwargs = cloudpickle.loads(payload)
|
230
232
|
retval = fn(*args, **kwargs)
|
231
|
-
return cloudpickle.dumps(retval)
|
233
|
+
return cloudpickle.dumps(retval) # type: ignore # no stubs available
|
232
234
|
|
233
235
|
|
234
236
|
class ParameterSchema(pydantic.BaseModel):
|
@@ -236,18 +238,18 @@ class ParameterSchema(pydantic.BaseModel):
|
|
236
238
|
|
237
239
|
title: Literal["Parameters"] = "Parameters"
|
238
240
|
type: Literal["object"] = "object"
|
239
|
-
properties:
|
240
|
-
required:
|
241
|
-
definitions:
|
241
|
+
properties: dict[str, Any] = pydantic.Field(default_factory=dict)
|
242
|
+
required: list[str] = pydantic.Field(default_factory=list)
|
243
|
+
definitions: dict[str, Any] = pydantic.Field(default_factory=dict)
|
242
244
|
|
243
|
-
def model_dump_for_openapi(self) ->
|
245
|
+
def model_dump_for_openapi(self) -> dict[str, Any]:
|
244
246
|
result = self.model_dump(mode="python", exclude_none=True)
|
245
247
|
if "required" in result and not result["required"]:
|
246
248
|
del result["required"]
|
247
249
|
return result
|
248
250
|
|
249
251
|
|
250
|
-
def parameter_docstrings(docstring: Optional[str]) ->
|
252
|
+
def parameter_docstrings(docstring: Optional[str]) -> dict[str, str]:
|
251
253
|
"""
|
252
254
|
Given a docstring in Google docstring format, parse the parameter section
|
253
255
|
and return a dictionary that maps parameter names to docstring.
|
@@ -258,7 +260,7 @@ def parameter_docstrings(docstring: Optional[str]) -> Dict[str, str]:
|
|
258
260
|
Returns:
|
259
261
|
Mapping from parameter names to docstrings.
|
260
262
|
"""
|
261
|
-
param_docstrings = {}
|
263
|
+
param_docstrings: dict[str, str] = {}
|
262
264
|
|
263
265
|
if not docstring:
|
264
266
|
return param_docstrings
|
@@ -279,9 +281,9 @@ def process_v1_params(
|
|
279
281
|
param: inspect.Parameter,
|
280
282
|
*,
|
281
283
|
position: int,
|
282
|
-
docstrings:
|
283
|
-
aliases:
|
284
|
-
) ->
|
284
|
+
docstrings: dict[str, str],
|
285
|
+
aliases: dict[str, str],
|
286
|
+
) -> tuple[str, Any, Any]:
|
285
287
|
# Pydantic model creation will fail if names collide with the BaseModel type
|
286
288
|
if hasattr(pydantic.BaseModel, param.name):
|
287
289
|
name = param.name + "__"
|
@@ -289,13 +291,13 @@ def process_v1_params(
|
|
289
291
|
else:
|
290
292
|
name = param.name
|
291
293
|
|
292
|
-
type_ = Any if param.annotation is inspect.
|
294
|
+
type_ = Any if param.annotation is inspect.Parameter.empty else param.annotation
|
293
295
|
|
294
296
|
with warnings.catch_warnings():
|
295
297
|
warnings.filterwarnings(
|
296
298
|
"ignore", category=pydantic.warnings.PydanticDeprecatedSince20
|
297
299
|
)
|
298
|
-
field = pydantic.Field(
|
300
|
+
field: Any = pydantic.Field( # type: ignore # this uses the v1 signature, not v2
|
299
301
|
default=... if param.default is param.empty else param.default,
|
300
302
|
title=param.name,
|
301
303
|
description=docstrings.get(param.name, None),
|
@@ -305,19 +307,24 @@ def process_v1_params(
|
|
305
307
|
return name, type_, field
|
306
308
|
|
307
309
|
|
308
|
-
def create_v1_schema(
|
310
|
+
def create_v1_schema(
|
311
|
+
name_: str, model_cfg: type[Any], model_fields: Optional[dict[str, Any]] = None
|
312
|
+
) -> dict[str, Any]:
|
309
313
|
with warnings.catch_warnings():
|
310
314
|
warnings.filterwarnings(
|
311
315
|
"ignore", category=pydantic.warnings.PydanticDeprecatedSince20
|
312
316
|
)
|
313
317
|
|
314
|
-
|
315
|
-
|
318
|
+
model_fields = model_fields or {}
|
319
|
+
model: type[pydantic.BaseModel] = pydantic.create_model( # type: ignore # this uses the v1 signature, not v2
|
320
|
+
name_,
|
321
|
+
__config__=model_cfg, # type: ignore # this uses the v1 signature, not v2
|
322
|
+
**model_fields,
|
316
323
|
)
|
317
|
-
return model.schema(by_alias=True)
|
324
|
+
return model.schema(by_alias=True) # type: ignore # this uses the v1 signature, not v2
|
318
325
|
|
319
326
|
|
320
|
-
def parameter_schema(fn: Callable) -> ParameterSchema:
|
327
|
+
def parameter_schema(fn: Callable[..., Any]) -> ParameterSchema:
|
321
328
|
"""Given a function, generates an OpenAPI-compatible description
|
322
329
|
of the function's arguments, including:
|
323
330
|
- name
|
@@ -378,7 +385,7 @@ def parameter_schema_from_entrypoint(entrypoint: str) -> ParameterSchema:
|
|
378
385
|
|
379
386
|
|
380
387
|
def generate_parameter_schema(
|
381
|
-
signature: inspect.Signature, docstrings:
|
388
|
+
signature: inspect.Signature, docstrings: dict[str, str]
|
382
389
|
) -> ParameterSchema:
|
383
390
|
"""
|
384
391
|
Generate a parameter schema from a function signature and docstrings.
|
@@ -394,22 +401,22 @@ def generate_parameter_schema(
|
|
394
401
|
ParameterSchema: The parameter schema.
|
395
402
|
"""
|
396
403
|
|
397
|
-
model_fields = {}
|
398
|
-
aliases = {}
|
404
|
+
model_fields: dict[str, Any] = {}
|
405
|
+
aliases: dict[str, str] = {}
|
399
406
|
|
400
407
|
if not has_v1_type_as_param(signature):
|
401
|
-
|
408
|
+
config = pydantic.ConfigDict(arbitrary_types_allowed=True)
|
409
|
+
|
410
|
+
create_schema = partial(create_v2_schema, model_cfg=config)
|
402
411
|
process_params = process_v2_params
|
403
412
|
|
404
|
-
config = pydantic.ConfigDict(arbitrary_types_allowed=True)
|
405
413
|
else:
|
406
|
-
create_schema = create_v1_schema
|
407
|
-
process_params = process_v1_params
|
408
414
|
|
409
415
|
class ModelConfig:
|
410
416
|
arbitrary_types_allowed = True
|
411
417
|
|
412
|
-
|
418
|
+
create_schema = partial(create_v1_schema, model_cfg=ModelConfig)
|
419
|
+
process_params = process_v1_params
|
413
420
|
|
414
421
|
for position, param in enumerate(signature.parameters.values()):
|
415
422
|
name, type_, field = process_params(
|
@@ -418,24 +425,26 @@ def generate_parameter_schema(
|
|
418
425
|
# Generate a Pydantic model at each step so we can check if this parameter
|
419
426
|
# type supports schema generation
|
420
427
|
try:
|
421
|
-
create_schema("CheckParameter",
|
428
|
+
create_schema("CheckParameter", model_fields={name: (type_, field)})
|
422
429
|
except (ValueError, TypeError):
|
423
430
|
# This field's type is not valid for schema creation, update it to `Any`
|
424
431
|
type_ = Any
|
425
432
|
model_fields[name] = (type_, field)
|
426
433
|
|
427
434
|
# Generate the final model and schema
|
428
|
-
schema = create_schema("Parameters",
|
435
|
+
schema = create_schema("Parameters", model_fields=model_fields)
|
429
436
|
return ParameterSchema(**schema)
|
430
437
|
|
431
438
|
|
432
|
-
def raise_for_reserved_arguments(
|
439
|
+
def raise_for_reserved_arguments(
|
440
|
+
fn: Callable[..., Any], reserved_arguments: Iterable[str]
|
441
|
+
) -> None:
|
433
442
|
"""Raise a ReservedArgumentError if `fn` has any parameters that conflict
|
434
443
|
with the names contained in `reserved_arguments`."""
|
435
|
-
|
444
|
+
function_parameters = inspect.signature(fn).parameters
|
436
445
|
|
437
446
|
for argument in reserved_arguments:
|
438
|
-
if argument in
|
447
|
+
if argument in function_parameters:
|
439
448
|
raise ReservedArgumentError(
|
440
449
|
f"{argument!r} is a reserved argument name and cannot be used."
|
441
450
|
)
|
@@ -479,7 +488,7 @@ def _generate_signature_from_source(
|
|
479
488
|
)
|
480
489
|
if func_def is None:
|
481
490
|
raise ValueError(f"Function {func_name} not found in source code")
|
482
|
-
parameters = []
|
491
|
+
parameters: list[inspect.Parameter] = []
|
483
492
|
|
484
493
|
# Handle annotations for positional only args e.g. def func(a, /, b, c)
|
485
494
|
for arg in func_def.args.posonlyargs:
|
@@ -642,8 +651,8 @@ def _get_docstring_from_source(source_code: str, func_name: str) -> Optional[str
|
|
642
651
|
|
643
652
|
|
644
653
|
def expand_mapping_parameters(
|
645
|
-
func: Callable, parameters:
|
646
|
-
) ->
|
654
|
+
func: Callable[..., Any], parameters: dict[str, Any]
|
655
|
+
) -> list[dict[str, Any]]:
|
647
656
|
"""
|
648
657
|
Generates a list of call parameters to be used for individual calls in a mapping
|
649
658
|
operation.
|
@@ -653,29 +662,29 @@ def expand_mapping_parameters(
|
|
653
662
|
parameters: A dictionary of parameters with iterables to be mapped over
|
654
663
|
|
655
664
|
Returns:
|
656
|
-
|
665
|
+
list: A list of dictionaries to be used as parameters for each
|
657
666
|
call in the mapping operation
|
658
667
|
"""
|
659
668
|
# Ensure that any parameters in kwargs are expanded before this check
|
660
669
|
parameters = explode_variadic_parameter(func, parameters)
|
661
670
|
|
662
|
-
iterable_parameters = {}
|
663
|
-
static_parameters = {}
|
664
|
-
annotated_parameters = {}
|
671
|
+
iterable_parameters: dict[str, list[Any]] = {}
|
672
|
+
static_parameters: dict[str, Any] = {}
|
673
|
+
annotated_parameters: dict[str, Union[allow_failure[Any], quote[Any]]] = {}
|
665
674
|
for key, val in parameters.items():
|
666
675
|
if isinstance(val, (allow_failure, quote)):
|
667
676
|
# Unwrap annotated parameters to determine if they are iterable
|
668
677
|
annotated_parameters[key] = val
|
669
|
-
val = val.unwrap()
|
678
|
+
val: Any = val.unwrap()
|
670
679
|
|
671
680
|
if isinstance(val, unmapped):
|
672
|
-
static_parameters[key] = val.value
|
681
|
+
static_parameters[key] = cast(unmapped[Any], val).value
|
673
682
|
elif isiterable(val):
|
674
683
|
iterable_parameters[key] = list(val)
|
675
684
|
else:
|
676
685
|
static_parameters[key] = val
|
677
686
|
|
678
|
-
if not
|
687
|
+
if not iterable_parameters:
|
679
688
|
raise MappingMissingIterable(
|
680
689
|
"No iterable parameters were received. Parameters for map must "
|
681
690
|
f"include at least one iterable. Parameters: {parameters}"
|
@@ -693,7 +702,7 @@ def expand_mapping_parameters(
|
|
693
702
|
|
694
703
|
map_length = list(lengths)[0]
|
695
704
|
|
696
|
-
call_parameters_list = []
|
705
|
+
call_parameters_list: list[dict[str, Any]] = []
|
697
706
|
for i in range(map_length):
|
698
707
|
call_parameters = {key: value[i] for key, value in iterable_parameters.items()}
|
699
708
|
call_parameters.update({key: value for key, value in static_parameters.items()})
|