zenml-nightly 0.71.0.dev20241212__py3-none-any.whl → 0.71.0.dev20241214__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 (47) hide show
  1. zenml/VERSION +1 -1
  2. zenml/artifacts/artifact_config.py +8 -5
  3. zenml/artifacts/utils.py +3 -1
  4. zenml/client.py +54 -2
  5. zenml/integrations/kubernetes/step_operators/kubernetes_step_operator.py +0 -1
  6. zenml/model/model.py +12 -16
  7. zenml/model/utils.py +3 -1
  8. zenml/models/v2/base/filter.py +26 -30
  9. zenml/models/v2/base/scoped.py +258 -5
  10. zenml/models/v2/core/artifact_version.py +15 -26
  11. zenml/models/v2/core/code_repository.py +1 -12
  12. zenml/models/v2/core/component.py +5 -46
  13. zenml/models/v2/core/flavor.py +1 -11
  14. zenml/models/v2/core/model.py +1 -57
  15. zenml/models/v2/core/model_version.py +5 -33
  16. zenml/models/v2/core/model_version_artifact.py +11 -3
  17. zenml/models/v2/core/model_version_pipeline_run.py +14 -3
  18. zenml/models/v2/core/pipeline.py +47 -55
  19. zenml/models/v2/core/pipeline_build.py +67 -12
  20. zenml/models/v2/core/pipeline_deployment.py +0 -10
  21. zenml/models/v2/core/pipeline_run.py +91 -29
  22. zenml/models/v2/core/run_template.py +21 -29
  23. zenml/models/v2/core/schedule.py +0 -10
  24. zenml/models/v2/core/secret.py +0 -14
  25. zenml/models/v2/core/service.py +9 -16
  26. zenml/models/v2/core/service_connector.py +0 -11
  27. zenml/models/v2/core/stack.py +21 -30
  28. zenml/models/v2/core/step_run.py +18 -14
  29. zenml/models/v2/core/trigger.py +19 -3
  30. zenml/orchestrators/step_launcher.py +9 -13
  31. zenml/orchestrators/step_run_utils.py +8 -204
  32. zenml/pipelines/build_utils.py +12 -0
  33. zenml/zen_server/rbac/rbac_sql_zen_store.py +173 -0
  34. zenml/zen_server/utils.py +4 -3
  35. zenml/zen_stores/base_zen_store.py +10 -2
  36. zenml/zen_stores/migrations/versions/26351d482b9e_add_step_run_unique_constraint.py +37 -0
  37. zenml/zen_stores/migrations/versions/a1237ba94fd8_add_model_version_producer_run_unique_.py +68 -0
  38. zenml/zen_stores/schemas/model_schemas.py +42 -6
  39. zenml/zen_stores/schemas/pipeline_deployment_schemas.py +7 -7
  40. zenml/zen_stores/schemas/pipeline_schemas.py +5 -0
  41. zenml/zen_stores/schemas/step_run_schemas.py +8 -1
  42. zenml/zen_stores/sql_zen_store.py +327 -99
  43. {zenml_nightly-0.71.0.dev20241212.dist-info → zenml_nightly-0.71.0.dev20241214.dist-info}/METADATA +1 -1
  44. {zenml_nightly-0.71.0.dev20241212.dist-info → zenml_nightly-0.71.0.dev20241214.dist-info}/RECORD +47 -44
  45. {zenml_nightly-0.71.0.dev20241212.dist-info → zenml_nightly-0.71.0.dev20241214.dist-info}/LICENSE +0 -0
  46. {zenml_nightly-0.71.0.dev20241212.dist-info → zenml_nightly-0.71.0.dev20241214.dist-info}/WHEEL +0 -0
  47. {zenml_nightly-0.71.0.dev20241212.dist-info → zenml_nightly-0.71.0.dev20241214.dist-info}/entry_points.txt +0 -0
@@ -15,10 +15,16 @@
15
15
 
16
16
  from datetime import datetime
17
17
  from typing import TYPE_CHECKING, Any, Dict, List, Optional, cast
18
- from uuid import UUID
18
+ from uuid import UUID, uuid4
19
19
 
20
20
  from pydantic import ConfigDict
21
- from sqlalchemy import BOOLEAN, INTEGER, TEXT, Column, UniqueConstraint
21
+ from sqlalchemy import (
22
+ BOOLEAN,
23
+ INTEGER,
24
+ TEXT,
25
+ Column,
26
+ UniqueConstraint,
27
+ )
22
28
  from sqlmodel import Field, Relationship
23
29
 
24
30
  from zenml.enums import (
@@ -228,11 +234,13 @@ class ModelVersionSchema(NamedSchema, RunMetadataInterface, table=True):
228
234
 
229
235
  __tablename__ = MODEL_VERSION_TABLENAME
230
236
  __table_args__ = (
231
- # We need two unique constraints here:
237
+ # We need three unique constraints here:
232
238
  # - The first to ensure that each model version for a
233
239
  # model has a unique version number
234
240
  # - The second one to ensure that explicit names given by
235
241
  # users are unique
242
+ # - The third one to ensure that a pipeline run only produces a single
243
+ # auto-incremented version per model
236
244
  UniqueConstraint(
237
245
  "number",
238
246
  "model_id",
@@ -243,6 +251,11 @@ class ModelVersionSchema(NamedSchema, RunMetadataInterface, table=True):
243
251
  "model_id",
244
252
  name="unique_version_for_model_id",
245
253
  ),
254
+ UniqueConstraint(
255
+ "model_id",
256
+ "producer_run_id_if_numeric",
257
+ name="unique_numeric_version_for_pipeline_run",
258
+ ),
246
259
  )
247
260
 
248
261
  workspace_id: UUID = build_foreign_key_field(
@@ -312,12 +325,23 @@ class ModelVersionSchema(NamedSchema, RunMetadataInterface, table=True):
312
325
  ),
313
326
  )
