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.
Files changed (191) hide show
  1. zenml/VERSION +1 -1
  2. zenml/__init__.py +2 -0
  3. zenml/analytics/context.py +7 -0
  4. zenml/analytics/enums.py +2 -2
  5. zenml/artifacts/utils.py +2 -4
  6. zenml/cli/__init__.py +8 -9
  7. zenml/cli/base.py +2 -2
  8. zenml/cli/code_repository.py +1 -1
  9. zenml/cli/login.py +6 -0
  10. zenml/cli/model.py +7 -15
  11. zenml/cli/pipeline.py +3 -3
  12. zenml/cli/project.py +172 -0
  13. zenml/cli/secret.py +47 -44
  14. zenml/cli/service_accounts.py +0 -1
  15. zenml/cli/service_connectors.py +15 -17
  16. zenml/cli/stack.py +0 -3
  17. zenml/cli/stack_components.py +2 -2
  18. zenml/cli/tag.py +3 -5
  19. zenml/cli/utils.py +25 -23
  20. zenml/client.py +749 -475
  21. zenml/config/global_config.py +48 -37
  22. zenml/config/pipeline_configurations.py +3 -2
  23. zenml/config/pipeline_run_configuration.py +2 -1
  24. zenml/config/secret_reference_mixin.py +1 -1
  25. zenml/constants.py +6 -6
  26. zenml/enums.py +0 -7
  27. zenml/event_hub/event_hub.py +3 -1
  28. zenml/exceptions.py +0 -24
  29. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +5 -3
  30. zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +1 -4
  31. zenml/integrations/gcp/service_connectors/gcp_service_connector.py +7 -6
  32. zenml/integrations/github/plugins/event_sources/github_webhook_event_source.py +1 -4
  33. zenml/integrations/mlflow/steps/mlflow_registry.py +3 -3
  34. zenml/integrations/seldon/model_deployers/seldon_model_deployer.py +1 -1
  35. zenml/integrations/wandb/__init__.py +1 -1
  36. zenml/integrations/wandb/experiment_trackers/wandb_experiment_tracker.py +29 -9
  37. zenml/integrations/wandb/flavors/wandb_experiment_tracker_flavor.py +5 -3
  38. zenml/model/model.py +10 -10
  39. zenml/model_registries/base_model_registry.py +1 -1
  40. zenml/models/__init__.py +45 -28
  41. zenml/models/v2/base/base.py +0 -5
  42. zenml/models/v2/base/filter.py +2 -2
  43. zenml/models/v2/base/scoped.py +135 -156
  44. zenml/models/v2/core/action.py +12 -12
  45. zenml/models/v2/core/api_key.py +1 -1
  46. zenml/models/v2/core/artifact.py +31 -18
  47. zenml/models/v2/core/artifact_version.py +57 -40
  48. zenml/models/v2/core/code_repository.py +12 -12
  49. zenml/models/v2/core/component.py +22 -33
  50. zenml/models/v2/core/device.py +3 -2
  51. zenml/models/v2/core/event_source.py +14 -14
  52. zenml/models/v2/core/flavor.py +19 -47
  53. zenml/models/v2/core/logs.py +1 -2
  54. zenml/models/v2/core/model.py +23 -20
  55. zenml/models/v2/core/model_version.py +51 -42
  56. zenml/models/v2/core/pipeline.py +16 -16
  57. zenml/models/v2/core/pipeline_build.py +14 -14
  58. zenml/models/v2/core/pipeline_deployment.py +12 -14
  59. zenml/models/v2/core/pipeline_run.py +21 -29
  60. zenml/models/v2/core/project.py +203 -0
  61. zenml/models/v2/core/run_metadata.py +2 -2
  62. zenml/models/v2/core/run_template.py +16 -17
  63. zenml/models/v2/core/schedule.py +12 -21
  64. zenml/models/v2/core/secret.py +94 -128
  65. zenml/models/v2/core/server_settings.py +2 -2
  66. zenml/models/v2/core/service.py +57 -26
  67. zenml/models/v2/core/service_connector.py +14 -16
  68. zenml/models/v2/core/stack.py +24 -26
  69. zenml/models/v2/core/step_run.py +16 -28
  70. zenml/models/v2/core/tag.py +41 -15
  71. zenml/models/v2/core/trigger.py +13 -13
  72. zenml/models/v2/core/trigger_execution.py +2 -2
  73. zenml/models/v2/core/user.py +2 -2
  74. zenml/models/v2/misc/statistics.py +45 -0
  75. zenml/models/v2/misc/tag.py +27 -0
  76. zenml/orchestrators/cache_utils.py +7 -7
  77. zenml/orchestrators/input_utils.py +1 -0
  78. zenml/orchestrators/step_launcher.py +1 -2
  79. zenml/orchestrators/step_run_utils.py +2 -4
  80. zenml/orchestrators/step_runner.py +10 -1
  81. zenml/orchestrators/utils.py +4 -4
  82. zenml/pipelines/build_utils.py +2 -4
  83. zenml/pipelines/pipeline_decorator.py +3 -2
  84. zenml/pipelines/pipeline_definition.py +8 -9
  85. zenml/pipelines/run_utils.py +4 -4
  86. zenml/service_connectors/service_connector.py +0 -10
  87. zenml/service_connectors/service_connector_utils.py +0 -2
  88. zenml/stack/authentication_mixin.py +1 -1
  89. zenml/stack/flavor.py +3 -14
  90. zenml/stack/stack.py +0 -1
  91. zenml/stack/stack_component.py +1 -5
  92. zenml/steps/base_step.py +10 -2
  93. zenml/steps/step_context.py +19 -0
  94. zenml/utils/string_utils.py +1 -1
  95. zenml/utils/tag_utils.py +642 -0
  96. zenml/zen_server/cloud_utils.py +21 -0
  97. zenml/zen_server/exceptions.py +0 -6
  98. zenml/zen_server/rbac/endpoint_utils.py +134 -46
  99. zenml/zen_server/rbac/models.py +65 -3
  100. zenml/zen_server/rbac/rbac_interface.py +9 -0
  101. zenml/zen_server/rbac/rbac_sql_zen_store.py +15 -7
  102. zenml/zen_server/rbac/utils.py +155 -30
  103. zenml/zen_server/rbac/zenml_cloud_rbac.py +39 -11
  104. zenml/zen_server/routers/actions_endpoints.py +3 -5
  105. zenml/zen_server/routers/artifact_endpoint.py +0 -5
  106. zenml/zen_server/routers/artifact_version_endpoints.py +15 -9
  107. zenml/zen_server/routers/auth_endpoints.py +22 -7
  108. zenml/zen_server/routers/code_repositories_endpoints.py +54 -3
  109. zenml/zen_server/routers/devices_endpoints.py +0 -4
  110. zenml/zen_server/routers/event_source_endpoints.py +0 -5
  111. zenml/zen_server/routers/flavors_endpoints.py +0 -5
  112. zenml/zen_server/routers/logs_endpoints.py +0 -1
  113. zenml/zen_server/routers/model_versions_endpoints.py +100 -23
  114. zenml/zen_server/routers/models_endpoints.py +50 -69
  115. zenml/zen_server/routers/pipeline_builds_endpoints.py +55 -3
  116. zenml/zen_server/routers/pipeline_deployments_endpoints.py +56 -4
  117. zenml/zen_server/routers/pipelines_endpoints.py +70 -3
  118. zenml/zen_server/routers/plugin_endpoints.py +0 -1
  119. zenml/zen_server/routers/projects_endpoints.py +283 -0
  120. zenml/zen_server/routers/run_metadata_endpoints.py +97 -0
  121. zenml/zen_server/routers/run_templates_endpoints.py +64 -3
  122. zenml/zen_server/routers/runs_endpoints.py +58 -8
  123. zenml/zen_server/routers/schedule_endpoints.py +67 -6
  124. zenml/zen_server/routers/secrets_endpoints.py +38 -4
  125. zenml/zen_server/routers/server_endpoints.py +53 -1
  126. zenml/zen_server/routers/service_accounts_endpoints.py +14 -15
  127. zenml/zen_server/routers/service_connectors_endpoints.py +94 -14
  128. zenml/zen_server/routers/service_endpoints.py +18 -7
  129. zenml/zen_server/routers/stack_components_endpoints.py +66 -7
  130. zenml/zen_server/routers/stacks_endpoints.py +95 -6
  131. zenml/zen_server/routers/steps_endpoints.py +17 -11
  132. zenml/zen_server/routers/tag_resource_endpoints.py +115 -0
  133. zenml/zen_server/routers/tags_endpoints.py +6 -17
  134. zenml/zen_server/routers/triggers_endpoints.py +5 -8
  135. zenml/zen_server/routers/users_endpoints.py +9 -12
  136. zenml/zen_server/template_execution/utils.py +8 -7
  137. zenml/zen_server/utils.py +21 -0
  138. zenml/zen_server/zen_server_api.py +7 -2
  139. zenml/zen_stores/base_zen_store.py +50 -69
  140. zenml/zen_stores/migrations/versions/12eff0206201_rename_workspace_to_project.py +768 -0
  141. zenml/zen_stores/migrations/versions/1cb6477f72d6_move_artifact_save_type.py +20 -10
  142. zenml/zen_stores/migrations/versions/1f9d1cd00b90_add_unique_name_constraints.py +231 -0
  143. zenml/zen_stores/migrations/versions/288f4fb6e112_make_tags_user_scoped.py +74 -0
  144. zenml/zen_stores/migrations/versions/2e695a26fe7a_add_user_default_workspace.py +45 -0
  145. zenml/zen_stores/migrations/versions/3b1776345020_remove_workspace_from_globals.py +81 -0
  146. zenml/zen_stores/migrations/versions/41b28cae31ce_make_artifacts_workspace_scoped.py +136 -0
  147. zenml/zen_stores/migrations/versions/9e7bf0970266_adding_exclusive_attribute_to_tags.py +47 -0
  148. zenml/zen_stores/migrations/versions/b557b2871693_update_step_run_input_types.py +8 -4
  149. zenml/zen_stores/migrations/versions/cbc6acd71f92_add_workspace_display_name.py +58 -0
  150. zenml/zen_stores/migrations/versions/cc269488e5a9_separate_run_metadata.py +12 -6
  151. zenml/zen_stores/migrations/versions/f1d723fd723b_add_secret_private_attr.py +61 -0
  152. zenml/zen_stores/migrations/versions/f76a368a25a5_add_stack_description.py +35 -0
  153. zenml/zen_stores/rest_zen_store.py +223 -230
  154. zenml/zen_stores/schemas/__init__.py +2 -2
  155. zenml/zen_stores/schemas/action_schemas.py +15 -8
  156. zenml/zen_stores/schemas/api_key_schemas.py +8 -1
  157. zenml/zen_stores/schemas/artifact_schemas.py +35 -10
  158. zenml/zen_stores/schemas/code_repository_schemas.py +22 -17
  159. zenml/zen_stores/schemas/component_schemas.py +9 -14
  160. zenml/zen_stores/schemas/event_source_schemas.py +15 -8
  161. zenml/zen_stores/schemas/flavor_schemas.py +14 -20
  162. zenml/zen_stores/schemas/model_schemas.py +18 -17
  163. zenml/zen_stores/schemas/pipeline_build_schemas.py +7 -7
  164. zenml/zen_stores/schemas/pipeline_deployment_schemas.py +10 -8
  165. zenml/zen_stores/schemas/pipeline_run_schemas.py +9 -12
  166. zenml/zen_stores/schemas/pipeline_schemas.py +9 -9
  167. zenml/zen_stores/schemas/{workspace_schemas.py → project_schemas.py} +53 -65
  168. zenml/zen_stores/schemas/run_metadata_schemas.py +5 -5
  169. zenml/zen_stores/schemas/run_template_schemas.py +17 -13
  170. zenml/zen_stores/schemas/schedule_schema.py +16 -21
  171. zenml/zen_stores/schemas/secret_schemas.py +15 -25
  172. zenml/zen_stores/schemas/service_connector_schemas.py +8 -17
  173. zenml/zen_stores/schemas/service_schemas.py +7 -8
  174. zenml/zen_stores/schemas/stack_schemas.py +12 -15
  175. zenml/zen_stores/schemas/step_run_schemas.py +14 -15
  176. zenml/zen_stores/schemas/tag_schemas.py +30 -2
  177. zenml/zen_stores/schemas/trigger_schemas.py +15 -8
  178. zenml/zen_stores/schemas/user_schemas.py +12 -2
  179. zenml/zen_stores/schemas/utils.py +16 -0
  180. zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +0 -3
  181. zenml/zen_stores/sql_zen_store.py +2984 -2369
  182. zenml/zen_stores/template_utils.py +1 -1
  183. zenml/zen_stores/zen_store_interface.py +136 -126
  184. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/METADATA +1 -1
  185. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/RECORD +188 -173
  186. zenml/cli/workspace.py +0 -86
  187. zenml/models/v2/core/workspace.py +0 -131
  188. zenml/zen_server/routers/workspaces_endpoints.py +0 -1469
  189. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/LICENSE +0 -0
  190. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/WHEEL +0 -0
  191. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/entry_points.txt +0 -0
