Skip to content

Models

Pydantic models for the various concepts in ZenML.

APIKey

Bases: BaseModel

Encoded model for API keys.

Source code in src/zenml/models/v2/core/api_key.py
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
class APIKey(BaseModel):
    """Encoded model for API keys."""

    id: UUID
    key: str

    @classmethod
    def decode_api_key(cls, encoded_key: str) -> "APIKey":
        """Decodes an API key from a base64 string.

        Args:
            encoded_key: The encoded API key.

        Returns:
            The decoded API key.

        Raises:
            ValueError: If the key is not valid.
        """
        if encoded_key.startswith(ZENML_API_KEY_PREFIX):
            encoded_key = encoded_key[len(ZENML_API_KEY_PREFIX) :]
        try:
            json_key = b64_decode(encoded_key)
            return cls.model_validate_json(json_key)
        except Exception:
            raise ValueError("Invalid API key.")

    def encode(self) -> str:
        """Encodes the API key in a base64 string that includes the key ID and prefix.

        Returns:
            The encoded API key.
        """
        encoded_key = b64_encode(self.model_dump_json())
        return f"{ZENML_API_KEY_PREFIX}{encoded_key}"

decode_api_key(encoded_key) classmethod

Decodes an API key from a base64 string.

Parameters:

Name Type Description Default
encoded_key str

The encoded API key.

required

Returns:

Type Description
APIKey

The decoded API key.

Raises:

Type Description
ValueError

If the key is not valid.

Source code in src/zenml/models/v2/core/api_key.py
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
@classmethod
def decode_api_key(cls, encoded_key: str) -> "APIKey":
    """Decodes an API key from a base64 string.

    Args:
        encoded_key: The encoded API key.

    Returns:
        The decoded API key.

    Raises:
        ValueError: If the key is not valid.
    """
    if encoded_key.startswith(ZENML_API_KEY_PREFIX):
        encoded_key = encoded_key[len(ZENML_API_KEY_PREFIX) :]
    try:
        json_key = b64_decode(encoded_key)
        return cls.model_validate_json(json_key)
    except Exception:
        raise ValueError("Invalid API key.")

encode()

Encodes the API key in a base64 string that includes the key ID and prefix.

Returns:

Type Description
str

The encoded API key.

Source code in src/zenml/models/v2/core/api_key.py
72
73
74
75
76
77
78
79
def encode(self) -> str:
    """Encodes the API key in a base64 string that includes the key ID and prefix.

    Returns:
        The encoded API key.
    """
    encoded_key = b64_encode(self.model_dump_json())
    return f"{ZENML_API_KEY_PREFIX}{encoded_key}"

APIKeyFilter

Bases: BaseFilter

Filter model for API keys.

Source code in src/zenml/models/v2/core/api_key.py
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
class APIKeyFilter(BaseFilter):
    """Filter model for API keys."""

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *BaseFilter.FILTER_EXCLUDE_FIELDS,
        "service_account",
    ]
    CLI_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *BaseFilter.CLI_EXCLUDE_FIELDS,
        "service_account",
    ]

    service_account: Optional[UUID] = Field(
        default=None,
        description="The service account to scope this query to.",
    )
    name: Optional[str] = Field(
        default=None,
        description="Name of the API key",
    )
    description: Optional[str] = Field(
        default=None,
        title="Filter by the API key description.",
    )
    active: Optional[Union[bool, str]] = Field(
        default=None,
        title="Whether the API key is active.",
        union_mode="left_to_right",
    )
    last_login: Optional[Union[datetime, str]] = Field(
        default=None,
        title="Time when the API key was last used to log in.",
        union_mode="left_to_right",
    )
    last_rotated: Optional[Union[datetime, str]] = Field(
        default=None,
        title="Time when the API key was last rotated.",
        union_mode="left_to_right",
    )

    def set_service_account(self, service_account_id: UUID) -> None:
        """Set the service account by which to scope this query.

        Args:
            service_account_id: The service account ID.
        """
        self.service_account = service_account_id

    def apply_filter(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Override to apply the service account scope as an additional filter.

        Args:
            query: The query to which to apply the filter.
            table: The query table.

        Returns:
            The query with filter applied.
        """
        query = super().apply_filter(query=query, table=table)

        if self.service_account:
            scope_filter = (
                getattr(table, "service_account_id") == self.service_account
            )
            query = query.where(scope_filter)

        return query

apply_filter(query, table)

Override to apply the service account scope as an additional filter.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the filter.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with filter applied.

Source code in src/zenml/models/v2/core/api_key.py
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
def apply_filter(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Override to apply the service account scope as an additional filter.

    Args:
        query: The query to which to apply the filter.
        table: The query table.

    Returns:
        The query with filter applied.
    """
    query = super().apply_filter(query=query, table=table)

    if self.service_account:
        scope_filter = (
            getattr(table, "service_account_id") == self.service_account
        )
        query = query.where(scope_filter)

    return query

set_service_account(service_account_id)

Set the service account by which to scope this query.

Parameters:

Name Type Description Default
service_account_id UUID

The service account ID.

required
Source code in src/zenml/models/v2/core/api_key.py
377
378
379
380
381
382
383
def set_service_account(self, service_account_id: UUID) -> None:
    """Set the service account by which to scope this query.

    Args:
        service_account_id: The service account ID.
    """
    self.service_account = service_account_id

APIKeyInternalResponse

Bases: APIKeyResponse

Response model for API keys used internally.

Source code in src/zenml/models/v2/core/api_key.py
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
class APIKeyInternalResponse(APIKeyResponse):
    """Response model for API keys used internally."""

    previous_key: Optional[str] = Field(
        default=None,
        title="The previous API key. Only set if the key was rotated.",
    )

    def verify_key(
        self,
        key: str,
    ) -> bool:
        """Verifies a given key against the stored (hashed) key(s).

        Args:
            key: Input key to be verified.

        Returns:
            True if the keys match.
        """
        # even when the hashed key is not set, we still want to execute
        # the hash verification to protect against response discrepancy
        # attacks (https://cwe.mitre.org/data/definitions/204.html)
        key_hash: Optional[str] = None
        context = CryptContext(schemes=["bcrypt"], deprecated="auto")
        if self.key is not None and self.active:
            key_hash = self.key
        result = context.verify(key, key_hash)

        # same for the previous key, if set and if it's still valid
        key_hash = None
        if (
            self.previous_key is not None
            and self.last_rotated is not None
            and self.active
            and self.retain_period_minutes > 0
        ):
            # check if the previous key is still valid
            if utc_now(
                tz_aware=self.last_rotated
            ) - self.last_rotated < timedelta(
                minutes=self.retain_period_minutes
            ):
                key_hash = self.previous_key
        previous_result = context.verify(key, key_hash)

        return result or previous_result

verify_key(key)

Verifies a given key against the stored (hashed) key(s).

Parameters:

Name Type Description Default
key str

Input key to be verified.

required

Returns:

Type Description
bool

True if the keys match.

Source code in src/zenml/models/v2/core/api_key.py
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
def verify_key(
    self,
    key: str,
) -> bool:
    """Verifies a given key against the stored (hashed) key(s).

    Args:
        key: Input key to be verified.

    Returns:
        True if the keys match.
    """
    # even when the hashed key is not set, we still want to execute
    # the hash verification to protect against response discrepancy
    # attacks (https://cwe.mitre.org/data/definitions/204.html)
    key_hash: Optional[str] = None
    context = CryptContext(schemes=["bcrypt"], deprecated="auto")
    if self.key is not None and self.active:
        key_hash = self.key
    result = context.verify(key, key_hash)

    # same for the previous key, if set and if it's still valid
    key_hash = None
    if (
        self.previous_key is not None
        and self.last_rotated is not None
        and self.active
        and self.retain_period_minutes > 0
    ):
        # check if the previous key is still valid
        if utc_now(
            tz_aware=self.last_rotated
        ) - self.last_rotated < timedelta(
            minutes=self.retain_period_minutes
        ):
            key_hash = self.previous_key
    previous_result = context.verify(key, key_hash)

    return result or previous_result

APIKeyInternalUpdate

Bases: APIKeyUpdate

Update model for API keys used internally.

Source code in src/zenml/models/v2/core/api_key.py
132
133
134
135
136
137
138
class APIKeyInternalUpdate(APIKeyUpdate):
    """Update model for API keys used internally."""

    update_last_login: bool = Field(
        default=False,
        title="Whether to update the last login timestamp.",
    )

APIKeyRequest

Bases: BaseRequest

Request model for API keys.

Source code in src/zenml/models/v2/core/api_key.py
85
86
87
88
89
90
91
92
93
94
95
96
97
class APIKeyRequest(BaseRequest):
    """Request model for API keys."""

    name: str = Field(
        title="The name of the API Key.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    description: Optional[str] = Field(
        default=None,
        title="The description of the API Key.",
        max_length=TEXT_FIELD_MAX_LENGTH,
    )

APIKeyResponse

Bases: BaseIdentifiedResponse[APIKeyResponseBody, APIKeyResponseMetadata, APIKeyResponseResources]

Response model for API keys.

Source code in src/zenml/models/v2/core/api_key.py
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
class APIKeyResponse(
    BaseIdentifiedResponse[
        APIKeyResponseBody, APIKeyResponseMetadata, APIKeyResponseResources
    ]
):
    """Response model for API keys."""

    name: str = Field(
        title="The name of the API Key.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    _warn_on_response_updates = False

    def get_hydrated_version(self) -> "APIKeyResponse":
        """Get the hydrated version of this API key.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_api_key(
            service_account_id=self.service_account.id,
            api_key_name_or_id=self.id,
        )

    # Helper functions
    def set_key(self, key: str) -> None:
        """Sets the API key and encodes it.

        Args:
            key: The API key value to be set.
        """
        self.get_body().key = APIKey(id=self.id, key=key).encode()

    # Body and metadata properties
    @property
    def key(self) -> Optional[str]:
        """The `key` property.

        Returns:
            the value of the property.
        """
        return self.get_body().key

    @property
    def active(self) -> bool:
        """The `active` property.

        Returns:
            the value of the property.
        """
        return self.get_body().active

    @property
    def service_account(self) -> "ServiceAccountResponse":
        """The `service_account` property.

        Returns:
            the value of the property.
        """
        return self.get_body().service_account

    @property
    def description(self) -> str:
        """The `description` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().description

    @property
    def retain_period_minutes(self) -> int:
        """The `retain_period_minutes` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().retain_period_minutes

    @property
    def last_login(self) -> Optional[datetime]:
        """The `last_login` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().last_login

    @property
    def last_rotated(self) -> Optional[datetime]:
        """The `last_rotated` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().last_rotated

active property

The active property.

Returns:

Type Description
bool

the value of the property.

description property

The description property.

Returns:

Type Description
str

the value of the property.

key property

The key property.

Returns:

Type Description
Optional[str]

the value of the property.

last_login property

The last_login property.

Returns:

Type Description
Optional[datetime]

the value of the property.

last_rotated property

The last_rotated property.

Returns:

Type Description
Optional[datetime]

the value of the property.

retain_period_minutes property

The retain_period_minutes property.

Returns:

Type Description
int

the value of the property.

service_account property

The service_account property.

Returns:

Type Description
ServiceAccountResponse

the value of the property.

get_hydrated_version()

Get the hydrated version of this API key.

Returns:

Type Description
APIKeyResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/api_key.py
198
199
200
201
202
203
204
205
206
207
208
209
def get_hydrated_version(self) -> "APIKeyResponse":
    """Get the hydrated version of this API key.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_api_key(
        service_account_id=self.service_account.id,
        api_key_name_or_id=self.id,
    )

set_key(key)

Sets the API key and encodes it.

Parameters:

Name Type Description Default
key str

The API key value to be set.

required
Source code in src/zenml/models/v2/core/api_key.py
212
213
214
215
216
217
218
def set_key(self, key: str) -> None:
    """Sets the API key and encodes it.

    Args:
        key: The API key value to be set.
    """
    self.get_body().key = APIKey(id=self.id, key=key).encode()

APIKeyResponseBody

Bases: BaseDatedResponseBody

Response body for API keys.

Source code in src/zenml/models/v2/core/api_key.py
144
145
146
147
148
149
150
151
152
153
154
155
156
157
class APIKeyResponseBody(BaseDatedResponseBody):
    """Response body for API keys."""

    key: Optional[str] = Field(
        default=None,
        title="The API key. Only set immediately after creation or rotation.",
    )
    active: bool = Field(
        default=True,
        title="Whether the API key is active.",
    )
    service_account: "ServiceAccountResponse" = Field(
        title="The service account associated with this API key."
    )

APIKeyResponseMetadata

Bases: BaseResponseMetadata

Response metadata for API keys.

Source code in src/zenml/models/v2/core/api_key.py
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
class APIKeyResponseMetadata(BaseResponseMetadata):
    """Response metadata for API keys."""

    description: str = Field(
        default="",
        title="The description of the API Key.",
        max_length=TEXT_FIELD_MAX_LENGTH,
    )
    retain_period_minutes: int = Field(
        title="Number of minutes for which the previous key is still valid "
        "after it has been rotated.",
    )
    last_login: Optional[datetime] = Field(
        default=None, title="Time when the API key was last used to log in."
    )
    last_rotated: Optional[datetime] = Field(
        default=None, title="Time when the API key was last rotated."
    )

APIKeyRotateRequest

Bases: BaseModel

Request model for API key rotation.

Source code in src/zenml/models/v2/core/api_key.py
100
101
102
103
104
105
106
107
class APIKeyRotateRequest(BaseModel):
    """Request model for API key rotation."""

    retain_period_minutes: int = Field(
        default=0,
        title="Number of minutes for which the previous key is still valid "
        "after it has been rotated.",
    )

APIKeyUpdate

Bases: BaseUpdate

Update model for API keys.

Source code in src/zenml/models/v2/core/api_key.py
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
class APIKeyUpdate(BaseUpdate):
    """Update model for API keys."""

    name: Optional[str] = Field(
        title="The name of the API Key.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    description: Optional[str] = Field(
        title="The description of the API Key.",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    active: Optional[bool] = Field(
        title="Whether the API key is active.",
        default=None,
    )

ActionFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of all actions.

Source code in src/zenml/models/v2/core/action.py
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
class ActionFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of all actions."""

    name: Optional[str] = Field(
        default=None,
        description="Name of the action.",
    )
    flavor: Optional[str] = Field(
        default=None,
        title="The flavor of the action.",
    )
    plugin_subtype: Optional[str] = Field(
        default=None,
        title="The subtype of the action.",
    )

ActionFlavorResponse

Bases: BasePluginFlavorResponse[ActionFlavorResponseBody, ActionFlavorResponseMetadata, ActionFlavorResponseResources]

Response model for Action Flavors.

Source code in src/zenml/models/v2/core/action_flavor.py
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class ActionFlavorResponse(
    BasePluginFlavorResponse[
        ActionFlavorResponseBody,
        ActionFlavorResponseMetadata,
        ActionFlavorResponseResources,
    ]
):
    """Response model for Action Flavors."""

    # Body and metadata properties
    @property
    def config_schema(self) -> Dict[str, Any]:
        """The `source_config_schema` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().config_schema

config_schema property

The source_config_schema property.

Returns:

Type Description
Dict[str, Any]

the value of the property.

ActionFlavorResponseBody

Bases: BasePluginResponseBody

Response body for action flavors.

Source code in src/zenml/models/v2/core/action_flavor.py
26
27
class ActionFlavorResponseBody(BasePluginResponseBody):
    """Response body for action flavors."""

ActionFlavorResponseMetadata

Bases: BasePluginResponseMetadata

Response metadata for action flavors.

Source code in src/zenml/models/v2/core/action_flavor.py
30
31
32
33
class ActionFlavorResponseMetadata(BasePluginResponseMetadata):
    """Response metadata for action flavors."""

    config_schema: Dict[str, Any]

ActionFlavorResponseResources

Bases: BasePluginResponseResources

Response resources for action flavors.

Source code in src/zenml/models/v2/core/action_flavor.py
36
37
class ActionFlavorResponseResources(BasePluginResponseResources):
    """Response resources for action flavors."""

ActionRequest

Bases: WorkspaceScopedRequest

Model for creating a new action.

Source code in src/zenml/models/v2/core/action.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class ActionRequest(WorkspaceScopedRequest):
    """Model for creating a new action."""

    name: str = Field(
        title="The name of the action.", max_length=STR_FIELD_MAX_LENGTH
    )
    description: str = Field(
        default="",
        title="The description of the action",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    flavor: str = Field(
        title="The flavor of the action.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    plugin_subtype: PluginSubType = Field(
        title="The subtype of the action.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    configuration: Dict[str, Any] = Field(
        title="The configuration for the action.",
    )
    service_account_id: UUID = Field(
        title="The service account that is used to execute the action.",
    )
    auth_window: Optional[int] = Field(
        default=None,
        title="The time window in minutes for which the service account is "
        "authorized to execute the action. Set this to 0 to authorize the "
        "service account indefinitely (not recommended). If not set, a "
        "default value defined for each individual action type is used.",
    )

ActionResponse

Bases: WorkspaceScopedResponse[ActionResponseBody, ActionResponseMetadata, ActionResponseResources]

Response model for actions.

Source code in src/zenml/models/v2/core/action.py
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
class ActionResponse(
    WorkspaceScopedResponse[
        ActionResponseBody, ActionResponseMetadata, ActionResponseResources
    ]
):
    """Response model for actions."""

    name: str = Field(
        title="The name of the action.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "ActionResponse":
        """Get the hydrated version of this action.

        Returns:
            An instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_action(self.id)

    # Body and metadata properties
    @property
    def flavor(self) -> str:
        """The `flavor` property.

        Returns:
            the value of the property.
        """
        return self.get_body().flavor

    @property
    def plugin_subtype(self) -> PluginSubType:
        """The `plugin_subtype` property.

        Returns:
            the value of the property.
        """
        return self.get_body().plugin_subtype

    @property
    def description(self) -> str:
        """The `description` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().description

    @property
    def auth_window(self) -> int:
        """The `auth_window` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().auth_window

    @property
    def configuration(self) -> Dict[str, Any]:
        """The `configuration` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().configuration

    def set_configuration(self, configuration: Dict[str, Any]) -> None:
        """Set the `configuration` property.

        Args:
            configuration: The value to set.
        """
        self.get_metadata().configuration = configuration

    # Resource properties
    @property
    def service_account(self) -> "UserResponse":
        """The `service_account` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().service_account

auth_window property

The auth_window property.

Returns:

Type Description
int

the value of the property.

configuration property

The configuration property.

Returns:

Type Description
Dict[str, Any]

the value of the property.

description property

The description property.

Returns:

Type Description
str

the value of the property.

flavor property

The flavor property.

Returns:

Type Description
str

the value of the property.

plugin_subtype property

The plugin_subtype property.

Returns:

Type Description
PluginSubType

the value of the property.

service_account property

The service_account property.

Returns:

Type Description
UserResponse

the value of the property.

get_hydrated_version()

Get the hydrated version of this action.

Returns:

Type Description
ActionResponse

An instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/action.py
184
185
186
187
188
189
190
191
192
def get_hydrated_version(self) -> "ActionResponse":
    """Get the hydrated version of this action.

    Returns:
        An instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_action(self.id)

set_configuration(configuration)

Set the configuration property.

Parameters:

Name Type Description Default
configuration Dict[str, Any]

The value to set.

required
Source code in src/zenml/models/v2/core/action.py
240
241
242
243
244
245
246
def set_configuration(self, configuration: Dict[str, Any]) -> None:
    """Set the `configuration` property.

    Args:
        configuration: The value to set.
    """
    self.get_metadata().configuration = configuration

ActionResponseBody

Bases: WorkspaceScopedResponseBody

Response body for actions.

Source code in src/zenml/models/v2/core/action.py
134
135
136
137
138
139
140
141
142
143
144
class ActionResponseBody(WorkspaceScopedResponseBody):
    """Response body for actions."""

    flavor: str = Field(
        title="The flavor of the action.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    plugin_subtype: PluginSubType = Field(
        title="The subtype of the action.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

ActionResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for actions.

Source code in src/zenml/models/v2/core/action.py
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
class ActionResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for actions."""

    description: str = Field(
        default="",
        title="The description of the action.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    configuration: Dict[str, Any] = Field(
        title="The configuration for the action.",
    )
    auth_window: int = Field(
        title="The time window in minutes for which the service account is "
        "authorized to execute the action."
    )

ActionResponseResources

Bases: WorkspaceScopedResponseResources

Class for all resource models associated with the action entity.

Source code in src/zenml/models/v2/core/action.py
164
165
166
167
168
169
class ActionResponseResources(WorkspaceScopedResponseResources):
    """Class for all resource models associated with the action entity."""

    service_account: UserResponse = Field(
        title="The service account that is used to execute the action.",
    )

ActionUpdate

Bases: BaseUpdate

Update model for actions.

Source code in src/zenml/models/v2/core/action.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
class ActionUpdate(BaseUpdate):
    """Update model for actions."""

    name: Optional[str] = Field(
        default=None,
        title="The new name for the action.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    description: Optional[str] = Field(
        default=None,
        title="The new description for the action.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    configuration: Optional[Dict[str, Any]] = Field(
        default=None,
        title="The configuration for the action.",
    )
    service_account_id: Optional[UUID] = Field(
        default=None,
        title="The service account that is used to execute the action.",
    )
    auth_window: Optional[int] = Field(
        default=None,
        title="The time window in minutes for which the service account is "
        "authorized to execute the action. Set this to 0 to authorize the "
        "service account indefinitely (not recommended). If not set, a "
        "default value defined for each individual action type is used.",
    )

    @classmethod
    def from_response(cls, response: "ActionResponse") -> "ActionUpdate":
        """Create an update model from a response model.

        Args:
            response: The response model to create the update model from.

        Returns:
            The update model.
        """
        return ActionUpdate(
            configuration=copy.deepcopy(response.configuration),
        )

from_response(response) classmethod

Create an update model from a response model.

Parameters:

Name Type Description Default
response ActionResponse

The response model to create the update model from.

required

Returns:

Type Description
ActionUpdate

The update model.

Source code in src/zenml/models/v2/core/action.py
116
117
118
119
120
121
122
123
124
125
126
127
128
@classmethod
def from_response(cls, response: "ActionResponse") -> "ActionUpdate":
    """Create an update model from a response model.

    Args:
        response: The response model to create the update model from.

    Returns:
        The update model.
    """
    return ActionUpdate(
        configuration=copy.deepcopy(response.configuration),
    )

ArtifactFilter

Bases: TaggableFilter

Model to enable advanced filtering of artifacts.

Source code in src/zenml/models/v2/core/artifact.py
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
class ArtifactFilter(TaggableFilter):
    """Model to enable advanced filtering of artifacts."""

    name: Optional[str] = None
    has_custom_name: Optional[bool] = None

    CUSTOM_SORTING_OPTIONS: ClassVar[List[str]] = [
        *TaggableFilter.CUSTOM_SORTING_OPTIONS,
        SORT_BY_LATEST_VERSION_KEY,
    ]

    def apply_sorting(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Apply sorting to the query for Artifacts.

        Args:
            query: The query to which to apply the sorting.
            table: The query table.

        Returns:
            The query with sorting applied.
        """
        from sqlmodel import asc, case, col, desc, func, select

        from zenml.enums import SorterOps
        from zenml.zen_stores.schemas import (
            ArtifactSchema,
            ArtifactVersionSchema,
        )

        sort_by, operand = self.sorting_params

        if sort_by == SORT_BY_LATEST_VERSION_KEY:
            # Subquery to find the latest version per artifact
            latest_version_subquery = (
                select(
                    ArtifactSchema.id,
                    case(
                        (
                            func.max(ArtifactVersionSchema.created).is_(None),
                            ArtifactSchema.created,
                        ),
                        else_=func.max(ArtifactVersionSchema.created),
                    ).label("latest_version_created"),
                )
                .outerjoin(
                    ArtifactVersionSchema,
                    ArtifactSchema.id == ArtifactVersionSchema.artifact_id,  # type: ignore[arg-type]
                )
                .group_by(col(ArtifactSchema.id))
                .subquery()
            )

            query = query.add_columns(
                latest_version_subquery.c.latest_version_created,
            ).where(ArtifactSchema.id == latest_version_subquery.c.id)

            # Apply sorting based on the operand
            if operand == SorterOps.ASCENDING:
                query = query.order_by(
                    asc(latest_version_subquery.c.latest_version_created),
                    asc(ArtifactSchema.id),
                )
            else:
                query = query.order_by(
                    desc(latest_version_subquery.c.latest_version_created),
                    desc(ArtifactSchema.id),
                )
            return query

        # For other sorting cases, delegate to the parent class
        return super().apply_sorting(query=query, table=table)

apply_sorting(query, table)

Apply sorting to the query for Artifacts.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the sorting.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with sorting applied.

Source code in src/zenml/models/v2/core/artifact.py
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
def apply_sorting(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Apply sorting to the query for Artifacts.

    Args:
        query: The query to which to apply the sorting.
        table: The query table.

    Returns:
        The query with sorting applied.
    """
    from sqlmodel import asc, case, col, desc, func, select

    from zenml.enums import SorterOps
    from zenml.zen_stores.schemas import (
        ArtifactSchema,
        ArtifactVersionSchema,
    )

    sort_by, operand = self.sorting_params

    if sort_by == SORT_BY_LATEST_VERSION_KEY:
        # Subquery to find the latest version per artifact
        latest_version_subquery = (
            select(
                ArtifactSchema.id,
                case(
                    (
                        func.max(ArtifactVersionSchema.created).is_(None),
                        ArtifactSchema.created,
                    ),
                    else_=func.max(ArtifactVersionSchema.created),
                ).label("latest_version_created"),
            )
            .outerjoin(
                ArtifactVersionSchema,
                ArtifactSchema.id == ArtifactVersionSchema.artifact_id,  # type: ignore[arg-type]
            )
            .group_by(col(ArtifactSchema.id))
            .subquery()
        )

        query = query.add_columns(
            latest_version_subquery.c.latest_version_created,
        ).where(ArtifactSchema.id == latest_version_subquery.c.id)

        # Apply sorting based on the operand
        if operand == SorterOps.ASCENDING:
            query = query.order_by(
                asc(latest_version_subquery.c.latest_version_created),
                asc(ArtifactSchema.id),
            )
        else:
            query = query.order_by(
                desc(latest_version_subquery.c.latest_version_created),
                desc(ArtifactSchema.id),
            )
        return query

    # For other sorting cases, delegate to the parent class
    return super().apply_sorting(query=query, table=table)

ArtifactRequest

Bases: BaseRequest

Artifact request model.

Source code in src/zenml/models/v2/core/artifact.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class ArtifactRequest(BaseRequest):
    """Artifact request model."""

    name: str = Field(
        title="Name of the artifact.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    has_custom_name: bool = Field(
        title="Whether the name is custom (True) or auto-generated (False).",
        default=False,
    )
    tags: Optional[List[str]] = Field(
        title="Artifact tags.",
        description="Should be a list of plain strings, e.g., ['tag1', 'tag2']",
        default=None,
    )

ArtifactResponse

Bases: BaseIdentifiedResponse[ArtifactResponseBody, ArtifactResponseMetadata, ArtifactResponseResources]

Artifact response model.

Source code in src/zenml/models/v2/core/artifact.py
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
class ArtifactResponse(
    BaseIdentifiedResponse[
        ArtifactResponseBody,
        ArtifactResponseMetadata,
        ArtifactResponseResources,
    ]
):
    """Artifact response model."""

    def get_hydrated_version(self) -> "ArtifactResponse":
        """Get the hydrated version of this artifact.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_artifact(self.id)

    name: str = Field(
        title="Name of the output in the parent step.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    # Body and metadata properties
    @property
    def tags(self) -> List[TagResponse]:
        """The `tags` property.

        Returns:
            the value of the property.
        """
        return self.get_body().tags

    @property
    def latest_version_name(self) -> Optional[str]:
        """The `latest_version_name` property.

        Returns:
            the value of the property.
        """
        return self.get_body().latest_version_name

    @property
    def latest_version_id(self) -> Optional[UUID]:
        """The `latest_version_id` property.

        Returns:
            the value of the property.
        """
        return self.get_body().latest_version_id

    @property
    def has_custom_name(self) -> bool:
        """The `has_custom_name` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().has_custom_name

    # Helper methods
    @property
    def versions(self) -> Dict[str, "ArtifactVersionResponse"]:
        """Get a list of all versions of this artifact.

        Returns:
            A list of all versions of this artifact.
        """
        from zenml.client import Client

        responses = Client().list_artifact_versions(name=self.name)
        return {str(response.version): response for response in responses}

has_custom_name property

The has_custom_name property.

Returns:

Type Description
bool

the value of the property.

latest_version_id property

The latest_version_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

latest_version_name property

The latest_version_name property.

Returns:

Type Description
Optional[str]

the value of the property.

tags property

The tags property.

Returns:

Type Description
List[TagResponse]

the value of the property.

versions property

Get a list of all versions of this artifact.

Returns:

Type Description
Dict[str, ArtifactVersionResponse]

A list of all versions of this artifact.

get_hydrated_version()

Get the hydrated version of this artifact.

Returns:

Type Description
ArtifactResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/artifact.py
117
118
119
120
121
122
123
124
125
def get_hydrated_version(self) -> "ArtifactResponse":
    """Get the hydrated version of this artifact.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_artifact(self.id)

ArtifactResponseBody

Bases: BaseDatedResponseBody

Response body for artifacts.

Source code in src/zenml/models/v2/core/artifact.py
85
86
87
88
89
90
91
92
class ArtifactResponseBody(BaseDatedResponseBody):
    """Response body for artifacts."""

    tags: List[TagResponse] = Field(
        title="Tags associated with the model",
    )
    latest_version_name: Optional[str] = None
    latest_version_id: Optional[UUID] = None

ArtifactResponseMetadata

Bases: BaseResponseMetadata

Response metadata for artifacts.

Source code in src/zenml/models/v2/core/artifact.py
 95
 96
 97
 98
 99
100
101
class ArtifactResponseMetadata(BaseResponseMetadata):
    """Response metadata for artifacts."""

    has_custom_name: bool = Field(
        title="Whether the name is custom (True) or auto-generated (False).",
        default=False,
    )

ArtifactUpdate

Bases: BaseModel

Artifact update model.

Source code in src/zenml/models/v2/core/artifact.py
73
74
75
76
77
78
79
class ArtifactUpdate(BaseModel):
    """Artifact update model."""

    name: Optional[str] = None
    add_tags: Optional[List[str]] = None
    remove_tags: Optional[List[str]] = None
    has_custom_name: Optional[bool] = None

ArtifactVersionFilter

Bases: WorkspaceScopedFilter, TaggableFilter

Model to enable advanced filtering of artifact versions.

Source code in src/zenml/models/v2/core/artifact_version.py
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
class ArtifactVersionFilter(WorkspaceScopedFilter, TaggableFilter):
    """Model to enable advanced filtering of artifact versions."""

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
        *TaggableFilter.FILTER_EXCLUDE_FIELDS,
        "name",
        "only_unused",
        "has_custom_name",
        "model",
        "pipeline_run",
        "model_version_id",
        "run_metadata",
    ]
    CUSTOM_SORTING_OPTIONS = [
        *WorkspaceScopedFilter.CUSTOM_SORTING_OPTIONS,
        *TaggableFilter.CUSTOM_SORTING_OPTIONS,
    ]
    CLI_EXCLUDE_FIELDS = [
        *WorkspaceScopedFilter.CLI_EXCLUDE_FIELDS,
        *TaggableFilter.CLI_EXCLUDE_FIELDS,
    ]

    artifact_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="ID of the artifact to which this version belongs.",
        union_mode="left_to_right",
    )
    name: Optional[str] = Field(
        default=None,
        description="Name of the artifact to which this version belongs.",
    )
    version: Optional[str] = Field(
        default=None,
        description="Version of the artifact",
    )
    version_number: Optional[Union[int, str]] = Field(
        default=None,
        description="Version of the artifact if it is an integer",
        union_mode="left_to_right",
    )
    uri: Optional[str] = Field(
        default=None,
        description="Uri of the artifact",
    )
    materializer: Optional[str] = Field(
        default=None,
        description="Materializer used to produce the artifact",
    )
    type: Optional[str] = Field(
        default=None,
        description="Type of the artifact",
    )
    data_type: Optional[str] = Field(
        default=None,
        description="Datatype of the artifact",
    )
    artifact_store_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Artifact store for this artifact",
        union_mode="left_to_right",
    )
    model_version_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="ID of the model version that is associated with this "
        "artifact version.",
        union_mode="left_to_right",
    )
    only_unused: Optional[bool] = Field(
        default=False, description="Filter only for unused artifacts"
    )
    has_custom_name: Optional[bool] = Field(
        default=None,
        description="Filter only artifacts with/without custom names.",
    )
    user: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of the user that created the artifact version.",
    )
    model: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of the model that is associated with this "
        "artifact version.",
    )
    pipeline_run: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of a pipeline run that is associated with this "
        "artifact version.",
    )
    run_metadata: Optional[Dict[str, Any]] = Field(
        default=None,
        description="The run_metadata to filter the artifact versions by.",
    )

    model_config = ConfigDict(protected_namespaces=())

    def get_custom_filters(
        self, table: Type["AnySchema"]
    ) -> List[Union["ColumnElement[bool]"]]:
        """Get custom filters.

        Args:
            table: The query table.

        Returns:
            A list of custom filters.
        """
        custom_filters = super().get_custom_filters(table)

        from sqlmodel import and_, or_, select

        from zenml.zen_stores.schemas import (
            ArtifactSchema,
            ArtifactVersionSchema,
            ModelSchema,
            ModelVersionArtifactSchema,
            ModelVersionSchema,
            PipelineRunSchema,
            RunMetadataResourceSchema,
            RunMetadataSchema,
            StepRunInputArtifactSchema,
            StepRunOutputArtifactSchema,
            StepRunSchema,
        )

        if self.name:
            value, filter_operator = self._resolve_operator(self.name)
            filter_ = StrFilter(
                operation=GenericFilterOps(filter_operator),
                column="name",
                value=value,
            )
            artifact_name_filter = and_(
                ArtifactVersionSchema.artifact_id == ArtifactSchema.id,
                filter_.generate_query_conditions(ArtifactSchema),
            )
            custom_filters.append(artifact_name_filter)

        if self.only_unused:
            unused_filter = and_(
                ArtifactVersionSchema.id.notin_(  # type: ignore[attr-defined]
                    select(StepRunOutputArtifactSchema.artifact_id)
                ),
                ArtifactVersionSchema.id.notin_(  # type: ignore[attr-defined]
                    select(StepRunInputArtifactSchema.artifact_id)
                ),
            )
            custom_filters.append(unused_filter)

        if self.model_version_id:
            value, operator = self._resolve_operator(self.model_version_id)

            model_version_filter = and_(
                ArtifactVersionSchema.id
                == ModelVersionArtifactSchema.artifact_version_id,
                ModelVersionArtifactSchema.model_version_id
                == ModelVersionSchema.id,
                FilterGenerator(ModelVersionSchema)
                .define_filter(column="id", value=value, operator=operator)
                .generate_query_conditions(ModelVersionSchema),
            )
            custom_filters.append(model_version_filter)

        if self.has_custom_name is not None:
            custom_name_filter = and_(
                ArtifactVersionSchema.artifact_id == ArtifactSchema.id,
                ArtifactSchema.has_custom_name == self.has_custom_name,
            )
            custom_filters.append(custom_name_filter)

        if self.model:
            model_filter = and_(
                ArtifactVersionSchema.id
                == ModelVersionArtifactSchema.artifact_version_id,
                ModelVersionArtifactSchema.model_version_id
                == ModelVersionSchema.id,
                ModelVersionSchema.model_id == ModelSchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.model, table=ModelSchema
                ),
            )
            custom_filters.append(model_filter)

        if self.pipeline_run:
            pipeline_run_filter = and_(
                or_(
                    and_(
                        ArtifactVersionSchema.id
                        == StepRunOutputArtifactSchema.artifact_id,
                        StepRunOutputArtifactSchema.step_id
                        == StepRunSchema.id,
                    ),
                    and_(
                        ArtifactVersionSchema.id
                        == StepRunInputArtifactSchema.artifact_id,
                        StepRunInputArtifactSchema.step_id == StepRunSchema.id,
                    ),
                ),
                StepRunSchema.pipeline_run_id == PipelineRunSchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.pipeline_run, table=PipelineRunSchema
                ),
            )
            custom_filters.append(pipeline_run_filter)

        if self.run_metadata is not None:
            from zenml.enums import MetadataResourceTypes

            for key, value in self.run_metadata.items():
                additional_filter = and_(
                    RunMetadataResourceSchema.resource_id
                    == ArtifactVersionSchema.id,
                    RunMetadataResourceSchema.resource_type
                    == MetadataResourceTypes.ARTIFACT_VERSION.value,
                    RunMetadataResourceSchema.run_metadata_id
                    == RunMetadataSchema.id,
                    self.generate_custom_query_conditions_for_column(
                        value=key,
                        table=RunMetadataSchema,
                        column="key",
                    ),
                    self.generate_custom_query_conditions_for_column(
                        value=value,
                        table=RunMetadataSchema,
                        column="value",
                        json_encode_value=True,
                    ),
                )
                custom_filters.append(additional_filter)

        return custom_filters

get_custom_filters(table)

Get custom filters.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
List[Union[ColumnElement[bool]]]

A list of custom filters.

Source code in src/zenml/models/v2/core/artifact_version.py
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
def get_custom_filters(
    self, table: Type["AnySchema"]
) -> List[Union["ColumnElement[bool]"]]:
    """Get custom filters.

    Args:
        table: The query table.

    Returns:
        A list of custom filters.
    """
    custom_filters = super().get_custom_filters(table)

    from sqlmodel import and_, or_, select

    from zenml.zen_stores.schemas import (
        ArtifactSchema,
        ArtifactVersionSchema,
        ModelSchema,
        ModelVersionArtifactSchema,
        ModelVersionSchema,
        PipelineRunSchema,
        RunMetadataResourceSchema,
        RunMetadataSchema,
        StepRunInputArtifactSchema,
        StepRunOutputArtifactSchema,
        StepRunSchema,
    )

    if self.name:
        value, filter_operator = self._resolve_operator(self.name)
        filter_ = StrFilter(
            operation=GenericFilterOps(filter_operator),
            column="name",
            value=value,
        )
        artifact_name_filter = and_(
            ArtifactVersionSchema.artifact_id == ArtifactSchema.id,
            filter_.generate_query_conditions(ArtifactSchema),
        )
        custom_filters.append(artifact_name_filter)

    if self.only_unused:
        unused_filter = and_(
            ArtifactVersionSchema.id.notin_(  # type: ignore[attr-defined]
                select(StepRunOutputArtifactSchema.artifact_id)
            ),
            ArtifactVersionSchema.id.notin_(  # type: ignore[attr-defined]
                select(StepRunInputArtifactSchema.artifact_id)
            ),
        )
        custom_filters.append(unused_filter)

    if self.model_version_id:
        value, operator = self._resolve_operator(self.model_version_id)

        model_version_filter = and_(
            ArtifactVersionSchema.id
            == ModelVersionArtifactSchema.artifact_version_id,
            ModelVersionArtifactSchema.model_version_id
            == ModelVersionSchema.id,
            FilterGenerator(ModelVersionSchema)
            .define_filter(column="id", value=value, operator=operator)
            .generate_query_conditions(ModelVersionSchema),
        )
        custom_filters.append(model_version_filter)

    if self.has_custom_name is not None:
        custom_name_filter = and_(
            ArtifactVersionSchema.artifact_id == ArtifactSchema.id,
            ArtifactSchema.has_custom_name == self.has_custom_name,
        )
        custom_filters.append(custom_name_filter)

    if self.model:
        model_filter = and_(
            ArtifactVersionSchema.id
            == ModelVersionArtifactSchema.artifact_version_id,
            ModelVersionArtifactSchema.model_version_id
            == ModelVersionSchema.id,
            ModelVersionSchema.model_id == ModelSchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.model, table=ModelSchema
            ),
        )
        custom_filters.append(model_filter)

    if self.pipeline_run:
        pipeline_run_filter = and_(
            or_(
                and_(
                    ArtifactVersionSchema.id
                    == StepRunOutputArtifactSchema.artifact_id,
                    StepRunOutputArtifactSchema.step_id
                    == StepRunSchema.id,
                ),
                and_(
                    ArtifactVersionSchema.id
                    == StepRunInputArtifactSchema.artifact_id,
                    StepRunInputArtifactSchema.step_id == StepRunSchema.id,
                ),
            ),
            StepRunSchema.pipeline_run_id == PipelineRunSchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.pipeline_run, table=PipelineRunSchema
            ),
        )
        custom_filters.append(pipeline_run_filter)

    if self.run_metadata is not None:
        from zenml.enums import MetadataResourceTypes

        for key, value in self.run_metadata.items():
            additional_filter = and_(
                RunMetadataResourceSchema.resource_id
                == ArtifactVersionSchema.id,
                RunMetadataResourceSchema.resource_type
                == MetadataResourceTypes.ARTIFACT_VERSION.value,
                RunMetadataResourceSchema.run_metadata_id
                == RunMetadataSchema.id,
                self.generate_custom_query_conditions_for_column(
                    value=key,
                    table=RunMetadataSchema,
                    column="key",
                ),
                self.generate_custom_query_conditions_for_column(
                    value=value,
                    table=RunMetadataSchema,
                    column="value",
                    json_encode_value=True,
                ),
            )
            custom_filters.append(additional_filter)

    return custom_filters

ArtifactVersionRequest

Bases: WorkspaceScopedRequest

Request model for artifact versions.

Source code in src/zenml/models/v2/core/artifact_version.py
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
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
class ArtifactVersionRequest(WorkspaceScopedRequest):
    """Request model for artifact versions."""

    artifact_id: Optional[UUID] = Field(
        default=None,
        title="ID of the artifact to which this version belongs.",
    )
    artifact_name: Optional[str] = Field(
        default=None,
        title="Name of the artifact to which this version belongs.",
    )
    version: Optional[Union[int, str]] = Field(
        default=None, title="Version of the artifact."
    )
    has_custom_name: bool = Field(
        title="Whether the name is custom (True) or auto-generated (False).",
        default=False,
    )
    type: ArtifactType = Field(title="Type of the artifact.")
    artifact_store_id: Optional[UUID] = Field(
        title="ID of the artifact store in which this artifact is stored.",
        default=None,
    )
    uri: str = Field(
        title="URI of the artifact.", max_length=TEXT_FIELD_MAX_LENGTH
    )
    materializer: SourceWithValidator = Field(
        title="Materializer class to use for this artifact.",
    )
    data_type: SourceWithValidator = Field(
        title="Data type of the artifact.",
    )
    tags: Optional[List[str]] = Field(
        title="Tags of the artifact.",
        description="Should be a list of plain strings, e.g., ['tag1', 'tag2']",
        default=None,
    )
    visualizations: Optional[List["ArtifactVisualizationRequest"]] = Field(
        default=None, title="Visualizations of the artifact."
    )
    save_type: ArtifactSaveType = Field(
        title="The save type of the artifact version.",
    )
    metadata: Optional[Dict[str, MetadataType]] = Field(
        default=None, title="Metadata of the artifact version."
    )

    @field_validator("version")
    @classmethod
    def str_field_max_length_check(cls, value: Any) -> Any:
        """Checks if the length of the value exceeds the maximum str length.

        Args:
            value: the value set in the field

        Returns:
            the value itself.

        Raises:
            AssertionError: if the length of the field is longer than the
                maximum threshold.
        """
        assert len(str(value)) < STR_FIELD_MAX_LENGTH, (
            "The length of the value for this field can not "
            f"exceed {STR_FIELD_MAX_LENGTH}"
        )
        return value

    @model_validator(mode="after")
    def _validate_request(self) -> "ArtifactVersionRequest":
        """Validate the request values.

        Raises:
            ValueError: If the request is invalid.

        Returns:
            The validated request.
        """
        if self.artifact_id and self.artifact_name:
            raise ValueError(
                "Only one of artifact_name and artifact_id can be set."
            )

        if not (self.artifact_id or self.artifact_name):
            raise ValueError(
                "Either artifact_name or artifact_id must be set."
            )

        return self

str_field_max_length_check(value) classmethod

Checks if the length of the value exceeds the maximum str length.

Parameters:

Name Type Description Default
value Any

the value set in the field

required

Returns:

Type Description
Any

the value itself.

Raises:

Type Description
AssertionError

if the length of the field is longer than the maximum threshold.

Source code in src/zenml/models/v2/core/artifact_version.py
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
@field_validator("version")
@classmethod
def str_field_max_length_check(cls, value: Any) -> Any:
    """Checks if the length of the value exceeds the maximum str length.

    Args:
        value: the value set in the field

    Returns:
        the value itself.

    Raises:
        AssertionError: if the length of the field is longer than the
            maximum threshold.
    """
    assert len(str(value)) < STR_FIELD_MAX_LENGTH, (
        "The length of the value for this field can not "
        f"exceed {STR_FIELD_MAX_LENGTH}"
    )
    return value

ArtifactVersionResponse

Bases: WorkspaceScopedResponse[ArtifactVersionResponseBody, ArtifactVersionResponseMetadata, ArtifactVersionResponseResources]

Response model for artifact versions.

Source code in src/zenml/models/v2/core/artifact_version.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
class ArtifactVersionResponse(
    WorkspaceScopedResponse[
        ArtifactVersionResponseBody,
        ArtifactVersionResponseMetadata,
        ArtifactVersionResponseResources,
    ]
):
    """Response model for artifact versions."""

    def get_hydrated_version(self) -> "ArtifactVersionResponse":
        """Get the hydrated version of this artifact version.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_artifact_version(self.id)

    # Body and metadata properties
    @property
    def artifact(self) -> "ArtifactResponse":
        """The `artifact` property.

        Returns:
            the value of the property.
        """
        return self.get_body().artifact

    @property
    def version(self) -> Union[str, int]:
        """The `version` property.

        Returns:
            the value of the property.
        """
        return self.get_body().version

    @property
    def uri(self) -> str:
        """The `uri` property.

        Returns:
            the value of the property.
        """
        return self.get_body().uri

    @property
    def type(self) -> ArtifactType:
        """The `type` property.

        Returns:
            the value of the property.
        """
        return self.get_body().type

    @property
    def tags(self) -> List[TagResponse]:
        """The `tags` property.

        Returns:
            the value of the property.
        """
        return self.get_body().tags

    @property
    def producer_pipeline_run_id(self) -> Optional[UUID]:
        """The `producer_pipeline_run_id` property.

        Returns:
            the value of the property.
        """
        return self.get_body().producer_pipeline_run_id

    @property
    def save_type(self) -> ArtifactSaveType:
        """The `save_type` property.

        Returns:
            the value of the property.
        """
        return self.get_body().save_type

    @property
    def artifact_store_id(self) -> Optional[UUID]:
        """The `artifact_store_id` property.

        Returns:
            the value of the property.
        """
        return self.get_body().artifact_store_id

    @property
    def producer_step_run_id(self) -> Optional[UUID]:
        """The `producer_step_run_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().producer_step_run_id

    @property
    def visualizations(
        self,
    ) -> Optional[List["ArtifactVisualizationResponse"]]:
        """The `visualizations` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().visualizations

    @property
    def run_metadata(self) -> Dict[str, MetadataType]:
        """The `metadata` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().run_metadata

    @property
    def materializer(self) -> Source:
        """The `materializer` property.

        Returns:
            the value of the property.
        """
        return self.get_body().materializer

    @property
    def data_type(self) -> Source:
        """The `data_type` property.

        Returns:
            the value of the property.
        """
        return self.get_body().data_type

    # Helper methods
    @property
    def name(self) -> str:
        """The `name` property.

        Returns:
            the value of the property.
        """
        return self.artifact.name

    @property
    def step(self) -> "StepRunResponse":
        """Get the step that produced this artifact.

        Returns:
            The step that produced this artifact.
        """
        from zenml.artifacts.utils import get_producer_step_of_artifact

        return get_producer_step_of_artifact(self)

    @property
    def run(self) -> "PipelineRunResponse":
        """Get the pipeline run that produced this artifact.

        Returns:
            The pipeline run that produced this artifact.
        """
        from zenml.client import Client

        return Client().get_pipeline_run(self.step.pipeline_run_id)

    def load(self) -> Any:
        """Materializes (loads) the data stored in this artifact.

        Returns:
            The materialized data.
        """
        from zenml.artifacts.utils import load_artifact_from_response

        return load_artifact_from_response(self)

    def download_files(self, path: str, overwrite: bool = False) -> None:
        """Downloads data for an artifact with no materializing.

        Any artifacts will be saved as a zip file to the given path.

        Args:
            path: The path to save the binary data to.
            overwrite: Whether to overwrite the file if it already exists.

        Raises:
            ValueError: If the path does not end with '.zip'.
        """
        if not path.endswith(".zip"):
            raise ValueError(
                "The path should end with '.zip' to save the binary data."
            )
        from zenml.artifacts.utils import (
            download_artifact_files_from_response,
        )

        download_artifact_files_from_response(
            self,
            path=path,
            overwrite=overwrite,
        )

    def visualize(self, title: Optional[str] = None) -> None:
        """Visualize the artifact in notebook environments.

        Args:
            title: Optional title to show before the visualizations.
        """
        from zenml.utils.visualization_utils import visualize_artifact

        visualize_artifact(self, title=title)

artifact property

The artifact property.

Returns:

Type Description
ArtifactResponse

the value of the property.

artifact_store_id property

The artifact_store_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

data_type property

The data_type property.

Returns:

Type Description
Source

the value of the property.

materializer property

The materializer property.

Returns:

Type Description
Source

the value of the property.

name property

The name property.

Returns:

Type Description
str

the value of the property.

producer_pipeline_run_id property

The producer_pipeline_run_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

producer_step_run_id property

The producer_step_run_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

run property

Get the pipeline run that produced this artifact.

Returns:

Type Description
PipelineRunResponse

The pipeline run that produced this artifact.

run_metadata property

The metadata property.

Returns:

Type Description
Dict[str, MetadataType]

the value of the property.

save_type property

The save_type property.

Returns:

Type Description
ArtifactSaveType

the value of the property.

step property

Get the step that produced this artifact.

Returns:

Type Description
StepRunResponse

The step that produced this artifact.

tags property

The tags property.

Returns:

Type Description
List[TagResponse]

the value of the property.

type property

The type property.

Returns:

Type Description
ArtifactType

the value of the property.

uri property

The uri property.

Returns:

Type Description
str

the value of the property.

version property

The version property.

Returns:

Type Description
Union[str, int]

the value of the property.

visualizations property

The visualizations property.

Returns:

Type Description
Optional[List[ArtifactVisualizationResponse]]

the value of the property.

download_files(path, overwrite=False)

Downloads data for an artifact with no materializing.

Any artifacts will be saved as a zip file to the given path.

Parameters:

Name Type Description Default
path str

The path to save the binary data to.

required
overwrite bool

Whether to overwrite the file if it already exists.

False

Raises:

Type Description
ValueError

If the path does not end with '.zip'.

Source code in src/zenml/models/v2/core/artifact_version.py
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
def download_files(self, path: str, overwrite: bool = False) -> None:
    """Downloads data for an artifact with no materializing.

    Any artifacts will be saved as a zip file to the given path.

    Args:
        path: The path to save the binary data to.
        overwrite: Whether to overwrite the file if it already exists.

    Raises:
        ValueError: If the path does not end with '.zip'.
    """
    if not path.endswith(".zip"):
        raise ValueError(
            "The path should end with '.zip' to save the binary data."
        )
    from zenml.artifacts.utils import (
        download_artifact_files_from_response,
    )

    download_artifact_files_from_response(
        self,
        path=path,
        overwrite=overwrite,
    )

get_hydrated_version()

Get the hydrated version of this artifact version.

Returns:

Type Description
ArtifactVersionResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/artifact_version.py
261
262
263
264
265
266
267
268
269
def get_hydrated_version(self) -> "ArtifactVersionResponse":
    """Get the hydrated version of this artifact version.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_artifact_version(self.id)

load()

Materializes (loads) the data stored in this artifact.

Returns:

Type Description
Any

The materialized data.

Source code in src/zenml/models/v2/core/artifact_version.py
423
424
425
426
427
428
429
430
431
def load(self) -> Any:
    """Materializes (loads) the data stored in this artifact.

    Returns:
        The materialized data.
    """
    from zenml.artifacts.utils import load_artifact_from_response

    return load_artifact_from_response(self)

visualize(title=None)

Visualize the artifact in notebook environments.

Parameters:

Name Type Description Default
title Optional[str]

Optional title to show before the visualizations.

None
Source code in src/zenml/models/v2/core/artifact_version.py
459
460
461
462
463
464
465
466
467
def visualize(self, title: Optional[str] = None) -> None:
    """Visualize the artifact in notebook environments.

    Args:
        title: Optional title to show before the visualizations.
    """
    from zenml.utils.visualization_utils import visualize_artifact

    visualize_artifact(self, title=title)

ArtifactVersionResponseBody

Bases: WorkspaceScopedResponseBody

Response body for artifact versions.

Source code in src/zenml/models/v2/core/artifact_version.py
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
class ArtifactVersionResponseBody(WorkspaceScopedResponseBody):
    """Response body for artifact versions."""

    artifact: ArtifactResponse = Field(
        title="Artifact to which this version belongs."
    )
    version: str = Field(title="Version of the artifact.")
    uri: str = Field(
        title="URI of the artifact.", max_length=TEXT_FIELD_MAX_LENGTH
    )
    type: ArtifactType = Field(title="Type of the artifact.")
    materializer: SourceWithValidator = Field(
        title="Materializer class to use for this artifact.",
    )
    data_type: SourceWithValidator = Field(
        title="Data type of the artifact.",
    )
    tags: List[TagResponse] = Field(
        title="Tags associated with the model",
    )
    producer_pipeline_run_id: Optional[UUID] = Field(
        title="The ID of the pipeline run that generated this artifact version.",
        default=None,
    )
    save_type: ArtifactSaveType = Field(
        title="The save type of the artifact version.",
    )
    artifact_store_id: Optional[UUID] = Field(
        title="ID of the artifact store in which this artifact is stored.",
        default=None,
    )

    @field_validator("version")
    @classmethod
    def str_field_max_length_check(cls, value: Any) -> Any:
        """Checks if the length of the value exceeds the maximum str length.

        Args:
            value: the value set in the field

        Returns:
            the value itself.

        Raises:
            AssertionError: if the length of the field is longer than the
                maximum threshold.
        """
        assert len(str(value)) < STR_FIELD_MAX_LENGTH, (
            "The length of the value for this field can not "
            f"exceed {STR_FIELD_MAX_LENGTH}"
        )
        return value

str_field_max_length_check(value) classmethod

Checks if the length of the value exceeds the maximum str length.

Parameters:

Name Type Description Default
value Any

the value set in the field

required

Returns:

Type Description
Any

the value itself.

Raises:

Type Description
AssertionError

if the length of the field is longer than the maximum threshold.

Source code in src/zenml/models/v2/core/artifact_version.py
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
@field_validator("version")
@classmethod
def str_field_max_length_check(cls, value: Any) -> Any:
    """Checks if the length of the value exceeds the maximum str length.

    Args:
        value: the value set in the field

    Returns:
        the value itself.

    Raises:
        AssertionError: if the length of the field is longer than the
            maximum threshold.
    """
    assert len(str(value)) < STR_FIELD_MAX_LENGTH, (
        "The length of the value for this field can not "
        f"exceed {STR_FIELD_MAX_LENGTH}"
    )
    return value

ArtifactVersionResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for artifact versions.

Source code in src/zenml/models/v2/core/artifact_version.py
233
234
235
236
237
238
239
240
241
242
243
244
245
class ArtifactVersionResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for artifact versions."""

    producer_step_run_id: Optional[UUID] = Field(
        title="ID of the step run that produced this artifact.",
        default=None,
    )
    visualizations: Optional[List["ArtifactVisualizationResponse"]] = Field(
        default=None, title="Visualizations of the artifact."
    )
    run_metadata: Dict[str, MetadataType] = Field(
        default={}, title="Metadata of the artifact."
    )

ArtifactVersionUpdate

Bases: BaseModel

Artifact version update model.

Source code in src/zenml/models/v2/core/artifact_version.py
168
169
170
171
172
173
class ArtifactVersionUpdate(BaseModel):
    """Artifact version update model."""

    name: Optional[str] = None
    add_tags: Optional[List[str]] = None
    remove_tags: Optional[List[str]] = None

ArtifactVisualizationRequest

Bases: BaseRequest

Request model for artifact visualization.

Source code in src/zenml/models/v2/core/artifact_visualization.py
30
31
32
33
34
class ArtifactVisualizationRequest(BaseRequest):
    """Request model for artifact visualization."""

    type: VisualizationType
    uri: str

ArtifactVisualizationResponse

Bases: BaseIdentifiedResponse[ArtifactVisualizationResponseBody, ArtifactVisualizationResponseMetadata, ArtifactVisualizationResponseResources]

Response model for artifact visualizations.

Source code in src/zenml/models/v2/core/artifact_visualization.py
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
class ArtifactVisualizationResponse(
    BaseIdentifiedResponse[
        ArtifactVisualizationResponseBody,
        ArtifactVisualizationResponseMetadata,
        ArtifactVisualizationResponseResources,
    ]
):
    """Response model for artifact visualizations."""

    def get_hydrated_version(self) -> "ArtifactVisualizationResponse":
        """Get the hydrated version of this artifact visualization.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_artifact_visualization(self.id)

    # Body and metadata properties
    @property
    def type(self) -> VisualizationType:
        """The `type` property.

        Returns:
            the value of the property.
        """
        return self.get_body().type

    @property
    def uri(self) -> str:
        """The `uri` property.

        Returns:
            the value of the property.
        """
        return self.get_body().uri

    @property
    def artifact_version_id(self) -> UUID:
        """The `artifact_version_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().artifact_version_id

artifact_version_id property

The artifact_version_id property.

Returns:

Type Description
UUID

the value of the property.

type property

The type property.

Returns:

Type Description
VisualizationType

the value of the property.

uri property

The uri property.

Returns:

Type Description
str

the value of the property.

get_hydrated_version()

Get the hydrated version of this artifact visualization.

Returns:

Type Description
ArtifactVisualizationResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/artifact_visualization.py
70
71
72
73
74
75
76
77
78
def get_hydrated_version(self) -> "ArtifactVisualizationResponse":
    """Get the hydrated version of this artifact visualization.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_artifact_visualization(self.id)

ArtifactVisualizationResponseBody

Bases: BaseDatedResponseBody

Response body for artifact visualizations.

Source code in src/zenml/models/v2/core/artifact_visualization.py
44
45
46
47
48
class ArtifactVisualizationResponseBody(BaseDatedResponseBody):
    """Response body for artifact visualizations."""

    type: VisualizationType
    uri: str

ArtifactVisualizationResponseMetadata

Bases: BaseResponseMetadata

Response metadata model for artifact visualizations.

Source code in src/zenml/models/v2/core/artifact_visualization.py
51
52
53
54
class ArtifactVisualizationResponseMetadata(BaseResponseMetadata):
    """Response metadata model for artifact visualizations."""

    artifact_version_id: UUID

AuthenticationMethodModel

Bases: BaseModel

Authentication method specification.

Describes the schema for the configuration and secrets that need to be provided to configure an authentication method.

Source code in src/zenml/models/v2/misc/service_connector_type.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
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
class AuthenticationMethodModel(BaseModel):
    """Authentication method specification.

    Describes the schema for the configuration and secrets that need to be
    provided to configure an authentication method.
    """

    name: str = Field(
        title="User readable name for the authentication method.",
    )
    auth_method: str = Field(
        title="The name of the authentication method.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    description: str = Field(
        default="",
        title="A description of the authentication method.",
    )
    config_schema: Dict[str, Any] = Field(
        default_factory=dict,
        title="The JSON schema of the configuration for this authentication "
        "method.",
    )
    min_expiration_seconds: Optional[int] = Field(
        default=None,
        title="The minimum number of seconds that the authentication "
        "session can be configured to be valid for. Set to None for "
        "authentication sessions and long-lived credentials that don't expire.",
    )
    max_expiration_seconds: Optional[int] = Field(
        default=None,
        title="The maximum number of seconds that the authentication "
        "session can be configured to be valid for. Set to None for "
        "authentication sessions and long-lived credentials that don't expire.",
    )
    default_expiration_seconds: Optional[int] = Field(
        default=None,
        title="The default number of seconds that the authentication "
        "session is valid for. Set to None for authentication sessions and "
        "long-lived credentials that don't expire.",
    )
    _config_class: Optional[Type[BaseModel]] = None

    def __init__(
        self, config_class: Optional[Type[BaseModel]] = None, **values: Any
    ):
        """Initialize the authentication method.

        Args:
            config_class: The configuration class for the authentication
                method.
            **values: The data to initialize the authentication method with.
        """
        if config_class:
            values["config_schema"] = config_class.model_json_schema()

        super().__init__(**values)
        self._config_class = config_class

    @property
    def config_class(self) -> Optional[Type[BaseModel]]:
        """Get the configuration class for the authentication method.

        Returns:
            The configuration class for the authentication method.
        """
        return self._config_class

    def supports_temporary_credentials(self) -> bool:
        """Check if the authentication method supports temporary credentials.

        Returns:
            True if the authentication method supports temporary credentials,
            False otherwise.
        """
        return (
            self.min_expiration_seconds is not None
            or self.max_expiration_seconds is not None
            or self.default_expiration_seconds is not None
        )

    def validate_expiration(
        self, expiration_seconds: Optional[int]
    ) -> Optional[int]:
        """Validate the expiration time.

        Args:
            expiration_seconds: The expiration time in seconds. If None, the
                default expiration time is used, if applicable.

        Returns:
            The expiration time in seconds or None if not applicable.

        Raises:
            ValueError: If the expiration time is not valid.
        """
        if not self.supports_temporary_credentials():
            if expiration_seconds is not None:
                # Expiration is not supported
                raise ValueError(
                    "Expiration time is not supported for this authentication "
                    f"method but a value was provided: {expiration_seconds}"
                )

            return None

        expiration_seconds = (
            expiration_seconds or self.default_expiration_seconds
        )

        if expiration_seconds is None:
            return None

        if self.min_expiration_seconds is not None:
            if expiration_seconds < self.min_expiration_seconds:
                raise ValueError(
                    f"Expiration time must be at least "
                    f"{self.min_expiration_seconds} seconds."
                )

        if self.max_expiration_seconds is not None:
            if expiration_seconds > self.max_expiration_seconds:
                raise ValueError(
                    f"Expiration time must be at most "
                    f"{self.max_expiration_seconds} seconds."
                )

        return expiration_seconds

config_class property

Get the configuration class for the authentication method.

Returns:

Type Description
Optional[Type[BaseModel]]

The configuration class for the authentication method.

__init__(config_class=None, **values)

Initialize the authentication method.

Parameters:

Name Type Description Default
config_class Optional[Type[BaseModel]]

The configuration class for the authentication method.

None
**values Any

The data to initialize the authentication method with.

{}
Source code in src/zenml/models/v2/misc/service_connector_type.py
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
def __init__(
    self, config_class: Optional[Type[BaseModel]] = None, **values: Any
):
    """Initialize the authentication method.

    Args:
        config_class: The configuration class for the authentication
            method.
        **values: The data to initialize the authentication method with.
    """
    if config_class:
        values["config_schema"] = config_class.model_json_schema()

    super().__init__(**values)
    self._config_class = config_class

supports_temporary_credentials()

Check if the authentication method supports temporary credentials.

Returns:

Type Description
bool

True if the authentication method supports temporary credentials,

bool

False otherwise.

Source code in src/zenml/models/v2/misc/service_connector_type.py
157
158
159
160
161
162
163
164
165
166
167
168
def supports_temporary_credentials(self) -> bool:
    """Check if the authentication method supports temporary credentials.

    Returns:
        True if the authentication method supports temporary credentials,
        False otherwise.
    """
    return (
        self.min_expiration_seconds is not None
        or self.max_expiration_seconds is not None
        or self.default_expiration_seconds is not None
    )

validate_expiration(expiration_seconds)

Validate the expiration time.

Parameters:

Name Type Description Default
expiration_seconds Optional[int]

The expiration time in seconds. If None, the default expiration time is used, if applicable.

required

Returns:

Type Description
Optional[int]

The expiration time in seconds or None if not applicable.

Raises:

Type Description
ValueError

If the expiration time is not valid.

Source code in src/zenml/models/v2/misc/service_connector_type.py
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
def validate_expiration(
    self, expiration_seconds: Optional[int]
) -> Optional[int]:
    """Validate the expiration time.

    Args:
        expiration_seconds: The expiration time in seconds. If None, the
            default expiration time is used, if applicable.

    Returns:
        The expiration time in seconds or None if not applicable.

    Raises:
        ValueError: If the expiration time is not valid.
    """
    if not self.supports_temporary_credentials():
        if expiration_seconds is not None:
            # Expiration is not supported
            raise ValueError(
                "Expiration time is not supported for this authentication "
                f"method but a value was provided: {expiration_seconds}"
            )

        return None

    expiration_seconds = (
        expiration_seconds or self.default_expiration_seconds
    )

    if expiration_seconds is None:
        return None

    if self.min_expiration_seconds is not None:
        if expiration_seconds < self.min_expiration_seconds:
            raise ValueError(
                f"Expiration time must be at least "
                f"{self.min_expiration_seconds} seconds."
            )

    if self.max_expiration_seconds is not None:
        if expiration_seconds > self.max_expiration_seconds:
            raise ValueError(
                f"Expiration time must be at most "
                f"{self.max_expiration_seconds} seconds."
            )

    return expiration_seconds

BaseDatedResponseBody

Bases: BaseResponseBody

Base body model for entities that track a creation and update timestamp.

Used as a base class for all body models associated with responses. Features a creation and update timestamp.

Source code in src/zenml/models/v2/base/base.py
332
333
334
335
336
337
338
339
340
341
342
343
344
class BaseDatedResponseBody(BaseResponseBody):
    """Base body model for entities that track a creation and update timestamp.

    Used as a base class for all body models associated with responses.
    Features a creation and update timestamp.
    """

    created: datetime = Field(
        title="The timestamp when this resource was created."
    )
    updated: datetime = Field(
        title="The timestamp when this resource was last updated."
    )

BaseFilter

Bases: BaseModel

Class to unify all filter, paginate and sort request parameters.

This Model allows fine-grained filtering, sorting and pagination of resources.

Usage example for subclasses of this class:

ResourceListModel(
    name="contains:default",
    workspace="default"
    count_steps="gte:5"
    sort_by="created",
    page=2,
    size=20
)
Source code in src/zenml/models/v2/base/filter.py
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
class BaseFilter(BaseModel):
    """Class to unify all filter, paginate and sort request parameters.

    This Model allows fine-grained filtering, sorting and pagination of
    resources.

    Usage example for subclasses of this class:
    ```
    ResourceListModel(
        name="contains:default",
        workspace="default"
        count_steps="gte:5"
        sort_by="created",
        page=2,
        size=20
    )
    ```
    """

    # List of fields that cannot be used as filters.
    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        "sort_by",
        "page",
        "size",
        "logical_operator",
    ]
    CUSTOM_SORTING_OPTIONS: ClassVar[List[str]] = []

    # List of fields that are not even mentioned as options in the CLI.
    CLI_EXCLUDE_FIELDS: ClassVar[List[str]] = []

    # List of fields that are wrapped with `fastapi.Query(default)` in API.
    API_MULTI_INPUT_PARAMS: ClassVar[List[str]] = []

    sort_by: str = Field(
        default="created", description="Which column to sort by."
    )
    logical_operator: LogicalOperators = Field(
        default=LogicalOperators.AND,
        description="Which logical operator to use between all filters "
        "['and', 'or']",
    )
    page: int = Field(
        default=PAGINATION_STARTING_PAGE, ge=1, description="Page number"
    )
    size: int = Field(
        default=PAGE_SIZE_DEFAULT,
        ge=1,
        le=PAGE_SIZE_MAXIMUM,
        description="Page size",
    )
    id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Id for this resource",
        union_mode="left_to_right",
    )
    created: Optional[Union[datetime, str]] = Field(
        default=None, description="Created", union_mode="left_to_right"
    )
    updated: Optional[Union[datetime, str]] = Field(
        default=None, description="Updated", union_mode="left_to_right"
    )

    _rbac_configuration: Optional[
        Tuple[UUID, Dict[str, Optional[Set[UUID]]]]
    ] = None

    @field_validator("sort_by", mode="before")
    @classmethod
    def validate_sort_by(cls, value: Any) -> Any:
        """Validate that the sort_column is a valid column with a valid operand.

        Args:
            value: The sort_by field value.

        Returns:
            The validated sort_by field value.

        Raises:
            ValidationError: If the sort_by field is not a string.
            ValueError: If the resource can't be sorted by this field.
        """
        # Somehow pydantic allows you to pass in int values, which will be
        #  interpreted as string, however within the validator they are still
        #  integers, which don't have a .split() method
        if not isinstance(value, str):
            raise ValidationError(
                f"str type expected for the sort_by field. "
                f"Received a {type(value)}"
            )
        column = value
        split_value = value.split(":", 1)
        if len(split_value) == 2:
            column = split_value[1]

            if split_value[0] not in SorterOps.values():
                logger.warning(
                    "Invalid operand used for column sorting. "
                    "Only the following operands are supported `%s`. "
                    "Defaulting to 'asc' on column `%s`.",
                    SorterOps.values(),
                    column,
                )
                value = column

        if column in cls.CUSTOM_SORTING_OPTIONS:
            return value
        elif column in cls.FILTER_EXCLUDE_FIELDS:
            raise ValueError(
                f"This resource can not be sorted by this field: '{value}'"
            )
        if column in cls.model_fields:
            return value
        else:
            raise ValueError(
                "You can only sort by valid fields of this resource"
            )

    @model_validator(mode="before")
    @classmethod
    @before_validator_handler
    def filter_ops(cls, data: Dict[str, Any]) -> Dict[str, Any]:
        """Parse incoming filters to ensure all filters are legal.

        Args:
            data: The values of the class.

        Returns:
            The values of the class.
        """
        cls._generate_filter_list(data)
        return data

    @property
    def list_of_filters(self) -> List[Filter]:
        """Converts the class variables into a list of usable Filter Models.

        Returns:
            A list of Filter models.
        """
        return self._generate_filter_list(
            {key: getattr(self, key) for key in self.model_fields}
        )

    @property
    def sorting_params(self) -> Tuple[str, SorterOps]:
        """Converts the class variables into a list of usable Filter Models.

        Returns:
            A tuple of the column to sort by and the sorting operand.
        """
        column = self.sort_by
        # The default sorting operand is asc
        operator = SorterOps.ASCENDING

        # Check if user explicitly set an operand
        split_value = self.sort_by.split(":", 1)
        if len(split_value) == 2:
            column = split_value[1]
            operator = SorterOps(split_value[0])

        return column, operator

    def configure_rbac(
        self,
        authenticated_user_id: UUID,
        **column_allowed_ids: Optional[Set[UUID]],
    ) -> None:
        """Configure RBAC allowed column values.

        Args:
            authenticated_user_id: ID of the authenticated user. All entities
                owned by this user will be included.
            column_allowed_ids: Set of IDs per column to limit the query to.
                If given, the remaining filters will be applied to entities
                within this set only. If `None`, the remaining filters will
                be applied to all entries in the table.
        """
        self._rbac_configuration = (authenticated_user_id, column_allowed_ids)

    def generate_rbac_filter(
        self,
        table: Type["AnySchema"],
    ) -> Optional["ColumnElement[bool]"]:
        """Generates an optional RBAC filter.

        Args:
            table: The query table.

        Returns:
            The RBAC filter.
        """
        from sqlmodel import or_

        if not self._rbac_configuration:
            return None

        expressions = []

        for column_name, allowed_ids in self._rbac_configuration[1].items():
            if allowed_ids is not None:
                expression = getattr(table, column_name).in_(allowed_ids)
                expressions.append(expression)

        if expressions and hasattr(table, "user_id"):
            # If `expressions` is not empty, we do not have full access to all
            # rows of the table. In this case, we also include rows which the
            # user owns.

            # Unowned entities are considered server-owned and can be seen
            # by anyone
            expressions.append(getattr(table, "user_id").is_(None))
            # The authenticated user owns this entity
            expressions.append(
                getattr(table, "user_id") == self._rbac_configuration[0]
            )

        if expressions:
            return or_(*expressions)
        else:
            return None

    @classmethod
    def _generate_filter_list(cls, values: Dict[str, Any]) -> List[Filter]:
        """Create a list of filters from a (column, value) dictionary.

        Args:
            values: A dictionary of column names and values to filter on.

        Returns:
            A list of filters.
        """
        list_of_filters: List[Filter] = []

        for key, value in values.items():
            # Ignore excluded filters
            if key in cls.FILTER_EXCLUDE_FIELDS:
                continue

            # Skip filtering for None values
            if value is None:
                continue

            # Determine the operator and filter value
            value, operator = cls._resolve_operator(value)

            # Define the filter
            filter = FilterGenerator(cls).define_filter(
                column=key, value=value, operator=operator
            )
            list_of_filters.append(filter)

        return list_of_filters

    @staticmethod
    def _resolve_operator(value: Any) -> Tuple[Any, GenericFilterOps]:
        """Determine the operator and filter value from a user-provided value.

        If the user-provided value is a string of the form "operator:value",
        then the operator is extracted and the value is returned. Otherwise,
        `GenericFilterOps.EQUALS` is used as default operator and the value
        is returned as-is.

        Args:
            value: The user-provided value.

        Returns:
            A tuple of the filter value and the operator.

        Raises:
            ValueError: when we try to use the `oneof` operator with the wrong
                value.
        """
        operator = GenericFilterOps.EQUALS  # Default operator
        if isinstance(value, str):
            split_value = value.split(":", 1)
            if (
                len(split_value) == 2
                and split_value[0] in GenericFilterOps.values()
            ):
                value = split_value[1]
                operator = GenericFilterOps(split_value[0])

            if operator == operator.ONEOF:
                try:
                    value = json.loads(value)
                    if not isinstance(value, list):
                        raise ValueError
                except ValueError:
                    raise ValueError(ONEOF_ERROR)

        return value, operator

    def generate_name_or_id_query_conditions(
        self,
        value: Union[UUID, str],
        table: Type["NamedSchema"],
        additional_columns: Optional[List[str]] = None,
    ) -> "ColumnElement[bool]":
        """Generate filter conditions for name or id of a table.

        Args:
            value: The filter value.
            table: The table to filter.
            additional_columns: Additional table columns that should also
                filtered for the given value as part of the or condition.

        Returns:
            The query conditions.
        """
        from sqlmodel import or_

        value, operator = BaseFilter._resolve_operator(value)
        value = str(value)

        conditions = []

        filter_ = FilterGenerator(table).define_filter(
            column="id", value=value, operator=operator
        )
        conditions.append(filter_.generate_query_conditions(table=table))

        filter_ = FilterGenerator(table).define_filter(
            column="name", value=value, operator=operator
        )
        conditions.append(filter_.generate_query_conditions(table=table))

        for column in additional_columns or []:
            filter_ = FilterGenerator(table).define_filter(
                column=column, value=value, operator=operator
            )
            conditions.append(filter_.generate_query_conditions(table=table))

        return or_(*conditions)

    @staticmethod
    def generate_custom_query_conditions_for_column(
        value: Any,
        table: Type[SQLModel],
        column: str,
        json_encode_value: bool = False,
    ) -> "ColumnElement[bool]":
        """Generate custom filter conditions for a column of a table.

        Args:
            value: The filter value.
            table: The table which contains the column.
            column: The column name.
            json_encode_value: Whether to json encode the value.

        Returns:
            The query conditions.
        """
        value, operator = BaseFilter._resolve_operator(value)
        filter_ = FilterGenerator(table).define_filter(
            column=column, value=value, operator=operator
        )
        if isinstance(filter_, StrFilter):
            filter_.json_encode_value = json_encode_value

        return filter_.generate_query_conditions(table=table)

    @property
    def offset(self) -> int:
        """Returns the offset needed for the query on the data persistence layer.

        Returns:
            The offset for the query.
        """
        return self.size * (self.page - 1)

    def generate_filter(
        self, table: Type["AnySchema"]
    ) -> Union["ColumnElement[bool]"]:
        """Generate the filter for the query.

        Args:
            table: The Table that is being queried from.

        Returns:
            The filter expression for the query.

        Raises:
            RuntimeError: If a valid logical operator is not supplied.
        """
        from sqlmodel import and_, or_

        filters = []
        for column_filter in self.list_of_filters:
            filters.append(
                column_filter.generate_query_conditions(table=table)
            )
        for custom_filter in self.get_custom_filters(table):
            filters.append(custom_filter)
        if self.logical_operator == LogicalOperators.OR:
            return or_(False, *filters)
        elif self.logical_operator == LogicalOperators.AND:
            return and_(True, *filters)
        else:
            raise RuntimeError("No valid logical operator was supplied.")

    def get_custom_filters(
        self, table: Type["AnySchema"]
    ) -> List["ColumnElement[bool]"]:
        """Get custom filters.

        This can be overridden by subclasses to define custom filters that are
        not based on the columns of the underlying table.

        Args:
            table: The query table.

        Returns:
            A list of custom filters.
        """
        return []

    def apply_filter(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Applies the filter to a query.

        Args:
            query: The query to which to apply the filter.
            table: The query table.

        Returns:
            The query with filter applied.
        """
        rbac_filter = self.generate_rbac_filter(table=table)

        if rbac_filter is not None:
            query = query.where(rbac_filter)

        filters = self.generate_filter(table=table)

        if filters is not None:
            query = query.where(filters)

        return query

    def apply_sorting(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Apply sorting to the query.

        Args:
            query: The query to which to apply the sorting.
            table: The query table.

        Returns:
            The query with sorting applied.
        """
        column, operand = self.sorting_params

        if operand == SorterOps.DESCENDING:
            sort_clause = desc(getattr(table, column))  # type: ignore[var-annotated]
        else:
            sort_clause = asc(getattr(table, column))

        # We always add the `id` column as a tiebreaker to ensure a stable,
        # repeatable order of items, otherwise subsequent pages might contain
        # the same items.
        query = query.order_by(sort_clause, asc(table.id))  # type: ignore[arg-type]

        return query

list_of_filters property

Converts the class variables into a list of usable Filter Models.

Returns:

Type Description
List[Filter]

A list of Filter models.

offset property

Returns the offset needed for the query on the data persistence layer.

Returns:

Type Description
int

The offset for the query.

sorting_params property

Converts the class variables into a list of usable Filter Models.

Returns:

Type Description
Tuple[str, SorterOps]

A tuple of the column to sort by and the sorting operand.

apply_filter(query, table)

Applies the filter to a query.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the filter.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with filter applied.

Source code in src/zenml/models/v2/base/filter.py
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
def apply_filter(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Applies the filter to a query.

    Args:
        query: The query to which to apply the filter.
        table: The query table.

    Returns:
        The query with filter applied.
    """
    rbac_filter = self.generate_rbac_filter(table=table)

    if rbac_filter is not None:
        query = query.where(rbac_filter)

    filters = self.generate_filter(table=table)

    if filters is not None:
        query = query.where(filters)

    return query

apply_sorting(query, table)

Apply sorting to the query.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the sorting.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with sorting applied.

Source code in src/zenml/models/v2/base/filter.py
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
def apply_sorting(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Apply sorting to the query.

    Args:
        query: The query to which to apply the sorting.
        table: The query table.

    Returns:
        The query with sorting applied.
    """
    column, operand = self.sorting_params

    if operand == SorterOps.DESCENDING:
        sort_clause = desc(getattr(table, column))  # type: ignore[var-annotated]
    else:
        sort_clause = asc(getattr(table, column))

    # We always add the `id` column as a tiebreaker to ensure a stable,
    # repeatable order of items, otherwise subsequent pages might contain
    # the same items.
    query = query.order_by(sort_clause, asc(table.id))  # type: ignore[arg-type]

    return query

configure_rbac(authenticated_user_id, **column_allowed_ids)

Configure RBAC allowed column values.

Parameters:

Name Type Description Default
authenticated_user_id UUID

ID of the authenticated user. All entities owned by this user will be included.

required
column_allowed_ids Optional[Set[UUID]]

Set of IDs per column to limit the query to. If given, the remaining filters will be applied to entities within this set only. If None, the remaining filters will be applied to all entries in the table.

{}
Source code in src/zenml/models/v2/base/filter.py
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
def configure_rbac(
    self,
    authenticated_user_id: UUID,
    **column_allowed_ids: Optional[Set[UUID]],
) -> None:
    """Configure RBAC allowed column values.

    Args:
        authenticated_user_id: ID of the authenticated user. All entities
            owned by this user will be included.
        column_allowed_ids: Set of IDs per column to limit the query to.
            If given, the remaining filters will be applied to entities
            within this set only. If `None`, the remaining filters will
            be applied to all entries in the table.
    """
    self._rbac_configuration = (authenticated_user_id, column_allowed_ids)

filter_ops(data) classmethod

Parse incoming filters to ensure all filters are legal.

Parameters:

Name Type Description Default
data Dict[str, Any]

The values of the class.

required

Returns:

Type Description
Dict[str, Any]

The values of the class.

Source code in src/zenml/models/v2/base/filter.py
532
533
534
535
536
537
538
539
540
541
542
543
544
545
@model_validator(mode="before")
@classmethod
@before_validator_handler
def filter_ops(cls, data: Dict[str, Any]) -> Dict[str, Any]:
    """Parse incoming filters to ensure all filters are legal.

    Args:
        data: The values of the class.

    Returns:
        The values of the class.
    """
    cls._generate_filter_list(data)
    return data

generate_custom_query_conditions_for_column(value, table, column, json_encode_value=False) staticmethod

Generate custom filter conditions for a column of a table.

Parameters:

Name Type Description Default
value Any

The filter value.

required
table Type[SQLModel]

The table which contains the column.

required
column str

The column name.

required
json_encode_value bool

Whether to json encode the value.

False

Returns:

Type Description
ColumnElement[bool]

The query conditions.

Source code in src/zenml/models/v2/base/filter.py
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
@staticmethod
def generate_custom_query_conditions_for_column(
    value: Any,
    table: Type[SQLModel],
    column: str,
    json_encode_value: bool = False,
) -> "ColumnElement[bool]":
    """Generate custom filter conditions for a column of a table.

    Args:
        value: The filter value.
        table: The table which contains the column.
        column: The column name.
        json_encode_value: Whether to json encode the value.

    Returns:
        The query conditions.
    """
    value, operator = BaseFilter._resolve_operator(value)
    filter_ = FilterGenerator(table).define_filter(
        column=column, value=value, operator=operator
    )
    if isinstance(filter_, StrFilter):
        filter_.json_encode_value = json_encode_value

    return filter_.generate_query_conditions(table=table)

generate_filter(table)

Generate the filter for the query.

Parameters:

Name Type Description Default
table Type[AnySchema]

The Table that is being queried from.

required

Returns:

Type Description
Union[ColumnElement[bool]]

The filter expression for the query.

Raises:

Type Description
RuntimeError

If a valid logical operator is not supplied.

Source code in src/zenml/models/v2/base/filter.py
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
def generate_filter(
    self, table: Type["AnySchema"]
) -> Union["ColumnElement[bool]"]:
    """Generate the filter for the query.

    Args:
        table: The Table that is being queried from.

    Returns:
        The filter expression for the query.

    Raises:
        RuntimeError: If a valid logical operator is not supplied.
    """
    from sqlmodel import and_, or_

    filters = []
    for column_filter in self.list_of_filters:
        filters.append(
            column_filter.generate_query_conditions(table=table)
        )
    for custom_filter in self.get_custom_filters(table):
        filters.append(custom_filter)
    if self.logical_operator == LogicalOperators.OR:
        return or_(False, *filters)
    elif self.logical_operator == LogicalOperators.AND:
        return and_(True, *filters)
    else:
        raise RuntimeError("No valid logical operator was supplied.")

generate_name_or_id_query_conditions(value, table, additional_columns=None)

Generate filter conditions for name or id of a table.

Parameters:

Name Type Description Default
value Union[UUID, str]

The filter value.

required
table Type[NamedSchema]

The table to filter.

required
additional_columns Optional[List[str]]

Additional table columns that should also filtered for the given value as part of the or condition.

None

Returns:

Type Description
ColumnElement[bool]

The query conditions.

Source code in src/zenml/models/v2/base/filter.py
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
def generate_name_or_id_query_conditions(
    self,
    value: Union[UUID, str],
    table: Type["NamedSchema"],
    additional_columns: Optional[List[str]] = None,
) -> "ColumnElement[bool]":
    """Generate filter conditions for name or id of a table.

    Args:
        value: The filter value.
        table: The table to filter.
        additional_columns: Additional table columns that should also
            filtered for the given value as part of the or condition.

    Returns:
        The query conditions.
    """
    from sqlmodel import or_

    value, operator = BaseFilter._resolve_operator(value)
    value = str(value)

    conditions = []

    filter_ = FilterGenerator(table).define_filter(
        column="id", value=value, operator=operator
    )
    conditions.append(filter_.generate_query_conditions(table=table))

    filter_ = FilterGenerator(table).define_filter(
        column="name", value=value, operator=operator
    )
    conditions.append(filter_.generate_query_conditions(table=table))

    for column in additional_columns or []:
        filter_ = FilterGenerator(table).define_filter(
            column=column, value=value, operator=operator
        )
        conditions.append(filter_.generate_query_conditions(table=table))

    return or_(*conditions)

generate_rbac_filter(table)

Generates an optional RBAC filter.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
Optional[ColumnElement[bool]]

The RBAC filter.

Source code in src/zenml/models/v2/base/filter.py
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
def generate_rbac_filter(
    self,
    table: Type["AnySchema"],
) -> Optional["ColumnElement[bool]"]:
    """Generates an optional RBAC filter.

    Args:
        table: The query table.

    Returns:
        The RBAC filter.
    """
    from sqlmodel import or_

    if not self._rbac_configuration:
        return None

    expressions = []

    for column_name, allowed_ids in self._rbac_configuration[1].items():
        if allowed_ids is not None:
            expression = getattr(table, column_name).in_(allowed_ids)
            expressions.append(expression)

    if expressions and hasattr(table, "user_id"):
        # If `expressions` is not empty, we do not have full access to all
        # rows of the table. In this case, we also include rows which the
        # user owns.

        # Unowned entities are considered server-owned and can be seen
        # by anyone
        expressions.append(getattr(table, "user_id").is_(None))
        # The authenticated user owns this entity
        expressions.append(
            getattr(table, "user_id") == self._rbac_configuration[0]
        )

    if expressions:
        return or_(*expressions)
    else:
        return None

get_custom_filters(table)

Get custom filters.

This can be overridden by subclasses to define custom filters that are not based on the columns of the underlying table.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
List[ColumnElement[bool]]

A list of custom filters.

Source code in src/zenml/models/v2/base/filter.py
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
def get_custom_filters(
    self, table: Type["AnySchema"]
) -> List["ColumnElement[bool]"]:
    """Get custom filters.

    This can be overridden by subclasses to define custom filters that are
    not based on the columns of the underlying table.

    Args:
        table: The query table.

    Returns:
        A list of custom filters.
    """
    return []

validate_sort_by(value) classmethod

Validate that the sort_column is a valid column with a valid operand.

Parameters:

Name Type Description Default
value Any

The sort_by field value.

required

Returns:

Type Description
Any

The validated sort_by field value.

Raises:

Type Description
ValidationError

If the sort_by field is not a string.

ValueError

If the resource can't be sorted by this field.

Source code in src/zenml/models/v2/base/filter.py
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
@field_validator("sort_by", mode="before")
@classmethod
def validate_sort_by(cls, value: Any) -> Any:
    """Validate that the sort_column is a valid column with a valid operand.

    Args:
        value: The sort_by field value.

    Returns:
        The validated sort_by field value.

    Raises:
        ValidationError: If the sort_by field is not a string.
        ValueError: If the resource can't be sorted by this field.
    """
    # Somehow pydantic allows you to pass in int values, which will be
    #  interpreted as string, however within the validator they are still
    #  integers, which don't have a .split() method
    if not isinstance(value, str):
        raise ValidationError(
            f"str type expected for the sort_by field. "
            f"Received a {type(value)}"
        )
    column = value
    split_value = value.split(":", 1)
    if len(split_value) == 2:
        column = split_value[1]

        if split_value[0] not in SorterOps.values():
            logger.warning(
                "Invalid operand used for column sorting. "
                "Only the following operands are supported `%s`. "
                "Defaulting to 'asc' on column `%s`.",
                SorterOps.values(),
                column,
            )
            value = column

    if column in cls.CUSTOM_SORTING_OPTIONS:
        return value
    elif column in cls.FILTER_EXCLUDE_FIELDS:
        raise ValueError(
            f"This resource can not be sorted by this field: '{value}'"
        )
    if column in cls.model_fields:
        return value
    else:
        raise ValueError(
            "You can only sort by valid fields of this resource"
        )

BaseIdentifiedResponse

Bases: BaseResponse[AnyDatedBody, AnyMetadata, AnyResources], Generic[AnyDatedBody, AnyMetadata, AnyResources]

Base domain model for resources with DB representation.

Source code in src/zenml/models/v2/base/base.py
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
class BaseIdentifiedResponse(
    BaseResponse[AnyDatedBody, AnyMetadata, AnyResources],
    Generic[AnyDatedBody, AnyMetadata, AnyResources],
):
    """Base domain model for resources with DB representation."""

    id: UUID = Field(title="The unique resource id.")

    permission_denied: bool = False

    # Helper functions
    def __hash__(self) -> int:
        """Implementation of hash magic method.

        Returns:
            Hash of the UUID.
        """
        return hash((type(self),) + tuple([self.id]))

    def __eq__(self, other: Any) -> bool:
        """Implementation of equality magic method.

        Args:
            other: The other object to compare to.

        Returns:
            True if the other object is of the same type and has the same UUID.
        """
        if isinstance(other, type(self)):
            return self.id == other.id
        else:
            return False

    def _validate_hydrated_version(
        self,
        hydrated_model: "BaseResponse[AnyDatedBody, AnyMetadata, AnyResources]",
    ) -> None:
        """Helper method to validate the values within the hydrated version.

        Args:
            hydrated_model: the hydrated version of the model.

        Raises:
            HydrationError: if the hydrated version has different values set
                for either the name of the body fields and the
                _method_body_mutation is set to ResponseBodyUpdate.DENY.
        """
        super()._validate_hydrated_version(hydrated_model)

        assert isinstance(hydrated_model, type(self))

        # Check if the ID is the same
        if self.id != hydrated_model.id:
            raise HydrationError(
                "The hydrated version of the model does not have the same id."
            )

    def get_hydrated_version(
        self,
    ) -> "BaseIdentifiedResponse[AnyDatedBody, AnyMetadata, AnyResources]":
        """Abstract method to fetch the hydrated version of the model.

        Raises:
            NotImplementedError: in case the method is not implemented.
        """
        raise NotImplementedError(
            "Please implement a `get_hydrated_version` method before "
            "using/hydrating the model."
        )

    def get_body(self) -> "AnyDatedBody":
        """Fetch the body of the entity.

        Returns:
            The body field of the response.

        Raises:
            IllegalOperationError: If the user lacks permission to access the
                entity represented by this response.
        """
        if self.permission_denied:
            raise IllegalOperationError(
                f"Missing permissions to access {type(self).__name__} with "
                f"ID {self.id}."
            )

        return super().get_body()

    def get_metadata(self) -> "AnyMetadata":
        """Fetch the metadata of the entity.

        Returns:
            The metadata field of the response.

        Raises:
            IllegalOperationError: If the user lacks permission to access this
                entity represented by this response.
        """
        if self.permission_denied:
            raise IllegalOperationError(
                f"Missing permissions to access {type(self).__name__} with "
                f"ID {self.id}."
            )

        return super().get_metadata()

    # Analytics
    def get_analytics_metadata(self) -> Dict[str, Any]:
        """Fetches the analytics metadata for base response models.

        Returns:
            The analytics metadata.
        """
        metadata = super().get_analytics_metadata()
        metadata["entity_id"] = self.id
        return metadata

    # Body and metadata properties
    @property
    def created(self) -> datetime:
        """The `created` property.

        Returns:
            the value of the property.
        """
        return self.get_body().created

    @property
    def updated(self) -> datetime:
        """The `updated` property.

        Returns:
            the value of the property.
        """
        return self.get_body().updated

created property

The created property.

Returns:

Type Description
datetime

the value of the property.

updated property

The updated property.

Returns:

Type Description
datetime

the value of the property.

__eq__(other)

Implementation of equality magic method.

Parameters:

Name Type Description Default
other Any

The other object to compare to.

required

Returns:

Type Description
bool

True if the other object is of the same type and has the same UUID.

Source code in src/zenml/models/v2/base/base.py
369
370
371
372
373
374
375
376
377
378
379
380
381
def __eq__(self, other: Any) -> bool:
    """Implementation of equality magic method.

    Args:
        other: The other object to compare to.

    Returns:
        True if the other object is of the same type and has the same UUID.
    """
    if isinstance(other, type(self)):
        return self.id == other.id
    else:
        return False

__hash__()

Implementation of hash magic method.

Returns:

Type Description
int

Hash of the UUID.

Source code in src/zenml/models/v2/base/base.py
361
362
363
364
365
366
367
def __hash__(self) -> int:
    """Implementation of hash magic method.

    Returns:
        Hash of the UUID.
    """
    return hash((type(self),) + tuple([self.id]))

get_analytics_metadata()

Fetches the analytics metadata for base response models.

Returns:

Type Description
Dict[str, Any]

The analytics metadata.

Source code in src/zenml/models/v2/base/base.py
457
458
459
460
461
462
463
464
465
def get_analytics_metadata(self) -> Dict[str, Any]:
    """Fetches the analytics metadata for base response models.

    Returns:
        The analytics metadata.
    """
    metadata = super().get_analytics_metadata()
    metadata["entity_id"] = self.id
    return metadata

get_body()

Fetch the body of the entity.

Returns:

Type Description
AnyDatedBody

The body field of the response.

Raises:

Type Description
IllegalOperationError

If the user lacks permission to access the entity represented by this response.

Source code in src/zenml/models/v2/base/base.py
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
def get_body(self) -> "AnyDatedBody":
    """Fetch the body of the entity.

    Returns:
        The body field of the response.

    Raises:
        IllegalOperationError: If the user lacks permission to access the
            entity represented by this response.
    """
    if self.permission_denied:
        raise IllegalOperationError(
            f"Missing permissions to access {type(self).__name__} with "
            f"ID {self.id}."
        )

    return super().get_body()

get_hydrated_version()

Abstract method to fetch the hydrated version of the model.

Raises:

Type Description
NotImplementedError

in case the method is not implemented.

Source code in src/zenml/models/v2/base/base.py
407
408
409
410
411
412
413
414
415
416
417
418
def get_hydrated_version(
    self,
) -> "BaseIdentifiedResponse[AnyDatedBody, AnyMetadata, AnyResources]":
    """Abstract method to fetch the hydrated version of the model.

    Raises:
        NotImplementedError: in case the method is not implemented.
    """
    raise NotImplementedError(
        "Please implement a `get_hydrated_version` method before "
        "using/hydrating the model."
    )

get_metadata()

Fetch the metadata of the entity.

Returns:

Type Description
AnyMetadata

The metadata field of the response.

Raises:

Type Description
IllegalOperationError

If the user lacks permission to access this entity represented by this response.

Source code in src/zenml/models/v2/base/base.py
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
def get_metadata(self) -> "AnyMetadata":
    """Fetch the metadata of the entity.

    Returns:
        The metadata field of the response.

    Raises:
        IllegalOperationError: If the user lacks permission to access this
            entity represented by this response.
    """
    if self.permission_denied:
        raise IllegalOperationError(
            f"Missing permissions to access {type(self).__name__} with "
            f"ID {self.id}."
        )

    return super().get_metadata()

BasePluginFlavorResponse

Bases: BaseResponse[AnyPluginBody, AnyPluginMetadata, AnyPluginResources], Generic[AnyPluginBody, AnyPluginMetadata, AnyPluginResources]

Base response for all Plugin Flavors.

Source code in src/zenml/models/v2/base/base_plugin_flavor.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
class BasePluginFlavorResponse(
    BaseResponse[AnyPluginBody, AnyPluginMetadata, AnyPluginResources],
    Generic[AnyPluginBody, AnyPluginMetadata, AnyPluginResources],
):
    """Base response for all Plugin Flavors."""

    name: str = Field(title="Name of the flavor.")
    type: PluginType = Field(title="Type of the plugin.")
    subtype: PluginSubType = Field(title="Subtype of the plugin.")
    model_config = ConfigDict(extra="ignore")

    def get_hydrated_version(
        self,
    ) -> "BasePluginFlavorResponse[AnyPluginBody, AnyPluginMetadata, AnyPluginResources]":
        """Abstract method to fetch the hydrated version of the model.

        Returns:
            Hydrated version of the PluginFlavorResponse
        """
        # TODO: shouldn't this call the Zen store ? The client should not have
        #  to know about the plugin flavor registry
        from zenml.zen_server.utils import plugin_flavor_registry

        plugin_flavor = plugin_flavor_registry().get_flavor_class(
            name=self.name, _type=self.type, subtype=self.subtype
        )
        return plugin_flavor.get_flavor_response_model(hydrate=True)

get_hydrated_version()

Abstract method to fetch the hydrated version of the model.

Returns:

Type Description
BasePluginFlavorResponse[AnyPluginBody, AnyPluginMetadata, AnyPluginResources]

Hydrated version of the PluginFlavorResponse

Source code in src/zenml/models/v2/base/base_plugin_flavor.py
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
def get_hydrated_version(
    self,
) -> "BasePluginFlavorResponse[AnyPluginBody, AnyPluginMetadata, AnyPluginResources]":
    """Abstract method to fetch the hydrated version of the model.

    Returns:
        Hydrated version of the PluginFlavorResponse
    """
    # TODO: shouldn't this call the Zen store ? The client should not have
    #  to know about the plugin flavor registry
    from zenml.zen_server.utils import plugin_flavor_registry

    plugin_flavor = plugin_flavor_registry().get_flavor_class(
        name=self.name, _type=self.type, subtype=self.subtype
    )
    return plugin_flavor.get_flavor_response_model(hydrate=True)

BaseRequest

Bases: BaseZenModel

Base request model.

Used as a base class for all request models.

Source code in src/zenml/models/v2/base/base.py
52
53
54
55
56
class BaseRequest(BaseZenModel):
    """Base request model.

    Used as a base class for all request models.
    """

BaseResponse

Bases: BaseZenModel, Generic[AnyBody, AnyMetadata, AnyResources]

Base domain model for all responses.

Source code in src/zenml/models/v2/base/base.py
102
103
104
105
106
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
class BaseResponse(BaseZenModel, Generic[AnyBody, AnyMetadata, AnyResources]):
    """Base domain model for all responses."""

    # Body and metadata pair
    body: Optional["AnyBody"] = Field(
        default=None, title="The body of the resource."
    )
    metadata: Optional["AnyMetadata"] = Field(
        default=None, title="The metadata related to this resource."
    )
    resources: Optional["AnyResources"] = Field(
        default=None, title="The resources related to this resource."
    )

    _response_update_strategy: ResponseUpdateStrategy = (
        ResponseUpdateStrategy.ALLOW
    )
    _warn_on_response_updates: bool = True

    def _validate_hydrated_version(
        self,
        hydrated_model: "BaseResponse[AnyBody, AnyMetadata, AnyResources]",
    ) -> None:
        """Helper method to validate the values within the hydrated version.

        Args:
            hydrated_model: the hydrated version of the model.

        Raises:
            HydrationError: if the hydrated version has different values set
                for either the name of the body fields and the
                _method_body_mutation is set to ResponseBodyUpdate.DENY.
        """
        # Check whether the metadata exists in the hydrated version
        if hydrated_model.metadata is None:
            raise HydrationError(
                "The hydrated model does not have a metadata field."
            )

        # Check if the name has changed
        if "name" in self.model_fields:
            original_name = getattr(self, "name")
            hydrated_name = getattr(hydrated_model, "name")

            if original_name != hydrated_name:
                if (
                    self._response_update_strategy
                    == ResponseUpdateStrategy.ALLOW
                ):
                    setattr(self, "name", hydrated_name)

                    if self._warn_on_response_updates:
                        logger.warning(
                            f"The name of the entity has changed from "
                            f"`{original_name}` to `{hydrated_name}`."
                        )

                elif (
                    self._response_update_strategy
                    == ResponseUpdateStrategy.IGNORE
                ):
                    if self._warn_on_response_updates:
                        logger.warning(
                            f"Ignoring the name change in the hydrated version "
                            f"of the response: `{original_name}` to "
                            f"`{hydrated_name}`."
                        )
                elif (
                    self._response_update_strategy
                    == ResponseUpdateStrategy.DENY
                ):
                    raise HydrationError(
                        f"Failing the hydration, because there is a change in "
                        f"the name of the entity: `{original_name}` to "
                        f"`{hydrated_name}`."
                    )

        # Check all the fields in the body
        for field in self.get_body().model_fields:
            original_value = getattr(self.get_body(), field)
            hydrated_value = getattr(hydrated_model.get_body(), field)

            if original_value != hydrated_value:
                if (
                    self._response_update_strategy
                    == ResponseUpdateStrategy.ALLOW
                ):
                    setattr(self.get_body(), field, hydrated_value)

                    if self._warn_on_response_updates:
                        logger.warning(
                            f"The field `{field}` in the body of the response "
                            f"has changed from `{original_value}` to "
                            f"`{hydrated_value}`."
                        )

                elif (
                    self._response_update_strategy
                    == ResponseUpdateStrategy.IGNORE
                ):
                    if self._warn_on_response_updates:
                        logger.warning(
                            f"Ignoring the change in the hydrated version of "
                            f"the field `{field}`: `{original_value}` -> "
                            f"`{hydrated_value}`."
                        )
                elif (
                    self._response_update_strategy
                    == ResponseUpdateStrategy.DENY
                ):
                    raise HydrationError(
                        f"Failing the hydration, because there is a change in "
                        f"the field `{field}`: `{original_value}` -> "
                        f"`{hydrated_value}`"
                    )

    def hydrate(self) -> None:
        """Hydrate the response."""
        hydrated_version = self.get_hydrated_version()
        self._validate_hydrated_version(hydrated_version)

        self.resources = hydrated_version.resources
        self.metadata = hydrated_version.metadata

    def get_hydrated_version(
        self,
    ) -> "BaseResponse[AnyBody, AnyMetadata, AnyResources]":
        """Abstract method to fetch the hydrated version of the model.

        Raises:
            NotImplementedError: in case the method is not implemented.
        """
        raise NotImplementedError(
            "Please implement a `get_hydrated_version` method before "
            "using/hydrating the model."
        )

    def get_body(self) -> "AnyBody":
        """Fetch the body of the entity.

        Returns:
            The body field of the response.

        Raises:
            RuntimeError: If the body was not included in the response.
        """
        if not self.body:
            raise RuntimeError(
                f"Missing response body for {type(self).__name__}."
            )

        return self.body

    def get_metadata(self) -> "AnyMetadata":
        """Fetch the metadata of the entity.

        Returns:
            The metadata field of the response.
        """
        if self.metadata is None:
            # If the metadata is not there, check the class first.
            metadata_annotation = self.model_fields["metadata"].annotation
            assert metadata_annotation is not None, (
                "For each response model, an annotated metadata"
                "field should exist."
            )

            # metadata is defined as:
            #   metadata: Optional[....ResponseMetadata] = Field(default=None)
            # We need to find the actual class inside the Optional annotation.
            from zenml.utils.typing_utils import get_args

            metadata_type = get_args(metadata_annotation)[0]
            assert issubclass(metadata_type, BaseResponseMetadata)

            if len(metadata_type.model_fields):
                # If the metadata class defines any fields, fetch the metadata
                # through the hydrated version.
                self.hydrate()
            else:
                # Otherwise, use the metadata class to create an empty metadata
                # object.
                self.metadata = metadata_type()

        assert self.metadata is not None

        return self.metadata

    def get_resources(self) -> "AnyResources":
        """Fetch the resources related to this entity.

        Returns:
            The resources field of the response.

        Raises:
            RuntimeError: If the resources field was not included in the response.
        """
        if self.resources is None:
            # If the resources are not there, check the class first.
            resources_annotation = self.model_fields["resources"].annotation
            assert resources_annotation is not None, (
                "For each response model, an annotated resources"
                "field should exist."
            )

            # resources is defined as:
            #   resources: Optional[....ResponseResources] = Field(default=None)
            # We need to find the actual class inside the Optional annotation.
            from zenml.utils.typing_utils import get_args

            resources_type = get_args(resources_annotation)[0]
            assert issubclass(resources_type, BaseResponseResources)

            if len(resources_type.model_fields):
                # If the resources class defines any fields, fetch the resources
                # through the hydrated version.
                self.hydrate()
            else:
                # Otherwise, use the resources class to create an empty
                # resources object.
                self.resources = resources_type()

        if self.resources is None:
            raise RuntimeError(
                f"Missing response resources for {type(self).__name__}."
            )

        return self.resources

get_body()

Fetch the body of the entity.

Returns:

Type Description
AnyBody

The body field of the response.

Raises:

Type Description
RuntimeError

If the body was not included in the response.

Source code in src/zenml/models/v2/base/base.py
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
def get_body(self) -> "AnyBody":
    """Fetch the body of the entity.

    Returns:
        The body field of the response.

    Raises:
        RuntimeError: If the body was not included in the response.
    """
    if not self.body:
        raise RuntimeError(
            f"Missing response body for {type(self).__name__}."
        )

    return self.body

get_hydrated_version()

Abstract method to fetch the hydrated version of the model.

Raises:

Type Description
NotImplementedError

in case the method is not implemented.

Source code in src/zenml/models/v2/base/base.py
226
227
228
229
230
231
232
233
234
235
236
237
def get_hydrated_version(
    self,
) -> "BaseResponse[AnyBody, AnyMetadata, AnyResources]":
    """Abstract method to fetch the hydrated version of the model.

    Raises:
        NotImplementedError: in case the method is not implemented.
    """
    raise NotImplementedError(
        "Please implement a `get_hydrated_version` method before "
        "using/hydrating the model."
    )

get_metadata()

Fetch the metadata of the entity.

Returns:

Type Description
AnyMetadata

The metadata field of the response.

Source code in src/zenml/models/v2/base/base.py
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
287
288
def get_metadata(self) -> "AnyMetadata":
    """Fetch the metadata of the entity.

    Returns:
        The metadata field of the response.
    """
    if self.metadata is None:
        # If the metadata is not there, check the class first.
        metadata_annotation = self.model_fields["metadata"].annotation
        assert metadata_annotation is not None, (
            "For each response model, an annotated metadata"
            "field should exist."
        )

        # metadata is defined as:
        #   metadata: Optional[....ResponseMetadata] = Field(default=None)
        # We need to find the actual class inside the Optional annotation.
        from zenml.utils.typing_utils import get_args

        metadata_type = get_args(metadata_annotation)[0]
        assert issubclass(metadata_type, BaseResponseMetadata)

        if len(metadata_type.model_fields):
            # If the metadata class defines any fields, fetch the metadata
            # through the hydrated version.
            self.hydrate()
        else:
            # Otherwise, use the metadata class to create an empty metadata
            # object.
            self.metadata = metadata_type()

    assert self.metadata is not None

    return self.metadata

get_resources()

Fetch the resources related to this entity.

Returns:

Type Description
AnyResources

The resources field of the response.

Raises:

Type Description
RuntimeError

If the resources field was not included in the response.

Source code in src/zenml/models/v2/base/base.py
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
def get_resources(self) -> "AnyResources":
    """Fetch the resources related to this entity.

    Returns:
        The resources field of the response.

    Raises:
        RuntimeError: If the resources field was not included in the response.
    """
    if self.resources is None:
        # If the resources are not there, check the class first.
        resources_annotation = self.model_fields["resources"].annotation
        assert resources_annotation is not None, (
            "For each response model, an annotated resources"
            "field should exist."
        )

        # resources is defined as:
        #   resources: Optional[....ResponseResources] = Field(default=None)
        # We need to find the actual class inside the Optional annotation.
        from zenml.utils.typing_utils import get_args

        resources_type = get_args(resources_annotation)[0]
        assert issubclass(resources_type, BaseResponseResources)

        if len(resources_type.model_fields):
            # If the resources class defines any fields, fetch the resources
            # through the hydrated version.
            self.hydrate()
        else:
            # Otherwise, use the resources class to create an empty
            # resources object.
            self.resources = resources_type()

    if self.resources is None:
        raise RuntimeError(
            f"Missing response resources for {type(self).__name__}."
        )

    return self.resources

hydrate()

Hydrate the response.

Source code in src/zenml/models/v2/base/base.py
218
219
220
221
222
223
224
def hydrate(self) -> None:
    """Hydrate the response."""
    hydrated_version = self.get_hydrated_version()
    self._validate_hydrated_version(hydrated_version)

    self.resources = hydrated_version.resources
    self.metadata = hydrated_version.metadata

BaseResponseBody

Bases: BaseZenModel

Base body model.

Source code in src/zenml/models/v2/base/base.py
77
78
class BaseResponseBody(BaseZenModel):
    """Base body model."""

BaseResponseMetadata

Bases: BaseZenModel

Base metadata model.

Used as a base class for all metadata models associated with responses.

Source code in src/zenml/models/v2/base/base.py
81
82
83
84
85
class BaseResponseMetadata(BaseZenModel):
    """Base metadata model.

    Used as a base class for all metadata models associated with responses.
    """

BaseResponseResources

Bases: BaseZenModel

Base resources model.

Used as a base class for all resource models associated with responses.

Source code in src/zenml/models/v2/base/base.py
88
89
90
91
92
93
94
class BaseResponseResources(BaseZenModel):
    """Base resources model.

    Used as a base class for all resource models associated with responses.
    """

    model_config = ConfigDict(extra="allow")

BaseUpdate

Bases: BaseZenModel

Base update model.

Used as a base class for all update models.

Source code in src/zenml/models/v2/base/base.py
62
63
64
65
66
67
68
69
70
71
class BaseUpdate(BaseZenModel):
    """Base update model.

    Used as a base class for all update models.
    """

    model_config = ConfigDict(
        # Ignore extras on all update models.
        extra="ignore",
    )

BaseZenModel

Bases: YAMLSerializationMixin, AnalyticsTrackedModelMixin

Base model class for all ZenML models.

This class is used as a base class for all ZenML models. It provides functionality for tracking analytics events.

Source code in src/zenml/models/v2/base/base.py
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class BaseZenModel(YAMLSerializationMixin, AnalyticsTrackedModelMixin):
    """Base model class for all ZenML models.

    This class is used as a base class for all ZenML models. It provides
    functionality for tracking analytics events.
    """

    model_config = ConfigDict(
        # Ignore extras on all models to support forwards and backwards
        # compatibility (e.g. new fields in newer versions of ZenML servers
        # are allowed to be passed to older versions of ZenML clients and
        # vice versa but will be ignored).
        extra="ignore",
    )

BoolFilter

Bases: Filter

Filter for all Boolean fields.

Source code in src/zenml/models/v2/base/filter.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
class BoolFilter(Filter):
    """Filter for all Boolean fields."""

    ALLOWED_OPS: ClassVar[List[str]] = [
        GenericFilterOps.EQUALS,
        GenericFilterOps.NOT_EQUALS,
    ]

    def generate_query_conditions_from_column(self, column: Any) -> Any:
        """Generate query conditions for a boolean column.

        Args:
            column: The boolean column of an SQLModel table on which to filter.

        Returns:
            A list of query conditions.
        """
        if self.operation == GenericFilterOps.NOT_EQUALS:
            return column != self.value

        return column == self.value

generate_query_conditions_from_column(column)

Generate query conditions for a boolean column.

Parameters:

Name Type Description Default
column Any

The boolean column of an SQLModel table on which to filter.

required

Returns:

Type Description
Any

A list of query conditions.

Source code in src/zenml/models/v2/base/filter.py
156
157
158
159
160
161
162
163
164
165
166
167
168
def generate_query_conditions_from_column(self, column: Any) -> Any:
    """Generate query conditions for a boolean column.

    Args:
        column: The boolean column of an SQLModel table on which to filter.

    Returns:
        A list of query conditions.
    """
    if self.operation == GenericFilterOps.NOT_EQUALS:
        return column != self.value

    return column == self.value

BuildItem

Bases: BaseModel

Pipeline build item.

Attributes:

Name Type Description
image str

The image name or digest.

dockerfile Optional[str]

The contents of the Dockerfile used to build the image.

requirements Optional[str]

The pip requirements installed in the image. This is a string consisting of multiple concatenated requirements.txt files.

settings_checksum Optional[str]

Checksum of the settings used for the build.

contains_code bool

Whether the image contains user files.

requires_code_download bool

Whether the image needs to download files.

Source code in src/zenml/models/v2/misc/build_item.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class BuildItem(BaseModel):
    """Pipeline build item.

    Attributes:
        image: The image name or digest.
        dockerfile: The contents of the Dockerfile used to build the image.
        requirements: The pip requirements installed in the image. This is a
            string consisting of multiple concatenated requirements.txt files.
        settings_checksum: Checksum of the settings used for the build.
        contains_code: Whether the image contains user files.
        requires_code_download: Whether the image needs to download files.
    """

    image: str = Field(title="The image name or digest.")
    dockerfile: Optional[str] = Field(
        default=None, title="The dockerfile used to build the image."
    )
    requirements: Optional[str] = Field(
        default=None, title="The pip requirements installed in the image."
    )
    settings_checksum: Optional[str] = Field(
        default=None, title="The checksum of the build settings."
    )
    contains_code: bool = Field(
        default=True, title="Whether the image contains user files."
    )
    requires_code_download: bool = Field(
        default=False, title="Whether the image needs to download files."
    )

CodeReferenceRequest

Bases: BaseRequest

Request model for code references.

Source code in src/zenml/models/v2/core/code_reference.py
36
37
38
39
40
41
42
43
44
45
class CodeReferenceRequest(BaseRequest):
    """Request model for code references."""

    commit: str = Field(description="The commit of the code reference.")
    subdirectory: str = Field(
        description="The subdirectory of the code reference."
    )
    code_repository: UUID = Field(
        description="The repository of the code reference."
    )

CodeReferenceResponse

Bases: BaseIdentifiedResponse[CodeReferenceResponseBody, CodeReferenceResponseMetadata, CodeReferenceResponseResources]

Response model for code references.

Source code in src/zenml/models/v2/core/code_reference.py
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
class CodeReferenceResponse(
    BaseIdentifiedResponse[
        CodeReferenceResponseBody,
        CodeReferenceResponseMetadata,
        CodeReferenceResponseResources,
    ]
):
    """Response model for code references."""

    def get_hydrated_version(self) -> "CodeReferenceResponse":
        """Get the hydrated version of this code reference.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_code_reference(self.id)

    # Body and metadata properties
    @property
    def commit(self) -> str:
        """The `commit` property.

        Returns:
            the value of the property.
        """
        return self.get_body().commit

    @property
    def subdirectory(self) -> str:
        """The `subdirectory` property.

        Returns:
            the value of the property.
        """
        return self.get_body().subdirectory

    @property
    def code_repository(self) -> "CodeRepositoryResponse":
        """The `code_repository` property.

        Returns:
            the value of the property.
        """
        return self.get_body().code_repository

code_repository property

The code_repository property.

Returns:

Type Description
CodeRepositoryResponse

the value of the property.

commit property

The commit property.

Returns:

Type Description
str

the value of the property.

subdirectory property

The subdirectory property.

Returns:

Type Description
str

the value of the property.

get_hydrated_version()

Get the hydrated version of this code reference.

Returns:

Type Description
CodeReferenceResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/code_reference.py
85
86
87
88
89
90
91
92
93
def get_hydrated_version(self) -> "CodeReferenceResponse":
    """Get the hydrated version of this code reference.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_code_reference(self.id)

CodeReferenceResponseBody

Bases: BaseDatedResponseBody

Response body for code references.

Source code in src/zenml/models/v2/core/code_reference.py
56
57
58
59
60
61
62
63
64
65
class CodeReferenceResponseBody(BaseDatedResponseBody):
    """Response body for code references."""

    commit: str = Field(description="The commit of the code reference.")
    subdirectory: str = Field(
        description="The subdirectory of the code reference."
    )
    code_repository: "CodeRepositoryResponse" = Field(
        description="The repository of the code reference."
    )

CodeReferenceResponseMetadata

Bases: BaseResponseMetadata

Response metadata for code references.

Source code in src/zenml/models/v2/core/code_reference.py
68
69
class CodeReferenceResponseMetadata(BaseResponseMetadata):
    """Response metadata for code references."""

CodeRepositoryFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of all code repositories.

Source code in src/zenml/models/v2/core/code_repository.py
184
185
186
187
188
189
190
class CodeRepositoryFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of all code repositories."""

    name: Optional[str] = Field(
        description="Name of the code repository.",
        default=None,
    )

CodeRepositoryRequest

Bases: WorkspaceScopedRequest

Request model for code repositories.

Source code in src/zenml/models/v2/core/code_repository.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class CodeRepositoryRequest(WorkspaceScopedRequest):
    """Request model for code repositories."""

    name: str = Field(
        title="The name of the code repository.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    config: Dict[str, Any] = Field(
        description="Configuration for the code repository."
    )
    source: Source = Field(description="The code repository source.")
    logo_url: Optional[str] = Field(
        description="Optional URL of a logo (png, jpg or svg) for the "
        "code repository.",
        default=None,
    )
    description: Optional[str] = Field(
        description="Code repository description.",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )

CodeRepositoryResponse

Bases: WorkspaceScopedResponse[CodeRepositoryResponseBody, CodeRepositoryResponseMetadata, CodeRepositoryResponseResources]

Response model for code repositories.

Source code in src/zenml/models/v2/core/code_repository.py
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
class CodeRepositoryResponse(
    WorkspaceScopedResponse[
        CodeRepositoryResponseBody,
        CodeRepositoryResponseMetadata,
        CodeRepositoryResponseResources,
    ]
):
    """Response model for code repositories."""

    name: str = Field(
        title="The name of the code repository.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "CodeRepositoryResponse":
        """Get the hydrated version of this code repository.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_code_repository(self.id)

    # Body and metadata properties
    @property
    def source(self) -> Source:
        """The `source` property.

        Returns:
            the value of the property.
        """
        return self.get_body().source

    @property
    def logo_url(self) -> Optional[str]:
        """The `logo_url` property.

        Returns:
            the value of the property.
        """
        return self.get_body().logo_url

    @property
    def config(self) -> Dict[str, Any]:
        """The `config` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().config

    @property
    def description(self) -> Optional[str]:
        """The `description` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().description

config property

The config property.

Returns:

Type Description
Dict[str, Any]

the value of the property.

description property

The description property.

Returns:

Type Description
Optional[str]

the value of the property.

logo_url property

The logo_url property.

Returns:

Type Description
Optional[str]

the value of the property.

source property

The source property.

Returns:

Type Description
Source

the value of the property.

get_hydrated_version()

Get the hydrated version of this code repository.

Returns:

Type Description
CodeRepositoryResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/code_repository.py
133
134
135
136
137
138
139
140
141
def get_hydrated_version(self) -> "CodeRepositoryResponse":
    """Get the hydrated version of this code repository.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_code_repository(self.id)

CodeRepositoryResponseBody

Bases: WorkspaceScopedResponseBody

Response body for code repositories.

Source code in src/zenml/models/v2/core/code_repository.py
91
92
93
94
95
96
97
98
99
class CodeRepositoryResponseBody(WorkspaceScopedResponseBody):
    """Response body for code repositories."""

    source: Source = Field(description="The code repository source.")
    logo_url: Optional[str] = Field(
        default=None,
        description="Optional URL of a logo (png, jpg or svg) for the "
        "code repository.",
    )

CodeRepositoryResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for code repositories.

Source code in src/zenml/models/v2/core/code_repository.py
102
103
104
105
106
107
108
109
110
111
112
class CodeRepositoryResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for code repositories."""

    config: Dict[str, Any] = Field(
        description="Configuration for the code repository."
    )
    description: Optional[str] = Field(
        default=None,
        description="Code repository description.",
        max_length=TEXT_FIELD_MAX_LENGTH,
    )

CodeRepositoryUpdate

Bases: BaseUpdate

Update model for code repositories.

Source code in src/zenml/models/v2/core/code_repository.py
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
class CodeRepositoryUpdate(BaseUpdate):
    """Update model for code repositories."""

    name: Optional[str] = Field(
        title="The name of the code repository.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    config: Optional[Dict[str, Any]] = Field(
        description="Configuration for the code repository.",
        default=None,
    )
    source: Optional[SourceWithValidator] = Field(
        description="The code repository source.", default=None
    )
    logo_url: Optional[str] = Field(
        description="Optional URL of a logo (png, jpg or svg) for the "
        "code repository.",
        default=None,
    )
    description: Optional[str] = Field(
        description="Code repository description.",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )

ComponentBase

Bases: BaseModel

Base model for components.

Source code in src/zenml/models/v2/core/component.py
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
class ComponentBase(BaseModel):
    """Base model for components."""

    name: str = Field(
        title="The name of the stack component.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    type: StackComponentType = Field(
        title="The type of the stack component.",
    )

    flavor: str = Field(
        title="The flavor of the stack component.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    configuration: Dict[str, Any] = Field(
        title="The stack component configuration.",
    )

    connector_resource_id: Optional[str] = Field(
        default=None,
        description="The ID of a specific resource instance to "
        "gain access to through the connector",
    )

    labels: Optional[Dict[str, Any]] = Field(
        default=None,
        title="The stack component labels.",
    )

ComponentFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of all ComponentModels.

The Component Model needs additional scoping. As such the _scope_user field can be set to the user that is doing the filtering. The generate_filter() method of the baseclass is overwritten to include the scoping.

Source code in src/zenml/models/v2/core/component.py
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
class ComponentFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of all ComponentModels.

    The Component Model needs additional scoping. As such the `_scope_user`
    field can be set to the user that is doing the filtering. The
    `generate_filter()` method of the baseclass is overwritten to include the
    scoping.
    """

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
        "scope_type",
        "stack_id",
    ]
    CLI_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.CLI_EXCLUDE_FIELDS,
        "scope_type",
    ]
    scope_type: Optional[str] = Field(
        default=None,
        description="The type to scope this query to.",
    )
    name: Optional[str] = Field(
        default=None,
        description="Name of the stack component",
    )
    flavor: Optional[str] = Field(
        default=None,
        description="Flavor of the stack component",
    )
    type: Optional[str] = Field(
        default=None,
        description="Type of the stack component",
    )
    connector_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Connector linked to the stack component",
        union_mode="left_to_right",
    )
    stack_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Stack of the stack component",
        union_mode="left_to_right",
    )

    def set_scope_type(self, component_type: str) -> None:
        """Set the type of component on which to perform the filtering to scope the response.

        Args:
            component_type: The type of component to scope the query to.
        """
        self.scope_type = component_type

    def generate_filter(
        self, table: Type["AnySchema"]
    ) -> Union["ColumnElement[bool]"]:
        """Generate the filter for the query.

        Stack components can be scoped by type to narrow the search.

        Args:
            table: The Table that is being queried from.

        Returns:
            The filter expression for the query.
        """
        from sqlmodel import and_, or_

        from zenml.zen_stores.schemas import (
            StackComponentSchema,
            StackCompositionSchema,
        )

        base_filter = super().generate_filter(table)
        if self.scope_type:
            type_filter = getattr(table, "type") == self.scope_type
            return and_(base_filter, type_filter)

        if self.stack_id:
            operator = (
                or_ if self.logical_operator == LogicalOperators.OR else and_
            )

            stack_filter = and_(
                StackCompositionSchema.stack_id == self.stack_id,
                StackCompositionSchema.component_id == StackComponentSchema.id,
            )
            base_filter = operator(base_filter, stack_filter)

        return base_filter

generate_filter(table)

Generate the filter for the query.

Stack components can be scoped by type to narrow the search.

Parameters:

Name Type Description Default
table Type[AnySchema]

The Table that is being queried from.

required

Returns:

Type Description
Union[ColumnElement[bool]]

The filter expression for the query.

Source code in src/zenml/models/v2/core/component.py
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
def generate_filter(
    self, table: Type["AnySchema"]
) -> Union["ColumnElement[bool]"]:
    """Generate the filter for the query.

    Stack components can be scoped by type to narrow the search.

    Args:
        table: The Table that is being queried from.

    Returns:
        The filter expression for the query.
    """
    from sqlmodel import and_, or_

    from zenml.zen_stores.schemas import (
        StackComponentSchema,
        StackCompositionSchema,
    )

    base_filter = super().generate_filter(table)
    if self.scope_type:
        type_filter = getattr(table, "type") == self.scope_type
        return and_(base_filter, type_filter)

    if self.stack_id:
        operator = (
            or_ if self.logical_operator == LogicalOperators.OR else and_
        )

        stack_filter = and_(
            StackCompositionSchema.stack_id == self.stack_id,
            StackCompositionSchema.component_id == StackComponentSchema.id,
        )
        base_filter = operator(base_filter, stack_filter)

    return base_filter

set_scope_type(component_type)

Set the type of component on which to perform the filtering to scope the response.

Parameters:

Name Type Description Default
component_type str

The type of component to scope the query to.

required
Source code in src/zenml/models/v2/core/component.py
394
395
396
397
398
399
400
def set_scope_type(self, component_type: str) -> None:
    """Set the type of component on which to perform the filtering to scope the response.

    Args:
        component_type: The type of component to scope the query to.
    """
    self.scope_type = component_type

ComponentInfo

Bases: BaseModel

Information about each stack components when creating a full stack.

Source code in src/zenml/models/v2/misc/info_models.py
34
35
36
37
38
39
40
41
42
43
44
45
46
class ComponentInfo(BaseModel):
    """Information about each stack components when creating a full stack."""

    flavor: str
    service_connector_index: Optional[int] = Field(
        default=None,
        title="The id of the service connector from the list "
        "`service_connectors`.",
        description="The id of the service connector from the list "
        "`service_connectors` from `FullStackRequest`.",
    )
    service_connector_resource_id: Optional[str] = None
    configuration: Dict[str, Any] = {}

ComponentRequest

Bases: ComponentBase, WorkspaceScopedRequest

Request model for components.

Source code in src/zenml/models/v2/core/component.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
class ComponentRequest(ComponentBase, WorkspaceScopedRequest):
    """Request model for components."""

    ANALYTICS_FIELDS: ClassVar[List[str]] = ["type", "flavor"]

    connector: Optional[UUID] = Field(
        default=None,
        title="The service connector linked to this stack component.",
    )

    @field_validator("name")
    @classmethod
    def name_cant_be_a_secret_reference(cls, name: str) -> str:
        """Validator to ensure that the given name is not a secret reference.

        Args:
            name: The name to validate.

        Returns:
            The name if it is not a secret reference.

        Raises:
            ValueError: If the name is a secret reference.
        """
        if secret_utils.is_secret_reference(name):
            raise ValueError(
                "Passing the `name` attribute of a stack component as a "
                "secret reference is not allowed."
            )
        return name

name_cant_be_a_secret_reference(name) classmethod

Validator to ensure that the given name is not a secret reference.

Parameters:

Name Type Description Default
name str

The name to validate.

required

Returns:

Type Description
str

The name if it is not a secret reference.

Raises:

Type Description
ValueError

If the name is a secret reference.

Source code in src/zenml/models/v2/core/component.py
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
@field_validator("name")
@classmethod
def name_cant_be_a_secret_reference(cls, name: str) -> str:
    """Validator to ensure that the given name is not a secret reference.

    Args:
        name: The name to validate.

    Returns:
        The name if it is not a secret reference.

    Raises:
        ValueError: If the name is a secret reference.
    """
    if secret_utils.is_secret_reference(name):
        raise ValueError(
            "Passing the `name` attribute of a stack component as a "
            "secret reference is not allowed."
        )
    return name

ComponentResponse

Bases: WorkspaceScopedResponse[ComponentResponseBody, ComponentResponseMetadata, ComponentResponseResources]

Response model for components.

Source code in src/zenml/models/v2/core/component.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
class ComponentResponse(
    WorkspaceScopedResponse[
        ComponentResponseBody,
        ComponentResponseMetadata,
        ComponentResponseResources,
    ]
):
    """Response model for components."""

    ANALYTICS_FIELDS: ClassVar[List[str]] = ["type"]

    name: str = Field(
        title="The name of the stack component.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_analytics_metadata(self) -> Dict[str, Any]:
        """Add the component labels to analytics metadata.

        Returns:
            Dict of analytics metadata.
        """
        metadata = super().get_analytics_metadata()

        if self.labels is not None:
            metadata.update(
                {
                    label[6:]: value
                    for label, value in self.labels.items()
                    if label.startswith("zenml:")
                }
            )
        metadata["flavor"] = self.flavor_name

        return metadata

    def get_hydrated_version(self) -> "ComponentResponse":
        """Get the hydrated version of this component.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_stack_component(self.id)

    # Body and metadata properties
    @property
    def type(self) -> StackComponentType:
        """The `type` property.

        Returns:
            the value of the property.
        """
        return self.get_body().type

    @property
    def flavor_name(self) -> str:
        """The `flavor_name` property.

        Returns:
            the value of the property.
        """
        return self.get_body().flavor_name

    @property
    def integration(self) -> Optional[str]:
        """The `integration` property.

        Returns:
            the value of the property.
        """
        return self.get_body().integration

    @property
    def logo_url(self) -> Optional[str]:
        """The `logo_url` property.

        Returns:
            the value of the property.
        """
        return self.get_body().logo_url

    @property
    def configuration(self) -> Dict[str, Any]:
        """The `configuration` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().configuration

    @property
    def labels(self) -> Optional[Dict[str, Any]]:
        """The `labels` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().labels

    @property
    def connector_resource_id(self) -> Optional[str]:
        """The `connector_resource_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().connector_resource_id

    @property
    def connector(self) -> Optional["ServiceConnectorResponse"]:
        """The `connector` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().connector

    @property
    def flavor(self) -> "FlavorResponse":
        """The `flavor` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().flavor

configuration property

The configuration property.

Returns:

Type Description
Dict[str, Any]

the value of the property.

connector property

The connector property.

Returns:

Type Description
Optional[ServiceConnectorResponse]

the value of the property.

connector_resource_id property

The connector_resource_id property.

Returns:

Type Description
Optional[str]

the value of the property.

flavor property

The flavor property.

Returns:

Type Description
FlavorResponse

the value of the property.

flavor_name property

The flavor_name property.

Returns:

Type Description
str

the value of the property.

integration property

The integration property.

Returns:

Type Description
Optional[str]

the value of the property.

labels property

The labels property.

Returns:

Type Description
Optional[Dict[str, Any]]

the value of the property.

logo_url property

The logo_url property.

Returns:

Type Description
Optional[str]

the value of the property.

type property

The type property.

Returns:

Type Description
StackComponentType

the value of the property.

get_analytics_metadata()

Add the component labels to analytics metadata.

Returns:

Type Description
Dict[str, Any]

Dict of analytics metadata.

Source code in src/zenml/models/v2/core/component.py
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
def get_analytics_metadata(self) -> Dict[str, Any]:
    """Add the component labels to analytics metadata.

    Returns:
        Dict of analytics metadata.
    """
    metadata = super().get_analytics_metadata()

    if self.labels is not None:
        metadata.update(
            {
                label[6:]: value
                for label, value in self.labels.items()
                if label.startswith("zenml:")
            }
        )
    metadata["flavor"] = self.flavor_name

    return metadata

get_hydrated_version()

Get the hydrated version of this component.

Returns:

Type Description
ComponentResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/component.py
253
254
255
256
257
258
259
260
261
def get_hydrated_version(self) -> "ComponentResponse":
    """Get the hydrated version of this component.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_stack_component(self.id)

ComponentResponseBody

Bases: WorkspaceScopedResponseBody

Response body for components.

Source code in src/zenml/models/v2/core/component.py
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
class ComponentResponseBody(WorkspaceScopedResponseBody):
    """Response body for components."""

    type: StackComponentType = Field(
        title="The type of the stack component.",
    )
    flavor_name: str = Field(
        title="The flavor of the stack component.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    integration: Optional[str] = Field(
        default=None,
        title="The name of the integration that the component's flavor "
        "belongs to.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    logo_url: Optional[str] = Field(
        default=None,
        title="Optionally, a url pointing to a png,"
        "svg or jpg can be attached.",
    )

ComponentResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for components.

Source code in src/zenml/models/v2/core/component.py
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
class ComponentResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for components."""

    configuration: Dict[str, Any] = Field(
        title="The stack component configuration.",
    )
    labels: Optional[Dict[str, Any]] = Field(
        default=None,
        title="The stack component labels.",
    )
    connector_resource_id: Optional[str] = Field(
        default=None,
        description="The ID of a specific resource instance to "
        "gain access to through the connector",
    )
    connector: Optional["ServiceConnectorResponse"] = Field(
        default=None,
        title="The service connector linked to this stack component.",
    )

ComponentResponseResources

Bases: WorkspaceScopedResponseResources

Class for all resource models associated with the component entity.

Source code in src/zenml/models/v2/core/component.py
209
210
211
212
213
214
class ComponentResponseResources(WorkspaceScopedResponseResources):
    """Class for all resource models associated with the component entity."""

    flavor: "FlavorResponse" = Field(
        title="The flavor of this stack component.",
    )

ComponentUpdate

Bases: BaseUpdate

Update model for stack components.

Source code in src/zenml/models/v2/core/component.py
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
class ComponentUpdate(BaseUpdate):
    """Update model for stack components."""

    name: Optional[str] = Field(
        title="The name of the stack component.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    configuration: Optional[Dict[str, Any]] = Field(
        title="The stack component configuration.",
        default=None,
    )
    connector_resource_id: Optional[str] = Field(
        description="The ID of a specific resource instance to "
        "gain access to through the connector",
        default=None,
    )
    labels: Optional[Dict[str, Any]] = Field(
        title="The stack component labels.",
        default=None,
    )
    connector: Optional[UUID] = Field(
        title="The service connector linked to this stack component.",
        default=None,
    )

DeployedStack

Bases: BaseModel

Information about a deployed stack.

Source code in src/zenml/models/v2/misc/stack_deployment.py
85
86
87
88
89
90
91
92
93
94
95
96
class DeployedStack(BaseModel):
    """Information about a deployed stack."""

    stack: StackResponse = Field(
        title="The stack that was deployed.",
        description="The stack that was deployed.",
    )
    service_connector: Optional[ServiceConnectorResponse] = Field(
        default=None,
        title="The service connector for the deployed stack.",
        description="The service connector for the deployed stack.",
    )

EventSourceFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of all EventSourceModels.

Source code in src/zenml/models/v2/core/event_source.py
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
class EventSourceFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of all EventSourceModels."""

    name: Optional[str] = Field(
        default=None,
        description="Name of the event source",
    )
    flavor: Optional[str] = Field(
        default=None,
        description="Flavor of the event source",
    )
    plugin_subtype: Optional[str] = Field(
        default=None,
        title="The plugin sub type of the event source.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

EventSourceFlavorResponse

Bases: BasePluginFlavorResponse[EventSourceFlavorResponseBody, EventSourceFlavorResponseMetadata, EventSourceFlavorResponseResources]

Response model for Event Source Flavors.

Source code in src/zenml/models/v2/core/event_source_flavor.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class EventSourceFlavorResponse(
    BasePluginFlavorResponse[
        EventSourceFlavorResponseBody,
        EventSourceFlavorResponseMetadata,
        EventSourceFlavorResponseResources,
    ]
):
    """Response model for Event Source Flavors."""

    # Body and metadata properties
    @property
    def source_config_schema(self) -> Dict[str, Any]:
        """The `source_config_schema` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().source_config_schema

    @property
    def filter_config_schema(self) -> Dict[str, Any]:
        """The `filter_config_schema` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().filter_config_schema

filter_config_schema property

The filter_config_schema property.

Returns:

Type Description
Dict[str, Any]

the value of the property.

source_config_schema property

The source_config_schema property.

Returns:

Type Description
Dict[str, Any]

the value of the property.

EventSourceFlavorResponseBody

Bases: BasePluginResponseBody

Response body for event flavors.

Source code in src/zenml/models/v2/core/event_source_flavor.py
26
27
class EventSourceFlavorResponseBody(BasePluginResponseBody):
    """Response body for event flavors."""

EventSourceFlavorResponseMetadata

Bases: BasePluginResponseMetadata

Response metadata for event flavors.

Source code in src/zenml/models/v2/core/event_source_flavor.py
30
31
32
33
34
class EventSourceFlavorResponseMetadata(BasePluginResponseMetadata):
    """Response metadata for event flavors."""

    source_config_schema: Dict[str, Any]
    filter_config_schema: Dict[str, Any]

EventSourceFlavorResponseResources

Bases: BasePluginResponseResources

Response resources for event source flavors.

Source code in src/zenml/models/v2/core/event_source_flavor.py
37
38
class EventSourceFlavorResponseResources(BasePluginResponseResources):
    """Response resources for event source flavors."""

EventSourceRequest

Bases: WorkspaceScopedRequest

BaseModel for all event sources.

Source code in src/zenml/models/v2/core/event_source.py
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class EventSourceRequest(WorkspaceScopedRequest):
    """BaseModel for all event sources."""

    name: str = Field(
        title="The name of the event source.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    flavor: str = Field(
        title="The flavor of event source.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    plugin_subtype: PluginSubType = Field(
        title="The plugin subtype of the event source.",
    )
    description: str = Field(
        default="",
        title="The description of the event source.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    configuration: Dict[str, Any] = Field(
        title="The event source configuration.",
    )

EventSourceResponse

Bases: WorkspaceScopedResponse[EventSourceResponseBody, EventSourceResponseMetadata, EventSourceResponseResources]

Response model for event sources.

Source code in src/zenml/models/v2/core/event_source.py
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
class EventSourceResponse(
    WorkspaceScopedResponse[
        EventSourceResponseBody,
        EventSourceResponseMetadata,
        EventSourceResponseResources,
    ]
):
    """Response model for event sources."""

    name: str = Field(
        title="The name of the event source.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "EventSourceResponse":
        """Get the hydrated version of this event source.

        Returns:
            An instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_event_source(self.id)

    # Body and metadata properties
    @property
    def flavor(self) -> str:
        """The `flavor` property.

        Returns:
            the value of the property.
        """
        return self.get_body().flavor

    @property
    def is_active(self) -> bool:
        """The `is_active` property.

        Returns:
            the value of the property.
        """
        return self.get_body().is_active

    @property
    def plugin_subtype(self) -> PluginSubType:
        """The `plugin_subtype` property.

        Returns:
            the value of the property.
        """
        return self.get_body().plugin_subtype

    @property
    def description(self) -> str:
        """The `description` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().description

    @property
    def configuration(self) -> Dict[str, Any]:
        """The `configuration` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().configuration

    def set_configuration(self, configuration: Dict[str, Any]) -> None:
        """Set the `configuration` property.

        Args:
            configuration: The value to set.
        """
        self.get_metadata().configuration = configuration

configuration property

The configuration property.

Returns:

Type Description
Dict[str, Any]

the value of the property.

description property

The description property.

Returns:

Type Description
str

the value of the property.

flavor property

The flavor property.

Returns:

Type Description
str

the value of the property.

is_active property

The is_active property.

Returns:

Type Description
bool

the value of the property.

plugin_subtype property

The plugin_subtype property.

Returns:

Type Description
PluginSubType

the value of the property.

get_hydrated_version()

Get the hydrated version of this event source.

Returns:

Type Description
EventSourceResponse

An instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/event_source.py
161
162
163
164
165
166
167
168
169
def get_hydrated_version(self) -> "EventSourceResponse":
    """Get the hydrated version of this event source.

    Returns:
        An instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_event_source(self.id)

set_configuration(configuration)

Set the configuration property.

Parameters:

Name Type Description Default
configuration Dict[str, Any]

The value to set.

required
Source code in src/zenml/models/v2/core/event_source.py
217
218
219
220
221
222
223
def set_configuration(self, configuration: Dict[str, Any]) -> None:
    """Set the `configuration` property.

    Args:
        configuration: The value to set.
    """
    self.get_metadata().configuration = configuration

EventSourceResponseBody

Bases: WorkspaceScopedResponseBody

ResponseBody for event sources.

Source code in src/zenml/models/v2/core/event_source.py
111
112
113
114
115
116
117
118
119
120
121
122
123
class EventSourceResponseBody(WorkspaceScopedResponseBody):
    """ResponseBody for event sources."""

    flavor: str = Field(
        title="The flavor of event source.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    plugin_subtype: PluginSubType = Field(
        title="The plugin subtype of the event source.",
    )
    is_active: bool = Field(
        title="Whether the event source is active.",
    )

EventSourceResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for event sources.

Source code in src/zenml/models/v2/core/event_source.py
126
127
128
129
130
131
132
133
134
135
136
class EventSourceResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for event sources."""

    description: str = Field(
        default="",
        title="The description of the event source.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    configuration: Dict[str, Any] = Field(
        title="The event source configuration.",
    )

EventSourceResponseResources

Bases: WorkspaceScopedResponseResources

Class for all resource models associated with the code repository entity.

Source code in src/zenml/models/v2/core/event_source.py
139
140
141
142
143
144
class EventSourceResponseResources(WorkspaceScopedResponseResources):
    """Class for all resource models associated with the code repository entity."""

    triggers: Page[TriggerResponse] = Field(
        title="The triggers configured with this event source.",
    )

EventSourceUpdate

Bases: BaseZenModel

Update model for event sources.

Source code in src/zenml/models/v2/core/event_source.py
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
class EventSourceUpdate(BaseZenModel):
    """Update model for event sources."""

    name: Optional[str] = Field(
        default=None,
        title="The updated name of the event source.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    description: Optional[str] = Field(
        default=None,
        title="The updated description of the event source.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    configuration: Optional[Dict[str, Any]] = Field(
        default=None,
        title="The updated event source configuration.",
    )
    is_active: Optional[bool] = Field(
        default=None,
        title="The status of the event source.",
    )

    @classmethod
    def from_response(
        cls, response: "EventSourceResponse"
    ) -> "EventSourceUpdate":
        """Create an update model from a response model.

        Args:
            response: The response model to create the update model from.

        Returns:
            The update model.
        """
        return EventSourceUpdate(
            name=response.name,
            description=response.description,
            configuration=copy.deepcopy(response.configuration),
            is_active=response.is_active,
        )

from_response(response) classmethod

Create an update model from a response model.

Parameters:

Name Type Description Default
response EventSourceResponse

The response model to create the update model from.

required

Returns:

Type Description
EventSourceUpdate

The update model.

Source code in src/zenml/models/v2/core/event_source.py
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
@classmethod
def from_response(
    cls, response: "EventSourceResponse"
) -> "EventSourceUpdate":
    """Create an update model from a response model.

    Args:
        response: The response model to create the update model from.

    Returns:
        The update model.
    """
    return EventSourceUpdate(
        name=response.name,
        description=response.description,
        configuration=copy.deepcopy(response.configuration),
        is_active=response.is_active,
    )

ExternalUserModel

Bases: BaseModel

External user model.

Source code in src/zenml/models/v2/misc/external_user.py
22
23
24
25
26
27
28
29
30
class ExternalUserModel(BaseModel):
    """External user model."""

    id: UUID
    email: str
    name: Optional[str] = None
    is_admin: bool = False

    model_config = ConfigDict(extra="ignore")

FlavorFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of all Flavors.

Source code in src/zenml/models/v2/core/flavor.py
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
class FlavorFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of all Flavors."""

    name: Optional[str] = Field(
        default=None,
        description="Name of the flavor",
    )
    type: Optional[str] = Field(
        default=None,
        description="Stack Component Type of the stack flavor",
    )
    integration: Optional[str] = Field(
        default=None,
        description="Integration associated with the flavor",
    )

FlavorRequest

Bases: UserScopedRequest

Request model for flavors.

Source code in src/zenml/models/v2/core/flavor.py
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
class FlavorRequest(UserScopedRequest):
    """Request model for flavors."""

    ANALYTICS_FIELDS: ClassVar[List[str]] = [
        "type",
        "integration",
    ]

    name: str = Field(
        title="The name of the Flavor.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    type: StackComponentType = Field(title="The type of the Flavor.")
    config_schema: Dict[str, Any] = Field(
        title="The JSON schema of this flavor's corresponding configuration.",
    )
    connector_type: Optional[str] = Field(
        default=None,
        title="The type of the connector that this flavor uses.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    connector_resource_type: Optional[str] = Field(
        default=None,
        title="The resource type of the connector that this flavor uses.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    connector_resource_id_attr: Optional[str] = Field(
        default=None,
        title="The name of an attribute in the stack component configuration "
        "that plays the role of resource ID when linked to a service "
        "connector.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    source: str = Field(
        title="The path to the module which contains this Flavor.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    integration: Optional[str] = Field(
        title="The name of the integration that the Flavor belongs to.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    logo_url: Optional[str] = Field(
        default=None,
        title="Optionally, a url pointing to a png,"
        "svg or jpg can be attached.",
    )
    docs_url: Optional[str] = Field(
        default=None,
        title="Optionally, a url pointing to docs, within docs.zenml.io.",
    )
    sdk_docs_url: Optional[str] = Field(
        default=None,
        title="Optionally, a url pointing to SDK docs,"
        "within sdkdocs.zenml.io.",
    )
    is_custom: bool = Field(
        title="Whether or not this flavor is a custom, user created flavor.",
        default=True,
    )
    workspace: Optional[UUID] = Field(
        default=None, title="The workspace to which this resource belongs."
    )

FlavorResponse

Bases: UserScopedResponse[FlavorResponseBody, FlavorResponseMetadata, FlavorResponseResources]

Response model for flavors.

Source code in src/zenml/models/v2/core/flavor.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
class FlavorResponse(
    UserScopedResponse[
        FlavorResponseBody, FlavorResponseMetadata, FlavorResponseResources
    ]
):
    """Response model for flavors."""

    # Analytics
    ANALYTICS_FIELDS: ClassVar[List[str]] = [
        "id",
        "type",
        "integration",
    ]

    name: str = Field(
        title="The name of the Flavor.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "FlavorResponse":
        """Get the hydrated version of the flavor.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_flavor(self.id)

    # Helper methods
    @property
    def connector_requirements(
        self,
    ) -> Optional["ServiceConnectorRequirements"]:
        """Returns the connector requirements for the flavor.

        Returns:
            The connector requirements for the flavor.
        """
        from zenml.models import (
            ServiceConnectorRequirements,
        )

        if not self.connector_resource_type:
            return None

        return ServiceConnectorRequirements(
            connector_type=self.connector_type,
            resource_type=self.connector_resource_type,
            resource_id_attr=self.connector_resource_id_attr,
        )

    # Body and metadata properties
    @property
    def type(self) -> StackComponentType:
        """The `type` property.

        Returns:
            the value of the property.
        """
        return self.get_body().type

    @property
    def integration(self) -> Optional[str]:
        """The `integration` property.

        Returns:
            the value of the property.
        """
        return self.get_body().integration

    @property
    def source(self) -> str:
        """The `source` property.

        Returns:
            the value of the property.
        """
        return self.get_body().source

    @property
    def logo_url(self) -> Optional[str]:
        """The `logo_url` property.

        Returns:
            the value of the property.
        """
        return self.get_body().logo_url

    @property
    def workspace(self) -> Optional["WorkspaceResponse"]:
        """The `workspace` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().workspace

    @property
    def config_schema(self) -> Dict[str, Any]:
        """The `config_schema` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().config_schema

    @property
    def connector_type(self) -> Optional[str]:
        """The `connector_type` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().connector_type

    @property
    def connector_resource_type(self) -> Optional[str]:
        """The `connector_resource_type` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().connector_resource_type

    @property
    def connector_resource_id_attr(self) -> Optional[str]:
        """The `connector_resource_id_attr` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().connector_resource_id_attr

    @property
    def docs_url(self) -> Optional[str]:
        """The `docs_url` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().docs_url

    @property
    def sdk_docs_url(self) -> Optional[str]:
        """The `sdk_docs_url` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().sdk_docs_url

    @property
    def is_custom(self) -> bool:
        """The `is_custom` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().is_custom

config_schema property

The config_schema property.

Returns:

Type Description
Dict[str, Any]

the value of the property.

connector_requirements property

Returns the connector requirements for the flavor.

Returns:

Type Description
Optional[ServiceConnectorRequirements]

The connector requirements for the flavor.

connector_resource_id_attr property

The connector_resource_id_attr property.

Returns:

Type Description
Optional[str]

the value of the property.

connector_resource_type property

The connector_resource_type property.

Returns:

Type Description
Optional[str]

the value of the property.

connector_type property

The connector_type property.

Returns:

Type Description
Optional[str]

the value of the property.

docs_url property

The docs_url property.

Returns:

Type Description
Optional[str]

the value of the property.

integration property

The integration property.

Returns:

Type Description
Optional[str]

the value of the property.

is_custom property

The is_custom property.

Returns:

Type Description
bool

the value of the property.

logo_url property

The logo_url property.

Returns:

Type Description
Optional[str]

the value of the property.

sdk_docs_url property

The sdk_docs_url property.

Returns:

Type Description
Optional[str]

the value of the property.

source property

The source property.

Returns:

Type Description
str

the value of the property.

type property

The type property.

Returns:

Type Description
StackComponentType

the value of the property.

workspace property

The workspace property.

Returns:

Type Description
Optional[WorkspaceResponse]

the value of the property.

get_hydrated_version()

Get the hydrated version of the flavor.

Returns:

Type Description
FlavorResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/flavor.py
270
271
272
273
274
275
276
277
278
def get_hydrated_version(self) -> "FlavorResponse":
    """Get the hydrated version of the flavor.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_flavor(self.id)

FlavorResponseBody

Bases: UserScopedResponseBody

Response body for flavor.

Source code in src/zenml/models/v2/core/flavor.py
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
class FlavorResponseBody(UserScopedResponseBody):
    """Response body for flavor."""

    type: StackComponentType = Field(title="The type of the Flavor.")
    integration: Optional[str] = Field(
        title="The name of the integration that the Flavor belongs to.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    source: str = Field(
        title="The path to the module which contains this Flavor.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    logo_url: Optional[str] = Field(
        default=None,
        title="Optionally, a url pointing to a png,"
        "svg or jpg can be attached.",
    )

FlavorResponseMetadata

Bases: UserScopedResponseMetadata

Response metadata for flavors.

Source code in src/zenml/models/v2/core/flavor.py
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
class FlavorResponseMetadata(UserScopedResponseMetadata):
    """Response metadata for flavors."""

    workspace: Optional["WorkspaceResponse"] = Field(
        title="The project of this resource."
    )
    config_schema: Dict[str, Any] = Field(
        title="The JSON schema of this flavor's corresponding configuration.",
    )
    connector_type: Optional[str] = Field(
        default=None,
        title="The type of the connector that this flavor uses.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    connector_resource_type: Optional[str] = Field(
        default=None,
        title="The resource type of the connector that this flavor uses.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    connector_resource_id_attr: Optional[str] = Field(
        default=None,
        title="The name of an attribute in the stack component configuration "
        "that plays the role of resource ID when linked to a service "
        "connector.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    docs_url: Optional[str] = Field(
        default=None,
        title="Optionally, a url pointing to docs, within docs.zenml.io.",
    )
    sdk_docs_url: Optional[str] = Field(
        default=None,
        title="Optionally, a url pointing to SDK docs,"
        "within sdkdocs.zenml.io.",
    )
    is_custom: bool = Field(
        title="Whether or not this flavor is a custom, user created flavor.",
        default=True,
    )

FlavorUpdate

Bases: BaseUpdate

Update model for flavors.

Source code in src/zenml/models/v2/core/flavor.py
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
class FlavorUpdate(BaseUpdate):
    """Update model for flavors."""

    name: Optional[str] = Field(
        title="The name of the Flavor.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    type: Optional[StackComponentType] = Field(
        title="The type of the Flavor.", default=None
    )
    config_schema: Optional[Dict[str, Any]] = Field(
        title="The JSON schema of this flavor's corresponding configuration.",
        default=None,
    )
    connector_type: Optional[str] = Field(
        title="The type of the connector that this flavor uses.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    connector_resource_type: Optional[str] = Field(
        title="The resource type of the connector that this flavor uses.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    connector_resource_id_attr: Optional[str] = Field(
        title="The name of an attribute in the stack component configuration "
        "that plays the role of resource ID when linked to a service "
        "connector.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    source: Optional[str] = Field(
        title="The path to the module which contains this Flavor.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    integration: Optional[str] = Field(
        title="The name of the integration that the Flavor belongs to.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    logo_url: Optional[str] = Field(
        title="Optionally, a url pointing to a png,"
        "svg or jpg can be attached.",
        default=None,
    )
    docs_url: Optional[str] = Field(
        title="Optionally, a url pointing to docs, within docs.zenml.io.",
        default=None,
    )
    sdk_docs_url: Optional[str] = Field(
        title="Optionally, a url pointing to SDK docs,"
        "within sdkdocs.zenml.io.",
        default=None,
    )
    is_custom: Optional[bool] = Field(
        title="Whether or not this flavor is a custom, user created flavor.",
        default=None,
    )
    workspace: Optional[UUID] = Field(
        title="The workspace to which this resource belongs.",
        default=None,
    )

LoadedVisualization

Bases: BaseModel

Model for loaded visualizations.

Source code in src/zenml/models/v2/misc/loaded_visualization.py
23
24
25
26
27
class LoadedVisualization(BaseModel):
    """Model for loaded visualizations."""

    type: VisualizationType
    value: Union[str, bytes] = Field(union_mode="left_to_right")

LogsRequest

Bases: BaseRequest

Request model for logs.

Source code in src/zenml/models/v2/core/logs.py
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
class LogsRequest(BaseRequest):
    """Request model for logs."""

    uri: str = Field(title="The uri of the logs file")

    artifact_store_id: Union[str, UUID] = Field(
        title="The artifact store ID to associate the logs with.",
        union_mode="left_to_right",
    )

    @field_validator("uri")
    @classmethod
    def text_field_max_length_check(cls, value: Any) -> Any:
        """Checks if the length of the value exceeds the maximum text length.

        Args:
            value: the value set in the field

        Returns:
            the value itself.

        Raises:
            AssertionError: if the length of the field is longer than the
                maximum threshold.
        """
        assert len(str(value)) < TEXT_FIELD_MAX_LENGTH, (
            "The length of the value for this field can not "
            f"exceed {TEXT_FIELD_MAX_LENGTH}"
        )
        return value

    @field_validator("artifact_store_id")
    @classmethod
    def str_field_max_length_check(cls, value: Any) -> Any:
        """Checks if the length of the value exceeds the maximum text length.

        Args:
            value: the value set in the field

        Returns:
            the value itself.

        Raises:
            AssertionError: if the length of the field is longer than the
                maximum threshold.
        """
        assert len(str(value)) < STR_FIELD_MAX_LENGTH, (
            "The length of the value for this field can not "
            f"exceed {STR_FIELD_MAX_LENGTH}"
        )
        return value

str_field_max_length_check(value) classmethod

Checks if the length of the value exceeds the maximum text length.

Parameters:

Name Type Description Default
value Any

the value set in the field

required

Returns:

Type Description
Any

the value itself.

Raises:

Type Description
AssertionError

if the length of the field is longer than the maximum threshold.

Source code in src/zenml/models/v2/core/logs.py
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
@field_validator("artifact_store_id")
@classmethod
def str_field_max_length_check(cls, value: Any) -> Any:
    """Checks if the length of the value exceeds the maximum text length.

    Args:
        value: the value set in the field

    Returns:
        the value itself.

    Raises:
        AssertionError: if the length of the field is longer than the
            maximum threshold.
    """
    assert len(str(value)) < STR_FIELD_MAX_LENGTH, (
        "The length of the value for this field can not "
        f"exceed {STR_FIELD_MAX_LENGTH}"
    )
    return value

text_field_max_length_check(value) classmethod

Checks if the length of the value exceeds the maximum text length.

Parameters:

Name Type Description Default
value Any

the value set in the field

required

Returns:

Type Description
Any

the value itself.

Raises:

Type Description
AssertionError

if the length of the field is longer than the maximum threshold.

Source code in src/zenml/models/v2/core/logs.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@field_validator("uri")
@classmethod
def text_field_max_length_check(cls, value: Any) -> Any:
    """Checks if the length of the value exceeds the maximum text length.

    Args:
        value: the value set in the field

    Returns:
        the value itself.

    Raises:
        AssertionError: if the length of the field is longer than the
            maximum threshold.
    """
    assert len(str(value)) < TEXT_FIELD_MAX_LENGTH, (
        "The length of the value for this field can not "
        f"exceed {TEXT_FIELD_MAX_LENGTH}"
    )
    return value

LogsResponse

Bases: BaseIdentifiedResponse[LogsResponseBody, LogsResponseMetadata, LogsResponseResources]

Response model for logs.

Source code in src/zenml/models/v2/core/logs.py
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
class LogsResponse(
    BaseIdentifiedResponse[
        LogsResponseBody, LogsResponseMetadata, LogsResponseResources
    ]
):
    """Response model for logs."""

    def get_hydrated_version(self) -> "LogsResponse":
        """Get the hydrated version of these logs.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_logs(self.id)

    # Body and metadata properties
    @property
    def uri(self) -> str:
        """The `uri` property.

        Returns:
            the value of the property.
        """
        return self.get_body().uri

    @property
    def step_run_id(self) -> Optional[Union[str, UUID]]:
        """The `step_run_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().step_run_id

    @property
    def pipeline_run_id(self) -> Optional[Union[str, UUID]]:
        """The `pipeline_run_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().pipeline_run_id

    @property
    def artifact_store_id(self) -> Union[str, UUID]:
        """The `artifact_store_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().artifact_store_id

artifact_store_id property

The artifact_store_id property.

Returns:

Type Description
Union[str, UUID]

the value of the property.

pipeline_run_id property

The pipeline_run_id property.

Returns:

Type Description
Optional[Union[str, UUID]]

the value of the property.

step_run_id property

The step_run_id property.

Returns:

Type Description
Optional[Union[str, UUID]]

the value of the property.

uri property

The uri property.

Returns:

Type Description
str

the value of the property.

get_hydrated_version()

Get the hydrated version of these logs.

Returns:

Type Description
LogsResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/logs.py
152
153
154
155
156
157
158
159
160
def get_hydrated_version(self) -> "LogsResponse":
    """Get the hydrated version of these logs.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_logs(self.id)

LogsResponseBody

Bases: BaseDatedResponseBody

Response body for logs.

Source code in src/zenml/models/v2/core/logs.py
93
94
95
96
97
98
99
class LogsResponseBody(BaseDatedResponseBody):
    """Response body for logs."""

    uri: str = Field(
        title="The uri of the logs file",
        max_length=TEXT_FIELD_MAX_LENGTH,
    )

LogsResponseMetadata

Bases: BaseResponseMetadata

Response metadata for logs.

Source code in src/zenml/models/v2/core/logs.py
102
103
104
105
106
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
class LogsResponseMetadata(BaseResponseMetadata):
    """Response metadata for logs."""

    step_run_id: Optional[Union[str, UUID]] = Field(
        title="Step ID to associate the logs with.",
        default=None,
        description="When this is set, pipeline_run_id should be set to None.",
        union_mode="left_to_right",
    )
    pipeline_run_id: Optional[Union[str, UUID]] = Field(
        title="Pipeline run ID to associate the logs with.",
        default=None,
        description="When this is set, step_run_id should be set to None.",
        union_mode="left_to_right",
    )
    artifact_store_id: Union[str, UUID] = Field(
        title="The artifact store ID to associate the logs with.",
        union_mode="left_to_right",
    )

    @field_validator("artifact_store_id")
    @classmethod
    def str_field_max_length_check(cls, value: Any) -> Any:
        """Checks if the length of the value exceeds the maximum text length.

        Args:
            value: the value set in the field

        Returns:
            the value itself.

        Raises:
            AssertionError: if the length of the field is longer than the
                maximum threshold.
        """
        assert len(str(value)) < STR_FIELD_MAX_LENGTH
        return value

str_field_max_length_check(value) classmethod

Checks if the length of the value exceeds the maximum text length.

Parameters:

Name Type Description Default
value Any

the value set in the field

required

Returns:

Type Description
Any

the value itself.

Raises:

Type Description
AssertionError

if the length of the field is longer than the maximum threshold.

Source code in src/zenml/models/v2/core/logs.py
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
@field_validator("artifact_store_id")
@classmethod
def str_field_max_length_check(cls, value: Any) -> Any:
    """Checks if the length of the value exceeds the maximum text length.

    Args:
        value: the value set in the field

    Returns:
        the value itself.

    Raises:
        AssertionError: if the length of the field is longer than the
            maximum threshold.
    """
    assert len(str(value)) < STR_FIELD_MAX_LENGTH
    return value

ModelFilter

Bases: WorkspaceScopedFilter, TaggableFilter

Model to enable advanced filtering of all Workspaces.

Source code in src/zenml/models/v2/core/model.py
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
411
class ModelFilter(WorkspaceScopedFilter, TaggableFilter):
    """Model to enable advanced filtering of all Workspaces."""

    name: Optional[str] = Field(
        default=None,
        description="Name of the Model",
    )

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
        *TaggableFilter.FILTER_EXCLUDE_FIELDS,
    ]
    CUSTOM_SORTING_OPTIONS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.CUSTOM_SORTING_OPTIONS,
        *TaggableFilter.CUSTOM_SORTING_OPTIONS,
        SORT_BY_LATEST_VERSION_KEY,
    ]
    CLI_EXCLUDE_FIELDS = [
        *WorkspaceScopedFilter.CLI_EXCLUDE_FIELDS,
        *TaggableFilter.CLI_EXCLUDE_FIELDS,
    ]

    def apply_sorting(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Apply sorting to the query for Models.

        Args:
            query: The query to which to apply the sorting.
            table: The query table.

        Returns:
            The query with sorting applied.
        """
        from sqlmodel import asc, case, col, desc, func, select

        from zenml.enums import SorterOps
        from zenml.zen_stores.schemas import (
            ModelSchema,
            ModelVersionSchema,
        )

        sort_by, operand = self.sorting_params

        if sort_by == SORT_BY_LATEST_VERSION_KEY:
            # Subquery to find the latest version per model
            latest_version_subquery = (
                select(
                    ModelSchema.id,
                    case(
                        (
                            func.max(ModelVersionSchema.created).is_(None),
                            ModelSchema.created,
                        ),
                        else_=func.max(ModelVersionSchema.created),
                    ).label("latest_version_created"),
                )
                .outerjoin(
                    ModelVersionSchema,
                    ModelSchema.id == ModelVersionSchema.model_id,  # type: ignore[arg-type]
                )
                .group_by(col(ModelSchema.id))
                .subquery()
            )

            query = query.add_columns(
                latest_version_subquery.c.latest_version_created,
            ).where(ModelSchema.id == latest_version_subquery.c.id)

            # Apply sorting based on the operand
            if operand == SorterOps.ASCENDING:
                query = query.order_by(
                    asc(latest_version_subquery.c.latest_version_created),
                    asc(ModelSchema.id),
                )
            else:
                query = query.order_by(
                    desc(latest_version_subquery.c.latest_version_created),
                    desc(ModelSchema.id),
                )
            return query

        # For other sorting cases, delegate to the parent class
        return super().apply_sorting(query=query, table=table)

apply_sorting(query, table)

Apply sorting to the query for Models.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the sorting.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with sorting applied.

Source code in src/zenml/models/v2/core/model.py
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
411
def apply_sorting(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Apply sorting to the query for Models.

    Args:
        query: The query to which to apply the sorting.
        table: The query table.

    Returns:
        The query with sorting applied.
    """
    from sqlmodel import asc, case, col, desc, func, select

    from zenml.enums import SorterOps
    from zenml.zen_stores.schemas import (
        ModelSchema,
        ModelVersionSchema,
    )

    sort_by, operand = self.sorting_params

    if sort_by == SORT_BY_LATEST_VERSION_KEY:
        # Subquery to find the latest version per model
        latest_version_subquery = (
            select(
                ModelSchema.id,
                case(
                    (
                        func.max(ModelVersionSchema.created).is_(None),
                        ModelSchema.created,
                    ),
                    else_=func.max(ModelVersionSchema.created),
                ).label("latest_version_created"),
            )
            .outerjoin(
                ModelVersionSchema,
                ModelSchema.id == ModelVersionSchema.model_id,  # type: ignore[arg-type]
            )
            .group_by(col(ModelSchema.id))
            .subquery()
        )

        query = query.add_columns(
            latest_version_subquery.c.latest_version_created,
        ).where(ModelSchema.id == latest_version_subquery.c.id)

        # Apply sorting based on the operand
        if operand == SorterOps.ASCENDING:
            query = query.order_by(
                asc(latest_version_subquery.c.latest_version_created),
                asc(ModelSchema.id),
            )
        else:
            query = query.order_by(
                desc(latest_version_subquery.c.latest_version_created),
                desc(ModelSchema.id),
            )
        return query

    # For other sorting cases, delegate to the parent class
    return super().apply_sorting(query=query, table=table)

ModelRequest

Bases: WorkspaceScopedRequest

Request model for models.

Source code in src/zenml/models/v2/core/model.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
class ModelRequest(WorkspaceScopedRequest):
    """Request model for models."""

    name: str = Field(
        title="The name of the model",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    license: Optional[str] = Field(
        title="The license model created under",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    description: Optional[str] = Field(
        title="The description of the model",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    audience: Optional[str] = Field(
        title="The target audience of the model",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    use_cases: Optional[str] = Field(
        title="The use cases of the model",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    limitations: Optional[str] = Field(
        title="The know limitations of the model",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    trade_offs: Optional[str] = Field(
        title="The trade offs of the model",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    ethics: Optional[str] = Field(
        title="The ethical implications of the model",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    tags: Optional[List[str]] = Field(
        title="Tags associated with the model",
        default=None,
    )
    save_models_to_registry: bool = Field(
        title="Whether to save all ModelArtifacts to Model Registry",
        default=True,
    )

ModelResponse

Bases: WorkspaceScopedResponse[ModelResponseBody, ModelResponseMetadata, ModelResponseResources]

Response model for models.

Source code in src/zenml/models/v2/core/model.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
class ModelResponse(
    WorkspaceScopedResponse[
        ModelResponseBody, ModelResponseMetadata, ModelResponseResources
    ]
):
    """Response model for models."""

    name: str = Field(
        title="The name of the model",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "ModelResponse":
        """Get the hydrated version of this model.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_model(self.id)

    # Body and metadata properties
    @property
    def tags(self) -> List["TagResponse"]:
        """The `tags` property.

        Returns:
            the value of the property.
        """
        return self.get_body().tags

    @property
    def latest_version_name(self) -> Optional[str]:
        """The `latest_version_name` property.

        Returns:
            the value of the property.
        """
        return self.get_body().latest_version_name

    @property
    def latest_version_id(self) -> Optional[UUID]:
        """The `latest_version_id` property.

        Returns:
            the value of the property.
        """
        return self.get_body().latest_version_id

    @property
    def license(self) -> Optional[str]:
        """The `license` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().license

    @property
    def description(self) -> Optional[str]:
        """The `description` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().description

    @property
    def audience(self) -> Optional[str]:
        """The `audience` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().audience

    @property
    def use_cases(self) -> Optional[str]:
        """The `use_cases` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().use_cases

    @property
    def limitations(self) -> Optional[str]:
        """The `limitations` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().limitations

    @property
    def trade_offs(self) -> Optional[str]:
        """The `trade_offs` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().trade_offs

    @property
    def ethics(self) -> Optional[str]:
        """The `ethics` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().ethics

    @property
    def save_models_to_registry(self) -> bool:
        """The `save_models_to_registry` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().save_models_to_registry

    # Helper functions
    @property
    def versions(self) -> List["Model"]:
        """List all versions of the model.

        Returns:
            The list of all model version.
        """
        from zenml.client import Client

        client = Client()
        model_versions = depaginate(
            client.list_model_versions, model_name_or_id=self.id
        )
        return [
            mv.to_model_class(suppress_class_validation_warnings=True)
            for mv in model_versions
        ]

audience property

The audience property.

Returns:

Type Description
Optional[str]

the value of the property.

description property

The description property.

Returns:

Type Description
Optional[str]

the value of the property.

ethics property

The ethics property.

Returns:

Type Description
Optional[str]

the value of the property.

latest_version_id property

The latest_version_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

latest_version_name property

The latest_version_name property.

Returns:

Type Description
Optional[str]

the value of the property.

license property

The license property.

Returns:

Type Description
Optional[str]

the value of the property.

limitations property

The limitations property.

Returns:

Type Description
Optional[str]

the value of the property.

save_models_to_registry property

The save_models_to_registry property.

Returns:

Type Description
bool

the value of the property.

tags property

The tags property.

Returns:

Type Description
List[TagResponse]

the value of the property.

trade_offs property

The trade_offs property.

Returns:

Type Description
Optional[str]

the value of the property.

use_cases property

The use_cases property.

Returns:

Type Description
Optional[str]

the value of the property.

versions property

List all versions of the model.

Returns:

Type Description
List[Model]

The list of all model version.

get_hydrated_version()

Get the hydrated version of this model.

Returns:

Type Description
ModelResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/model.py
193
194
195
196
197
198
199
200
201
def get_hydrated_version(self) -> "ModelResponse":
    """Get the hydrated version of this model.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_model(self.id)

ModelResponseBody

Bases: WorkspaceScopedResponseBody

Response body for models.

Source code in src/zenml/models/v2/core/model.py
123
124
125
126
127
128
129
130
class ModelResponseBody(WorkspaceScopedResponseBody):
    """Response body for models."""

    tags: List["TagResponse"] = Field(
        title="Tags associated with the model",
    )
    latest_version_name: Optional[str] = None
    latest_version_id: Optional[UUID] = None

ModelResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for models.

Source code in src/zenml/models/v2/core/model.py
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
class ModelResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for models."""

    license: Optional[str] = Field(
        title="The license model created under",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    description: Optional[str] = Field(
        title="The description of the model",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    audience: Optional[str] = Field(
        title="The target audience of the model",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    use_cases: Optional[str] = Field(
        title="The use cases of the model",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    limitations: Optional[str] = Field(
        title="The know limitations of the model",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    trade_offs: Optional[str] = Field(
        title="The trade offs of the model",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    ethics: Optional[str] = Field(
        title="The ethical implications of the model",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    save_models_to_registry: bool = Field(
        title="Whether to save all ModelArtifacts to Model Registry",
        default=True,
    )

ModelUpdate

Bases: BaseModel

Update model for models.

Source code in src/zenml/models/v2/core/model.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
class ModelUpdate(BaseModel):
    """Update model for models."""

    name: Optional[str] = None
    license: Optional[str] = None
    description: Optional[str] = None
    audience: Optional[str] = None
    use_cases: Optional[str] = None
    limitations: Optional[str] = None
    trade_offs: Optional[str] = None
    ethics: Optional[str] = None
    add_tags: Optional[List[str]] = None
    remove_tags: Optional[List[str]] = None
    save_models_to_registry: Optional[bool] = None

ModelVersionArtifactFilter

Bases: BaseFilter

Model version pipeline run links filter model.

Source code in src/zenml/models/v2/core/model_version_artifact.py
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
class ModelVersionArtifactFilter(BaseFilter):
    """Model version pipeline run links filter model."""

    # Artifact name and type are not DB fields and need to be handled separately
    FILTER_EXCLUDE_FIELDS = [
        *BaseFilter.FILTER_EXCLUDE_FIELDS,
        "artifact_name",
        "only_data_artifacts",
        "only_model_artifacts",
        "only_deployment_artifacts",
        "has_custom_name",
        "user",
    ]
    CLI_EXCLUDE_FIELDS = [
        *BaseFilter.CLI_EXCLUDE_FIELDS,
        "only_data_artifacts",
        "only_model_artifacts",
        "only_deployment_artifacts",
        "has_custom_name",
        "model_version_id",
        "updated",
        "id",
    ]

    model_version_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Filter by model version ID",
        union_mode="left_to_right",
    )
    artifact_version_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Filter by artifact ID",
        union_mode="left_to_right",
    )
    artifact_name: Optional[str] = Field(
        default=None,
        description="Name of the artifact",
    )
    only_data_artifacts: Optional[bool] = False
    only_model_artifacts: Optional[bool] = False
    only_deployment_artifacts: Optional[bool] = False
    has_custom_name: Optional[bool] = None
    user: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of the user that created the artifact.",
    )

    # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
    #  fields defined under base models. If not handled, this raises a warning.
    #  It is possible to suppress this warning message with the following
    #  configuration, however the ultimate solution is to rename these fields.
    #  Even though they do not cause any problems right now, if we are not
    #  careful we might overwrite some fields protected by pydantic.
    model_config = ConfigDict(protected_namespaces=())

    def get_custom_filters(
        self, table: Type["AnySchema"]
    ) -> List[Union["ColumnElement[bool]"]]:
        """Get custom filters.

        Args:
            table: The query table.

        Returns:
            A list of custom filters.
        """
        custom_filters = super().get_custom_filters(table)

        from sqlmodel import and_, col

        from zenml.zen_stores.schemas import (
            ArtifactSchema,
            ArtifactVersionSchema,
            ModelVersionArtifactSchema,
            UserSchema,
        )

        if self.artifact_name:
            value, filter_operator = self._resolve_operator(self.artifact_name)
            filter_ = StrFilter(
                operation=GenericFilterOps(filter_operator),
                column="name",
                value=value,
            )
            artifact_name_filter = and_(
                ModelVersionArtifactSchema.artifact_version_id
                == ArtifactVersionSchema.id,
                ArtifactVersionSchema.artifact_id == ArtifactSchema.id,
                filter_.generate_query_conditions(ArtifactSchema),
            )
            custom_filters.append(artifact_name_filter)

        if self.only_data_artifacts:
            data_artifact_filter = and_(
                ModelVersionArtifactSchema.artifact_version_id
                == ArtifactVersionSchema.id,
                col(ArtifactVersionSchema.type).not_in(
                    ["ServiceArtifact", "ModelArtifact"]
                ),
            )
            custom_filters.append(data_artifact_filter)

        if self.only_model_artifacts:
            model_artifact_filter = and_(
                ModelVersionArtifactSchema.artifact_version_id
                == ArtifactVersionSchema.id,
                ArtifactVersionSchema.type == "ModelArtifact",
            )
            custom_filters.append(model_artifact_filter)

        if self.only_deployment_artifacts:
            deployment_artifact_filter = and_(
                ModelVersionArtifactSchema.artifact_version_id
                == ArtifactVersionSchema.id,
                ArtifactVersionSchema.type == "ServiceArtifact",
            )
            custom_filters.append(deployment_artifact_filter)

        if self.has_custom_name is not None:
            custom_name_filter = and_(
                ModelVersionArtifactSchema.artifact_version_id
                == ArtifactVersionSchema.id,
                ArtifactVersionSchema.artifact_id == ArtifactSchema.id,
                ArtifactSchema.has_custom_name == self.has_custom_name,
            )
            custom_filters.append(custom_name_filter)

        if self.user:
            user_filter = and_(
                ModelVersionArtifactSchema.artifact_version_id
                == ArtifactVersionSchema.id,
                ArtifactVersionSchema.user_id == UserSchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.user,
                    table=UserSchema,
                    additional_columns=["full_name"],
                ),
            )
            custom_filters.append(user_filter)

        return custom_filters

get_custom_filters(table)

Get custom filters.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
List[Union[ColumnElement[bool]]]

A list of custom filters.

Source code in src/zenml/models/v2/core/model_version_artifact.py
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
def get_custom_filters(
    self, table: Type["AnySchema"]
) -> List[Union["ColumnElement[bool]"]]:
    """Get custom filters.

    Args:
        table: The query table.

    Returns:
        A list of custom filters.
    """
    custom_filters = super().get_custom_filters(table)

    from sqlmodel import and_, col

    from zenml.zen_stores.schemas import (
        ArtifactSchema,
        ArtifactVersionSchema,
        ModelVersionArtifactSchema,
        UserSchema,
    )

    if self.artifact_name:
        value, filter_operator = self._resolve_operator(self.artifact_name)
        filter_ = StrFilter(
            operation=GenericFilterOps(filter_operator),
            column="name",
            value=value,
        )
        artifact_name_filter = and_(
            ModelVersionArtifactSchema.artifact_version_id
            == ArtifactVersionSchema.id,
            ArtifactVersionSchema.artifact_id == ArtifactSchema.id,
            filter_.generate_query_conditions(ArtifactSchema),
        )
        custom_filters.append(artifact_name_filter)

    if self.only_data_artifacts:
        data_artifact_filter = and_(
            ModelVersionArtifactSchema.artifact_version_id
            == ArtifactVersionSchema.id,
            col(ArtifactVersionSchema.type).not_in(
                ["ServiceArtifact", "ModelArtifact"]
            ),
        )
        custom_filters.append(data_artifact_filter)

    if self.only_model_artifacts:
        model_artifact_filter = and_(
            ModelVersionArtifactSchema.artifact_version_id
            == ArtifactVersionSchema.id,
            ArtifactVersionSchema.type == "ModelArtifact",
        )
        custom_filters.append(model_artifact_filter)

    if self.only_deployment_artifacts:
        deployment_artifact_filter = and_(
            ModelVersionArtifactSchema.artifact_version_id
            == ArtifactVersionSchema.id,
            ArtifactVersionSchema.type == "ServiceArtifact",
        )
        custom_filters.append(deployment_artifact_filter)

    if self.has_custom_name is not None:
        custom_name_filter = and_(
            ModelVersionArtifactSchema.artifact_version_id
            == ArtifactVersionSchema.id,
            ArtifactVersionSchema.artifact_id == ArtifactSchema.id,
            ArtifactSchema.has_custom_name == self.has_custom_name,
        )
        custom_filters.append(custom_name_filter)

    if self.user:
        user_filter = and_(
            ModelVersionArtifactSchema.artifact_version_id
            == ArtifactVersionSchema.id,
            ArtifactVersionSchema.user_id == UserSchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.user,
                table=UserSchema,
                additional_columns=["full_name"],
            ),
        )
        custom_filters.append(user_filter)

    return custom_filters

ModelVersionArtifactRequest

Bases: BaseRequest

Request model for links between model versions and artifacts.

Source code in src/zenml/models/v2/core/model_version_artifact.py
43
44
45
46
47
48
49
50
51
52
53
54
55
class ModelVersionArtifactRequest(BaseRequest):
    """Request model for links between model versions and artifacts."""

    model_version: UUID
    artifact_version: UUID

    # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
    #  fields defined under base models. If not handled, this raises a warning.
    #  It is possible to suppress this warning message with the following
    #  configuration, however the ultimate solution is to rename these fields.
    #  Even though they do not cause any problems right now, if we are not
    #  careful we might overwrite some fields protected by pydantic.
    model_config = ConfigDict(protected_namespaces=())

ModelVersionArtifactResponse

Bases: BaseIdentifiedResponse[ModelVersionArtifactResponseBody, BaseResponseMetadata, ModelVersionArtifactResponseResources]

Response model for links between model versions and artifacts.

Source code in src/zenml/models/v2/core/model_version_artifact.py
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
class ModelVersionArtifactResponse(
    BaseIdentifiedResponse[
        ModelVersionArtifactResponseBody,
        BaseResponseMetadata,
        ModelVersionArtifactResponseResources,
    ]
):
    """Response model for links between model versions and artifacts."""

    @property
    def model_version(self) -> UUID:
        """The `model_version` property.

        Returns:
            the value of the property.
        """
        return self.get_body().model_version

    @property
    def artifact_version(self) -> "ArtifactVersionResponse":
        """The `artifact_version` property.

        Returns:
            the value of the property.
        """
        return self.get_body().artifact_version

artifact_version property

The artifact_version property.

Returns:

Type Description
ArtifactVersionResponse

the value of the property.

model_version property

The model_version property.

Returns:

Type Description
UUID

the value of the property.

ModelVersionArtifactResponseBody

Bases: BaseDatedResponseBody

Response body for links between model versions and artifacts.

Source code in src/zenml/models/v2/core/model_version_artifact.py
65
66
67
68
69
70
71
72
73
74
75
76
77
class ModelVersionArtifactResponseBody(BaseDatedResponseBody):
    """Response body for links between model versions and artifacts."""

    model_version: UUID
    artifact_version: "ArtifactVersionResponse"

    # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
    #  fields defined under base models. If not handled, this raises a warning.
    #  It is possible to suppress this warning message with the following
    #  configuration, however the ultimate solution is to rename these fields.
    #  Even though they do not cause any problems right now, if we are not
    #  careful we might overwrite some fields protected by pydantic.
    model_config = ConfigDict(protected_namespaces=())

ModelVersionFilter

Bases: WorkspaceScopedFilter, TaggableFilter

Filter model for model versions.

Source code in src/zenml/models/v2/core/model_version.py
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
class ModelVersionFilter(WorkspaceScopedFilter, TaggableFilter):
    """Filter model for model versions."""

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
        *TaggableFilter.FILTER_EXCLUDE_FIELDS,
        "run_metadata",
    ]
    CUSTOM_SORTING_OPTIONS = [
        *WorkspaceScopedFilter.CUSTOM_SORTING_OPTIONS,
        *TaggableFilter.CUSTOM_SORTING_OPTIONS,
    ]
    CLI_EXCLUDE_FIELDS = [
        *WorkspaceScopedFilter.CLI_EXCLUDE_FIELDS,
        *TaggableFilter.CLI_EXCLUDE_FIELDS,
    ]

    name: Optional[str] = Field(
        default=None,
        description="The name of the Model Version",
    )
    number: Optional[int] = Field(
        default=None,
        description="The number of the Model Version",
    )
    stage: Optional[Union[str, ModelStages]] = Field(
        description="The model version stage",
        default=None,
        union_mode="left_to_right",
    )
    run_metadata: Optional[Dict[str, str]] = Field(
        default=None,
        description="The run_metadata to filter the model versions by.",
    )

    _model_id: UUID = PrivateAttr(None)

    def set_scope_model(self, model_name_or_id: Union[str, UUID]) -> None:
        """Set the model to scope this response.

        Args:
            model_name_or_id: The model to scope this response to.
        """
        try:
            model_id = UUID(str(model_name_or_id))
        except ValueError:
            from zenml.client import Client

            model_id = Client().get_model(model_name_or_id).id

        self._model_id = model_id

    def get_custom_filters(
        self, table: Type["AnySchema"]
    ) -> List["ColumnElement[bool]"]:
        """Get custom filters.

        Args:
            table: The query table.

        Returns:
            A list of custom filters.
        """
        custom_filters = super().get_custom_filters(table)

        from sqlmodel import and_

        from zenml.zen_stores.schemas import (
            ModelVersionSchema,
            RunMetadataResourceSchema,
            RunMetadataSchema,
        )

        if self.run_metadata is not None:
            from zenml.enums import MetadataResourceTypes

            for key, value in self.run_metadata.items():
                additional_filter = and_(
                    RunMetadataResourceSchema.resource_id
                    == ModelVersionSchema.id,
                    RunMetadataResourceSchema.resource_type
                    == MetadataResourceTypes.MODEL_VERSION,
                    RunMetadataResourceSchema.run_metadata_id
                    == RunMetadataSchema.id,
                    self.generate_custom_query_conditions_for_column(
                        value=value,
                        table=RunMetadataSchema,
                        column="value",
                    ),
                )
                custom_filters.append(additional_filter)

        return custom_filters

    def apply_filter(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Applies the filter to a query.

        Args:
            query: The query to which to apply the filter.
            table: The query table.

        Returns:
            The query with filter applied.
        """
        query = super().apply_filter(query=query, table=table)

        if self._model_id:
            query = query.where(getattr(table, "model_id") == self._model_id)

        return query

apply_filter(query, table)

Applies the filter to a query.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the filter.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with filter applied.

Source code in src/zenml/models/v2/core/model_version.py
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
def apply_filter(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Applies the filter to a query.

    Args:
        query: The query to which to apply the filter.
        table: The query table.

    Returns:
        The query with filter applied.
    """
    query = super().apply_filter(query=query, table=table)

    if self._model_id:
        query = query.where(getattr(table, "model_id") == self._model_id)

    return query

get_custom_filters(table)

Get custom filters.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
List[ColumnElement[bool]]

A list of custom filters.

Source code in src/zenml/models/v2/core/model_version.py
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
def get_custom_filters(
    self, table: Type["AnySchema"]
) -> List["ColumnElement[bool]"]:
    """Get custom filters.

    Args:
        table: The query table.

    Returns:
        A list of custom filters.
    """
    custom_filters = super().get_custom_filters(table)

    from sqlmodel import and_

    from zenml.zen_stores.schemas import (
        ModelVersionSchema,
        RunMetadataResourceSchema,
        RunMetadataSchema,
    )

    if self.run_metadata is not None:
        from zenml.enums import MetadataResourceTypes

        for key, value in self.run_metadata.items():
            additional_filter = and_(
                RunMetadataResourceSchema.resource_id
                == ModelVersionSchema.id,
                RunMetadataResourceSchema.resource_type
                == MetadataResourceTypes.MODEL_VERSION,
                RunMetadataResourceSchema.run_metadata_id
                == RunMetadataSchema.id,
                self.generate_custom_query_conditions_for_column(
                    value=value,
                    table=RunMetadataSchema,
                    column="value",
                ),
            )
            custom_filters.append(additional_filter)

    return custom_filters

set_scope_model(model_name_or_id)

Set the model to scope this response.

Parameters:

Name Type Description Default
model_name_or_id Union[str, UUID]

The model to scope this response to.

required
Source code in src/zenml/models/v2/core/model_version.py
608
609
610
611
612
613
614
615
616
617
618
619
620
621
def set_scope_model(self, model_name_or_id: Union[str, UUID]) -> None:
    """Set the model to scope this response.

    Args:
        model_name_or_id: The model to scope this response to.
    """
    try:
        model_id = UUID(str(model_name_or_id))
    except ValueError:
        from zenml.client import Client

        model_id = Client().get_model(model_name_or_id).id

    self._model_id = model_id

ModelVersionPipelineRunFilter

Bases: BaseFilter

Model version pipeline run links filter model.

Source code in src/zenml/models/v2/core/model_version_pipeline_run.py
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
class ModelVersionPipelineRunFilter(BaseFilter):
    """Model version pipeline run links filter model."""

    FILTER_EXCLUDE_FIELDS = [
        *BaseFilter.FILTER_EXCLUDE_FIELDS,
        "pipeline_run_name",
        "user",
    ]
    CLI_EXCLUDE_FIELDS = [
        *BaseFilter.CLI_EXCLUDE_FIELDS,
        "model_version_id",
        "updated",
        "id",
    ]

    model_version_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Filter by model version ID",
        union_mode="left_to_right",
    )
    pipeline_run_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Filter by pipeline run ID",
        union_mode="left_to_right",
    )
    pipeline_run_name: Optional[str] = Field(
        default=None,
        description="Name of the pipeline run",
    )
    user: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of the user that created the pipeline run.",
    )

    # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
    #  fields defined under base models. If not handled, this raises a warning.
    #  It is possible to suppress this warning message with the following
    #  configuration, however the ultimate solution is to rename these fields.
    #  Even though they do not cause any problems right now, if we are not
    #  careful we might overwrite some fields protected by pydantic.
    model_config = ConfigDict(protected_namespaces=())

    def get_custom_filters(
        self, table: Type["AnySchema"]
    ) -> List["ColumnElement[bool]"]:
        """Get custom filters.

        Args:
            table: The query table.

        Returns:
            A list of custom filters.
        """
        custom_filters = super().get_custom_filters(table)

        from sqlmodel import and_

        from zenml.zen_stores.schemas import (
            ModelVersionPipelineRunSchema,
            PipelineRunSchema,
            UserSchema,
        )

        if self.pipeline_run_name:
            value, filter_operator = self._resolve_operator(
                self.pipeline_run_name
            )
            filter_ = StrFilter(
                operation=GenericFilterOps(filter_operator),
                column="name",
                value=value,
            )
            pipeline_run_name_filter = and_(
                ModelVersionPipelineRunSchema.pipeline_run_id
                == PipelineRunSchema.id,
                filter_.generate_query_conditions(PipelineRunSchema),
            )
            custom_filters.append(pipeline_run_name_filter)

        if self.user:
            user_filter = and_(
                ModelVersionPipelineRunSchema.pipeline_run_id
                == PipelineRunSchema.id,
                PipelineRunSchema.user_id == UserSchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.user,
                    table=UserSchema,
                    additional_columns=["full_name"],
                ),
            )
            custom_filters.append(user_filter)

        return custom_filters

get_custom_filters(table)

Get custom filters.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
List[ColumnElement[bool]]

A list of custom filters.

Source code in src/zenml/models/v2/core/model_version_pipeline_run.py
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
def get_custom_filters(
    self, table: Type["AnySchema"]
) -> List["ColumnElement[bool]"]:
    """Get custom filters.

    Args:
        table: The query table.

    Returns:
        A list of custom filters.
    """
    custom_filters = super().get_custom_filters(table)

    from sqlmodel import and_

    from zenml.zen_stores.schemas import (
        ModelVersionPipelineRunSchema,
        PipelineRunSchema,
        UserSchema,
    )

    if self.pipeline_run_name:
        value, filter_operator = self._resolve_operator(
            self.pipeline_run_name
        )
        filter_ = StrFilter(
            operation=GenericFilterOps(filter_operator),
            column="name",
            value=value,
        )
        pipeline_run_name_filter = and_(
            ModelVersionPipelineRunSchema.pipeline_run_id
            == PipelineRunSchema.id,
            filter_.generate_query_conditions(PipelineRunSchema),
        )
        custom_filters.append(pipeline_run_name_filter)

    if self.user:
        user_filter = and_(
            ModelVersionPipelineRunSchema.pipeline_run_id
            == PipelineRunSchema.id,
            PipelineRunSchema.user_id == UserSchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.user,
                table=UserSchema,
                additional_columns=["full_name"],
            ),
        )
        custom_filters.append(user_filter)

    return custom_filters

ModelVersionPipelineRunRequest

Bases: BaseRequest

Request model for links between model versions and pipeline runs.

Source code in src/zenml/models/v2/core/model_version_pipeline_run.py
42
43
44
45
46
47
48
49
50
51
52
53
54
class ModelVersionPipelineRunRequest(BaseRequest):
    """Request model for links between model versions and pipeline runs."""

    model_version: UUID
    pipeline_run: UUID

    # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
    #  fields defined under base models. If not handled, this raises a warning.
    #  It is possible to suppress this warning message with the following
    #  configuration, however the ultimate solution is to rename these fields.
    #  Even though they do not cause any problems right now, if we are not
    #  careful we might overwrite some fields protected by pydantic.
    model_config = ConfigDict(protected_namespaces=())

ModelVersionPipelineRunResponse

Bases: BaseIdentifiedResponse[ModelVersionPipelineRunResponseBody, BaseResponseMetadata, ModelVersionPipelineRunResponseResources]

Response model for links between model versions and pipeline runs.

Source code in src/zenml/models/v2/core/model_version_pipeline_run.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
class ModelVersionPipelineRunResponse(
    BaseIdentifiedResponse[
        ModelVersionPipelineRunResponseBody,
        BaseResponseMetadata,
        ModelVersionPipelineRunResponseResources,
    ]
):
    """Response model for links between model versions and pipeline runs."""

    @property
    def model_version(self) -> UUID:
        """The `model_version` property.

        Returns:
            the value of the property.
        """
        return self.get_body().model_version

    @property
    def pipeline_run(self) -> "PipelineRunResponse":
        """The `pipeline_run` property.

        Returns:
            the value of the property.
        """
        return self.get_body().pipeline_run

model_version property

The model_version property.

Returns:

Type Description
UUID

the value of the property.

pipeline_run property

The pipeline_run property.

Returns:

Type Description
PipelineRunResponse

the value of the property.

ModelVersionPipelineRunResponseBody

Bases: BaseDatedResponseBody

Response body for links between model versions and pipeline runs.

Source code in src/zenml/models/v2/core/model_version_pipeline_run.py
64
65
66
67
68
69
70
71
72
73
74
75
76
class ModelVersionPipelineRunResponseBody(BaseDatedResponseBody):
    """Response body for links between model versions and pipeline runs."""

    model_version: UUID
    pipeline_run: PipelineRunResponse

    # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
    #  fields defined under base models. If not handled, this raises a warning.
    #  It is possible to suppress this warning message with the following
    #  configuration, however the ultimate solution is to rename these fields.
    #  Even though they do not cause any problems right now, if we are not
    #  careful we might overwrite some fields protected by pydantic.
    model_config = ConfigDict(protected_namespaces=())

ModelVersionRequest

Bases: WorkspaceScopedRequest

Request model for model versions.

Source code in src/zenml/models/v2/core/model_version.py
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
class ModelVersionRequest(WorkspaceScopedRequest):
    """Request model for model versions."""

    name: Optional[str] = Field(
        description="The name of the model version",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    description: Optional[str] = Field(
        description="The description of the model version",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    stage: Optional[str] = Field(
        description="The stage of the model version",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )

    model: UUID = Field(
        description="The ID of the model containing version",
    )
    tags: Optional[List[str]] = Field(
        title="Tags associated with the model version",
        default=None,
    )

ModelVersionResponse

Bases: WorkspaceScopedResponse[ModelVersionResponseBody, ModelVersionResponseMetadata, ModelVersionResponseResources]

Response model for model versions.

Source code in src/zenml/models/v2/core/model_version.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
class ModelVersionResponse(
    WorkspaceScopedResponse[
        ModelVersionResponseBody,
        ModelVersionResponseMetadata,
        ModelVersionResponseResources,
    ]
):
    """Response model for model versions."""

    name: Optional[str] = Field(
        description="The name of the model version",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )

    @property
    def stage(self) -> Optional[str]:
        """The `stage` property.

        Returns:
            the value of the property.
        """
        return self.get_body().stage

    @property
    def number(self) -> int:
        """The `number` property.

        Returns:
            the value of the property.
        """
        return self.get_body().number

    @property
    def model(self) -> "ModelResponse":
        """The `model` property.

        Returns:
            the value of the property.
        """
        return self.get_body().model

    @property
    def model_artifact_ids(self) -> Dict[str, Dict[str, UUID]]:
        """The `model_artifact_ids` property.

        Returns:
            the value of the property.
        """
        return self.get_body().model_artifact_ids

    @property
    def data_artifact_ids(self) -> Dict[str, Dict[str, UUID]]:
        """The `data_artifact_ids` property.

        Returns:
            the value of the property.
        """
        return self.get_body().data_artifact_ids

    @property
    def deployment_artifact_ids(self) -> Dict[str, Dict[str, UUID]]:
        """The `deployment_artifact_ids` property.

        Returns:
            the value of the property.
        """
        return self.get_body().deployment_artifact_ids

    @property
    def pipeline_run_ids(self) -> Dict[str, UUID]:
        """The `pipeline_run_ids` property.

        Returns:
            the value of the property.
        """
        return self.get_body().pipeline_run_ids

    @property
    def tags(self) -> List[TagResponse]:
        """The `tags` property.

        Returns:
            the value of the property.
        """
        return self.get_body().tags

    @property
    def description(self) -> Optional[str]:
        """The `description` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().description

    @property
    def run_metadata(self) -> Dict[str, MetadataType]:
        """The `run_metadata` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().run_metadata

    def get_hydrated_version(self) -> "ModelVersionResponse":
        """Get the hydrated version of this model version.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_model_version(self.id)

    # Helper functions
    def to_model_class(
        self,
        suppress_class_validation_warnings: bool = True,
    ) -> "Model":
        """Convert response model to Model object.

        Args:
            suppress_class_validation_warnings: internally used to suppress
                repeated warnings.

        Returns:
            Model object
        """
        from zenml.model.model import Model

        mv = Model(
            name=self.model.name,
            license=self.model.license,
            description=self.description,
            audience=self.model.audience,
            use_cases=self.model.use_cases,
            limitations=self.model.limitations,
            trade_offs=self.model.trade_offs,
            ethics=self.model.ethics,
            tags=[t.name for t in self.tags],
            version=self.name,
            suppress_class_validation_warnings=suppress_class_validation_warnings,
            model_version_id=self.id,
        )

        return mv

    @property
    def model_artifacts(
        self,
    ) -> Dict[str, Dict[str, "ArtifactVersionResponse"]]:
        """Get all model artifacts linked to this model version.

        Returns:
            Dictionary of model artifacts with versions as
            Dict[str, Dict[str, ArtifactResponse]]
        """
        from zenml.client import Client

        return {
            name: {
                version: Client().get_artifact_version(a)
                for version, a in self.model_artifact_ids[name].items()
            }
            for name in self.model_artifact_ids
        }

    @property
    def data_artifacts(
        self,
    ) -> Dict[str, Dict[str, "ArtifactVersionResponse"]]:
        """Get all data artifacts linked to this model version.

        Returns:
            Dictionary of data artifacts with versions as
            Dict[str, Dict[str, ArtifactResponse]]
        """
        from zenml.client import Client

        return {
            name: {
                version: Client().get_artifact_version(a)
                for version, a in self.data_artifact_ids[name].items()
            }
            for name in self.data_artifact_ids
        }

    @property
    def deployment_artifacts(
        self,
    ) -> Dict[str, Dict[str, "ArtifactVersionResponse"]]:
        """Get all deployment artifacts linked to this model version.

        Returns:
            Dictionary of deployment artifacts with versions as
            Dict[str, Dict[str, ArtifactResponse]]
        """
        from zenml.client import Client

        return {
            name: {
                version: Client().get_artifact_version(a)
                for version, a in self.deployment_artifact_ids[name].items()
            }
            for name in self.deployment_artifact_ids
        }

    @property
    def pipeline_runs(self) -> Dict[str, "PipelineRunResponse"]:
        """Get all pipeline runs linked to this version.

        Returns:
            Dictionary of Pipeline Runs as PipelineRunResponseModel
        """
        from zenml.client import Client

        return {
            name: Client().get_pipeline_run(pr)
            for name, pr in self.pipeline_run_ids.items()
        }

    def _get_linked_object(
        self,
        name: str,
        version: Optional[str] = None,
        type: Optional[ArtifactType] = None,
    ) -> Optional["ArtifactVersionResponse"]:
        """Get the artifact linked to this model version given type.

        Args:
            name: The name of the artifact to retrieve.
            version: The version of the artifact to retrieve (None for
                latest/non-versioned)
            type: The type of the artifact to filter by.

        Returns:
            Specific version of an artifact from collection or None
        """
        from zenml.client import Client

        artifact_versions = Client().list_artifact_versions(
            sort_by="desc:created",
            size=1,
            name=name,
            version=version,
            model_version_id=self.id,
            type=type,
            hydrate=True,
        )

        if not artifact_versions.items:
            return None
        return artifact_versions.items[0]

    def get_artifact(
        self,
        name: str,
        version: Optional[str] = None,
    ) -> Optional["ArtifactVersionResponse"]:
        """Get the artifact linked to this model version.

        Args:
            name: The name of the artifact to retrieve.
            version: The version of the artifact to retrieve (None for
                latest/non-versioned)

        Returns:
            Specific version of an artifact or None
        """
        return self._get_linked_object(name, version)

    def get_model_artifact(
        self,
        name: str,
        version: Optional[str] = None,
    ) -> Optional["ArtifactVersionResponse"]:
        """Get the model artifact linked to this model version.

        Args:
            name: The name of the model artifact to retrieve.
            version: The version of the model artifact to retrieve (None for
                latest/non-versioned)

        Returns:
            Specific version of the model artifact or None
        """
        return self._get_linked_object(name, version, ArtifactType.MODEL)

    def get_data_artifact(
        self,
        name: str,
        version: Optional[str] = None,
    ) -> Optional["ArtifactVersionResponse"]:
        """Get the data artifact linked to this model version.

        Args:
            name: The name of the data artifact to retrieve.
            version: The version of the data artifact to retrieve (None for
                latest/non-versioned)

        Returns:
            Specific version of the data artifact or None
        """
        return self._get_linked_object(name, version, ArtifactType.DATA)

    def get_deployment_artifact(
        self,
        name: str,
        version: Optional[str] = None,
    ) -> Optional["ArtifactVersionResponse"]:
        """Get the deployment artifact linked to this model version.

        Args:
            name: The name of the deployment artifact to retrieve.
            version: The version of the deployment artifact to retrieve (None for
                latest/non-versioned)

        Returns:
            Specific version of the deployment artifact or None
        """
        return self._get_linked_object(name, version, ArtifactType.SERVICE)

    def get_pipeline_run(self, name: str) -> "PipelineRunResponse":
        """Get pipeline run linked to this version.

        Args:
            name: The name of the pipeline run to retrieve.

        Returns:
            PipelineRun as PipelineRunResponseModel
        """
        from zenml.client import Client

        return Client().get_pipeline_run(self.pipeline_run_ids[name])

    def set_stage(
        self, stage: Union[str, ModelStages], force: bool = False
    ) -> None:
        """Sets this Model Version to a desired stage.

        Args:
            stage: the target stage for model version.
            force: whether to force archiving of current model version in
                target stage or raise.

        Raises:
            ValueError: if model_stage is not valid.
        """
        from zenml.client import Client

        stage = getattr(stage, "value", stage)
        if stage not in [stage.value for stage in ModelStages]:
            raise ValueError(f"`{stage}` is not a valid model stage.")

        Client().update_model_version(
            model_name_or_id=self.model.id,
            version_name_or_id=self.id,
            stage=stage,
            force=force,
        )

data_artifact_ids property

The data_artifact_ids property.

Returns:

Type Description
Dict[str, Dict[str, UUID]]

the value of the property.

data_artifacts property

Get all data artifacts linked to this model version.

Returns:

Type Description
Dict[str, Dict[str, ArtifactVersionResponse]]

Dictionary of data artifacts with versions as

Dict[str, Dict[str, ArtifactVersionResponse]]

Dict[str, Dict[str, ArtifactResponse]]

deployment_artifact_ids property

The deployment_artifact_ids property.

Returns:

Type Description
Dict[str, Dict[str, UUID]]

the value of the property.

deployment_artifacts property

Get all deployment artifacts linked to this model version.

Returns:

Type Description
Dict[str, Dict[str, ArtifactVersionResponse]]

Dictionary of deployment artifacts with versions as

Dict[str, Dict[str, ArtifactVersionResponse]]

Dict[str, Dict[str, ArtifactResponse]]

description property

The description property.

Returns:

Type Description
Optional[str]

the value of the property.

model property

The model property.

Returns:

Type Description
ModelResponse

the value of the property.

model_artifact_ids property

The model_artifact_ids property.

Returns:

Type Description
Dict[str, Dict[str, UUID]]

the value of the property.

model_artifacts property

Get all model artifacts linked to this model version.

Returns:

Type Description
Dict[str, Dict[str, ArtifactVersionResponse]]

Dictionary of model artifacts with versions as

Dict[str, Dict[str, ArtifactVersionResponse]]

Dict[str, Dict[str, ArtifactResponse]]

number property

The number property.

Returns:

Type Description
int

the value of the property.

pipeline_run_ids property

The pipeline_run_ids property.

Returns:

Type Description
Dict[str, UUID]

the value of the property.

pipeline_runs property

Get all pipeline runs linked to this version.

Returns:

Type Description
Dict[str, PipelineRunResponse]

Dictionary of Pipeline Runs as PipelineRunResponseModel

run_metadata property

The run_metadata property.

Returns:

Type Description
Dict[str, MetadataType]

the value of the property.

stage property

The stage property.

Returns:

Type Description
Optional[str]

the value of the property.

tags property

The tags property.

Returns:

Type Description
List[TagResponse]

the value of the property.

get_artifact(name, version=None)

Get the artifact linked to this model version.

Parameters:

Name Type Description Default
name str

The name of the artifact to retrieve.

required
version Optional[str]

The version of the artifact to retrieve (None for latest/non-versioned)

None

Returns:

Type Description
Optional[ArtifactVersionResponse]

Specific version of an artifact or None

Source code in src/zenml/models/v2/core/model_version.py
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
def get_artifact(
    self,
    name: str,
    version: Optional[str] = None,
) -> Optional["ArtifactVersionResponse"]:
    """Get the artifact linked to this model version.

    Args:
        name: The name of the artifact to retrieve.
        version: The version of the artifact to retrieve (None for
            latest/non-versioned)

    Returns:
        Specific version of an artifact or None
    """
    return self._get_linked_object(name, version)

get_data_artifact(name, version=None)

Get the data artifact linked to this model version.

Parameters:

Name Type Description Default
name str

The name of the data artifact to retrieve.

required
version Optional[str]

The version of the data artifact to retrieve (None for latest/non-versioned)

None

Returns:

Type Description
Optional[ArtifactVersionResponse]

Specific version of the data artifact or None

Source code in src/zenml/models/v2/core/model_version.py
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
def get_data_artifact(
    self,
    name: str,
    version: Optional[str] = None,
) -> Optional["ArtifactVersionResponse"]:
    """Get the data artifact linked to this model version.

    Args:
        name: The name of the data artifact to retrieve.
        version: The version of the data artifact to retrieve (None for
            latest/non-versioned)

    Returns:
        Specific version of the data artifact or None
    """
    return self._get_linked_object(name, version, ArtifactType.DATA)

get_deployment_artifact(name, version=None)

Get the deployment artifact linked to this model version.

Parameters:

Name Type Description Default
name str

The name of the deployment artifact to retrieve.

required
version Optional[str]

The version of the deployment artifact to retrieve (None for latest/non-versioned)

None

Returns:

Type Description
Optional[ArtifactVersionResponse]

Specific version of the deployment artifact or None

Source code in src/zenml/models/v2/core/model_version.py
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
def get_deployment_artifact(
    self,
    name: str,
    version: Optional[str] = None,
) -> Optional["ArtifactVersionResponse"]:
    """Get the deployment artifact linked to this model version.

    Args:
        name: The name of the deployment artifact to retrieve.
        version: The version of the deployment artifact to retrieve (None for
            latest/non-versioned)

    Returns:
        Specific version of the deployment artifact or None
    """
    return self._get_linked_object(name, version, ArtifactType.SERVICE)

get_hydrated_version()

Get the hydrated version of this model version.

Returns:

Type Description
ModelVersionResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/model_version.py
310
311
312
313
314
315
316
317
318
def get_hydrated_version(self) -> "ModelVersionResponse":
    """Get the hydrated version of this model version.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_model_version(self.id)

get_model_artifact(name, version=None)

Get the model artifact linked to this model version.

Parameters:

Name Type Description Default
name str

The name of the model artifact to retrieve.

required
version Optional[str]

The version of the model artifact to retrieve (None for latest/non-versioned)

None

Returns:

Type Description
Optional[ArtifactVersionResponse]

Specific version of the model artifact or None

Source code in src/zenml/models/v2/core/model_version.py
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
def get_model_artifact(
    self,
    name: str,
    version: Optional[str] = None,
) -> Optional["ArtifactVersionResponse"]:
    """Get the model artifact linked to this model version.

    Args:
        name: The name of the model artifact to retrieve.
        version: The version of the model artifact to retrieve (None for
            latest/non-versioned)

    Returns:
        Specific version of the model artifact or None
    """
    return self._get_linked_object(name, version, ArtifactType.MODEL)

get_pipeline_run(name)

Get pipeline run linked to this version.

Parameters:

Name Type Description Default
name str

The name of the pipeline run to retrieve.

required

Returns:

Type Description
PipelineRunResponse

PipelineRun as PipelineRunResponseModel

Source code in src/zenml/models/v2/core/model_version.py
528
529
530
531
532
533
534
535
536
537
538
539
def get_pipeline_run(self, name: str) -> "PipelineRunResponse":
    """Get pipeline run linked to this version.

    Args:
        name: The name of the pipeline run to retrieve.

    Returns:
        PipelineRun as PipelineRunResponseModel
    """
    from zenml.client import Client

    return Client().get_pipeline_run(self.pipeline_run_ids[name])

set_stage(stage, force=False)

Sets this Model Version to a desired stage.

Parameters:

Name Type Description Default
stage Union[str, ModelStages]

the target stage for model version.

required
force bool

whether to force archiving of current model version in target stage or raise.

False

Raises:

Type Description
ValueError

if model_stage is not valid.

Source code in src/zenml/models/v2/core/model_version.py
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
def set_stage(
    self, stage: Union[str, ModelStages], force: bool = False
) -> None:
    """Sets this Model Version to a desired stage.

    Args:
        stage: the target stage for model version.
        force: whether to force archiving of current model version in
            target stage or raise.

    Raises:
        ValueError: if model_stage is not valid.
    """
    from zenml.client import Client

    stage = getattr(stage, "value", stage)
    if stage not in [stage.value for stage in ModelStages]:
        raise ValueError(f"`{stage}` is not a valid model stage.")

    Client().update_model_version(
        model_name_or_id=self.model.id,
        version_name_or_id=self.id,
        stage=stage,
        force=force,
    )

to_model_class(suppress_class_validation_warnings=True)

Convert response model to Model object.

Parameters:

Name Type Description Default
suppress_class_validation_warnings bool

internally used to suppress repeated warnings.

True

Returns:

Type Description
Model

Model object

Source code in src/zenml/models/v2/core/model_version.py
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
def to_model_class(
    self,
    suppress_class_validation_warnings: bool = True,
) -> "Model":
    """Convert response model to Model object.

    Args:
        suppress_class_validation_warnings: internally used to suppress
            repeated warnings.

    Returns:
        Model object
    """
    from zenml.model.model import Model

    mv = Model(
        name=self.model.name,
        license=self.model.license,
        description=self.description,
        audience=self.model.audience,
        use_cases=self.model.use_cases,
        limitations=self.model.limitations,
        trade_offs=self.model.trade_offs,
        ethics=self.model.ethics,
        tags=[t.name for t in self.tags],
        version=self.name,
        suppress_class_validation_warnings=suppress_class_validation_warnings,
        model_version_id=self.id,
    )

    return mv

ModelVersionResponseBody

Bases: WorkspaceScopedResponseBody

Response body for model versions.

Source code in src/zenml/models/v2/core/model_version.py
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
class ModelVersionResponseBody(WorkspaceScopedResponseBody):
    """Response body for model versions."""

    stage: Optional[str] = Field(
        description="The stage of the model version",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    number: int = Field(
        description="The number of the model version",
    )
    model: "ModelResponse" = Field(
        description="The model containing version",
    )
    model_artifact_ids: Dict[str, Dict[str, UUID]] = Field(
        description="Model artifacts linked to the model version",
        default={},
    )
    data_artifact_ids: Dict[str, Dict[str, UUID]] = Field(
        description="Data artifacts linked to the model version",
        default={},
    )
    deployment_artifact_ids: Dict[str, Dict[str, UUID]] = Field(
        description="Deployment artifacts linked to the model version",
        default={},
    )
    pipeline_run_ids: Dict[str, UUID] = Field(
        description="Pipeline runs linked to the model version",
        default={},
    )
    tags: List[TagResponse] = Field(
        title="Tags associated with the model version", default=[]
    )

    # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
    #  fields defined under base models. If not handled, this raises a warning.
    #  It is possible to suppress this warning message with the following
    #  configuration, however the ultimate solution is to rename these fields.
    #  Even though they do not cause any problems right now, if we are not
    #  careful we might overwrite some fields protected by pydantic.
    model_config = ConfigDict(protected_namespaces=())

ModelVersionResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for model versions.

Source code in src/zenml/models/v2/core/model_version.py
183
184
185
186
187
188
189
190
191
192
193
194
class ModelVersionResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for model versions."""

    description: Optional[str] = Field(
        description="The description of the model version",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    run_metadata: Dict[str, MetadataType] = Field(
        description="Metadata linked to the model version",
        default={},
    )

ModelVersionResponseResources

Bases: WorkspaceScopedResponseResources

Class for all resource models associated with the model version entity.

Source code in src/zenml/models/v2/core/model_version.py
197
198
199
200
201
202
class ModelVersionResponseResources(WorkspaceScopedResponseResources):
    """Class for all resource models associated with the model version entity."""

    services: Page[ServiceResponse] = Field(
        description="Services linked to the model version",
    )

ModelVersionUpdate

Bases: BaseModel

Update model for model versions.

Source code in src/zenml/models/v2/core/model_version.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
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
class ModelVersionUpdate(BaseModel):
    """Update model for model versions."""

    model: UUID = Field(
        description="The ID of the model containing version",
    )
    stage: Optional[Union[str, ModelStages]] = Field(
        description="Target model version stage to be set",
        default=None,
        union_mode="left_to_right",
    )
    force: bool = Field(
        description="Whether existing model version in target stage should be "
        "silently archived or an error should be raised.",
        default=False,
    )
    name: Optional[str] = Field(
        description="Target model version name to be set",
        default=None,
    )
    description: Optional[str] = Field(
        description="Target model version description to be set",
        default=None,
    )
    add_tags: Optional[List[str]] = Field(
        description="Tags to be added to the model version",
        default=None,
    )
    remove_tags: Optional[List[str]] = Field(
        description="Tags to be removed from the model version",
        default=None,
    )

    @field_validator("stage")
    @classmethod
    def _validate_stage(cls, stage: str) -> str:
        stage = getattr(stage, "value", stage)
        if stage is not None and stage not in [
            stage.value for stage in ModelStages
        ]:
            raise ValueError(f"`{stage}` is not a valid model stage.")
        return stage

NumericFilter

Bases: Filter

Filter for all numeric fields.

Source code in src/zenml/models/v2/base/filter.py
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
class NumericFilter(Filter):
    """Filter for all numeric fields."""

    value: Union[float, datetime] = Field(union_mode="left_to_right")

    ALLOWED_OPS: ClassVar[List[str]] = [
        GenericFilterOps.EQUALS,
        GenericFilterOps.NOT_EQUALS,
        GenericFilterOps.GT,
        GenericFilterOps.GTE,
        GenericFilterOps.LT,
        GenericFilterOps.LTE,
    ]

    def generate_query_conditions_from_column(self, column: Any) -> Any:
        """Generate query conditions for a numeric column.

        Args:
            column: The numeric column of an SQLModel table on which to filter.

        Returns:
            A list of query conditions.
        """
        if self.operation == GenericFilterOps.GTE:
            return column >= self.value
        if self.operation == GenericFilterOps.GT:
            return column > self.value
        if self.operation == GenericFilterOps.LTE:
            return column <= self.value
        if self.operation == GenericFilterOps.LT:
            return column < self.value
        if self.operation == GenericFilterOps.NOT_EQUALS:
            return column != self.value
        return column == self.value

generate_query_conditions_from_column(column)

Generate query conditions for a numeric column.

Parameters:

Name Type Description Default
column Any

The numeric column of an SQLModel table on which to filter.

required

Returns:

Type Description
Any

A list of query conditions.

Source code in src/zenml/models/v2/base/filter.py
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
def generate_query_conditions_from_column(self, column: Any) -> Any:
    """Generate query conditions for a numeric column.

    Args:
        column: The numeric column of an SQLModel table on which to filter.

    Returns:
        A list of query conditions.
    """
    if self.operation == GenericFilterOps.GTE:
        return column >= self.value
    if self.operation == GenericFilterOps.GT:
        return column > self.value
    if self.operation == GenericFilterOps.LTE:
        return column <= self.value
    if self.operation == GenericFilterOps.LT:
        return column < self.value
    if self.operation == GenericFilterOps.NOT_EQUALS:
        return column != self.value
    return column == self.value

OAuthDeviceAuthorizationRequest

Bases: BaseModel

OAuth2 device authorization grant request.

Source code in src/zenml/models/v2/misc/auth_models.py
28
29
30
31
32
class OAuthDeviceAuthorizationRequest(BaseModel):
    """OAuth2 device authorization grant request."""

    client_id: UUID
    device_id: Optional[UUID] = None

OAuthDeviceAuthorizationResponse

Bases: BaseModel

OAuth2 device authorization grant response.

Source code in src/zenml/models/v2/misc/auth_models.py
104
105
106
107
108
109
110
111
112
class OAuthDeviceAuthorizationResponse(BaseModel):
    """OAuth2 device authorization grant response."""

    device_code: str
    user_code: str
    verification_uri: str
    verification_uri_complete: Optional[str] = None
    expires_in: int
    interval: int

OAuthDeviceFilter

Bases: UserScopedFilter

Model to enable advanced filtering of OAuth2 devices.

Source code in src/zenml/models/v2/core/device.py
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
class OAuthDeviceFilter(UserScopedFilter):
    """Model to enable advanced filtering of OAuth2 devices."""

    expires: Optional[Union[datetime, str, None]] = Field(
        default=None,
        description="The expiration date of the OAuth2 device.",
        union_mode="left_to_right",
    )
    client_id: Union[UUID, str, None] = Field(
        default=None,
        description="The client ID of the OAuth2 device.",
        union_mode="left_to_right",
    )
    status: Union[OAuthDeviceStatus, str, None] = Field(
        default=None,
        description="The status of the OAuth2 device.",
        union_mode="left_to_right",
    )
    trusted_device: Union[bool, str, None] = Field(
        default=None,
        description="Whether the OAuth2 device was marked as trusted.",
        union_mode="left_to_right",
    )
    failed_auth_attempts: Union[int, str, None] = Field(
        default=None,
        description="The number of failed authentication attempts.",
        union_mode="left_to_right",
    )
    last_login: Optional[Union[datetime, str, None]] = Field(
        default=None,
        description="The date of the last successful login.",
        union_mode="left_to_right",
    )

OAuthDeviceInternalRequest

Bases: BaseRequest

Internal request model for OAuth2 devices.

Source code in src/zenml/models/v2/core/device.py
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
class OAuthDeviceInternalRequest(BaseRequest):
    """Internal request model for OAuth2 devices."""

    client_id: UUID = Field(description="The client ID of the OAuth2 device.")
    expires_in: int = Field(
        description="The number of seconds after which the OAuth2 device "
        "expires and can no longer be used for authentication."
    )
    os: Optional[str] = Field(
        default=None,
        description="The operating system of the device used for "
        "authentication.",
    )
    ip_address: Optional[str] = Field(
        default=None,
        description="The IP address of the device used for authentication.",
    )
    hostname: Optional[str] = Field(
        default=None,
        description="The hostname of the device used for authentication.",
    )
    python_version: Optional[str] = Field(
        default=None,
        description="The Python version of the device used for authentication.",
    )
    zenml_version: Optional[str] = Field(
        default=None,
        description="The ZenML version of the device used for authentication.",
    )
    city: Optional[str] = Field(
        default=None,
        description="The city where the device is located.",
    )
    region: Optional[str] = Field(
        default=None,
        description="The region where the device is located.",
    )
    country: Optional[str] = Field(
        default=None,
        description="The country where the device is located.",
    )

OAuthDeviceInternalResponse

Bases: OAuthDeviceResponse

OAuth2 device response model used internally for authentication.

Source code in src/zenml/models/v2/core/device.py
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
class OAuthDeviceInternalResponse(OAuthDeviceResponse):
    """OAuth2 device response model used internally for authentication."""

    user_code: str = Field(
        title="The user code.",
    )
    device_code: str = Field(
        title="The device code.",
    )

    def _verify_code(
        self,
        code: str,
        code_hash: Optional[str],
    ) -> bool:
        """Verifies a given code against the stored (hashed) code.

        Args:
            code: The code to verify.
            code_hash: The hashed code to verify against.

        Returns:
            True if the code is valid, False otherwise.
        """
        context = CryptContext(schemes=["bcrypt"], deprecated="auto")
        result = context.verify(code, code_hash)

        return result

    def verify_user_code(
        self,
        user_code: str,
    ) -> bool:
        """Verifies a given user code against the stored (hashed) user code.

        Args:
            user_code: The user code to verify.

        Returns:
            True if the user code is valid, False otherwise.
        """
        return self._verify_code(user_code, self.user_code)

    def verify_device_code(
        self,
        device_code: str,
    ) -> bool:
        """Verifies a given device code against the stored (hashed) device code.

        Args:
            device_code: The device code to verify.

        Returns:
            True if the device code is valid, False otherwise.
        """
        return self._verify_code(device_code, self.device_code)

verify_device_code(device_code)

Verifies a given device code against the stored (hashed) device code.

Parameters:

Name Type Description Default
device_code str

The device code to verify.

required

Returns:

Type Description
bool

True if the device code is valid, False otherwise.

Source code in src/zenml/models/v2/core/device.py
421
422
423
424
425
426
427
428
429
430
431
432
433
def verify_device_code(
    self,
    device_code: str,
) -> bool:
    """Verifies a given device code against the stored (hashed) device code.

    Args:
        device_code: The device code to verify.

    Returns:
        True if the device code is valid, False otherwise.
    """
    return self._verify_code(device_code, self.device_code)

verify_user_code(user_code)

Verifies a given user code against the stored (hashed) user code.

Parameters:

Name Type Description Default
user_code str

The user code to verify.

required

Returns:

Type Description
bool

True if the user code is valid, False otherwise.

Source code in src/zenml/models/v2/core/device.py
407
408
409
410
411
412
413
414
415
416
417
418
419
def verify_user_code(
    self,
    user_code: str,
) -> bool:
    """Verifies a given user code against the stored (hashed) user code.

    Args:
        user_code: The user code to verify.

    Returns:
        True if the user code is valid, False otherwise.
    """
    return self._verify_code(user_code, self.user_code)

OAuthDeviceInternalUpdate

Bases: OAuthDeviceUpdate

OAuth2 device update model used internally for authentication.

Source code in src/zenml/models/v2/core/device.py
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
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
class OAuthDeviceInternalUpdate(OAuthDeviceUpdate):
    """OAuth2 device update model used internally for authentication."""

    user_id: Optional[UUID] = Field(
        default=None, description="User that owns the OAuth2 device."
    )
    status: Optional[OAuthDeviceStatus] = Field(
        default=None, description="The new status of the OAuth2 device."
    )
    expires_in: Optional[int] = Field(
        default=None,
        description="Set the device to expire in the given number of seconds. "
        "If the value is 0 or negative, the device is set to never expire.",
    )
    failed_auth_attempts: Optional[int] = Field(
        default=None,
        description="Set the number of failed authentication attempts.",
    )
    trusted_device: Optional[bool] = Field(
        default=None,
        description="Whether to mark the OAuth2 device as trusted. A trusted "
        "device has a much longer validity time.",
    )
    update_last_login: bool = Field(
        default=False, description="Whether to update the last login date."
    )
    generate_new_codes: bool = Field(
        default=False,
        description="Whether to generate new user and device codes.",
    )
    os: Optional[str] = Field(
        default=None,
        description="The operating system of the device used for "
        "authentication.",
    )
    ip_address: Optional[str] = Field(
        default=None,
        description="The IP address of the device used for authentication.",
    )
    hostname: Optional[str] = Field(
        default=None,
        description="The hostname of the device used for authentication.",
    )
    python_version: Optional[str] = Field(
        default=None,
        description="The Python version of the device used for authentication.",
    )
    zenml_version: Optional[str] = Field(
        default=None,
        description="The ZenML version of the device used for authentication.",
    )
    city: Optional[str] = Field(
        default=None,
        description="The city where the device is located.",
    )
    region: Optional[str] = Field(
        default=None,
        description="The region where the device is located.",
    )
    country: Optional[str] = Field(
        default=None,
        description="The country where the device is located.",
    )

OAuthDeviceResponse

Bases: UserScopedResponse[OAuthDeviceResponseBody, OAuthDeviceResponseMetadata, OAuthDeviceResponseResources]

Response model for OAuth2 devices.

Source code in src/zenml/models/v2/core/device.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
class OAuthDeviceResponse(
    UserScopedResponse[
        OAuthDeviceResponseBody,
        OAuthDeviceResponseMetadata,
        OAuthDeviceResponseResources,
    ]
):
    """Response model for OAuth2 devices."""

    _warn_on_response_updates = False

    def get_hydrated_version(self) -> "OAuthDeviceResponse":
        """Get the hydrated version of this OAuth2 device.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_authorized_device(self.id)

    # Body and metadata properties
    @property
    def client_id(self) -> UUID:
        """The `client_id` property.

        Returns:
            the value of the property.
        """
        return self.get_body().client_id

    @property
    def expires(self) -> Optional[datetime]:
        """The `expires` property.

        Returns:
            the value of the property.
        """
        return self.get_body().expires

    @property
    def trusted_device(self) -> bool:
        """The `trusted_device` property.

        Returns:
            the value of the property.
        """
        return self.get_body().trusted_device

    @property
    def status(self) -> OAuthDeviceStatus:
        """The `status` property.

        Returns:
            the value of the property.
        """
        return self.get_body().status

    @property
    def os(self) -> Optional[str]:
        """The `os` property.

        Returns:
            the value of the property.
        """
        return self.get_body().os

    @property
    def ip_address(self) -> Optional[str]:
        """The `ip_address` property.

        Returns:
            the value of the property.
        """
        return self.get_body().ip_address

    @property
    def hostname(self) -> Optional[str]:
        """The `hostname` property.

        Returns:
            the value of the property.
        """
        return self.get_body().hostname

    @property
    def python_version(self) -> Optional[str]:
        """The `python_version` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().python_version

    @property
    def zenml_version(self) -> Optional[str]:
        """The `zenml_version` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().zenml_version

    @property
    def city(self) -> Optional[str]:
        """The `city` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().city

    @property
    def region(self) -> Optional[str]:
        """The `region` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().region

    @property
    def country(self) -> Optional[str]:
        """The `country` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().country

    @property
    def failed_auth_attempts(self) -> int:
        """The `failed_auth_attempts` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().failed_auth_attempts

    @property
    def last_login(self) -> Optional[datetime]:
        """The `last_login` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().last_login

city property

The city property.

Returns:

Type Description
Optional[str]

the value of the property.

client_id property

The client_id property.

Returns:

Type Description
UUID

the value of the property.

country property

The country property.

Returns:

Type Description
Optional[str]

the value of the property.

expires property

The expires property.

Returns:

Type Description
Optional[datetime]

the value of the property.

failed_auth_attempts property

The failed_auth_attempts property.

Returns:

Type Description
int

the value of the property.

hostname property

The hostname property.

Returns:

Type Description
Optional[str]

the value of the property.

ip_address property

The ip_address property.

Returns:

Type Description
Optional[str]

the value of the property.

last_login property

The last_login property.

Returns:

Type Description
Optional[datetime]

the value of the property.

os property

The os property.

Returns:

Type Description
Optional[str]

the value of the property.

python_version property

The python_version property.

Returns:

Type Description
Optional[str]

the value of the property.

region property

The region property.

Returns:

Type Description
Optional[str]

the value of the property.

status property

The status property.

Returns:

Type Description
OAuthDeviceStatus

the value of the property.

trusted_device property

The trusted_device property.

Returns:

Type Description
bool

the value of the property.

zenml_version property

The zenml_version property.

Returns:

Type Description
Optional[str]

the value of the property.

get_hydrated_version()

Get the hydrated version of this OAuth2 device.

Returns:

Type Description
OAuthDeviceResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/device.py
240
241
242
243
244
245
246
247
248
def get_hydrated_version(self) -> "OAuthDeviceResponse":
    """Get the hydrated version of this OAuth2 device.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_authorized_device(self.id)

OAuthDeviceResponseBody

Bases: UserScopedResponseBody

Response body for OAuth2 devices.

Source code in src/zenml/models/v2/core/device.py
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
class OAuthDeviceResponseBody(UserScopedResponseBody):
    """Response body for OAuth2 devices."""

    client_id: UUID = Field(description="The client ID of the OAuth2 device.")
    expires: Optional[datetime] = Field(
        default=None,
        description="The expiration date of the OAuth2 device after which "
        "the device is no longer valid and cannot be used for "
        "authentication.",
    )
    trusted_device: bool = Field(
        description="Whether the OAuth2 device was marked as trusted. A "
        "trusted device has a much longer validity time.",
    )
    status: OAuthDeviceStatus = Field(
        description="The status of the OAuth2 device."
    )
    os: Optional[str] = Field(
        default=None,
        description="The operating system of the device used for "
        "authentication.",
    )
    ip_address: Optional[str] = Field(
        default=None,
        description="The IP address of the device used for authentication.",
    )
    hostname: Optional[str] = Field(
        default=None,
        description="The hostname of the device used for authentication.",
    )

OAuthDeviceResponseMetadata

Bases: UserScopedResponseMetadata

Response metadata for OAuth2 devices.

Source code in src/zenml/models/v2/core/device.py
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
class OAuthDeviceResponseMetadata(UserScopedResponseMetadata):
    """Response metadata for OAuth2 devices."""

    python_version: Optional[str] = Field(
        default=None,
        description="The Python version of the device used for authentication.",
    )
    zenml_version: Optional[str] = Field(
        default=None,
        description="The ZenML version of the device used for authentication.",
    )
    city: Optional[str] = Field(
        default=None,
        description="The city where the device is located.",
    )
    region: Optional[str] = Field(
        default=None,
        description="The region where the device is located.",
    )
    country: Optional[str] = Field(
        default=None,
        description="The country where the device is located.",
    )
    failed_auth_attempts: int = Field(
        description="The number of failed authentication attempts.",
    )
    last_login: Optional[datetime] = Field(
        description="The date of the last successful login."
    )

OAuthDeviceTokenRequest

Bases: BaseModel

OAuth2 device authorization grant request.

Source code in src/zenml/models/v2/misc/auth_models.py
42
43
44
45
46
47
class OAuthDeviceTokenRequest(BaseModel):
    """OAuth2 device authorization grant request."""

    grant_type: str = OAuthGrantTypes.OAUTH_DEVICE_CODE
    client_id: UUID
    device_code: str

OAuthDeviceUpdate

Bases: BaseModel

OAuth2 device update model.

Source code in src/zenml/models/v2/core/device.py
84
85
86
87
88
89
90
91
class OAuthDeviceUpdate(BaseModel):
    """OAuth2 device update model."""

    locked: Optional[bool] = Field(
        default=None,
        description="Whether to lock or unlock the OAuth2 device. A locked "
        "device cannot be used for authentication.",
    )

OAuthDeviceUserAgentHeader

Bases: BaseModel

OAuth2 device user agent header.

Source code in src/zenml/models/v2/misc/auth_models.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
class OAuthDeviceUserAgentHeader(BaseModel):
    """OAuth2 device user agent header."""

    hostname: Optional[str] = None
    os: Optional[str] = None
    python_version: Optional[str] = None
    zenml_version: Optional[str] = None

    @classmethod
    def decode(cls, header_str: str) -> "OAuthDeviceUserAgentHeader":
        """Decode the user agent header.

        Args:
            header_str: The user agent header string value.

        Returns:
            The decoded user agent header.
        """
        header = cls()
        properties = header_str.strip().split(" ")
        for property in properties:
            try:
                key, value = property.split("/", maxsplit=1)
            except ValueError:
                continue
            if key == "Host":
                header.hostname = value
            elif key == "ZenML":
                header.zenml_version = value
            elif key == "Python":
                header.python_version = value
            elif key == "OS":
                header.os = value
        return header

    def encode(self) -> str:
        """Encode the user agent header.

        Returns:
            The encoded user agent header.
        """
        return (
            f"Host/{self.hostname} "
            f"ZenML/{self.zenml_version} "
            f"Python/{self.python_version} "
            f"OS/{self.os}"
        )

decode(header_str) classmethod

Decode the user agent header.

Parameters:

Name Type Description Default
header_str str

The user agent header string value.

required

Returns:

Type Description
OAuthDeviceUserAgentHeader

The decoded user agent header.

Source code in src/zenml/models/v2/misc/auth_models.py
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
@classmethod
def decode(cls, header_str: str) -> "OAuthDeviceUserAgentHeader":
    """Decode the user agent header.

    Args:
        header_str: The user agent header string value.

    Returns:
        The decoded user agent header.
    """
    header = cls()
    properties = header_str.strip().split(" ")
    for property in properties:
        try:
            key, value = property.split("/", maxsplit=1)
        except ValueError:
            continue
        if key == "Host":
            header.hostname = value
        elif key == "ZenML":
            header.zenml_version = value
        elif key == "Python":
            header.python_version = value
        elif key == "OS":
            header.os = value
    return header

encode()

Encode the user agent header.

Returns:

Type Description
str

The encoded user agent header.

Source code in src/zenml/models/v2/misc/auth_models.py
85
86
87
88
89
90
91
92
93
94
95
96
def encode(self) -> str:
    """Encode the user agent header.

    Returns:
        The encoded user agent header.
    """
    return (
        f"Host/{self.hostname} "
        f"ZenML/{self.zenml_version} "
        f"Python/{self.python_version} "
        f"OS/{self.os}"
    )

OAuthDeviceVerificationRequest

Bases: BaseModel

OAuth2 device authorization verification request.

Source code in src/zenml/models/v2/misc/auth_models.py
35
36
37
38
39
class OAuthDeviceVerificationRequest(BaseModel):
    """OAuth2 device authorization verification request."""

    user_code: str
    trusted_device: bool = False

OAuthRedirectResponse

Bases: BaseModel

Redirect response.

Source code in src/zenml/models/v2/misc/auth_models.py
133
134
135
136
class OAuthRedirectResponse(BaseModel):
    """Redirect response."""

    authorization_url: str

OAuthTokenResponse

Bases: BaseModel

OAuth2 device authorization token response.

Source code in src/zenml/models/v2/misc/auth_models.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
class OAuthTokenResponse(BaseModel):
    """OAuth2 device authorization token response."""

    access_token: str
    token_type: str
    expires_in: Optional[int] = None
    refresh_token: Optional[str] = None
    csrf_token: Optional[str] = None
    scope: Optional[str] = None
    device_id: Optional[UUID] = None
    device_metadata: Optional[Dict[str, Any]] = None

    model_config = ConfigDict(
        # Allow extra attributes to allow compatibility with different versions
        extra="allow",
    )

Page

Bases: BaseModel, Generic[B]

Return Model for List Models to accommodate pagination.

Source code in src/zenml/models/v2/base/page.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
class Page(BaseModel, Generic[B]):
    """Return Model for List Models to accommodate pagination."""

    index: PositiveInt
    max_size: PositiveInt
    total_pages: NonNegativeInt
    total: NonNegativeInt
    items: List[B]

    __params_type__ = BaseFilter

    @property
    def size(self) -> int:
        """Return the item count of the page.

        Returns:
            The amount of items in the page.
        """
        return len(self.items)

    def __len__(self) -> int:
        """Return the item count of the page.

        This enables `len(page)`.

        Returns:
            The amount of items in the page.
        """
        return len(self.items)

    def __getitem__(self, index: int) -> B:
        """Return the item at the given index.

        This enables `page[index]`.

        Args:
            index: The index to get the item from.

        Returns:
            The item at the given index.
        """
        return self.items[index]

    def __iter__(self) -> Generator[B, None, None]:  # type: ignore[override]
        """Return an iterator over the items in the page.

        This enables `for item in page` loops, but breaks `dict(page)`.

        Yields:
            An iterator over the items in the page.
        """
        for item in self.items.__iter__():
            yield item

    def __contains__(self, item: B) -> bool:
        """Returns whether the page contains a specific item.

        This enables `item in page` checks.

        Args:
            item: The item to check for.

        Returns:
            Whether the item is in the page.
        """
        return item in self.items

size property

Return the item count of the page.

Returns:

Type Description
int

The amount of items in the page.

__contains__(item)

Returns whether the page contains a specific item.

This enables item in page checks.

Parameters:

Name Type Description Default
item B

The item to check for.

required

Returns:

Type Description
bool

Whether the item is in the page.

Source code in src/zenml/models/v2/base/page.py
81
82
83
84
85
86
87
88
89
90
91
92
def __contains__(self, item: B) -> bool:
    """Returns whether the page contains a specific item.

    This enables `item in page` checks.

    Args:
        item: The item to check for.

    Returns:
        Whether the item is in the page.
    """
    return item in self.items

__getitem__(index)

Return the item at the given index.

This enables page[index].

Parameters:

Name Type Description Default
index int

The index to get the item from.

required

Returns:

Type Description
B

The item at the given index.

Source code in src/zenml/models/v2/base/page.py
57
58
59
60
61
62
63
64
65
66
67
68
def __getitem__(self, index: int) -> B:
    """Return the item at the given index.

    This enables `page[index]`.

    Args:
        index: The index to get the item from.

    Returns:
        The item at the given index.
    """
    return self.items[index]

__iter__()

Return an iterator over the items in the page.

This enables for item in page loops, but breaks dict(page).

Yields:

Type Description
B

An iterator over the items in the page.

Source code in src/zenml/models/v2/base/page.py
70
71
72
73
74
75
76
77
78
79
def __iter__(self) -> Generator[B, None, None]:  # type: ignore[override]
    """Return an iterator over the items in the page.

    This enables `for item in page` loops, but breaks `dict(page)`.

    Yields:
        An iterator over the items in the page.
    """
    for item in self.items.__iter__():
        yield item

__len__()

Return the item count of the page.

This enables len(page).

Returns:

Type Description
int

The amount of items in the page.

Source code in src/zenml/models/v2/base/page.py
47
48
49
50
51
52
53
54
55
def __len__(self) -> int:
    """Return the item count of the page.

    This enables `len(page)`.

    Returns:
        The amount of items in the page.
    """
    return len(self.items)

PipelineBuildBase

Bases: BaseZenModel

Base model for pipeline builds.

Source code in src/zenml/models/v2/core/pipeline_build.py
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
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
class PipelineBuildBase(BaseZenModel):
    """Base model for pipeline builds."""

    images: Dict[str, BuildItem] = Field(
        default={}, title="The images of this build."
    )
    is_local: bool = Field(
        title="Whether the build images are stored in a container registry "
        "or locally.",
    )
    contains_code: bool = Field(
        title="Whether any image of the build contains user code.",
    )
    zenml_version: Optional[str] = Field(
        title="The version of ZenML used for this build.", default=None
    )
    python_version: Optional[str] = Field(
        title="The Python version used for this build.", default=None
    )

    # Helper methods
    @property
    def requires_code_download(self) -> bool:
        """Whether the build requires code download.

        Returns:
            Whether the build requires code download.
        """
        return any(
            item.requires_code_download for item in self.images.values()
        )

    @staticmethod
    def get_image_key(component_key: str, step: Optional[str] = None) -> str:
        """Get the image key.

        Args:
            component_key: The component key.
            step: The pipeline step for which the image was built.

        Returns:
            The image key.
        """
        if step:
            return f"{step}.{component_key}"
        else:
            return component_key

    def get_image(self, component_key: str, step: Optional[str] = None) -> str:
        """Get the image built for a specific key.

        Args:
            component_key: The key for which to get the image.
            step: The pipeline step for which to get the image. If no image
                exists for this step, will fall back to the pipeline image for
                the same key.

        Returns:
            The image name or digest.
        """
        return self._get_item(component_key=component_key, step=step).image

    def get_settings_checksum(
        self, component_key: str, step: Optional[str] = None
    ) -> Optional[str]:
        """Get the settings checksum for a specific key.

        Args:
            component_key: The key for which to get the checksum.
            step: The pipeline step for which to get the checksum. If no
                image exists for this step, will fall back to the pipeline image
                for the same key.

        Returns:
            The settings checksum.
        """
        return self._get_item(
            component_key=component_key, step=step
        ).settings_checksum

    def _get_item(
        self, component_key: str, step: Optional[str] = None
    ) -> "BuildItem":
        """Get the item for a specific key.

        Args:
            component_key: The key for which to get the item.
            step: The pipeline step for which to get the item. If no item
                exists for this step, will fall back to the item for
                the same key.

        Raises:
            KeyError: If no item exists for the given key.

        Returns:
            The build item.
        """
        if step:
            try:
                combined_key = self.get_image_key(
                    component_key=component_key, step=step
                )
                return self.images[combined_key]
            except KeyError:
                pass

        try:
            return self.images[component_key]
        except KeyError:
            raise KeyError(
                f"Unable to find image for key {component_key}. Available keys: "
                f"{set(self.images)}."
            )

requires_code_download property

Whether the build requires code download.

Returns:

Type Description
bool

Whether the build requires code download.

get_image(component_key, step=None)

Get the image built for a specific key.

Parameters:

Name Type Description Default
component_key str

The key for which to get the image.

required
step Optional[str]

The pipeline step for which to get the image. If no image exists for this step, will fall back to the pipeline image for the same key.

None

Returns:

Type Description
str

The image name or digest.

Source code in src/zenml/models/v2/core/pipeline_build.py
104
105
106
107
108
109
110
111
112
113
114
115
116
def get_image(self, component_key: str, step: Optional[str] = None) -> str:
    """Get the image built for a specific key.

    Args:
        component_key: The key for which to get the image.
        step: The pipeline step for which to get the image. If no image
            exists for this step, will fall back to the pipeline image for
            the same key.

    Returns:
        The image name or digest.
    """
    return self._get_item(component_key=component_key, step=step).image

get_image_key(component_key, step=None) staticmethod

Get the image key.

Parameters:

Name Type Description Default
component_key str

The component key.

required
step Optional[str]

The pipeline step for which the image was built.

None

Returns:

Type Description
str

The image key.

Source code in src/zenml/models/v2/core/pipeline_build.py
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
@staticmethod
def get_image_key(component_key: str, step: Optional[str] = None) -> str:
    """Get the image key.

    Args:
        component_key: The component key.
        step: The pipeline step for which the image was built.

    Returns:
        The image key.
    """
    if step:
        return f"{step}.{component_key}"
    else:
        return component_key

get_settings_checksum(component_key, step=None)

Get the settings checksum for a specific key.

Parameters:

Name Type Description Default
component_key str

The key for which to get the checksum.

required
step Optional[str]

The pipeline step for which to get the checksum. If no image exists for this step, will fall back to the pipeline image for the same key.

None

Returns:

Type Description
Optional[str]

The settings checksum.

Source code in src/zenml/models/v2/core/pipeline_build.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
def get_settings_checksum(
    self, component_key: str, step: Optional[str] = None
) -> Optional[str]:
    """Get the settings checksum for a specific key.

    Args:
        component_key: The key for which to get the checksum.
        step: The pipeline step for which to get the checksum. If no
            image exists for this step, will fall back to the pipeline image
            for the same key.

    Returns:
        The settings checksum.
    """
    return self._get_item(
        component_key=component_key, step=step
    ).settings_checksum

PipelineBuildFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of all pipeline builds.

Source code in src/zenml/models/v2/core/pipeline_build.py
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
class PipelineBuildFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of all pipeline builds."""

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
        "container_registry_id",
    ]

    pipeline_id: Optional[Union[UUID, str]] = Field(
        description="Pipeline associated with the pipeline build.",
        default=None,
        union_mode="left_to_right",
    )
    stack_id: Optional[Union[UUID, str]] = Field(
        description="Stack associated with the pipeline build.",
        default=None,
        union_mode="left_to_right",
    )
    container_registry_id: Optional[Union[UUID, str]] = Field(
        description="Container registry associated with the pipeline build.",
        default=None,
        union_mode="left_to_right",
    )
    is_local: Optional[bool] = Field(
        description="Whether the build images are stored in a container "
        "registry or locally.",
        default=None,
    )
    contains_code: Optional[bool] = Field(
        description="Whether any image of the build contains user code.",
        default=None,
    )
    zenml_version: Optional[str] = Field(
        description="The version of ZenML used for this build.", default=None
    )
    python_version: Optional[str] = Field(
        description="The Python version used for this build.", default=None
    )
    checksum: Optional[str] = Field(
        description="The build checksum.", default=None
    )
    stack_checksum: Optional[str] = Field(
        description="The stack checksum.", default=None
    )

    def get_custom_filters(
        self,
        table: Type["AnySchema"],
    ) -> List["ColumnElement[bool]"]:
        """Get custom filters.

        Args:
            table: The query table.

        Returns:
            A list of custom filters.
        """
        custom_filters = super().get_custom_filters(table)

        from sqlmodel import and_

        from zenml.enums import StackComponentType
        from zenml.zen_stores.schemas import (
            PipelineBuildSchema,
            StackComponentSchema,
            StackCompositionSchema,
            StackSchema,
        )

        if self.container_registry_id:
            container_registry_filter = and_(
                PipelineBuildSchema.stack_id == StackSchema.id,
                StackSchema.id == StackCompositionSchema.stack_id,
                StackCompositionSchema.component_id == StackComponentSchema.id,
                StackComponentSchema.type
                == StackComponentType.CONTAINER_REGISTRY.value,
                StackComponentSchema.id == self.container_registry_id,
            )
            custom_filters.append(container_registry_filter)

        return custom_filters

get_custom_filters(table)

Get custom filters.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
List[ColumnElement[bool]]

A list of custom filters.

Source code in src/zenml/models/v2/core/pipeline_build.py
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
def get_custom_filters(
    self,
    table: Type["AnySchema"],
) -> List["ColumnElement[bool]"]:
    """Get custom filters.

    Args:
        table: The query table.

    Returns:
        A list of custom filters.
    """
    custom_filters = super().get_custom_filters(table)

    from sqlmodel import and_

    from zenml.enums import StackComponentType
    from zenml.zen_stores.schemas import (
        PipelineBuildSchema,
        StackComponentSchema,
        StackCompositionSchema,
        StackSchema,
    )

    if self.container_registry_id:
        container_registry_filter = and_(
            PipelineBuildSchema.stack_id == StackSchema.id,
            StackSchema.id == StackCompositionSchema.stack_id,
            StackCompositionSchema.component_id == StackComponentSchema.id,
            StackComponentSchema.type
            == StackComponentType.CONTAINER_REGISTRY.value,
            StackComponentSchema.id == self.container_registry_id,
        )
        custom_filters.append(container_registry_filter)

    return custom_filters

PipelineBuildRequest

Bases: PipelineBuildBase, WorkspaceScopedRequest

Request model for pipelines builds.

Source code in src/zenml/models/v2/core/pipeline_build.py
171
172
173
174
175
176
177
178
179
180
181
182
183
184
class PipelineBuildRequest(PipelineBuildBase, WorkspaceScopedRequest):
    """Request model for pipelines builds."""

    checksum: Optional[str] = Field(title="The build checksum.", default=None)
    stack_checksum: Optional[str] = Field(
        title="The stack checksum.", default=None
    )

    stack: Optional[UUID] = Field(
        title="The stack that was used for this build.", default=None
    )
    pipeline: Optional[UUID] = Field(
        title="The pipeline that was used for this build.", default=None
    )

PipelineBuildResponse

Bases: WorkspaceScopedResponse[PipelineBuildResponseBody, PipelineBuildResponseMetadata, PipelineBuildResponseResources]

Response model for pipeline builds.

Source code in src/zenml/models/v2/core/pipeline_build.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
class PipelineBuildResponse(
    WorkspaceScopedResponse[
        PipelineBuildResponseBody,
        PipelineBuildResponseMetadata,
        PipelineBuildResponseResources,
    ]
):
    """Response model for pipeline builds."""

    def get_hydrated_version(self) -> "PipelineBuildResponse":
        """Return the hydrated version of this pipeline build.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_build(self.id)

    # Helper methods
    def to_yaml(self) -> Dict[str, Any]:
        """Create a yaml representation of the pipeline build.

        Create a yaml representation of the pipeline build that can be used
        to create a PipelineBuildBase instance.

        Returns:
            The yaml representation of the pipeline build.
        """
        # Get the base attributes
        yaml_dict: Dict[str, Any] = json.loads(
            self.model_dump_json(
                exclude={
                    "body",
                    "metadata",
                }
            )
        )
        images = json.loads(
            self.get_metadata().model_dump_json(
                exclude={
                    "pipeline",
                    "stack",
                    "workspace",
                }
            )
        )
        yaml_dict.update(images)
        return yaml_dict

    @property
    def requires_code_download(self) -> bool:
        """Whether the build requires code download.

        Returns:
            Whether the build requires code download.
        """
        return any(
            item.requires_code_download for item in self.images.values()
        )

    @staticmethod
    def get_image_key(component_key: str, step: Optional[str] = None) -> str:
        """Get the image key.

        Args:
            component_key: The component key.
            step: The pipeline step for which the image was built.

        Returns:
            The image key.
        """
        if step:
            return f"{step}.{component_key}"
        else:
            return component_key

    def get_image(self, component_key: str, step: Optional[str] = None) -> str:
        """Get the image built for a specific key.

        Args:
            component_key: The key for which to get the image.
            step: The pipeline step for which to get the image. If no image
                exists for this step, will fall back to the pipeline image for
                the same key.

        Returns:
            The image name or digest.
        """
        return self._get_item(component_key=component_key, step=step).image

    def get_settings_checksum(
        self, component_key: str, step: Optional[str] = None
    ) -> Optional[str]:
        """Get the settings checksum for a specific key.

        Args:
            component_key: The key for which to get the checksum.
            step: The pipeline step for which to get the checksum. If no
                image exists for this step, will fall back to the pipeline image
                for the same key.

        Returns:
            The settings checksum.
        """
        return self._get_item(
            component_key=component_key, step=step
        ).settings_checksum

    def _get_item(
        self, component_key: str, step: Optional[str] = None
    ) -> "BuildItem":
        """Get the item for a specific key.

        Args:
            component_key: The key for which to get the item.
            step: The pipeline step for which to get the item. If no item
                exists for this step, will fall back to the item for
                the same key.

        Raises:
            KeyError: If no item exists for the given key.

        Returns:
            The build item.
        """
        if step:
            try:
                combined_key = self.get_image_key(
                    component_key=component_key, step=step
                )
                return self.images[combined_key]
            except KeyError:
                pass

        try:
            return self.images[component_key]
        except KeyError:
            raise KeyError(
                f"Unable to find image for key {component_key}. Available keys: "
                f"{set(self.images)}."
            )

    # Body and metadata properties
    @property
    def pipeline(self) -> Optional["PipelineResponse"]:
        """The `pipeline` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().pipeline

    @property
    def stack(self) -> Optional["StackResponse"]:
        """The `stack` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().stack

    @property
    def images(self) -> Dict[str, "BuildItem"]:
        """The `images` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().images

    @property
    def zenml_version(self) -> Optional[str]:
        """The `zenml_version` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().zenml_version

    @property
    def python_version(self) -> Optional[str]:
        """The `python_version` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().python_version

    @property
    def checksum(self) -> Optional[str]:
        """The `checksum` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().checksum

    @property
    def stack_checksum(self) -> Optional[str]:
        """The `stack_checksum` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().stack_checksum

    @property
    def is_local(self) -> bool:
        """The `is_local` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().is_local

    @property
    def contains_code(self) -> bool:
        """The `contains_code` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().contains_code

checksum property

The checksum property.

Returns:

Type Description
Optional[str]

the value of the property.

contains_code property

The contains_code property.

Returns:

Type Description
bool

the value of the property.

images property

The images property.

Returns:

Type Description
Dict[str, BuildItem]

the value of the property.

is_local property

The is_local property.

Returns:

Type Description
bool

the value of the property.

pipeline property

The pipeline property.

Returns:

Type Description
Optional[PipelineResponse]

the value of the property.

python_version property

The python_version property.

Returns:

Type Description
Optional[str]

the value of the property.

requires_code_download property

Whether the build requires code download.

Returns:

Type Description
bool

Whether the build requires code download.

stack property

The stack property.

Returns:

Type Description
Optional[StackResponse]

the value of the property.

stack_checksum property

The stack_checksum property.

Returns:

Type Description
Optional[str]

the value of the property.

zenml_version property

The zenml_version property.

Returns:

Type Description
Optional[str]

the value of the property.

get_hydrated_version()

Return the hydrated version of this pipeline build.

Returns:

Type Description
PipelineBuildResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/pipeline_build.py
241
242
243
244
245
246
247
248
249
def get_hydrated_version(self) -> "PipelineBuildResponse":
    """Return the hydrated version of this pipeline build.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_build(self.id)

get_image(component_key, step=None)

Get the image built for a specific key.

Parameters:

Name Type Description Default
component_key str

The key for which to get the image.

required
step Optional[str]

The pipeline step for which to get the image. If no image exists for this step, will fall back to the pipeline image for the same key.

None

Returns:

Type Description
str

The image name or digest.

Source code in src/zenml/models/v2/core/pipeline_build.py
309
310
311
312
313
314
315
316
317
318
319
320
321
def get_image(self, component_key: str, step: Optional[str] = None) -> str:
    """Get the image built for a specific key.

    Args:
        component_key: The key for which to get the image.
        step: The pipeline step for which to get the image. If no image
            exists for this step, will fall back to the pipeline image for
            the same key.

    Returns:
        The image name or digest.
    """
    return self._get_item(component_key=component_key, step=step).image

get_image_key(component_key, step=None) staticmethod

Get the image key.

Parameters:

Name Type Description Default
component_key str

The component key.

required
step Optional[str]

The pipeline step for which the image was built.

None

Returns:

Type Description
str

The image key.

Source code in src/zenml/models/v2/core/pipeline_build.py
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
@staticmethod
def get_image_key(component_key: str, step: Optional[str] = None) -> str:
    """Get the image key.

    Args:
        component_key: The component key.
        step: The pipeline step for which the image was built.

    Returns:
        The image key.
    """
    if step:
        return f"{step}.{component_key}"
    else:
        return component_key

get_settings_checksum(component_key, step=None)

Get the settings checksum for a specific key.

Parameters:

Name Type Description Default
component_key str

The key for which to get the checksum.

required
step Optional[str]

The pipeline step for which to get the checksum. If no image exists for this step, will fall back to the pipeline image for the same key.

None

Returns:

Type Description
Optional[str]

The settings checksum.

Source code in src/zenml/models/v2/core/pipeline_build.py
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
def get_settings_checksum(
    self, component_key: str, step: Optional[str] = None
) -> Optional[str]:
    """Get the settings checksum for a specific key.

    Args:
        component_key: The key for which to get the checksum.
        step: The pipeline step for which to get the checksum. If no
            image exists for this step, will fall back to the pipeline image
            for the same key.

    Returns:
        The settings checksum.
    """
    return self._get_item(
        component_key=component_key, step=step
    ).settings_checksum

to_yaml()

Create a yaml representation of the pipeline build.

Create a yaml representation of the pipeline build that can be used to create a PipelineBuildBase instance.

Returns:

Type Description
Dict[str, Any]

The yaml representation of the pipeline build.

Source code in src/zenml/models/v2/core/pipeline_build.py
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
def to_yaml(self) -> Dict[str, Any]:
    """Create a yaml representation of the pipeline build.

    Create a yaml representation of the pipeline build that can be used
    to create a PipelineBuildBase instance.

    Returns:
        The yaml representation of the pipeline build.
    """
    # Get the base attributes
    yaml_dict: Dict[str, Any] = json.loads(
        self.model_dump_json(
            exclude={
                "body",
                "metadata",
            }
        )
    )
    images = json.loads(
        self.get_metadata().model_dump_json(
            exclude={
                "pipeline",
                "stack",
                "workspace",
            }
        )
    )
    yaml_dict.update(images)
    return yaml_dict

PipelineBuildResponseBody

Bases: WorkspaceScopedResponseBody

Response body for pipeline builds.

Source code in src/zenml/models/v2/core/pipeline_build.py
193
194
class PipelineBuildResponseBody(WorkspaceScopedResponseBody):
    """Response body for pipeline builds."""

PipelineBuildResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for pipeline builds.

Source code in src/zenml/models/v2/core/pipeline_build.py
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
class PipelineBuildResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for pipeline builds."""

    pipeline: Optional["PipelineResponse"] = Field(
        default=None, title="The pipeline that was used for this build."
    )
    stack: Optional["StackResponse"] = Field(
        default=None, title="The stack that was used for this build."
    )
    images: Dict[str, "BuildItem"] = Field(
        default={}, title="The images of this build."
    )
    zenml_version: Optional[str] = Field(
        default=None, title="The version of ZenML used for this build."
    )
    python_version: Optional[str] = Field(
        default=None, title="The Python version used for this build."
    )
    checksum: Optional[str] = Field(default=None, title="The build checksum.")
    stack_checksum: Optional[str] = Field(
        default=None, title="The stack checksum."
    )
    is_local: bool = Field(
        title="Whether the build images are stored in a container "
        "registry or locally.",
    )
    contains_code: bool = Field(
        title="Whether any image of the build contains user code.",
    )

PipelineDeploymentBase

Bases: BaseZenModel

Base model for pipeline deployments.

Source code in src/zenml/models/v2/core/pipeline_deployment.py
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
class PipelineDeploymentBase(BaseZenModel):
    """Base model for pipeline deployments."""

    run_name_template: str = Field(
        title="The run name template for runs created using this deployment.",
    )
    pipeline_configuration: PipelineConfiguration = Field(
        title="The pipeline configuration for this deployment."
    )
    step_configurations: Dict[str, Step] = Field(
        default={}, title="The step configurations for this deployment."
    )
    client_environment: Dict[str, str] = Field(
        default={}, title="The client environment for this deployment."
    )
    client_version: Optional[str] = Field(
        default=None,
        title="The version of the ZenML installation on the client side.",
    )
    server_version: Optional[str] = Field(
        default=None,
        title="The version of the ZenML installation on the server side.",
    )
    pipeline_version_hash: Optional[str] = Field(
        default=None,
        title="The pipeline version hash of the deployment.",
    )
    pipeline_spec: Optional[PipelineSpec] = Field(
        default=None,
        title="The pipeline spec of the deployment.",
    )

    @property
    def should_prevent_build_reuse(self) -> bool:
        """Whether the deployment prevents a build reuse.

        Returns:
            Whether the deployment prevents a build reuse.
        """
        return any(
            step.config.docker_settings.prevent_build_reuse
            for step in self.step_configurations.values()
        )

should_prevent_build_reuse property

Whether the deployment prevents a build reuse.

Returns:

Type Description
bool

Whether the deployment prevents a build reuse.

PipelineDeploymentFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of all pipeline deployments.

Source code in src/zenml/models/v2/core/pipeline_deployment.py
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
class PipelineDeploymentFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of all pipeline deployments."""

    pipeline_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Pipeline associated with the deployment.",
        union_mode="left_to_right",
    )
    stack_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Stack associated with the deployment.",
        union_mode="left_to_right",
    )
    build_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Build associated with the deployment.",
        union_mode="left_to_right",
    )
    schedule_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Schedule associated with the deployment.",
        union_mode="left_to_right",
    )
    template_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Template used as base for the deployment.",
        union_mode="left_to_right",
    )

PipelineDeploymentRequest

Bases: PipelineDeploymentBase, WorkspaceScopedRequest

Request model for pipeline deployments.

Source code in src/zenml/models/v2/core/pipeline_deployment.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
class PipelineDeploymentRequest(
    PipelineDeploymentBase, WorkspaceScopedRequest
):
    """Request model for pipeline deployments."""

    stack: UUID = Field(title="The stack associated with the deployment.")
    pipeline: Optional[UUID] = Field(
        default=None, title="The pipeline associated with the deployment."
    )
    build: Optional[UUID] = Field(
        default=None, title="The build associated with the deployment."
    )
    schedule: Optional[UUID] = Field(
        default=None, title="The schedule associated with the deployment."
    )
    code_reference: Optional["CodeReferenceRequest"] = Field(
        default=None,
        title="The code reference associated with the deployment.",
    )
    code_path: Optional[str] = Field(
        default=None,
        title="Optional path where the code is stored in the artifact store.",
    )
    template: Optional[UUID] = Field(
        default=None,
        description="Template used for the deployment.",
    )

PipelineDeploymentResponse

Bases: WorkspaceScopedResponse[PipelineDeploymentResponseBody, PipelineDeploymentResponseMetadata, PipelineDeploymentResponseResources]

Response model for pipeline deployments.

Source code in src/zenml/models/v2/core/pipeline_deployment.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
class PipelineDeploymentResponse(
    WorkspaceScopedResponse[
        PipelineDeploymentResponseBody,
        PipelineDeploymentResponseMetadata,
        PipelineDeploymentResponseResources,
    ]
):
    """Response model for pipeline deployments."""

    def get_hydrated_version(self) -> "PipelineDeploymentResponse":
        """Return the hydrated version of this pipeline deployment.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_deployment(self.id)

    # Body and metadata properties
    @property
    def run_name_template(self) -> str:
        """The `run_name_template` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().run_name_template

    @property
    def pipeline_configuration(self) -> PipelineConfiguration:
        """The `pipeline_configuration` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().pipeline_configuration

    @property
    def step_configurations(self) -> Dict[str, Step]:
        """The `step_configurations` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().step_configurations

    @property
    def client_environment(self) -> Dict[str, str]:
        """The `client_environment` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().client_environment

    @property
    def client_version(self) -> Optional[str]:
        """The `client_version` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().client_version

    @property
    def server_version(self) -> Optional[str]:
        """The `server_version` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().server_version

    @property
    def pipeline_version_hash(self) -> Optional[str]:
        """The `pipeline_version_hash` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().pipeline_version_hash

    @property
    def pipeline_spec(self) -> Optional[PipelineSpec]:
        """The `pipeline_spec` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().pipeline_spec

    @property
    def code_path(self) -> Optional[str]:
        """The `code_path` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().code_path

    @property
    def pipeline(self) -> Optional[PipelineResponse]:
        """The `pipeline` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().pipeline

    @property
    def stack(self) -> Optional[StackResponse]:
        """The `stack` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().stack

    @property
    def build(self) -> Optional[PipelineBuildResponse]:
        """The `build` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().build

    @property
    def schedule(self) -> Optional[ScheduleResponse]:
        """The `schedule` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().schedule

    @property
    def code_reference(self) -> Optional[CodeReferenceResponse]:
        """The `code_reference` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().code_reference

    @property
    def template_id(self) -> Optional[UUID]:
        """The `template_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().template_id

build property

The build property.

Returns:

Type Description
Optional[PipelineBuildResponse]

the value of the property.

client_environment property

The client_environment property.

Returns:

Type Description
Dict[str, str]

the value of the property.

client_version property

The client_version property.

Returns:

Type Description
Optional[str]

the value of the property.

code_path property

The code_path property.

Returns:

Type Description
Optional[str]

the value of the property.

code_reference property

The code_reference property.

Returns:

Type Description
Optional[CodeReferenceResponse]

the value of the property.

pipeline property

The pipeline property.

Returns:

Type Description
Optional[PipelineResponse]

the value of the property.

pipeline_configuration property

The pipeline_configuration property.

Returns:

Type Description
PipelineConfiguration

the value of the property.

pipeline_spec property

The pipeline_spec property.

Returns:

Type Description
Optional[PipelineSpec]

the value of the property.

pipeline_version_hash property

The pipeline_version_hash property.

Returns:

Type Description
Optional[str]

the value of the property.

run_name_template property

The run_name_template property.

Returns:

Type Description
str

the value of the property.

schedule property

The schedule property.

Returns:

Type Description
Optional[ScheduleResponse]

the value of the property.

server_version property

The server_version property.

Returns:

Type Description
Optional[str]

the value of the property.

stack property

The stack property.

Returns:

Type Description
Optional[StackResponse]

the value of the property.

step_configurations property

The step_configurations property.

Returns:

Type Description
Dict[str, Step]

the value of the property.

template_id property

The template_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

get_hydrated_version()

Return the hydrated version of this pipeline deployment.

Returns:

Type Description
PipelineDeploymentResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/pipeline_deployment.py
208
209
210
211
212
213
214
215
216
def get_hydrated_version(self) -> "PipelineDeploymentResponse":
    """Return the hydrated version of this pipeline deployment.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_deployment(self.id)

PipelineDeploymentResponseBody

Bases: WorkspaceScopedResponseBody

Response body for pipeline deployments.

Source code in src/zenml/models/v2/core/pipeline_deployment.py
132
133
class PipelineDeploymentResponseBody(WorkspaceScopedResponseBody):
    """Response body for pipeline deployments."""

PipelineDeploymentResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for pipeline deployments.

Source code in src/zenml/models/v2/core/pipeline_deployment.py
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
class PipelineDeploymentResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for pipeline deployments."""

    run_name_template: str = Field(
        title="The run name template for runs created using this deployment.",
    )
    pipeline_configuration: PipelineConfiguration = Field(
        title="The pipeline configuration for this deployment."
    )
    step_configurations: Dict[str, Step] = Field(
        default={}, title="The step configurations for this deployment."
    )
    client_environment: Dict[str, str] = Field(
        default={}, title="The client environment for this deployment."
    )
    client_version: Optional[str] = Field(
        title="The version of the ZenML installation on the client side."
    )
    server_version: Optional[str] = Field(
        title="The version of the ZenML installation on the server side."
    )
    pipeline_version_hash: Optional[str] = Field(
        default=None, title="The pipeline version hash of the deployment."
    )
    pipeline_spec: Optional[PipelineSpec] = Field(
        default=None, title="The pipeline spec of the deployment."
    )
    code_path: Optional[str] = Field(
        default=None,
        title="Optional path where the code is stored in the artifact store.",
    )

    pipeline: Optional[PipelineResponse] = Field(
        default=None, title="The pipeline associated with the deployment."
    )
    stack: Optional[StackResponse] = Field(
        default=None, title="The stack associated with the deployment."
    )
    build: Optional[PipelineBuildResponse] = Field(
        default=None,
        title="The pipeline build associated with the deployment.",
    )
    schedule: Optional[ScheduleResponse] = Field(
        default=None, title="The schedule associated with the deployment."
    )
    code_reference: Optional[CodeReferenceResponse] = Field(
        default=None,
        title="The code reference associated with the deployment.",
    )
    template_id: Optional[UUID] = Field(
        default=None,
        description="Template used for the pipeline run.",
    )

PipelineFilter

Bases: WorkspaceScopedFilter, TaggableFilter

Pipeline filter model.

Source code in src/zenml/models/v2/core/pipeline.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
class PipelineFilter(WorkspaceScopedFilter, TaggableFilter):
    """Pipeline filter model."""

    CUSTOM_SORTING_OPTIONS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.CUSTOM_SORTING_OPTIONS,
        *TaggableFilter.CUSTOM_SORTING_OPTIONS,
        SORT_PIPELINES_BY_LATEST_RUN_KEY,
    ]
    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
        *TaggableFilter.FILTER_EXCLUDE_FIELDS,
        "latest_run_status",
    ]
    CLI_EXCLUDE_FIELDS = [
        *WorkspaceScopedFilter.CLI_EXCLUDE_FIELDS,
        *TaggableFilter.CLI_EXCLUDE_FIELDS,
    ]

    name: Optional[str] = Field(
        default=None,
        description="Name of the Pipeline",
    )
    latest_run_status: Optional[str] = Field(
        default=None,
        description="Filter by the status of the latest run of a pipeline. "
        "This will always be applied as an `AND` filter for now.",
    )

    def apply_filter(
        self, query: AnyQuery, table: Type["AnySchema"]
    ) -> AnyQuery:
        """Applies the filter to a query.

        Args:
            query: The query to which to apply the filter.
            table: The query table.

        Returns:
            The query with filter applied.
        """
        query = super().apply_filter(query, table)

        from sqlmodel import and_, col, func, select

        from zenml.zen_stores.schemas import PipelineRunSchema, PipelineSchema

        if self.latest_run_status:
            latest_pipeline_run_subquery = (
                select(
                    PipelineRunSchema.pipeline_id,
                    func.max(PipelineRunSchema.created).label("created"),
                )
                .where(col(PipelineRunSchema.pipeline_id).is_not(None))
                .group_by(col(PipelineRunSchema.pipeline_id))
                .subquery()
            )

            query = (
                query.join(
                    PipelineRunSchema,
                    PipelineSchema.id == PipelineRunSchema.pipeline_id,
                )
                .join(
                    latest_pipeline_run_subquery,
                    and_(
                        PipelineRunSchema.pipeline_id
                        == latest_pipeline_run_subquery.c.pipeline_id,
                        PipelineRunSchema.created
                        == latest_pipeline_run_subquery.c.created,
                    ),
                )
                .where(
                    self.generate_custom_query_conditions_for_column(
                        value=self.latest_run_status,
                        table=PipelineRunSchema,
                        column="status",
                    )
                )
            )

        return query

    def apply_sorting(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Apply sorting to the query.

        Args:
            query: The query to which to apply the sorting.
            table: The query table.

        Returns:
            The query with sorting applied.
        """
        from sqlmodel import asc, case, col, desc, func, select

        from zenml.enums import SorterOps
        from zenml.zen_stores.schemas import PipelineRunSchema, PipelineSchema

        sort_by, operand = self.sorting_params

        if sort_by == SORT_PIPELINES_BY_LATEST_RUN_KEY:
            # Subquery to find the latest run per pipeline
            latest_run_subquery = (
                select(
                    PipelineSchema.id,
                    case(
                        (
                            func.max(PipelineRunSchema.created).is_(None),
                            PipelineSchema.created,
                        ),
                        else_=func.max(PipelineRunSchema.created),
                    ).label("latest_run"),
                )
                .outerjoin(
                    PipelineRunSchema,
                    PipelineSchema.id == PipelineRunSchema.pipeline_id,  # type: ignore[arg-type]
                )
                .group_by(col(PipelineSchema.id))
                .subquery()
            )

            query = query.add_columns(
                latest_run_subquery.c.latest_run,
            ).where(PipelineSchema.id == latest_run_subquery.c.id)

            if operand == SorterOps.ASCENDING:
                query = query.order_by(
                    asc(latest_run_subquery.c.latest_run),
                    asc(PipelineSchema.id),
                )
            else:
                query = query.order_by(
                    desc(latest_run_subquery.c.latest_run),
                    desc(PipelineSchema.id),
                )
            return query
        else:
            return super().apply_sorting(query=query, table=table)

apply_filter(query, table)

Applies the filter to a query.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the filter.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with filter applied.

Source code in src/zenml/models/v2/core/pipeline.py
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
def apply_filter(
    self, query: AnyQuery, table: Type["AnySchema"]
) -> AnyQuery:
    """Applies the filter to a query.

    Args:
        query: The query to which to apply the filter.
        table: The query table.

    Returns:
        The query with filter applied.
    """
    query = super().apply_filter(query, table)

    from sqlmodel import and_, col, func, select

    from zenml.zen_stores.schemas import PipelineRunSchema, PipelineSchema

    if self.latest_run_status:
        latest_pipeline_run_subquery = (
            select(
                PipelineRunSchema.pipeline_id,
                func.max(PipelineRunSchema.created).label("created"),
            )
            .where(col(PipelineRunSchema.pipeline_id).is_not(None))
            .group_by(col(PipelineRunSchema.pipeline_id))
            .subquery()
        )

        query = (
            query.join(
                PipelineRunSchema,
                PipelineSchema.id == PipelineRunSchema.pipeline_id,
            )
            .join(
                latest_pipeline_run_subquery,
                and_(
                    PipelineRunSchema.pipeline_id
                    == latest_pipeline_run_subquery.c.pipeline_id,
                    PipelineRunSchema.created
                    == latest_pipeline_run_subquery.c.created,
                ),
            )
            .where(
                self.generate_custom_query_conditions_for_column(
                    value=self.latest_run_status,
                    table=PipelineRunSchema,
                    column="status",
                )
            )
        )

    return query

apply_sorting(query, table)

Apply sorting to the query.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the sorting.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with sorting applied.

Source code in src/zenml/models/v2/core/pipeline.py
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
def apply_sorting(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Apply sorting to the query.

    Args:
        query: The query to which to apply the sorting.
        table: The query table.

    Returns:
        The query with sorting applied.
    """
    from sqlmodel import asc, case, col, desc, func, select

    from zenml.enums import SorterOps
    from zenml.zen_stores.schemas import PipelineRunSchema, PipelineSchema

    sort_by, operand = self.sorting_params

    if sort_by == SORT_PIPELINES_BY_LATEST_RUN_KEY:
        # Subquery to find the latest run per pipeline
        latest_run_subquery = (
            select(
                PipelineSchema.id,
                case(
                    (
                        func.max(PipelineRunSchema.created).is_(None),
                        PipelineSchema.created,
                    ),
                    else_=func.max(PipelineRunSchema.created),
                ).label("latest_run"),
            )
            .outerjoin(
                PipelineRunSchema,
                PipelineSchema.id == PipelineRunSchema.pipeline_id,  # type: ignore[arg-type]
            )
            .group_by(col(PipelineSchema.id))
            .subquery()
        )

        query = query.add_columns(
            latest_run_subquery.c.latest_run,
        ).where(PipelineSchema.id == latest_run_subquery.c.id)

        if operand == SorterOps.ASCENDING:
            query = query.order_by(
                asc(latest_run_subquery.c.latest_run),
                asc(PipelineSchema.id),
            )
        else:
            query = query.order_by(
                desc(latest_run_subquery.c.latest_run),
                desc(PipelineSchema.id),
            )
        return query
    else:
        return super().apply_sorting(query=query, table=table)

PipelineRequest

Bases: WorkspaceScopedRequest

Request model for pipelines.

Source code in src/zenml/models/v2/core/pipeline.py
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
class PipelineRequest(WorkspaceScopedRequest):
    """Request model for pipelines."""

    name: str = Field(
        title="The name of the pipeline.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    description: Optional[str] = Field(
        default=None,
        title="The description of the pipeline.",
        max_length=TEXT_FIELD_MAX_LENGTH,
    )
    tags: Optional[List[str]] = Field(
        default=None,
        title="Tags of the pipeline.",
    )

PipelineResponse

Bases: WorkspaceScopedResponse[PipelineResponseBody, PipelineResponseMetadata, PipelineResponseResources]

Response model for pipelines.

Source code in src/zenml/models/v2/core/pipeline.py
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
class PipelineResponse(
    WorkspaceScopedResponse[
        PipelineResponseBody,
        PipelineResponseMetadata,
        PipelineResponseResources,
    ]
):
    """Response model for pipelines."""

    name: str = Field(
        title="The name of the pipeline.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "PipelineResponse":
        """Get the hydrated version of this pipeline.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_pipeline(self.id)

    # Helper methods
    def get_runs(self, **kwargs: Any) -> List["PipelineRunResponse"]:
        """Get runs of this pipeline.

        Can be used to fetch runs other than `self.runs` and supports
        fine-grained filtering and pagination.

        Args:
            **kwargs: Further arguments for filtering or pagination that are
                passed to `client.list_pipeline_runs()`.

        Returns:
            List of runs of this pipeline.
        """
        from zenml.client import Client

        return Client().list_pipeline_runs(pipeline_id=self.id, **kwargs).items

    @property
    def runs(self) -> List["PipelineRunResponse"]:
        """Returns the 20 most recent runs of this pipeline in descending order.

        Returns:
            The 20 most recent runs of this pipeline in descending order.
        """
        return self.get_runs()

    @property
    def num_runs(self) -> int:
        """Returns the number of runs of this pipeline.

        Returns:
            The number of runs of this pipeline.
        """
        from zenml.client import Client

        return Client().list_pipeline_runs(pipeline_id=self.id, size=1).total

    @property
    def last_run(self) -> "PipelineRunResponse":
        """Returns the last run of this pipeline.

        Returns:
            The last run of this pipeline.

        Raises:
            RuntimeError: If no runs were found for this pipeline.
        """
        runs = self.get_runs(size=1)
        if not runs:
            raise RuntimeError(
                f"No runs found for pipeline '{self.name}' with id {self.id}."
            )
        return runs[0]

    @property
    def last_successful_run(self) -> "PipelineRunResponse":
        """Returns the last successful run of this pipeline.

        Returns:
            The last successful run of this pipeline.

        Raises:
            RuntimeError: If no successful runs were found for this pipeline.
        """
        runs = self.get_runs(status=ExecutionStatus.COMPLETED, size=1)
        if not runs:
            raise RuntimeError(
                f"No successful runs found for pipeline '{self.name}' with id "
                f"{self.id}."
            )
        return runs[0]

    @property
    def latest_run_id(self) -> Optional[UUID]:
        """The `latest_run_id` property.

        Returns:
            the value of the property.
        """
        return self.get_body().latest_run_id

    @property
    def latest_run_status(self) -> Optional[ExecutionStatus]:
        """The `latest_run_status` property.

        Returns:
            the value of the property.
        """
        return self.get_body().latest_run_status

    @property
    def tags(self) -> List[TagResponse]:
        """The `tags` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().tags

last_run property

Returns the last run of this pipeline.

Returns:

Type Description
PipelineRunResponse

The last run of this pipeline.

Raises:

Type Description
RuntimeError

If no runs were found for this pipeline.

last_successful_run property

Returns the last successful run of this pipeline.

Returns:

Type Description
PipelineRunResponse

The last successful run of this pipeline.

Raises:

Type Description
RuntimeError

If no successful runs were found for this pipeline.

latest_run_id property

The latest_run_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

latest_run_status property

The latest_run_status property.

Returns:

Type Description
Optional[ExecutionStatus]

the value of the property.

num_runs property

Returns the number of runs of this pipeline.

Returns:

Type Description
int

The number of runs of this pipeline.

runs property

Returns the 20 most recent runs of this pipeline in descending order.

Returns:

Type Description
List[PipelineRunResponse]

The 20 most recent runs of this pipeline in descending order.

tags property

The tags property.

Returns:

Type Description
List[TagResponse]

the value of the property.

get_hydrated_version()

Get the hydrated version of this pipeline.

Returns:

Type Description
PipelineResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/pipeline.py
146
147
148
149
150
151
152
153
154
def get_hydrated_version(self) -> "PipelineResponse":
    """Get the hydrated version of this pipeline.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_pipeline(self.id)

get_runs(**kwargs)

Get runs of this pipeline.

Can be used to fetch runs other than self.runs and supports fine-grained filtering and pagination.

Parameters:

Name Type Description Default
**kwargs Any

Further arguments for filtering or pagination that are passed to client.list_pipeline_runs().

{}

Returns:

Type Description
List[PipelineRunResponse]

List of runs of this pipeline.

Source code in src/zenml/models/v2/core/pipeline.py
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
def get_runs(self, **kwargs: Any) -> List["PipelineRunResponse"]:
    """Get runs of this pipeline.

    Can be used to fetch runs other than `self.runs` and supports
    fine-grained filtering and pagination.

    Args:
        **kwargs: Further arguments for filtering or pagination that are
            passed to `client.list_pipeline_runs()`.

    Returns:
        List of runs of this pipeline.
    """
    from zenml.client import Client

    return Client().list_pipeline_runs(pipeline_id=self.id, **kwargs).items

PipelineResponseBody

Bases: WorkspaceScopedResponseBody

Response body for pipelines.

Source code in src/zenml/models/v2/core/pipeline.py
 98
 99
100
101
102
103
104
105
106
107
108
class PipelineResponseBody(WorkspaceScopedResponseBody):
    """Response body for pipelines."""

    latest_run_id: Optional[UUID] = Field(
        default=None,
        title="The ID of the latest run of the pipeline.",
    )
    latest_run_status: Optional[ExecutionStatus] = Field(
        default=None,
        title="The status of the latest run of the pipeline.",
    )

PipelineResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for pipelines.

Source code in src/zenml/models/v2/core/pipeline.py
111
112
113
114
115
116
117
class PipelineResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for pipelines."""

    description: Optional[str] = Field(
        default=None,
        title="The description of the pipeline.",
    )

PipelineResponseResources

Bases: WorkspaceScopedResponseResources

Class for all resource models associated with the pipeline entity.

Source code in src/zenml/models/v2/core/pipeline.py
120
121
122
123
124
125
126
127
128
129
class PipelineResponseResources(WorkspaceScopedResponseResources):
    """Class for all resource models associated with the pipeline entity."""

    latest_run_user: Optional["UserResponse"] = Field(
        default=None,
        title="The user that created the latest run of this pipeline.",
    )
    tags: List[TagResponse] = Field(
        title="Tags associated with the pipeline.",
    )

PipelineRunFilter

Bases: WorkspaceScopedFilter, TaggableFilter

Model to enable advanced filtering of all Workspaces.

Source code in src/zenml/models/v2/core/pipeline_run.py
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
class PipelineRunFilter(WorkspaceScopedFilter, TaggableFilter):
    """Model to enable advanced filtering of all Workspaces."""

    CUSTOM_SORTING_OPTIONS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.CUSTOM_SORTING_OPTIONS,
        *TaggableFilter.CUSTOM_SORTING_OPTIONS,
        "tag",
        "stack",
        "pipeline",
        "model",
        "model_version",
    ]
    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
        *TaggableFilter.FILTER_EXCLUDE_FIELDS,
        "unlisted",
        "code_repository_id",
        "build_id",
        "schedule_id",
        "stack_id",
        "template_id",
        "pipeline",
        "stack",
        "code_repository",
        "model",
        "stack_component",
        "pipeline_name",
        "templatable",
        "run_metadata",
    ]
    CLI_EXCLUDE_FIELDS = [
        *WorkspaceScopedFilter.CLI_EXCLUDE_FIELDS,
        *TaggableFilter.CLI_EXCLUDE_FIELDS,
    ]

    name: Optional[str] = Field(
        default=None,
        description="Name of the Pipeline Run",
    )
    orchestrator_run_id: Optional[str] = Field(
        default=None,
        description="Name of the Pipeline Run within the orchestrator",
    )
    pipeline_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Pipeline associated with the Pipeline Run",
        union_mode="left_to_right",
    )
    stack_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Stack used for the Pipeline Run",
        union_mode="left_to_right",
    )
    schedule_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Schedule that triggered the Pipeline Run",
        union_mode="left_to_right",
    )
    build_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Build used for the Pipeline Run",
        union_mode="left_to_right",
    )
    deployment_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Deployment used for the Pipeline Run",
        union_mode="left_to_right",
    )
    code_repository_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Code repository used for the Pipeline Run",
        union_mode="left_to_right",
    )
    template_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Template used for the pipeline run.",
        union_mode="left_to_right",
    )
    model_version_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Model version associated with the pipeline run.",
        union_mode="left_to_right",
    )
    status: Optional[str] = Field(
        default=None,
        description="Name of the Pipeline Run",
    )
    start_time: Optional[Union[datetime, str]] = Field(
        default=None,
        description="Start time for this run",
        union_mode="left_to_right",
    )
    end_time: Optional[Union[datetime, str]] = Field(
        default=None,
        description="End time for this run",
        union_mode="left_to_right",
    )
    unlisted: Optional[bool] = None
    run_metadata: Optional[Dict[str, Any]] = Field(
        default=None,
        description="The run_metadata to filter the pipeline runs by.",
    )
    # TODO: Remove once frontend is ready for it. This is replaced by the more
    #   generic `pipeline` filter below.
    pipeline_name: Optional[str] = Field(
        default=None,
        description="Name of the pipeline associated with the run",
    )
    pipeline: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of the pipeline associated with the run.",
    )
    stack: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of the stack associated with the run.",
    )
    code_repository: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of the code repository associated with the run.",
    )
    model: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of the model associated with the run.",
    )
    stack_component: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of the stack component associated with the run.",
    )
    templatable: Optional[bool] = Field(
        default=None, description="Whether the run is templatable."
    )
    model_config = ConfigDict(protected_namespaces=())

    def get_custom_filters(
        self,
        table: Type["AnySchema"],
    ) -> List["ColumnElement[bool]"]:
        """Get custom filters.

        Args:
            table: The query table.

        Returns:
            A list of custom filters.
        """
        custom_filters = super().get_custom_filters(table)

        from sqlmodel import and_, col, or_

        from zenml.zen_stores.schemas import (
            CodeReferenceSchema,
            CodeRepositorySchema,
            ModelSchema,
            ModelVersionSchema,
            PipelineBuildSchema,
            PipelineDeploymentSchema,
            PipelineRunSchema,
            PipelineSchema,
            RunMetadataResourceSchema,
            RunMetadataSchema,
            ScheduleSchema,
            StackComponentSchema,
            StackCompositionSchema,
            StackSchema,
        )

        if self.unlisted is not None:
            if self.unlisted is True:
                unlisted_filter = PipelineRunSchema.pipeline_id.is_(None)  # type: ignore[union-attr]
            else:
                unlisted_filter = PipelineRunSchema.pipeline_id.is_not(None)  # type: ignore[union-attr]
            custom_filters.append(unlisted_filter)

        if self.code_repository_id:
            code_repo_filter = and_(
                PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.code_reference_id
                == CodeReferenceSchema.id,
                CodeReferenceSchema.code_repository_id
                == self.code_repository_id,
            )
            custom_filters.append(code_repo_filter)

        if self.stack_id:
            stack_filter = and_(
                PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.stack_id == StackSchema.id,
                StackSchema.id == self.stack_id,
            )
            custom_filters.append(stack_filter)

        if self.schedule_id:
            schedule_filter = and_(
                PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.schedule_id == ScheduleSchema.id,
                ScheduleSchema.id == self.schedule_id,
            )
            custom_filters.append(schedule_filter)

        if self.build_id:
            pipeline_build_filter = and_(
                PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.build_id == PipelineBuildSchema.id,
                PipelineBuildSchema.id == self.build_id,
            )
            custom_filters.append(pipeline_build_filter)

        if self.template_id:
            run_template_filter = and_(
                PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.template_id == self.template_id,
            )
            custom_filters.append(run_template_filter)

        if self.pipeline:
            pipeline_filter = and_(
                PipelineRunSchema.pipeline_id == PipelineSchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.pipeline, table=PipelineSchema
                ),
            )
            custom_filters.append(pipeline_filter)

        if self.stack:
            stack_filter = and_(
                PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.stack_id == StackSchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.stack,
                    table=StackSchema,
                ),
            )
            custom_filters.append(stack_filter)

        if self.code_repository:
            code_repo_filter = and_(
                PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.code_reference_id
                == CodeReferenceSchema.id,
                CodeReferenceSchema.code_repository_id
                == CodeRepositorySchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.code_repository,
                    table=CodeRepositorySchema,
                ),
            )
            custom_filters.append(code_repo_filter)

        if self.model:
            model_filter = and_(
                PipelineRunSchema.model_version_id == ModelVersionSchema.id,
                ModelVersionSchema.model_id == ModelSchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.model, table=ModelSchema
                ),
            )
            custom_filters.append(model_filter)

        if self.stack_component:
            component_filter = and_(
                PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.stack_id == StackSchema.id,
                StackSchema.id == StackCompositionSchema.stack_id,
                StackCompositionSchema.component_id == StackComponentSchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.stack_component,
                    table=StackComponentSchema,
                ),
            )
            custom_filters.append(component_filter)

        if self.pipeline_name:
            pipeline_name_filter = and_(
                PipelineRunSchema.pipeline_id == PipelineSchema.id,
                self.generate_custom_query_conditions_for_column(
                    value=self.pipeline_name,
                    table=PipelineSchema,
                    column="name",
                ),
            )
            custom_filters.append(pipeline_name_filter)

        if self.templatable is not None:
            if self.templatable is True:
                templatable_filter = and_(
                    # The following condition is not perfect as it does not
                    # consider stacks with custom flavor components or local
                    # components, but the best we can do currently with our
                    # table columns.
                    PipelineRunSchema.deployment_id
                    == PipelineDeploymentSchema.id,
                    PipelineDeploymentSchema.build_id
                    == PipelineBuildSchema.id,
                    col(PipelineBuildSchema.is_local).is_(False),
                    col(PipelineBuildSchema.stack_id).is_not(None),
                )
            else:
                templatable_filter = or_(
                    col(PipelineRunSchema.deployment_id).is_(None),
                    and_(
                        PipelineRunSchema.deployment_id
                        == PipelineDeploymentSchema.id,
                        col(PipelineDeploymentSchema.build_id).is_(None),
                    ),
                    and_(
                        PipelineRunSchema.deployment_id
                        == PipelineDeploymentSchema.id,
                        PipelineDeploymentSchema.build_id
                        == PipelineBuildSchema.id,
                        or_(
                            col(PipelineBuildSchema.is_local).is_(True),
                            col(PipelineBuildSchema.stack_id).is_(None),
                        ),
                    ),
                )

            custom_filters.append(templatable_filter)
        if self.run_metadata is not None:
            from zenml.enums import MetadataResourceTypes

            for key, value in self.run_metadata.items():
                additional_filter = and_(
                    RunMetadataResourceSchema.resource_id
                    == PipelineRunSchema.id,
                    RunMetadataResourceSchema.resource_type
                    == MetadataResourceTypes.PIPELINE_RUN.value,
                    RunMetadataResourceSchema.run_metadata_id
                    == RunMetadataSchema.id,
                    self.generate_custom_query_conditions_for_column(
                        value=key,
                        table=RunMetadataSchema,
                        column="key",
                    ),
                    self.generate_custom_query_conditions_for_column(
                        value=value,
                        table=RunMetadataSchema,
                        column="value",
                        json_encode_value=True,
                    ),
                )
                custom_filters.append(additional_filter)

        return custom_filters

    def apply_sorting(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Apply sorting to the query.

        Args:
            query: The query to which to apply the sorting.
            table: The query table.

        Returns:
            The query with sorting applied.
        """
        from sqlmodel import asc, desc

        from zenml.enums import SorterOps
        from zenml.zen_stores.schemas import (
            ModelSchema,
            ModelVersionSchema,
            PipelineDeploymentSchema,
            PipelineRunSchema,
            PipelineSchema,
            StackSchema,
        )

        sort_by, operand = self.sorting_params

        if sort_by == "pipeline":
            query = query.outerjoin(
                PipelineSchema,
                PipelineRunSchema.pipeline_id == PipelineSchema.id,
            )
            column = PipelineSchema.name
        elif sort_by == "stack":
            query = query.outerjoin(
                PipelineDeploymentSchema,
                PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
            ).outerjoin(
                StackSchema,
                PipelineDeploymentSchema.stack_id == StackSchema.id,
            )
            column = StackSchema.name
        elif sort_by == "model":
            query = query.outerjoin(
                ModelVersionSchema,
                PipelineRunSchema.model_version_id == ModelVersionSchema.id,
            ).outerjoin(
                ModelSchema,
                ModelVersionSchema.model_id == ModelSchema.id,
            )
            column = ModelSchema.name
        elif sort_by == "model_version":
            query = query.outerjoin(
                ModelVersionSchema,
                PipelineRunSchema.model_version_id == ModelVersionSchema.id,
            )
            column = ModelVersionSchema.name
        else:
            return super().apply_sorting(query=query, table=table)

        query = query.add_columns(column)

        if operand == SorterOps.ASCENDING:
            query = query.order_by(asc(column))
        else:
            query = query.order_by(desc(column))

        return query

apply_sorting(query, table)

Apply sorting to the query.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the sorting.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with sorting applied.

Source code in src/zenml/models/v2/core/pipeline_run.py
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
def apply_sorting(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Apply sorting to the query.

    Args:
        query: The query to which to apply the sorting.
        table: The query table.

    Returns:
        The query with sorting applied.
    """
    from sqlmodel import asc, desc

    from zenml.enums import SorterOps
    from zenml.zen_stores.schemas import (
        ModelSchema,
        ModelVersionSchema,
        PipelineDeploymentSchema,
        PipelineRunSchema,
        PipelineSchema,
        StackSchema,
    )

    sort_by, operand = self.sorting_params

    if sort_by == "pipeline":
        query = query.outerjoin(
            PipelineSchema,
            PipelineRunSchema.pipeline_id == PipelineSchema.id,
        )
        column = PipelineSchema.name
    elif sort_by == "stack":
        query = query.outerjoin(
            PipelineDeploymentSchema,
            PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
        ).outerjoin(
            StackSchema,
            PipelineDeploymentSchema.stack_id == StackSchema.id,
        )
        column = StackSchema.name
    elif sort_by == "model":
        query = query.outerjoin(
            ModelVersionSchema,
            PipelineRunSchema.model_version_id == ModelVersionSchema.id,
        ).outerjoin(
            ModelSchema,
            ModelVersionSchema.model_id == ModelSchema.id,
        )
        column = ModelSchema.name
    elif sort_by == "model_version":
        query = query.outerjoin(
            ModelVersionSchema,
            PipelineRunSchema.model_version_id == ModelVersionSchema.id,
        )
        column = ModelVersionSchema.name
    else:
        return super().apply_sorting(query=query, table=table)

    query = query.add_columns(column)

    if operand == SorterOps.ASCENDING:
        query = query.order_by(asc(column))
    else:
        query = query.order_by(desc(column))

    return query

get_custom_filters(table)

Get custom filters.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
List[ColumnElement[bool]]

A list of custom filters.

Source code in src/zenml/models/v2/core/pipeline_run.py
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
def get_custom_filters(
    self,
    table: Type["AnySchema"],
) -> List["ColumnElement[bool]"]:
    """Get custom filters.

    Args:
        table: The query table.

    Returns:
        A list of custom filters.
    """
    custom_filters = super().get_custom_filters(table)

    from sqlmodel import and_, col, or_

    from zenml.zen_stores.schemas import (
        CodeReferenceSchema,
        CodeRepositorySchema,
        ModelSchema,
        ModelVersionSchema,
        PipelineBuildSchema,
        PipelineDeploymentSchema,
        PipelineRunSchema,
        PipelineSchema,
        RunMetadataResourceSchema,
        RunMetadataSchema,
        ScheduleSchema,
        StackComponentSchema,
        StackCompositionSchema,
        StackSchema,
    )

    if self.unlisted is not None:
        if self.unlisted is True:
            unlisted_filter = PipelineRunSchema.pipeline_id.is_(None)  # type: ignore[union-attr]
        else:
            unlisted_filter = PipelineRunSchema.pipeline_id.is_not(None)  # type: ignore[union-attr]
        custom_filters.append(unlisted_filter)

    if self.code_repository_id:
        code_repo_filter = and_(
            PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
            PipelineDeploymentSchema.code_reference_id
            == CodeReferenceSchema.id,
            CodeReferenceSchema.code_repository_id
            == self.code_repository_id,
        )
        custom_filters.append(code_repo_filter)

    if self.stack_id:
        stack_filter = and_(
            PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
            PipelineDeploymentSchema.stack_id == StackSchema.id,
            StackSchema.id == self.stack_id,
        )
        custom_filters.append(stack_filter)

    if self.schedule_id:
        schedule_filter = and_(
            PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
            PipelineDeploymentSchema.schedule_id == ScheduleSchema.id,
            ScheduleSchema.id == self.schedule_id,
        )
        custom_filters.append(schedule_filter)

    if self.build_id:
        pipeline_build_filter = and_(
            PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
            PipelineDeploymentSchema.build_id == PipelineBuildSchema.id,
            PipelineBuildSchema.id == self.build_id,
        )
        custom_filters.append(pipeline_build_filter)

    if self.template_id:
        run_template_filter = and_(
            PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
            PipelineDeploymentSchema.template_id == self.template_id,
        )
        custom_filters.append(run_template_filter)

    if self.pipeline:
        pipeline_filter = and_(
            PipelineRunSchema.pipeline_id == PipelineSchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.pipeline, table=PipelineSchema
            ),
        )
        custom_filters.append(pipeline_filter)

    if self.stack:
        stack_filter = and_(
            PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
            PipelineDeploymentSchema.stack_id == StackSchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.stack,
                table=StackSchema,
            ),
        )
        custom_filters.append(stack_filter)

    if self.code_repository:
        code_repo_filter = and_(
            PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
            PipelineDeploymentSchema.code_reference_id
            == CodeReferenceSchema.id,
            CodeReferenceSchema.code_repository_id
            == CodeRepositorySchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.code_repository,
                table=CodeRepositorySchema,
            ),
        )
        custom_filters.append(code_repo_filter)

    if self.model:
        model_filter = and_(
            PipelineRunSchema.model_version_id == ModelVersionSchema.id,
            ModelVersionSchema.model_id == ModelSchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.model, table=ModelSchema
            ),
        )
        custom_filters.append(model_filter)

    if self.stack_component:
        component_filter = and_(
            PipelineRunSchema.deployment_id == PipelineDeploymentSchema.id,
            PipelineDeploymentSchema.stack_id == StackSchema.id,
            StackSchema.id == StackCompositionSchema.stack_id,
            StackCompositionSchema.component_id == StackComponentSchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.stack_component,
                table=StackComponentSchema,
            ),
        )
        custom_filters.append(component_filter)

    if self.pipeline_name:
        pipeline_name_filter = and_(
            PipelineRunSchema.pipeline_id == PipelineSchema.id,
            self.generate_custom_query_conditions_for_column(
                value=self.pipeline_name,
                table=PipelineSchema,
                column="name",
            ),
        )
        custom_filters.append(pipeline_name_filter)

    if self.templatable is not None:
        if self.templatable is True:
            templatable_filter = and_(
                # The following condition is not perfect as it does not
                # consider stacks with custom flavor components or local
                # components, but the best we can do currently with our
                # table columns.
                PipelineRunSchema.deployment_id
                == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.build_id
                == PipelineBuildSchema.id,
                col(PipelineBuildSchema.is_local).is_(False),
                col(PipelineBuildSchema.stack_id).is_not(None),
            )
        else:
            templatable_filter = or_(
                col(PipelineRunSchema.deployment_id).is_(None),
                and_(
                    PipelineRunSchema.deployment_id
                    == PipelineDeploymentSchema.id,
                    col(PipelineDeploymentSchema.build_id).is_(None),
                ),
                and_(
                    PipelineRunSchema.deployment_id
                    == PipelineDeploymentSchema.id,
                    PipelineDeploymentSchema.build_id
                    == PipelineBuildSchema.id,
                    or_(
                        col(PipelineBuildSchema.is_local).is_(True),
                        col(PipelineBuildSchema.stack_id).is_(None),
                    ),
                ),
            )

        custom_filters.append(templatable_filter)
    if self.run_metadata is not None:
        from zenml.enums import MetadataResourceTypes

        for key, value in self.run_metadata.items():
            additional_filter = and_(
                RunMetadataResourceSchema.resource_id
                == PipelineRunSchema.id,
                RunMetadataResourceSchema.resource_type
                == MetadataResourceTypes.PIPELINE_RUN.value,
                RunMetadataResourceSchema.run_metadata_id
                == RunMetadataSchema.id,
                self.generate_custom_query_conditions_for_column(
                    value=key,
                    table=RunMetadataSchema,
                    column="key",
                ),
                self.generate_custom_query_conditions_for_column(
                    value=value,
                    table=RunMetadataSchema,
                    column="value",
                    json_encode_value=True,
                ),
            )
            custom_filters.append(additional_filter)

    return custom_filters

PipelineRunRequest

Bases: WorkspaceScopedRequest

Request model for pipeline runs.

Source code in src/zenml/models/v2/core/pipeline_run.py
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
class PipelineRunRequest(WorkspaceScopedRequest):
    """Request model for pipeline runs."""

    name: str = Field(
        title="The name of the pipeline run.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    deployment: UUID = Field(
        title="The deployment associated with the pipeline run."
    )
    pipeline: Optional[UUID] = Field(
        title="The pipeline associated with the pipeline run.",
        default=None,
    )
    orchestrator_run_id: Optional[str] = Field(
        title="The orchestrator run ID.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    start_time: Optional[datetime] = Field(
        title="The start time of the pipeline run.",
        default=None,
    )
    end_time: Optional[datetime] = Field(
        title="The end time of the pipeline run.",
        default=None,
    )
    status: ExecutionStatus = Field(
        title="The status of the pipeline run.",
    )
    client_environment: Dict[str, str] = Field(
        default={},
        title=(
            "Environment of the client that initiated this pipeline run "
            "(OS, Python version, etc.)."
        ),
    )
    orchestrator_environment: Dict[str, str] = Field(
        default={},
        title=(
            "Environment of the orchestrator that executed this pipeline run "
            "(OS, Python version, etc.)."
        ),
    )
    trigger_execution_id: Optional[UUID] = Field(
        default=None,
        title="ID of the trigger execution that triggered this run.",
    )
    tags: Optional[List[str]] = Field(
        default=None,
        title="Tags of the pipeline run.",
    )
    model_version_id: Optional[UUID] = Field(
        title="The ID of the model version that was "
        "configured by this pipeline run explicitly.",
        default=None,
    )

    model_config = ConfigDict(protected_namespaces=())

PipelineRunResponse

Bases: WorkspaceScopedResponse[PipelineRunResponseBody, PipelineRunResponseMetadata, PipelineRunResponseResources]

Response model for pipeline runs.

Source code in src/zenml/models/v2/core/pipeline_run.py
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
class PipelineRunResponse(
    WorkspaceScopedResponse[
        PipelineRunResponseBody,
        PipelineRunResponseMetadata,
        PipelineRunResponseResources,
    ]
):
    """Response model for pipeline runs."""

    name: str = Field(
        title="The name of the pipeline run.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "PipelineRunResponse":
        """Get the hydrated version of this pipeline run.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_run(self.id)

    # Helper methods
    @property
    def artifact_versions(self) -> List["ArtifactVersionResponse"]:
        """Get all artifact versions that are outputs of steps of this run.

        Returns:
            All output artifact versions of this run (including cached ones).
        """
        from zenml.artifacts.utils import (
            get_artifacts_versions_of_pipeline_run,
        )

        return get_artifacts_versions_of_pipeline_run(self)

    @property
    def produced_artifact_versions(self) -> List["ArtifactVersionResponse"]:
        """Get all artifact versions produced during this pipeline run.

        Returns:
            A list of all artifact versions produced during this pipeline run.
        """
        from zenml.artifacts.utils import (
            get_artifacts_versions_of_pipeline_run,
        )

        return get_artifacts_versions_of_pipeline_run(self, only_produced=True)

    def refresh_run_status(self) -> "PipelineRunResponse":
        """Method to refresh the status of a run if it is initializing/running.

        Returns:
            The updated pipeline.

        Raises:
            ValueError: If the stack of the run response is None.
        """
        if self.status in [
            ExecutionStatus.INITIALIZING,
            ExecutionStatus.RUNNING,
        ]:
            # Check if the stack still accessible
            if self.stack is None:
                raise ValueError(
                    "The stack that this pipeline run response was executed on"
                    "has been deleted."
                )

            # Create the orchestrator instance
            from zenml.enums import StackComponentType
            from zenml.orchestrators.base_orchestrator import BaseOrchestrator
            from zenml.stack.stack_component import StackComponent

            # Check if the stack still accessible
            orchestrator_list = self.stack.components.get(
                StackComponentType.ORCHESTRATOR, []
            )
            if len(orchestrator_list) == 0:
                raise ValueError(
                    "The orchestrator that this pipeline run response was "
                    "executed with has been deleted."
                )

            orchestrator = cast(
                BaseOrchestrator,
                StackComponent.from_model(
                    component_model=orchestrator_list[0]
                ),
            )

            # Fetch the status
            status = orchestrator.fetch_status(run=self)

            # If it is different from the current status, update it
            if status != self.status:
                from zenml.client import Client
                from zenml.models import PipelineRunUpdate

                client = Client()
                return client.zen_store.update_run(
                    run_id=self.id,
                    run_update=PipelineRunUpdate(status=status),
                )

        return self

    # Body and metadata properties
    @property
    def status(self) -> ExecutionStatus:
        """The `status` property.

        Returns:
            the value of the property.
        """
        return self.get_body().status

    @property
    def stack(self) -> Optional["StackResponse"]:
        """The `stack` property.

        Returns:
            the value of the property.
        """
        return self.get_body().stack

    @property
    def pipeline(self) -> Optional["PipelineResponse"]:
        """The `pipeline` property.

        Returns:
            the value of the property.
        """
        return self.get_body().pipeline

    @property
    def build(self) -> Optional["PipelineBuildResponse"]:
        """The `build` property.

        Returns:
            the value of the property.
        """
        return self.get_body().build

    @property
    def schedule(self) -> Optional["ScheduleResponse"]:
        """The `schedule` property.

        Returns:
            the value of the property.
        """
        return self.get_body().schedule

    @property
    def trigger_execution(self) -> Optional["TriggerExecutionResponse"]:
        """The `trigger_execution` property.

        Returns:
            the value of the property.
        """
        return self.get_body().trigger_execution

    @property
    def code_reference(self) -> Optional["CodeReferenceResponse"]:
        """The `schedule` property.

        Returns:
            the value of the property.
        """
        return self.get_body().code_reference

    @property
    def deployment_id(self) -> Optional["UUID"]:
        """The `deployment_id` property.

        Returns:
            the value of the property.
        """
        return self.get_body().deployment_id

    @property
    def model_version_id(self) -> Optional[UUID]:
        """The `model_version_id` property.

        Returns:
            the value of the property.
        """
        return self.get_body().model_version_id

    @property
    def run_metadata(self) -> Dict[str, MetadataType]:
        """The `run_metadata` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().run_metadata

    @property
    def steps(self) -> Dict[str, "StepRunResponse"]:
        """The `steps` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().steps

    @property
    def config(self) -> PipelineConfiguration:
        """The `config` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().config

    @property
    def start_time(self) -> Optional[datetime]:
        """The `start_time` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().start_time

    @property
    def end_time(self) -> Optional[datetime]:
        """The `end_time` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().end_time

    @property
    def client_environment(self) -> Dict[str, str]:
        """The `client_environment` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().client_environment

    @property
    def orchestrator_environment(self) -> Dict[str, str]:
        """The `orchestrator_environment` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().orchestrator_environment

    @property
    def orchestrator_run_id(self) -> Optional[str]:
        """The `orchestrator_run_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().orchestrator_run_id

    @property
    def code_path(self) -> Optional[str]:
        """The `code_path` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().code_path

    @property
    def template_id(self) -> Optional[UUID]:
        """The `template_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().template_id

    @property
    def is_templatable(self) -> bool:
        """The `is_templatable` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().is_templatable

    @property
    def step_substitutions(self) -> Dict[str, Dict[str, str]]:
        """The `step_substitutions` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().step_substitutions

    @property
    def model_version(self) -> Optional[ModelVersionResponse]:
        """The `model_version` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().model_version

    @property
    def tags(self) -> List[TagResponse]:
        """The `tags` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().tags

artifact_versions property

Get all artifact versions that are outputs of steps of this run.

Returns:

Type Description
List[ArtifactVersionResponse]

All output artifact versions of this run (including cached ones).

build property

The build property.

Returns:

Type Description
Optional[PipelineBuildResponse]

the value of the property.

client_environment property

The client_environment property.

Returns:

Type Description
Dict[str, str]

the value of the property.

code_path property

The code_path property.

Returns:

Type Description
Optional[str]

the value of the property.

code_reference property

The schedule property.

Returns:

Type Description
Optional[CodeReferenceResponse]

the value of the property.

config property

The config property.

Returns:

Type Description
PipelineConfiguration

the value of the property.

deployment_id property

The deployment_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

end_time property

The end_time property.

Returns:

Type Description
Optional[datetime]

the value of the property.

is_templatable property

The is_templatable property.

Returns:

Type Description
bool

the value of the property.

model_version property

The model_version property.

Returns:

Type Description
Optional[ModelVersionResponse]

the value of the property.

model_version_id property

The model_version_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

orchestrator_environment property

The orchestrator_environment property.

Returns:

Type Description
Dict[str, str]

the value of the property.

orchestrator_run_id property

The orchestrator_run_id property.

Returns:

Type Description
Optional[str]

the value of the property.

pipeline property

The pipeline property.

Returns:

Type Description
Optional[PipelineResponse]

the value of the property.

produced_artifact_versions property

Get all artifact versions produced during this pipeline run.

Returns:

Type Description
List[ArtifactVersionResponse]

A list of all artifact versions produced during this pipeline run.

run_metadata property

The run_metadata property.

Returns:

Type Description
Dict[str, MetadataType]

the value of the property.

schedule property

The schedule property.

Returns:

Type Description
Optional[ScheduleResponse]

the value of the property.

stack property

The stack property.

Returns:

Type Description
Optional[StackResponse]

the value of the property.

start_time property

The start_time property.

Returns:

Type Description
Optional[datetime]

the value of the property.

status property

The status property.

Returns:

Type Description
ExecutionStatus

the value of the property.

step_substitutions property

The step_substitutions property.

Returns:

Type Description
Dict[str, Dict[str, str]]

the value of the property.

steps property

The steps property.

Returns:

Type Description
Dict[str, StepRunResponse]

the value of the property.

tags property

The tags property.

Returns:

Type Description
List[TagResponse]

the value of the property.

template_id property

The template_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

trigger_execution property

The trigger_execution property.

Returns:

Type Description
Optional[TriggerExecutionResponse]

the value of the property.

get_hydrated_version()

Get the hydrated version of this pipeline run.

Returns:

Type Description
PipelineRunResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/pipeline_run.py
286
287
288
289
290
291
292
293
294
def get_hydrated_version(self) -> "PipelineRunResponse":
    """Get the hydrated version of this pipeline run.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_run(self.id)

refresh_run_status()

Method to refresh the status of a run if it is initializing/running.

Returns:

Type Description
PipelineRunResponse

The updated pipeline.

Raises:

Type Description
ValueError

If the stack of the run response is None.

Source code in src/zenml/models/v2/core/pipeline_run.py
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
def refresh_run_status(self) -> "PipelineRunResponse":
    """Method to refresh the status of a run if it is initializing/running.

    Returns:
        The updated pipeline.

    Raises:
        ValueError: If the stack of the run response is None.
    """
    if self.status in [
        ExecutionStatus.INITIALIZING,
        ExecutionStatus.RUNNING,
    ]:
        # Check if the stack still accessible
        if self.stack is None:
            raise ValueError(
                "The stack that this pipeline run response was executed on"
                "has been deleted."
            )

        # Create the orchestrator instance
        from zenml.enums import StackComponentType
        from zenml.orchestrators.base_orchestrator import BaseOrchestrator
        from zenml.stack.stack_component import StackComponent

        # Check if the stack still accessible
        orchestrator_list = self.stack.components.get(
            StackComponentType.ORCHESTRATOR, []
        )
        if len(orchestrator_list) == 0:
            raise ValueError(
                "The orchestrator that this pipeline run response was "
                "executed with has been deleted."
            )

        orchestrator = cast(
            BaseOrchestrator,
            StackComponent.from_model(
                component_model=orchestrator_list[0]
            ),
        )

        # Fetch the status
        status = orchestrator.fetch_status(run=self)

        # If it is different from the current status, update it
        if status != self.status:
            from zenml.client import Client
            from zenml.models import PipelineRunUpdate

            client = Client()
            return client.zen_store.update_run(
                run_id=self.id,
                run_update=PipelineRunUpdate(status=status),
            )

    return self

PipelineRunResponseBody

Bases: WorkspaceScopedResponseBody

Response body for pipeline runs.

Source code in src/zenml/models/v2/core/pipeline_run.py
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
class PipelineRunResponseBody(WorkspaceScopedResponseBody):
    """Response body for pipeline runs."""

    status: ExecutionStatus = Field(
        title="The status of the pipeline run.",
    )
    stack: Optional["StackResponse"] = Field(
        default=None, title="The stack that was used for this run."
    )
    pipeline: Optional["PipelineResponse"] = Field(
        default=None, title="The pipeline this run belongs to."
    )
    build: Optional["PipelineBuildResponse"] = Field(
        default=None, title="The pipeline build that was used for this run."
    )
    schedule: Optional["ScheduleResponse"] = Field(
        default=None, title="The schedule that was used for this run."
    )
    code_reference: Optional["CodeReferenceResponse"] = Field(
        default=None, title="The code reference that was used for this run."
    )
    deployment_id: Optional[UUID] = Field(
        default=None, title="The deployment that was used for this run."
    )
    trigger_execution: Optional["TriggerExecutionResponse"] = Field(
        default=None, title="The trigger execution that triggered this run."
    )
    model_version_id: Optional[UUID] = Field(
        title="The ID of the model version that was "
        "configured by this pipeline run explicitly.",
        default=None,
    )

    model_config = ConfigDict(protected_namespaces=())

PipelineRunResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for pipeline runs.

Source code in src/zenml/models/v2/core/pipeline_run.py
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
class PipelineRunResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for pipeline runs."""

    run_metadata: Dict[str, MetadataType] = Field(
        default={},
        title="Metadata associated with this pipeline run.",
    )
    steps: Dict[str, "StepRunResponse"] = Field(
        default={}, title="The steps of this run."
    )
    config: PipelineConfiguration = Field(
        title="The pipeline configuration used for this pipeline run.",
    )
    start_time: Optional[datetime] = Field(
        title="The start time of the pipeline run.",
        default=None,
    )
    end_time: Optional[datetime] = Field(
        title="The end time of the pipeline run.",
        default=None,
    )
    client_environment: Dict[str, str] = Field(
        default={},
        title=(
            "Environment of the client that initiated this pipeline run "
            "(OS, Python version, etc.)."
        ),
    )
    orchestrator_environment: Dict[str, str] = Field(
        default={},
        title=(
            "Environment of the orchestrator that executed this pipeline run "
            "(OS, Python version, etc.)."
        ),
    )
    orchestrator_run_id: Optional[str] = Field(
        title="The orchestrator run ID.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    code_path: Optional[str] = Field(
        default=None,
        title="Optional path where the code is stored in the artifact store.",
    )
    template_id: Optional[UUID] = Field(
        default=None,
        description="Template used for the pipeline run.",
    )
    is_templatable: bool = Field(
        default=False,
        description="Whether a template can be created from this run.",
    )
    step_substitutions: Dict[str, Dict[str, str]] = Field(
        title="Substitutions used in the step runs of this pipeline run.",
        default_factory=dict,
    )

PipelineRunResponseResources

Bases: WorkspaceScopedResponseResources

Class for all resource models associated with the pipeline run entity.

Source code in src/zenml/models/v2/core/pipeline_run.py
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
class PipelineRunResponseResources(WorkspaceScopedResponseResources):
    """Class for all resource models associated with the pipeline run entity."""

    model_version: Optional[ModelVersionResponse] = None
    tags: List[TagResponse] = Field(
        title="Tags associated with the pipeline run.",
    )

    # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
    #  fields defined under base models. If not handled, this raises a warning.
    #  It is possible to suppress this warning message with the following
    #  configuration, however the ultimate solution is to rename these fields.
    #  Even though they do not cause any problems right now, if we are not
    #  careful we might overwrite some fields protected by pydantic.
    model_config = ConfigDict(protected_namespaces=())

PipelineRunUpdate

Bases: BaseModel

Pipeline run update model.

Source code in src/zenml/models/v2/core/pipeline_run.py
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
class PipelineRunUpdate(BaseModel):
    """Pipeline run update model."""

    status: Optional[ExecutionStatus] = None
    end_time: Optional[datetime] = None
    model_version_id: Optional[UUID] = Field(
        title="The ID of the model version that was "
        "configured by this pipeline run explicitly.",
        default=None,
    )
    # TODO: we should maybe have a different update model here, the upper
    #  three attributes should only be for internal use
    add_tags: Optional[List[str]] = Field(
        default=None, title="New tags to add to the pipeline run."
    )
    remove_tags: Optional[List[str]] = Field(
        default=None, title="Tags to remove from the pipeline run."
    )

    model_config = ConfigDict(protected_namespaces=())

PipelineUpdate

Bases: BaseUpdate

Update model for pipelines.

Source code in src/zenml/models/v2/core/pipeline.py
79
80
81
82
83
84
85
86
87
88
89
90
91
92
class PipelineUpdate(BaseUpdate):
    """Update model for pipelines."""

    description: Optional[str] = Field(
        default=None,
        title="The description of the pipeline.",
        max_length=TEXT_FIELD_MAX_LENGTH,
    )
    add_tags: Optional[List[str]] = Field(
        default=None, title="New tags to add to the pipeline."
    )
    remove_tags: Optional[List[str]] = Field(
        default=None, title="Tags to remove from the pipeline."
    )

ResourceTypeModel

Bases: BaseModel

Resource type specification.

Describes the authentication methods and resource instantiation model for one or more resource types.

Source code in src/zenml/models/v2/misc/service_connector_type.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
class ResourceTypeModel(BaseModel):
    """Resource type specification.

    Describes the authentication methods and resource instantiation model for
    one or more resource types.
    """

    name: str = Field(
        title="User readable name for the resource type.",
    )
    resource_type: str = Field(
        title="Resource type identifier.",
    )
    description: str = Field(
        default="",
        title="A description of the resource type.",
    )
    auth_methods: List[str] = Field(
        title="The list of authentication methods that can be used to access "
        "resources of this type.",
    )
    supports_instances: bool = Field(
        default=False,
        title="Specifies if a single connector instance can be used to access "
        "multiple instances of this resource type. If set to True, the "
        "connector is able to provide a list of resource IDs identifying all "
        "the resources that it can access and a resource ID needs to be "
        "explicitly configured or supplied when access to a resource is "
        "requested. If set to False, a connector instance is only able to "
        "access a single resource and a resource ID is not required to access "
        "the resource.",
    )
    logo_url: Optional[str] = Field(
        default=None,
        title="Optionally, a URL pointing to a png,"
        "svg or jpg file can be attached.",
    )
    emoji: Optional[str] = Field(
        default=None,
        title="Optionally, a python-rich emoji can be attached.",
    )

    @property
    def emojified_resource_type(self) -> str:
        """Get the emojified resource type.

        Returns:
            The emojified resource type.
        """
        if not self.emoji:
            return self.resource_type
        return f"{self.emoji} {self.resource_type}"

emojified_resource_type property

Get the emojified resource type.

Returns:

Type Description
str

The emojified resource type.

ResourcesInfo

Bases: BaseModel

Information about the resources needed for CLI and UI.

Source code in src/zenml/models/v2/misc/info_models.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class ResourcesInfo(BaseModel):
    """Information about the resources needed for CLI and UI."""

    flavor: str
    flavor_display_name: str
    required_configuration: Dict[str, str] = {}
    use_resource_value_as_fixed_config: bool = False

    accessible_by_service_connector: List[str]
    connected_through_service_connector: List["ComponentResponse"]

    @model_validator(mode="after")
    def _validate_resource_info(self) -> "ResourcesInfo":
        if (
            self.use_resource_value_as_fixed_config
            and len(self.required_configuration) > 1
        ):
            raise ValueError(
                "Cannot use resource value as fixed config if more than "
                "one required configuration key is provided."
            )
        return self

RunMetadataEntry

Bases: BaseModel

Utility class to sort/list run metadata entries.

Source code in src/zenml/models/v2/misc/run_metadata.py
32
33
34
35
36
37
38
class RunMetadataEntry(BaseModel):
    """Utility class to sort/list run metadata entries."""

    value: MetadataType = Field(title="The value for the run metadata entry")
    created: datetime = Field(
        title="The timestamp when this resource was created."
    )

RunMetadataRequest

Bases: WorkspaceScopedRequest

Request model for run metadata.

Source code in src/zenml/models/v2/core/run_metadata.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
class RunMetadataRequest(WorkspaceScopedRequest):
    """Request model for run metadata."""

    resources: List[RunMetadataResource] = Field(
        title="The list of resources that this metadata belongs to."
    )
    stack_component_id: Optional[UUID] = Field(
        title="The ID of the stack component that this metadata belongs to.",
        default=None,
    )
    values: Dict[str, "MetadataType"] = Field(
        title="The metadata to be created.",
    )
    types: Dict[str, "MetadataTypeEnum"] = Field(
        title="The types of the metadata to be created.",
    )
    publisher_step_id: Optional[UUID] = Field(
        title="The ID of the step execution that published this metadata.",
        default=None,
    )

    @model_validator(mode="after")
    def validate_values_keys(self) -> "RunMetadataRequest":
        """Validates if the keys in the metadata are properly defined.

        Returns:
            self

        Raises:
            ValueError: if one of the key in the metadata contains `:`
        """
        invalid_keys = [key for key in self.values.keys() if ":" in key]
        if invalid_keys:
            raise ValueError(
                "You can not use colons (`:`) in the key names when you "
                "are creating metadata for your ZenML objects. Please change "
                f"the following keys: {invalid_keys}"
            )
        return self

validate_values_keys()

Validates if the keys in the metadata are properly defined.

Returns:

Type Description
RunMetadataRequest

self

Raises:

Type Description
ValueError

if one of the key in the metadata contains :

Source code in src/zenml/models/v2/core/run_metadata.py
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
@model_validator(mode="after")
def validate_values_keys(self) -> "RunMetadataRequest":
    """Validates if the keys in the metadata are properly defined.

    Returns:
        self

    Raises:
        ValueError: if one of the key in the metadata contains `:`
    """
    invalid_keys = [key for key in self.values.keys() if ":" in key]
    if invalid_keys:
        raise ValueError(
            "You can not use colons (`:`) in the key names when you "
            "are creating metadata for your ZenML objects. Please change "
            f"the following keys: {invalid_keys}"
        )
    return self

RunMetadataResource

Bases: BaseModel

Utility class to help identify resources to tag metadata to.

Source code in src/zenml/models/v2/misc/run_metadata.py
25
26
27
28
29
class RunMetadataResource(BaseModel):
    """Utility class to help identify resources to tag metadata to."""

    id: UUID = Field(title="The ID of the resource.")
    type: MetadataResourceTypes = Field(title="The type of the resource.")

RunTemplateFilter

Bases: WorkspaceScopedFilter, TaggableFilter

Model for filtering of run templates.

Source code in src/zenml/models/v2/core/run_template.py
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
class RunTemplateFilter(WorkspaceScopedFilter, TaggableFilter):
    """Model for filtering of run templates."""

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
        *TaggableFilter.FILTER_EXCLUDE_FIELDS,
        "code_repository_id",
        "stack_id",
        "build_id",
        "pipeline_id",
        "user",
        "pipeline",
        "stack",
    ]
    CUSTOM_SORTING_OPTIONS = [
        *WorkspaceScopedFilter.CUSTOM_SORTING_OPTIONS,
        *TaggableFilter.CUSTOM_SORTING_OPTIONS,
    ]
    CLI_EXCLUDE_FIELDS = [
        *WorkspaceScopedFilter.CLI_EXCLUDE_FIELDS,
        *TaggableFilter.CLI_EXCLUDE_FIELDS,
    ]

    name: Optional[str] = Field(
        default=None,
        description="Name of the run template.",
    )
    pipeline_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Pipeline associated with the template.",
        union_mode="left_to_right",
    )
    build_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Build associated with the template.",
        union_mode="left_to_right",
    )
    stack_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Stack associated with the template.",
        union_mode="left_to_right",
    )
    code_repository_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Code repository associated with the template.",
        union_mode="left_to_right",
    )
    pipeline: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of the pipeline associated with the template.",
    )
    stack: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of the stack associated with the template.",
    )

    def get_custom_filters(
        self, table: Type["AnySchema"]
    ) -> List["ColumnElement[bool]"]:
        """Get custom filters.

        Args:
            table: The query table.

        Returns:
            A list of custom filters.
        """
        custom_filters = super().get_custom_filters(table)

        from sqlmodel import and_

        from zenml.zen_stores.schemas import (
            CodeReferenceSchema,
            PipelineDeploymentSchema,
            PipelineSchema,
            RunTemplateSchema,
            StackSchema,
        )

        if self.code_repository_id:
            code_repo_filter = and_(
                RunTemplateSchema.source_deployment_id
                == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.code_reference_id
                == CodeReferenceSchema.id,
                CodeReferenceSchema.code_repository_id
                == self.code_repository_id,
            )
            custom_filters.append(code_repo_filter)

        if self.stack_id:
            stack_filter = and_(
                RunTemplateSchema.source_deployment_id
                == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.stack_id == self.stack_id,
            )
            custom_filters.append(stack_filter)

        if self.build_id:
            build_filter = and_(
                RunTemplateSchema.source_deployment_id
                == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.build_id == self.build_id,
            )
            custom_filters.append(build_filter)

        if self.pipeline_id:
            pipeline_filter = and_(
                RunTemplateSchema.source_deployment_id
                == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.pipeline_id == self.pipeline_id,
            )
            custom_filters.append(pipeline_filter)

        if self.pipeline:
            pipeline_filter = and_(
                RunTemplateSchema.source_deployment_id
                == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.pipeline_id == PipelineSchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.pipeline,
                    table=PipelineSchema,
                ),
            )
            custom_filters.append(pipeline_filter)

        if self.stack:
            stack_filter = and_(
                RunTemplateSchema.source_deployment_id
                == PipelineDeploymentSchema.id,
                PipelineDeploymentSchema.stack_id == StackSchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.stack,
                    table=StackSchema,
                ),
            )
            custom_filters.append(stack_filter)

        return custom_filters

get_custom_filters(table)

Get custom filters.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
List[ColumnElement[bool]]

A list of custom filters.

Source code in src/zenml/models/v2/core/run_template.py
367
368
369
370
371
372
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
def get_custom_filters(
    self, table: Type["AnySchema"]
) -> List["ColumnElement[bool]"]:
    """Get custom filters.

    Args:
        table: The query table.

    Returns:
        A list of custom filters.
    """
    custom_filters = super().get_custom_filters(table)

    from sqlmodel import and_

    from zenml.zen_stores.schemas import (
        CodeReferenceSchema,
        PipelineDeploymentSchema,
        PipelineSchema,
        RunTemplateSchema,
        StackSchema,
    )

    if self.code_repository_id:
        code_repo_filter = and_(
            RunTemplateSchema.source_deployment_id
            == PipelineDeploymentSchema.id,
            PipelineDeploymentSchema.code_reference_id
            == CodeReferenceSchema.id,
            CodeReferenceSchema.code_repository_id
            == self.code_repository_id,
        )
        custom_filters.append(code_repo_filter)

    if self.stack_id:
        stack_filter = and_(
            RunTemplateSchema.source_deployment_id
            == PipelineDeploymentSchema.id,
            PipelineDeploymentSchema.stack_id == self.stack_id,
        )
        custom_filters.append(stack_filter)

    if self.build_id:
        build_filter = and_(
            RunTemplateSchema.source_deployment_id
            == PipelineDeploymentSchema.id,
            PipelineDeploymentSchema.build_id == self.build_id,
        )
        custom_filters.append(build_filter)

    if self.pipeline_id:
        pipeline_filter = and_(
            RunTemplateSchema.source_deployment_id
            == PipelineDeploymentSchema.id,
            PipelineDeploymentSchema.pipeline_id == self.pipeline_id,
        )
        custom_filters.append(pipeline_filter)

    if self.pipeline:
        pipeline_filter = and_(
            RunTemplateSchema.source_deployment_id
            == PipelineDeploymentSchema.id,
            PipelineDeploymentSchema.pipeline_id == PipelineSchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.pipeline,
                table=PipelineSchema,
            ),
        )
        custom_filters.append(pipeline_filter)

    if self.stack:
        stack_filter = and_(
            RunTemplateSchema.source_deployment_id
            == PipelineDeploymentSchema.id,
            PipelineDeploymentSchema.stack_id == StackSchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.stack,
                table=StackSchema,
            ),
        )
        custom_filters.append(stack_filter)

    return custom_filters

RunTemplateRequest

Bases: WorkspaceScopedRequest

Request model for run templates.

Source code in src/zenml/models/v2/core/run_template.py
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
class RunTemplateRequest(WorkspaceScopedRequest):
    """Request model for run templates."""

    name: str = Field(
        title="The name of the run template.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    description: Optional[str] = Field(
        default=None,
        title="The description of the run template.",
        max_length=TEXT_FIELD_MAX_LENGTH,
    )
    source_deployment_id: UUID = Field(
        title="The deployment that should be the base of the created template."
    )
    tags: Optional[List[str]] = Field(
        default=None,
        title="Tags of the run template.",
    )

RunTemplateResponse

Bases: WorkspaceScopedResponse[RunTemplateResponseBody, RunTemplateResponseMetadata, RunTemplateResponseResources]

Response model for run templates.

Source code in src/zenml/models/v2/core/run_template.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
class RunTemplateResponse(
    WorkspaceScopedResponse[
        RunTemplateResponseBody,
        RunTemplateResponseMetadata,
        RunTemplateResponseResources,
    ]
):
    """Response model for run templates."""

    name: str = Field(
        title="The name of the run template.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "RunTemplateResponse":
        """Return the hydrated version of this run template.

        Returns:
            The hydrated run template.
        """
        from zenml.client import Client

        return Client().zen_store.get_run_template(
            template_id=self.id, hydrate=True
        )

    # Body and metadata properties
    @property
    def runnable(self) -> bool:
        """The `runnable` property.

        Returns:
            the value of the property.
        """
        return self.get_body().runnable

    @property
    def latest_run_id(self) -> Optional[UUID]:
        """The `latest_run_id` property.

        Returns:
            the value of the property.
        """
        return self.get_body().latest_run_id

    @property
    def latest_run_status(self) -> Optional[ExecutionStatus]:
        """The `latest_run_status` property.

        Returns:
            the value of the property.
        """
        return self.get_body().latest_run_status

    @property
    def description(self) -> Optional[str]:
        """The `description` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().description

    @property
    def pipeline_spec(self) -> Optional[PipelineSpec]:
        """The `pipeline_spec` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().pipeline_spec

    @property
    def config_template(self) -> Optional[Dict[str, Any]]:
        """The `config_template` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().config_template

    @property
    def config_schema(self) -> Optional[Dict[str, Any]]:
        """The `config_schema` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().config_schema

    @property
    def source_deployment(self) -> Optional[PipelineDeploymentResponse]:
        """The `source_deployment` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().source_deployment

    @property
    def pipeline(self) -> Optional[PipelineResponse]:
        """The `pipeline` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().pipeline

    @property
    def build(self) -> Optional[PipelineBuildResponse]:
        """The `build` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().build

    @property
    def code_reference(self) -> Optional[CodeReferenceResponse]:
        """The `code_reference` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().code_reference

    @property
    def tags(self) -> List[TagResponse]:
        """The `tags` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().tags

build property

The build property.

Returns:

Type Description
Optional[PipelineBuildResponse]

the value of the property.

code_reference property

The code_reference property.

Returns:

Type Description
Optional[CodeReferenceResponse]

the value of the property.

config_schema property

The config_schema property.

Returns:

Type Description
Optional[Dict[str, Any]]

the value of the property.

config_template property

The config_template property.

Returns:

Type Description
Optional[Dict[str, Any]]

the value of the property.

description property

The description property.

Returns:

Type Description
Optional[str]

the value of the property.

latest_run_id property

The latest_run_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

latest_run_status property

The latest_run_status property.

Returns:

Type Description
Optional[ExecutionStatus]

the value of the property.

pipeline property

The pipeline property.

Returns:

Type Description
Optional[PipelineResponse]

the value of the property.

pipeline_spec property

The pipeline_spec property.

Returns:

Type Description
Optional[PipelineSpec]

the value of the property.

runnable property

The runnable property.

Returns:

Type Description
bool

the value of the property.

source_deployment property

The source_deployment property.

Returns:

Type Description
Optional[PipelineDeploymentResponse]

the value of the property.

tags property

The tags property.

Returns:

Type Description
List[TagResponse]

the value of the property.

get_hydrated_version()

Return the hydrated version of this run template.

Returns:

Type Description
RunTemplateResponse

The hydrated run template.

Source code in src/zenml/models/v2/core/run_template.py
186
187
188
189
190
191
192
193
194
195
196
def get_hydrated_version(self) -> "RunTemplateResponse":
    """Return the hydrated version of this run template.

    Returns:
        The hydrated run template.
    """
    from zenml.client import Client

    return Client().zen_store.get_run_template(
        template_id=self.id, hydrate=True
    )

RunTemplateResponseBody

Bases: WorkspaceScopedResponseBody

Response body for run templates.

Source code in src/zenml/models/v2/core/run_template.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
class RunTemplateResponseBody(WorkspaceScopedResponseBody):
    """Response body for run templates."""

    runnable: bool = Field(
        title="If a run can be started from the template.",
    )
    latest_run_id: Optional[UUID] = Field(
        default=None,
        title="The ID of the latest run of the run template.",
    )
    latest_run_status: Optional[ExecutionStatus] = Field(
        default=None,
        title="The status of the latest run of the run template.",
    )

RunTemplateResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for run templates.

Source code in src/zenml/models/v2/core/run_template.py
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
class RunTemplateResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for run templates."""

    description: Optional[str] = Field(
        default=None,
        title="The description of the run template.",
    )
    pipeline_spec: Optional[PipelineSpec] = Field(
        default=None, title="The spec of the pipeline."
    )
    config_template: Optional[Dict[str, Any]] = Field(
        default=None, title="Run configuration template."
    )
    config_schema: Optional[Dict[str, Any]] = Field(
        default=None, title="Run configuration schema."
    )

RunTemplateResponseResources

Bases: WorkspaceScopedResponseResources

All resource models associated with the run template.

Source code in src/zenml/models/v2/core/run_template.py
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
class RunTemplateResponseResources(WorkspaceScopedResponseResources):
    """All resource models associated with the run template."""

    source_deployment: Optional[PipelineDeploymentResponse] = Field(
        default=None,
        title="The deployment that is the source of the template.",
    )
    pipeline: Optional[PipelineResponse] = Field(
        default=None, title="The pipeline associated with the template."
    )
    build: Optional[PipelineBuildResponse] = Field(
        default=None,
        title="The pipeline build associated with the template.",
    )
    code_reference: Optional[CodeReferenceResponse] = Field(
        default=None,
        title="The code reference associated with the template.",
    )
    tags: List[TagResponse] = Field(
        title="Tags associated with the run template.",
    )

RunTemplateUpdate

Bases: BaseUpdate

Run template update model.

Source code in src/zenml/models/v2/core/run_template.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
class RunTemplateUpdate(BaseUpdate):
    """Run template update model."""

    name: Optional[str] = Field(
        default=None,
        title="The name of the run template.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    description: Optional[str] = Field(
        default=None,
        title="The description of the run template.",
        max_length=TEXT_FIELD_MAX_LENGTH,
    )
    add_tags: Optional[List[str]] = Field(
        default=None, title="New tags to add to the run template."
    )
    remove_tags: Optional[List[str]] = Field(
        default=None, title="Tags to remove from the run template."
    )

ScheduleFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of all Users.

Source code in src/zenml/models/v2/core/schedule.py
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
class ScheduleFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of all Users."""

    pipeline_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Pipeline that the schedule is attached to.",
        union_mode="left_to_right",
    )
    orchestrator_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Orchestrator that the schedule is attached to.",
        union_mode="left_to_right",
    )
    active: Optional[bool] = Field(
        default=None,
        description="If the schedule is active",
    )
    cron_expression: Optional[str] = Field(
        default=None,
        description="The cron expression, describing the schedule",
    )
    start_time: Optional[Union[datetime, str]] = Field(
        default=None, description="Start time", union_mode="left_to_right"
    )
    end_time: Optional[Union[datetime, str]] = Field(
        default=None, description="End time", union_mode="left_to_right"
    )
    interval_second: Optional[Optional[float]] = Field(
        default=None,
        description="The repetition interval in seconds",
    )
    catchup: Optional[bool] = Field(
        default=None,
        description="Whether or not the schedule is set to catchup past missed "
        "events",
    )
    name: Optional[str] = Field(
        default=None,
        description="Name of the schedule",
    )
    run_once_start_time: Optional[Union[datetime, str]] = Field(
        default=None,
        description="The time at which the schedule should run once",
        union_mode="left_to_right",
    )

ScheduleRequest

Bases: WorkspaceScopedRequest

Request model for schedules.

Source code in src/zenml/models/v2/core/schedule.py
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
class ScheduleRequest(WorkspaceScopedRequest):
    """Request model for schedules."""

    name: str
    active: bool

    cron_expression: Optional[str] = None
    start_time: Optional[datetime] = None
    end_time: Optional[datetime] = None
    interval_second: Optional[timedelta] = None
    catchup: bool = False
    run_once_start_time: Optional[datetime] = None

    orchestrator_id: Optional[UUID]
    pipeline_id: Optional[UUID]

    @field_validator(
        "start_time", "end_time", "run_once_start_time", mode="after"
    )
    @classmethod
    def _ensure_tzunaware_utc(
        cls, value: Optional[datetime]
    ) -> Optional[datetime]:
        """Ensures that all datetimes are timezone unaware and in UTC time.

        Args:
            value: The datetime.

        Returns:
            The datetime in UTC time without timezone.
        """
        if value and value.tzinfo:
            value = value.astimezone(timezone.utc)
            value = value.replace(tzinfo=None)

        return value

    @model_validator(mode="after")
    def _ensure_cron_or_periodic_schedule_configured(
        self,
    ) -> "ScheduleRequest":
        """Ensures that the cron expression or start time + interval are set.

        Returns:
            All schedule attributes.

        Raises:
            ValueError: If no cron expression or start time + interval were
                provided.
        """
        cron_expression = self.cron_expression
        periodic_schedule = self.start_time and self.interval_second
        run_once_starts_at = self.run_once_start_time

        if cron_expression and periodic_schedule:
            logger.warning(
                "This schedule was created with a cron expression as well as "
                "values for `start_time` and `interval_seconds`. The resulting "
                "behavior depends on the concrete orchestrator implementation "
                "but will usually ignore the interval and use the cron "
                "expression."
            )
            return self
        elif cron_expression and run_once_starts_at:
            logger.warning(
                "This schedule was created with a cron expression as well as "
                "a value for `run_once_start_time`. The resulting behavior "
                "depends on the concrete orchestrator implementation but will "
                "usually ignore the `run_once_start_time`."
            )
            return self
        elif cron_expression or periodic_schedule or run_once_starts_at:
            return self
        else:
            raise ValueError(
                "Either a cron expression, a start time and interval seconds "
                "or a run once start time "
                "need to be set for a valid schedule."
            )

ScheduleResponse

Bases: WorkspaceScopedResponse[ScheduleResponseBody, ScheduleResponseMetadata, ScheduleResponseResources]

Response model for schedules.

Source code in src/zenml/models/v2/core/schedule.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
class ScheduleResponse(
    WorkspaceScopedResponse[
        ScheduleResponseBody,
        ScheduleResponseMetadata,
        ScheduleResponseResources,
    ],
):
    """Response model for schedules."""

    name: str = Field(
        title="Name of this schedule.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "ScheduleResponse":
        """Get the hydrated version of this schedule.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_schedule(self.id)

    # Helper methods
    @property
    def utc_start_time(self) -> Optional[str]:
        """Optional ISO-formatted string of the UTC start time.

        Returns:
            Optional ISO-formatted string of the UTC start time.
        """
        if not self.start_time:
            return None

        return to_utc_timezone(self.start_time).isoformat()

    @property
    def utc_end_time(self) -> Optional[str]:
        """Optional ISO-formatted string of the UTC end time.

        Returns:
            Optional ISO-formatted string of the UTC end time.
        """
        if not self.end_time:
            return None

        return to_utc_timezone(self.end_time).isoformat()

    # Body and metadata properties
    @property
    def active(self) -> bool:
        """The `active` property.

        Returns:
            the value of the property.
        """
        return self.get_body().active

    @property
    def cron_expression(self) -> Optional[str]:
        """The `cron_expression` property.

        Returns:
            the value of the property.
        """
        return self.get_body().cron_expression

    @property
    def start_time(self) -> Optional[datetime]:
        """The `start_time` property.

        Returns:
            the value of the property.
        """
        return self.get_body().start_time

    @property
    def end_time(self) -> Optional[datetime]:
        """The `end_time` property.

        Returns:
            the value of the property.
        """
        return self.get_body().end_time

    @property
    def run_once_start_time(self) -> Optional[datetime]:
        """The `run_once_start_time` property.

        Returns:
            the value of the property.
        """
        return self.get_body().run_once_start_time

    @property
    def interval_second(self) -> Optional[timedelta]:
        """The `interval_second` property.

        Returns:
            the value of the property.
        """
        return self.get_body().interval_second

    @property
    def catchup(self) -> bool:
        """The `catchup` property.

        Returns:
            the value of the property.
        """
        return self.get_body().catchup

    @property
    def orchestrator_id(self) -> Optional[UUID]:
        """The `orchestrator_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().orchestrator_id

    @property
    def pipeline_id(self) -> Optional[UUID]:
        """The `pipeline_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().pipeline_id

    @property
    def run_metadata(self) -> Dict[str, MetadataType]:
        """The `run_metadata` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().run_metadata

active property

The active property.

Returns:

Type Description
bool

the value of the property.

catchup property

The catchup property.

Returns:

Type Description
bool

the value of the property.

cron_expression property

The cron_expression property.

Returns:

Type Description
Optional[str]

the value of the property.

end_time property

The end_time property.

Returns:

Type Description
Optional[datetime]

the value of the property.

interval_second property

The interval_second property.

Returns:

Type Description
Optional[timedelta]

the value of the property.

orchestrator_id property

The orchestrator_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

pipeline_id property

The pipeline_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

run_metadata property

The run_metadata property.

Returns:

Type Description
Dict[str, MetadataType]

the value of the property.

run_once_start_time property

The run_once_start_time property.

Returns:

Type Description
Optional[datetime]

the value of the property.

start_time property

The start_time property.

Returns:

Type Description
Optional[datetime]

the value of the property.

utc_end_time property

Optional ISO-formatted string of the UTC end time.

Returns:

Type Description
Optional[str]

Optional ISO-formatted string of the UTC end time.

utc_start_time property

Optional ISO-formatted string of the UTC start time.

Returns:

Type Description
Optional[str]

Optional ISO-formatted string of the UTC start time.

get_hydrated_version()

Get the hydrated version of this schedule.

Returns:

Type Description
ScheduleResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/schedule.py
186
187
188
189
190
191
192
193
194
def get_hydrated_version(self) -> "ScheduleResponse":
    """Get the hydrated version of this schedule.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_schedule(self.id)

ScheduleResponseBody

Bases: WorkspaceScopedResponseBody

Response body for schedules.

Source code in src/zenml/models/v2/core/schedule.py
144
145
146
147
148
149
150
151
152
153
class ScheduleResponseBody(WorkspaceScopedResponseBody):
    """Response body for schedules."""

    active: bool
    cron_expression: Optional[str] = None
    start_time: Optional[datetime] = None
    end_time: Optional[datetime] = None
    interval_second: Optional[timedelta] = None
    catchup: bool = False
    run_once_start_time: Optional[datetime] = None

ScheduleResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for schedules.

Source code in src/zenml/models/v2/core/schedule.py
156
157
158
159
160
161
162
163
164
165
class ScheduleResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for schedules."""

    orchestrator_id: Optional[UUID]
    pipeline_id: Optional[UUID]

    run_metadata: Dict[str, MetadataType] = Field(
        title="Metadata associated with this schedule.",
        default={},
    )

ScheduleUpdate

Bases: BaseUpdate

Update model for schedules.

Source code in src/zenml/models/v2/core/schedule.py
126
127
128
129
130
131
132
133
134
135
136
137
138
class ScheduleUpdate(BaseUpdate):
    """Update model for schedules."""

    name: Optional[str] = None
    active: Optional[bool] = None
    cron_expression: Optional[str] = None
    start_time: Optional[datetime] = None
    end_time: Optional[datetime] = None
    interval_second: Optional[timedelta] = None
    catchup: Optional[bool] = None
    run_once_start_time: Optional[datetime] = None
    orchestrator_id: Optional[UUID] = None
    pipeline_id: Optional[UUID] = None

SecretFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of all Secrets.

Source code in src/zenml/models/v2/core/secret.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
class SecretFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of all Secrets."""

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
        "values",
    ]

    name: Optional[str] = Field(
        default=None,
        description="Name of the secret",
    )
    scope: Optional[Union[SecretScope, str]] = Field(
        default=None,
        description="Scope in which to filter secrets",
        union_mode="left_to_right",
    )

    @staticmethod
    def _get_filtering_value(value: Optional[Any]) -> str:
        """Convert the value to a string that can be used for lexicographical filtering and sorting.

        Args:
            value: The value to convert.

        Returns:
            The value converted to string format that can be used for
            lexicographical sorting and filtering.
        """
        if value is None:
            return ""
        str_value = str(value)
        if isinstance(value, datetime):
            str_value = value.strftime("%Y-%m-%d %H:%M:%S")
        return str_value

    def secret_matches(self, secret: SecretResponse) -> bool:
        """Checks if a secret matches the filter criteria.

        Args:
            secret: The secret to check.

        Returns:
            True if the secret matches the filter criteria, False otherwise.
        """
        for filter in self.list_of_filters:
            column_value: Optional[Any] = None
            if filter.column == "workspace_id":
                column_value = secret.workspace.id
            elif filter.column == "user_id":
                column_value = secret.user.id if secret.user else None
            else:
                column_value = getattr(secret, filter.column)

            # Convert the values to strings for lexicographical comparison.
            str_column_value = self._get_filtering_value(column_value)
            str_filter_value = self._get_filtering_value(filter.value)

            # Compare the lexicographical values according to the operation.
            if filter.operation == GenericFilterOps.EQUALS:
                result = str_column_value == str_filter_value
            elif filter.operation == GenericFilterOps.CONTAINS:
                result = str_filter_value in str_column_value
            elif filter.operation == GenericFilterOps.STARTSWITH:
                result = str_column_value.startswith(str_filter_value)
            elif filter.operation == GenericFilterOps.ENDSWITH:
                result = str_column_value.endswith(str_filter_value)
            elif filter.operation == GenericFilterOps.GT:
                result = str_column_value > str_filter_value
            elif filter.operation == GenericFilterOps.GTE:
                result = str_column_value >= str_filter_value
            elif filter.operation == GenericFilterOps.LT:
                result = str_column_value < str_filter_value
            elif filter.operation == GenericFilterOps.LTE:
                result = str_column_value <= str_filter_value

            # Exit early if the result is False for AND, and True for OR
            if self.logical_operator == LogicalOperators.AND:
                if not result:
                    return False
            else:
                if result:
                    return True

        # If we get here, all filters have been checked and the result is
        # True for AND, and False for OR
        if self.logical_operator == LogicalOperators.AND:
            return True
        else:
            return False

    def sort_secrets(
        self, secrets: List[SecretResponse]
    ) -> List[SecretResponse]:
        """Sorts a list of secrets according to the filter criteria.

        Args:
            secrets: The list of secrets to sort.

        Returns:
            The sorted list of secrets.
        """
        column, sort_op = self.sorting_params
        sorted_secrets = sorted(
            secrets,
            key=lambda secret: self._get_filtering_value(
                getattr(secret, column)
            ),
            reverse=sort_op == SorterOps.DESCENDING,
        )

        return sorted_secrets

secret_matches(secret)

Checks if a secret matches the filter criteria.

Parameters:

Name Type Description Default
secret SecretResponse

The secret to check.

required

Returns:

Type Description
bool

True if the secret matches the filter criteria, False otherwise.

Source code in src/zenml/models/v2/core/secret.py
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
def secret_matches(self, secret: SecretResponse) -> bool:
    """Checks if a secret matches the filter criteria.

    Args:
        secret: The secret to check.

    Returns:
        True if the secret matches the filter criteria, False otherwise.
    """
    for filter in self.list_of_filters:
        column_value: Optional[Any] = None
        if filter.column == "workspace_id":
            column_value = secret.workspace.id
        elif filter.column == "user_id":
            column_value = secret.user.id if secret.user else None
        else:
            column_value = getattr(secret, filter.column)

        # Convert the values to strings for lexicographical comparison.
        str_column_value = self._get_filtering_value(column_value)
        str_filter_value = self._get_filtering_value(filter.value)

        # Compare the lexicographical values according to the operation.
        if filter.operation == GenericFilterOps.EQUALS:
            result = str_column_value == str_filter_value
        elif filter.operation == GenericFilterOps.CONTAINS:
            result = str_filter_value in str_column_value
        elif filter.operation == GenericFilterOps.STARTSWITH:
            result = str_column_value.startswith(str_filter_value)
        elif filter.operation == GenericFilterOps.ENDSWITH:
            result = str_column_value.endswith(str_filter_value)
        elif filter.operation == GenericFilterOps.GT:
            result = str_column_value > str_filter_value
        elif filter.operation == GenericFilterOps.GTE:
            result = str_column_value >= str_filter_value
        elif filter.operation == GenericFilterOps.LT:
            result = str_column_value < str_filter_value
        elif filter.operation == GenericFilterOps.LTE:
            result = str_column_value <= str_filter_value

        # Exit early if the result is False for AND, and True for OR
        if self.logical_operator == LogicalOperators.AND:
            if not result:
                return False
        else:
            if result:
                return True

    # If we get here, all filters have been checked and the result is
    # True for AND, and False for OR
    if self.logical_operator == LogicalOperators.AND:
        return True
    else:
        return False

sort_secrets(secrets)

Sorts a list of secrets according to the filter criteria.

Parameters:

Name Type Description Default
secrets List[SecretResponse]

The list of secrets to sort.

required

Returns:

Type Description
List[SecretResponse]

The sorted list of secrets.

Source code in src/zenml/models/v2/core/secret.py
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
def sort_secrets(
    self, secrets: List[SecretResponse]
) -> List[SecretResponse]:
    """Sorts a list of secrets according to the filter criteria.

    Args:
        secrets: The list of secrets to sort.

    Returns:
        The sorted list of secrets.
    """
    column, sort_op = self.sorting_params
    sorted_secrets = sorted(
        secrets,
        key=lambda secret: self._get_filtering_value(
            getattr(secret, column)
        ),
        reverse=sort_op == SorterOps.DESCENDING,
    )

    return sorted_secrets

SecretRequest

Bases: WorkspaceScopedRequest

Request models for secrets.

Source code in src/zenml/models/v2/core/secret.py
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
class SecretRequest(WorkspaceScopedRequest):
    """Request models for secrets."""

    ANALYTICS_FIELDS: ClassVar[List[str]] = ["scope"]

    name: str = Field(
        title="The name of the secret.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    scope: SecretScope = Field(
        SecretScope.WORKSPACE, title="The scope of the secret."
    )
    values: Dict[str, Optional[PlainSerializedSecretStr]] = Field(
        default_factory=dict, title="The values stored in this secret."
    )

    @property
    def secret_values(self) -> Dict[str, str]:
        """A dictionary with all un-obfuscated values stored in this secret.

        The values are returned as strings, not SecretStr. If a value is
        None, it is not included in the returned dictionary. This is to enable
        the use of None values in the update model to indicate that a secret
        value should be deleted.

        Returns:
            A dictionary containing the secret's values.
        """
        return {
            k: v.get_secret_value()
            for k, v in self.values.items()
            if v is not None
        }

secret_values property

A dictionary with all un-obfuscated values stored in this secret.

The values are returned as strings, not SecretStr. If a value is None, it is not included in the returned dictionary. This is to enable the use of None values in the update model to indicate that a secret value should be deleted.

Returns:

Type Description
Dict[str, str]

A dictionary containing the secret's values.

SecretResponse

Bases: WorkspaceScopedResponse[SecretResponseBody, SecretResponseMetadata, SecretResponseResources]

Response model for secrets.

Source code in src/zenml/models/v2/core/secret.py
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
class SecretResponse(
    WorkspaceScopedResponse[
        SecretResponseBody, SecretResponseMetadata, SecretResponseResources
    ]
):
    """Response model for secrets."""

    ANALYTICS_FIELDS: ClassVar[List[str]] = ["scope"]

    name: str = Field(
        title="The name of the secret.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "SecretResponse":
        """Get the hydrated version of this workspace.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_secret(self.id)

    # Body and metadata properties

    @property
    def scope(self) -> SecretScope:
        """The `scope` property.

        Returns:
            the value of the property.
        """
        return self.get_body().scope

    @property
    def values(self) -> Dict[str, Optional[SecretStr]]:
        """The `values` property.

        Returns:
            the value of the property.
        """
        return self.get_body().values

    # Helper methods
    @property
    def secret_values(self) -> Dict[str, str]:
        """A dictionary with all un-obfuscated values stored in this secret.

        The values are returned as strings, not SecretStr. If a value is
        None, it is not included in the returned dictionary. This is to enable
        the use of None values in the update model to indicate that a secret
        value should be deleted.

        Returns:
            A dictionary containing the secret's values.
        """
        return {
            k: v.get_secret_value()
            for k, v in self.values.items()
            if v is not None
        }

    @property
    def has_missing_values(self) -> bool:
        """Returns True if the secret has missing values (i.e. None).

        Values can be missing from a secret for example if the user retrieves a
        secret but does not have the permission to view the secret values.

        Returns:
            True if the secret has any values set to None.
        """
        return any(v is None for v in self.values.values())

    def add_secret(self, key: str, value: str) -> None:
        """Adds a secret value to the secret.

        Args:
            key: The key of the secret value.
            value: The secret value.
        """
        self.get_body().values[key] = SecretStr(value)

    def remove_secret(self, key: str) -> None:
        """Removes a secret value from the secret.

        Args:
            key: The key of the secret value.
        """
        del self.get_body().values[key]

    def remove_secrets(self) -> None:
        """Removes all secret values from the secret but keep the keys."""
        self.get_body().values = {k: None for k in self.values.keys()}

    def set_secrets(self, values: Dict[str, str]) -> None:
        """Sets the secret values of the secret.

        Args:
            values: The secret values to set.
        """
        self.get_body().values = {k: SecretStr(v) for k, v in values.items()}

has_missing_values property

Returns True if the secret has missing values (i.e. None).

Values can be missing from a secret for example if the user retrieves a secret but does not have the permission to view the secret values.

Returns:

Type Description
bool

True if the secret has any values set to None.

scope property

The scope property.

Returns:

Type Description
SecretScope

the value of the property.

secret_values property

A dictionary with all un-obfuscated values stored in this secret.

The values are returned as strings, not SecretStr. If a value is None, it is not included in the returned dictionary. This is to enable the use of None values in the update model to indicate that a secret value should be deleted.

Returns:

Type Description
Dict[str, str]

A dictionary containing the secret's values.

values property

The values property.

Returns:

Type Description
Dict[str, Optional[SecretStr]]

the value of the property.

add_secret(key, value)

Adds a secret value to the secret.

Parameters:

Name Type Description Default
key str

The key of the secret value.

required
value str

The secret value.

required
Source code in src/zenml/models/v2/core/secret.py
210
211
212
213
214
215
216
217
def add_secret(self, key: str, value: str) -> None:
    """Adds a secret value to the secret.

    Args:
        key: The key of the secret value.
        value: The secret value.
    """
    self.get_body().values[key] = SecretStr(value)

get_hydrated_version()

Get the hydrated version of this workspace.

Returns:

Type Description
SecretResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/secret.py
149
150
151
152
153
154
155
156
157
def get_hydrated_version(self) -> "SecretResponse":
    """Get the hydrated version of this workspace.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_secret(self.id)

remove_secret(key)

Removes a secret value from the secret.

Parameters:

Name Type Description Default
key str

The key of the secret value.

required
Source code in src/zenml/models/v2/core/secret.py
219
220
221
222
223
224
225
def remove_secret(self, key: str) -> None:
    """Removes a secret value from the secret.

    Args:
        key: The key of the secret value.
    """
    del self.get_body().values[key]

remove_secrets()

Removes all secret values from the secret but keep the keys.

Source code in src/zenml/models/v2/core/secret.py
227
228
229
def remove_secrets(self) -> None:
    """Removes all secret values from the secret but keep the keys."""
    self.get_body().values = {k: None for k in self.values.keys()}

set_secrets(values)

Sets the secret values of the secret.

Parameters:

Name Type Description Default
values Dict[str, str]

The secret values to set.

required
Source code in src/zenml/models/v2/core/secret.py
231
232
233
234
235
236
237
def set_secrets(self, values: Dict[str, str]) -> None:
    """Sets the secret values of the secret.

    Args:
        values: The secret values to set.
    """
    self.get_body().values = {k: SecretStr(v) for k, v in values.items()}

SecretResponseBody

Bases: WorkspaceScopedResponseBody

Response body for secrets.

Source code in src/zenml/models/v2/core/secret.py
116
117
118
119
120
121
122
123
124
class SecretResponseBody(WorkspaceScopedResponseBody):
    """Response body for secrets."""

    scope: SecretScope = Field(
        SecretScope.WORKSPACE, title="The scope of the secret."
    )
    values: Dict[str, Optional[PlainSerializedSecretStr]] = Field(
        default_factory=dict, title="The values stored in this secret."
    )

SecretResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for secrets.

Source code in src/zenml/models/v2/core/secret.py
127
128
class SecretResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for secrets."""

SecretUpdate

Bases: BaseUpdate

Secret update model.

Source code in src/zenml/models/v2/core/secret.py
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
class SecretUpdate(BaseUpdate):
    """Secret update model."""

    ANALYTICS_FIELDS: ClassVar[List[str]] = ["scope"]

    name: Optional[str] = Field(
        title="The name of the secret.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    scope: Optional[SecretScope] = Field(
        default=None, title="The scope of the secret."
    )
    values: Optional[Dict[str, Optional[PlainSerializedSecretStr]]] = Field(
        title="The values stored in this secret.",
        default=None,
    )

    def get_secret_values_update(self) -> Dict[str, Optional[str]]:
        """Returns a dictionary with the secret values to update.

        Returns:
            A dictionary with the secret values to update.
        """
        if self.values is not None:
            return {
                k: v.get_secret_value() if v is not None else None
                for k, v in self.values.items()
            }

        return {}

get_secret_values_update()

Returns a dictionary with the secret values to update.

Returns:

Type Description
Dict[str, Optional[str]]

A dictionary with the secret values to update.

Source code in src/zenml/models/v2/core/secret.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
def get_secret_values_update(self) -> Dict[str, Optional[str]]:
    """Returns a dictionary with the secret values to update.

    Returns:
        A dictionary with the secret values to update.
    """
    if self.values is not None:
        return {
            k: v.get_secret_value() if v is not None else None
            for k, v in self.values.items()
        }

    return {}

ServerActivationRequest

Bases: ServerSettingsUpdate

Model for activating the server.

Source code in src/zenml/models/v2/core/server_settings.py
211
212
213
214
215
216
217
218
219
220
221
222
223
224
class ServerActivationRequest(ServerSettingsUpdate):
    """Model for activating the server."""

    admin_username: Optional[str] = Field(
        default=None,
        title="The username of the default admin account to create. Leave "
        "empty to skip creating the default admin account.",
    )

    admin_password: Optional[str] = Field(
        default=None,
        title="The password of the default admin account to create. Leave "
        "empty to skip creating the default admin account.",
    )

ServerDatabaseType

Bases: StrEnum

Enum for server database types.

Source code in src/zenml/models/v2/misc/server_models.py
42
43
44
45
46
47
class ServerDatabaseType(StrEnum):
    """Enum for server database types."""

    SQLITE = "sqlite"
    MYSQL = "mysql"
    OTHER = "other"

ServerDeploymentType

Bases: StrEnum

Enum for server deployment types.

Source code in src/zenml/models/v2/misc/server_models.py
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class ServerDeploymentType(StrEnum):
    """Enum for server deployment types."""

    LOCAL = "local"
    DOCKER = "docker"
    KUBERNETES = "kubernetes"
    AWS = "aws"
    GCP = "gcp"
    AZURE = "azure"
    ALPHA = "alpha"
    OTHER = "other"
    HF_SPACES = "hf_spaces"
    SANDBOX = "sandbox"
    CLOUD = "cloud"

ServerLoadInfo

Bases: BaseModel

Domain model for ZenML server load information.

Source code in src/zenml/models/v2/misc/server_models.py
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
class ServerLoadInfo(BaseModel):
    """Domain model for ZenML server load information."""

    threads: int = Field(
        title="Number of threads that the server is currently using."
    )

    db_connections_total: int = Field(
        title="Total number of database connections (active and idle) that the "
        "server currently has established."
    )

    db_connections_active: int = Field(
        title="Number of database connections that the server is currently "
        "actively using to make queries or transactions."
    )

    db_connections_overflow: int = Field(
        title="Number of overflow database connections that the server is "
        "currently actively using to make queries or transactions."
    )

ServerModel

Bases: BaseModel

Domain model for ZenML servers.

Source code in src/zenml/models/v2/misc/server_models.py
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
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
class ServerModel(BaseModel):
    """Domain model for ZenML servers."""

    id: UUID = Field(default_factory=uuid4, title="The unique server id.")

    name: Optional[str] = Field(None, title="The name of the ZenML server.")

    version: str = Field(
        title="The ZenML version that the server is running.",
    )

    active: bool = Field(
        True, title="Flag to indicate whether the server is active."
    )

    debug: bool = Field(
        False, title="Flag to indicate whether ZenML is running on debug mode."
    )

    deployment_type: ServerDeploymentType = Field(
        ServerDeploymentType.OTHER,
        title="The ZenML server deployment type.",
    )
    database_type: ServerDatabaseType = Field(
        ServerDatabaseType.OTHER,
        title="The database type that the server is using.",
    )
    secrets_store_type: SecretsStoreType = Field(
        SecretsStoreType.NONE,
        title="The type of secrets store that the server is using.",
    )
    auth_scheme: AuthScheme = Field(
        title="The authentication scheme that the server is using.",
    )
    server_url: str = Field(
        "",
        title="The URL where the ZenML server API is reachable. If not "
        "specified, the clients will use the same URL used to connect them to "
        "the ZenML server.",
    )
    dashboard_url: str = Field(
        "",
        title="The URL where the ZenML dashboard is reachable. If "
        "not specified, the `server_url` value will be used instead.",
    )
    analytics_enabled: bool = Field(
        default=True,  # We set a default for migrations from < 0.57.0
        title="Enable server-side analytics.",
    )

    metadata: Dict[str, str] = Field(
        {},
        title="The metadata associated with the server.",
    )

    last_user_activity: Optional[datetime] = Field(
        None,
        title="Timestamp of latest user activity traced on the server.",
    )

    pro_dashboard_url: Optional[str] = Field(
        None,
        title="The base URL of the ZenML Pro dashboard to which the server "
        "is connected. Only set if the server is a ZenML Pro server.",
    )

    pro_api_url: Optional[str] = Field(
        None,
        title="The base URL of the ZenML Pro API to which the server is "
        "connected. Only set if the server is a ZenML Pro server.",
    )

    pro_organization_id: Optional[UUID] = Field(
        None,
        title="The ID of the ZenML Pro organization to which the server is "
        "connected. Only set if the server is a ZenML Pro server.",
    )

    pro_organization_name: Optional[str] = Field(
        None,
        title="The name of the ZenML Pro organization to which the server is "
        "connected. Only set if the server is a ZenML Pro server.",
    )

    pro_tenant_id: Optional[UUID] = Field(
        None,
        title="The ID of the ZenML Pro tenant to which the server is connected. "
        "Only set if the server is a ZenML Pro server.",
    )

    pro_tenant_name: Optional[str] = Field(
        None,
        title="The name of the ZenML Pro tenant to which the server is connected. "
        "Only set if the server is a ZenML Pro server.",
    )

    def is_local(self) -> bool:
        """Return whether the server is running locally.

        Returns:
            True if the server is running locally, False otherwise.
        """
        from zenml.config.global_config import GlobalConfiguration

        # Local ZenML servers are identifiable by the fact that their
        # server ID is the same as the local client (user) ID.
        return self.id == GlobalConfiguration().user_id

    def is_pro_server(self) -> bool:
        """Return whether the server is a ZenML Pro server.

        Returns:
            True if the server is a ZenML Pro server, False otherwise.
        """
        return self.deployment_type == ServerDeploymentType.CLOUD

is_local()

Return whether the server is running locally.

Returns:

Type Description
bool

True if the server is running locally, False otherwise.

Source code in src/zenml/models/v2/misc/server_models.py
146
147
148
149
150
151
152
153
154
155
156
def is_local(self) -> bool:
    """Return whether the server is running locally.

    Returns:
        True if the server is running locally, False otherwise.
    """
    from zenml.config.global_config import GlobalConfiguration

    # Local ZenML servers are identifiable by the fact that their
    # server ID is the same as the local client (user) ID.
    return self.id == GlobalConfiguration().user_id

is_pro_server()

Return whether the server is a ZenML Pro server.

Returns:

Type Description
bool

True if the server is a ZenML Pro server, False otherwise.

Source code in src/zenml/models/v2/misc/server_models.py
158
159
160
161
162
163
164
def is_pro_server(self) -> bool:
    """Return whether the server is a ZenML Pro server.

    Returns:
        True if the server is a ZenML Pro server, False otherwise.
    """
    return self.deployment_type == ServerDeploymentType.CLOUD

ServerSettingsResponse

Bases: BaseResponse[ServerSettingsResponseBody, ServerSettingsResponseMetadata, ServerSettingsResponseResources]

Response model for server settings.

Source code in src/zenml/models/v2/core/server_settings.py
101
102
103
104
105
106
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
class ServerSettingsResponse(
    BaseResponse[
        ServerSettingsResponseBody,
        ServerSettingsResponseMetadata,
        ServerSettingsResponseResources,
    ]
):
    """Response model for server settings."""

    def get_hydrated_version(self) -> "ServerSettingsResponse":
        """Get the hydrated version of the server settings.

        Returns:
            An instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_server_settings(hydrate=True)

    # Body and metadata properties

    @property
    def server_id(self) -> UUID:
        """The `server_id` property.

        Returns:
            the value of the property.
        """
        return self.get_body().server_id

    @property
    def server_name(self) -> str:
        """The `server_name` property.

        Returns:
            the value of the property.
        """
        return self.get_body().server_name

    @property
    def logo_url(self) -> Optional[str]:
        """The `logo_url` property.

        Returns:
            the value of the property.
        """
        return self.get_body().logo_url

    @property
    def enable_analytics(self) -> bool:
        """The `enable_analytics` property.

        Returns:
            the value of the property.
        """
        return self.get_body().enable_analytics

    @property
    def display_announcements(self) -> Optional[bool]:
        """The `display_announcements` property.

        Returns:
            the value of the property.
        """
        return self.get_body().display_announcements

    @property
    def display_updates(self) -> Optional[bool]:
        """The `display_updates` property.

        Returns:
            the value of the property.
        """
        return self.get_body().display_updates

    @property
    def active(self) -> bool:
        """The `active` property.

        Returns:
            the value of the property.
        """
        return self.get_body().active

    @property
    def last_user_activity(self) -> datetime:
        """The `last_user_activity` property.

        Returns:
            the value of the property.
        """
        return self.get_body().last_user_activity

    @property
    def updated(self) -> datetime:
        """The `updated` property.

        Returns:
            the value of the property.
        """
        return self.get_body().updated

active property

The active property.

Returns:

Type Description
bool

the value of the property.

display_announcements property

The display_announcements property.

Returns:

Type Description
Optional[bool]

the value of the property.

display_updates property

The display_updates property.

Returns:

Type Description
Optional[bool]

the value of the property.

enable_analytics property

The enable_analytics property.

Returns:

Type Description
bool

the value of the property.

last_user_activity property

The last_user_activity property.

Returns:

Type Description
datetime

the value of the property.

logo_url property

The logo_url property.

Returns:

Type Description
Optional[str]

the value of the property.

server_id property

The server_id property.

Returns:

Type Description
UUID

the value of the property.

server_name property

The server_name property.

Returns:

Type Description
str

the value of the property.

updated property

The updated property.

Returns:

Type Description
datetime

the value of the property.

get_hydrated_version()

Get the hydrated version of the server settings.

Returns:

Type Description
ServerSettingsResponse

An instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/server_settings.py
110
111
112
113
114
115
116
117
118
def get_hydrated_version(self) -> "ServerSettingsResponse":
    """Get the hydrated version of the server settings.

    Returns:
        An instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_server_settings(hydrate=True)

ServerSettingsResponseBody

Bases: BaseResponseBody

Response body for server settings.

Source code in src/zenml/models/v2/core/server_settings.py
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
class ServerSettingsResponseBody(BaseResponseBody):
    """Response body for server settings."""

    server_id: UUID = Field(
        title="The unique server id.",
    )
    server_name: str = Field(title="The name of the server.")
    logo_url: Optional[str] = Field(
        default=None, title="The logo URL of the server."
    )
    active: bool = Field(
        title="Whether the server has been activated or not.",
    )
    enable_analytics: bool = Field(
        title="Whether analytics are enabled for the server.",
    )
    display_announcements: Optional[bool] = Field(
        title="Whether to display announcements about ZenML in the dashboard.",
    )
    display_updates: Optional[bool] = Field(
        title="Whether to display notifications about ZenML updates in the dashboard.",
    )
    last_user_activity: datetime = Field(
        title="The timestamp when the last user activity was detected.",
    )
    updated: datetime = Field(
        title="The timestamp when this resource was last updated."
    )

ServerSettingsResponseMetadata

Bases: BaseResponseMetadata

Response metadata for server settings.

Source code in src/zenml/models/v2/core/server_settings.py
93
94
class ServerSettingsResponseMetadata(BaseResponseMetadata):
    """Response metadata for server settings."""

ServerSettingsResponseResources

Bases: BaseResponseResources

Response resources for server settings.

Source code in src/zenml/models/v2/core/server_settings.py
97
98
class ServerSettingsResponseResources(BaseResponseResources):
    """Response resources for server settings."""

ServerSettingsUpdate

Bases: BaseZenModel

Model for updating server settings.

Source code in src/zenml/models/v2/core/server_settings.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class ServerSettingsUpdate(BaseZenModel):
    """Model for updating server settings."""

    server_name: Optional[str] = Field(
        default=None, title="The name of the server."
    )
    logo_url: Optional[str] = Field(
        default=None, title="The logo URL of the server."
    )
    enable_analytics: Optional[bool] = Field(
        default=None,
        title="Whether to enable analytics for the server.",
    )
    display_announcements: Optional[bool] = Field(
        default=None,
        title="Whether to display announcements about ZenML in the dashboard.",
    )
    display_updates: Optional[bool] = Field(
        default=None,
        title="Whether to display notifications about ZenML updates in the dashboard.",
    )

ServiceAccountFilter

Bases: BaseFilter

Model to enable advanced filtering of service accounts.

Source code in src/zenml/models/v2/core/service_account.py
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
class ServiceAccountFilter(BaseFilter):
    """Model to enable advanced filtering of service accounts."""

    name: Optional[str] = Field(
        default=None,
        description="Name of the user",
    )
    description: Optional[str] = Field(
        default=None,
        title="Filter by the service account description.",
    )
    active: Optional[Union[bool, str]] = Field(
        default=None,
        description="Whether the user is active",
        union_mode="left_to_right",
    )

    def apply_filter(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Override to filter out user accounts from the query.

        Args:
            query: The query to which to apply the filter.
            table: The query table.

        Returns:
            The query with filter applied.
        """
        query = super().apply_filter(query=query, table=table)
        query = query.where(
            getattr(table, "is_service_account") == True  # noqa: E712
        )

        return query

apply_filter(query, table)

Override to filter out user accounts from the query.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the filter.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with filter applied.

Source code in src/zenml/models/v2/core/service_account.py
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
def apply_filter(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Override to filter out user accounts from the query.

    Args:
        query: The query to which to apply the filter.
        table: The query table.

    Returns:
        The query with filter applied.
    """
    query = super().apply_filter(query=query, table=table)
    query = query.where(
        getattr(table, "is_service_account") == True  # noqa: E712
    )

    return query

ServiceAccountRequest

Bases: BaseRequest

Request model for service accounts.

Source code in src/zenml/models/v2/core/service_account.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class ServiceAccountRequest(BaseRequest):
    """Request model for service accounts."""

    ANALYTICS_FIELDS: ClassVar[List[str]] = [
        "name",
        "active",
    ]

    name: str = Field(
        title="The unique name for the service account.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    description: Optional[str] = Field(
        default=None,
        title="A description of the service account.",
        max_length=TEXT_FIELD_MAX_LENGTH,
    )
    active: bool = Field(title="Whether the service account is active or not.")
    model_config = ConfigDict(validate_assignment=True, extra="ignore")

ServiceAccountResponse

Bases: BaseIdentifiedResponse[ServiceAccountResponseBody, ServiceAccountResponseMetadata, ServiceAccountResponseResources]

Response model for service accounts.

Source code in src/zenml/models/v2/core/service_account.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
class ServiceAccountResponse(
    BaseIdentifiedResponse[
        ServiceAccountResponseBody,
        ServiceAccountResponseMetadata,
        ServiceAccountResponseResources,
    ]
):
    """Response model for service accounts."""

    ANALYTICS_FIELDS: ClassVar[List[str]] = [
        "name",
        "active",
    ]

    name: str = Field(
        title="The unique username for the account.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "ServiceAccountResponse":
        """Get the hydrated version of this service account.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_service_account(self.id)

    def to_user_model(self) -> "UserResponse":
        """Converts the service account to a user model.

        For now, a lot of code still relies on the active user and resource
        owners being a UserResponse object, which is a superset of the
        ServiceAccountResponse object. We need this method to convert the
        service account to a user.

        Returns:
            The user model.
        """
        from zenml.models.v2.core.user import (
            UserResponse,
            UserResponseBody,
            UserResponseMetadata,
        )

        return UserResponse(
            id=self.id,
            name=self.name,
            body=UserResponseBody(
                active=self.active,
                is_service_account=True,
                email_opted_in=False,
                created=self.created,
                updated=self.updated,
                is_admin=False,
            ),
            metadata=UserResponseMetadata(
                description=self.description,
            ),
        )

    # Body and metadata properties
    @property
    def active(self) -> bool:
        """The `active` property.

        Returns:
            the value of the property.
        """
        return self.get_body().active

    @property
    def description(self) -> str:
        """The `description` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().description

active property

The active property.

Returns:

Type Description
bool

the value of the property.

description property

The description property.

Returns:

Type Description
str

the value of the property.

get_hydrated_version()

Get the hydrated version of this service account.

Returns:

Type Description
ServiceAccountResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/service_account.py
126
127
128
129
130
131
132
133
134
def get_hydrated_version(self) -> "ServiceAccountResponse":
    """Get the hydrated version of this service account.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_service_account(self.id)

to_user_model()

Converts the service account to a user model.

For now, a lot of code still relies on the active user and resource owners being a UserResponse object, which is a superset of the ServiceAccountResponse object. We need this method to convert the service account to a user.

Returns:

Type Description
UserResponse

The user model.

Source code in src/zenml/models/v2/core/service_account.py
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
def to_user_model(self) -> "UserResponse":
    """Converts the service account to a user model.

    For now, a lot of code still relies on the active user and resource
    owners being a UserResponse object, which is a superset of the
    ServiceAccountResponse object. We need this method to convert the
    service account to a user.

    Returns:
        The user model.
    """
    from zenml.models.v2.core.user import (
        UserResponse,
        UserResponseBody,
        UserResponseMetadata,
    )

    return UserResponse(
        id=self.id,
        name=self.name,
        body=UserResponseBody(
            active=self.active,
            is_service_account=True,
            email_opted_in=False,
            created=self.created,
            updated=self.updated,
            is_admin=False,
        ),
        metadata=UserResponseMetadata(
            description=self.description,
        ),
    )

ServiceAccountResponseBody

Bases: BaseDatedResponseBody

Response body for service accounts.

Source code in src/zenml/models/v2/core/service_account.py
87
88
89
90
class ServiceAccountResponseBody(BaseDatedResponseBody):
    """Response body for service accounts."""

    active: bool = Field(default=False, title="Whether the account is active.")

ServiceAccountResponseMetadata

Bases: BaseResponseMetadata

Response metadata for service accounts.

Source code in src/zenml/models/v2/core/service_account.py
 93
 94
 95
 96
 97
 98
 99
100
class ServiceAccountResponseMetadata(BaseResponseMetadata):
    """Response metadata for service accounts."""

    description: str = Field(
        default="",
        title="A description of the service account.",
        max_length=TEXT_FIELD_MAX_LENGTH,
    )

ServiceAccountUpdate

Bases: BaseUpdate

Update model for service accounts.

Source code in src/zenml/models/v2/core/service_account.py
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class ServiceAccountUpdate(BaseUpdate):
    """Update model for service accounts."""

    ANALYTICS_FIELDS: ClassVar[List[str]] = ["name", "active"]

    name: Optional[str] = Field(
        title="The unique name for the service account.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    description: Optional[str] = Field(
        title="A description of the service account.",
        max_length=TEXT_FIELD_MAX_LENGTH,
        default=None,
    )
    active: Optional[bool] = Field(
        title="Whether the service account is active or not.",
        default=None,
    )

    model_config = ConfigDict(validate_assignment=True)

ServiceConnectorFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of service connectors.

Source code in src/zenml/models/v2/core/service_connector.py
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
class ServiceConnectorFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of service connectors."""

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
        "scope_type",
        "resource_type",
        "labels_str",
        "labels",
    ]
    CLI_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.CLI_EXCLUDE_FIELDS,
        "scope_type",
        "labels_str",
        "labels",
    ]
    scope_type: Optional[str] = Field(
        default=None,
        description="The type to scope this query to.",
    )
    name: Optional[str] = Field(
        default=None,
        description="The name to filter by",
    )
    connector_type: Optional[str] = Field(
        default=None,
        description="The type of service connector to filter by",
    )
    auth_method: Optional[str] = Field(
        default=None,
        title="Filter by the authentication method configured for the "
        "connector",
    )
    resource_type: Optional[str] = Field(
        default=None,
        title="Filter by the type of resource that the connector can be used "
        "to access",
    )
    resource_id: Optional[str] = Field(
        default=None,
        title="Filter by the ID of the resource instance that the connector "
        "is configured to access",
    )
    labels_str: Optional[str] = Field(
        default=None,
        title="Filter by one or more labels. This field can be either a JSON "
        "formatted dictionary of label names and values, where the values are "
        'optional and can be set to None (e.g. `{"label1":"value1", "label2": '
        "null}` ), or a comma-separated list of label names and values (e.g "
        "`label1=value1,label2=`. If a label name is specified without a "
        "value, the filter will match all service connectors that have that "
        "label present, regardless of value.",
    )
    secret_id: Optional[Union[UUID, str]] = Field(
        default=None,
        title="Filter by the ID of the secret that contains the service "
        "connector's credentials",
        union_mode="left_to_right",
    )

    # Use this internally to configure and access the labels as a dictionary
    labels: Optional[Dict[str, Optional[str]]] = Field(
        default=None,
        title="The labels to filter by, as a dictionary",
        exclude=True,
    )

    @model_validator(mode="after")
    def validate_labels(self) -> "ServiceConnectorFilter":
        """Parse the labels string into a label dictionary and vice-versa.

        Returns:
            The validated values.
        """
        if self.labels_str is not None:
            try:
                self.labels = json.loads(self.labels_str)
            except json.JSONDecodeError:
                # Interpret as comma-separated values instead
                self.labels = {
                    label.split("=", 1)[0]: label.split("=", 1)[1]
                    if "=" in label
                    else None
                    for label in self.labels_str.split(",")
                }
        elif self.labels is not None:
            self.labels_str = json.dumps(self.labels)

        return self

validate_labels()

Parse the labels string into a label dictionary and vice-versa.

Returns:

Type Description
ServiceConnectorFilter

The validated values.

Source code in src/zenml/models/v2/core/service_connector.py
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
@model_validator(mode="after")
def validate_labels(self) -> "ServiceConnectorFilter":
    """Parse the labels string into a label dictionary and vice-versa.

    Returns:
        The validated values.
    """
    if self.labels_str is not None:
        try:
            self.labels = json.loads(self.labels_str)
        except json.JSONDecodeError:
            # Interpret as comma-separated values instead
            self.labels = {
                label.split("=", 1)[0]: label.split("=", 1)[1]
                if "=" in label
                else None
                for label in self.labels_str.split(",")
            }
    elif self.labels is not None:
        self.labels_str = json.dumps(self.labels)

    return self

ServiceConnectorInfo

Bases: BaseModel

Information about the service connector when creating a full stack.

Source code in src/zenml/models/v2/misc/info_models.py
26
27
28
29
30
31
class ServiceConnectorInfo(BaseModel):
    """Information about the service connector when creating a full stack."""

    type: str
    auth_method: str
    configuration: Dict[str, Any] = {}

ServiceConnectorRequest

Bases: WorkspaceScopedRequest

Request model for service connectors.

Source code in src/zenml/models/v2/core/service_connector.py
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
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
class ServiceConnectorRequest(WorkspaceScopedRequest):
    """Request model for service connectors."""

    name: str = Field(
        title="The service connector name.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    connector_type: Union[str, "ServiceConnectorTypeModel"] = Field(
        title="The type of service connector.",
        union_mode="left_to_right",
    )
    description: str = Field(
        default="",
        title="The service connector instance description.",
    )
    auth_method: str = Field(
        title="The authentication method that the connector instance uses to "
        "access the resources.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    resource_types: List[str] = Field(
        default_factory=list,
        title="The type(s) of resource that the connector instance can be used "
        "to gain access to.",
    )
    resource_id: Optional[str] = Field(
        default=None,
        title="Uniquely identifies a specific resource instance that the "
        "connector instance can be used to access. If omitted, the connector "
        "instance can be used to access any and all resource instances that "
        "the authentication method and resource type(s) allow.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    supports_instances: bool = Field(
        default=False,
        title="Indicates whether the connector instance can be used to access "
        "multiple instances of the configured resource type.",
    )
    expires_at: Optional[datetime] = Field(
        default=None,
        title="Time when the authentication credentials configured for the "
        "connector expire. If omitted, the credentials do not expire.",
    )
    expires_skew_tolerance: Optional[int] = Field(
        default=None,
        title="The number of seconds of tolerance to apply when checking "
        "whether the authentication credentials configured for the connector "
        "have expired. If omitted, no tolerance is applied.",
    )
    expiration_seconds: Optional[int] = Field(
        default=None,
        title="The duration, in seconds, that the temporary credentials "
        "generated by this connector should remain valid. Only applicable for "
        "connectors and authentication methods that involve generating "
        "temporary credentials from the ones configured in the connector.",
    )
    configuration: Dict[str, Any] = Field(
        default_factory=dict,
        title="The service connector configuration, not including secrets.",
    )
    secrets: Dict[str, Optional[PlainSerializedSecretStr]] = Field(
        default_factory=dict,
        title="The service connector secrets.",
    )
    labels: Dict[str, str] = Field(
        default_factory=dict,
        title="Service connector labels.",
    )

    # Analytics
    ANALYTICS_FIELDS: ClassVar[List[str]] = [
        "connector_type",
        "auth_method",
        "resource_types",
    ]

    def get_analytics_metadata(self) -> Dict[str, Any]:
        """Format the resource types in the analytics metadata.

        Returns:
            Dict of analytics metadata.
        """
        metadata = super().get_analytics_metadata()
        if len(self.resource_types) == 1:
            metadata["resource_types"] = self.resource_types[0]
        else:
            metadata["resource_types"] = ", ".join(self.resource_types)
        metadata["connector_type"] = self.type
        return metadata

    # Helper methods
    @property
    def type(self) -> str:
        """Get the connector type.

        Returns:
            The connector type.
        """
        if isinstance(self.connector_type, str):
            return self.connector_type
        return self.connector_type.connector_type

    @property
    def emojified_connector_type(self) -> str:
        """Get the emojified connector type.

        Returns:
            The emojified connector type.
        """
        if not isinstance(self.connector_type, str):
            return self.connector_type.emojified_connector_type

        return self.connector_type

    @property
    def emojified_resource_types(self) -> List[str]:
        """Get the emojified connector type.

        Returns:
            The emojified connector type.
        """
        if not isinstance(self.connector_type, str):
            return [
                self.connector_type.resource_type_dict[
                    resource_type
                ].emojified_resource_type
                for resource_type in self.resource_types
            ]

        return self.resource_types

    def validate_and_configure_resources(
        self,
        connector_type: "ServiceConnectorTypeModel",
        resource_types: Optional[Union[str, List[str]]] = None,
        resource_id: Optional[str] = None,
        configuration: Optional[Dict[str, Any]] = None,
        secrets: Optional[Dict[str, Optional[SecretStr]]] = None,
    ) -> None:
        """Validate and configure the resources that the connector can be used to access.

        Args:
            connector_type: The connector type specification used to validate
                the connector configuration.
            resource_types: The type(s) of resource that the connector instance
                can be used to access. If omitted, a multi-type connector is
                configured.
            resource_id: Uniquely identifies a specific resource instance that
                the connector instance can be used to access.
            configuration: The connector configuration.
            secrets: The connector secrets.
        """
        _validate_and_configure_resources(
            connector=self,
            connector_type=connector_type,
            resource_types=resource_types,
            resource_id=resource_id,
            configuration=configuration,
            secrets=secrets,
        )

emojified_connector_type property

Get the emojified connector type.

Returns:

Type Description
str

The emojified connector type.

emojified_resource_types property

Get the emojified connector type.

Returns:

Type Description
List[str]

The emojified connector type.

type property

Get the connector type.

Returns:

Type Description
str

The connector type.

get_analytics_metadata()

Format the resource types in the analytics metadata.

Returns:

Type Description
Dict[str, Any]

Dict of analytics metadata.

Source code in src/zenml/models/v2/core/service_connector.py
120
121
122
123
124
125
126
127
128
129
130
131
132
def get_analytics_metadata(self) -> Dict[str, Any]:
    """Format the resource types in the analytics metadata.

    Returns:
        Dict of analytics metadata.
    """
    metadata = super().get_analytics_metadata()
    if len(self.resource_types) == 1:
        metadata["resource_types"] = self.resource_types[0]
    else:
        metadata["resource_types"] = ", ".join(self.resource_types)
    metadata["connector_type"] = self.type
    return metadata

validate_and_configure_resources(connector_type, resource_types=None, resource_id=None, configuration=None, secrets=None)

Validate and configure the resources that the connector can be used to access.

Parameters:

Name Type Description Default
connector_type ServiceConnectorTypeModel

The connector type specification used to validate the connector configuration.

required
resource_types Optional[Union[str, List[str]]]

The type(s) of resource that the connector instance can be used to access. If omitted, a multi-type connector is configured.

None
resource_id Optional[str]

Uniquely identifies a specific resource instance that the connector instance can be used to access.

None
configuration Optional[Dict[str, Any]]

The connector configuration.

None
secrets Optional[Dict[str, Optional[SecretStr]]]

The connector secrets.

None
Source code in src/zenml/models/v2/core/service_connector.py
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
def validate_and_configure_resources(
    self,
    connector_type: "ServiceConnectorTypeModel",
    resource_types: Optional[Union[str, List[str]]] = None,
    resource_id: Optional[str] = None,
    configuration: Optional[Dict[str, Any]] = None,
    secrets: Optional[Dict[str, Optional[SecretStr]]] = None,
) -> None:
    """Validate and configure the resources that the connector can be used to access.

    Args:
        connector_type: The connector type specification used to validate
            the connector configuration.
        resource_types: The type(s) of resource that the connector instance
            can be used to access. If omitted, a multi-type connector is
            configured.
        resource_id: Uniquely identifies a specific resource instance that
            the connector instance can be used to access.
        configuration: The connector configuration.
        secrets: The connector secrets.
    """
    _validate_and_configure_resources(
        connector=self,
        connector_type=connector_type,
        resource_types=resource_types,
        resource_id=resource_id,
        configuration=configuration,
        secrets=secrets,
    )

ServiceConnectorRequirements

Bases: BaseModel

Service connector requirements.

Describes requirements that a service connector consumer has for a service connector instance that it needs in order to access a resource.

Attributes:

Name Type Description
connector_type Optional[str]

The type of service connector that is required. If omitted, any service connector type can be used.

resource_type str

The type of resource that the service connector instance must be able to access.

resource_id_attr Optional[str]

The name of an attribute in the stack component configuration that contains the resource ID of the resource that the service connector instance must be able to access.

Source code in src/zenml/models/v2/misc/service_connector_type.py
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
class ServiceConnectorRequirements(BaseModel):
    """Service connector requirements.

    Describes requirements that a service connector consumer has for a
    service connector instance that it needs in order to access a resource.

    Attributes:
        connector_type: The type of service connector that is required. If
            omitted, any service connector type can be used.
        resource_type: The type of resource that the service connector instance
            must be able to access.
        resource_id_attr: The name of an attribute in the stack component
            configuration that contains the resource ID of the resource that
            the service connector instance must be able to access.
    """

    connector_type: Optional[str] = None
    resource_type: str
    resource_id_attr: Optional[str] = None

    def is_satisfied_by(
        self,
        connector: Union[
            "ServiceConnectorResponse", "ServiceConnectorRequest"
        ],
        component: Union["ComponentResponse", "ComponentBase"],
    ) -> Tuple[bool, str]:
        """Check if the requirements are satisfied by a connector.

        Args:
            connector: The connector to check.
            component: The stack component that the connector is associated
                with.

        Returns:
            True if the requirements are satisfied, False otherwise, and a
            message describing the reason for the failure.
        """
        if self.connector_type and self.connector_type != connector.type:
            return (
                False,
                f"connector type '{connector.type}' does not match the "
                f"'{self.connector_type}' connector type specified in the "
                "stack component requirements",
            )
        if self.resource_type not in connector.resource_types:
            return False, (
                f"connector does not provide the '{self.resource_type}' "
                "resource type specified in the stack component requirements. "
                "Only the following resource types are supported: "
                f"{', '.join(connector.resource_types)}"
            )
        if self.resource_id_attr:
            resource_id = component.configuration.get(self.resource_id_attr)
            if not resource_id:
                return (
                    False,
                    f"the '{self.resource_id_attr}' stack component "
                    f"configuration attribute plays the role of resource "
                    f"identifier, but the stack component does not contain a "
                    f"'{self.resource_id_attr}' attribute. Please add the "
                    f"'{self.resource_id_attr}' attribute to the stack "
                    "component configuration and try again.",
                )

        return True, ""

is_satisfied_by(connector, component)

Check if the requirements are satisfied by a connector.

Parameters:

Name Type Description Default
connector Union[ServiceConnectorResponse, ServiceConnectorRequest]

The connector to check.

required
component Union[ComponentResponse, ComponentBase]

The stack component that the connector is associated with.

required

Returns:

Type Description
bool

True if the requirements are satisfied, False otherwise, and a

str

message describing the reason for the failure.

Source code in src/zenml/models/v2/misc/service_connector_type.py
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
def is_satisfied_by(
    self,
    connector: Union[
        "ServiceConnectorResponse", "ServiceConnectorRequest"
    ],
    component: Union["ComponentResponse", "ComponentBase"],
) -> Tuple[bool, str]:
    """Check if the requirements are satisfied by a connector.

    Args:
        connector: The connector to check.
        component: The stack component that the connector is associated
            with.

    Returns:
        True if the requirements are satisfied, False otherwise, and a
        message describing the reason for the failure.
    """
    if self.connector_type and self.connector_type != connector.type:
        return (
            False,
            f"connector type '{connector.type}' does not match the "
            f"'{self.connector_type}' connector type specified in the "
            "stack component requirements",
        )
    if self.resource_type not in connector.resource_types:
        return False, (
            f"connector does not provide the '{self.resource_type}' "
            "resource type specified in the stack component requirements. "
            "Only the following resource types are supported: "
            f"{', '.join(connector.resource_types)}"
        )
    if self.resource_id_attr:
        resource_id = component.configuration.get(self.resource_id_attr)
        if not resource_id:
            return (
                False,
                f"the '{self.resource_id_attr}' stack component "
                f"configuration attribute plays the role of resource "
                f"identifier, but the stack component does not contain a "
                f"'{self.resource_id_attr}' attribute. Please add the "
                f"'{self.resource_id_attr}' attribute to the stack "
                "component configuration and try again.",
            )

    return True, ""

ServiceConnectorResourcesInfo

Bases: BaseModel

Information about the service connector resources needed for CLI and UI.

Source code in src/zenml/models/v2/misc/info_models.py
73
74
75
76
77
78
class ServiceConnectorResourcesInfo(BaseModel):
    """Information about the service connector resources needed for CLI and UI."""

    connector_type: str

    components_resources_info: Dict[StackComponentType, List[ResourcesInfo]]

ServiceConnectorResourcesModel

Bases: BaseModel

Service connector resources list.

Lists the resource types and resource instances that a service connector can provide access to.

Source code in src/zenml/models/v2/misc/service_connector_type.py
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
class ServiceConnectorResourcesModel(BaseModel):
    """Service connector resources list.

    Lists the resource types and resource instances that a service connector
    can provide access to.
    """

    id: Optional[UUID] = Field(
        default=None,
        title="The ID of the service connector instance providing this "
        "resource.",
    )

    name: Optional[str] = Field(
        default=None,
        title="The name of the service connector instance providing this "
        "resource.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    connector_type: Union[str, "ServiceConnectorTypeModel"] = Field(
        title="The type of service connector.", union_mode="left_to_right"
    )

    resources: List[ServiceConnectorTypedResourcesModel] = Field(
        default_factory=list,
        title="The list of resources that the service connector instance can "
        "give access to. Contains one entry for every resource type "
        "that the connector is configured for.",
    )

    error: Optional[str] = Field(
        default=None,
        title="A global error message describing why the service connector "
        "instance could not authenticate to the remote service.",
    )

    @property
    def resources_dict(self) -> Dict[str, ServiceConnectorTypedResourcesModel]:
        """Get the resources as a dictionary indexed by resource type.

        Returns:
            The resources as a dictionary indexed by resource type.
        """
        return {
            resource.resource_type: resource for resource in self.resources
        }

    @property
    def resource_types(self) -> List[str]:
        """Get the resource types.

        Returns:
            The resource types.
        """
        return [resource.resource_type for resource in self.resources]

    def set_error(
        self, error: str, resource_type: Optional[str] = None
    ) -> None:
        """Set a global error message or an error for a single resource type.

        Args:
            error: The error message.
            resource_type: The resource type to set the error message for. If
                omitted, or if there is only one resource type involved, the
                error message is (also) set globally.

        Raises:
            KeyError: If the resource type is not found in the resources list.
        """
        if resource_type:
            resource = self.resources_dict.get(resource_type)
            if not resource:
                raise KeyError(
                    f"resource type '{resource_type}' not found in "
                    "service connector resources list"
                )
            resource.error = error
            resource.resource_ids = None
            if len(self.resources) == 1:
                # If there is only one resource type involved, set the global
                # error message as well.
                self.error = error
        else:
            self.error = error
            for resource in self.resources:
                resource.error = error
                resource.resource_ids = None

    def set_resource_ids(
        self, resource_type: str, resource_ids: List[str]
    ) -> None:
        """Set the resource IDs for a resource type.

        Args:
            resource_type: The resource type to set the resource IDs for.
            resource_ids: The resource IDs to set.

        Raises:
            KeyError: If the resource type is not found in the resources list.
        """
        resource = self.resources_dict.get(resource_type)
        if not resource:
            raise KeyError(
                f"resource type '{resource_type}' not found in "
                "service connector resources list"
            )
        resource.resource_ids = resource_ids
        resource.error = None

    @property
    def type(self) -> str:
        """Get the connector type.

        Returns:
            The connector type.
        """
        if isinstance(self.connector_type, str):
            return self.connector_type
        return self.connector_type.connector_type

    @property
    def emojified_connector_type(self) -> str:
        """Get the emojified connector type.

        Returns:
            The emojified connector type.
        """
        if not isinstance(self.connector_type, str):
            return self.connector_type.emojified_connector_type

        return self.connector_type

    def get_emojified_resource_types(
        self, resource_type: Optional[str] = None
    ) -> List[str]:
        """Get the emojified resource type.

        Args:
            resource_type: The resource type to get the emojified resource type
                for. If omitted, the emojified resource type for all resource
                types is returned.


        Returns:
            The list of emojified resource types.
        """
        if not isinstance(self.connector_type, str):
            if resource_type:
                return [
                    self.connector_type.resource_type_dict[
                        resource_type
                    ].emojified_resource_type
                ]
            return [
                self.connector_type.resource_type_dict[
                    resource_type
                ].emojified_resource_type
                for resource_type in self.resources_dict.keys()
            ]
        if resource_type:
            return [resource_type]
        return list(self.resources_dict.keys())

    def get_default_resource_id(self) -> Optional[str]:
        """Get the default resource ID, if included in the resource list.

        The default resource ID is a resource ID supplied by the connector
        implementation only for resource types that do not support multiple
        instances.

        Returns:
            The default resource ID, or None if no resource ID is set.
        """
        if len(self.resources) != 1:
            # multi-type connectors do not have a default resource ID
            return None

        if isinstance(self.connector_type, str):
            # can't determine default resource ID for unknown connector types
            return None

        resource_type_spec = self.connector_type.resource_type_dict[
            self.resources[0].resource_type
        ]
        if resource_type_spec.supports_instances:
            # resource types that support multiple instances do not have a
            # default resource ID
            return None

        resource_ids = self.resources[0].resource_ids

        if not resource_ids or len(resource_ids) != 1:
            return None

        return resource_ids[0]

    @classmethod
    def from_connector_model(
        cls,
        connector_model: "ServiceConnectorResponse",
        resource_type: Optional[str] = None,
    ) -> "ServiceConnectorResourcesModel":
        """Initialize a resource model from a connector model.

        Args:
            connector_model: The connector model.
            resource_type: The resource type to set on the resource model. If
                omitted, the resource type is set according to the connector
                model.

        Returns:
            A resource list model instance.
        """
        resources = cls(
            id=connector_model.id,
            name=connector_model.name,
            connector_type=connector_model.type,
        )

        resource_types = resource_type or connector_model.resource_types
        for resource_type in resource_types:
            resources.resources.append(
                ServiceConnectorTypedResourcesModel(
                    resource_type=resource_type,
                    resource_ids=[connector_model.resource_id]
                    if connector_model.resource_id
                    else None,
                )
            )

        return resources

emojified_connector_type property

Get the emojified connector type.

Returns:

Type Description
str

The emojified connector type.

resource_types property

Get the resource types.

Returns:

Type Description
List[str]

The resource types.

resources_dict property

Get the resources as a dictionary indexed by resource type.

Returns:

Type Description
Dict[str, ServiceConnectorTypedResourcesModel]

The resources as a dictionary indexed by resource type.

type property

Get the connector type.

Returns:

Type Description
str

The connector type.

from_connector_model(connector_model, resource_type=None) classmethod

Initialize a resource model from a connector model.

Parameters:

Name Type Description Default
connector_model ServiceConnectorResponse

The connector model.

required
resource_type Optional[str]

The resource type to set on the resource model. If omitted, the resource type is set according to the connector model.

None

Returns:

Type Description
ServiceConnectorResourcesModel

A resource list model instance.

Source code in src/zenml/models/v2/misc/service_connector_type.py
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
@classmethod
def from_connector_model(
    cls,
    connector_model: "ServiceConnectorResponse",
    resource_type: Optional[str] = None,
) -> "ServiceConnectorResourcesModel":
    """Initialize a resource model from a connector model.

    Args:
        connector_model: The connector model.
        resource_type: The resource type to set on the resource model. If
            omitted, the resource type is set according to the connector
            model.

    Returns:
        A resource list model instance.
    """
    resources = cls(
        id=connector_model.id,
        name=connector_model.name,
        connector_type=connector_model.type,
    )

    resource_types = resource_type or connector_model.resource_types
    for resource_type in resource_types:
        resources.resources.append(
            ServiceConnectorTypedResourcesModel(
                resource_type=resource_type,
                resource_ids=[connector_model.resource_id]
                if connector_model.resource_id
                else None,
            )
        )

    return resources

get_default_resource_id()

Get the default resource ID, if included in the resource list.

The default resource ID is a resource ID supplied by the connector implementation only for resource types that do not support multiple instances.

Returns:

Type Description
Optional[str]

The default resource ID, or None if no resource ID is set.

Source code in src/zenml/models/v2/misc/service_connector_type.py
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
def get_default_resource_id(self) -> Optional[str]:
    """Get the default resource ID, if included in the resource list.

    The default resource ID is a resource ID supplied by the connector
    implementation only for resource types that do not support multiple
    instances.

    Returns:
        The default resource ID, or None if no resource ID is set.
    """
    if len(self.resources) != 1:
        # multi-type connectors do not have a default resource ID
        return None

    if isinstance(self.connector_type, str):
        # can't determine default resource ID for unknown connector types
        return None

    resource_type_spec = self.connector_type.resource_type_dict[
        self.resources[0].resource_type
    ]
    if resource_type_spec.supports_instances:
        # resource types that support multiple instances do not have a
        # default resource ID
        return None

    resource_ids = self.resources[0].resource_ids

    if not resource_ids or len(resource_ids) != 1:
        return None

    return resource_ids[0]

get_emojified_resource_types(resource_type=None)

Get the emojified resource type.

Parameters:

Name Type Description Default
resource_type Optional[str]

The resource type to get the emojified resource type for. If omitted, the emojified resource type for all resource types is returned.

None

Returns:

Type Description
List[str]

The list of emojified resource types.

Source code in src/zenml/models/v2/misc/service_connector_type.py
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
def get_emojified_resource_types(
    self, resource_type: Optional[str] = None
) -> List[str]:
    """Get the emojified resource type.

    Args:
        resource_type: The resource type to get the emojified resource type
            for. If omitted, the emojified resource type for all resource
            types is returned.


    Returns:
        The list of emojified resource types.
    """
    if not isinstance(self.connector_type, str):
        if resource_type:
            return [
                self.connector_type.resource_type_dict[
                    resource_type
                ].emojified_resource_type
            ]
        return [
            self.connector_type.resource_type_dict[
                resource_type
            ].emojified_resource_type
            for resource_type in self.resources_dict.keys()
        ]
    if resource_type:
        return [resource_type]
    return list(self.resources_dict.keys())

set_error(error, resource_type=None)

Set a global error message or an error for a single resource type.

Parameters:

Name Type Description Default
error str

The error message.

required
resource_type Optional[str]

The resource type to set the error message for. If omitted, or if there is only one resource type involved, the error message is (also) set globally.

None

Raises:

Type Description
KeyError

If the resource type is not found in the resources list.

Source code in src/zenml/models/v2/misc/service_connector_type.py
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
def set_error(
    self, error: str, resource_type: Optional[str] = None
) -> None:
    """Set a global error message or an error for a single resource type.

    Args:
        error: The error message.
        resource_type: The resource type to set the error message for. If
            omitted, or if there is only one resource type involved, the
            error message is (also) set globally.

    Raises:
        KeyError: If the resource type is not found in the resources list.
    """
    if resource_type:
        resource = self.resources_dict.get(resource_type)
        if not resource:
            raise KeyError(
                f"resource type '{resource_type}' not found in "
                "service connector resources list"
            )
        resource.error = error
        resource.resource_ids = None
        if len(self.resources) == 1:
            # If there is only one resource type involved, set the global
            # error message as well.
            self.error = error
    else:
        self.error = error
        for resource in self.resources:
            resource.error = error
            resource.resource_ids = None

set_resource_ids(resource_type, resource_ids)

Set the resource IDs for a resource type.

Parameters:

Name Type Description Default
resource_type str

The resource type to set the resource IDs for.

required
resource_ids List[str]

The resource IDs to set.

required

Raises:

Type Description
KeyError

If the resource type is not found in the resources list.

Source code in src/zenml/models/v2/misc/service_connector_type.py
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
def set_resource_ids(
    self, resource_type: str, resource_ids: List[str]
) -> None:
    """Set the resource IDs for a resource type.

    Args:
        resource_type: The resource type to set the resource IDs for.
        resource_ids: The resource IDs to set.

    Raises:
        KeyError: If the resource type is not found in the resources list.
    """
    resource = self.resources_dict.get(resource_type)
    if not resource:
        raise KeyError(
            f"resource type '{resource_type}' not found in "
            "service connector resources list"
        )
    resource.resource_ids = resource_ids
    resource.error = None

ServiceConnectorResponse

Bases: WorkspaceScopedResponse[ServiceConnectorResponseBody, ServiceConnectorResponseMetadata, ServiceConnectorResponseResources]

Response model for service connectors.

Source code in src/zenml/models/v2/core/service_connector.py
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
class ServiceConnectorResponse(
    WorkspaceScopedResponse[
        ServiceConnectorResponseBody,
        ServiceConnectorResponseMetadata,
        ServiceConnectorResponseResources,
    ]
):
    """Response model for service connectors."""

    # Disable the warning for updating responses, because we update the
    # service connector type in place
    _warn_on_response_updates: bool = False

    name: str = Field(
        title="The service connector name.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_analytics_metadata(self) -> Dict[str, Any]:
        """Add the service connector labels to analytics metadata.

        Returns:
            Dict of analytics metadata.
        """
        metadata = super().get_analytics_metadata()

        metadata.update(
            {
                label[6:]: value
                for label, value in self.labels.items()
                if label.startswith("zenml:")
            }
        )
        return metadata

    def get_hydrated_version(self) -> "ServiceConnectorResponse":
        """Get the hydrated version of this service connector.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_service_connector(self.id)

    # Helper methods
    @property
    def type(self) -> str:
        """Get the connector type.

        Returns:
            The connector type.
        """
        if isinstance(self.connector_type, str):
            return self.connector_type
        return self.connector_type.connector_type

    @property
    def emojified_connector_type(self) -> str:
        """Get the emojified connector type.

        Returns:
            The emojified connector type.
        """
        if not isinstance(self.connector_type, str):
            return self.connector_type.emojified_connector_type

        return self.connector_type

    @property
    def emojified_resource_types(self) -> List[str]:
        """Get the emojified connector type.

        Returns:
            The emojified connector type.
        """
        if not isinstance(self.connector_type, str):
            return [
                self.connector_type.resource_type_dict[
                    resource_type
                ].emojified_resource_type
                for resource_type in self.resource_types
            ]

        return self.resource_types

    @property
    def is_multi_type(self) -> bool:
        """Checks if the connector is multi-type.

        A multi-type connector can be used to access multiple types of
        resources.

        Returns:
            True if the connector is multi-type, False otherwise.
        """
        return len(self.resource_types) > 1

    @property
    def is_multi_instance(self) -> bool:
        """Checks if the connector is multi-instance.

        A multi-instance connector is configured to access multiple instances
        of the configured resource type.

        Returns:
            True if the connector is multi-instance, False otherwise.
        """
        return (
            not self.is_multi_type
            and self.supports_instances
            and not self.resource_id
        )

    @property
    def is_single_instance(self) -> bool:
        """Checks if the connector is single-instance.

        A single-instance connector is configured to access only a single
        instance of the configured resource type or does not support multiple
        resource instances.

        Returns:
            True if the connector is single-instance, False otherwise.
        """
        return not self.is_multi_type and not self.is_multi_instance

    @property
    def full_configuration(self) -> Dict[str, str]:
        """Get the full connector configuration, including secrets.

        Returns:
            The full connector configuration, including secrets.
        """
        config = self.configuration.copy()
        config.update(
            {k: v.get_secret_value() for k, v in self.secrets.items() if v}
        )
        return config

    def set_connector_type(
        self, value: Union[str, "ServiceConnectorTypeModel"]
    ) -> None:
        """Auxiliary method to set the connector type.

        Args:
            value: the new value for the connector type.
        """
        self.get_body().connector_type = value

    def validate_and_configure_resources(
        self,
        connector_type: "ServiceConnectorTypeModel",
        resource_types: Optional[Union[str, List[str]]] = None,
        resource_id: Optional[str] = None,
        configuration: Optional[Dict[str, Any]] = None,
        secrets: Optional[Dict[str, Optional[SecretStr]]] = None,
    ) -> None:
        """Validate and configure the resources that the connector can be used to access.

        Args:
            connector_type: The connector type specification used to validate
                the connector configuration.
            resource_types: The type(s) of resource that the connector instance
                can be used to access. If omitted, a multi-type connector is
                configured.
            resource_id: Uniquely identifies a specific resource instance that
                the connector instance can be used to access.
            configuration: The connector configuration.
            secrets: The connector secrets.
        """
        _validate_and_configure_resources(
            connector=self,
            connector_type=connector_type,
            resource_types=resource_types,
            resource_id=resource_id,
            configuration=configuration,
            secrets=secrets,
        )

    # Body and metadata properties
    @property
    def description(self) -> str:
        """The `description` property.

        Returns:
            the value of the property.
        """
        return self.get_body().description

    @property
    def connector_type(self) -> Union[str, "ServiceConnectorTypeModel"]:
        """The `connector_type` property.

        Returns:
            the value of the property.
        """
        return self.get_body().connector_type

    @property
    def auth_method(self) -> str:
        """The `auth_method` property.

        Returns:
            the value of the property.
        """
        return self.get_body().auth_method

    @property
    def resource_types(self) -> List[str]:
        """The `resource_types` property.

        Returns:
            the value of the property.
        """
        return self.get_body().resource_types

    @property
    def resource_id(self) -> Optional[str]:
        """The `resource_id` property.

        Returns:
            the value of the property.
        """
        return self.get_body().resource_id

    @property
    def supports_instances(self) -> bool:
        """The `supports_instances` property.

        Returns:
            the value of the property.
        """
        return self.get_body().supports_instances

    @property
    def expires_at(self) -> Optional[datetime]:
        """The `expires_at` property.

        Returns:
            the value of the property.
        """
        return self.get_body().expires_at

    @property
    def expires_skew_tolerance(self) -> Optional[int]:
        """The `expires_skew_tolerance` property.

        Returns:
            the value of the property.
        """
        return self.get_body().expires_skew_tolerance

    @property
    def configuration(self) -> Dict[str, Any]:
        """The `configuration` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().configuration

    @property
    def secret_id(self) -> Optional[UUID]:
        """The `secret_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().secret_id

    @property
    def expiration_seconds(self) -> Optional[int]:
        """The `expiration_seconds` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().expiration_seconds

    @property
    def secrets(self) -> Dict[str, Optional[SecretStr]]:
        """The `secrets` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().secrets

    @property
    def labels(self) -> Dict[str, str]:
        """The `labels` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().labels

auth_method property

The auth_method property.

Returns:

Type Description
str

the value of the property.

configuration property

The configuration property.

Returns:

Type Description
Dict[str, Any]

the value of the property.

connector_type property

The connector_type property.

Returns:

Type Description
Union[str, ServiceConnectorTypeModel]

the value of the property.

description property

The description property.

Returns:

Type Description
str

the value of the property.

emojified_connector_type property

Get the emojified connector type.

Returns:

Type Description
str

The emojified connector type.

emojified_resource_types property

Get the emojified connector type.

Returns:

Type Description
List[str]

The emojified connector type.

expiration_seconds property

The expiration_seconds property.

Returns:

Type Description
Optional[int]

the value of the property.

expires_at property

The expires_at property.

Returns:

Type Description
Optional[datetime]

the value of the property.

expires_skew_tolerance property

The expires_skew_tolerance property.

Returns:

Type Description
Optional[int]

the value of the property.

full_configuration property

Get the full connector configuration, including secrets.

Returns:

Type Description
Dict[str, str]

The full connector configuration, including secrets.

is_multi_instance property

Checks if the connector is multi-instance.

A multi-instance connector is configured to access multiple instances of the configured resource type.

Returns:

Type Description
bool

True if the connector is multi-instance, False otherwise.

is_multi_type property

Checks if the connector is multi-type.

A multi-type connector can be used to access multiple types of resources.

Returns:

Type Description
bool

True if the connector is multi-type, False otherwise.

is_single_instance property

Checks if the connector is single-instance.

A single-instance connector is configured to access only a single instance of the configured resource type or does not support multiple resource instances.

Returns:

Type Description
bool

True if the connector is single-instance, False otherwise.

labels property

The labels property.

Returns:

Type Description
Dict[str, str]

the value of the property.

resource_id property

The resource_id property.

Returns:

Type Description
Optional[str]

the value of the property.

resource_types property

The resource_types property.

Returns:

Type Description
List[str]

the value of the property.

secret_id property

The secret_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

secrets property

The secrets property.

Returns:

Type Description
Dict[str, Optional[SecretStr]]

the value of the property.

supports_instances property

The supports_instances property.

Returns:

Type Description
bool

the value of the property.

type property

Get the connector type.

Returns:

Type Description
str

The connector type.

get_analytics_metadata()

Add the service connector labels to analytics metadata.

Returns:

Type Description
Dict[str, Any]

Dict of analytics metadata.

Source code in src/zenml/models/v2/core/service_connector.py
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
def get_analytics_metadata(self) -> Dict[str, Any]:
    """Add the service connector labels to analytics metadata.

    Returns:
        Dict of analytics metadata.
    """
    metadata = super().get_analytics_metadata()

    metadata.update(
        {
            label[6:]: value
            for label, value in self.labels.items()
            if label.startswith("zenml:")
        }
    )
    return metadata

get_hydrated_version()

Get the hydrated version of this service connector.

Returns:

Type Description
ServiceConnectorResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/service_connector.py
517
518
519
520
521
522
523
524
525
def get_hydrated_version(self) -> "ServiceConnectorResponse":
    """Get the hydrated version of this service connector.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_service_connector(self.id)

set_connector_type(value)

Auxiliary method to set the connector type.

Parameters:

Name Type Description Default
value Union[str, ServiceConnectorTypeModel]

the new value for the connector type.

required
Source code in src/zenml/models/v2/core/service_connector.py
622
623
624
625
626
627
628
629
630
def set_connector_type(
    self, value: Union[str, "ServiceConnectorTypeModel"]
) -> None:
    """Auxiliary method to set the connector type.

    Args:
        value: the new value for the connector type.
    """
    self.get_body().connector_type = value

validate_and_configure_resources(connector_type, resource_types=None, resource_id=None, configuration=None, secrets=None)

Validate and configure the resources that the connector can be used to access.

Parameters:

Name Type Description Default
connector_type ServiceConnectorTypeModel

The connector type specification used to validate the connector configuration.

required
resource_types Optional[Union[str, List[str]]]

The type(s) of resource that the connector instance can be used to access. If omitted, a multi-type connector is configured.

None
resource_id Optional[str]

Uniquely identifies a specific resource instance that the connector instance can be used to access.

None
configuration Optional[Dict[str, Any]]

The connector configuration.

None
secrets Optional[Dict[str, Optional[SecretStr]]]

The connector secrets.

None
Source code in src/zenml/models/v2/core/service_connector.py
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
def validate_and_configure_resources(
    self,
    connector_type: "ServiceConnectorTypeModel",
    resource_types: Optional[Union[str, List[str]]] = None,
    resource_id: Optional[str] = None,
    configuration: Optional[Dict[str, Any]] = None,
    secrets: Optional[Dict[str, Optional[SecretStr]]] = None,
) -> None:
    """Validate and configure the resources that the connector can be used to access.

    Args:
        connector_type: The connector type specification used to validate
            the connector configuration.
        resource_types: The type(s) of resource that the connector instance
            can be used to access. If omitted, a multi-type connector is
            configured.
        resource_id: Uniquely identifies a specific resource instance that
            the connector instance can be used to access.
        configuration: The connector configuration.
        secrets: The connector secrets.
    """
    _validate_and_configure_resources(
        connector=self,
        connector_type=connector_type,
        resource_types=resource_types,
        resource_id=resource_id,
        configuration=configuration,
        secrets=secrets,
    )

ServiceConnectorResponseBody

Bases: WorkspaceScopedResponseBody

Response body for service connectors.

Source code in src/zenml/models/v2/core/service_connector.py
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
class ServiceConnectorResponseBody(WorkspaceScopedResponseBody):
    """Response body for service connectors."""

    description: str = Field(
        default="",
        title="The service connector instance description.",
    )
    connector_type: Union[str, "ServiceConnectorTypeModel"] = Field(
        title="The type of service connector.", union_mode="left_to_right"
    )
    auth_method: str = Field(
        title="The authentication method that the connector instance uses to "
        "access the resources.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    resource_types: List[str] = Field(
        default_factory=list,
        title="The type(s) of resource that the connector instance can be used "
        "to gain access to.",
    )
    resource_id: Optional[str] = Field(
        default=None,
        title="Uniquely identifies a specific resource instance that the "
        "connector instance can be used to access. If omitted, the connector "
        "instance can be used to access any and all resource instances that "
        "the authentication method and resource type(s) allow.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    supports_instances: bool = Field(
        default=False,
        title="Indicates whether the connector instance can be used to access "
        "multiple instances of the configured resource type.",
    )
    expires_at: Optional[datetime] = Field(
        default=None,
        title="Time when the authentication credentials configured for the "
        "connector expire. If omitted, the credentials do not expire.",
    )
    expires_skew_tolerance: Optional[int] = Field(
        default=None,
        title="The number of seconds of tolerance to apply when checking "
        "whether the authentication credentials configured for the connector "
        "have expired. If omitted, no tolerance is applied.",
    )

ServiceConnectorResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for service connectors.

Source code in src/zenml/models/v2/core/service_connector.py
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
class ServiceConnectorResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for service connectors."""

    configuration: Dict[str, Any] = Field(
        default_factory=dict,
        title="The service connector configuration, not including secrets.",
    )
    secret_id: Optional[UUID] = Field(
        default=None,
        title="The ID of the secret that contains the service connector "
        "secret configuration values.",
    )
    expiration_seconds: Optional[int] = Field(
        default=None,
        title="The duration, in seconds, that the temporary credentials "
        "generated by this connector should remain valid. Only applicable for "
        "connectors and authentication methods that involve generating "
        "temporary credentials from the ones configured in the connector.",
    )
    secrets: Dict[str, Optional[PlainSerializedSecretStr]] = Field(
        default_factory=dict,
        title="The service connector secrets.",
    )
    labels: Dict[str, str] = Field(
        default_factory=dict,
        title="Service connector labels.",
    )

ServiceConnectorTypeModel

Bases: BaseModel

Service connector type specification.

Describes the types of resources to which the service connector can be used to gain access and the authentication methods that are supported by the service connector.

The connector type, resource types, resource IDs and authentication methods can all be used as search criteria to lookup and filter service connector instances that are compatible with the requirements of a consumer (e.g. a stack component).

Source code in src/zenml/models/v2/misc/service_connector_type.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
class ServiceConnectorTypeModel(BaseModel):
    """Service connector type specification.

    Describes the types of resources to which the service connector can be used
    to gain access and the authentication methods that are supported by the
    service connector.

    The connector type, resource types, resource IDs and authentication
    methods can all be used as search criteria to lookup and filter service
    connector instances that are compatible with the requirements of a consumer
    (e.g. a stack component).
    """

    name: str = Field(
        title="User readable name for the service connector type.",
    )
    connector_type: str = Field(
        title="The type of service connector. It can be used to represent a "
        "generic resource (e.g. Docker, Kubernetes) or a group of different "
        "resources accessible through a common interface or point of access "
        "and authentication (e.g. a cloud provider or a platform).",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    description: str = Field(
        default="",
        title="A description of the service connector.",
    )
    resource_types: List[ResourceTypeModel] = Field(
        title="A list of resource types that the connector can be used to "
        "access.",
    )
    auth_methods: List[AuthenticationMethodModel] = Field(
        title="A list of specifications describing the authentication "
        "methods that are supported by the service connector, along with the "
        "configuration and secrets attributes that need to be configured for "
        "them.",
    )
    supports_auto_configuration: bool = Field(
        default=False,
        title="Models if the connector can be configured automatically based "
        "on information extracted from a local environment.",
    )
    logo_url: Optional[str] = Field(
        default=None,
        title="Optionally, a URL pointing to a png,"
        "svg or jpg can be attached.",
    )
    emoji: Optional[str] = Field(
        default=None,
        title="Optionally, a python-rich emoji can be attached.",
    )
    docs_url: Optional[str] = Field(
        default=None,
        title="Optionally, a URL pointing to docs, within docs.zenml.io.",
    )
    sdk_docs_url: Optional[str] = Field(
        default=None,
        title="Optionally, a URL pointing to SDK docs,"
        "within sdkdocs.zenml.io.",
    )
    local: bool = Field(
        default=True,
        title="If True, the service connector is available locally.",
    )
    remote: bool = Field(
        default=False,
        title="If True, the service connector is available remotely.",
    )
    _connector_class: Optional[Type["ServiceConnector"]] = None

    @property
    def connector_class(self) -> Optional[Type["ServiceConnector"]]:
        """Get the service connector class.

        Returns:
            The service connector class.
        """
        return self._connector_class

    @property
    def emojified_connector_type(self) -> str:
        """Get the emojified connector type.

        Returns:
            The emojified connector type.
        """
        if not self.emoji:
            return self.connector_type
        return f"{self.emoji} {self.connector_type}"

    @property
    def emojified_resource_types(self) -> List[str]:
        """Get the emojified connector types.

        Returns:
            The emojified connector types.
        """
        return [
            resource_type.emojified_resource_type
            for resource_type in self.resource_types
        ]

    def set_connector_class(
        self, connector_class: Type["ServiceConnector"]
    ) -> None:
        """Set the service connector class.

        Args:
            connector_class: The service connector class.
        """
        self._connector_class = connector_class

    @field_validator("resource_types")
    @classmethod
    def validate_resource_types(
        cls, values: List[ResourceTypeModel]
    ) -> List[ResourceTypeModel]:
        """Validate that the resource types are unique.

        Args:
            values: The list of resource types.

        Returns:
            The list of resource types.

        Raises:
            ValueError: If two or more resource type specifications list the
                same resource type.
        """
        # Gather all resource types from the list of resource type
        # specifications.
        resource_types = [r.resource_type for r in values]
        if len(resource_types) != len(set(resource_types)):
            raise ValueError(
                "Two or more resource type specifications must not list "
                "the same resource type."
            )

        return values

    @field_validator("auth_methods")
    @classmethod
    def validate_auth_methods(
        cls, values: List[AuthenticationMethodModel]
    ) -> List[AuthenticationMethodModel]:
        """Validate that the authentication methods are unique.

        Args:
            values: The list of authentication methods.

        Returns:
            The list of authentication methods.

        Raises:
            ValueError: If two or more authentication method specifications
                share the same authentication method value.
        """
        # Gather all auth methods from the list of auth method
        # specifications.
        auth_methods = [a.auth_method for a in values]
        if len(auth_methods) != len(set(auth_methods)):
            raise ValueError(
                "Two or more authentication method specifications must not "
                "share the same authentication method value."
            )

        return values

    @property
    def resource_type_dict(
        self,
    ) -> Dict[str, ResourceTypeModel]:
        """Returns a map of resource types to resource type specifications.

        Returns:
            A map of resource types to resource type specifications.
        """
        return {r.resource_type: r for r in self.resource_types}

    @property
    def auth_method_dict(
        self,
    ) -> Dict[str, AuthenticationMethodModel]:
        """Returns a map of authentication methods to authentication method specifications.

        Returns:
            A map of authentication methods to authentication method
            specifications.
        """
        return {a.auth_method: a for a in self.auth_methods}

    def find_resource_specifications(
        self,
        auth_method: str,
        resource_type: Optional[str] = None,
    ) -> Tuple[AuthenticationMethodModel, Optional[ResourceTypeModel]]:
        """Find the specifications for a configurable resource.

        Validate the supplied connector configuration parameters against the
        connector specification and return the matching authentication method
        specification and resource specification.

        Args:
            auth_method: The name of the authentication method.
            resource_type: The type of resource being configured.

        Returns:
            The authentication method specification and resource specification
            for the specified authentication method and resource type.

        Raises:
            KeyError: If the authentication method is not supported by the
                connector for the specified resource type and ID.
        """
        # Verify the authentication method
        auth_method_dict = self.auth_method_dict
        if auth_method in auth_method_dict:
            # A match was found for the authentication method
            auth_method_spec = auth_method_dict[auth_method]
        else:
            # No match was found for the authentication method
            raise KeyError(
                f"connector type '{self.connector_type}' does not support the "
                f"'{auth_method}' authentication method. Supported "
                f"authentication methods are: {list(auth_method_dict.keys())}."
            )

        if resource_type is None:
            # No resource type was specified, so no resource type
            # specification can be returned.
            return auth_method_spec, None

        # Verify the resource type
        resource_type_dict = self.resource_type_dict
        if resource_type in resource_type_dict:
            resource_type_spec = resource_type_dict[resource_type]
        else:
            raise KeyError(
                f"connector type '{self.connector_type}' does not support "
                f"resource type '{resource_type}'. Supported resource types "
                f"are: {list(resource_type_dict.keys())}."
            )

        if auth_method not in resource_type_spec.auth_methods:
            raise KeyError(
                f"the '{self.connector_type}' connector type does not support "
                f"the '{auth_method}' authentication method for the "
                f"'{resource_type}' resource type. Supported authentication "
                f"methods are: {resource_type_spec.auth_methods}."
            )

        return auth_method_spec, resource_type_spec

auth_method_dict property

Returns a map of authentication methods to authentication method specifications.

Returns:

Type Description
Dict[str, AuthenticationMethodModel]

A map of authentication methods to authentication method

Dict[str, AuthenticationMethodModel]

specifications.

connector_class property

Get the service connector class.

Returns:

Type Description
Optional[Type[ServiceConnector]]

The service connector class.

emojified_connector_type property

Get the emojified connector type.

Returns:

Type Description
str

The emojified connector type.

emojified_resource_types property

Get the emojified connector types.

Returns:

Type Description
List[str]

The emojified connector types.

resource_type_dict property

Returns a map of resource types to resource type specifications.

Returns:

Type Description
Dict[str, ResourceTypeModel]

A map of resource types to resource type specifications.

find_resource_specifications(auth_method, resource_type=None)

Find the specifications for a configurable resource.

Validate the supplied connector configuration parameters against the connector specification and return the matching authentication method specification and resource specification.

Parameters:

Name Type Description Default
auth_method str

The name of the authentication method.

required
resource_type Optional[str]

The type of resource being configured.

None

Returns:

Type Description
AuthenticationMethodModel

The authentication method specification and resource specification

Optional[ResourceTypeModel]

for the specified authentication method and resource type.

Raises:

Type Description
KeyError

If the authentication method is not supported by the connector for the specified resource type and ID.

Source code in src/zenml/models/v2/misc/service_connector_type.py
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
def find_resource_specifications(
    self,
    auth_method: str,
    resource_type: Optional[str] = None,
) -> Tuple[AuthenticationMethodModel, Optional[ResourceTypeModel]]:
    """Find the specifications for a configurable resource.

    Validate the supplied connector configuration parameters against the
    connector specification and return the matching authentication method
    specification and resource specification.

    Args:
        auth_method: The name of the authentication method.
        resource_type: The type of resource being configured.

    Returns:
        The authentication method specification and resource specification
        for the specified authentication method and resource type.

    Raises:
        KeyError: If the authentication method is not supported by the
            connector for the specified resource type and ID.
    """
    # Verify the authentication method
    auth_method_dict = self.auth_method_dict
    if auth_method in auth_method_dict:
        # A match was found for the authentication method
        auth_method_spec = auth_method_dict[auth_method]
    else:
        # No match was found for the authentication method
        raise KeyError(
            f"connector type '{self.connector_type}' does not support the "
            f"'{auth_method}' authentication method. Supported "
            f"authentication methods are: {list(auth_method_dict.keys())}."
        )

    if resource_type is None:
        # No resource type was specified, so no resource type
        # specification can be returned.
        return auth_method_spec, None

    # Verify the resource type
    resource_type_dict = self.resource_type_dict
    if resource_type in resource_type_dict:
        resource_type_spec = resource_type_dict[resource_type]
    else:
        raise KeyError(
            f"connector type '{self.connector_type}' does not support "
            f"resource type '{resource_type}'. Supported resource types "
            f"are: {list(resource_type_dict.keys())}."
        )

    if auth_method not in resource_type_spec.auth_methods:
        raise KeyError(
            f"the '{self.connector_type}' connector type does not support "
            f"the '{auth_method}' authentication method for the "
            f"'{resource_type}' resource type. Supported authentication "
            f"methods are: {resource_type_spec.auth_methods}."
        )

    return auth_method_spec, resource_type_spec

set_connector_class(connector_class)

Set the service connector class.

Parameters:

Name Type Description Default
connector_class Type[ServiceConnector]

The service connector class.

required
Source code in src/zenml/models/v2/misc/service_connector_type.py
321
322
323
324
325
326
327
328
329
def set_connector_class(
    self, connector_class: Type["ServiceConnector"]
) -> None:
    """Set the service connector class.

    Args:
        connector_class: The service connector class.
    """
    self._connector_class = connector_class

validate_auth_methods(values) classmethod

Validate that the authentication methods are unique.

Parameters:

Name Type Description Default
values List[AuthenticationMethodModel]

The list of authentication methods.

required

Returns:

Type Description
List[AuthenticationMethodModel]

The list of authentication methods.

Raises:

Type Description
ValueError

If two or more authentication method specifications share the same authentication method value.

Source code in src/zenml/models/v2/misc/service_connector_type.py
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
@field_validator("auth_methods")
@classmethod
def validate_auth_methods(
    cls, values: List[AuthenticationMethodModel]
) -> List[AuthenticationMethodModel]:
    """Validate that the authentication methods are unique.

    Args:
        values: The list of authentication methods.

    Returns:
        The list of authentication methods.

    Raises:
        ValueError: If two or more authentication method specifications
            share the same authentication method value.
    """
    # Gather all auth methods from the list of auth method
    # specifications.
    auth_methods = [a.auth_method for a in values]
    if len(auth_methods) != len(set(auth_methods)):
        raise ValueError(
            "Two or more authentication method specifications must not "
            "share the same authentication method value."
        )

    return values

validate_resource_types(values) classmethod

Validate that the resource types are unique.

Parameters:

Name Type Description Default
values List[ResourceTypeModel]

The list of resource types.

required

Returns:

Type Description
List[ResourceTypeModel]

The list of resource types.

Raises:

Type Description
ValueError

If two or more resource type specifications list the same resource type.

Source code in src/zenml/models/v2/misc/service_connector_type.py
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
@field_validator("resource_types")
@classmethod
def validate_resource_types(
    cls, values: List[ResourceTypeModel]
) -> List[ResourceTypeModel]:
    """Validate that the resource types are unique.

    Args:
        values: The list of resource types.

    Returns:
        The list of resource types.

    Raises:
        ValueError: If two or more resource type specifications list the
            same resource type.
    """
    # Gather all resource types from the list of resource type
    # specifications.
    resource_types = [r.resource_type for r in values]
    if len(resource_types) != len(set(resource_types)):
        raise ValueError(
            "Two or more resource type specifications must not list "
            "the same resource type."
        )

    return values

ServiceConnectorTypedResourcesModel

Bases: BaseModel

Service connector typed resources list.

Lists the resource instances that a service connector can provide access to.

Source code in src/zenml/models/v2/misc/service_connector_type.py
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
class ServiceConnectorTypedResourcesModel(BaseModel):
    """Service connector typed resources list.

    Lists the resource instances that a service connector can provide
    access to.
    """

    resource_type: str = Field(
        title="The type of resource that the service connector instance can "
        "be used to access.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    resource_ids: Optional[List[str]] = Field(
        default=None,
        title="The resource IDs of all resource instances that the service "
        "connector instance can be used to access. Omitted (set to None) for "
        "multi-type service connectors that didn't explicitly request to "
        "fetch resources for all resource types. Also omitted if an error "
        "occurred while listing the resource instances or if no resources are "
        "listed due to authorization issues or lack of permissions (in both "
        "cases the 'error' field is set to an error message). For resource "
        "types that do not support multiple instances, a single resource ID is "
        "listed.",
    )

    error: Optional[str] = Field(
        default=None,
        title="An error message describing why the service connector instance "
        "could not list the resources that it is configured to access.",
    )

ServiceConnectorUpdate

Bases: BaseUpdate

Model used for service connector updates.

Most fields in the update model are optional and will not be updated if omitted. However, the following fields are "special" and leaving them out will also cause the corresponding value to be removed from the service connector in the database:

  • the resource_id field
  • the expiration_seconds field

In addition to the above exceptions, the following rules apply:

  • the configuration and secrets fields together represent a full valid configuration update, not just a partial update. If either is set (i.e. not None) in the update, their values are merged together and will replace the existing configuration and secrets values.
  • the secret_id field value in the update is ignored, given that secrets are managed internally by the ZenML store.
  • the labels field is also a full labels update: if set (i.e. not None), all existing labels are removed and replaced by the new labels in the update.

NOTE: the attributes here override the ones in the base class, so they have a None default value.

Source code in src/zenml/models/v2/core/service_connector.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
class ServiceConnectorUpdate(BaseUpdate):
    """Model used for service connector updates.

    Most fields in the update model are optional and will not be updated if
    omitted. However, the following fields are "special" and leaving them out
    will also cause the corresponding value to be removed from the service
    connector in the database:

    * the `resource_id` field
    * the `expiration_seconds` field

    In addition to the above exceptions, the following rules apply:

    * the `configuration` and `secrets` fields together represent a full
    valid configuration update, not just a partial update. If either is
    set (i.e. not None) in the update, their values are merged together and
    will replace the existing configuration and secrets values.
    * the `secret_id` field value in the update is ignored, given that
    secrets are managed internally by the ZenML store.
    * the `labels` field is also a full labels update: if set (i.e. not
    `None`), all existing labels are removed and replaced by the new labels
    in the update.

    NOTE: the attributes here override the ones in the base class, so they
    have a None default value.
    """

    name: Optional[str] = Field(
        title="The service connector name.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    connector_type: Optional[Union[str, "ServiceConnectorTypeModel"]] = Field(
        title="The type of service connector.",
        default=None,
        union_mode="left_to_right",
    )
    description: Optional[str] = Field(
        title="The service connector instance description.",
        default=None,
    )
    auth_method: Optional[str] = Field(
        title="The authentication method that the connector instance uses to "
        "access the resources.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    resource_types: Optional[List[str]] = Field(
        title="The type(s) of resource that the connector instance can be used "
        "to gain access to.",
        default=None,
    )
    resource_id: Optional[str] = Field(
        title="Uniquely identifies a specific resource instance that the "
        "connector instance can be used to access. If omitted, the "
        "connector instance can be used to access any and all resource "
        "instances that the authentication method and resource type(s) "
        "allow.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    supports_instances: Optional[bool] = Field(
        title="Indicates whether the connector instance can be used to access "
        "multiple instances of the configured resource type.",
        default=None,
    )
    expires_at: Optional[datetime] = Field(
        title="Time when the authentication credentials configured for the "
        "connector expire. If omitted, the credentials do not expire.",
        default=None,
    )
    expires_skew_tolerance: Optional[int] = Field(
        title="The number of seconds of tolerance to apply when checking "
        "whether the authentication credentials configured for the "
        "connector have expired. If omitted, no tolerance is applied.",
        default=None,
    )
    expiration_seconds: Optional[int] = Field(
        title="The duration, in seconds, that the temporary credentials "
        "generated by this connector should remain valid. Only "
        "applicable for connectors and authentication methods that "
        "involve generating temporary credentials from the ones "
        "configured in the connector.",
        default=None,
    )
    configuration: Optional[Dict[str, Any]] = Field(
        title="The service connector configuration, not including secrets.",
        default=None,
    )
    secrets: Optional[Dict[str, Optional[PlainSerializedSecretStr]]] = Field(
        title="The service connector secrets.",
        default=None,
    )
    labels: Optional[Dict[str, str]] = Field(
        title="Service connector labels.",
        default=None,
    )

    # Analytics
    ANALYTICS_FIELDS: ClassVar[List[str]] = [
        "connector_type",
        "auth_method",
        "resource_types",
    ]

    def get_analytics_metadata(self) -> Dict[str, Any]:
        """Format the resource types in the analytics metadata.

        Returns:
            Dict of analytics metadata.
        """
        metadata = super().get_analytics_metadata()

        if self.resource_types is not None:
            if len(self.resource_types) == 1:
                metadata["resource_types"] = self.resource_types[0]
            else:
                metadata["resource_types"] = ", ".join(self.resource_types)

        if self.connector_type is not None:
            metadata["connector_type"] = self.type

        return metadata

    # Helper methods
    @property
    def type(self) -> Optional[str]:
        """Get the connector type.

        Returns:
            The connector type.
        """
        if self.connector_type is not None:
            if isinstance(self.connector_type, str):
                return self.connector_type
            return self.connector_type.connector_type
        return None

    def validate_and_configure_resources(
        self,
        connector_type: "ServiceConnectorTypeModel",
        resource_types: Optional[Union[str, List[str]]] = None,
        resource_id: Optional[str] = None,
        configuration: Optional[Dict[str, Any]] = None,
        secrets: Optional[Dict[str, Optional[SecretStr]]] = None,
    ) -> None:
        """Validate and configure the resources that the connector can be used to access.

        Args:
            connector_type: The connector type specification used to validate
                the connector configuration.
            resource_types: The type(s) of resource that the connector instance
                can be used to access. If omitted, a multi-type connector is
                configured.
            resource_id: Uniquely identifies a specific resource instance that
                the connector instance can be used to access.
            configuration: The connector configuration.
            secrets: The connector secrets.
        """
        _validate_and_configure_resources(
            connector=self,
            connector_type=connector_type,
            resource_types=resource_types,
            resource_id=resource_id,
            configuration=configuration,
            secrets=secrets,
        )

    def convert_to_request(self) -> "ServiceConnectorRequest":
        """Method to generate a service connector request object from self.

        For certain operations, the service connector update model need to
        adhere to the limitations set by the request model. In order to use
        update models in such situations, we need to be able to convert an
        update model into a request model.

        Returns:
            The equivalent request model

        Raises:
            RuntimeError: if the model can not be converted to a request model.
        """
        try:
            return ServiceConnectorRequest.model_validate(self.model_dump())
        except ValidationError as e:
            raise RuntimeError(
                "The service connector update model can not be converted into "
                f"an equivalent request model: {e}"
            )

type property

Get the connector type.

Returns:

Type Description
Optional[str]

The connector type.

convert_to_request()

Method to generate a service connector request object from self.

For certain operations, the service connector update model need to adhere to the limitations set by the request model. In order to use update models in such situations, we need to be able to convert an update model into a request model.

Returns:

Type Description
ServiceConnectorRequest

The equivalent request model

Raises:

Type Description
RuntimeError

if the model can not be converted to a request model.

Source code in src/zenml/models/v2/core/service_connector.py
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
def convert_to_request(self) -> "ServiceConnectorRequest":
    """Method to generate a service connector request object from self.

    For certain operations, the service connector update model need to
    adhere to the limitations set by the request model. In order to use
    update models in such situations, we need to be able to convert an
    update model into a request model.

    Returns:
        The equivalent request model

    Raises:
        RuntimeError: if the model can not be converted to a request model.
    """
    try:
        return ServiceConnectorRequest.model_validate(self.model_dump())
    except ValidationError as e:
        raise RuntimeError(
            "The service connector update model can not be converted into "
            f"an equivalent request model: {e}"
        )

get_analytics_metadata()

Format the resource types in the analytics metadata.

Returns:

Type Description
Dict[str, Any]

Dict of analytics metadata.

Source code in src/zenml/models/v2/core/service_connector.py
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
def get_analytics_metadata(self) -> Dict[str, Any]:
    """Format the resource types in the analytics metadata.

    Returns:
        Dict of analytics metadata.
    """
    metadata = super().get_analytics_metadata()

    if self.resource_types is not None:
        if len(self.resource_types) == 1:
            metadata["resource_types"] = self.resource_types[0]
        else:
            metadata["resource_types"] = ", ".join(self.resource_types)

    if self.connector_type is not None:
        metadata["connector_type"] = self.type

    return metadata

validate_and_configure_resources(connector_type, resource_types=None, resource_id=None, configuration=None, secrets=None)

Validate and configure the resources that the connector can be used to access.

Parameters:

Name Type Description Default
connector_type ServiceConnectorTypeModel

The connector type specification used to validate the connector configuration.

required
resource_types Optional[Union[str, List[str]]]

The type(s) of resource that the connector instance can be used to access. If omitted, a multi-type connector is configured.

None
resource_id Optional[str]

Uniquely identifies a specific resource instance that the connector instance can be used to access.

None
configuration Optional[Dict[str, Any]]

The connector configuration.

None
secrets Optional[Dict[str, Optional[SecretStr]]]

The connector secrets.

None
Source code in src/zenml/models/v2/core/service_connector.py
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
def validate_and_configure_resources(
    self,
    connector_type: "ServiceConnectorTypeModel",
    resource_types: Optional[Union[str, List[str]]] = None,
    resource_id: Optional[str] = None,
    configuration: Optional[Dict[str, Any]] = None,
    secrets: Optional[Dict[str, Optional[SecretStr]]] = None,
) -> None:
    """Validate and configure the resources that the connector can be used to access.

    Args:
        connector_type: The connector type specification used to validate
            the connector configuration.
        resource_types: The type(s) of resource that the connector instance
            can be used to access. If omitted, a multi-type connector is
            configured.
        resource_id: Uniquely identifies a specific resource instance that
            the connector instance can be used to access.
        configuration: The connector configuration.
        secrets: The connector secrets.
    """
    _validate_and_configure_resources(
        connector=self,
        connector_type=connector_type,
        resource_types=resource_types,
        resource_id=resource_id,
        configuration=configuration,
        secrets=secrets,
    )

ServiceFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of services.

The Service needs additional scoping. As such the _scope_user field can be set to the user that is doing the filtering. The generate_filter() method of the baseclass is overwritten to include the scoping.

Source code in src/zenml/models/v2/core/service.py
370
371
372
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
class ServiceFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of services.

    The Service needs additional scoping. As such the `_scope_user` field
    can be set to the user that is doing the filtering. The
    `generate_filter()` method of the baseclass is overwritten to include the
    scoping.
    """

    name: Optional[str] = Field(
        default=None,
        description="Name of the service. Use this to filter services by "
        "their name.",
    )
    type: Optional[str] = Field(
        default=None,
        description="Type of the service. Filter services by their type.",
    )
    flavor: Optional[str] = Field(
        default=None,
        description="Flavor of the service. Use this to filter services by "
        "their flavor.",
    )
    config: Optional[bytes] = Field(
        default=None,
        description="Config of the service. Use this to filter services by "
        "their config.",
    )
    pipeline_name: Optional[str] = Field(
        default=None,
        description="Pipeline name responsible for deploying the service",
    )
    pipeline_step_name: Optional[str] = Field(
        default=None,
        description="Pipeline step name responsible for deploying the service",
    )
    running: Optional[bool] = Field(
        default=None, description="Whether the service is running"
    )
    model_version_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="By the model version this service is attached to.",
        union_mode="left_to_right",
    )
    pipeline_run_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="By the pipeline run this service is attached to.",
        union_mode="left_to_right",
    )

    # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
    #  fields defined under base models. If not handled, this raises a warning.
    #  It is possible to suppress this warning message with the following
    #  configuration, however the ultimate solution is to rename these fields.
    #  Even though they do not cause any problems right now, if we are not
    #  careful we might overwrite some fields protected by pydantic.
    model_config = ConfigDict(protected_namespaces=())

    def set_type(self, type: str) -> None:
        """Set the type of the service.

        Args:
            type: The type of the service.
        """
        self.type = type

    def set_flavor(self, flavor: str) -> None:
        """Set the flavor of the service.

        Args:
            flavor: The flavor of the service.
        """
        self.flavor = flavor

    # Artifact name and type are not DB fields and need to be handled separately
    FILTER_EXCLUDE_FIELDS = [
        *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
        "flavor",
        "type",
        "pipeline_step_name",
        "running",
        "pipeline_name",
        "config",
    ]
    CLI_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.CLI_EXCLUDE_FIELDS,
        "flavor",
        "type",
        "pipeline_step_name",
        "running",
        "pipeline_name",
    ]

    def generate_filter(
        self, table: Type["AnySchema"]
    ) -> Union["ColumnElement[bool]"]:
        """Generate the filter for the query.

        Services can be scoped by type to narrow the search.

        Args:
            table: The Table that is being queried from.

        Returns:
            The filter expression for the query.
        """
        from sqlmodel import and_

        base_filter = super().generate_filter(table)

        if self.type:
            type_filter = getattr(table, "type") == self.type
            base_filter = and_(base_filter, type_filter)

        if self.flavor:
            flavor_filter = getattr(table, "flavor") == self.flavor
            base_filter = and_(base_filter, flavor_filter)

        if self.pipeline_name:
            pipeline_name_filter = (
                getattr(table, "pipeline_name") == self.pipeline_name
            )
            base_filter = and_(base_filter, pipeline_name_filter)

        if self.pipeline_step_name:
            pipeline_step_name_filter = (
                getattr(table, "pipeline_step_name") == self.pipeline_step_name
            )
            base_filter = and_(base_filter, pipeline_step_name_filter)

        return base_filter

generate_filter(table)

Generate the filter for the query.

Services can be scoped by type to narrow the search.

Parameters:

Name Type Description Default
table Type[AnySchema]

The Table that is being queried from.

required

Returns:

Type Description
Union[ColumnElement[bool]]

The filter expression for the query.

Source code in src/zenml/models/v2/core/service.py
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
def generate_filter(
    self, table: Type["AnySchema"]
) -> Union["ColumnElement[bool]"]:
    """Generate the filter for the query.

    Services can be scoped by type to narrow the search.

    Args:
        table: The Table that is being queried from.

    Returns:
        The filter expression for the query.
    """
    from sqlmodel import and_

    base_filter = super().generate_filter(table)

    if self.type:
        type_filter = getattr(table, "type") == self.type
        base_filter = and_(base_filter, type_filter)

    if self.flavor:
        flavor_filter = getattr(table, "flavor") == self.flavor
        base_filter = and_(base_filter, flavor_filter)

    if self.pipeline_name:
        pipeline_name_filter = (
            getattr(table, "pipeline_name") == self.pipeline_name
        )
        base_filter = and_(base_filter, pipeline_name_filter)

    if self.pipeline_step_name:
        pipeline_step_name_filter = (
            getattr(table, "pipeline_step_name") == self.pipeline_step_name
        )
        base_filter = and_(base_filter, pipeline_step_name_filter)

    return base_filter

set_flavor(flavor)

Set the flavor of the service.

Parameters:

Name Type Description Default
flavor str

The flavor of the service.

required
Source code in src/zenml/models/v2/core/service.py
436
437
438
439
440
441
442
def set_flavor(self, flavor: str) -> None:
    """Set the flavor of the service.

    Args:
        flavor: The flavor of the service.
    """
    self.flavor = flavor

set_type(type)

Set the type of the service.

Parameters:

Name Type Description Default
type str

The type of the service.

required
Source code in src/zenml/models/v2/core/service.py
428
429
430
431
432
433
434
def set_type(self, type: str) -> None:
    """Set the type of the service.

    Args:
        type: The type of the service.
    """
    self.type = type

ServiceRequest

Bases: WorkspaceScopedRequest

Request model for services.

Source code in src/zenml/models/v2/core/service.py
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
class ServiceRequest(WorkspaceScopedRequest):
    """Request model for services."""

    name: str = Field(
        title="The name of the service.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    service_type: ServiceType = Field(
        title="The type of the service.",
    )
    service_source: Optional[str] = Field(
        title="The class of the service.",
        description="The fully qualified class name of the service "
        "implementation.",
        default=None,
    )
    admin_state: Optional[ServiceState] = Field(
        title="The admin state of the service.",
        description="The administrative state of the service, e.g., ACTIVE, "
        "INACTIVE.",
        default=None,
    )
    config: Dict[str, Any] = Field(
        title="The service config.",
        description="A dictionary containing configuration parameters for the "
        "service.",
    )
    labels: Optional[Dict[str, str]] = Field(
        default=None,
        title="The service labels.",
    )
    status: Optional[Dict[str, Any]] = Field(
        default=None,
        title="The status of the service.",
    )
    endpoint: Optional[Dict[str, Any]] = Field(
        default=None,
        title="The service endpoint.",
    )
    prediction_url: Optional[str] = Field(
        default=None,
        title="The service endpoint URL.",
    )
    health_check_url: Optional[str] = Field(
        default=None,
        title="The service health check URL.",
    )
    model_version_id: Optional[UUID] = Field(
        default=None,
        title="The model version id linked to the service.",
    )
    pipeline_run_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="By the event source this trigger is attached to.",
        union_mode="left_to_right",
    )

    # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
    #  fields defined under base models. If not handled, this raises a warning.
    #  It is possible to suppress this warning message with the following
    #  configuration, however the ultimate solution is to rename these fields.
    #  Even though they do not cause any problems right now, if we are not
    #  careful we might overwrite some fields protected by pydantic.
    model_config = ConfigDict(protected_namespaces=())

ServiceResponse

Bases: WorkspaceScopedResponse[ServiceResponseBody, ServiceResponseMetadata, ServiceResponseResources]

Response model for services.

Source code in src/zenml/models/v2/core/service.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
class ServiceResponse(
    WorkspaceScopedResponse[
        ServiceResponseBody, ServiceResponseMetadata, ServiceResponseResources
    ]
):
    """Response model for services."""

    name: str = Field(
        title="The name of the service.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "ServiceResponse":
        """Get the hydrated version of this artifact.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_service(self.id)

    # Body and metadata properties

    @property
    def service_type(self) -> ServiceType:
        """The `service_type` property.

        Returns:
            the value of the property.
        """
        return self.get_body().service_type

    @property
    def labels(self) -> Optional[Dict[str, str]]:
        """The `labels` property.

        Returns:
            the value of the property.
        """
        return self.get_body().labels

    @property
    def service_source(self) -> Optional[str]:
        """The `service_source` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().service_source

    @property
    def config(self) -> Dict[str, Any]:
        """The `config` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().config

    @property
    def status(self) -> Optional[Dict[str, Any]]:
        """The `status` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().status

    @property
    def endpoint(self) -> Optional[Dict[str, Any]]:
        """The `endpoint` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().endpoint

    @property
    def created(self) -> datetime:
        """The `created` property.

        Returns:
            the value of the property.
        """
        return self.get_body().created

    @property
    def updated(self) -> datetime:
        """The `updated` property.

        Returns:
            the value of the property.
        """
        return self.get_body().updated

    @property
    def admin_state(self) -> Optional[ServiceState]:
        """The `admin_state` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().admin_state

    @property
    def prediction_url(self) -> Optional[str]:
        """The `prediction_url` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().prediction_url

    @property
    def health_check_url(self) -> Optional[str]:
        """The `health_check_url` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().health_check_url

    @property
    def state(self) -> Optional[ServiceState]:
        """The `state` property.

        Returns:
            the value of the property.
        """
        return self.get_body().state

admin_state property

The admin_state property.

Returns:

Type Description
Optional[ServiceState]

the value of the property.

config property

The config property.

Returns:

Type Description
Dict[str, Any]

the value of the property.

created property

The created property.

Returns:

Type Description
datetime

the value of the property.

endpoint property

The endpoint property.

Returns:

Type Description
Optional[Dict[str, Any]]

the value of the property.

health_check_url property

The health_check_url property.

Returns:

Type Description
Optional[str]

the value of the property.

labels property

The labels property.

Returns:

Type Description
Optional[Dict[str, str]]

the value of the property.

prediction_url property

The prediction_url property.

Returns:

Type Description
Optional[str]

the value of the property.

service_source property

The service_source property.

Returns:

Type Description
Optional[str]

the value of the property.

service_type property

The service_type property.

Returns:

Type Description
ServiceType

the value of the property.

state property

The state property.

Returns:

Type Description
Optional[ServiceState]

the value of the property.

status property

The status property.

Returns:

Type Description
Optional[Dict[str, Any]]

the value of the property.

updated property

The updated property.

Returns:

Type Description
datetime

the value of the property.

get_hydrated_version()

Get the hydrated version of this artifact.

Returns:

Type Description
ServiceResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/service.py
246
247
248
249
250
251
252
253
254
def get_hydrated_version(self) -> "ServiceResponse":
    """Get the hydrated version of this artifact.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_service(self.id)

ServiceResponseBody

Bases: WorkspaceScopedResponseBody

Response body for services.

Source code in src/zenml/models/v2/core/service.py
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
class ServiceResponseBody(WorkspaceScopedResponseBody):
    """Response body for services."""

    service_type: ServiceType = Field(
        title="The type of the service.",
    )
    labels: Optional[Dict[str, str]] = Field(
        default=None,
        title="The service labels.",
    )
    created: datetime = Field(
        title="The timestamp when this component was created."
    )
    updated: datetime = Field(
        title="The timestamp when this component was last updated.",
    )
    state: Optional[ServiceState] = Field(
        default=None,
        title="The current state of the service.",
    )

ServiceResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for services.

Source code in src/zenml/models/v2/core/service.py
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
class ServiceResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for services."""

    service_source: Optional[str] = Field(
        title="The class of the service.",
    )
    admin_state: Optional[ServiceState] = Field(
        title="The admin state of the service.",
    )
    config: Dict[str, Any] = Field(
        title="The service config.",
    )
    status: Optional[Dict[str, Any]] = Field(
        title="The status of the service.",
    )
    endpoint: Optional[Dict[str, Any]] = Field(
        default=None,
        title="The service endpoint.",
    )
    prediction_url: Optional[str] = Field(
        default=None,
        title="The service endpoint URL.",
    )
    health_check_url: Optional[str] = Field(
        default=None,
        title="The service health check URL.",
    )

ServiceResponseResources

Bases: WorkspaceScopedResponseResources

Class for all resource models associated with the service entity.

Source code in src/zenml/models/v2/core/service.py
230
231
class ServiceResponseResources(WorkspaceScopedResponseResources):
    """Class for all resource models associated with the service entity."""

ServiceUpdate

Bases: BaseModel

Update model for stack components.

Source code in src/zenml/models/v2/core/service.py
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
class ServiceUpdate(BaseModel):
    """Update model for stack components."""

    name: Optional[str] = Field(
        None,
        title="The name of the service.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    admin_state: Optional[ServiceState] = Field(
        None,
        title="The admin state of the service.",
        description="The administrative state of the service, e.g., ACTIVE, "
        "INACTIVE.",
    )
    service_source: Optional[str] = Field(
        None,
        title="The class of the service.",
        description="The fully qualified class name of the service "
        "implementation.",
    )
    status: Optional[Dict[str, Any]] = Field(
        None,
        title="The status of the service.",
    )
    endpoint: Optional[Dict[str, Any]] = Field(
        None,
        title="The service endpoint.",
    )
    prediction_url: Optional[str] = Field(
        None,
        title="The service endpoint URL.",
    )
    health_check_url: Optional[str] = Field(
        None,
        title="The service health check URL.",
    )
    labels: Optional[Dict[str, str]] = Field(
        default=None,
        title="The service labels.",
    )
    model_version_id: Optional[UUID] = Field(
        default=None,
        title="The model version id linked to the service.",
    )

    # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
    #  fields defined under base models. If not handled, this raises a warning.
    #  It is possible to suppress this warning message with the following
    #  configuration, however the ultimate solution is to rename these fields.
    #  Even though they do not cause any problems right now, if we are not
    #  careful we might overwrite some fields protected by pydantic.
    model_config = ConfigDict(protected_namespaces=())

StackDeploymentConfig

Bases: BaseModel

Configuration about a stack deployment.

Source code in src/zenml/models/v2/misc/stack_deployment.py
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
class StackDeploymentConfig(BaseModel):
    """Configuration about a stack deployment."""

    deployment_url: str = Field(
        title="The cloud provider console URL where the stack will be deployed.",
    )
    deployment_url_text: str = Field(
        title="A textual description for the cloud provider console URL.",
    )
    configuration: Optional[str] = Field(
        default=None,
        title="Configuration for the stack deployment that the user must "
        "manually configure into the cloud provider console.",
    )
    instructions: Optional[str] = Field(
        default=None,
        title="Instructions for deploying the stack.",
    )

StackDeploymentInfo

Bases: BaseModel

Information about a stack deployment.

Source code in src/zenml/models/v2/misc/stack_deployment.py
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class StackDeploymentInfo(BaseModel):
    """Information about a stack deployment."""

    provider: StackDeploymentProvider = Field(
        title="The provider of the stack deployment."
    )
    description: str = Field(
        title="The description of the stack deployment.",
        description="The description of the stack deployment.",
    )
    instructions: str = Field(
        title="The instructions for deploying the stack.",
        description="The instructions for deploying the stack.",
    )
    post_deploy_instructions: str = Field(
        title="The instructions for post-deployment.",
        description="The instructions for post-deployment.",
    )
    integrations: List[str] = Field(
        title="ZenML integrations required for the stack.",
        description="The list of ZenML integrations that need to be installed "
        "for the stack to be usable.",
    )
    permissions: Dict[str, List[str]] = Field(
        title="The permissions granted to ZenML to access the cloud resources.",
        description="The permissions granted to ZenML to access the cloud "
        "resources, as a dictionary grouping permissions by resource.",
    )
    locations: Dict[str, str] = Field(
        title="The locations where the stack can be deployed.",
        description="The locations where the stack can be deployed, as a "
        "dictionary mapping location names to descriptions.",
    )
    skypilot_default_regions: Dict[str, str] = Field(
        title="The locations where the Skypilot clusters can be deployed by default.",
        description="The locations where the Skypilot clusters can be deployed by default, as a "
        "dictionary mapping location names to descriptions.",
    )

StackFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of all StackModels.

The Stack Model needs additional scoping. As such the _scope_user field can be set to the user that is doing the filtering. The generate_filter() method of the baseclass is overwritten to include the scoping.

Source code in src/zenml/models/v2/core/stack.py
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
class StackFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of all StackModels.

    The Stack Model needs additional scoping. As such the `_scope_user` field
    can be set to the user that is doing the filtering. The
    `generate_filter()` method of the baseclass is overwritten to include the
    scoping.
    """

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
        "component_id",
        "component",
    ]

    name: Optional[str] = Field(
        default=None,
        description="Name of the stack",
    )
    description: Optional[str] = Field(
        default=None, description="Description of the stack"
    )
    component_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Component in the stack",
        union_mode="left_to_right",
    )
    component: Optional[Union[UUID, str]] = Field(
        default=None, description="Name/ID of a component in the stack."
    )

    def get_custom_filters(
        self, table: Type["AnySchema"]
    ) -> List["ColumnElement[bool]"]:
        """Get custom filters.

        Args:
            table: The query table.

        Returns:
            A list of custom filters.
        """
        custom_filters = super().get_custom_filters(table)

        from zenml.zen_stores.schemas import (
            StackComponentSchema,
            StackCompositionSchema,
            StackSchema,
        )

        if self.component_id:
            component_id_filter = and_(
                StackCompositionSchema.stack_id == StackSchema.id,
                StackCompositionSchema.component_id == self.component_id,
            )
            custom_filters.append(component_id_filter)

        if self.component:
            component_filter = and_(
                StackCompositionSchema.stack_id == StackSchema.id,
                StackCompositionSchema.component_id == StackComponentSchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.component,
                    table=StackComponentSchema,
                ),
            )
            custom_filters.append(component_filter)

        return custom_filters

get_custom_filters(table)

Get custom filters.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
List[ColumnElement[bool]]

A list of custom filters.

Source code in src/zenml/models/v2/core/stack.py
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
def get_custom_filters(
    self, table: Type["AnySchema"]
) -> List["ColumnElement[bool]"]:
    """Get custom filters.

    Args:
        table: The query table.

    Returns:
        A list of custom filters.
    """
    custom_filters = super().get_custom_filters(table)

    from zenml.zen_stores.schemas import (
        StackComponentSchema,
        StackCompositionSchema,
        StackSchema,
    )

    if self.component_id:
        component_id_filter = and_(
            StackCompositionSchema.stack_id == StackSchema.id,
            StackCompositionSchema.component_id == self.component_id,
        )
        custom_filters.append(component_id_filter)

    if self.component:
        component_filter = and_(
            StackCompositionSchema.stack_id == StackSchema.id,
            StackCompositionSchema.component_id == StackComponentSchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.component,
                table=StackComponentSchema,
            ),
        )
        custom_filters.append(component_filter)

    return custom_filters

StackRequest

Bases: BaseRequest

Request model for a stack.

Source code in src/zenml/models/v2/core/stack.py
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
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
class StackRequest(BaseRequest):
    """Request model for a stack."""

    user: Optional[UUID] = None
    workspace: Optional[UUID] = None

    name: str = Field(
        title="The name of the stack.", max_length=STR_FIELD_MAX_LENGTH
    )
    description: str = Field(
        default="",
        title="The description of the stack",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    stack_spec_path: Optional[str] = Field(
        default=None,
        title="The path to the stack spec used for mlstacks deployments.",
    )
    components: Dict[StackComponentType, List[Union[UUID, ComponentInfo]]] = (
        Field(
            title="The mapping for the components of the full stack registration.",
            description="The mapping from component types to either UUIDs of "
            "existing components or request information for brand new "
            "components.",
        )
    )
    labels: Optional[Dict[str, Any]] = Field(
        default=None,
        title="The stack labels.",
    )
    service_connectors: List[Union[UUID, ServiceConnectorInfo]] = Field(
        default=[],
        title="The service connectors dictionary for the full stack "
        "registration.",
        description="The UUID of an already existing service connector or "
        "request information to create a service connector from "
        "scratch.",
    )

    @property
    def is_valid(self) -> bool:
        """Check if the stack is valid.

        Returns:
            True if the stack is valid, False otherwise.
        """
        if not self.components:
            return False
        return (
            StackComponentType.ARTIFACT_STORE in self.components
            and StackComponentType.ORCHESTRATOR in self.components
        )

    @model_validator(mode="after")
    def _validate_indexes_in_components(self) -> "StackRequest":
        for components in self.components.values():
            for component in components:
                if isinstance(component, ComponentInfo):
                    if component.service_connector_index is not None:
                        if (
                            component.service_connector_index < 0
                            or component.service_connector_index
                            >= len(self.service_connectors)
                        ):
                            raise ValueError(
                                f"Service connector index "
                                f"{component.service_connector_index} "
                                "is out of range. Please provide a valid index "
                                "referring to the position in the list of service "
                                "connectors."
                            )
        return self

is_valid property

Check if the stack is valid.

Returns:

Type Description
bool

True if the stack is valid, False otherwise.

StackResponse

Bases: WorkspaceScopedResponse[StackResponseBody, StackResponseMetadata, StackResponseResources]

Response model for stacks.

Source code in src/zenml/models/v2/core/stack.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
class StackResponse(
    WorkspaceScopedResponse[
        StackResponseBody, StackResponseMetadata, StackResponseResources
    ]
):
    """Response model for stacks."""

    name: str = Field(
        title="The name of the stack.", max_length=STR_FIELD_MAX_LENGTH
    )

    def get_hydrated_version(self) -> "StackResponse":
        """Get the hydrated version of this stack.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_stack(self.id)

    # Helper methods
    @property
    def is_valid(self) -> bool:
        """Check if the stack is valid.

        Returns:
            True if the stack is valid, False otherwise.
        """
        return (
            StackComponentType.ARTIFACT_STORE in self.components
            and StackComponentType.ORCHESTRATOR in self.components
        )

    def to_yaml(self) -> Dict[str, Any]:
        """Create yaml representation of the Stack Model.

        Returns:
            The yaml representation of the Stack Model.
        """
        component_data = {}
        for component_type, components_list in self.components.items():
            component = components_list[0]
            component_dict = dict(
                name=component.name,
                type=str(component.type),
                flavor=component.flavor_name,
            )
            configuration = json.loads(
                component.get_metadata().model_dump_json(
                    include={"configuration"}
                )
            )
            component_dict.update(configuration)

            component_data[component_type.value] = component_dict

        # write zenml version and stack dict to YAML
        yaml_data = {
            "stack_name": self.name,
            "components": component_data,
        }

        return yaml_data

    # Analytics
    def get_analytics_metadata(self) -> Dict[str, Any]:
        """Add the stack components to the stack analytics metadata.

        Returns:
            Dict of analytics metadata.
        """
        metadata = super().get_analytics_metadata()
        metadata.update(
            {ct: c[0].flavor_name for ct, c in self.components.items()}
        )

        if self.labels is not None:
            metadata.update(
                {
                    label[6:]: value
                    for label, value in self.labels.items()
                    if label.startswith("zenml:")
                }
            )
        return metadata

    @property
    def description(self) -> Optional[str]:
        """The `description` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().description

    @property
    def stack_spec_path(self) -> Optional[str]:
        """The `stack_spec_path` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().stack_spec_path

    @property
    def components(
        self,
    ) -> Dict[StackComponentType, List["ComponentResponse"]]:
        """The `components` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().components

    @property
    def labels(self) -> Optional[Dict[str, Any]]:
        """The `labels` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().labels

components property

The components property.

Returns:

Type Description
Dict[StackComponentType, List[ComponentResponse]]

the value of the property.

description property

The description property.

Returns:

Type Description
Optional[str]

the value of the property.

is_valid property

Check if the stack is valid.

Returns:

Type Description
bool

True if the stack is valid, False otherwise.

labels property

The labels property.

Returns:

Type Description
Optional[Dict[str, Any]]

the value of the property.

stack_spec_path property

The stack_spec_path property.

Returns:

Type Description
Optional[str]

the value of the property.

get_analytics_metadata()

Add the stack components to the stack analytics metadata.

Returns:

Type Description
Dict[str, Any]

Dict of analytics metadata.

Source code in src/zenml/models/v2/core/stack.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
def get_analytics_metadata(self) -> Dict[str, Any]:
    """Add the stack components to the stack analytics metadata.

    Returns:
        Dict of analytics metadata.
    """
    metadata = super().get_analytics_metadata()
    metadata.update(
        {ct: c[0].flavor_name for ct, c in self.components.items()}
    )

    if self.labels is not None:
        metadata.update(
            {
                label[6:]: value
                for label, value in self.labels.items()
                if label.startswith("zenml:")
            }
        )
    return metadata

get_hydrated_version()

Get the hydrated version of this stack.

Returns:

Type Description
StackResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/stack.py
209
210
211
212
213
214
215
216
217
def get_hydrated_version(self) -> "StackResponse":
    """Get the hydrated version of this stack.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_stack(self.id)

to_yaml()

Create yaml representation of the Stack Model.

Returns:

Type Description
Dict[str, Any]

The yaml representation of the Stack Model.

Source code in src/zenml/models/v2/core/stack.py
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
def to_yaml(self) -> Dict[str, Any]:
    """Create yaml representation of the Stack Model.

    Returns:
        The yaml representation of the Stack Model.
    """
    component_data = {}
    for component_type, components_list in self.components.items():
        component = components_list[0]
        component_dict = dict(
            name=component.name,
            type=str(component.type),
            flavor=component.flavor_name,
        )
        configuration = json.loads(
            component.get_metadata().model_dump_json(
                include={"configuration"}
            )
        )
        component_dict.update(configuration)

        component_data[component_type.value] = component_dict

    # write zenml version and stack dict to YAML
    yaml_data = {
        "stack_name": self.name,
        "components": component_data,
    }

    return yaml_data

StackResponseBody

Bases: WorkspaceScopedResponseBody

Response body for stacks.

Source code in src/zenml/models/v2/core/stack.py
168
169
class StackResponseBody(WorkspaceScopedResponseBody):
    """Response body for stacks."""

StackResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for stacks.

Source code in src/zenml/models/v2/core/stack.py
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
class StackResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for stacks."""

    components: Dict[StackComponentType, List["ComponentResponse"]] = Field(
        title="A mapping of stack component types to the actual"
        "instances of components of this type."
    )
    description: Optional[str] = Field(
        default="",
        title="The description of the stack",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    stack_spec_path: Optional[str] = Field(
        default=None,
        title="The path to the stack spec used for mlstacks deployments.",
    )
    labels: Optional[Dict[str, Any]] = Field(
        default=None,
        title="The stack labels.",
    )

StackUpdate

Bases: BaseUpdate

Update model for stacks.

Source code in src/zenml/models/v2/core/stack.py
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
class StackUpdate(BaseUpdate):
    """Update model for stacks."""

    name: Optional[str] = Field(
        title="The name of the stack.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    description: Optional[str] = Field(
        title="The description of the stack",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    stack_spec_path: Optional[str] = Field(
        title="The path to the stack spec used for mlstacks deployments.",
        default=None,
    )
    components: Optional[Dict[StackComponentType, List[UUID]]] = Field(
        title="A mapping of stack component types to the actual"
        "instances of components of this type.",
        default=None,
    )
    labels: Optional[Dict[str, Any]] = Field(
        default=None,
        title="The stack labels.",
    )

StepRunFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of step runs.

Source code in src/zenml/models/v2/core/step_run.py
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
class StepRunFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of step runs."""

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
        "model",
        "run_metadata",
    ]

    name: Optional[str] = Field(
        default=None,
        description="Name of the step run",
    )
    code_hash: Optional[str] = Field(
        default=None,
        description="Code hash for this step run",
    )
    cache_key: Optional[str] = Field(
        default=None,
        description="Cache key for this step run",
    )
    status: Optional[str] = Field(
        default=None,
        description="Status of the Step Run",
    )
    start_time: Optional[Union[datetime, str]] = Field(
        default=None,
        description="Start time for this run",
        union_mode="left_to_right",
    )
    end_time: Optional[Union[datetime, str]] = Field(
        default=None,
        description="End time for this run",
        union_mode="left_to_right",
    )
    pipeline_run_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Pipeline run of this step run",
        union_mode="left_to_right",
    )
    deployment_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Deployment of this step run",
        union_mode="left_to_right",
    )
    original_step_run_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Original id for this step run",
        union_mode="left_to_right",
    )
    model_version_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Model version associated with the step run.",
        union_mode="left_to_right",
    )
    model: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of the model associated with the step run.",
    )
    run_metadata: Optional[Dict[str, Any]] = Field(
        default=None,
        description="The run_metadata to filter the step runs by.",
    )
    model_config = ConfigDict(protected_namespaces=())

    def get_custom_filters(
        self, table: Type["AnySchema"]
    ) -> List["ColumnElement[bool]"]:
        """Get custom filters.

        Args:
            table: The query table.

        Returns:
            A list of custom filters.
        """
        custom_filters = super().get_custom_filters(table)

        from sqlmodel import and_

        from zenml.zen_stores.schemas import (
            ModelSchema,
            ModelVersionSchema,
            RunMetadataResourceSchema,
            RunMetadataSchema,
            StepRunSchema,
        )

        if self.model:
            model_filter = and_(
                StepRunSchema.model_version_id == ModelVersionSchema.id,
                ModelVersionSchema.model_id == ModelSchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.model, table=ModelSchema
                ),
            )
            custom_filters.append(model_filter)
        if self.run_metadata is not None:
            from zenml.enums import MetadataResourceTypes

            for key, value in self.run_metadata.items():
                additional_filter = and_(
                    RunMetadataResourceSchema.resource_id == StepRunSchema.id,
                    RunMetadataResourceSchema.resource_type
                    == MetadataResourceTypes.STEP_RUN.value,
                    RunMetadataResourceSchema.run_metadata_id
                    == RunMetadataSchema.id,
                    self.generate_custom_query_conditions_for_column(
                        value=key,
                        table=RunMetadataSchema,
                        column="key",
                    ),
                    self.generate_custom_query_conditions_for_column(
                        value=value,
                        table=RunMetadataSchema,
                        column="value",
                        json_encode_value=True,
                    ),
                )
                custom_filters.append(additional_filter)

        return custom_filters

get_custom_filters(table)

Get custom filters.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
List[ColumnElement[bool]]

A list of custom filters.

Source code in src/zenml/models/v2/core/step_run.py
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
def get_custom_filters(
    self, table: Type["AnySchema"]
) -> List["ColumnElement[bool]"]:
    """Get custom filters.

    Args:
        table: The query table.

    Returns:
        A list of custom filters.
    """
    custom_filters = super().get_custom_filters(table)

    from sqlmodel import and_

    from zenml.zen_stores.schemas import (
        ModelSchema,
        ModelVersionSchema,
        RunMetadataResourceSchema,
        RunMetadataSchema,
        StepRunSchema,
    )

    if self.model:
        model_filter = and_(
            StepRunSchema.model_version_id == ModelVersionSchema.id,
            ModelVersionSchema.model_id == ModelSchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.model, table=ModelSchema
            ),
        )
        custom_filters.append(model_filter)
    if self.run_metadata is not None:
        from zenml.enums import MetadataResourceTypes

        for key, value in self.run_metadata.items():
            additional_filter = and_(
                RunMetadataResourceSchema.resource_id == StepRunSchema.id,
                RunMetadataResourceSchema.resource_type
                == MetadataResourceTypes.STEP_RUN.value,
                RunMetadataResourceSchema.run_metadata_id
                == RunMetadataSchema.id,
                self.generate_custom_query_conditions_for_column(
                    value=key,
                    table=RunMetadataSchema,
                    column="key",
                ),
                self.generate_custom_query_conditions_for_column(
                    value=value,
                    table=RunMetadataSchema,
                    column="value",
                    json_encode_value=True,
                ),
            )
            custom_filters.append(additional_filter)

    return custom_filters

StepRunRequest

Bases: WorkspaceScopedRequest

Request model for step runs.

Source code in src/zenml/models/v2/core/step_run.py
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
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
class StepRunRequest(WorkspaceScopedRequest):
    """Request model for step runs."""

    name: str = Field(
        title="The name of the pipeline run step.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    start_time: Optional[datetime] = Field(
        title="The start time of the step run.",
        default=None,
    )
    end_time: Optional[datetime] = Field(
        title="The end time of the step run.",
        default=None,
    )
    status: ExecutionStatus = Field(title="The status of the step.")
    cache_key: Optional[str] = Field(
        title="The cache key of the step run.",
        default=None,
        max_length=STR_FIELD_MAX_LENGTH,
    )
    code_hash: Optional[str] = Field(
        title="The code hash of the step run.",
        default=None,
        max_length=STR_FIELD_MAX_LENGTH,
    )
    docstring: Optional[str] = Field(
        title="The docstring of the step function or class.",
        default=None,
        max_length=TEXT_FIELD_MAX_LENGTH,
    )
    source_code: Optional[str] = Field(
        title="The source code of the step function or class.",
        default=None,
        max_length=TEXT_FIELD_MAX_LENGTH,
    )
    pipeline_run_id: UUID = Field(
        title="The ID of the pipeline run that this step run belongs to.",
    )
    original_step_run_id: Optional[UUID] = Field(
        title="The ID of the original step run if this step was cached.",
        default=None,
    )
    parent_step_ids: List[UUID] = Field(
        title="The IDs of the parent steps of this step run.",
        default_factory=list,
    )
    inputs: Dict[str, UUID] = Field(
        title="The IDs of the input artifact versions of the step run.",
        default_factory=dict,
    )
    outputs: Dict[str, List[UUID]] = Field(
        title="The IDs of the output artifact versions of the step run.",
        default_factory=dict,
    )
    logs: Optional["LogsRequest"] = Field(
        title="Logs associated with this step run.",
        default=None,
    )
    deployment: UUID = Field(
        title="The deployment associated with the step run."
    )
    model_version_id: Optional[UUID] = Field(
        title="The ID of the model version that was "
        "configured by this step run explicitly.",
        default=None,
    )

    model_config = ConfigDict(protected_namespaces=())

StepRunResponse

Bases: WorkspaceScopedResponse[StepRunResponseBody, StepRunResponseMetadata, StepRunResponseResources]

Response model for step runs.

Source code in src/zenml/models/v2/core/step_run.py
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
class StepRunResponse(
    WorkspaceScopedResponse[
        StepRunResponseBody, StepRunResponseMetadata, StepRunResponseResources
    ]
):
    """Response model for step runs."""

    name: str = Field(
        title="The name of the pipeline run step.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "StepRunResponse":
        """Get the hydrated version of this step run.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_run_step(self.id)

    # Helper properties
    @property
    def input(self) -> ArtifactVersionResponse:
        """Returns the input artifact that was used to run this step.

        Returns:
            The input artifact.

        Raises:
            ValueError: If there were zero or multiple inputs to this step.
        """
        if not self.inputs:
            raise ValueError(f"Step {self.name} has no inputs.")
        if len(self.inputs) > 1:
            raise ValueError(
                f"Step {self.name} has multiple inputs, so `Step.input` is "
                "ambiguous. Please use `Step.inputs` instead."
            )
        return next(iter(self.inputs.values()))

    @property
    def output(self) -> ArtifactVersionResponse:
        """Returns the output artifact that was written by this step.

        Returns:
            The output artifact.

        Raises:
            ValueError: If there were zero or multiple step outputs.
        """
        if not self.outputs:
            raise ValueError(f"Step {self.name} has no outputs.")
        if len(self.outputs) > 1 or (
            len(self.outputs) == 1
            and len(next(iter(self.outputs.values()))) > 1
        ):
            raise ValueError(
                f"Step {self.name} has multiple outputs, so `Step.output` is "
                "ambiguous. Please use `Step.outputs` instead."
            )
        return next(iter(self.outputs.values()))[0]

    # Body and metadata properties
    @property
    def status(self) -> ExecutionStatus:
        """The `status` property.

        Returns:
            the value of the property.
        """
        return self.get_body().status

    @property
    def inputs(self) -> Dict[str, StepRunInputResponse]:
        """The `inputs` property.

        Returns:
            the value of the property.
        """
        return self.get_body().inputs

    @property
    def outputs(self) -> Dict[str, List[ArtifactVersionResponse]]:
        """The `outputs` property.

        Returns:
            the value of the property.
        """
        return self.get_body().outputs

    @property
    def model_version_id(self) -> Optional[UUID]:
        """The `model_version_id` property.

        Returns:
            the value of the property.
        """
        return self.get_body().model_version_id

    @property
    def config(self) -> "StepConfiguration":
        """The `config` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().config

    @property
    def spec(self) -> "StepSpec":
        """The `spec` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().spec

    @property
    def cache_key(self) -> Optional[str]:
        """The `cache_key` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().cache_key

    @property
    def code_hash(self) -> Optional[str]:
        """The `code_hash` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().code_hash

    @property
    def docstring(self) -> Optional[str]:
        """The `docstring` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().docstring

    @property
    def source_code(self) -> Optional[str]:
        """The `source_code` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().source_code

    @property
    def start_time(self) -> Optional[datetime]:
        """The `start_time` property.

        Returns:
            the value of the property.
        """
        return self.get_body().start_time

    @property
    def end_time(self) -> Optional[datetime]:
        """The `end_time` property.

        Returns:
            the value of the property.
        """
        return self.get_body().end_time

    @property
    def logs(self) -> Optional["LogsResponse"]:
        """The `logs` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().logs

    @property
    def deployment_id(self) -> UUID:
        """The `deployment_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().deployment_id

    @property
    def pipeline_run_id(self) -> UUID:
        """The `pipeline_run_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().pipeline_run_id

    @property
    def original_step_run_id(self) -> Optional[UUID]:
        """The `original_step_run_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().original_step_run_id

    @property
    def parent_step_ids(self) -> List[UUID]:
        """The `parent_step_ids` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().parent_step_ids

    @property
    def run_metadata(self) -> Dict[str, MetadataType]:
        """The `run_metadata` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().run_metadata

    @property
    def model_version(self) -> Optional[ModelVersionResponse]:
        """The `model_version` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().model_version

cache_key property

The cache_key property.

Returns:

Type Description
Optional[str]

the value of the property.

code_hash property

The code_hash property.

Returns:

Type Description
Optional[str]

the value of the property.

config property

The config property.

Returns:

Type Description
StepConfiguration

the value of the property.

deployment_id property

The deployment_id property.

Returns:

Type Description
UUID

the value of the property.

docstring property

The docstring property.

Returns:

Type Description
Optional[str]

the value of the property.

end_time property

The end_time property.

Returns:

Type Description
Optional[datetime]

the value of the property.

input property

Returns the input artifact that was used to run this step.

Returns:

Type Description
ArtifactVersionResponse

The input artifact.

Raises:

Type Description
ValueError

If there were zero or multiple inputs to this step.

inputs property

The inputs property.

Returns:

Type Description
Dict[str, StepRunInputResponse]

the value of the property.

logs property

The logs property.

Returns:

Type Description
Optional[LogsResponse]

the value of the property.

model_version property

The model_version property.

Returns:

Type Description
Optional[ModelVersionResponse]

the value of the property.

model_version_id property

The model_version_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

original_step_run_id property

The original_step_run_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

output property

Returns the output artifact that was written by this step.

Returns:

Type Description
ArtifactVersionResponse

The output artifact.

Raises:

Type Description
ValueError

If there were zero or multiple step outputs.

outputs property

The outputs property.

Returns:

Type Description
Dict[str, List[ArtifactVersionResponse]]

the value of the property.

parent_step_ids property

The parent_step_ids property.

Returns:

Type Description
List[UUID]

the value of the property.

pipeline_run_id property

The pipeline_run_id property.

Returns:

Type Description
UUID

the value of the property.

run_metadata property

The run_metadata property.

Returns:

Type Description
Dict[str, MetadataType]

the value of the property.

source_code property

The source_code property.

Returns:

Type Description
Optional[str]

the value of the property.

spec property

The spec property.

Returns:

Type Description
StepSpec

the value of the property.

start_time property

The start_time property.

Returns:

Type Description
Optional[datetime]

the value of the property.

status property

The status property.

Returns:

Type Description
ExecutionStatus

the value of the property.

get_hydrated_version()

Get the hydrated version of this step run.

Returns:

Type Description
StepRunResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/step_run.py
291
292
293
294
295
296
297
298
299
def get_hydrated_version(self) -> "StepRunResponse":
    """Get the hydrated version of this step run.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_run_step(self.id)

StepRunResponseBody

Bases: WorkspaceScopedResponseBody

Response body for step runs.

Source code in src/zenml/models/v2/core/step_run.py
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
class StepRunResponseBody(WorkspaceScopedResponseBody):
    """Response body for step runs."""

    status: ExecutionStatus = Field(title="The status of the step.")
    start_time: Optional[datetime] = Field(
        title="The start time of the step run.",
        default=None,
    )
    end_time: Optional[datetime] = Field(
        title="The end time of the step run.",
        default=None,
    )
    inputs: Dict[str, StepRunInputResponse] = Field(
        title="The input artifact versions of the step run.",
        default_factory=dict,
    )
    outputs: Dict[str, List[ArtifactVersionResponse]] = Field(
        title="The output artifact versions of the step run.",
        default_factory=dict,
    )
    model_version_id: Optional[UUID] = Field(
        title="The ID of the model version that was "
        "configured by this step run explicitly.",
        default=None,
    )
    model_config = ConfigDict(protected_namespaces=())

StepRunResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for step runs.

Source code in src/zenml/models/v2/core/step_run.py
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
class StepRunResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for step runs."""

    # Configuration
    config: "StepConfiguration" = Field(title="The configuration of the step.")
    spec: "StepSpec" = Field(title="The spec of the step.")

    # Code related fields
    cache_key: Optional[str] = Field(
        title="The cache key of the step run.",
        default=None,
        max_length=STR_FIELD_MAX_LENGTH,
    )
    code_hash: Optional[str] = Field(
        title="The code hash of the step run.",
        default=None,
        max_length=STR_FIELD_MAX_LENGTH,
    )
    docstring: Optional[str] = Field(
        title="The docstring of the step function or class.",
        default=None,
        max_length=TEXT_FIELD_MAX_LENGTH,
    )
    source_code: Optional[str] = Field(
        title="The source code of the step function or class.",
        default=None,
        max_length=TEXT_FIELD_MAX_LENGTH,
    )

    # References
    logs: Optional["LogsResponse"] = Field(
        title="Logs associated with this step run.",
        default=None,
    )
    deployment_id: UUID = Field(
        title="The deployment associated with the step run."
    )
    pipeline_run_id: UUID = Field(
        title="The ID of the pipeline run that this step run belongs to.",
    )
    original_step_run_id: Optional[UUID] = Field(
        title="The ID of the original step run if this step was cached.",
        default=None,
    )
    parent_step_ids: List[UUID] = Field(
        title="The IDs of the parent steps of this step run.",
        default_factory=list,
    )
    run_metadata: Dict[str, MetadataType] = Field(
        title="Metadata associated with this step run.",
        default={},
    )

StepRunResponseResources

Bases: WorkspaceScopedResponseResources

Class for all resource models associated with the step run entity.

Source code in src/zenml/models/v2/core/step_run.py
265
266
267
268
269
270
271
272
273
274
275
276
class StepRunResponseResources(WorkspaceScopedResponseResources):
    """Class for all resource models associated with the step run entity."""

    model_version: Optional[ModelVersionResponse] = None

    # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
    #  fields defined under base models. If not handled, this raises a warning.
    #  It is possible to suppress this warning message with the following
    #  configuration, however the ultimate solution is to rename these fields.
    #  Even though they do not cause any problems right now, if we are not
    #  careful we might overwrite some fields protected by pydantic.
    model_config = ConfigDict(protected_namespaces=())

StepRunUpdate

Bases: BaseModel

Update model for step runs.

Source code in src/zenml/models/v2/core/step_run.py
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
class StepRunUpdate(BaseModel):
    """Update model for step runs."""

    outputs: Dict[str, List[UUID]] = Field(
        title="The IDs of the output artifact versions of the step run.",
        default={},
    )
    loaded_artifact_versions: Dict[str, UUID] = Field(
        title="The IDs of artifact versions that were loaded by this step run.",
        default={},
    )
    status: Optional[ExecutionStatus] = Field(
        title="The status of the step.",
        default=None,
    )
    end_time: Optional[datetime] = Field(
        title="The end time of the step run.",
        default=None,
    )
    model_version_id: Optional[UUID] = Field(
        title="The ID of the model version that was "
        "configured by this step run explicitly.",
        default=None,
    )
    model_config = ConfigDict(protected_namespaces=())

StrFilter

Bases: Filter

Filter for all string fields.

Source code in src/zenml/models/v2/base/filter.py
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
class StrFilter(Filter):
    """Filter for all string fields."""

    json_encode_value: bool = False

    ALLOWED_OPS: ClassVar[List[str]] = [
        GenericFilterOps.EQUALS,
        GenericFilterOps.NOT_EQUALS,
        GenericFilterOps.STARTSWITH,
        GenericFilterOps.CONTAINS,
        GenericFilterOps.ENDSWITH,
        GenericFilterOps.ONEOF,
        GenericFilterOps.GT,
        GenericFilterOps.GTE,
        GenericFilterOps.LT,
        GenericFilterOps.LTE,
    ]

    @model_validator(mode="after")
    def check_value_if_operation_oneof(self) -> "StrFilter":
        """Validator to check if value is a list if oneof operation is used.

        Raises:
            ValueError: If the value is not a list

        Returns:
            self
        """
        if self.operation == GenericFilterOps.ONEOF:
            if not isinstance(self.value, list):
                raise ValueError(ONEOF_ERROR)
        return self

    def generate_query_conditions_from_column(self, column: Any) -> Any:
        """Generate query conditions for a string column.

        Args:
            column: The string column of an SQLModel table on which to filter.

        Returns:
            A list of query conditions.

        Raises:
            ValueError: the comparison of the column to a numeric value fails.
        """
        if self.operation in {
            GenericFilterOps.GT,
            GenericFilterOps.LT,
            GenericFilterOps.GTE,
            GenericFilterOps.LTE,
        }:
            try:
                numeric_column = cast(column, Float)

                assert self.value is not None

                if self.operation == GenericFilterOps.GT:
                    return and_(
                        numeric_column, numeric_column > float(self.value)
                    )
                if self.operation == GenericFilterOps.LT:
                    return and_(
                        numeric_column, numeric_column < float(self.value)
                    )
                if self.operation == GenericFilterOps.GTE:
                    return and_(
                        numeric_column, numeric_column >= float(self.value)
                    )
                if self.operation == GenericFilterOps.LTE:
                    return and_(
                        numeric_column, numeric_column <= float(self.value)
                    )
            except Exception as e:
                raise ValueError(
                    f"Failed to compare the column '{column}' to the "
                    f"value '{self.value}' (must be numeric): {e}"
                )

        if self.operation == GenericFilterOps.ONEOF:
            assert isinstance(self.value, list)
            # Convert the list of values to a list of json strings
            json_list = (
                [json.dumps(v) for v in self.value]
                if self.json_encode_value
                else self.value
            )
            return column.in_(json_list)

        # Don't convert the value to a json string if the operation is contains
        # because the quotes around strings will mess with the comparison
        if self.operation == GenericFilterOps.CONTAINS:
            return column.like(f"%{self.value}%")

        json_value = (
            json.dumps(self.value) if self.json_encode_value else self.value
        )

        if self.operation == GenericFilterOps.STARTSWITH:
            return column.startswith(f"{json_value}")
        if self.operation == GenericFilterOps.ENDSWITH:
            return column.endswith(f"{json_value}")
        if self.operation == GenericFilterOps.NOT_EQUALS:
            return column != json_value

        return column == json_value

check_value_if_operation_oneof()

Validator to check if value is a list if oneof operation is used.

Raises:

Type Description
ValueError

If the value is not a list

Returns:

Type Description
StrFilter

self

Source code in src/zenml/models/v2/base/filter.py
189
190
191
192
193
194
195
196
197
198
199
200
201
202
@model_validator(mode="after")
def check_value_if_operation_oneof(self) -> "StrFilter":
    """Validator to check if value is a list if oneof operation is used.

    Raises:
        ValueError: If the value is not a list

    Returns:
        self
    """
    if self.operation == GenericFilterOps.ONEOF:
        if not isinstance(self.value, list):
            raise ValueError(ONEOF_ERROR)
    return self

generate_query_conditions_from_column(column)

Generate query conditions for a string column.

Parameters:

Name Type Description Default
column Any

The string column of an SQLModel table on which to filter.

required

Returns:

Type Description
Any

A list of query conditions.

Raises:

Type Description
ValueError

the comparison of the column to a numeric value fails.

Source code in src/zenml/models/v2/base/filter.py
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
def generate_query_conditions_from_column(self, column: Any) -> Any:
    """Generate query conditions for a string column.

    Args:
        column: The string column of an SQLModel table on which to filter.

    Returns:
        A list of query conditions.

    Raises:
        ValueError: the comparison of the column to a numeric value fails.
    """
    if self.operation in {
        GenericFilterOps.GT,
        GenericFilterOps.LT,
        GenericFilterOps.GTE,
        GenericFilterOps.LTE,
    }:
        try:
            numeric_column = cast(column, Float)

            assert self.value is not None

            if self.operation == GenericFilterOps.GT:
                return and_(
                    numeric_column, numeric_column > float(self.value)
                )
            if self.operation == GenericFilterOps.LT:
                return and_(
                    numeric_column, numeric_column < float(self.value)
                )
            if self.operation == GenericFilterOps.GTE:
                return and_(
                    numeric_column, numeric_column >= float(self.value)
                )
            if self.operation == GenericFilterOps.LTE:
                return and_(
                    numeric_column, numeric_column <= float(self.value)
                )
        except Exception as e:
            raise ValueError(
                f"Failed to compare the column '{column}' to the "
                f"value '{self.value}' (must be numeric): {e}"
            )

    if self.operation == GenericFilterOps.ONEOF:
        assert isinstance(self.value, list)
        # Convert the list of values to a list of json strings
        json_list = (
            [json.dumps(v) for v in self.value]
            if self.json_encode_value
            else self.value
        )
        return column.in_(json_list)

    # Don't convert the value to a json string if the operation is contains
    # because the quotes around strings will mess with the comparison
    if self.operation == GenericFilterOps.CONTAINS:
        return column.like(f"%{self.value}%")

    json_value = (
        json.dumps(self.value) if self.json_encode_value else self.value
    )

    if self.operation == GenericFilterOps.STARTSWITH:
        return column.startswith(f"{json_value}")
    if self.operation == GenericFilterOps.ENDSWITH:
        return column.endswith(f"{json_value}")
    if self.operation == GenericFilterOps.NOT_EQUALS:
        return column != json_value

    return column == json_value

TagFilter

Bases: BaseFilter

Model to enable advanced filtering of all tags.

Source code in src/zenml/models/v2/core/tag.py
121
122
123
124
125
126
127
128
129
class TagFilter(BaseFilter):
    """Model to enable advanced filtering of all tags."""

    name: Optional[str] = Field(
        description="The unique title of the tag.", default=None
    )
    color: Optional[ColorVariants] = Field(
        description="The color variant assigned to the tag.", default=None
    )

TagRequest

Bases: BaseRequest

Request model for tags.

Source code in src/zenml/models/v2/core/tag.py
35
36
37
38
39
40
41
42
43
44
45
class TagRequest(BaseRequest):
    """Request model for tags."""

    name: str = Field(
        description="The unique title of the tag.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    color: ColorVariants = Field(
        description="The color variant assigned to the tag.",
        default_factory=lambda: random.choice(list(ColorVariants)),
    )

TagResourceRequest

Bases: BaseRequest

Request model for links between tags and resources.

Source code in src/zenml/models/v2/core/tag_resource.py
30
31
32
33
34
35
class TagResourceRequest(BaseRequest):
    """Request model for links between tags and resources."""

    tag_id: UUID
    resource_id: UUID
    resource_type: TaggableResourceTypes

TagResourceResponse

Bases: BaseIdentifiedResponse[TagResourceResponseBody, BaseResponseMetadata, TagResourceResponseResources]

Response model for the links between tags and resources.

Source code in src/zenml/models/v2/core/tag_resource.py
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
class TagResourceResponse(
    BaseIdentifiedResponse[
        TagResourceResponseBody,
        BaseResponseMetadata,
        TagResourceResponseResources,
    ]
):
    """Response model for the links between tags and resources."""

    @property
    def tag_id(self) -> UUID:
        """The `tag_id` property.

        Returns:
            the value of the property.
        """
        return self.get_body().tag_id

    @property
    def resource_id(self) -> UUID:
        """The `resource_id` property.

        Returns:
            the value of the property.
        """
        return self.get_body().resource_id

    @property
    def resource_type(self) -> TaggableResourceTypes:
        """The `resource_type` property.

        Returns:
            the value of the property.
        """
        return self.get_body().resource_type

resource_id property

The resource_id property.

Returns:

Type Description
UUID

the value of the property.

resource_type property

The resource_type property.

Returns:

Type Description
TaggableResourceTypes

the value of the property.

tag_id property

The tag_id property.

Returns:

Type Description
UUID

the value of the property.

TagResourceResponseBody

Bases: BaseDatedResponseBody

Response body for the links between tags and resources.

Source code in src/zenml/models/v2/core/tag_resource.py
45
46
47
48
49
50
class TagResourceResponseBody(BaseDatedResponseBody):
    """Response body for the links between tags and resources."""

    tag_id: UUID
    resource_id: UUID
    resource_type: TaggableResourceTypes

TagResponse

Bases: BaseIdentifiedResponse[TagResponseBody, BaseResponseMetadata, TagResponseResources]

Response model for tags.

Source code in src/zenml/models/v2/core/tag.py
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
class TagResponse(
    BaseIdentifiedResponse[
        TagResponseBody, BaseResponseMetadata, TagResponseResources
    ]
):
    """Response model for tags."""

    name: str = Field(
        description="The unique title of the tag.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "TagResponse":
        """Get the hydrated version of this tag.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_tag(self.id)

    @property
    def color(self) -> ColorVariants:
        """The `color` property.

        Returns:
            the value of the property.
        """
        return self.get_body().color

    @property
    def tagged_count(self) -> int:
        """The `tagged_count` property.

        Returns:
            the value of the property.
        """
        return self.get_body().tagged_count

color property

The color property.

Returns:

Type Description
ColorVariants

the value of the property.

tagged_count property

The tagged_count property.

Returns:

Type Description
int

the value of the property.

get_hydrated_version()

Get the hydrated version of this tag.

Returns:

Type Description
TagResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/tag.py
89
90
91
92
93
94
95
96
97
def get_hydrated_version(self) -> "TagResponse":
    """Get the hydrated version of this tag.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_tag(self.id)

TagResponseBody

Bases: BaseDatedResponseBody

Response body for tags.

Source code in src/zenml/models/v2/core/tag.py
61
62
63
64
65
66
67
68
69
70
class TagResponseBody(BaseDatedResponseBody):
    """Response body for tags."""

    color: ColorVariants = Field(
        description="The color variant assigned to the tag.",
        default_factory=lambda: random.choice(list(ColorVariants)),
    )
    tagged_count: int = Field(
        description="The count of resources tagged with this tag."
    )

TagUpdate

Bases: BaseModel

Update model for tags.

Source code in src/zenml/models/v2/core/tag.py
51
52
53
54
55
class TagUpdate(BaseModel):
    """Update model for tags."""

    name: Optional[str] = None
    color: Optional[ColorVariants] = None

TaggableFilter

Bases: BaseFilter

Model to enable filtering and sorting by tags.

Source code in src/zenml/models/v2/base/scoped.py
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
class TaggableFilter(BaseFilter):
    """Model to enable filtering and sorting by tags."""

    tag: Optional[str] = Field(
        description="Tag to apply to the filter query.", default=None
    )

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *BaseFilter.FILTER_EXCLUDE_FIELDS,
        "tag",
    ]
    CUSTOM_SORTING_OPTIONS: ClassVar[List[str]] = [
        *BaseFilter.CUSTOM_SORTING_OPTIONS,
        "tags",
    ]

    def apply_filter(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Applies the filter to a query.

        Args:
            query: The query to which to apply the filter.
            table: The query table.

        Returns:
            The query with filter applied.
        """
        from zenml.zen_stores.schemas import TagResourceSchema, TagSchema

        query = super().apply_filter(query=query, table=table)
        if self.tag:
            query = query.join(
                TagResourceSchema,
                TagResourceSchema.resource_id == getattr(table, "id"),
            ).join(TagSchema, TagSchema.id == TagResourceSchema.tag_id)

        return query

    def get_custom_filters(
        self, table: Type["AnySchema"]
    ) -> List["ColumnElement[bool]"]:
        """Get custom tag filters.

        Args:
            table: The query table.

        Returns:
            A list of custom filters.
        """
        from zenml.zen_stores.schemas import TagSchema

        custom_filters = super().get_custom_filters(table)
        if self.tag:
            custom_filters.append(
                self.generate_custom_query_conditions_for_column(
                    value=self.tag, table=TagSchema, column="name"
                )
            )

        return custom_filters

    def apply_sorting(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Apply sorting to the query.

        Args:
            query: The query to which to apply the sorting.
            table: The query table.

        Returns:
            The query with sorting applied.
        """
        sort_by, operand = self.sorting_params

        if sort_by == "tags":
            from sqlmodel import asc, desc, func, select

            from zenml.enums import SorterOps, TaggableResourceTypes
            from zenml.zen_stores.schemas import (
                ArtifactSchema,
                ArtifactVersionSchema,
                ModelSchema,
                ModelVersionSchema,
                PipelineRunSchema,
                PipelineSchema,
                RunTemplateSchema,
                TagResourceSchema,
                TagSchema,
            )

            resource_type_mapping = {
                ArtifactSchema: TaggableResourceTypes.ARTIFACT,
                ArtifactVersionSchema: TaggableResourceTypes.ARTIFACT_VERSION,
                ModelSchema: TaggableResourceTypes.MODEL,
                ModelVersionSchema: TaggableResourceTypes.MODEL_VERSION,
                PipelineSchema: TaggableResourceTypes.PIPELINE,
                PipelineRunSchema: TaggableResourceTypes.PIPELINE_RUN,
                RunTemplateSchema: TaggableResourceTypes.RUN_TEMPLATE,
            }

            sorted_tags = (
                select(TagResourceSchema.resource_id, TagSchema.name)
                .join(TagSchema, TagResourceSchema.tag_id == TagSchema.id)  # type: ignore[arg-type]
                .filter(
                    TagResourceSchema.resource_type  # type: ignore[arg-type]
                    == resource_type_mapping[table]
                )
                .order_by(
                    asc(TagResourceSchema.resource_id), asc(TagSchema.name)
                )
            ).alias("sorted_tags")

            tags_subquery = (
                select(
                    sorted_tags.c.resource_id,
                    func.group_concat(sorted_tags.c.name, ", ").label(
                        "tags_list"
                    ),
                ).group_by(sorted_tags.c.resource_id)
            ).alias("tags_subquery")

            query = query.add_columns(tags_subquery.c.tags_list).outerjoin(
                tags_subquery, table.id == tags_subquery.c.resource_id
            )

            # Apply ordering based on the tags list
            if operand == SorterOps.ASCENDING:
                query = query.order_by(asc("tags_list"))
            else:
                query = query.order_by(desc("tags_list"))

            return query

        return super().apply_sorting(query=query, table=table)

apply_filter(query, table)

Applies the filter to a query.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the filter.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with filter applied.

Source code in src/zenml/models/v2/base/scoped.py
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
def apply_filter(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Applies the filter to a query.

    Args:
        query: The query to which to apply the filter.
        table: The query table.

    Returns:
        The query with filter applied.
    """
    from zenml.zen_stores.schemas import TagResourceSchema, TagSchema

    query = super().apply_filter(query=query, table=table)
    if self.tag:
        query = query.join(
            TagResourceSchema,
            TagResourceSchema.resource_id == getattr(table, "id"),
        ).join(TagSchema, TagSchema.id == TagResourceSchema.tag_id)

    return query

apply_sorting(query, table)

Apply sorting to the query.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the sorting.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with sorting applied.

Source code in src/zenml/models/v2/base/scoped.py
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
def apply_sorting(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Apply sorting to the query.

    Args:
        query: The query to which to apply the sorting.
        table: The query table.

    Returns:
        The query with sorting applied.
    """
    sort_by, operand = self.sorting_params

    if sort_by == "tags":
        from sqlmodel import asc, desc, func, select

        from zenml.enums import SorterOps, TaggableResourceTypes
        from zenml.zen_stores.schemas import (
            ArtifactSchema,
            ArtifactVersionSchema,
            ModelSchema,
            ModelVersionSchema,
            PipelineRunSchema,
            PipelineSchema,
            RunTemplateSchema,
            TagResourceSchema,
            TagSchema,
        )

        resource_type_mapping = {
            ArtifactSchema: TaggableResourceTypes.ARTIFACT,
            ArtifactVersionSchema: TaggableResourceTypes.ARTIFACT_VERSION,
            ModelSchema: TaggableResourceTypes.MODEL,
            ModelVersionSchema: TaggableResourceTypes.MODEL_VERSION,
            PipelineSchema: TaggableResourceTypes.PIPELINE,
            PipelineRunSchema: TaggableResourceTypes.PIPELINE_RUN,
            RunTemplateSchema: TaggableResourceTypes.RUN_TEMPLATE,
        }

        sorted_tags = (
            select(TagResourceSchema.resource_id, TagSchema.name)
            .join(TagSchema, TagResourceSchema.tag_id == TagSchema.id)  # type: ignore[arg-type]
            .filter(
                TagResourceSchema.resource_type  # type: ignore[arg-type]
                == resource_type_mapping[table]
            )
            .order_by(
                asc(TagResourceSchema.resource_id), asc(TagSchema.name)
            )
        ).alias("sorted_tags")

        tags_subquery = (
            select(
                sorted_tags.c.resource_id,
                func.group_concat(sorted_tags.c.name, ", ").label(
                    "tags_list"
                ),
            ).group_by(sorted_tags.c.resource_id)
        ).alias("tags_subquery")

        query = query.add_columns(tags_subquery.c.tags_list).outerjoin(
            tags_subquery, table.id == tags_subquery.c.resource_id
        )

        # Apply ordering based on the tags list
        if operand == SorterOps.ASCENDING:
            query = query.order_by(asc("tags_list"))
        else:
            query = query.order_by(desc("tags_list"))

        return query

    return super().apply_sorting(query=query, table=table)

get_custom_filters(table)

Get custom tag filters.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
List[ColumnElement[bool]]

A list of custom filters.

Source code in src/zenml/models/v2/base/scoped.py
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
def get_custom_filters(
    self, table: Type["AnySchema"]
) -> List["ColumnElement[bool]"]:
    """Get custom tag filters.

    Args:
        table: The query table.

    Returns:
        A list of custom filters.
    """
    from zenml.zen_stores.schemas import TagSchema

    custom_filters = super().get_custom_filters(table)
    if self.tag:
        custom_filters.append(
            self.generate_custom_query_conditions_for_column(
                value=self.tag, table=TagSchema, column="name"
            )
        )

    return custom_filters

TriggerExecutionFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of all trigger executions.

Source code in src/zenml/models/v2/core/trigger_execution.py
112
113
114
115
116
117
118
119
class TriggerExecutionFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of all trigger executions."""

    trigger_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="ID of the trigger of the execution.",
        union_mode="left_to_right",
    )

TriggerExecutionRequest

Bases: BaseRequest

Model for creating a new Trigger execution.

Source code in src/zenml/models/v2/core/trigger_execution.py
38
39
40
41
42
class TriggerExecutionRequest(BaseRequest):
    """Model for creating a new Trigger execution."""

    trigger: UUID
    event_metadata: Dict[str, Any] = {}

TriggerExecutionResponse

Bases: BaseIdentifiedResponse[TriggerExecutionResponseBody, TriggerExecutionResponseMetadata, TriggerExecutionResponseResources]

Response model for trigger executions.

Source code in src/zenml/models/v2/core/trigger_execution.py
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
class TriggerExecutionResponse(
    BaseIdentifiedResponse[
        TriggerExecutionResponseBody,
        TriggerExecutionResponseMetadata,
        TriggerExecutionResponseResources,
    ]
):
    """Response model for trigger executions."""

    def get_hydrated_version(self) -> "TriggerExecutionResponse":
        """Get the hydrated version of this trigger execution.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_trigger_execution(self.id)

    # Body and metadata properties

    @property
    def trigger(self) -> "TriggerResponse":
        """The `trigger` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().trigger

    @property
    def event_metadata(self) -> Dict[str, Any]:
        """The `event_metadata` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().event_metadata

event_metadata property

The event_metadata property.

Returns:

Type Description
Dict[str, Any]

the value of the property.

trigger property

The trigger property.

Returns:

Type Description
TriggerResponse

the value of the property.

get_hydrated_version()

Get the hydrated version of this trigger execution.

Returns:

Type Description
TriggerExecutionResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/trigger_execution.py
78
79
80
81
82
83
84
85
86
def get_hydrated_version(self) -> "TriggerExecutionResponse":
    """Get the hydrated version of this trigger execution.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_trigger_execution(self.id)

TriggerExecutionResponseBody

Bases: BaseDatedResponseBody

Response body for trigger executions.

Source code in src/zenml/models/v2/core/trigger_execution.py
51
52
class TriggerExecutionResponseBody(BaseDatedResponseBody):
    """Response body for trigger executions."""

TriggerExecutionResponseMetadata

Bases: BaseResponseMetadata

Response metadata for trigger executions.

Source code in src/zenml/models/v2/core/trigger_execution.py
55
56
57
58
class TriggerExecutionResponseMetadata(BaseResponseMetadata):
    """Response metadata for trigger executions."""

    event_metadata: Dict[str, Any] = {}

TriggerExecutionResponseResources

Bases: BaseResponseResources

Class for all resource models associated with the trigger entity.

Source code in src/zenml/models/v2/core/trigger_execution.py
61
62
63
64
65
66
class TriggerExecutionResponseResources(BaseResponseResources):
    """Class for all resource models associated with the trigger entity."""

    trigger: "TriggerResponse" = Field(
        title="The event source that activates this trigger.",
    )

TriggerFilter

Bases: WorkspaceScopedFilter

Model to enable advanced filtering of all triggers.

Source code in src/zenml/models/v2/core/trigger.py
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
class TriggerFilter(WorkspaceScopedFilter):
    """Model to enable advanced filtering of all triggers."""

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
        "action_flavor",
        "action_subtype",
        "event_source_flavor",
        "event_source_subtype",
    ]

    name: Optional[str] = Field(
        default=None,
        description="Name of the trigger.",
    )
    event_source_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="The event source this trigger is attached to.",
        union_mode="left_to_right",
    )
    action_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="The action this trigger is attached to.",
        union_mode="left_to_right",
    )
    is_active: Optional[bool] = Field(
        default=None,
        description="Whether the trigger is active.",
    )
    action_flavor: Optional[str] = Field(
        default=None,
        title="The flavor of the action that is executed by this trigger.",
    )
    action_subtype: Optional[str] = Field(
        default=None,
        title="The subtype of the action that is executed by this trigger.",
    )
    event_source_flavor: Optional[str] = Field(
        default=None,
        title="The flavor of the event source that activates this trigger.",
    )
    event_source_subtype: Optional[str] = Field(
        default=None,
        title="The subtype of the event source that activates this trigger.",
    )

    def get_custom_filters(
        self, table: Type["AnySchema"]
    ) -> List["ColumnElement[bool]"]:
        """Get custom filters.

        Args:
            table: The query table.

        Returns:
            A list of custom filters.
        """
        from sqlmodel import and_

        from zenml.zen_stores.schemas import (
            ActionSchema,
            EventSourceSchema,
            TriggerSchema,
        )

        custom_filters = super().get_custom_filters(table)

        if self.event_source_flavor:
            event_source_flavor_filter = and_(
                EventSourceSchema.id == TriggerSchema.event_source_id,
                EventSourceSchema.flavor == self.event_source_flavor,
            )
            custom_filters.append(event_source_flavor_filter)

        if self.event_source_subtype:
            event_source_subtype_filter = and_(
                EventSourceSchema.id == TriggerSchema.event_source_id,
                EventSourceSchema.plugin_subtype == self.event_source_subtype,
            )
            custom_filters.append(event_source_subtype_filter)

        if self.action_flavor:
            action_flavor_filter = and_(
                ActionSchema.id == TriggerSchema.action_id,
                ActionSchema.flavor == self.action_flavor,
            )
            custom_filters.append(action_flavor_filter)

        if self.action_subtype:
            action_subtype_filter = and_(
                ActionSchema.id == TriggerSchema.action_id,
                ActionSchema.plugin_subtype == self.action_subtype,
            )
            custom_filters.append(action_subtype_filter)

        return custom_filters

get_custom_filters(table)

Get custom filters.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
List[ColumnElement[bool]]

A list of custom filters.

Source code in src/zenml/models/v2/core/trigger.py
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
def get_custom_filters(
    self, table: Type["AnySchema"]
) -> List["ColumnElement[bool]"]:
    """Get custom filters.

    Args:
        table: The query table.

    Returns:
        A list of custom filters.
    """
    from sqlmodel import and_

    from zenml.zen_stores.schemas import (
        ActionSchema,
        EventSourceSchema,
        TriggerSchema,
    )

    custom_filters = super().get_custom_filters(table)

    if self.event_source_flavor:
        event_source_flavor_filter = and_(
            EventSourceSchema.id == TriggerSchema.event_source_id,
            EventSourceSchema.flavor == self.event_source_flavor,
        )
        custom_filters.append(event_source_flavor_filter)

    if self.event_source_subtype:
        event_source_subtype_filter = and_(
            EventSourceSchema.id == TriggerSchema.event_source_id,
            EventSourceSchema.plugin_subtype == self.event_source_subtype,
        )
        custom_filters.append(event_source_subtype_filter)

    if self.action_flavor:
        action_flavor_filter = and_(
            ActionSchema.id == TriggerSchema.action_id,
            ActionSchema.flavor == self.action_flavor,
        )
        custom_filters.append(action_flavor_filter)

    if self.action_subtype:
        action_subtype_filter = and_(
            ActionSchema.id == TriggerSchema.action_id,
            ActionSchema.plugin_subtype == self.action_subtype,
        )
        custom_filters.append(action_subtype_filter)

    return custom_filters

TriggerRequest

Bases: WorkspaceScopedRequest

Model for creating a new trigger.

Source code in src/zenml/models/v2/core/trigger.py
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
class TriggerRequest(WorkspaceScopedRequest):
    """Model for creating a new trigger."""

    name: str = Field(
        title="The name of the trigger.", max_length=STR_FIELD_MAX_LENGTH
    )
    description: str = Field(
        default="",
        title="The description of the trigger",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    action_id: UUID = Field(
        title="The action that is executed by this trigger.",
    )
    schedule: Optional[Schedule] = Field(
        default=None,
        title="The schedule for the trigger. Either a schedule or an event "
        "source is required.",
    )
    event_source_id: Optional[UUID] = Field(
        default=None,
        title="The event source that activates this trigger. Either a schedule "
        "or an event source is required.",
    )
    event_filter: Optional[Dict[str, Any]] = Field(
        default=None,
        title="Filter applied to events that activate this trigger. Only "
        "set if the trigger is activated by an event source.",
    )

    @model_validator(mode="after")
    def _validate_schedule_or_event_source(self) -> "TriggerRequest":
        """Validate that either a schedule or an event source is provided.

        Returns:
            The validated request.

        Raises:
            ValueError: If neither a schedule nor an event source is provided,
                or if both are provided.
        """
        if not self.schedule and not self.event_source_id:
            raise ValueError(
                "Either a schedule or an event source is required."
            )

        if self.schedule and self.event_source_id:
            raise ValueError("Only a schedule or an event source is allowed.")

        return self

TriggerResponse

Bases: WorkspaceScopedResponse[TriggerResponseBody, TriggerResponseMetadata, TriggerResponseResources]

Response model for models.

Source code in src/zenml/models/v2/core/trigger.py
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
class TriggerResponse(
    WorkspaceScopedResponse[
        TriggerResponseBody, TriggerResponseMetadata, TriggerResponseResources
    ]
):
    """Response model for models."""

    name: str = Field(
        title="The name of the trigger",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "TriggerResponse":
        """Get the hydrated version of this trigger.

        Returns:
            An instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_trigger(self.id)

    @property
    def action_flavor(self) -> str:
        """The `action_flavor` property.

        Returns:
            the value of the property.
        """
        return self.get_body().action_flavor

    @property
    def action_subtype(self) -> str:
        """The `action_subtype` property.

        Returns:
            the value of the property.
        """
        return self.get_body().action_subtype

    @property
    def event_source_flavor(self) -> Optional[str]:
        """The `event_source_flavor` property.

        Returns:
            the value of the property.
        """
        return self.get_body().event_source_flavor

    @property
    def event_source_subtype(self) -> Optional[str]:
        """The `event_source_subtype` property.

        Returns:
            the value of the property.
        """
        return self.get_body().event_source_subtype

    @property
    def is_active(self) -> bool:
        """The `is_active` property.

        Returns:
            the value of the property.
        """
        return self.get_body().is_active

    @property
    def event_filter(self) -> Optional[Dict[str, Any]]:
        """The `event_filter` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().event_filter

    @property
    def description(self) -> str:
        """The `description` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().description

    @property
    def action(self) -> "ActionResponse":
        """The `action` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().action

    @property
    def event_source(self) -> Optional["EventSourceResponse"]:
        """The `event_source` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().event_source

    @property
    def executions(self) -> Page[TriggerExecutionResponse]:
        """The `event_source` property.

        Returns:
            the value of the property.
        """
        return self.get_resources().executions

action property

The action property.

Returns:

Type Description
ActionResponse

the value of the property.

action_flavor property

The action_flavor property.

Returns:

Type Description
str

the value of the property.

action_subtype property

The action_subtype property.

Returns:

Type Description
str

the value of the property.

description property

The description property.

Returns:

Type Description
str

the value of the property.

event_filter property

The event_filter property.

Returns:

Type Description
Optional[Dict[str, Any]]

the value of the property.

event_source property

The event_source property.

Returns:

Type Description
Optional[EventSourceResponse]

the value of the property.

event_source_flavor property

The event_source_flavor property.

Returns:

Type Description
Optional[str]

the value of the property.

event_source_subtype property

The event_source_subtype property.

Returns:

Type Description
Optional[str]

the value of the property.

executions property

The event_source property.

Returns:

Type Description
Page[TriggerExecutionResponse]

the value of the property.

is_active property

The is_active property.

Returns:

Type Description
bool

the value of the property.

get_hydrated_version()

Get the hydrated version of this trigger.

Returns:

Type Description
TriggerResponse

An instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/trigger.py
223
224
225
226
227
228
229
230
231
def get_hydrated_version(self) -> "TriggerResponse":
    """Get the hydrated version of this trigger.

    Returns:
        An instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_trigger(self.id)

TriggerResponseBody

Bases: WorkspaceScopedResponseBody

Response body for triggers.

Source code in src/zenml/models/v2/core/trigger.py
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
class TriggerResponseBody(WorkspaceScopedResponseBody):
    """Response body for triggers."""

    action_flavor: str = Field(
        title="The flavor of the action that is executed by this trigger.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    action_subtype: str = Field(
        title="The subtype of the action that is executed by this trigger.",
    )
    event_source_flavor: Optional[str] = Field(
        default=None,
        title="The flavor of the event source that activates this trigger. Not "
        "set if the trigger is activated by a schedule.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    event_source_subtype: Optional[str] = Field(
        default=None,
        title="The subtype of the event source that activates this trigger. "
        "Not set if the trigger is activated by a schedule.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    is_active: bool = Field(
        title="Whether the trigger is active.",
    )

TriggerResponseMetadata

Bases: WorkspaceScopedResponseMetadata

Response metadata for triggers.

Source code in src/zenml/models/v2/core/trigger.py
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
class TriggerResponseMetadata(WorkspaceScopedResponseMetadata):
    """Response metadata for triggers."""

    description: str = Field(
        default="",
        title="The description of the trigger.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    event_filter: Optional[Dict[str, Any]] = Field(
        default=None,
        title="The event that activates this trigger. Not set if the trigger "
        "is activated by a schedule.",
    )
    schedule: Optional[Schedule] = Field(
        default=None,
        title="The schedule that activates this trigger. Not set if the "
        "trigger is activated by an event source.",
    )

TriggerResponseResources

Bases: WorkspaceScopedResponseResources

Class for all resource models associated with the trigger entity.

Source code in src/zenml/models/v2/core/trigger.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
class TriggerResponseResources(WorkspaceScopedResponseResources):
    """Class for all resource models associated with the trigger entity."""

    action: "ActionResponse" = Field(
        title="The action that is executed by this trigger.",
    )
    event_source: Optional["EventSourceResponse"] = Field(
        default=None,
        title="The event source that activates this trigger. Not set if the "
        "trigger is activated by a schedule.",
    )
    executions: Page[TriggerExecutionResponse] = Field(
        title="The executions of this trigger.",
    )

TriggerUpdate

Bases: BaseUpdate

Update model for triggers.

Source code in src/zenml/models/v2/core/trigger.py
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
class TriggerUpdate(BaseUpdate):
    """Update model for triggers."""

    name: Optional[str] = Field(
        default=None,
        title="The new name for the trigger.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    description: Optional[str] = Field(
        default=None,
        title="The new description for the trigger.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    event_filter: Optional[Dict[str, Any]] = Field(
        default=None,
        title="New filter applied to events that activate this trigger. Only "
        "valid if the trigger is already configured to be activated by an "
        "event source.",
    )
    schedule: Optional[Schedule] = Field(
        default=None,
        title="The updated schedule for the trigger. Only valid if the trigger "
        "is already configured to be activated by a schedule.",
    )
    is_active: Optional[bool] = Field(
        default=None,
        title="The new status of the trigger.",
    )

UUIDFilter

Bases: StrFilter

Filter for all uuid fields which are mostly treated like strings.

Source code in src/zenml/models/v2/base/filter.py
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
class UUIDFilter(StrFilter):
    """Filter for all uuid fields which are mostly treated like strings."""

    @field_validator("value", mode="before")
    @classmethod
    def _remove_hyphens_from_value(cls, value: Any) -> Any:
        """Remove hyphens from the value to enable string comparisons.

        Args:
            value: The filter value.

        Returns:
            The filter value with removed hyphens.
        """
        if isinstance(value, str):
            return value.replace("-", "")

        if isinstance(value, list):
            return [str(v).replace("-", "") for v in value]

        return value

    def generate_query_conditions_from_column(self, column: Any) -> Any:
        """Generate query conditions for a UUID column.

        Args:
            column: The UUID column of an SQLModel table on which to filter.

        Returns:
            A list of query conditions.
        """
        import sqlalchemy
        from sqlalchemy_utils.functions import cast_if

        from zenml.utils import uuid_utils

        # For equality checks, compare the UUID directly
        if self.operation == GenericFilterOps.EQUALS:
            if not uuid_utils.is_valid_uuid(self.value):
                return False

            return column == self.value

        if self.operation == GenericFilterOps.NOT_EQUALS:
            if not uuid_utils.is_valid_uuid(self.value):
                return True

            return column != self.value

        # For all other operations, cast and handle the column as string
        return super().generate_query_conditions_from_column(
            column=cast_if(column, sqlalchemy.String)
        )

generate_query_conditions_from_column(column)

Generate query conditions for a UUID column.

Parameters:

Name Type Description Default
column Any

The UUID column of an SQLModel table on which to filter.

required

Returns:

Type Description
Any

A list of query conditions.

Source code in src/zenml/models/v2/base/filter.py
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
def generate_query_conditions_from_column(self, column: Any) -> Any:
    """Generate query conditions for a UUID column.

    Args:
        column: The UUID column of an SQLModel table on which to filter.

    Returns:
        A list of query conditions.
    """
    import sqlalchemy
    from sqlalchemy_utils.functions import cast_if

    from zenml.utils import uuid_utils

    # For equality checks, compare the UUID directly
    if self.operation == GenericFilterOps.EQUALS:
        if not uuid_utils.is_valid_uuid(self.value):
            return False

        return column == self.value

    if self.operation == GenericFilterOps.NOT_EQUALS:
        if not uuid_utils.is_valid_uuid(self.value):
            return True

        return column != self.value

    # For all other operations, cast and handle the column as string
    return super().generate_query_conditions_from_column(
        column=cast_if(column, sqlalchemy.String)
    )

UserAuthModel

Bases: BaseZenModel

Authentication Model for the User.

This model is only used server-side. The server endpoints can use this model to authenticate the user credentials (Token, Password).

Source code in src/zenml/models/v2/misc/user_auth.py
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
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
class UserAuthModel(BaseZenModel):
    """Authentication Model for the User.

    This model is only used server-side. The server endpoints can use this model
    to authenticate the user credentials (Token, Password).
    """

    id: UUID = Field(title="The unique resource id.")

    created: datetime = Field(title="Time when this resource was created.")
    updated: datetime = Field(
        title="Time when this resource was last updated."
    )

    active: bool = Field(default=False, title="Active account.")
    is_service_account: bool = Field(
        title="Indicates whether this is a service account or a regular user "
        "account."
    )

    activation_token: Optional[PlainSerializedSecretStr] = Field(
        default=None, exclude=True
    )
    password: Optional[PlainSerializedSecretStr] = Field(
        default=None, exclude=True
    )
    name: str = Field(
        title="The unique username for the account.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    full_name: str = Field(
        default="",
        title="The full name for the account owner. Only relevant for user "
        "accounts.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    email_opted_in: Optional[bool] = Field(
        default=None,
        title="Whether the user agreed to share their email. Only relevant for "
        "user accounts",
        description="`null` if not answered, `true` if agreed, "
        "`false` if skipped.",
    )

    @classmethod
    def _get_crypt_context(cls) -> "CryptContext":
        """Returns the password encryption context.

        Returns:
            The password encryption context.
        """
        from passlib.context import CryptContext

        return CryptContext(schemes=["bcrypt"], deprecated="auto")

    @classmethod
    def _is_hashed_secret(cls, secret: SecretStr) -> bool:
        """Checks if a secret value is already hashed.

        Args:
            secret: The secret value to check.

        Returns:
            True if the secret value is hashed, otherwise False.
        """
        return (
            re.match(r"^\$2[ayb]\$.{56}$", secret.get_secret_value())
            is not None
        )

    @classmethod
    def _get_hashed_secret(cls, secret: Optional[SecretStr]) -> Optional[str]:
        """Hashes the input secret and returns the hash value.

        Only applied if supplied and if not already hashed.

        Args:
            secret: The secret value to hash.

        Returns:
            The secret hash value, or None if no secret was supplied.
        """
        if secret is None:
            return None
        if cls._is_hashed_secret(secret):
            return secret.get_secret_value()
        pwd_context = cls._get_crypt_context()
        return pwd_context.hash(secret.get_secret_value())

    def get_password(self) -> Optional[str]:
        """Get the password.

        Returns:
            The password as a plain string, if it exists.
        """
        if self.password is None:
            return None
        return self.password.get_secret_value()

    def get_hashed_password(self) -> Optional[str]:
        """Returns the hashed password, if configured.

        Returns:
            The hashed password.
        """
        return self._get_hashed_secret(self.password)

    def get_hashed_activation_token(self) -> Optional[str]:
        """Returns the hashed activation token, if configured.

        Returns:
            The hashed activation token.
        """
        return self._get_hashed_secret(self.activation_token)

    @classmethod
    def verify_password(
        cls, plain_password: str, user: Optional["UserAuthModel"] = None
    ) -> bool:
        """Verifies a given plain password against the stored password.

        Args:
            plain_password: Input password to be verified.
            user: User for which the password is to be verified.

        Returns:
            True if the passwords match.
        """
        # even when the user or password is not set, we still want to execute
        # the password hash verification to protect against response discrepancy
        # attacks (https://cwe.mitre.org/data/definitions/204.html)
        password_hash: Optional[str] = None
        if (
            user is not None
            # Disable password verification for service accounts as an extra
            # security measure. Service accounts should only be used with API
            # keys.
            and not user.is_service_account
            and user.password is not None
        ):  # and user.active:
            password_hash = user.get_hashed_password()
        pwd_context = cls._get_crypt_context()
        return pwd_context.verify(plain_password, password_hash)

    @classmethod
    def verify_activation_token(
        cls, activation_token: str, user: Optional["UserAuthModel"] = None
    ) -> bool:
        """Verifies a given activation token against the stored token.

        Args:
            activation_token: Input activation token to be verified.
            user: User for which the activation token is to be verified.

        Returns:
            True if the token is valid.
        """
        # even when the user or token is not set, we still want to execute the
        # token hash verification to protect against response discrepancy
        # attacks (https://cwe.mitre.org/data/definitions/204.html)
        token_hash: str = ""
        if (
            user is not None
            # Disable activation tokens for service accounts as an extra
            # security measure. Service accounts should only be used with API
            # keys.
            and not user.is_service_account
            and user.activation_token is not None
            and not user.active
        ):
            token_hash = user.get_hashed_activation_token() or ""
        pwd_context = cls._get_crypt_context()
        return pwd_context.verify(activation_token, token_hash)

get_hashed_activation_token()

Returns the hashed activation token, if configured.

Returns:

Type Description
Optional[str]

The hashed activation token.

Source code in src/zenml/models/v2/misc/user_auth.py
139
140
141
142
143
144
145
def get_hashed_activation_token(self) -> Optional[str]:
    """Returns the hashed activation token, if configured.

    Returns:
        The hashed activation token.
    """
    return self._get_hashed_secret(self.activation_token)

get_hashed_password()

Returns the hashed password, if configured.

Returns:

Type Description
Optional[str]

The hashed password.

Source code in src/zenml/models/v2/misc/user_auth.py
131
132
133
134
135
136
137
def get_hashed_password(self) -> Optional[str]:
    """Returns the hashed password, if configured.

    Returns:
        The hashed password.
    """
    return self._get_hashed_secret(self.password)

get_password()

Get the password.

Returns:

Type Description
Optional[str]

The password as a plain string, if it exists.

Source code in src/zenml/models/v2/misc/user_auth.py
121
122
123
124
125
126
127
128
129
def get_password(self) -> Optional[str]:
    """Get the password.

    Returns:
        The password as a plain string, if it exists.
    """
    if self.password is None:
        return None
    return self.password.get_secret_value()

verify_activation_token(activation_token, user=None) classmethod

Verifies a given activation token against the stored token.

Parameters:

Name Type Description Default
activation_token str

Input activation token to be verified.

required
user Optional[UserAuthModel]

User for which the activation token is to be verified.

None

Returns:

Type Description
bool

True if the token is valid.

Source code in src/zenml/models/v2/misc/user_auth.py
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
@classmethod
def verify_activation_token(
    cls, activation_token: str, user: Optional["UserAuthModel"] = None
) -> bool:
    """Verifies a given activation token against the stored token.

    Args:
        activation_token: Input activation token to be verified.
        user: User for which the activation token is to be verified.

    Returns:
        True if the token is valid.
    """
    # even when the user or token is not set, we still want to execute the
    # token hash verification to protect against response discrepancy
    # attacks (https://cwe.mitre.org/data/definitions/204.html)
    token_hash: str = ""
    if (
        user is not None
        # Disable activation tokens for service accounts as an extra
        # security measure. Service accounts should only be used with API
        # keys.
        and not user.is_service_account
        and user.activation_token is not None
        and not user.active
    ):
        token_hash = user.get_hashed_activation_token() or ""
    pwd_context = cls._get_crypt_context()
    return pwd_context.verify(activation_token, token_hash)

verify_password(plain_password, user=None) classmethod

Verifies a given plain password against the stored password.

Parameters:

Name Type Description Default
plain_password str

Input password to be verified.

required
user Optional[UserAuthModel]

User for which the password is to be verified.

None

Returns:

Type Description
bool

True if the passwords match.

Source code in src/zenml/models/v2/misc/user_auth.py
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
@classmethod
def verify_password(
    cls, plain_password: str, user: Optional["UserAuthModel"] = None
) -> bool:
    """Verifies a given plain password against the stored password.

    Args:
        plain_password: Input password to be verified.
        user: User for which the password is to be verified.

    Returns:
        True if the passwords match.
    """
    # even when the user or password is not set, we still want to execute
    # the password hash verification to protect against response discrepancy
    # attacks (https://cwe.mitre.org/data/definitions/204.html)
    password_hash: Optional[str] = None
    if (
        user is not None
        # Disable password verification for service accounts as an extra
        # security measure. Service accounts should only be used with API
        # keys.
        and not user.is_service_account
        and user.password is not None
    ):  # and user.active:
        password_hash = user.get_hashed_password()
    pwd_context = cls._get_crypt_context()
    return pwd_context.verify(plain_password, password_hash)

UserFilter

Bases: BaseFilter

Model to enable advanced filtering of all Users.

Source code in src/zenml/models/v2/core/user.py
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
class UserFilter(BaseFilter):
    """Model to enable advanced filtering of all Users."""

    name: Optional[str] = Field(
        default=None,
        description="Name of the user",
    )
    full_name: Optional[str] = Field(
        default=None,
        description="Full Name of the user",
    )
    email: Optional[str] = Field(
        default=None,
        description="Email of the user",
    )
    active: Optional[Union[bool, str]] = Field(
        default=None,
        description="Whether the user is active",
        union_mode="left_to_right",
    )
    email_opted_in: Optional[Union[bool, str]] = Field(
        default=None,
        description="Whether the user has opted in to emails",
        union_mode="left_to_right",
    )
    external_user_id: Optional[Union[UUID, str]] = Field(
        default=None,
        title="The external user ID associated with the account.",
        union_mode="left_to_right",
    )

    def apply_filter(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Override to filter out service accounts from the query.

        Args:
            query: The query to which to apply the filter.
            table: The query table.

        Returns:
            The query with filter applied.
        """
        query = super().apply_filter(query=query, table=table)
        query = query.where(
            getattr(table, "is_service_account") != True  # noqa: E712
        )

        return query

apply_filter(query, table)

Override to filter out service accounts from the query.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the filter.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with filter applied.

Source code in src/zenml/models/v2/core/user.py
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
def apply_filter(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Override to filter out service accounts from the query.

    Args:
        query: The query to which to apply the filter.
        table: The query table.

    Returns:
        The query with filter applied.
    """
    query = super().apply_filter(query=query, table=table)
    query = query.where(
        getattr(table, "is_service_account") != True  # noqa: E712
    )

    return query

UserRequest

Bases: UserBase, BaseRequest

Request model for users.

Source code in src/zenml/models/v2/core/user.py
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
class UserRequest(UserBase, BaseRequest):
    """Request model for users."""

    # Analytics fields for user request models
    ANALYTICS_FIELDS: ClassVar[List[str]] = [
        "name",
        "full_name",
        "active",
        "email_opted_in",
    ]

    name: str = Field(
        title="The unique username for the account.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    full_name: str = Field(
        default="",
        title="The full name for the account owner. Only relevant for user "
        "accounts.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    is_admin: bool = Field(
        title="Whether the account is an administrator.",
    )
    active: bool = Field(default=False, title="Whether the account is active.")

    model_config = ConfigDict(
        # Validate attributes when assigning them
        validate_assignment=True,
        # Forbid extra attributes to prevent unexpected behavior
        extra="forbid",
    )

UserResponse

Bases: BaseIdentifiedResponse[UserResponseBody, UserResponseMetadata, UserResponseResources]

Response model for user and service accounts.

This returns the activation_token that is required for the user-invitation-flow of the frontend. The email is returned optionally as well for use by the analytics on the client-side.

Source code in src/zenml/models/v2/core/user.py
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
class UserResponse(
    BaseIdentifiedResponse[
        UserResponseBody, UserResponseMetadata, UserResponseResources
    ]
):
    """Response model for user and service accounts.

    This returns the activation_token that is required for the
    user-invitation-flow of the frontend. The email is returned optionally as
    well for use by the analytics on the client-side.
    """

    ANALYTICS_FIELDS: ClassVar[List[str]] = [
        "name",
        "full_name",
        "active",
        "email_opted_in",
        "is_service_account",
    ]

    name: str = Field(
        title="The unique username for the account.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "UserResponse":
        """Get the hydrated version of this user.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_user(self.id)

    # Body and metadata properties
    @property
    def active(self) -> bool:
        """The `active` property.

        Returns:
            the value of the property.
        """
        return self.get_body().active

    @property
    def activation_token(self) -> Optional[str]:
        """The `activation_token` property.

        Returns:
            the value of the property.
        """
        return self.get_body().activation_token

    @property
    def full_name(self) -> str:
        """The `full_name` property.

        Returns:
            the value of the property.
        """
        return self.get_body().full_name

    @property
    def email_opted_in(self) -> Optional[bool]:
        """The `email_opted_in` property.

        Returns:
            the value of the property.
        """
        return self.get_body().email_opted_in

    @property
    def is_service_account(self) -> bool:
        """The `is_service_account` property.

        Returns:
            the value of the property.
        """
        return self.get_body().is_service_account

    @property
    def is_admin(self) -> bool:
        """The `is_admin` property.

        Returns:
            Whether the user is an admin.
        """
        return self.get_body().is_admin

    @property
    def email(self) -> Optional[str]:
        """The `email` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().email

    @property
    def external_user_id(self) -> Optional[UUID]:
        """The `external_user_id` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().external_user_id

    @property
    def user_metadata(self) -> Dict[str, Any]:
        """The `user_metadata` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().user_metadata

    # Helper methods
    @classmethod
    def _get_crypt_context(cls) -> "CryptContext":
        """Returns the password encryption context.

        Returns:
            The password encryption context.
        """
        from passlib.context import CryptContext

        return CryptContext(schemes=["bcrypt"], deprecated="auto")

activation_token property

The activation_token property.

Returns:

Type Description
Optional[str]

the value of the property.

active property

The active property.

Returns:

Type Description
bool

the value of the property.

email property

The email property.

Returns:

Type Description
Optional[str]

the value of the property.

email_opted_in property

The email_opted_in property.

Returns:

Type Description
Optional[bool]

the value of the property.

external_user_id property

The external_user_id property.

Returns:

Type Description
Optional[UUID]

the value of the property.

full_name property

The full_name property.

Returns:

Type Description
str

the value of the property.

is_admin property

The is_admin property.

Returns:

Type Description
bool

Whether the user is an admin.

is_service_account property

The is_service_account property.

Returns:

Type Description
bool

the value of the property.

user_metadata property

The user_metadata property.

Returns:

Type Description
Dict[str, Any]

the value of the property.

get_hydrated_version()

Get the hydrated version of this user.

Returns:

Type Description
UserResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/user.py
333
334
335
336
337
338
339
340
341
def get_hydrated_version(self) -> "UserResponse":
    """Get the hydrated version of this user.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_user(self.id)

UserResponseBody

Bases: BaseDatedResponseBody

Response body for users.

Source code in src/zenml/models/v2/core/user.py
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
class UserResponseBody(BaseDatedResponseBody):
    """Response body for users."""

    active: bool = Field(default=False, title="Whether the account is active.")
    activation_token: Optional[str] = Field(
        default=None,
        max_length=STR_FIELD_MAX_LENGTH,
        title="The activation token for the user. Only relevant for user "
        "accounts.",
    )
    full_name: str = Field(
        default="",
        title="The full name for the account owner. Only relevant for user "
        "accounts.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    email_opted_in: Optional[bool] = Field(
        default=None,
        title="Whether the user agreed to share their email. Only relevant for "
        "user accounts",
        description="`null` if not answered, `true` if agreed, "
        "`false` if skipped.",
    )
    is_service_account: bool = Field(
        title="Indicates whether this is a service account or a user account."
    )
    is_admin: bool = Field(
        title="Whether the account is an administrator.",
    )

UserResponseMetadata

Bases: BaseResponseMetadata

Response metadata for users.

Source code in src/zenml/models/v2/core/user.py
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
class UserResponseMetadata(BaseResponseMetadata):
    """Response metadata for users."""

    email: Optional[str] = Field(
        default="",
        title="The email address associated with the account. Only relevant "
        "for user accounts.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    external_user_id: Optional[UUID] = Field(
        default=None,
        title="The external user ID associated with the account. Only relevant "
        "for user accounts.",
    )
    user_metadata: Dict[str, Any] = Field(
        default={},
        title="The metadata associated with the user.",
    )

UserScopedFilter

Bases: BaseFilter

Model to enable advanced user-based scoping.

Source code in src/zenml/models/v2/base/scoped.py
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
class UserScopedFilter(BaseFilter):
    """Model to enable advanced user-based scoping."""

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *BaseFilter.FILTER_EXCLUDE_FIELDS,
        "user",
        "scope_user",
    ]
    CLI_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *BaseFilter.CLI_EXCLUDE_FIELDS,
        "user_id",
        "scope_user",
    ]
    CUSTOM_SORTING_OPTIONS: ClassVar[List[str]] = [
        *BaseFilter.CUSTOM_SORTING_OPTIONS,
        "user",
    ]

    scope_user: Optional[UUID] = Field(
        default=None,
        description="The user to scope this query to.",
    )
    user_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="UUID of the user that created the entity.",
        union_mode="left_to_right",
    )
    user: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of the user that created the entity.",
    )

    def set_scope_user(self, user_id: UUID) -> None:
        """Set the user that is performing the filtering to scope the response.

        Args:
            user_id: The user ID to scope the response to.
        """
        self.scope_user = user_id

    def get_custom_filters(
        self, table: Type["AnySchema"]
    ) -> List["ColumnElement[bool]"]:
        """Get custom filters.

        Args:
            table: The query table.

        Returns:
            A list of custom filters.
        """
        custom_filters = super().get_custom_filters(table)

        from sqlmodel import and_

        from zenml.zen_stores.schemas import UserSchema

        if self.user:
            user_filter = and_(
                getattr(table, "user_id") == UserSchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.user,
                    table=UserSchema,
                    additional_columns=["full_name"],
                ),
            )
            custom_filters.append(user_filter)

        return custom_filters

    def apply_sorting(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Apply sorting to the query.

        Args:
            query: The query to which to apply the sorting.
            table: The query table.

        Returns:
            The query with sorting applied.
        """
        from sqlmodel import asc, desc

        from zenml.enums import SorterOps
        from zenml.zen_stores.schemas import UserSchema

        sort_by, operand = self.sorting_params

        if sort_by == "user":
            column = UserSchema.name

            query = query.outerjoin(
                UserSchema,
                getattr(table, "user_id") == UserSchema.id,
            )

            query = query.add_columns(UserSchema.name)

            if operand == SorterOps.ASCENDING:
                query = query.order_by(asc(column))
            else:
                query = query.order_by(desc(column))

            return query

        return super().apply_sorting(query=query, table=table)

    def apply_filter(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Applies the filter to a query.

        Args:
            query: The query to which to apply the filter.
            table: The query table.

        Returns:
            The query with filter applied.
        """
        query = super().apply_filter(query=query, table=table)

        if self.scope_user:
            query = query.where(getattr(table, "user_id") == self.scope_user)

        return query

apply_filter(query, table)

Applies the filter to a query.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the filter.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with filter applied.

Source code in src/zenml/models/v2/base/scoped.py
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
def apply_filter(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Applies the filter to a query.

    Args:
        query: The query to which to apply the filter.
        table: The query table.

    Returns:
        The query with filter applied.
    """
    query = super().apply_filter(query=query, table=table)

    if self.scope_user:
        query = query.where(getattr(table, "user_id") == self.scope_user)

    return query

apply_sorting(query, table)

Apply sorting to the query.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the sorting.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with sorting applied.

Source code in src/zenml/models/v2/base/scoped.py
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
def apply_sorting(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Apply sorting to the query.

    Args:
        query: The query to which to apply the sorting.
        table: The query table.

    Returns:
        The query with sorting applied.
    """
    from sqlmodel import asc, desc

    from zenml.enums import SorterOps
    from zenml.zen_stores.schemas import UserSchema

    sort_by, operand = self.sorting_params

    if sort_by == "user":
        column = UserSchema.name

        query = query.outerjoin(
            UserSchema,
            getattr(table, "user_id") == UserSchema.id,
        )

        query = query.add_columns(UserSchema.name)

        if operand == SorterOps.ASCENDING:
            query = query.order_by(asc(column))
        else:
            query = query.order_by(desc(column))

        return query

    return super().apply_sorting(query=query, table=table)

get_custom_filters(table)

Get custom filters.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
List[ColumnElement[bool]]

A list of custom filters.

Source code in src/zenml/models/v2/base/scoped.py
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
def get_custom_filters(
    self, table: Type["AnySchema"]
) -> List["ColumnElement[bool]"]:
    """Get custom filters.

    Args:
        table: The query table.

    Returns:
        A list of custom filters.
    """
    custom_filters = super().get_custom_filters(table)

    from sqlmodel import and_

    from zenml.zen_stores.schemas import UserSchema

    if self.user:
        user_filter = and_(
            getattr(table, "user_id") == UserSchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.user,
                table=UserSchema,
                additional_columns=["full_name"],
            ),
        )
        custom_filters.append(user_filter)

    return custom_filters

set_scope_user(user_id)

Set the user that is performing the filtering to scope the response.

Parameters:

Name Type Description Default
user_id UUID

The user ID to scope the response to.

required
Source code in src/zenml/models/v2/base/scoped.py
182
183
184
185
186
187
188
def set_scope_user(self, user_id: UUID) -> None:
    """Set the user that is performing the filtering to scope the response.

    Args:
        user_id: The user ID to scope the response to.
    """
    self.scope_user = user_id

UserScopedRequest

Bases: BaseRequest

Base user-owned request model.

Used as a base class for all domain models that are "owned" by a user.

Source code in src/zenml/models/v2/base/scoped.py
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class UserScopedRequest(BaseRequest):
    """Base user-owned request model.

    Used as a base class for all domain models that are "owned" by a user.
    """

    user: UUID = Field(title="The id of the user that created this resource.")

    def get_analytics_metadata(self) -> Dict[str, Any]:
        """Fetches the analytics metadata for user scoped models.

        Returns:
            The analytics metadata.
        """
        metadata = super().get_analytics_metadata()
        metadata["user_id"] = self.user
        return metadata

get_analytics_metadata()

Fetches the analytics metadata for user scoped models.

Returns:

Type Description
Dict[str, Any]

The analytics metadata.

Source code in src/zenml/models/v2/base/scoped.py
61
62
63
64
65
66
67
68
69
def get_analytics_metadata(self) -> Dict[str, Any]:
    """Fetches the analytics metadata for user scoped models.

    Returns:
        The analytics metadata.
    """
    metadata = super().get_analytics_metadata()
    metadata["user_id"] = self.user
    return metadata

UserScopedResponse

Bases: BaseIdentifiedResponse[UserBody, UserMetadata, UserResources], Generic[UserBody, UserMetadata, UserResources]

Base user-owned model.

Used as a base class for all domain models that are "owned" by a user.

Source code in src/zenml/models/v2/base/scoped.py
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
class UserScopedResponse(
    BaseIdentifiedResponse[UserBody, UserMetadata, UserResources],
    Generic[UserBody, UserMetadata, UserResources],
):
    """Base user-owned model.

    Used as a base class for all domain models that are "owned" by a user.
    """

    # Analytics
    def get_analytics_metadata(self) -> Dict[str, Any]:
        """Fetches the analytics metadata for user scoped models.

        Returns:
            The analytics metadata.
        """
        metadata = super().get_analytics_metadata()
        if self.user is not None:
            metadata["user_id"] = self.user.id
        return metadata

    # Body and metadata properties
    @property
    def user(self) -> Optional["UserResponse"]:
        """The `user` property.

        Returns:
            the value of the property.
        """
        return self.get_body().user

user property

The user property.

Returns:

Type Description
Optional[UserResponse]

the value of the property.

get_analytics_metadata()

Fetches the analytics metadata for user scoped models.

Returns:

Type Description
Dict[str, Any]

The analytics metadata.

Source code in src/zenml/models/v2/base/scoped.py
128
129
130
131
132
133
134
135
136
137
def get_analytics_metadata(self) -> Dict[str, Any]:
    """Fetches the analytics metadata for user scoped models.

    Returns:
        The analytics metadata.
    """
    metadata = super().get_analytics_metadata()
    if self.user is not None:
        metadata["user_id"] = self.user.id
    return metadata

UserScopedResponseBody

Bases: BaseDatedResponseBody

Base user-owned body.

Source code in src/zenml/models/v2/base/scoped.py
 97
 98
 99
100
101
102
class UserScopedResponseBody(BaseDatedResponseBody):
    """Base user-owned body."""

    user: Optional["UserResponse"] = Field(
        title="The user who created this resource.", default=None
    )

UserScopedResponseMetadata

Bases: BaseResponseMetadata

Base user-owned metadata.

Source code in src/zenml/models/v2/base/scoped.py
105
106
class UserScopedResponseMetadata(BaseResponseMetadata):
    """Base user-owned metadata."""

UserUpdate

Bases: UserBase, BaseZenModel

Update model for users.

Source code in src/zenml/models/v2/core/user.py
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
class UserUpdate(UserBase, BaseZenModel):
    """Update model for users."""

    name: Optional[str] = Field(
        title="The unique username for the account.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    full_name: Optional[str] = Field(
        default=None,
        title="The full name for the account owner. Only relevant for user "
        "accounts.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    is_admin: Optional[bool] = Field(
        default=None,
        title="Whether the account is an administrator.",
    )
    active: Optional[bool] = Field(
        default=None, title="Whether the account is active."
    )
    old_password: Optional[str] = Field(
        default=None,
        title="The previous password for the user. Only relevant for user "
        "accounts. Required when updating the password.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    @model_validator(mode="after")
    def user_email_updates(self) -> "UserUpdate":
        """Validate that the UserUpdateModel conforms to the email-opt-in-flow.

        Returns:
            The validated values.

        Raises:
            ValueError: If the email was not provided when the email_opted_in
                field was set to True.
        """
        # When someone sets the email, or updates the email and hasn't
        #  before explicitly opted out, they are opted in
        if self.email is not None:
            if self.email_opted_in is None:
                self.email_opted_in = True

        # It should not be possible to do opt in without an email
        if self.email_opted_in is True:
            if self.email is None:
                raise ValueError(
                    "Please provide an email, when you are opting-in with "
                    "your email."
                )
        return self

    def create_copy(self, exclude: AbstractSet[str]) -> "UserUpdate":
        """Create a copy of the current instance.

        Args:
            exclude: Fields to exclude from the copy.

        Returns:
            A copy of the current instance.
        """
        return UserUpdate(
            **self.model_dump(
                exclude=set(exclude),
                exclude_unset=True,
            )
        )

create_copy(exclude)

Create a copy of the current instance.

Parameters:

Name Type Description Default
exclude AbstractSet[str]

Fields to exclude from the copy.

required

Returns:

Type Description
UserUpdate

A copy of the current instance.

Source code in src/zenml/models/v2/core/user.py
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
def create_copy(self, exclude: AbstractSet[str]) -> "UserUpdate":
    """Create a copy of the current instance.

    Args:
        exclude: Fields to exclude from the copy.

    Returns:
        A copy of the current instance.
    """
    return UserUpdate(
        **self.model_dump(
            exclude=set(exclude),
            exclude_unset=True,
        )
    )

user_email_updates()

Validate that the UserUpdateModel conforms to the email-opt-in-flow.

Returns:

Type Description
UserUpdate

The validated values.

Raises:

Type Description
ValueError

If the email was not provided when the email_opted_in field was set to True.

Source code in src/zenml/models/v2/core/user.py
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
@model_validator(mode="after")
def user_email_updates(self) -> "UserUpdate":
    """Validate that the UserUpdateModel conforms to the email-opt-in-flow.

    Returns:
        The validated values.

    Raises:
        ValueError: If the email was not provided when the email_opted_in
            field was set to True.
    """
    # When someone sets the email, or updates the email and hasn't
    #  before explicitly opted out, they are opted in
    if self.email is not None:
        if self.email_opted_in is None:
            self.email_opted_in = True

    # It should not be possible to do opt in without an email
    if self.email_opted_in is True:
        if self.email is None:
            raise ValueError(
                "Please provide an email, when you are opting-in with "
                "your email."
            )
    return self

WorkspaceFilter

Bases: BaseFilter

Model to enable advanced filtering of all Workspaces.

Source code in src/zenml/models/v2/core/workspace.py
125
126
127
128
129
130
131
class WorkspaceFilter(BaseFilter):
    """Model to enable advanced filtering of all Workspaces."""

    name: Optional[str] = Field(
        default=None,
        description="Name of the workspace",
    )

WorkspaceRequest

Bases: BaseRequest

Request model for workspaces.

Source code in src/zenml/models/v2/core/workspace.py
34
35
36
37
38
39
40
41
42
43
44
45
class WorkspaceRequest(BaseRequest):
    """Request model for workspaces."""

    name: str = Field(
        title="The unique name of the workspace.",
        max_length=STR_FIELD_MAX_LENGTH,
    )
    description: str = Field(
        default="",
        title="The description of the workspace.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

WorkspaceResponse

Bases: BaseIdentifiedResponse[WorkspaceResponseBody, WorkspaceResponseMetadata, WorkspaceResponseResources]

Response model for workspaces.

Source code in src/zenml/models/v2/core/workspace.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
class WorkspaceResponse(
    BaseIdentifiedResponse[
        WorkspaceResponseBody,
        WorkspaceResponseMetadata,
        WorkspaceResponseResources,
    ]
):
    """Response model for workspaces."""

    name: str = Field(
        title="The unique name of the workspace.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

    def get_hydrated_version(self) -> "WorkspaceResponse":
        """Get the hydrated version of this workspace.

        Returns:
            an instance of the same entity with the metadata field attached.
        """
        from zenml.client import Client

        return Client().zen_store.get_workspace(self.id)

    # Body and metadata properties
    @property
    def description(self) -> str:
        """The `description` property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().description

description property

The description property.

Returns:

Type Description
str

the value of the property.

get_hydrated_version()

Get the hydrated version of this workspace.

Returns:

Type Description
WorkspaceResponse

an instance of the same entity with the metadata field attached.

Source code in src/zenml/models/v2/core/workspace.py
101
102
103
104
105
106
107
108
109
def get_hydrated_version(self) -> "WorkspaceResponse":
    """Get the hydrated version of this workspace.

    Returns:
        an instance of the same entity with the metadata field attached.
    """
    from zenml.client import Client

    return Client().zen_store.get_workspace(self.id)

WorkspaceResponseBody

Bases: BaseDatedResponseBody

Response body for workspaces.

Source code in src/zenml/models/v2/core/workspace.py
69
70
class WorkspaceResponseBody(BaseDatedResponseBody):
    """Response body for workspaces."""

WorkspaceResponseMetadata

Bases: BaseResponseMetadata

Response metadata for workspaces.

Source code in src/zenml/models/v2/core/workspace.py
73
74
75
76
77
78
79
80
class WorkspaceResponseMetadata(BaseResponseMetadata):
    """Response metadata for workspaces."""

    description: str = Field(
        default="",
        title="The description of the workspace.",
        max_length=STR_FIELD_MAX_LENGTH,
    )

WorkspaceScopedFilter

Bases: UserScopedFilter

Model to enable advanced scoping with workspace.

Source code in src/zenml/models/v2/base/scoped.py
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
class WorkspaceScopedFilter(UserScopedFilter):
    """Model to enable advanced scoping with workspace."""

    FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *UserScopedFilter.FILTER_EXCLUDE_FIELDS,
        "workspace",
        "scope_workspace",
    ]
    CLI_EXCLUDE_FIELDS: ClassVar[List[str]] = [
        *UserScopedFilter.CLI_EXCLUDE_FIELDS,
        "workspace_id",
        "workspace",
        "scope_workspace",
    ]
    CUSTOM_SORTING_OPTIONS: ClassVar[List[str]] = [
        *UserScopedFilter.CUSTOM_SORTING_OPTIONS,
        "workspace",
    ]
    scope_workspace: Optional[UUID] = Field(
        default=None,
        description="The workspace to scope this query to.",
    )
    workspace_id: Optional[Union[UUID, str]] = Field(
        default=None,
        description="UUID of the workspace that this entity belongs to.",
        union_mode="left_to_right",
    )
    workspace: Optional[Union[UUID, str]] = Field(
        default=None,
        description="Name/ID of the workspace that this entity belongs to.",
    )

    def set_scope_workspace(self, workspace_id: UUID) -> None:
        """Set the workspace to scope this response.

        Args:
            workspace_id: The workspace to scope this response to.
        """
        self.scope_workspace = workspace_id

    def get_custom_filters(
        self, table: Type["AnySchema"]
    ) -> List["ColumnElement[bool]"]:
        """Get custom filters.

        Args:
            table: The query table.

        Returns:
            A list of custom filters.
        """
        custom_filters = super().get_custom_filters(table)

        from sqlmodel import and_

        from zenml.zen_stores.schemas import WorkspaceSchema

        if self.workspace:
            workspace_filter = and_(
                getattr(table, "workspace_id") == WorkspaceSchema.id,
                self.generate_name_or_id_query_conditions(
                    value=self.workspace,
                    table=WorkspaceSchema,
                ),
            )
            custom_filters.append(workspace_filter)

        return custom_filters

    def apply_filter(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Applies the filter to a query.

        Args:
            query: The query to which to apply the filter.
            table: The query table.

        Returns:
            The query with filter applied.
        """
        from sqlmodel import or_

        query = super().apply_filter(query=query, table=table)

        if self.scope_workspace:
            scope_filter = or_(
                getattr(table, "workspace_id") == self.scope_workspace,
                getattr(table, "workspace_id").is_(None),
            )
            query = query.where(scope_filter)

        return query

    def apply_sorting(
        self,
        query: AnyQuery,
        table: Type["AnySchema"],
    ) -> AnyQuery:
        """Apply sorting to the query.

        Args:
            query: The query to which to apply the sorting.
            table: The query table.

        Returns:
            The query with sorting applied.
        """
        from sqlmodel import asc, desc

        from zenml.enums import SorterOps
        from zenml.zen_stores.schemas import WorkspaceSchema

        sort_by, operand = self.sorting_params

        if sort_by == "workspace":
            column = WorkspaceSchema.name

            query = query.join(
                WorkspaceSchema,
                getattr(table, "workspace_id") == WorkspaceSchema.id,
            )

            query = query.add_columns(WorkspaceSchema.name)

            if operand == SorterOps.ASCENDING:
                query = query.order_by(asc(column))
            else:
                query = query.order_by(desc(column))

            return query

        return super().apply_sorting(query=query, table=table)

apply_filter(query, table)

Applies the filter to a query.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the filter.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with filter applied.

Source code in src/zenml/models/v2/base/scoped.py
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
def apply_filter(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Applies the filter to a query.

    Args:
        query: The query to which to apply the filter.
        table: The query table.

    Returns:
        The query with filter applied.
    """
    from sqlmodel import or_

    query = super().apply_filter(query=query, table=table)

    if self.scope_workspace:
        scope_filter = or_(
            getattr(table, "workspace_id") == self.scope_workspace,
            getattr(table, "workspace_id").is_(None),
        )
        query = query.where(scope_filter)

    return query

apply_sorting(query, table)

Apply sorting to the query.

Parameters:

Name Type Description Default
query AnyQuery

The query to which to apply the sorting.

required
table Type[AnySchema]

The query table.

required

Returns:

Type Description
AnyQuery

The query with sorting applied.

Source code in src/zenml/models/v2/base/scoped.py
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
def apply_sorting(
    self,
    query: AnyQuery,
    table: Type["AnySchema"],
) -> AnyQuery:
    """Apply sorting to the query.

    Args:
        query: The query to which to apply the sorting.
        table: The query table.

    Returns:
        The query with sorting applied.
    """
    from sqlmodel import asc, desc

    from zenml.enums import SorterOps
    from zenml.zen_stores.schemas import WorkspaceSchema

    sort_by, operand = self.sorting_params

    if sort_by == "workspace":
        column = WorkspaceSchema.name

        query = query.join(
            WorkspaceSchema,
            getattr(table, "workspace_id") == WorkspaceSchema.id,
        )

        query = query.add_columns(WorkspaceSchema.name)

        if operand == SorterOps.ASCENDING:
            query = query.order_by(asc(column))
        else:
            query = query.order_by(desc(column))

        return query

    return super().apply_sorting(query=query, table=table)

get_custom_filters(table)

Get custom filters.

Parameters:

Name Type Description Default
table Type[AnySchema]

The query table.

required

Returns:

Type Description
List[ColumnElement[bool]]

A list of custom filters.

Source code in src/zenml/models/v2/base/scoped.py
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
def get_custom_filters(
    self, table: Type["AnySchema"]
) -> List["ColumnElement[bool]"]:
    """Get custom filters.

    Args:
        table: The query table.

    Returns:
        A list of custom filters.
    """
    custom_filters = super().get_custom_filters(table)

    from sqlmodel import and_

    from zenml.zen_stores.schemas import WorkspaceSchema

    if self.workspace:
        workspace_filter = and_(
            getattr(table, "workspace_id") == WorkspaceSchema.id,
            self.generate_name_or_id_query_conditions(
                value=self.workspace,
                table=WorkspaceSchema,
            ),
        )
        custom_filters.append(workspace_filter)

    return custom_filters

set_scope_workspace(workspace_id)

Set the workspace to scope this response.

Parameters:

Name Type Description Default
workspace_id UUID

The workspace to scope this response to.

required
Source code in src/zenml/models/v2/base/scoped.py
362
363
364
365
366
367
368
def set_scope_workspace(self, workspace_id: UUID) -> None:
    """Set the workspace to scope this response.

    Args:
        workspace_id: The workspace to scope this response to.
    """
    self.scope_workspace = workspace_id

WorkspaceScopedRequest

Bases: UserScopedRequest

Base workspace-scoped request domain model.

Used as a base class for all domain models that are workspace-scoped.

Source code in src/zenml/models/v2/base/scoped.py
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
class WorkspaceScopedRequest(UserScopedRequest):
    """Base workspace-scoped request domain model.

    Used as a base class for all domain models that are workspace-scoped.
    """

    workspace: UUID = Field(
        title="The workspace to which this resource belongs."
    )

    def get_analytics_metadata(self) -> Dict[str, Any]:
        """Fetches the analytics metadata for workspace scoped models.

        Returns:
            The analytics metadata.
        """
        metadata = super().get_analytics_metadata()
        metadata["workspace_id"] = self.workspace
        return metadata

get_analytics_metadata()

Fetches the analytics metadata for workspace scoped models.

Returns:

Type Description
Dict[str, Any]

The analytics metadata.

Source code in src/zenml/models/v2/base/scoped.py
82
83
84
85
86
87
88
89
90
def get_analytics_metadata(self) -> Dict[str, Any]:
    """Fetches the analytics metadata for workspace scoped models.

    Returns:
        The analytics metadata.
    """
    metadata = super().get_analytics_metadata()
    metadata["workspace_id"] = self.workspace
    return metadata

WorkspaceScopedResponse

Bases: UserScopedResponse[WorkspaceBody, WorkspaceMetadata, WorkspaceResources], Generic[WorkspaceBody, WorkspaceMetadata, WorkspaceResources]

Base workspace-scoped domain model.

Used as a base class for all domain models that are workspace-scoped.

Source code in src/zenml/models/v2/base/scoped.py
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
class WorkspaceScopedResponse(
    UserScopedResponse[WorkspaceBody, WorkspaceMetadata, WorkspaceResources],
    Generic[WorkspaceBody, WorkspaceMetadata, WorkspaceResources],
):
    """Base workspace-scoped domain model.

    Used as a base class for all domain models that are workspace-scoped.
    """

    # Body and metadata properties
    @property
    def workspace(self) -> "WorkspaceResponse":
        """The workspace property.

        Returns:
            the value of the property.
        """
        return self.get_metadata().workspace

workspace property

The workspace property.

Returns:

Type Description
WorkspaceResponse

the value of the property.

WorkspaceScopedResponseBody

Bases: UserScopedResponseBody

Base workspace-scoped body.

Source code in src/zenml/models/v2/base/scoped.py
285
286
class WorkspaceScopedResponseBody(UserScopedResponseBody):
    """Base workspace-scoped body."""

WorkspaceScopedResponseMetadata

Bases: UserScopedResponseMetadata

Base workspace-scoped metadata.

Source code in src/zenml/models/v2/base/scoped.py
289
290
291
292
293
294
class WorkspaceScopedResponseMetadata(UserScopedResponseMetadata):
    """Base workspace-scoped metadata."""

    workspace: "WorkspaceResponse" = Field(
        title="The workspace of this resource."
    )

WorkspaceScopedResponseResources

Bases: UserScopedResponseResources

Base workspace-scoped resources.

Source code in src/zenml/models/v2/base/scoped.py
297
298
class WorkspaceScopedResponseResources(UserScopedResponseResources):
    """Base workspace-scoped resources."""

WorkspaceUpdate

Bases: BaseUpdate

Update model for workspaces.

Source code in src/zenml/models/v2/core/workspace.py
51
52
53
54
55
56
57
58
59
60
61
62
63
class WorkspaceUpdate(BaseUpdate):
    """Update model for workspaces."""

    name: Optional[str] = Field(
        title="The unique name of the workspace.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )
    description: Optional[str] = Field(
        title="The description of the workspace.",
        max_length=STR_FIELD_MAX_LENGTH,
        default=None,
    )