Skip to content

prefect.server.schemas.states

State schemas.

State

Bases: StateBaseModel

Represents the state of a run.

Source code in src/prefect/server/schemas/states.py
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
class State(StateBaseModel):
    """Represents the state of a run."""

    model_config = ConfigDict(from_attributes=True)

    type: StateType
    name: Optional[str] = Field(default=None)
    timestamp: DateTime = Field(default_factory=lambda: pendulum.now("UTC"))
    message: Optional[str] = Field(default=None, examples=["Run started"])
    data: Optional[Any] = Field(
        default=None,
        description=(
            "Data associated with the state, e.g. a result. "
            "Content must be storable as JSON."
        ),
    )
    state_details: StateDetails = Field(default_factory=StateDetails)

    @classmethod
    def from_orm_without_result(
        cls,
        orm_state: Union["ORMFlowRunState", "ORMTaskRunState"],
        with_data: Optional[Any] = None,
    ):
        """
        During orchestration, ORM states can be instantiated prior to inserting results
        into the artifact table and the `data` field will not be eagerly loaded. In
        these cases, sqlalchemy will attempt to lazily load the the relationship, which
        will fail when called within a synchronous pydantic method.

        This method will construct a `State` object from an ORM model without a loaded
        artifact and attach data passed using the `with_data` argument to the `data`
        field.
        """

        field_keys = cls.model_json_schema()["properties"].keys()
        state_data = {
            field: getattr(orm_state, field, None)
            for field in field_keys
            if field != "data"
        }
        state_data["data"] = with_data
        return cls(**state_data)

    @model_validator(mode="after")
    def default_name_from_type(self):
        """If a name is not provided, use the type"""
        # if `type` is not in `values` it means the `type` didn't pass its own
        # validation check and an error will be raised after this function is called
        name = self.name
        if name is None and self.type:
            self.name = " ".join([v.capitalize() for v in self.type.value.split("_")])
        return self

    @model_validator(mode="after")
    def default_scheduled_start_time(self):
        from prefect.server.schemas.states import StateType

        if self.type == StateType.SCHEDULED:
            if not self.state_details.scheduled_time:
                self.state_details.scheduled_time = pendulum.now("utc")

        return self

    def is_scheduled(self) -> bool:
        return self.type == StateType.SCHEDULED

    def is_pending(self) -> bool:
        return self.type == StateType.PENDING

    def is_running(self) -> bool:
        return self.type == StateType.RUNNING

    def is_completed(self) -> bool:
        return self.type == StateType.COMPLETED

    def is_failed(self) -> bool:
        return self.type == StateType.FAILED

    def is_crashed(self) -> bool:
        return self.type == StateType.CRASHED

    def is_cancelled(self) -> bool:
        return self.type == StateType.CANCELLED

    def is_cancelling(self) -> bool:
        return self.type == StateType.CANCELLING

    def is_final(self) -> bool:
        return self.type in TERMINAL_STATES

    def is_paused(self) -> bool:
        return self.type == StateType.PAUSED

    def fresh_copy(self, **kwargs) -> Self:
        """
        Return a fresh copy of the state with a new ID.
        """
        return self.model_copy(
            update={
                "id": uuid4(),
                "created": pendulum.now("utc"),
                "updated": pendulum.now("utc"),
                "timestamp": pendulum.now("utc"),
            },
            deep=True,
            **kwargs,
        )

    def result(self, raise_on_failure: bool = True, fetch: Optional[bool] = None):
        # Backwards compatible `result` handling on the server-side schema
        from prefect.states import State

        warnings.warn(
            (
                "`result` is no longer supported by"
                " `prefect.server.schemas.states.State` and will be removed in a future"
                " release. When result retrieval is needed, use `prefect.states.State`."
            ),
            DeprecationWarning,
            stacklevel=2,
        )

        state = State.model_validate(self)
        return state.result(raise_on_failure=raise_on_failure, fetch=fetch)

    def to_state_create(self) -> "StateCreate":
        from prefect.server.schemas.actions import StateCreate

        return StateCreate(
            type=self.type,
            name=self.name,
            message=self.message,
            data=self.data,
            state_details=self.state_details,
        )

    def __repr__(self) -> str:
        """
        Generates a complete state representation appropriate for introspection
        and debugging, including the result:

        `MyCompletedState(message="my message", type=COMPLETED, result=...)`
        """
        result = self.data

        display = dict(
            message=repr(self.message),
            type=str(self.type.value),
            result=repr(result),
        )

        return f"{self.name}({', '.join(f'{k}={v}' for k, v in display.items())})"

    def __str__(self) -> str:
        """
        Generates a simple state representation appropriate for logging:

        `MyCompletedState("my message", type=COMPLETED)`
        """

        display = []

        if self.message:
            display.append(repr(self.message))

        if self.type.value.lower() != self.name.lower():
            display.append(f"type={self.type.value}")

        return f"{self.name}({', '.join(display)})"

    def __hash__(self) -> int:
        return hash(
            (
                getattr(self.state_details, "flow_run_id", None),
                getattr(self.state_details, "task_run_id", None),
                self.timestamp,
                self.type,
            )
        )

