prefect-client 3.1.12__py3-none-any.whl → 3.1.13__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/_experimental/sla/client.py +53 -27
- prefect/_experimental/sla/objects.py +10 -2
- prefect/_internal/concurrency/services.py +2 -2
- prefect/_internal/concurrency/threads.py +6 -0
- prefect/_internal/retries.py +6 -3
- prefect/_internal/schemas/validators.py +6 -4
- prefect/_version.py +3 -3
- prefect/artifacts.py +4 -1
- prefect/automations.py +1 -1
- prefect/blocks/abstract.py +5 -2
- prefect/blocks/notifications.py +1 -0
- prefect/cache_policies.py +20 -20
- prefect/client/utilities.py +3 -3
- prefect/deployments/base.py +7 -4
- prefect/deployments/flow_runs.py +5 -1
- prefect/deployments/runner.py +6 -11
- prefect/deployments/steps/core.py +1 -1
- prefect/deployments/steps/pull.py +8 -3
- prefect/deployments/steps/utility.py +2 -2
- prefect/docker/docker_image.py +13 -9
- prefect/engine.py +19 -10
- prefect/events/cli/automations.py +4 -4
- prefect/events/clients.py +17 -14
- prefect/events/schemas/automations.py +12 -8
- prefect/events/schemas/events.py +5 -1
- prefect/events/worker.py +1 -1
- prefect/filesystems.py +1 -1
- prefect/flow_engine.py +17 -9
- prefect/flows.py +118 -73
- prefect/futures.py +14 -7
- prefect/infrastructure/provisioners/__init__.py +2 -0
- prefect/infrastructure/provisioners/cloud_run.py +4 -4
- prefect/infrastructure/provisioners/coiled.py +249 -0
- prefect/infrastructure/provisioners/container_instance.py +4 -3
- prefect/infrastructure/provisioners/ecs.py +55 -43
- prefect/infrastructure/provisioners/modal.py +5 -4
- prefect/input/actions.py +5 -1
- prefect/input/run_input.py +157 -43
- prefect/logging/configuration.py +3 -3
- prefect/logging/filters.py +2 -2
- prefect/logging/formatters.py +15 -11
- prefect/logging/handlers.py +24 -14
- prefect/logging/highlighters.py +5 -5
- prefect/logging/loggers.py +28 -18
- prefect/main.py +3 -1
- prefect/results.py +166 -86
- prefect/runner/runner.py +34 -27
- prefect/runner/server.py +3 -1
- prefect/runner/storage.py +18 -18
- prefect/runner/submit.py +19 -12
- prefect/runtime/deployment.py +15 -8
- prefect/runtime/flow_run.py +19 -6
- prefect/runtime/task_run.py +7 -3
- prefect/settings/base.py +17 -7
- prefect/settings/legacy.py +4 -4
- prefect/settings/models/api.py +4 -3
- prefect/settings/models/cli.py +4 -3
- prefect/settings/models/client.py +7 -4
- prefect/settings/models/cloud.py +4 -3
- prefect/settings/models/deployments.py +4 -3
- prefect/settings/models/experiments.py +4 -3
- prefect/settings/models/flows.py +4 -3
- prefect/settings/models/internal.py +4 -3
- prefect/settings/models/logging.py +8 -6
- prefect/settings/models/results.py +4 -3
- prefect/settings/models/root.py +11 -16
- prefect/settings/models/runner.py +8 -5
- prefect/settings/models/server/api.py +6 -3
- prefect/settings/models/server/database.py +120 -25
- prefect/settings/models/server/deployments.py +4 -3
- prefect/settings/models/server/ephemeral.py +7 -4
- prefect/settings/models/server/events.py +6 -3
- prefect/settings/models/server/flow_run_graph.py +4 -3
- prefect/settings/models/server/root.py +4 -3
- prefect/settings/models/server/services.py +15 -12
- prefect/settings/models/server/tasks.py +7 -4
- prefect/settings/models/server/ui.py +4 -3
- prefect/settings/models/tasks.py +10 -5
- prefect/settings/models/testing.py +4 -3
- prefect/settings/models/worker.py +7 -4
- prefect/settings/profiles.py +13 -12
- prefect/settings/sources.py +20 -19
- prefect/states.py +17 -13
- prefect/task_engine.py +43 -33
- prefect/task_runners.py +35 -23
- prefect/task_runs.py +20 -11
- prefect/task_worker.py +12 -7
- prefect/tasks.py +30 -24
- prefect/telemetry/bootstrap.py +4 -1
- prefect/telemetry/run_telemetry.py +15 -13
- prefect/transactions.py +3 -3
- prefect/types/__init__.py +3 -1
- prefect/utilities/_deprecated.py +38 -0
- prefect/utilities/engine.py +11 -4
- prefect/utilities/filesystem.py +2 -2
- prefect/utilities/generics.py +1 -1
- prefect/utilities/pydantic.py +21 -36
- prefect/workers/base.py +52 -30
- prefect/workers/process.py +20 -15
- prefect/workers/server.py +4 -5
- {prefect_client-3.1.12.dist-info → prefect_client-3.1.13.dist-info}/METADATA +2 -2
- {prefect_client-3.1.12.dist-info → prefect_client-3.1.13.dist-info}/RECORD +105 -103
- {prefect_client-3.1.12.dist-info → prefect_client-3.1.13.dist-info}/LICENSE +0 -0
- {prefect_client-3.1.12.dist-info → prefect_client-3.1.13.dist-info}/WHEEL +0 -0
- {prefect_client-3.1.12.dist-info → prefect_client-3.1.13.dist-info}/top_level.txt +0 -0
prefect/engine.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import os
|
2
2
|
import sys
|
3
|
-
from typing import Any, Callable
|
3
|
+
from typing import TYPE_CHECKING, Any, Callable
|
4
4
|
from uuid import UUID
|
5
5
|
|
6
6
|
from prefect._internal.compatibility.migration import getattr_migration
|
@@ -15,12 +15,19 @@ from prefect.utilities.asyncutils import (
|
|
15
15
|
run_coro_as_sync,
|
16
16
|
)
|
17
17
|
|
18
|
-
|
18
|
+
if TYPE_CHECKING:
|
19
|
+
import logging
|
20
|
+
|
21
|
+
from prefect.flow_engine import FlowRun
|
22
|
+
from prefect.flows import Flow
|
23
|
+
from prefect.logging.loggers import LoggingAdapter
|
24
|
+
|
25
|
+
engine_logger: "logging.Logger" = get_logger("engine")
|
19
26
|
|
20
27
|
|
21
28
|
if __name__ == "__main__":
|
22
29
|
try:
|
23
|
-
flow_run_id = UUID(
|
30
|
+
flow_run_id: UUID = UUID(
|
24
31
|
sys.argv[1] if len(sys.argv) > 1 else os.environ.get("PREFECT__FLOW_RUN_ID")
|
25
32
|
)
|
26
33
|
except Exception:
|
@@ -37,11 +44,11 @@ if __name__ == "__main__":
|
|
37
44
|
run_flow,
|
38
45
|
)
|
39
46
|
|
40
|
-
flow_run = load_flow_run(flow_run_id=flow_run_id)
|
41
|
-
run_logger = flow_run_logger(flow_run=flow_run)
|
47
|
+
flow_run: "FlowRun" = load_flow_run(flow_run_id=flow_run_id)
|
48
|
+
run_logger: "LoggingAdapter" = flow_run_logger(flow_run=flow_run)
|
42
49
|
|
43
50
|
try:
|
44
|
-
flow = load_flow(flow_run)
|
51
|
+
flow: "Flow[..., Any]" = load_flow(flow_run)
|
45
52
|
except Exception:
|
46
53
|
run_logger.error(
|
47
54
|
"Unexpected exception encountered when trying to load flow",
|
@@ -55,15 +62,17 @@ if __name__ == "__main__":
|
|
55
62
|
else:
|
56
63
|
run_flow(flow, flow_run=flow_run, error_logger=run_logger)
|
57
64
|
|
58
|
-
except Abort as
|
65
|
+
except Abort as abort_signal:
|
66
|
+
abort_signal: Abort
|
59
67
|
engine_logger.info(
|
60
68
|
f"Engine execution of flow run '{flow_run_id}' aborted by orchestrator:"
|
61
|
-
f" {
|
69
|
+
f" {abort_signal}"
|
62
70
|
)
|
63
71
|
exit(0)
|
64
|
-
except Pause as
|
72
|
+
except Pause as pause_signal:
|
73
|
+
pause_signal: Pause
|
65
74
|
engine_logger.info(
|
66
|
-
f"Engine execution of flow run '{flow_run_id}' is paused: {
|
75
|
+
f"Engine execution of flow run '{flow_run_id}' is paused: {pause_signal}"
|
67
76
|
)
|
68
77
|
exit(0)
|
69
78
|
except Exception:
|
@@ -3,7 +3,7 @@ Command line interface for working with automations.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import functools
|
6
|
-
from typing import Optional, Type
|
6
|
+
from typing import Any, Callable, Optional, Type
|
7
7
|
from uuid import UUID
|
8
8
|
|
9
9
|
import orjson
|
@@ -21,16 +21,16 @@ from prefect.client.orchestration import get_client
|
|
21
21
|
from prefect.events.schemas.automations import Automation
|
22
22
|
from prefect.exceptions import PrefectHTTPStatusError
|
23
23
|
|
24
|
-
automations_app = PrefectTyper(
|
24
|
+
automations_app: PrefectTyper = PrefectTyper(
|
25
25
|
name="automation",
|
26
26
|
help="Manage automations.",
|
27
27
|
)
|
28
28
|
app.add_typer(automations_app, aliases=["automations"])
|
29
29
|
|
30
30
|
|
31
|
-
def requires_automations(func):
|
31
|
+
def requires_automations(func: Callable[..., Any]) -> Callable[..., Any]:
|
32
32
|
@functools.wraps(func)
|
33
|
-
async def wrapper(*args, **kwargs):
|
33
|
+
async def wrapper(*args: Any, **kwargs: Any) -> Any:
|
34
34
|
try:
|
35
35
|
return await func(*args, **kwargs)
|
36
36
|
except RuntimeError as exc:
|
prefect/events/clients.py
CHANGED
@@ -70,18 +70,21 @@ EVENT_WEBSOCKET_CHECKPOINTS = Counter(
|
|
70
70
|
labelnames=["client"],
|
71
71
|
)
|
72
72
|
|
73
|
-
|
73
|
+
if TYPE_CHECKING:
|
74
|
+
import logging
|
75
|
+
|
76
|
+
logger: "logging.Logger" = get_logger(__name__)
|
74
77
|
|
75
78
|
|
76
|
-
def http_to_ws(url: str):
|
79
|
+
def http_to_ws(url: str) -> str:
|
77
80
|
return url.replace("https://", "wss://").replace("http://", "ws://").rstrip("/")
|
78
81
|
|
79
82
|
|
80
|
-
def events_in_socket_from_api_url(url: str):
|
83
|
+
def events_in_socket_from_api_url(url: str) -> str:
|
81
84
|
return http_to_ws(url) + "/events/in"
|
82
85
|
|
83
86
|
|
84
|
-
def events_out_socket_from_api_url(url: str):
|
87
|
+
def events_out_socket_from_api_url(url: str) -> str:
|
85
88
|
return http_to_ws(url) + "/events/out"
|
86
89
|
|
87
90
|
|
@@ -250,11 +253,11 @@ class AssertingEventsClient(EventsClient):
|
|
250
253
|
last: ClassVar["Optional[AssertingEventsClient]"] = None
|
251
254
|
all: ClassVar[List["AssertingEventsClient"]] = []
|
252
255
|
|
253
|
-
args:
|
254
|
-
kwargs:
|
255
|
-
events:
|
256
|
+
args: tuple[Any, ...]
|
257
|
+
kwargs: dict[str, Any]
|
258
|
+
events: list[Event]
|
256
259
|
|
257
|
-
def __init__(self, *args, **kwargs):
|
260
|
+
def __init__(self, *args: Any, **kwargs: Any):
|
258
261
|
AssertingEventsClient.last = self
|
259
262
|
AssertingEventsClient.all.append(self)
|
260
263
|
self.args = args
|
@@ -431,13 +434,13 @@ class AssertingPassthroughEventsClient(PrefectEventsClient):
|
|
431
434
|
during tests AND sends them to a Prefect server."""
|
432
435
|
|
433
436
|
last: ClassVar["Optional[AssertingPassthroughEventsClient]"] = None
|
434
|
-
all: ClassVar[
|
437
|
+
all: ClassVar[list["AssertingPassthroughEventsClient"]] = []
|
435
438
|
|
436
|
-
args:
|
437
|
-
kwargs:
|
438
|
-
events:
|
439
|
+
args: tuple[Any, ...]
|
440
|
+
kwargs: dict[str, Any]
|
441
|
+
events: list[Event]
|
439
442
|
|
440
|
-
def __init__(self, *args, **kwargs):
|
443
|
+
def __init__(self, *args: Any, **kwargs: Any):
|
441
444
|
super().__init__(*args, **kwargs)
|
442
445
|
AssertingPassthroughEventsClient.last = self
|
443
446
|
AssertingPassthroughEventsClient.all.append(self)
|
@@ -449,7 +452,7 @@ class AssertingPassthroughEventsClient(PrefectEventsClient):
|
|
449
452
|
cls.last = None
|
450
453
|
cls.all = []
|
451
454
|
|
452
|
-
def pop_events(self) ->
|
455
|
+
def pop_events(self) -> list[Event]:
|
453
456
|
events = self.events
|
454
457
|
self.events = []
|
455
458
|
return events
|
@@ -52,7 +52,7 @@ class Trigger(PrefectBaseModel, abc.ABC, extra="ignore"): # type: ignore[call-a
|
|
52
52
|
|
53
53
|
_deployment_id: Optional[UUID] = PrivateAttr(default=None)
|
54
54
|
|
55
|
-
def set_deployment_id(self, deployment_id: UUID):
|
55
|
+
def set_deployment_id(self, deployment_id: UUID) -> None:
|
56
56
|
self._deployment_id = deployment_id
|
57
57
|
|
58
58
|
def owner_resource(self) -> Optional[str]:
|
@@ -277,7 +277,7 @@ class MetricTriggerQuery(PrefectBaseModel):
|
|
277
277
|
)
|
278
278
|
|
279
279
|
@field_validator("range", "firing_for")
|
280
|
-
def enforce_minimum_range(cls, value: timedelta):
|
280
|
+
def enforce_minimum_range(cls, value: timedelta) -> timedelta:
|
281
281
|
if value < timedelta(seconds=300):
|
282
282
|
raise ValueError("The minimum range is 300 seconds (5 minutes)")
|
283
283
|
return value
|
@@ -404,13 +404,17 @@ class AutomationCore(PrefectBaseModel, extra="ignore"): # type: ignore[call-arg
|
|
404
404
|
"""Defines an action a user wants to take when a certain number of events
|
405
405
|
do or don't happen to the matching resources"""
|
406
406
|
|
407
|
-
name: str = Field(
|
408
|
-
description: str = Field(
|
407
|
+
name: str = Field(default=..., description="The name of this automation")
|
408
|
+
description: str = Field(
|
409
|
+
default="", description="A longer description of this automation"
|
410
|
+
)
|
409
411
|
|
410
|
-
enabled: bool = Field(
|
412
|
+
enabled: bool = Field(
|
413
|
+
default=True, description="Whether this automation will be evaluated"
|
414
|
+
)
|
411
415
|
|
412
416
|
trigger: TriggerTypes = Field(
|
413
|
-
|
417
|
+
default=...,
|
414
418
|
description=(
|
415
419
|
"The criteria for which events this Automation covers and how it will "
|
416
420
|
"respond to the presence or absence of those events"
|
@@ -418,7 +422,7 @@ class AutomationCore(PrefectBaseModel, extra="ignore"): # type: ignore[call-arg
|
|
418
422
|
)
|
419
423
|
|
420
424
|
actions: List[ActionTypes] = Field(
|
421
|
-
|
425
|
+
default=...,
|
422
426
|
description="The actions to perform when this Automation triggers",
|
423
427
|
)
|
424
428
|
|
@@ -438,4 +442,4 @@ class AutomationCore(PrefectBaseModel, extra="ignore"): # type: ignore[call-arg
|
|
438
442
|
|
439
443
|
|
440
444
|
class Automation(AutomationCore):
|
441
|
-
id: UUID = Field(
|
445
|
+
id: UUID = Field(default=..., description="The ID of this automation")
|
prefect/events/schemas/events.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import copy
|
2
2
|
from collections import defaultdict
|
3
3
|
from typing import (
|
4
|
+
TYPE_CHECKING,
|
4
5
|
Any,
|
5
6
|
ClassVar,
|
6
7
|
Dict,
|
@@ -32,7 +33,10 @@ from prefect.types import DateTime
|
|
32
33
|
|
33
34
|
from .labelling import Labelled
|
34
35
|
|
35
|
-
|
36
|
+
if TYPE_CHECKING:
|
37
|
+
import logging
|
38
|
+
|
39
|
+
logger: "logging.Logger" = get_logger(__name__)
|
36
40
|
|
37
41
|
|
38
42
|
class Resource(Labelled):
|
prefect/events/worker.py
CHANGED
@@ -82,7 +82,7 @@ class EventsWorker(QueueService[Event]):
|
|
82
82
|
|
83
83
|
await self._client.emit(event)
|
84
84
|
|
85
|
-
async def attach_related_resources_from_context(self, event: Event):
|
85
|
+
async def attach_related_resources_from_context(self, event: Event) -> None:
|
86
86
|
if "prefect.resource.lineage-group" in event.resource:
|
87
87
|
# We attach related resources to lineage events in `emit_lineage_event`,
|
88
88
|
# instead of the worker, because not all run-related resources are
|
prefect/filesystems.py
CHANGED
@@ -281,7 +281,7 @@ class RemoteFileSystem(WritableFileSystem, WritableDeploymentStorage):
|
|
281
281
|
_filesystem: fsspec.AbstractFileSystem = None
|
282
282
|
|
283
283
|
@field_validator("basepath")
|
284
|
-
def check_basepath(cls, value):
|
284
|
+
def check_basepath(cls, value: str) -> str:
|
285
285
|
return validate_basepath(value)
|
286
286
|
|
287
287
|
def _resolve_path(self, path: str) -> str:
|
prefect/flow_engine.py
CHANGED
@@ -146,7 +146,7 @@ class BaseFlowRunEngine(Generic[P, R]):
|
|
146
146
|
_flow_run_name_set: bool = False
|
147
147
|
_telemetry: RunTelemetry = field(default_factory=RunTelemetry)
|
148
148
|
|
149
|
-
def __post_init__(self):
|
149
|
+
def __post_init__(self) -> None:
|
150
150
|
if self.flow is None and self.flow_run_id is None:
|
151
151
|
raise ValueError("Either a flow or a flow_run_id must be provided.")
|
152
152
|
|
@@ -167,7 +167,7 @@ class BaseFlowRunEngine(Generic[P, R]):
|
|
167
167
|
return False # TODO: handle this differently?
|
168
168
|
return getattr(self, "flow_run").state.is_pending()
|
169
169
|
|
170
|
-
def cancel_all_tasks(self):
|
170
|
+
def cancel_all_tasks(self) -> None:
|
171
171
|
if hasattr(self.flow.task_runner, "cancel_all"):
|
172
172
|
self.flow.task_runner.cancel_all() # type: ignore
|
173
173
|
|
@@ -208,6 +208,8 @@ class BaseFlowRunEngine(Generic[P, R]):
|
|
208
208
|
@dataclass
|
209
209
|
class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
210
210
|
_client: Optional[SyncPrefectClient] = None
|
211
|
+
flow_run: FlowRun | None = None
|
212
|
+
parameters: dict[str, Any] | None = None
|
211
213
|
|
212
214
|
@property
|
213
215
|
def client(self) -> SyncPrefectClient:
|
@@ -502,7 +504,7 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
502
504
|
tags=TagsContext.get().current_tags,
|
503
505
|
)
|
504
506
|
|
505
|
-
def call_hooks(self, state: Optional[State] = None):
|
507
|
+
def call_hooks(self, state: Optional[State] = None) -> None:
|
506
508
|
if state is None:
|
507
509
|
state = self.state
|
508
510
|
flow = self.flow
|
@@ -600,7 +602,9 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
600
602
|
|
601
603
|
# set the logger to the flow run logger
|
602
604
|
|
603
|
-
self.logger = flow_run_logger(
|
605
|
+
self.logger: "logging.Logger" = flow_run_logger(
|
606
|
+
flow_run=self.flow_run, flow=self.flow
|
607
|
+
) # type: ignore
|
604
608
|
|
605
609
|
# update the flow run name if necessary
|
606
610
|
if not self._flow_run_name_set and self.flow.flow_run_name:
|
@@ -768,6 +772,8 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
768
772
|
"""
|
769
773
|
|
770
774
|
_client: Optional[PrefectClient] = None
|
775
|
+
parameters: dict[str, Any] | None = None
|
776
|
+
flow_run: FlowRun | None = None
|
771
777
|
|
772
778
|
@property
|
773
779
|
def client(self) -> PrefectClient:
|
@@ -1061,7 +1067,7 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
1061
1067
|
tags=TagsContext.get().current_tags,
|
1062
1068
|
)
|
1063
1069
|
|
1064
|
-
async def call_hooks(self, state: Optional[State] = None):
|
1070
|
+
async def call_hooks(self, state: Optional[State] = None) -> None:
|
1065
1071
|
if state is None:
|
1066
1072
|
state = self.state
|
1067
1073
|
flow = self.flow
|
@@ -1158,7 +1164,9 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
1158
1164
|
stack.enter_context(ConcurrencyContext())
|
1159
1165
|
|
1160
1166
|
# set the logger to the flow run logger
|
1161
|
-
self.logger = flow_run_logger(
|
1167
|
+
self.logger: "logging.Logger" = flow_run_logger(
|
1168
|
+
flow_run=self.flow_run, flow=self.flow
|
1169
|
+
)
|
1162
1170
|
|
1163
1171
|
# update the flow run name if necessary
|
1164
1172
|
|
@@ -1320,7 +1328,7 @@ def run_flow_sync(
|
|
1320
1328
|
flow: Flow[P, R],
|
1321
1329
|
flow_run: Optional[FlowRun] = None,
|
1322
1330
|
parameters: Optional[Dict[str, Any]] = None,
|
1323
|
-
wait_for: Optional[Iterable[PrefectFuture]] = None,
|
1331
|
+
wait_for: Optional[Iterable[PrefectFuture[Any]]] = None,
|
1324
1332
|
return_type: Literal["state", "result"] = "result",
|
1325
1333
|
) -> Union[R, State, None]:
|
1326
1334
|
engine = FlowRunEngine[P, R](
|
@@ -1342,7 +1350,7 @@ async def run_flow_async(
|
|
1342
1350
|
flow: Flow[P, R],
|
1343
1351
|
flow_run: Optional[FlowRun] = None,
|
1344
1352
|
parameters: Optional[Dict[str, Any]] = None,
|
1345
|
-
wait_for: Optional[Iterable[PrefectFuture]] = None,
|
1353
|
+
wait_for: Optional[Iterable[PrefectFuture[Any]]] = None,
|
1346
1354
|
return_type: Literal["state", "result"] = "result",
|
1347
1355
|
) -> Union[R, State, None]:
|
1348
1356
|
engine = AsyncFlowRunEngine[P, R](
|
@@ -1361,7 +1369,7 @@ def run_generator_flow_sync(
|
|
1361
1369
|
flow: Flow[P, R],
|
1362
1370
|
flow_run: Optional[FlowRun] = None,
|
1363
1371
|
parameters: Optional[Dict[str, Any]] = None,
|
1364
|
-
wait_for: Optional[Iterable[PrefectFuture]] = None,
|
1372
|
+
wait_for: Optional[Iterable[PrefectFuture[Any]]] = None,
|
1365
1373
|
return_type: Literal["state", "result"] = "result",
|
1366
1374
|
) -> Generator[R, None, None]:
|
1367
1375
|
if return_type != "result":
|