314
327
  pipeline_runs: List["PipelineRunSchema"] = Relationship(
315
- back_populates="model_version"
328
+ back_populates="model_version",
316
329
  )
317
330
  step_runs: List["StepRunSchema"] = Relationship(
318
331
  back_populates="model_version"
319
332
  )
320
333
 
334
+ # We want to make sure each pipeline run only creates a single numeric
335
+ # version for each model. To solve this, we need to add a unique constraint.
336
+ # If a value of a unique constraint is NULL it is ignored and the
337
+ # remaining values in the unique constraint have to be unique. In
338
+ # our case however, we only want the unique constraint applied in
339
+ # case there is a producer run and only for numeric versions. To solve this,
340
+ # we fall back to the model version ID (which is the primary key and
341
+ # therefore unique) in case there is no producer run or the version is not
342
+ # numeric.
343
+ producer_run_id_if_numeric: UUID
344
+
321
345
  # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
322
346
  # fields defined under base models. If not handled, this raises a warning.
323
347
  # It is possible to suppress this warning message with the following
@@ -328,24 +352,36 @@ class ModelVersionSchema(NamedSchema, RunMetadataInterface, table=True):
328
352
 
329
353
  @classmethod
330
354
  def from_request(
331
- cls, model_version_request: ModelVersionRequest
355
+ cls,
356
+ model_version_request: ModelVersionRequest,
357
+ model_version_number: int,
358
+ producer_run_id: Optional[UUID] = None,
332
359
  ) -> "ModelVersionSchema":
333
360
  """Convert an `ModelVersionRequest` to an `ModelVersionSchema`.
334
361
 
335
362
  Args:
336
363
  model_version_request: The request model version to convert.
364
+ model_version_number: The model version number.
365
+ producer_run_id: The ID of the producer run.
337
366
 
338
367
  Returns:
339
368
  The converted schema.
340
369
  """
370
+ id_ = uuid4()
371
+ is_numeric = str(model_version_number) == model_version_request.name
372
+
341
373
  return cls(
374
+ id=id_,
342
375
  workspace_id=model_version_request.workspace,
343
376
  user_id=model_version_request.user,
344
377
  model_id=model_version_request.model,
345
378
  name=model_version_request.name,
346
- number=model_version_request.number,
379
+ number=model_version_number,
347
380
  description=model_version_request.description,
348
381
  stage=model_version_request.stage,
382
+ producer_run_id_if_numeric=producer_run_id
383
+ if (producer_run_id and is_numeric)
384
+ else id_,
349
385
  )
350
386
 
351
387
  def to_model(
@@ -228,13 +228,6 @@ class PipelineDeploymentSchema(BaseSchema, table=True):
228
228
  Returns:
229
229
  The created `PipelineDeploymentResponse`.
230
230
  """
231
- pipeline_configuration = PipelineConfiguration.model_validate_json(
232
- self.pipeline_configuration
233
- )
234
- step_configurations = json.loads(self.step_configurations)
235
- for s, c in step_configurations.items():
236
- step_configurations[s] = Step.model_validate(c)
237
-
238
231
  body = PipelineDeploymentResponseBody(
239
232
  user=self.user.to_model() if self.user else None,
240
233
  created=self.created,
@@ -242,6 +235,13 @@ class PipelineDeploymentSchema(BaseSchema, table=True):
242
235
  )
243
236
  metadata = None
244
237
  if include_metadata:
238
+ pipeline_configuration = PipelineConfiguration.model_validate_json(
239
+ self.pipeline_configuration
240
+ )
241
+ step_configurations = json.loads(self.step_configurations)
242
+ for s, c in step_configurations.items():
243
+ step_configurations[s] = Step.model_validate(c)
244
+
245
245
  metadata = PipelineDeploymentResponseMetadata(
246
246
  workspace=self.workspace.to_model(),
247
247
  run_name_template=self.run_name_template,
@@ -156,7 +156,12 @@ class PipelineSchema(NamedSchema, table=True):
156
156
 
157
157
  resources = None
158
158
  if include_resources:
159
+ latest_run_user = self.runs[-1].user if self.runs else None
160
+
159
161
  resources = PipelineResponseResources(
162
+ latest_run_user=latest_run_user.to_model()
163
+ if latest_run_user
164
+ else None,
160
165
  tags=[t.tag.to_model() for t in self.tags],
161
166
  )
162
167
 
@@ -19,7 +19,7 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional
19
19
  from uuid import UUID
20
20
 
21
21
  from pydantic import ConfigDict
22
- from sqlalchemy import TEXT, Column, String
22
+ from sqlalchemy import TEXT, Column, String, UniqueConstraint
23
23
  from sqlalchemy.dialects.mysql import MEDIUMTEXT
24
24
  from sqlmodel import Field, Relationship, SQLModel
25
25
 
@@ -67,6 +67,13 @@ class StepRunSchema(NamedSchema, RunMetadataInterface, table=True):
67
67
  """SQL Model for steps of pipeline runs."""
68
68
 
69
69
  __tablename__ = "step_run"
70
+ __table_args__ = (
71
+ UniqueConstraint(
72
+ "name",
73
+ "pipeline_run_id",
74
+ name="unique_step_name_for_pipeline_run",
75
+ ),
76
+ )
70
77
 
71
78
  # Fields
72
79
  start_time: Optional[datetime] = Field(nullable=True)