zenml/models/__init__.py CHANGED
@@ -34,13 +34,13 @@ from zenml.models.v2.base.scoped import (
34
34
  UserScopedResponse,
35
35
  UserScopedResponseBody,
36
36
  UserScopedResponseMetadata,
37
- WorkspaceScopedRequest,
38
- WorkspaceScopedFilter,
39
- WorkspaceScopedResponse,
40
- WorkspaceScopedResponseBody,
41
- WorkspaceScopedResponseMetadata,
42
- WorkspaceScopedResponseResources,
43
- WorkspaceScopedFilter,
37
+ ProjectScopedRequest,
38
+ ProjectScopedFilter,
39
+ ProjectScopedResponse,
40
+ ProjectScopedResponseBody,
41
+ ProjectScopedResponseMetadata,
42
+ ProjectScopedResponseResources,
43
+ ProjectScopedFilter,
44
44
  )
45
45
  from zenml.models.v2.base.filter import (
46
46
  BaseFilter,
@@ -133,7 +133,8 @@ from zenml.models.v2.core.component import (
133
133
  ComponentResponse,
134
134
  ComponentResponseBody,
135
135
  ComponentResponseMetadata,
136
- ComponentResponseResources
136
+ ComponentResponseResources,
137
+ DefaultComponentRequest,
137
138
  )
138
139
  from zenml.models.v2.core.event_source_flavor import (
139
140
  EventSourceFlavorResponse,
@@ -275,6 +276,7 @@ from zenml.models.v2.core.service_connector import (
275
276
  ServiceConnectorResponseMetadata,
276
277
  )
277
278
  from zenml.models.v2.core.stack import (
279
+ DefaultStackRequest,
278
280
  StackRequest,
279
281
  StackUpdate,
280
282
  StackFilter,
@@ -282,6 +284,10 @@ from zenml.models.v2.core.stack import (
282
284
  StackResponseBody,
283
285
  StackResponseMetadata,
284
286
  )
287
+ from zenml.models.v2.misc.statistics import (
288
+ ProjectStatistics,
289
+ ServerStatistics,
290
+ )
285
291
  from zenml.models.v2.core.step_run import (
286
292
  StepRunRequest,
287
293
  StepRunUpdate,
@@ -295,6 +301,7 @@ from zenml.models.v2.core.tag import (
295
301
  TagFilter,
296
302
  TagResponse,
297
303
  TagResponseBody,
304
+ TagResponseMetadata,
298
305
  TagRequest,
299
306
  TagUpdate,
300
307
  )
@@ -311,13 +318,13 @@ from zenml.models.v2.core.user import (
311
318
  UserResponseBody,
312
319
  UserResponseMetadata,
313
320
  )
314
- from zenml.models.v2.core.workspace import (
315
- WorkspaceRequest,
316
- WorkspaceUpdate,
317
- WorkspaceFilter,
318
- WorkspaceResponse,
319
- WorkspaceResponseBody,
320
- WorkspaceResponseMetadata,
321
+ from zenml.models.v2.core.project import (
322
+ ProjectRequest,
323
+ ProjectUpdate,
324
+ ProjectFilter,
325
+ ProjectResponse,
326
+ ProjectResponseBody,
327
+ ProjectResponseMetadata,
321
328
  )
322
329
 
323
330
  # V2 Misc
@@ -395,6 +402,9 @@ from zenml.models.v2.misc.stack_deployment import (
395
402
  StackDeploymentConfig,
396
403
  StackDeploymentInfo,
397
404
  )
405
+ from zenml.models.v2.misc.tag import (
406
+ TagResource,
407
+ )
398
408
  from zenml.models.v2.misc.info_models import (
399
409
  ComponentInfo,
400
410
  ServiceConnectorInfo,
@@ -440,6 +450,7 @@ PipelineDeploymentRequest.model_rebuild()
440
450
  PipelineDeploymentResponseBody.model_rebuild()
441
451
  PipelineDeploymentResponseMetadata.model_rebuild()
442
452
  PipelineDeploymentResponseResources.model_rebuild()
453
+ PipelineRunRequest.model_rebuild()
443
454
  PipelineRunResponseBody.model_rebuild()
444
455
  PipelineRunResponseMetadata.model_rebuild()
445
456
  PipelineRunResponseResources.model_rebuild()
@@ -492,13 +503,13 @@ __all__ = [
492
503
  "UserScopedResponse",
493
504
  "UserScopedResponseBody",
494
505
  "UserScopedResponseMetadata",
495
- "WorkspaceScopedRequest",
496
- "WorkspaceScopedFilter",
497
- "WorkspaceScopedResponse",
498
- "WorkspaceScopedResponseBody",
499
- "WorkspaceScopedResponseMetadata",
500
- "WorkspaceScopedResponseResources",
501
- "WorkspaceScopedFilter",
506
+ "ProjectScopedRequest",
507
+ "ProjectScopedFilter",
508
+ "ProjectScopedResponse",
509
+ "ProjectScopedResponseBody",
510
+ "ProjectScopedResponseMetadata",
511
+ "ProjectScopedResponseResources",
512
+ "ProjectScopedFilter",
502
513
  "BaseFilter",
503
514
  "StrFilter",
504
515
  "BoolFilter",
@@ -562,6 +573,8 @@ __all__ = [
562
573
  "ComponentResponseBody",
563
574
  "ComponentResponseMetadata",
564
575
  "ComponentResponseResources",
576
+ "DefaultComponentRequest",
577
+ "DefaultStackRequest",
565
578
  "EventSourceFlavorResponse",
566
579
  "EventSourceFlavorResponseBody",
567
580
  "EventSourceFlavorResponseMetadata",
@@ -695,6 +708,7 @@ __all__ = [
695
708
  "TagResourceRequest",
696
709
  "TagResponse",
697
710
  "TagResponseBody",
711
+ "TagResponseMetadata",
698
712
  "TagRequest",
699
713
  "TagUpdate",
700
714
  "TriggerResponse",
@@ -723,12 +737,12 @@ __all__ = [
723
737
  "UserResponse",
724
738
  "UserResponseBody",
725
739
  "UserResponseMetadata",
726
- "WorkspaceRequest",
727
- "WorkspaceUpdate",
728
- "WorkspaceFilter",
729
- "WorkspaceResponse",
730
- "WorkspaceResponseBody",
731
- "WorkspaceResponseMetadata",
740
+ "ProjectRequest",
741
+ "ProjectUpdate",
742
+ "ProjectFilter",
743
+ "ProjectResponse",
744
+ "ProjectResponseBody",
745
+ "ProjectResponseMetadata",
732
746
  # V2 Misc
733
747
  "AuthenticationMethodModel",
734
748
  "DeployedStack",
@@ -745,6 +759,7 @@ __all__ = [
745
759
  "ServerModel",
746
760
  "ServerDatabaseType",
747
761
  "ServerDeploymentType",
762
+ "ServerStatistics",
748
763
  "StackDeploymentConfig",
749
764
  "StackDeploymentInfo",
750
765
  "OAuthDeviceAuthorizationRequest",
@@ -757,7 +772,9 @@ __all__ = [
757
772
  "ComponentInfo",
758
773
  "ServiceConnectorInfo",
759
774
  "ServiceConnectorResourcesInfo",
775
+ "TagResource",
760
776
  "ResourcesInfo",
761
777
  "RunMetadataEntry",
762
778
  "RunMetadataResource",
779
+ "ProjectStatistics",
763
780
  ]
@@ -65,11 +65,6 @@ class BaseUpdate(BaseZenModel):
65
65
  Used as a base class for all update models.
66
66
  """
67
67
 
68
- model_config = ConfigDict(
69
- # Ignore extras on all update models.
70
- extra="ignore",
71
- )
72
-
73
68
 
74
69
  # -------------------- Response Model --------------------
75
70
 
@@ -421,7 +421,7 @@ class BaseFilter(BaseModel):
421
421
  ```
422
422
  ResourceListModel(
423
423
  name="contains:default",
424
- workspace="default"
424
+ project="default"
425
425
  count_steps="gte:5"
426
426
  sort_by="created",
427
427
  page=2,
@@ -716,7 +716,7 @@ class BaseFilter(BaseModel):
716
716
  value: The filter value.
717
717
  table: The table to filter.
718
718
  additional_columns: Additional table columns that should also
719
- filtered for the given value as part of the or condition.
719
+ filter for the given value as part of the or condition.
720
720
 
721
721
  Returns:
722
722
  The query conditions.
@@ -27,8 +27,9 @@ from typing import (
27
27
  )
28
28
  from uuid import UUID
29
29
 
30
- from pydantic import Field
30
+ from pydantic import Field, model_validator
31
31
 
32
+ from zenml.logger import get_logger
32
33
  from zenml.models.v2.base.base import (
33
34
  BaseDatedResponseBody,
34
35
  BaseIdentifiedResponse,
@@ -41,12 +42,15 @@ from zenml.models.v2.base.filter import AnyQuery, BaseFilter
41
42
  if TYPE_CHECKING:
42
43
  from sqlalchemy.sql.elements import ColumnElement
43
44
 
45
+ from zenml.models.v2.core.project import ProjectResponse
44
46
  from zenml.models.v2.core.user import UserResponse
45
- from zenml.models.v2.core.workspace import WorkspaceResponse
46
47
  from zenml.zen_stores.schemas import BaseSchema
47
48
 
48
49
  AnySchema = TypeVar("AnySchema", bound=BaseSchema)
49
50
 
51
+ logger = get_logger(__name__)
52
+
53
+
50
54
  # ---------------------- Request Models ----------------------
51
55
 
52
56
 
@@ -56,7 +60,14 @@ class UserScopedRequest(BaseRequest):
56
60
  Used as a base class for all domain models that are "owned" by a user.
57
61
  """
58
62
 
59
- user: UUID = Field(title="The id of the user that created this resource.")
63
+ user: Optional[UUID] = Field(
64
+ default=None,
65
+ title="The id of the user that created this resource. Set "
66
+ "automatically by the server.",
67
+ # This field is set automatically by the server, so the client doesn't
68
+ # need to set it and it will not be serialized.
69
+ exclude=True,
70
+ )
60
71
 
61
72
  def get_analytics_metadata(self) -> Dict[str, Any]:
62
73
  """Fetches the analytics metadata for user scoped models.
@@ -69,24 +80,22 @@ class UserScopedRequest(BaseRequest):
69
80
  return metadata
70
81
 
71
82
 
72
- class WorkspaceScopedRequest(UserScopedRequest):
73
- """Base workspace-scoped request domain model.
83
+ class ProjectScopedRequest(UserScopedRequest):
84
+ """Base project-scoped request domain model.
74
85
 
75
- Used as a base class for all domain models that are workspace-scoped.
86
+ Used as a base class for all domain models that are project-scoped.
76
87
  """
77
88
 
78
- workspace: UUID = Field(
79
- title="The workspace to which this resource belongs."
80
- )
89
+ project: UUID = Field(title="The project to which this resource belongs.")
81
90
 
82
91
  def get_analytics_metadata(self) -> Dict[str, Any]:
83
- """Fetches the analytics metadata for workspace scoped models.
92
+ """Fetches the analytics metadata for project scoped models.
84
93
 
85
94
  Returns:
86
95
  The analytics metadata.
87
96
  """
88
97
  metadata = super().get_analytics_metadata()
89
- metadata["workspace_id"] = self.workspace
98
+ metadata["project_id"] = self.project
90
99
  return metadata
91
100
 
92
101
 
@@ -157,7 +166,6 @@ class UserScopedFilter(BaseFilter):
157
166
  ]
158
167
  CLI_EXCLUDE_FIELDS: ClassVar[List[str]] = [
159
168
  *BaseFilter.CLI_EXCLUDE_FIELDS,
160
- "user_id",
161
169
  "scope_user",
162
170
  ]
163
171
  CUSTOM_SORTING_OPTIONS: ClassVar[List[str]] = [
@@ -169,14 +177,10 @@ class UserScopedFilter(BaseFilter):
169
177
  default=None,
170
178
  description="The user to scope this query to.",
171
179
  )
172
- user_id: Optional[Union[UUID, str]] = Field(
173
- default=None,
174
- description="UUID of the user that created the entity.",
175
- union_mode="left_to_right",
176
- )
177
180
  user: Optional[Union[UUID, str]] = Field(
178
181
  default=None,
179
182
  description="Name/ID of the user that created the entity.",
183
+ union_mode="left_to_right",
180
184
  )
181
185
 
182
186
  def set_scope_user(self, user_id: UUID) -> None:
@@ -279,122 +283,82 @@ class UserScopedFilter(BaseFilter):
279
283
  return query
280
284
 
281
285
 
282
- # Workspace-scoped models
286
+ # Project-scoped models
283
287
 
284
288
 
285
- class WorkspaceScopedResponseBody(UserScopedResponseBody):
286
- """Base workspace-scoped body."""
289
+ class ProjectScopedResponseBody(UserScopedResponseBody):
290
+ """Base project-scoped body."""
287
291
 
288
292
 
289
- class WorkspaceScopedResponseMetadata(UserScopedResponseMetadata):
290
- """Base workspace-scoped metadata."""
293
+ class ProjectScopedResponseMetadata(UserScopedResponseMetadata):
294
+ """Base project-scoped metadata."""
291
295
 
292
- workspace: "WorkspaceResponse" = Field(
293
- title="The workspace of this resource."
294
- )
296
+ project: "ProjectResponse" = Field(title="The project of this resource.")
295
297
 
296
298
 
297
- class WorkspaceScopedResponseResources(UserScopedResponseResources):
298
- """Base workspace-scoped resources."""
299
+ class ProjectScopedResponseResources(UserScopedResponseResources):
300
+ """Base project-scoped resources."""
299
301
 
300
302
 
301
- WorkspaceBody = TypeVar("WorkspaceBody", bound=WorkspaceScopedResponseBody)
302
- WorkspaceMetadata = TypeVar(
303
- "WorkspaceMetadata", bound=WorkspaceScopedResponseMetadata
303
+ ProjectBody = TypeVar("ProjectBody", bound=ProjectScopedResponseBody)
304
+ ProjectMetadata = TypeVar(
305
+ "ProjectMetadata", bound=ProjectScopedResponseMetadata
304
306
  )
305
- WorkspaceResources = TypeVar(
306
- "WorkspaceResources", bound=WorkspaceScopedResponseResources
307
+ ProjectResources = TypeVar(
308
+ "ProjectResources", bound=ProjectScopedResponseResources
307
309
  )
308
310
 
309
311
 
310
- class WorkspaceScopedResponse(
311
- UserScopedResponse[WorkspaceBody, WorkspaceMetadata, WorkspaceResources],
312
- Generic[WorkspaceBody, WorkspaceMetadata, WorkspaceResources],
312
+ class ProjectScopedResponse(
313
+ UserScopedResponse[ProjectBody, ProjectMetadata, ProjectResources],
314
+ Generic[ProjectBody, ProjectMetadata, ProjectResources],
313
315
  ):
314
- """Base workspace-scoped domain model.
316
+ """Base project-scoped domain model.
315
317
 
316
- Used as a base class for all domain models that are workspace-scoped.
318
+ Used as a base class for all domain models that are project-scoped.
317
319
  """
318
320
 
321
+ # Analytics
322
+ def get_analytics_metadata(self) -> Dict[str, Any]:
323
+ """Fetches the analytics metadata for project scoped models.
324
+
325
+ Returns:
326
+ The analytics metadata.
327
+ """
328
+ metadata = super().get_analytics_metadata()
329
+ if self.project is not None:
330
+ metadata["project_id"] = self.project.id
331
+ return metadata
332
+
319
333
  # Body and metadata properties
320
334
  @property
321
- def workspace(self) -> "WorkspaceResponse":
322
- """The workspace property.
335
+ def project(self) -> "ProjectResponse":
336
+ """The project property.
323
337
 
324
338
  Returns:
325
339
  the value of the property.
326
340
  """
327
- return self.get_metadata().workspace
341
+ return self.get_metadata().project
342
+
343
+
344
+ # ---------------------- Filter Models ----------------------
328
345
 
329
346
 
330
- class WorkspaceScopedFilter(UserScopedFilter):
331
- """Model to enable advanced scoping with workspace."""
347
+ class ProjectScopedFilter(UserScopedFilter):
348
+ """Model to enable advanced scoping with project."""
332
349
 
333
350
  FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
334
351
  *UserScopedFilter.FILTER_EXCLUDE_FIELDS,
335
- "workspace",
336
- "scope_workspace",
352
+ "project",
337
353
  ]
338
- CLI_EXCLUDE_FIELDS: ClassVar[List[str]] = [
339
- *UserScopedFilter.CLI_EXCLUDE_FIELDS,
340
- "workspace_id",
341
- "workspace",
342
- "scope_workspace",
343
- ]
344
- CUSTOM_SORTING_OPTIONS: ClassVar[List[str]] = [
345
- *UserScopedFilter.CUSTOM_SORTING_OPTIONS,
346
- "workspace",
347
- ]
348
- scope_workspace: Optional[UUID] = Field(
354
+ project: Optional[Union[UUID, str]] = Field(
349
355
  default=None,
350
- description="The workspace to scope this query to.",
351
- )
352
- workspace_id: Optional[Union[UUID, str]] = Field(
353
- default=None,
354
- description="UUID of the workspace that this entity belongs to.",
356
+ description="Name/ID of the project which the search is scoped to. "
357
+ "This field must always be set and is always applied in addition to "
358
+ "the other filters, regardless of the value of the "
359
+ "logical_operator field.",
355
360
  union_mode="left_to_right",
356
361
  )
357
- workspace: Optional[Union[UUID, str]] = Field(
358
- default=None,
359
- description="Name/ID of the workspace that this entity belongs to.",
360
- )
361
-
362
- def set_scope_workspace(self, workspace_id: UUID) -> None:
363
- """Set the workspace to scope this response.
364
-
365
- Args:
366
- workspace_id: The workspace to scope this response to.
367
- """
368
- self.scope_workspace = workspace_id
369
-
370
- def get_custom_filters(
371
- self, table: Type["AnySchema"]
372
- ) -> List["ColumnElement[bool]"]:
373
- """Get custom filters.
374
-
375
- Args:
376
- table: The query table.
377
-
378
- Returns:
379
- A list of custom filters.
380
- """
381
- custom_filters = super().get_custom_filters(table)
382
-
383
- from sqlmodel import and_
384
-
385
- from zenml.zen_stores.schemas import WorkspaceSchema
386
-
387
- if self.workspace:
388
- workspace_filter = and_(
389
- getattr(table, "workspace_id") == WorkspaceSchema.id,
390
- self.generate_name_or_id_query_conditions(
391
- value=self.workspace,
392
- table=WorkspaceSchema,
393
- ),
394
- )
395
- custom_filters.append(workspace_filter)
396
-
397
- return custom_filters
398
362
 
399
363
  def apply_filter(
400
364
  self,
@@ -409,59 +373,35 @@ class WorkspaceScopedFilter(UserScopedFilter):
409
373
 
410
374
  Returns:
411
375
  The query with filter applied.
412
- """
413
- from sqlmodel import or_
414
376
 
415
- query = super().apply_filter(query=query, table=table)
416
-
417
- if self.scope_workspace:
418
- scope_filter = or_(
419
- getattr(table, "workspace_id") == self.scope_workspace,
420
- getattr(table, "workspace_id").is_(None),
421
- )
422
- query = query.where(scope_filter)
423
-
424
- return query
425
-
426
- def apply_sorting(
427
- self,
428
- query: AnyQuery,
429
- table: Type["AnySchema"],
430
- ) -> AnyQuery:
431
- """Apply sorting to the query.
432
-
433
- Args:
434
- query: The query to which to apply the sorting.
435
- table: The query table.
436
-
437
- Returns:
438
- The query with sorting applied.
377
+ Raises:
378
+ ValueError: If the project scope is missing from the filter.
439
379
  """
440
- from sqlmodel import asc, desc
441
-
442
- from zenml.enums import SorterOps
443
- from zenml.zen_stores.schemas import WorkspaceSchema
444
-
445
- sort_by, operand = self.sorting_params
446
-
447
- if sort_by == "workspace":
448
- column = WorkspaceSchema.name
380
+ query = super().apply_filter(query=query, table=table)
449
381
 
450
- query = query.join(
451
- WorkspaceSchema,
452
- getattr(table, "workspace_id") == WorkspaceSchema.id,
382
+ # The project scope must always be set and must be a UUID. If the
383
+ # client sets this to a string, the server will try to resolve it to a
384
+ # project ID.
385
+ #
386
+ # If not set by the client, the server will fall back to using the
387
+ # user's default project or even the server's default project, if
388
+ # they are configured. If this also fails to yield a project, this
389
+ # method will raise a ValueError.
390
+ #
391
+ # See: SqlZenStore._set_filter_project_id
392
+
393
+ if not self.project:
394
+ raise ValueError("Project scope missing from the filter.")
395
+
396
+ if not isinstance(self.project, UUID):
397
+ raise ValueError(
398
+ f"Project scope must be a UUID, got {type(self.project)}."
453
399
  )
454
400
 
455
- query = query.add_columns(WorkspaceSchema.name)
401
+ scope_filter = getattr(table, "project_id") == self.project
402
+ query = query.where(scope_filter)
456
403
 
457
- if operand == SorterOps.ASCENDING:
458
- query = query.order_by(asc(column))
459
- else:
460
- query = query.order_by(desc(column))
461
-
462
- return query
463
-
464
- return super().apply_sorting(query=query, table=table)
404
+ return query
465
405
 
466
406
 
467
407
  class TaggableFilter(BaseFilter):
@@ -470,16 +410,44 @@ class TaggableFilter(BaseFilter):
470
410
  tag: Optional[str] = Field(
471
411
  description="Tag to apply to the filter query.", default=None
472
412
  )
413
+ tags: Optional[List[str]] = Field(
414
+ description="Tags to apply to the filter query.", default=None
415
+ )
473
416
 
417
+ CLI_EXCLUDE_FIELDS = [
418
+ *BaseFilter.CLI_EXCLUDE_FIELDS,
419
+ ]
474
420
  FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
475
421
  *BaseFilter.FILTER_EXCLUDE_FIELDS,
476
422
  "tag",
423
+ "tags",
477
424
  ]
478
425
  CUSTOM_SORTING_OPTIONS: ClassVar[List[str]] = [
479
426
  *BaseFilter.CUSTOM_SORTING_OPTIONS,
480
427
  "tags",
481
428
  ]
482
429
 
430
+ @model_validator(mode="after")
431
+ def add_tag_to_tags(self) -> "TaggableFilter":
432
+ """Deprecated the tag attribute in favor of the tags attribute.
433
+
434
+ Returns:
435
+ self
436
+ """
437
+ if self.tag is not None:
438
+ logger.warning(
439
+ "The `tag` attribute is deprecated in favor of the `tags` attribute. "
440
+ "Please update your code to use the `tags` attribute instead."
441
+ )
442
+ if self.tags is not None:
443
+ self.tags.append(self.tag)
444
+ else:
445
+ self.tags = [self.tag]
446
+
447
+ self.tag = None
448
+
449
+ return self
450
+
483
451
  def apply_filter(
484
452
  self,
485
453
  query: AnyQuery,
@@ -497,7 +465,8 @@ class TaggableFilter(BaseFilter):
497
465
  from zenml.zen_stores.schemas import TagResourceSchema, TagSchema
498
466
 
499
467
  query = super().apply_filter(query=query, table=table)
500
- if self.tag:
468
+
469
+ if self.tags:
501
470
  query = query.join(
502
471
  TagResourceSchema,
503
472
  TagResourceSchema.resource_id == getattr(table, "id"),
@@ -516,15 +485,25 @@ class TaggableFilter(BaseFilter):
516
485
  Returns:
517
486
  A list of custom filters.
518
487
  """
519
- from zenml.zen_stores.schemas import TagSchema
520
-
521
488
  custom_filters = super().get_custom_filters(table)
522
- if self.tag:
523
- custom_filters.append(
524
- self.generate_custom_query_conditions_for_column(
525
- value=self.tag, table=TagSchema, column="name"
489
+
490
+ if self.tags:
491
+ from sqlmodel import exists, select
492
+
493
+ from zenml.zen_stores.schemas import TagResourceSchema, TagSchema
494
+
495
+ for tag in self.tags:
496
+ condition = self.generate_custom_query_conditions_for_column(
497
+ value=tag, table=TagSchema, column="name"
526
498
  )
527
- )
499
+ exists_subquery = exists(
500
+ select(TagResourceSchema)
501
+ .join(TagSchema, TagSchema.id == TagResourceSchema.tag_id) # type: ignore[arg-type]
502
+ .where(
503
+ TagResourceSchema.resource_id == table.id, condition
504
+ )
505
+ )
506
+ custom_filters.append(exists_subquery)
528
507
 
529
508
  return custom_filters
530
509