prefect-client 3.0.0rc19__py3-none-any.whl → 3.0.0rc20__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 CHANGED
@@ -31,7 +31,6 @@ if TYPE_CHECKING:
31
31
  Flow,
32
32
  get_client,
33
33
  get_run_logger,
34
- Manifest,
35
34
  State,
36
35
  tags,
37
36
  task,
@@ -60,7 +59,6 @@ _public_api: dict[str, tuple[str, str]] = {
60
59
  "Flow": (__spec__.parent, ".main"),
61
60
  "get_client": (__spec__.parent, ".main"),
62
61
  "get_run_logger": (__spec__.parent, ".main"),
63
- "Manifest": (__spec__.parent, ".main"),
64
62
  "State": (__spec__.parent, ".main"),
65
63
  "tags": (__spec__.parent, ".main"),
66
64
  "task": (__spec__.parent, ".main"),
@@ -81,7 +79,6 @@ __all__ = [
81
79
  "Flow",
82
80
  "get_client",
83
81
  "get_run_logger",
84
- "Manifest",
85
82
  "State",
86
83
  "tags",
87
84
  "task",
prefect/blocks/core.py CHANGED
@@ -150,7 +150,11 @@ def _collect_secret_fields(
150
150
  _collect_secret_fields(f"{name}.{field_name}", field.annotation, secrets)
151
151
  return
152
152
 
153
- if type_ in (SecretStr, SecretBytes):
153
+ if type_ in (SecretStr, SecretBytes) or (
154
+ isinstance(type_, type)
155
+ and getattr(type_, "__module__", None) == "pydantic.types"
156
+ and getattr(type_, "__name__", None) == "Secret"
157
+ ):
154
158
  secrets.append(name)
155
159
  elif type_ == SecretDict:
156
160
  # Append .* to field name to signify that all values under this
prefect/blocks/system.py CHANGED
@@ -1,11 +1,26 @@
1
- from typing import Any
2
-
3
- from pydantic import Field, SecretStr
4
- from pydantic_extra_types.pendulum_dt import DateTime
1
+ import json
2
+ from typing import Annotated, Any, Generic, TypeVar, Union
3
+
4
+ from pydantic import (
5
+ Field,
6
+ JsonValue,
7
+ SecretStr,
8
+ StrictStr,
9
+ field_validator,
10
+ )
11
+ from pydantic import Secret as PydanticSecret
12
+ from pydantic_extra_types.pendulum_dt import DateTime as PydanticDateTime
5
13
 
6
14
  from prefect._internal.compatibility.deprecated import deprecated_class
7
15
  from prefect.blocks.core import Block
8
16
 
17
+ _SecretValueType = Union[
18
+ Annotated[StrictStr, Field(title="string")],
19
+ Annotated[JsonValue, Field(title="JSON")],
20
+ ]
21
+
22
+ T = TypeVar("T", bound=_SecretValueType)
23
+
9
24
 
10
25
  @deprecated_class(
11
26
  start_date="Jun 2024",
@@ -86,24 +101,26 @@ class DateTime(Block):
86
101
  _logo_url = "https://cdn.sanity.io/images/3ugk85nk/production/8b3da9a6621e92108b8e6a75b82e15374e170ff7-48x48.png"
87
102
  _documentation_url = "https://docs.prefect.io/api-ref/prefect/blocks/system/#prefect.blocks.system.DateTime"
88
103
 
89
- value: DateTime = Field(
104
+ value: PydanticDateTime = Field(
90
105
  default=...,
91
106
  description="An ISO 8601-compatible datetime value.",
92
107
  )
93
108
 
94
109
 
95
- class Secret(Block):
110
+ class Secret(Block, Generic[T]):
96
111
  """
97
112
  A block that represents a secret value. The value stored in this block will be obfuscated when
98
- this block is logged or shown in the UI.
113
+ this block is viewed or edited in the UI.
99
114
 
100
115
  Attributes:
101
- value: A string value that should be kept secret.
116
+ value: A value that should be kept secret.
102
117
 
103
118
  Example:
104
119
  ```python
105
120
  from prefect.blocks.system import Secret
106
121
 
122
+ Secret(value="sk-1234567890").save("BLOCK_NAME", overwrite=True)
123
+
107
124
  secret_block = Secret.load("BLOCK_NAME")
108
125
 
109
126
  # Access the stored secret
@@ -114,9 +131,28 @@ class Secret(Block):
114
131
  _logo_url = "https://cdn.sanity.io/images/3ugk85nk/production/c6f20e556dd16effda9df16551feecfb5822092b-48x48.png"
115
132
  _documentation_url = "https://docs.prefect.io/api-ref/prefect/blocks/system/#prefect.blocks.system.Secret"
116
133
 
117
- value: SecretStr = Field(
118
- default=..., description="A string value that should be kept secret."
134
+ value: Union[SecretStr, PydanticSecret[T]] = Field(
135
+ default=...,
136
+ description="A value that should be kept secret.",
137
+ examples=["sk-1234567890", {"username": "johndoe", "password": "s3cr3t"}],
138
+ json_schema_extra={
139
+ "writeOnly": True,
140
+ "format": "password",
141
+ },
119
142
  )
120
143
 
121
- def get(self):
122
- return self.value.get_secret_value()
144
+ @field_validator("value", mode="before")
145
+ def validate_value(
146
+ cls, value: Union[T, SecretStr, PydanticSecret[T]]
147
+ ) -> Union[SecretStr, PydanticSecret[T]]:
148
+ if isinstance(value, (PydanticSecret, SecretStr)):
149
+ return value
150
+ else:
151
+ return PydanticSecret[type(value)](value)
152
+
153
+ def get(self) -> T:
154
+ try:
155
+ value = self.value.get_secret_value()
156
+ return json.loads(value)
157
+ except (TypeError, json.JSONDecodeError):
158
+ return value
prefect/client/cloud.py CHANGED
@@ -1,5 +1,5 @@
1
1
  import re
2
- from typing import Any, Dict, List, Optional
2
+ from typing import Any, Dict, List, Optional, cast
3
3
 
4
4
  import anyio
5
5
  import httpx
@@ -9,7 +9,11 @@ from starlette import status
9
9
  import prefect.context
10
10
  import prefect.settings
11
11
  from prefect.client.base import PrefectHttpxAsyncClient
12
- from prefect.client.schemas.objects import Workspace
12
+ from prefect.client.schemas.objects import (
13
+ IPAllowlist,
14
+ IPAllowlistMyAccessResponse,
15
+ Workspace,
16
+ )
13
17
  from prefect.exceptions import ObjectNotFound, PrefectException
14
18
  from prefect.settings import (
15
19
  PREFECT_API_KEY,
@@ -69,6 +73,26 @@ class CloudClient:
69
73
  **httpx_settings, enable_csrf_support=False
70
74
  )
71
75
 
76
+ if match := (
77
+ re.search(PARSE_API_URL_REGEX, host)
78
+ or re.search(PARSE_API_URL_REGEX, prefect.settings.PREFECT_API_URL.value())
79
+ ):
80
+ self.account_id, self.workspace_id = match.groups()
81
+
82
+ @property
83
+ def account_base_url(self) -> str:
84
+ if not self.account_id:
85
+ raise ValueError("Account ID not set")
86
+
87
+ return f"accounts/{self.account_id}"
88
+
89
+ @property
90
+ def workspace_base_url(self) -> str:
91
+ if not self.workspace_id:
92
+ raise ValueError("Workspace ID not set")
93
+
94
+ return f"{self.account_base_url}/workspaces/{self.workspace_id}"
95
+
72
96
  async def api_healthcheck(self):
73
97
  """
74
98
  Attempts to connect to the Cloud API and raises the encountered exception if not
@@ -86,11 +110,36 @@ class CloudClient:
86
110
  return workspaces
87
111
 
88
112
  async def read_worker_metadata(self) -> Dict[str, Any]:
89
- configured_url = prefect.settings.PREFECT_API_URL.value()
90
- account_id, workspace_id = re.findall(PARSE_API_URL_REGEX, configured_url)[0]
91
- return await self.get(
92
- f"accounts/{account_id}/workspaces/{workspace_id}/collections/work_pool_types"
113
+ response = await self.get(
114
+ f"{self.workspace_base_url}/collections/work_pool_types"
93
115
  )
116
+ return cast(Dict[str, Any], response)
117
+
118
+ async def read_account_settings(self) -> Dict[str, Any]:
119
+ response = await self.get(f"{self.account_base_url}/settings")
120
+ return cast(Dict[str, Any], response)
121
+
122
+ async def update_account_settings(self, settings: Dict[str, Any]):
123
+ await self.request(
124
+ "PATCH",
125
+ f"{self.account_base_url}/settings",
126
+ json=settings,
127
+ )
128
+
129
+ async def read_account_ip_allowlist(self) -> IPAllowlist:
130
+ response = await self.get(f"{self.account_base_url}/ip_allowlist")
131
+ return IPAllowlist.model_validate(response)
132
+
133
+ async def update_account_ip_allowlist(self, updated_allowlist: IPAllowlist):
134
+ await self.request(
135
+ "PUT",
136
+ f"{self.account_base_url}/ip_allowlist",
137
+ json=updated_allowlist.model_dump(mode="json"),
138
+ )
139
+
140
+ async def check_ip_allowlist_access(self) -> IPAllowlistMyAccessResponse:
141
+ response = await self.get(f"{self.account_base_url}/ip_allowlist/my_access")
142
+ return IPAllowlistMyAccessResponse.model_validate(response)
94
143
 
95
144
  async def __aenter__(self):
96
145
  await self._client.__aenter__()
@@ -120,7 +169,7 @@ class CloudClient:
120
169
  status.HTTP_401_UNAUTHORIZED,
121
170
  status.HTTP_403_FORBIDDEN,
122
171
  ):
123
- raise CloudUnauthorizedError
172
+ raise CloudUnauthorizedError(str(exc)) from exc
124
173
  elif exc.response.status_code == status.HTTP_404_NOT_FOUND:
125
174
  raise ObjectNotFound(http_exc=exc) from exc
126
175
  else:
@@ -29,6 +29,6 @@ def get_collections_metadata_client(
29
29
  """
30
30
  orchestration_client = get_client(httpx_settings=httpx_settings)
31
31
  if orchestration_client.server_type == ServerType.CLOUD:
32
- return get_cloud_client(httpx_settings=httpx_settings)
32
+ return get_cloud_client(httpx_settings=httpx_settings, infer_cloud_url=True)
33
33
  else:
34
34
  return orchestration_client
@@ -1324,15 +1324,17 @@ class PrefectClient:
1324
1324
  `SecretBytes` fields. Note Blocks may not work as expected if
1325
1325
  this is set to `False`.
1326
1326
  """
1327
+ block_document_data = block_document.model_dump(
1328
+ mode="json",
1329
+ exclude_unset=True,
1330
+ exclude={"id", "block_schema", "block_type"},
1331
+ context={"include_secrets": include_secrets},
1332
+ serialize_as_any=True,
1333
+ )
1327
1334
  try:
1328
1335
  response = await self._client.post(
1329
1336
  "/block_documents/",
1330
- json=block_document.model_dump(
1331
- mode="json",
1332
- exclude_unset=True,
1333
- exclude={"id", "block_schema", "block_type"},
1334
- context={"include_secrets": include_secrets},
1335
- ),
1337
+ json=block_document_data,
1336
1338
  )
1337
1339
  except httpx.HTTPStatusError as e:
1338
1340
  if e.response.status_code == status.HTTP_409_CONFLICT:
@@ -1786,6 +1788,12 @@ class PrefectClient:
1786
1788
  Returns:
1787
1789
  a [Deployment model][prefect.client.schemas.objects.Deployment] representation of the deployment
1788
1790
  """
1791
+ if not isinstance(deployment_id, UUID):
1792
+ try:
1793
+ deployment_id = UUID(deployment_id)
1794
+ except ValueError:
1795
+ raise ValueError(f"Invalid deployment ID: {deployment_id}")
1796
+
1789
1797
  try:
1790
1798
  response = await self._client.get(f"/deployments/{deployment_id}")
1791
1799
  except httpx.HTTPStatusError as e:
@@ -19,11 +19,13 @@ from pydantic import (
19
19
  ConfigDict,
20
20
  Field,
21
21
  HttpUrl,
22
+ IPvAnyNetwork,
22
23
  SerializationInfo,
23
24
  field_validator,
24
25
  model_serializer,
25
26
  model_validator,
26
27
  )
28
+ from pydantic.functional_validators import ModelWrapValidatorHandler
27
29
  from pydantic_extra_types.pendulum_dt import DateTime
28
30
  from typing_extensions import Literal, Self, TypeVar
29
31
 
@@ -276,11 +278,16 @@ class State(ObjectBaseModel, Generic[R]):
276
278
  from prefect.client.schemas.actions import StateCreate
277
279
  from prefect.results import BaseResult
278
280
 
281
+ if isinstance(self.data, BaseResult) and self.data.serialize_to_none is False:
282
+ data = self.data
283
+ else:
284
+ data = None
285
+
279
286
  return StateCreate(
280
287
  type=self.type,
281
288
  name=self.name,
282
289
  message=self.message,
283
- data=self.data if isinstance(self.data, BaseResult) else None,
290
+ data=data,
284
291
  state_details=self.state_details,
285
292
  )
286
293
 
@@ -848,6 +855,35 @@ class Workspace(PrefectBaseModel):
848
855
  return hash(self.handle)
849
856
 
850
857
 
858
+ class IPAllowlistEntry(PrefectBaseModel):
859
+ ip_network: IPvAnyNetwork
860
+ enabled: bool
861
+ description: Optional[str] = Field(
862
+ default=None, description="A description of the IP entry."
863
+ )
864
+ last_seen: Optional[str] = Field(
865
+ default=None,
866
+ description="The last time this IP was seen accessing Prefect Cloud.",
867
+ )
868
+
869
+
870
+ class IPAllowlist(PrefectBaseModel):
871
+ """
872
+ A Prefect Cloud IP allowlist.
873
+
874
+ Expected payload for an IP allowlist from the Prefect Cloud API.
875
+ """
876
+
877
+ entries: List[IPAllowlistEntry]
878
+
879
+
880
+ class IPAllowlistMyAccessResponse(PrefectBaseModel):
881
+ """Expected payload for an IP allowlist access response from the Prefect Cloud API."""
882
+
883
+ allowed: bool
884
+ detail: str
885
+
886
+
851
887
  class BlockType(ObjectBaseModel):
852
888
  """An ORM representation of a block type"""
853
889
 
@@ -933,7 +969,9 @@ class BlockDocument(ObjectBaseModel):
933
969
  return validate_name_present_on_nonanonymous_blocks(values)
934
970
 
935
971
  @model_serializer(mode="wrap")
936
- def serialize_data(self, handler, info: SerializationInfo):
972
+ def serialize_data(
973
+ self, handler: ModelWrapValidatorHandler, info: SerializationInfo
974
+ ):
937
975
  self.data = visit_collection(
938
976
  self.data,
939
977
  visit_fn=partial(handle_secret_render, context=info.context or {}),
@@ -36,7 +36,8 @@ async def concurrency(
36
36
  names: Union[str, List[str]],
37
37
  occupy: int = 1,
38
38
  timeout_seconds: Optional[float] = None,
39
- create_if_missing: Optional[bool] = True,
39
+ create_if_missing: bool = True,
40
+ max_retries: Optional[int] = None,
40
41
  ) -> AsyncGenerator[None, None]:
41
42
  """A context manager that acquires and releases concurrency slots from the
42
43
  given concurrency limits.
@@ -47,6 +48,7 @@ async def concurrency(
47
48
  timeout_seconds: The number of seconds to wait for the slots to be acquired before
48
49
  raising a `TimeoutError`. A timeout of `None` will wait indefinitely.
49
50
  create_if_missing: Whether to create the concurrency limits if they do not exist.
51
+ max_retries: The maximum number of retries to acquire the concurrency slots.
50
52
 
51
53
  Raises:
52
54
  TimeoutError: If the slots are not acquired within the given timeout.
@@ -75,6 +77,7 @@ async def concurrency(
75
77
  occupy,
76
78
  timeout_seconds=timeout_seconds,
77
79
  create_if_missing=create_if_missing,
80
+ max_retries=max_retries,
78
81
  )
79
82
  acquisition_time = pendulum.now("UTC")
80
83
  emitted_events = _emit_concurrency_acquisition_events(limits, occupy)
@@ -137,9 +140,12 @@ async def _acquire_concurrency_slots(
137
140
  mode: Union[Literal["concurrency"], Literal["rate_limit"]] = "concurrency",
138
141
  timeout_seconds: Optional[float] = None,
139
142
  create_if_missing: Optional[bool] = True,
143
+ max_retries: Optional[int] = None,
140
144
  ) -> List[MinimalConcurrencyLimitResponse]:
141
145
  service = ConcurrencySlotAcquisitionService.instance(frozenset(names))
142
- future = service.send((slots, mode, timeout_seconds, create_if_missing))
146
+ future = service.send(
147
+ (slots, mode, timeout_seconds, create_if_missing, max_retries)
148
+ )
143
149
  response_or_exception = await asyncio.wrap_future(future)
144
150
 
145
151
  if isinstance(response_or_exception, Exception):
@@ -36,13 +36,18 @@ class ConcurrencySlotAcquisitionService(QueueService):
36
36
  async def _handle(
37
37
  self,
38
38
  item: Tuple[
39
- int, str, Optional[float], concurrent.futures.Future, Optional[bool]
39
+ int,
40
+ str,
41
+ Optional[float],
42
+ concurrent.futures.Future,
43
+ Optional[bool],
44
+ Optional[int],
40
45
  ],
41
46
  ) -> None:
42
- occupy, mode, timeout_seconds, future, create_if_missing = item
47
+ occupy, mode, timeout_seconds, future, create_if_missing, max_retries = item
43
48
  try:
44
49
  response = await self.acquire_slots(
45
- occupy, mode, timeout_seconds, create_if_missing
50
+ occupy, mode, timeout_seconds, create_if_missing, max_retries
46
51
  )
47
52
  except Exception as exc:
48
53
  # If the request to the increment endpoint fails in a non-standard
@@ -59,6 +64,7 @@ class ConcurrencySlotAcquisitionService(QueueService):
59
64
  mode: str,
60
65
  timeout_seconds: Optional[float] = None,
61
66
  create_if_missing: Optional[bool] = False,
67
+ max_retries: Optional[int] = None,
62
68
  ) -> httpx.Response:
63
69
  with timeout_async(seconds=timeout_seconds):
64
70
  while True:
@@ -74,15 +80,19 @@ class ConcurrencySlotAcquisitionService(QueueService):
74
80
  isinstance(exc, httpx.HTTPStatusError)
75
81
  and exc.response.status_code == status.HTTP_423_LOCKED
76
82
  ):
83
+ if max_retries is not None and max_retries <= 0:
84
+ raise exc
77
85
  retry_after = float(exc.response.headers["Retry-After"])
78
86
  await asyncio.sleep(retry_after)
87
+ if max_retries is not None:
88
+ max_retries -= 1
79
89
  else:
80
90
  raise exc
81
91
  else:
82
92
  return response
83
93
 
84
94
  def send(
85
- self, item: Tuple[int, str, Optional[float], Optional[bool]]
95
+ self, item: Tuple[int, str, Optional[float], Optional[bool], Optional[int]]
86
96
  ) -> concurrent.futures.Future:
87
97
  with self._lock:
88
98
  if self._stopped:
@@ -91,9 +101,9 @@ class ConcurrencySlotAcquisitionService(QueueService):
91
101
  logger.debug("Service %r enqueuing item %r", self, item)
92
102
  future: concurrent.futures.Future = concurrent.futures.Future()
93
103
 
94
- occupy, mode, timeout_seconds, create_if_missing = item
104
+ occupy, mode, timeout_seconds, create_if_missing, max_retries = item
95
105
  self._queue.put_nowait(
96
- (occupy, mode, timeout_seconds, future, create_if_missing)
106
+ (occupy, mode, timeout_seconds, future, create_if_missing, max_retries)
97
107
  )
98
108
 
99
109
  return future
@@ -40,7 +40,8 @@ def concurrency(
40
40
  names: Union[str, List[str]],
41
41
  occupy: int = 1,
42
42
  timeout_seconds: Optional[float] = None,
43
- create_if_missing: Optional[bool] = True,
43
+ create_if_missing: bool = True,
44
+ max_retries: Optional[int] = None,
44
45
  ) -> Generator[None, None, None]:
45
46
  """A context manager that acquires and releases concurrency slots from the
46
47
  given concurrency limits.
@@ -51,6 +52,7 @@ def concurrency(
51
52
  timeout_seconds: The number of seconds to wait for the slots to be acquired before
52
53
  raising a `TimeoutError`. A timeout of `None` will wait indefinitely.
53
54
  create_if_missing: Whether to create the concurrency limits if they do not exist.
55
+ max_retries: The maximum number of retries to acquire the concurrency slots.
54
56
 
55
57
  Raises:
56
58
  TimeoutError: If the slots are not acquired within the given timeout.
@@ -80,6 +82,7 @@ def concurrency(
80
82
  occupy,
81
83
  timeout_seconds=timeout_seconds,
82
84
  create_if_missing=create_if_missing,
85
+ max_retries=max_retries,
83
86
  )
84
87
  acquisition_time = pendulum.now("UTC")
85
88
  emitted_events = _emit_concurrency_acquisition_events(limits, occupy)
prefect/exceptions.py CHANGED
@@ -412,3 +412,9 @@ class PrefectImportError(ImportError):
412
412
 
413
413
  def __init__(self, message: str) -> None:
414
414
  super().__init__(message)
415
+
416
+
417
+ class SerializationError(PrefectException):
418
+ """
419
+ Raised when an object cannot be serialized.
420
+ """
prefect/flow_engine.py CHANGED
@@ -205,6 +205,7 @@ class FlowRunEngine(Generic[P, R]):
205
205
  result_factory=run_coro_as_sync(ResultFactory.from_flow(self.flow)),
206
206
  )
207
207
  self.short_circuit = True
208
+ self.call_hooks()
208
209
 
209
210
  new_state = Running()
210
211
  state = self.set_state(new_state)
@@ -268,6 +269,7 @@ class FlowRunEngine(Generic[P, R]):
268
269
  return_value_to_state(
269
270
  resolved_result,
270
271
  result_factory=result_factory,
272
+ write_result=True,
271
273
  )
272
274
  )
273
275
  self.set_state(terminal_state)
@@ -287,6 +289,7 @@ class FlowRunEngine(Generic[P, R]):
287
289
  message=msg or "Flow run encountered an exception:",
288
290
  result_factory=result_factory
289
291
  or getattr(context, "result_factory", None),
292
+ write_result=True,
290
293
  )
291
294
  )
292
295
  state = self.set_state(terminal_state)
prefect/flows.py CHANGED
@@ -642,7 +642,7 @@ class Flow(Generic[P, R]):
642
642
  cron: Optional[Union[Iterable[str], str]] = None,
643
643
  rrule: Optional[Union[Iterable[str], str]] = None,
644
644
  paused: Optional[bool] = None,
645
- schedules: Optional[List["FlexibleScheduleList"]] = None,
645
+ schedules: Optional["FlexibleScheduleList"] = None,
646
646
  concurrency_limit: Optional[int] = None,
647
647
  parameters: Optional[dict] = None,
648
648
  triggers: Optional[List[Union[DeploymentTriggerTypes, TriggerTypes]]] = None,
@@ -730,7 +730,7 @@ class Flow(Generic[P, R]):
730
730
  work_pool_name=work_pool_name,
731
731
  work_queue_name=work_queue_name,
732
732
  job_variables=job_variables,
733
- )
733
+ ) # type: ignore # TODO: remove sync_compatible
734
734
  else:
735
735
  return RunnerDeployment.from_flow(
736
736
  self,
@@ -157,7 +157,10 @@ class APILogHandler(logging.Handler):
157
157
  if log_handling_when_missing_flow == "warn":
158
158
  # Warn when a logger is used outside of a run context, the stack level here
159
159
  # gets us to the user logging call
160
- warnings.warn(str(exc), stacklevel=8)
160
+ warnings.warn(
161
+ f"{exc} Set PREFECT_LOGGING_TO_API_WHEN_MISSING_FLOW=ignore to suppress this warning.",
162
+ stacklevel=8,
163
+ )
161
164
  return
162
165
  elif log_handling_when_missing_flow == "ignore":
163
166
  return
prefect/main.py CHANGED
@@ -6,7 +6,6 @@ from prefect.flows import flow, Flow, serve
6
6
  from prefect.transactions import Transaction
7
7
  from prefect.tasks import task, Task
8
8
  from prefect.context import tags
9
- from prefect.manifests import Manifest
10
9
  from prefect.utilities.annotations import unmapped, allow_failure
11
10
  from prefect.results import BaseResult
12
11
  from prefect.flow_runs import pause_flow_run, resume_flow_run, suspend_flow_run
@@ -26,10 +25,14 @@ import prefect.context
26
25
  # Perform any forward-ref updates needed for Pydantic models
27
26
  import prefect.client.schemas
28
27
 
29
- prefect.context.FlowRunContext.model_rebuild()
30
- prefect.context.TaskRunContext.model_rebuild()
31
- prefect.client.schemas.State.model_rebuild()
32
- prefect.client.schemas.StateCreate.model_rebuild()
28
+ prefect.context.FlowRunContext.model_rebuild(
29
+ _types_namespace={"Flow": Flow, "BaseResult": BaseResult}
30
+ )
31
+ prefect.context.TaskRunContext.model_rebuild(_types_namespace={"Task": Task})
32
+ prefect.client.schemas.State.model_rebuild(_types_namespace={"BaseResult": BaseResult})
33
+ prefect.client.schemas.StateCreate.model_rebuild(
34
+ _types_namespace={"BaseResult": BaseResult}
35
+ )
33
36
  Transaction.model_rebuild()
34
37
 
35
38
  # Configure logging
@@ -55,7 +58,6 @@ __all__ = [
55
58
  "Flow",
56
59
  "get_client",
57
60
  "get_run_logger",
58
- "Manifest",
59
61
  "State",
60
62
  "tags",
61
63
  "task",