__repr__()

Generates a complete state representation appropriate for introspection and debugging, including the result:

MyCompletedState(message="my message", type=COMPLETED, result=...)

Source code in src/prefect/server/schemas/states.py
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
def __repr__(self) -> str:
    """
    Generates a complete state representation appropriate for introspection
    and debugging, including the result:

    `MyCompletedState(message="my message", type=COMPLETED, result=...)`
    """
    result = self.data

    display = dict(
        message=repr(self.message),
        type=str(self.type.value),
        result=repr(result),
    )

    return f"{self.name}({', '.join(f'{k}={v}' for k, v in display.items())})"

__str__()

Generates a simple state representation appropriate for logging:

MyCompletedState("my message", type=COMPLETED)

Source code in src/prefect/server/schemas/states.py
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
def __str__(self) -> str:
    """
    Generates a simple state representation appropriate for logging:

    `MyCompletedState("my message", type=COMPLETED)`
    """

    display = []

    if self.message:
        display.append(repr(self.message))

    if self.type.value.lower() != self.name.lower():
        display.append(f"type={self.type.value}")

    return f"{self.name}({', '.join(display)})"

default_name_from_type()

If a name is not provided, use the type

Source code in src/prefect/server/schemas/states.py
151
152
153
154
155
156
157
158
159
@model_validator(mode="after")
def default_name_from_type(self):
    """If a name is not provided, use the type"""
    # if `type` is not in `values` it means the `type` didn't pass its own
    # validation check and an error will be raised after this function is called
    name = self.name
    if name is None and self.type:
        self.name = " ".join([v.capitalize() for v in self.type.value.split("_")])
    return self

fresh_copy(**kwargs)

Return a fresh copy of the state with a new ID.

Source code in src/prefect/server/schemas/states.py
201
202
203
204
205
206
207
208
209
210
211
212
213
214
def fresh_copy(self, **kwargs) -> Self:
    """
    Return a fresh copy of the state with a new ID.
    """
    return self.model_copy(
        update={
            "id": uuid4(),
            "created": pendulum.now("utc"),
            "updated": pendulum.now("utc"),
            "timestamp": pendulum.now("utc"),
        },
        deep=True,
        **kwargs,
    )

from_orm_without_result(orm_state, with_data=None) classmethod

During orchestration, ORM states can be instantiated prior to inserting results into the artifact table and the data field will not be eagerly loaded. In these cases, sqlalchemy will attempt to lazily load the the relationship, which will fail when called within a synchronous pydantic method.

This method will construct a State object from an ORM model without a loaded artifact and attach data passed using the with_data argument to the data field.

Source code in src/prefect/server/schemas/states.py
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
@classmethod
def from_orm_without_result(
    cls,
    orm_state: Union["ORMFlowRunState", "ORMTaskRunState"],
    with_data: Optional[Any] = None,
):
    """
    During orchestration, ORM states can be instantiated prior to inserting results
    into the artifact table and the `data` field will not be eagerly loaded. In
    these cases, sqlalchemy will attempt to lazily load the the relationship, which
    will fail when called within a synchronous pydantic method.

    This method will construct a `State` object from an ORM model without a loaded
    artifact and attach data passed using the `with_data` argument to the `data`
    field.
    """

    field_keys = cls.model_json_schema()["properties"].keys()
    state_data = {
        field: getattr(orm_state, field, None)
        for field in field_keys
        if field != "data"
    }
    state_data["data"] = with_data
    return cls(**state_data)

StateBaseModel

Bases: IDBaseModel

Source code in src/prefect/server/schemas/states.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
class StateBaseModel(IDBaseModel):
    def orm_dict(self, *args, **kwargs) -> dict:
        """
        This method is used as a convenience method for constructing fixtues by first
        building a `State` schema object and converting it into an ORM-compatible
        format. Because the `data` field is not writable on ORM states, this method
        omits the `data` field entirely for the purposes of constructing an ORM model.
        If state data is required, an artifact must be created separately.
        """

        schema_dict = self.model_dump(*args, **kwargs)
        # remove the data field in order to construct a state ORM model
        schema_dict.pop("data", None)
        return schema_dict

orm_dict(*args, **kwargs)

