zenml-nightly 0.75.0.dev20250312__py3-none-any.whl → 0.75.0.dev20250314__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zenml/VERSION +1 -1
- zenml/__init__.py +2 -0
- zenml/analytics/context.py +7 -0
- zenml/analytics/enums.py +2 -2
- zenml/artifacts/utils.py +2 -4
- zenml/cli/__init__.py +8 -9
- zenml/cli/base.py +2 -2
- zenml/cli/code_repository.py +1 -1
- zenml/cli/login.py +6 -0
- zenml/cli/model.py +7 -15
- zenml/cli/pipeline.py +3 -3
- zenml/cli/project.py +172 -0
- zenml/cli/secret.py +47 -44
- zenml/cli/service_accounts.py +0 -1
- zenml/cli/service_connectors.py +15 -17
- zenml/cli/stack.py +0 -3
- zenml/cli/stack_components.py +2 -2
- zenml/cli/tag.py +3 -5
- zenml/cli/utils.py +25 -23
- zenml/client.py +749 -475
- zenml/config/global_config.py +48 -37
- zenml/config/pipeline_configurations.py +3 -2
- zenml/config/pipeline_run_configuration.py +2 -1
- zenml/config/secret_reference_mixin.py +1 -1
- zenml/constants.py +6 -6
- zenml/enums.py +0 -7
- zenml/event_hub/event_hub.py +3 -1
- zenml/exceptions.py +0 -24
- zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +5 -3
- zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +1 -4
- zenml/integrations/gcp/service_connectors/gcp_service_connector.py +7 -6
- zenml/integrations/github/plugins/event_sources/github_webhook_event_source.py +1 -4
- zenml/integrations/mlflow/steps/mlflow_registry.py +3 -3
- zenml/integrations/seldon/model_deployers/seldon_model_deployer.py +1 -1
- zenml/integrations/wandb/__init__.py +1 -1
- zenml/integrations/wandb/experiment_trackers/wandb_experiment_tracker.py +29 -9
- zenml/integrations/wandb/flavors/wandb_experiment_tracker_flavor.py +5 -3
- zenml/model/model.py +10 -10
- zenml/model_registries/base_model_registry.py +1 -1
- zenml/models/__init__.py +45 -28
- zenml/models/v2/base/base.py +0 -5
- zenml/models/v2/base/filter.py +2 -2
- zenml/models/v2/base/scoped.py +135 -156
- zenml/models/v2/core/action.py +12 -12
- zenml/models/v2/core/api_key.py +1 -1
- zenml/models/v2/core/artifact.py +31 -18
- zenml/models/v2/core/artifact_version.py +57 -40
- zenml/models/v2/core/code_repository.py +12 -12
- zenml/models/v2/core/component.py +22 -33
- zenml/models/v2/core/device.py +3 -2
- zenml/models/v2/core/event_source.py +14 -14
- zenml/models/v2/core/flavor.py +19 -47
- zenml/models/v2/core/logs.py +1 -2
- zenml/models/v2/core/model.py +23 -20
- zenml/models/v2/core/model_version.py +51 -42
- zenml/models/v2/core/pipeline.py +16 -16
- zenml/models/v2/core/pipeline_build.py +14 -14
- zenml/models/v2/core/pipeline_deployment.py +12 -14
- zenml/models/v2/core/pipeline_run.py +21 -29
- zenml/models/v2/core/project.py +203 -0
- zenml/models/v2/core/run_metadata.py +2 -2
- zenml/models/v2/core/run_template.py +16 -17
- zenml/models/v2/core/schedule.py +12 -21
- zenml/models/v2/core/secret.py +94 -128
- zenml/models/v2/core/server_settings.py +2 -2
- zenml/models/v2/core/service.py +57 -26
- zenml/models/v2/core/service_connector.py +14 -16
- zenml/models/v2/core/stack.py +24 -26
- zenml/models/v2/core/step_run.py +16 -28
- zenml/models/v2/core/tag.py +41 -15
- zenml/models/v2/core/trigger.py +13 -13
- zenml/models/v2/core/trigger_execution.py +2 -2
- zenml/models/v2/core/user.py +2 -2
- zenml/models/v2/misc/statistics.py +45 -0
- zenml/models/v2/misc/tag.py +27 -0
- zenml/orchestrators/cache_utils.py +7 -7
- zenml/orchestrators/input_utils.py +1 -0
- zenml/orchestrators/step_launcher.py +1 -2
- zenml/orchestrators/step_run_utils.py +2 -4
- zenml/orchestrators/step_runner.py +10 -1
- zenml/orchestrators/utils.py +4 -4
- zenml/pipelines/build_utils.py +2 -4
- zenml/pipelines/pipeline_decorator.py +3 -2
- zenml/pipelines/pipeline_definition.py +8 -9
- zenml/pipelines/run_utils.py +4 -4
- zenml/service_connectors/service_connector.py +0 -10
- zenml/service_connectors/service_connector_utils.py +0 -2
- zenml/stack/authentication_mixin.py +1 -1
- zenml/stack/flavor.py +3 -14
- zenml/stack/stack.py +0 -1
- zenml/stack/stack_component.py +1 -5
- zenml/steps/base_step.py +10 -2
- zenml/steps/step_context.py +19 -0
- zenml/utils/string_utils.py +1 -1
- zenml/utils/tag_utils.py +642 -0
- zenml/zen_server/cloud_utils.py +21 -0
- zenml/zen_server/exceptions.py +0 -6
- zenml/zen_server/rbac/endpoint_utils.py +134 -46
- zenml/zen_server/rbac/models.py +65 -3
- zenml/zen_server/rbac/rbac_interface.py +9 -0
- zenml/zen_server/rbac/rbac_sql_zen_store.py +15 -7
- zenml/zen_server/rbac/utils.py +155 -30
- zenml/zen_server/rbac/zenml_cloud_rbac.py +39 -11
- zenml/zen_server/routers/actions_endpoints.py +3 -5
- zenml/zen_server/routers/artifact_endpoint.py +0 -5
- zenml/zen_server/routers/artifact_version_endpoints.py +15 -9
- zenml/zen_server/routers/auth_endpoints.py +22 -7
- zenml/zen_server/routers/code_repositories_endpoints.py +54 -3
- zenml/zen_server/routers/devices_endpoints.py +0 -4
- zenml/zen_server/routers/event_source_endpoints.py +0 -5
- zenml/zen_server/routers/flavors_endpoints.py +0 -5
- zenml/zen_server/routers/logs_endpoints.py +0 -1
- zenml/zen_server/routers/model_versions_endpoints.py +100 -23
- zenml/zen_server/routers/models_endpoints.py +50 -69
- zenml/zen_server/routers/pipeline_builds_endpoints.py +55 -3
- zenml/zen_server/routers/pipeline_deployments_endpoints.py +56 -4
- zenml/zen_server/routers/pipelines_endpoints.py +70 -3
- zenml/zen_server/routers/plugin_endpoints.py +0 -1
- zenml/zen_server/routers/projects_endpoints.py +283 -0
- zenml/zen_server/routers/run_metadata_endpoints.py +97 -0
- zenml/zen_server/routers/run_templates_endpoints.py +64 -3
- zenml/zen_server/routers/runs_endpoints.py +58 -8
- zenml/zen_server/routers/schedule_endpoints.py +67 -6
- zenml/zen_server/routers/secrets_endpoints.py +38 -4
- zenml/zen_server/routers/server_endpoints.py +53 -1
- zenml/zen_server/routers/service_accounts_endpoints.py +14 -15
- zenml/zen_server/routers/service_connectors_endpoints.py +94 -14
- zenml/zen_server/routers/service_endpoints.py +18 -7
- zenml/zen_server/routers/stack_components_endpoints.py +66 -7
- zenml/zen_server/routers/stacks_endpoints.py +95 -6
- zenml/zen_server/routers/steps_endpoints.py +17 -11
- zenml/zen_server/routers/tag_resource_endpoints.py +115 -0
- zenml/zen_server/routers/tags_endpoints.py +6 -17
- zenml/zen_server/routers/triggers_endpoints.py +5 -8
- zenml/zen_server/routers/users_endpoints.py +9 -12
- zenml/zen_server/template_execution/utils.py +8 -7
- zenml/zen_server/utils.py +21 -0
- zenml/zen_server/zen_server_api.py +7 -2
- zenml/zen_stores/base_zen_store.py +50 -69
- zenml/zen_stores/migrations/versions/12eff0206201_rename_workspace_to_project.py +768 -0
- zenml/zen_stores/migrations/versions/1cb6477f72d6_move_artifact_save_type.py +20 -10
- zenml/zen_stores/migrations/versions/1f9d1cd00b90_add_unique_name_constraints.py +231 -0
- zenml/zen_stores/migrations/versions/288f4fb6e112_make_tags_user_scoped.py +74 -0
- zenml/zen_stores/migrations/versions/2e695a26fe7a_add_user_default_workspace.py +45 -0
- zenml/zen_stores/migrations/versions/3b1776345020_remove_workspace_from_globals.py +81 -0
- zenml/zen_stores/migrations/versions/41b28cae31ce_make_artifacts_workspace_scoped.py +136 -0
- zenml/zen_stores/migrations/versions/9e7bf0970266_adding_exclusive_attribute_to_tags.py +47 -0
- zenml/zen_stores/migrations/versions/b557b2871693_update_step_run_input_types.py +8 -4
- zenml/zen_stores/migrations/versions/cbc6acd71f92_add_workspace_display_name.py +58 -0
- zenml/zen_stores/migrations/versions/cc269488e5a9_separate_run_metadata.py +12 -6
- zenml/zen_stores/migrations/versions/f1d723fd723b_add_secret_private_attr.py +61 -0
- zenml/zen_stores/migrations/versions/f76a368a25a5_add_stack_description.py +35 -0
- zenml/zen_stores/rest_zen_store.py +223 -230
- zenml/zen_stores/schemas/__init__.py +2 -2
- zenml/zen_stores/schemas/action_schemas.py +15 -8
- zenml/zen_stores/schemas/api_key_schemas.py +8 -1
- zenml/zen_stores/schemas/artifact_schemas.py +35 -10
- zenml/zen_stores/schemas/code_repository_schemas.py +22 -17
- zenml/zen_stores/schemas/component_schemas.py +9 -14
- zenml/zen_stores/schemas/event_source_schemas.py +15 -8
- zenml/zen_stores/schemas/flavor_schemas.py +14 -20
- zenml/zen_stores/schemas/model_schemas.py +18 -17
- zenml/zen_stores/schemas/pipeline_build_schemas.py +7 -7
- zenml/zen_stores/schemas/pipeline_deployment_schemas.py +10 -8
- zenml/zen_stores/schemas/pipeline_run_schemas.py +9 -12
- zenml/zen_stores/schemas/pipeline_schemas.py +9 -9
- zenml/zen_stores/schemas/{workspace_schemas.py → project_schemas.py} +53 -65
- zenml/zen_stores/schemas/run_metadata_schemas.py +5 -5
- zenml/zen_stores/schemas/run_template_schemas.py +17 -13
- zenml/zen_stores/schemas/schedule_schema.py +16 -21
- zenml/zen_stores/schemas/secret_schemas.py +15 -25
- zenml/zen_stores/schemas/service_connector_schemas.py +8 -17
- zenml/zen_stores/schemas/service_schemas.py +7 -8
- zenml/zen_stores/schemas/stack_schemas.py +12 -15
- zenml/zen_stores/schemas/step_run_schemas.py +14 -15
- zenml/zen_stores/schemas/tag_schemas.py +30 -2
- zenml/zen_stores/schemas/trigger_schemas.py +15 -8
- zenml/zen_stores/schemas/user_schemas.py +12 -2
- zenml/zen_stores/schemas/utils.py +16 -0
- zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +0 -3
- zenml/zen_stores/sql_zen_store.py +2984 -2369
- zenml/zen_stores/template_utils.py +1 -1
- zenml/zen_stores/zen_store_interface.py +136 -126
- {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/METADATA +1 -1
- {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/RECORD +188 -173
- zenml/cli/workspace.py +0 -86
- zenml/models/v2/core/workspace.py +0 -131
- zenml/zen_server/routers/workspaces_endpoints.py +0 -1469
- {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/entry_points.txt +0 -0
zenml/models/v2/core/secret.py
CHANGED
@@ -13,43 +13,52 @@
|
|
13
13
|
# permissions and limitations under the License.
|
14
14
|
"""Models representing secrets."""
|
15
15
|
|
16
|
-
from
|
17
|
-
|
16
|
+
from typing import (
|
17
|
+
TYPE_CHECKING,
|
18
|
+
ClassVar,
|
19
|
+
Dict,
|
20
|
+
List,
|
21
|
+
Optional,
|
22
|
+
Type,
|
23
|
+
TypeVar,
|
24
|
+
)
|
18
25
|
|
19
26
|
from pydantic import Field, SecretStr
|
20
27
|
|
21
28
|
from zenml.constants import STR_FIELD_MAX_LENGTH
|
22
|
-
from zenml.enums import (
|
23
|
-
GenericFilterOps,
|
24
|
-
LogicalOperators,
|
25
|
-
SecretScope,
|
26
|
-
SorterOps,
|
27
|
-
)
|
28
29
|
from zenml.models.v2.base.base import BaseUpdate
|
30
|
+
from zenml.models.v2.base.filter import AnyQuery
|
29
31
|
from zenml.models.v2.base.scoped import (
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
UserScopedFilter,
|
33
|
+
UserScopedRequest,
|
34
|
+
UserScopedResponse,
|
35
|
+
UserScopedResponseBody,
|
36
|
+
UserScopedResponseMetadata,
|
37
|
+
UserScopedResponseResources,
|
36
38
|
)
|
37
39
|
from zenml.utils.secret_utils import PlainSerializedSecretStr
|
38
40
|
|
41
|
+
if TYPE_CHECKING:
|
42
|
+
from zenml.zen_stores.schemas.base_schemas import BaseSchema
|
43
|
+
|
44
|
+
AnySchema = TypeVar("AnySchema", bound=BaseSchema)
|
45
|
+
|
39
46
|
# ------------------ Request Model ------------------
|
40
47
|
|
41
48
|
|
42
|
-
class SecretRequest(
|
43
|
-
"""Request
|
49
|
+
class SecretRequest(UserScopedRequest):
|
50
|
+
"""Request model for secrets."""
|
44
51
|
|
45
|
-
ANALYTICS_FIELDS: ClassVar[List[str]] = ["
|
52
|
+
ANALYTICS_FIELDS: ClassVar[List[str]] = ["private"]
|
46
53
|
|
47
54
|
name: str = Field(
|
48
55
|
title="The name of the secret.",
|
49
56
|
max_length=STR_FIELD_MAX_LENGTH,
|
50
57
|
)
|
51
|
-
|
52
|
-
|
58
|
+
private: bool = Field(
|
59
|
+
False,
|
60
|
+
title="Whether the secret is private. A private secret is only "
|
61
|
+
"accessible to the user who created it.",
|
53
62
|
)
|
54
63
|
values: Dict[str, Optional[PlainSerializedSecretStr]] = Field(
|
55
64
|
default_factory=dict, title="The values stored in this secret."
|
@@ -78,17 +87,19 @@ class SecretRequest(WorkspaceScopedRequest):
|
|
78
87
|
|
79
88
|
|
80
89
|
class SecretUpdate(BaseUpdate):
|
81
|
-
"""
|
90
|
+
"""Update model for secrets."""
|
82
91
|
|
83
|
-
ANALYTICS_FIELDS: ClassVar[List[str]] = ["
|
92
|
+
ANALYTICS_FIELDS: ClassVar[List[str]] = ["private"]
|
84
93
|
|
85
94
|
name: Optional[str] = Field(
|
86
95
|
title="The name of the secret.",
|
87
96
|
max_length=STR_FIELD_MAX_LENGTH,
|
88
97
|
default=None,
|
89
98
|
)
|
90
|
-
|
91
|
-
default=None,
|
99
|
+
private: Optional[bool] = Field(
|
100
|
+
default=None,
|
101
|
+
title="Whether the secret is private. A private secret is only "
|
102
|
+
"accessible to the user who created it.",
|
92
103
|
)
|
93
104
|
values: Optional[Dict[str, Optional[PlainSerializedSecretStr]]] = Field(
|
94
105
|
title="The values stored in this secret.",
|
@@ -113,33 +124,37 @@ class SecretUpdate(BaseUpdate):
|
|
113
124
|
# ------------------ Response Model ------------------
|
114
125
|
|
115
126
|
|
116
|
-
class SecretResponseBody(
|
127
|
+
class SecretResponseBody(UserScopedResponseBody):
|
117
128
|
"""Response body for secrets."""
|
118
129
|
|
119
|
-
|
120
|
-
|
130
|
+
private: bool = Field(
|
131
|
+
False,
|
132
|
+
title="Whether the secret is private. A private secret is only "
|
133
|
+
"accessible to the user who created it.",
|
121
134
|
)
|
122
135
|
values: Dict[str, Optional[PlainSerializedSecretStr]] = Field(
|
123
136
|
default_factory=dict, title="The values stored in this secret."
|
124
137
|
)
|
125
138
|
|
126
139
|
|
127
|
-
class SecretResponseMetadata(
|
140
|
+
class SecretResponseMetadata(UserScopedResponseMetadata):
|
128
141
|
"""Response metadata for secrets."""
|
129
142
|
|
130
143
|
|
131
|
-
class SecretResponseResources(
|
132
|
-
"""
|
144
|
+
class SecretResponseResources(UserScopedResponseResources):
|
145
|
+
"""Response resources for secrets."""
|
133
146
|
|
134
147
|
|
135
148
|
class SecretResponse(
|
136
|
-
|
137
|
-
SecretResponseBody,
|
149
|
+
UserScopedResponse[
|
150
|
+
SecretResponseBody,
|
151
|
+
SecretResponseMetadata,
|
152
|
+
SecretResponseResources,
|
138
153
|
]
|
139
154
|
):
|
140
155
|
"""Response model for secrets."""
|
141
156
|
|
142
|
-
ANALYTICS_FIELDS: ClassVar[List[str]] = ["
|
157
|
+
ANALYTICS_FIELDS: ClassVar[List[str]] = ["private"]
|
143
158
|
|
144
159
|
name: str = Field(
|
145
160
|
title="The name of the secret.",
|
@@ -147,7 +162,7 @@ class SecretResponse(
|
|
147
162
|
)
|
148
163
|
|
149
164
|
def get_hydrated_version(self) -> "SecretResponse":
|
150
|
-
"""Get the hydrated version of this
|
165
|
+
"""Get the hydrated version of this secret.
|
151
166
|
|
152
167
|
Returns:
|
153
168
|
an instance of the same entity with the metadata field attached.
|
@@ -159,13 +174,13 @@ class SecretResponse(
|
|
159
174
|
# Body and metadata properties
|
160
175
|
|
161
176
|
@property
|
162
|
-
def
|
163
|
-
"""The `
|
177
|
+
def private(self) -> bool:
|
178
|
+
"""The `private` property.
|
164
179
|
|
165
180
|
Returns:
|
166
181
|
the value of the property.
|
167
182
|
"""
|
168
|
-
return self.get_body().
|
183
|
+
return self.get_body().private
|
169
184
|
|
170
185
|
@property
|
171
186
|
def values(self) -> Dict[str, Optional[SecretStr]]:
|
@@ -240,11 +255,11 @@ class SecretResponse(
|
|
240
255
|
# ------------------ Filter Model ------------------
|
241
256
|
|
242
257
|
|
243
|
-
class SecretFilter(
|
244
|
-
"""Model to enable advanced filtering
|
258
|
+
class SecretFilter(UserScopedFilter):
|
259
|
+
"""Model to enable advanced secret filtering."""
|
245
260
|
|
246
261
|
FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
|
247
|
-
*
|
262
|
+
*UserScopedFilter.FILTER_EXCLUDE_FIELDS,
|
248
263
|
"values",
|
249
264
|
]
|
250
265
|
|
@@ -252,103 +267,54 @@ class SecretFilter(WorkspaceScopedFilter):
|
|
252
267
|
default=None,
|
253
268
|
description="Name of the secret",
|
254
269
|
)
|
255
|
-
|
270
|
+
private: Optional[bool] = Field(
|
256
271
|
default=None,
|
257
|
-
description="
|
258
|
-
union_mode="left_to_right",
|
272
|
+
description="Whether to filter secrets by private status",
|
259
273
|
)
|
260
274
|
|
261
|
-
|
262
|
-
|
263
|
-
|
275
|
+
def apply_filter(
|
276
|
+
self,
|
277
|
+
query: AnyQuery,
|
278
|
+
table: Type["AnySchema"],
|
279
|
+
) -> AnyQuery:
|
280
|
+
"""Applies the filter to a query.
|
264
281
|
|
265
282
|
Args:
|
266
|
-
|
283
|
+
query: The query to which to apply the filter.
|
284
|
+
table: The query table.
|
267
285
|
|
268
286
|
Returns:
|
269
|
-
The
|
270
|
-
lexicographical sorting and filtering.
|
287
|
+
The query with filter applied.
|
271
288
|
"""
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
if
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
289
|
+
# The secret user scoping works a bit differently than the other
|
290
|
+
# scoped filters. We have to filter out all private secrets that are
|
291
|
+
# not owned by the current user.
|
292
|
+
if not self.scope_user:
|
293
|
+
return super().apply_filter(query=query, table=table)
|
294
|
+
|
295
|
+
scope_user = self.scope_user
|
296
|
+
|
297
|
+
# First we apply the inherited filters without the user scoping
|
298
|
+
# applied.
|
299
|
+
self.scope_user = None
|
300
|
+
query = super().apply_filter(query=query, table=table)
|
301
|
+
self.scope_user = scope_user
|
302
|
+
|
303
|
+
# Then we apply the user scoping filter.
|
304
|
+
if self.scope_user:
|
305
|
+
from sqlmodel import and_, or_
|
306
|
+
|
307
|
+
query = query.where(
|
308
|
+
or_(
|
309
|
+
and_(
|
310
|
+
getattr(table, "user_id") == self.scope_user,
|
311
|
+
getattr(table, "private") == True, # noqa: E712
|
312
|
+
),
|
313
|
+
getattr(table, "private") == False, # noqa: E712
|
314
|
+
)
|
315
|
+
)
|
284
316
|
|
285
|
-
Returns:
|
286
|
-
True if the secret matches the filter criteria, False otherwise.
|
287
|
-
"""
|
288
|
-
for filter in self.list_of_filters:
|
289
|
-
column_value: Optional[Any] = None
|
290
|
-
if filter.column == "workspace_id":
|
291
|
-
column_value = secret.workspace.id
|
292
|
-
elif filter.column == "user_id":
|
293
|
-
column_value = secret.user.id if secret.user else None
|
294
|
-
else:
|
295
|
-
column_value = getattr(secret, filter.column)
|
296
|
-
|
297
|
-
# Convert the values to strings for lexicographical comparison.
|
298
|
-
str_column_value = self._get_filtering_value(column_value)
|
299
|
-
str_filter_value = self._get_filtering_value(filter.value)
|
300
|
-
|
301
|
-
# Compare the lexicographical values according to the operation.
|
302
|
-
if filter.operation == GenericFilterOps.EQUALS:
|
303
|
-
result = str_column_value == str_filter_value
|
304
|
-
elif filter.operation == GenericFilterOps.CONTAINS:
|
305
|
-
result = str_filter_value in str_column_value
|
306
|
-
elif filter.operation == GenericFilterOps.STARTSWITH:
|
307
|
-
result = str_column_value.startswith(str_filter_value)
|
308
|
-
elif filter.operation == GenericFilterOps.ENDSWITH:
|
309
|
-
result = str_column_value.endswith(str_filter_value)
|
310
|
-
elif filter.operation == GenericFilterOps.GT:
|
311
|
-
result = str_column_value > str_filter_value
|
312
|
-
elif filter.operation == GenericFilterOps.GTE:
|
313
|
-
result = str_column_value >= str_filter_value
|
314
|
-
elif filter.operation == GenericFilterOps.LT:
|
315
|
-
result = str_column_value < str_filter_value
|
316
|
-
elif filter.operation == GenericFilterOps.LTE:
|
317
|
-
result = str_column_value <= str_filter_value
|
318
|
-
|
319
|
-
# Exit early if the result is False for AND, and True for OR
|
320
|
-
if self.logical_operator == LogicalOperators.AND:
|
321
|
-
if not result:
|
322
|
-
return False
|
323
|
-
else:
|
324
|
-
if result:
|
325
|
-
return True
|
326
|
-
|
327
|
-
# If we get here, all filters have been checked and the result is
|
328
|
-
# True for AND, and False for OR
|
329
|
-
if self.logical_operator == LogicalOperators.AND:
|
330
|
-
return True
|
331
317
|
else:
|
332
|
-
|
318
|
+
query = query.where(getattr(table, "private") == False) # noqa: E712
|
333
319
|
|
334
|
-
|
335
|
-
self, secrets: List[SecretResponse]
|
336
|
-
) -> List[SecretResponse]:
|
337
|
-
"""Sorts a list of secrets according to the filter criteria.
|
338
|
-
|
339
|
-
Args:
|
340
|
-
secrets: The list of secrets to sort.
|
341
|
-
|
342
|
-
Returns:
|
343
|
-
The sorted list of secrets.
|
344
|
-
"""
|
345
|
-
column, sort_op = self.sorting_params
|
346
|
-
sorted_secrets = sorted(
|
347
|
-
secrets,
|
348
|
-
key=lambda secret: self._get_filtering_value(
|
349
|
-
getattr(secret, column)
|
350
|
-
),
|
351
|
-
reverse=sort_op == SorterOps.DESCENDING,
|
352
|
-
)
|
353
|
-
|
354
|
-
return sorted_secrets
|
320
|
+
return query
|
@@ -26,7 +26,7 @@ from zenml.models.v2.base.base import (
|
|
26
26
|
BaseResponseBody,
|
27
27
|
BaseResponseMetadata,
|
28
28
|
BaseResponseResources,
|
29
|
-
|
29
|
+
BaseUpdate,
|
30
30
|
)
|
31
31
|
|
32
32
|
# ------------------ Base Model ------------------
|
@@ -34,7 +34,7 @@ from zenml.models.v2.base.base import (
|
|
34
34
|
# ------------------ Update Model ------------------
|
35
35
|
|
36
36
|
|
37
|
-
class ServerSettingsUpdate(
|
37
|
+
class ServerSettingsUpdate(BaseUpdate):
|
38
38
|
"""Model for updating server settings."""
|
39
39
|
|
40
40
|
server_name: Optional[str] = Field(
|
zenml/models/v2/core/service.py
CHANGED
@@ -27,22 +27,25 @@ from typing import (
|
|
27
27
|
)
|
28
28
|
from uuid import UUID
|
29
29
|
|
30
|
-
from pydantic import
|
30
|
+
from pydantic import ConfigDict, Field
|
31
31
|
from sqlalchemy.sql.elements import ColumnElement
|
32
32
|
|
33
33
|
from zenml.constants import STR_FIELD_MAX_LENGTH
|
34
|
+
from zenml.models.v2.base.base import BaseUpdate
|
34
35
|
from zenml.models.v2.base.scoped import (
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
ProjectScopedFilter,
|
37
|
+
ProjectScopedRequest,
|
38
|
+
ProjectScopedResponse,
|
39
|
+
ProjectScopedResponseBody,
|
40
|
+
ProjectScopedResponseMetadata,
|
41
|
+
ProjectScopedResponseResources,
|
41
42
|
)
|
42
43
|
from zenml.services.service_status import ServiceState
|
43
44
|
from zenml.services.service_type import ServiceType
|
44
45
|
|
45
46
|
if TYPE_CHECKING:
|
47
|
+
from zenml.models.v2.core.model_version import ModelVersionResponse
|
48
|
+
from zenml.models.v2.core.pipeline_run import PipelineRunResponse
|
46
49
|
from zenml.zen_stores.schemas import BaseSchema
|
47
50
|
|
48
51
|
AnySchema = TypeVar("AnySchema", bound=BaseSchema)
|
@@ -50,7 +53,7 @@ if TYPE_CHECKING:
|
|
50
53
|
# ------------------ Request Model ------------------
|
51
54
|
|
52
55
|
|
53
|
-
class ServiceRequest(
|
56
|
+
class ServiceRequest(ProjectScopedRequest):
|
54
57
|
"""Request model for services."""
|
55
58
|
|
56
59
|
name: str = Field(
|
@@ -101,10 +104,9 @@ class ServiceRequest(WorkspaceScopedRequest):
|
|
101
104
|
default=None,
|
102
105
|
title="The model version id linked to the service.",
|
103
106
|
)
|
104
|
-
pipeline_run_id: Optional[
|
107
|
+
pipeline_run_id: Optional[UUID] = Field(
|
105
108
|
default=None,
|
106
|
-
|
107
|
-
union_mode="left_to_right",
|
109
|
+
title="The pipeline run id linked to the service.",
|
108
110
|
)
|
109
111
|
|
110
112
|
# TODO: In Pydantic v2, the `model_` is a protected namespaces for all
|
@@ -119,7 +121,7 @@ class ServiceRequest(WorkspaceScopedRequest):
|
|
119
121
|
# ------------------ Update Model ------------------
|
120
122
|
|
121
123
|
|
122
|
-
class ServiceUpdate(
|
124
|
+
class ServiceUpdate(BaseUpdate):
|
123
125
|
"""Update model for stack components."""
|
124
126
|
|
125
127
|
name: Optional[str] = Field(
|
@@ -176,7 +178,7 @@ class ServiceUpdate(BaseModel):
|
|
176
178
|
# ------------------ Response Model ------------------
|
177
179
|
|
178
180
|
|
179
|
-
class ServiceResponseBody(
|
181
|
+
class ServiceResponseBody(ProjectScopedResponseBody):
|
180
182
|
"""Response body for services."""
|
181
183
|
|
182
184
|
service_type: ServiceType = Field(
|
@@ -198,7 +200,7 @@ class ServiceResponseBody(WorkspaceScopedResponseBody):
|
|
198
200
|
)
|
199
201
|
|
200
202
|
|
201
|
-
class ServiceResponseMetadata(
|
203
|
+
class ServiceResponseMetadata(ProjectScopedResponseMetadata):
|
202
204
|
"""Response metadata for services."""
|
203
205
|
|
204
206
|
service_source: Optional[str] = Field(
|
@@ -227,12 +229,29 @@ class ServiceResponseMetadata(WorkspaceScopedResponseMetadata):
|
|
227
229
|
)
|
228
230
|
|
229
231
|
|
230
|
-
class ServiceResponseResources(
|
232
|
+
class ServiceResponseResources(ProjectScopedResponseResources):
|
231
233
|
"""Class for all resource models associated with the service entity."""
|
232
234
|
|
235
|
+
pipeline_run: Optional["PipelineRunResponse"] = Field(
|
236
|
+
default=None,
|
237
|
+
title="The pipeline run associated with the service.",
|
238
|
+
)
|
239
|
+
model_version: Optional["ModelVersionResponse"] = Field(
|
240
|
+
default=None,
|
241
|
+
title="The model version associated with the service.",
|
242
|
+
)
|
243
|
+
|
244
|
+
# TODO: In Pydantic v2, the `model_` is a protected namespaces for all
|
245
|
+
# fields defined under base models. If not handled, this raises a warning.
|
246
|
+
# It is possible to suppress this warning message with the following
|
247
|
+
# configuration, however the ultimate solution is to rename these fields.
|
248
|
+
# Even though they do not cause any problems right now, if we are not
|
249
|
+
# careful we might overwrite some fields protected by pydantic.
|
250
|
+
model_config = ConfigDict(protected_namespaces=())
|
251
|
+
|
233
252
|
|
234
253
|
class ServiceResponse(
|
235
|
-
|
254
|
+
ProjectScopedResponse[
|
236
255
|
ServiceResponseBody, ServiceResponseMetadata, ServiceResponseResources
|
237
256
|
]
|
238
257
|
):
|
@@ -363,18 +382,30 @@ class ServiceResponse(
|
|
363
382
|
"""
|
364
383
|
return self.get_body().state
|
365
384
|
|
385
|
+
@property
|
386
|
+
def pipeline_run(self) -> Optional["PipelineRunResponse"]:
|
387
|
+
"""The `pipeline_run` property.
|
366
388
|
|
367
|
-
|
389
|
+
Returns:
|
390
|
+
the value of the property.
|
391
|
+
"""
|
392
|
+
return self.get_resources().pipeline_run
|
393
|
+
|
394
|
+
@property
|
395
|
+
def model_version(self) -> Optional["ModelVersionResponse"]:
|
396
|
+
"""The `model_version` property.
|
368
397
|
|
398
|
+
Returns:
|
399
|
+
the value of the property.
|
400
|
+
"""
|
401
|
+
return self.get_resources().model_version
|
402
|
+
|
403
|
+
|
404
|
+
# ------------------ Filter Model ------------------
|
369
405
|
|
370
|
-
class ServiceFilter(WorkspaceScopedFilter):
|
371
|
-
"""Model to enable advanced filtering of services.
|
372
406
|
|
373
|
-
|
374
|
-
|
375
|
-
`generate_filter()` method of the baseclass is overwritten to include the
|
376
|
-
scoping.
|
377
|
-
"""
|
407
|
+
class ServiceFilter(ProjectScopedFilter):
|
408
|
+
"""Model to enable advanced filtering of services."""
|
378
409
|
|
379
410
|
name: Optional[str] = Field(
|
380
411
|
default=None,
|
@@ -443,7 +474,7 @@ class ServiceFilter(WorkspaceScopedFilter):
|
|
443
474
|
|
444
475
|
# Artifact name and type are not DB fields and need to be handled separately
|
445
476
|
FILTER_EXCLUDE_FIELDS = [
|
446
|
-
*
|
477
|
+
*ProjectScopedFilter.FILTER_EXCLUDE_FIELDS,
|
447
478
|
"flavor",
|
448
479
|
"type",
|
449
480
|
"pipeline_step_name",
|
@@ -452,7 +483,7 @@ class ServiceFilter(WorkspaceScopedFilter):
|
|
452
483
|
"config",
|
453
484
|
]
|
454
485
|
CLI_EXCLUDE_FIELDS: ClassVar[List[str]] = [
|
455
|
-
*
|
486
|
+
*ProjectScopedFilter.CLI_EXCLUDE_FIELDS,
|
456
487
|
"flavor",
|
457
488
|
"type",
|
458
489
|
"pipeline_step_name",
|
@@ -24,12 +24,12 @@ from zenml.constants import STR_FIELD_MAX_LENGTH
|
|
24
24
|
from zenml.logger import get_logger
|
25
25
|
from zenml.models.v2.base.base import BaseUpdate
|
26
26
|
from zenml.models.v2.base.scoped import (
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
UserScopedFilter,
|
28
|
+
UserScopedRequest,
|
29
|
+
UserScopedResponse,
|
30
|
+
UserScopedResponseBody,
|
31
|
+
UserScopedResponseMetadata,
|
32
|
+
UserScopedResponseResources,
|
33
33
|
)
|
34
34
|
from zenml.models.v2.misc.service_connector_type import (
|
35
35
|
ServiceConnectorTypeModel,
|
@@ -41,7 +41,7 @@ logger = get_logger(__name__)
|
|
41
41
|
# ------------------ Request Model ------------------
|
42
42
|
|
43
43
|
|
44
|
-
class ServiceConnectorRequest(
|
44
|
+
class ServiceConnectorRequest(UserScopedRequest):
|
45
45
|
"""Request model for service connectors."""
|
46
46
|
|
47
47
|
name: str = Field(
|
@@ -223,8 +223,6 @@ class ServiceConnectorUpdate(BaseUpdate):
|
|
223
223
|
valid configuration update, not just a partial update. If either is
|
224
224
|
set (i.e. not None) in the update, their values are merged together and
|
225
225
|
will replace the existing configuration and secrets values.
|
226
|
-
* the `secret_id` field value in the update is ignored, given that
|
227
|
-
secrets are managed internally by the ZenML store.
|
228
226
|
* the `labels` field is also a full labels update: if set (i.e. not
|
229
227
|
`None`), all existing labels are removed and replaced by the new labels
|
230
228
|
in the update.
|
@@ -400,7 +398,7 @@ class ServiceConnectorUpdate(BaseUpdate):
|
|
400
398
|
# ------------------ Response Model ------------------
|
401
399
|
|
402
400
|
|
403
|
-
class ServiceConnectorResponseBody(
|
401
|
+
class ServiceConnectorResponseBody(UserScopedResponseBody):
|
404
402
|
"""Response body for service connectors."""
|
405
403
|
|
406
404
|
description: str = Field(
|
@@ -446,7 +444,7 @@ class ServiceConnectorResponseBody(WorkspaceScopedResponseBody):
|
|
446
444
|
)
|
447
445
|
|
448
446
|
|
449
|
-
class ServiceConnectorResponseMetadata(
|
447
|
+
class ServiceConnectorResponseMetadata(UserScopedResponseMetadata):
|
450
448
|
"""Response metadata for service connectors."""
|
451
449
|
|
452
450
|
configuration: Dict[str, Any] = Field(
|
@@ -475,12 +473,12 @@ class ServiceConnectorResponseMetadata(WorkspaceScopedResponseMetadata):
|
|
475
473
|
)
|
476
474
|
|
477
475
|
|
478
|
-
class ServiceConnectorResponseResources(
|
476
|
+
class ServiceConnectorResponseResources(UserScopedResponseResources):
|
479
477
|
"""Class for all resource models associated with the service connector entity."""
|
480
478
|
|
481
479
|
|
482
480
|
class ServiceConnectorResponse(
|
483
|
-
|
481
|
+
UserScopedResponse[
|
484
482
|
ServiceConnectorResponseBody,
|
485
483
|
ServiceConnectorResponseMetadata,
|
486
484
|
ServiceConnectorResponseResources,
|
@@ -781,18 +779,18 @@ class ServiceConnectorResponse(
|
|
781
779
|
# ------------------ Filter Model ------------------
|
782
780
|
|
783
781
|
|
784
|
-
class ServiceConnectorFilter(
|
782
|
+
class ServiceConnectorFilter(UserScopedFilter):
|
785
783
|
"""Model to enable advanced filtering of service connectors."""
|
786
784
|
|
787
785
|
FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
|
788
|
-
*
|
786
|
+
*UserScopedFilter.FILTER_EXCLUDE_FIELDS,
|
789
787
|
"scope_type",
|
790
788
|
"resource_type",
|
791
789
|
"labels_str",
|
792
790
|
"labels",
|
793
791
|
]
|
794
792
|
CLI_EXCLUDE_FIELDS: ClassVar[List[str]] = [
|
795
|
-
*
|
793
|
+
*UserScopedFilter.CLI_EXCLUDE_FIELDS,
|
796
794
|
"scope_type",
|
797
795
|
"labels_str",
|
798
796
|
"labels",
|