This method is used as a convenience method for constructing fixtues by first building a State schema object and converting it into an ORM-compatible format. Because the data field is not writable on ORM states, this method omits the data field entirely for the purposes of constructing an ORM model. If state data is required, an artifact must be created separately.

Source code in src/prefect/server/schemas/states.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
def orm_dict(self, *args, **kwargs) -> dict:
    """
    This method is used as a convenience method for constructing fixtues by first
    building a `State` schema object and converting it into an ORM-compatible
    format. Because the `data` field is not writable on ORM states, this method
    omits the `data` field entirely for the purposes of constructing an ORM model.
    If state data is required, an artifact must be created separately.
    """

    schema_dict = self.model_dump(*args, **kwargs)
    # remove the data field in order to construct a state ORM model
    schema_dict.pop("data", None)
    return schema_dict

StateType

Bases: AutoEnum

Enumeration of state types.

Source code in src/prefect/server/schemas/states.py
28
29
30
31
32
33
34
35
36
37
38
39
class StateType(AutoEnum):
    """Enumeration of state types."""

    SCHEDULED = AutoEnum.auto()
    PENDING = AutoEnum.auto()
    RUNNING = AutoEnum.auto()
    COMPLETED = AutoEnum.auto()
    FAILED = AutoEnum.auto()
    CANCELLED = AutoEnum.auto()
    CRASHED = AutoEnum.auto()
    PAUSED = AutoEnum.auto()
    CANCELLING = AutoEnum.auto()

AwaitingRetry(scheduled_time=None, cls=State, **kwargs)

Convenience function for creating AwaitingRetry states.

Returns:

Name Type Description
State State

a AwaitingRetry state

Source code in src/prefect/server/schemas/states.py
433
434
435
436
437
438
439
440
441
442
443
def AwaitingRetry(
    scheduled_time: datetime.datetime = None, cls: Type[State] = State, **kwargs
) -> State:
    """Convenience function for creating `AwaitingRetry` states.

    Returns:
        State: a AwaitingRetry state
    """
    return Scheduled(
        cls=cls, scheduled_time=scheduled_time, name="AwaitingRetry", **kwargs
    )

Cancelled(cls=State, **kwargs)

Convenience function for creating Cancelled states.

Returns:

Name Type Description
State State

a Cancelled state

Source code in src/prefect/server/schemas/states.py
356
357
358
359
360
361
362
def Cancelled(cls: Type[State] = State, **kwargs) -> State:
    """Convenience function for creating `Cancelled` states.

    Returns:
        State: a Cancelled state
    """
    return cls(type=StateType.CANCELLED, **kwargs)

Cancelling(cls=State, **kwargs)

Convenience function for creating Cancelling states.

Returns:

Name Type Description
State State

a Cancelling state

Source code in src/prefect/server/schemas/states.py
347
348
349
350
351
352
353
def Cancelling(cls: Type[State] = State, **kwargs) -> State:
    """Convenience function for creating `Cancelling` states.

    Returns:
        State: a Cancelling state
    """
    return cls(type=StateType.CANCELLING, **kwargs)

Completed(cls=State, **kwargs)

Convenience function for creating Completed states.

Returns:

Name Type Description
State State

a Completed state

Source code in src/prefect/server/schemas/states.py
311
312
313
314
315
316
317
def Completed(cls: Type[State] = State, **kwargs) -> State:
    """Convenience function for creating `Completed` states.

    Returns:
        State: a Completed state
    """
    return cls(type=StateType.COMPLETED, **kwargs)

Crashed(cls=State, **kwargs)

Convenience function for creating Crashed states.

Returns:

Name Type Description
State State

a Crashed state

Source code in src/prefect/server/schemas/states.py
338
339
340
341
342
343
344
def Crashed(cls: Type[State] = State, **kwargs) -> State:
    """Convenience function for creating `Crashed` states.

    Returns:
        State: a Crashed state
    """
    return cls(type=StateType.CRASHED, **kwargs)

Failed(cls=State, **kwargs)

Convenience function for creating Failed states.

Returns:

Name Type Description
State State

a Failed state

Source code in src/prefect/server/schemas/states.py
329
330
331
332
333
334
335
def Failed(cls: Type[State] = State, **kwargs) -> State:
    """Convenience function for creating `Failed` states.

    Returns:
        State: a Failed state
    """
    return cls(type=StateType.FAILED, **kwargs)

Late(scheduled_time=None, cls=State, **kwargs)

Convenience function for creating Late states.

Returns:

Name Type Description
State State

a Late state

Source code in src/prefect/server/schemas/states.py
455
456
457
458
459
460
461
462
463
def Late(
    scheduled_time: datetime.datetime = None, cls: Type[State] = State, **kwargs
) -> State:
    """Convenience function for creating `Late` states.

    Returns:
        State: a Late state
    """
    return Scheduled(cls=cls, scheduled_time=scheduled_time, name="Late", **kwargs)

Paused(cls=State, timeout_seconds=None, pause_expiration_time=None, reschedule=False, pause_key=None, **kwargs)

Convenience function for creating Paused states.

Returns:

Name Type Description
State State

a Paused state

Source code in src/prefect/server/schemas/states.py
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
def Paused(
    cls: Type[State] = State,
    timeout_seconds: Optional[int] = None,
    pause_expiration_time: Optional[datetime.datetime] = None,
    reschedule: Optional[bool] = False,
    pause_key: Optional[str] = None,
    **kwargs,
) -> State:
    """Convenience function for creating `Paused` states.

    Returns:
        State: a Paused state
    """
    state_details = StateDetails.model_validate(kwargs.pop("state_details", {}))

    if state_details.pause_timeout:
        raise ValueError("An extra pause timeout was provided in state_details")

    if pause_expiration_time is not None and timeout_seconds is not None:
        raise ValueError(
            "Cannot supply both a pause_expiration_time and timeout_seconds"
        )

    if pause_expiration_time is None and timeout_seconds is None:
        pass
    else:
        state_details.pause_timeout = pause_expiration_time or (
            pendulum.now("UTC") + pendulum.Duration(seconds=timeout_seconds)
        )

    state_details.pause_reschedule = reschedule
    state_details.pause_key = pause_key

    return cls(type=StateType.PAUSED, state_details=state_details, **kwargs)

Pending(cls=State, **kwargs)

Convenience function for creating Pending states.

Returns:

Name Type Description
State State

a Pending state

Source code in src/prefect/server/schemas/states.py
365
366
367
368
369
370
371
def Pending(cls: Type[State] = State, **kwargs) -> State:
    """Convenience function for creating `Pending` states.

    Returns:
        State: a Pending state
    """
    return cls(type=StateType.PENDING, **kwargs)

Retrying(cls=State, **kwargs)

Convenience function for creating Retrying states.

Returns:

Name Type Description
State State

a Retrying state

Source code in src/prefect/server/schemas/states.py
446
447
448
449
450
451
452
def Retrying(cls: Type[State] = State, **kwargs) -> State:
    """Convenience function for creating `Retrying` states.

    Returns:
        State: a Retrying state
    """
    return cls(type=StateType.RUNNING, name="Retrying", **kwargs)

Running(cls=State, **kwargs)

Convenience function for creating Running states.

Returns:

Name Type Description
State State

a Running state

Source code in src/prefect/server/schemas/states.py
320
321
322
323
324
325
326
def Running(cls: Type[State] = State, **kwargs) -> State:
    """Convenience function for creating `Running` states.

    Returns:
        State: a Running state
    """
    return cls(type=StateType.RUNNING, **kwargs)

Scheduled(scheduled_time=None, cls=State, **kwargs)

Convenience function for creating Scheduled states.

Returns:

Name Type Description
State State

a Scheduled state

Source code in src/prefect/server/schemas/states.py
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
def Scheduled(
    scheduled_time: Optional[datetime.datetime] = None,
    cls: Type[State] = State,
    **kwargs,
) -> State:
    """Convenience function for creating `Scheduled` states.

    Returns:
        State: a Scheduled state
    """
    # NOTE: `scheduled_time` must come first for backwards compatibility

    state_details = StateDetails.model_validate(kwargs.pop("state_details", {}))
    if scheduled_time is None:
        scheduled_time = pendulum.now("UTC")
    elif state_details.scheduled_time:
        raise ValueError("An extra scheduled_time was provided in state_details")
    state_details.scheduled_time = scheduled_time

    return cls(type=StateType.SCHEDULED, state_details=state_details, **kwargs)

Suspended(cls=State, timeout_seconds=None, pause_expiration_time=None, pause_key=None, **kwargs)

Convenience function for creating Suspended states.

Returns:

Name Type Description
State

a Suspended state

Source code in src/prefect/server/schemas/states.py
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
def Suspended(
    cls: Type[State] = State,
    timeout_seconds: Optional[int] = None,
    pause_expiration_time: Optional[datetime.datetime] = None,
    pause_key: Optional[str] = None,
    **kwargs,
):
    """Convenience function for creating `Suspended` states.

    Returns:
        State: a Suspended state
    """
    return Paused(
        cls=cls,
        name="Suspended",
        reschedule=True,
        timeout_seconds=timeout_seconds,
        pause_expiration_time=pause_expiration_time,
        pause_key=pause_key,
        **kwargs,
    )