zenml-nightly 0.58.2.dev20240618__py3-none-any.whl → 0.58.2.dev20240619__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 (300) hide show
  1. zenml/VERSION +1 -1
  2. zenml/_hub/client.py +8 -5
  3. zenml/actions/base_action.py +8 -10
  4. zenml/artifact_stores/base_artifact_store.py +20 -15
  5. zenml/artifact_stores/local_artifact_store.py +3 -2
  6. zenml/artifacts/artifact_config.py +34 -19
  7. zenml/artifacts/external_artifact.py +18 -8
  8. zenml/artifacts/external_artifact_config.py +14 -6
  9. zenml/artifacts/unmaterialized_artifact.py +2 -11
  10. zenml/cli/__init__.py +6 -0
  11. zenml/cli/artifact.py +20 -2
  12. zenml/cli/served_model.py +0 -1
  13. zenml/cli/server.py +3 -3
  14. zenml/cli/utils.py +36 -40
  15. zenml/cli/web_login.py +2 -2
  16. zenml/client.py +198 -24
  17. zenml/client_lazy_loader.py +20 -14
  18. zenml/config/base_settings.py +5 -6
  19. zenml/config/build_configuration.py +1 -1
  20. zenml/config/compiler.py +3 -3
  21. zenml/config/docker_settings.py +27 -28
  22. zenml/config/global_config.py +33 -37
  23. zenml/config/pipeline_configurations.py +8 -11
  24. zenml/config/pipeline_run_configuration.py +6 -2
  25. zenml/config/pipeline_spec.py +3 -4
  26. zenml/config/resource_settings.py +8 -9
  27. zenml/config/schedule.py +16 -20
  28. zenml/config/secret_reference_mixin.py +6 -3
  29. zenml/config/secrets_store_config.py +16 -23
  30. zenml/config/server_config.py +50 -46
  31. zenml/config/settings_resolver.py +1 -1
  32. zenml/config/source.py +45 -35
  33. zenml/config/step_configurations.py +53 -31
  34. zenml/config/store_config.py +20 -19
  35. zenml/config/strict_base_model.py +2 -6
  36. zenml/constants.py +26 -2
  37. zenml/container_registries/base_container_registry.py +3 -2
  38. zenml/container_registries/default_container_registry.py +3 -3
  39. zenml/event_hub/base_event_hub.py +1 -1
  40. zenml/event_sources/base_event_source.py +11 -16
  41. zenml/exceptions.py +4 -0
  42. zenml/integrations/airflow/__init__.py +2 -10
  43. zenml/integrations/airflow/flavors/airflow_orchestrator_flavor.py +6 -7
  44. zenml/integrations/airflow/orchestrators/airflow_orchestrator.py +13 -249
  45. zenml/integrations/airflow/orchestrators/dag_generator.py +5 -3
  46. zenml/integrations/argilla/flavors/argilla_annotator_flavor.py +5 -4
  47. zenml/integrations/aws/__init__.py +1 -1
  48. zenml/integrations/aws/flavors/aws_container_registry_flavor.py +3 -2
  49. zenml/integrations/aws/flavors/sagemaker_orchestrator_flavor.py +11 -5
  50. zenml/integrations/aws/flavors/sagemaker_step_operator_flavor.py +6 -2
  51. zenml/integrations/aws/service_connectors/aws_service_connector.py +5 -4
  52. zenml/integrations/azure/flavors/azureml_step_operator_flavor.py +4 -4
  53. zenml/integrations/azure/service_connectors/azure_service_connector.py +4 -3
  54. zenml/integrations/azure/step_operators/azureml_step_operator.py +1 -1
  55. zenml/integrations/bentoml/steps/bentoml_deployer.py +1 -1
  56. zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +8 -12
  57. zenml/integrations/comet/flavors/comet_experiment_tracker_flavor.py +1 -1
  58. zenml/integrations/evidently/__init__.py +3 -4
  59. zenml/integrations/evidently/column_mapping.py +11 -3
  60. zenml/integrations/evidently/data_validators/evidently_data_validator.py +21 -3
  61. zenml/integrations/evidently/metrics.py +5 -6
  62. zenml/integrations/evidently/tests.py +5 -6
  63. zenml/integrations/facets/models.py +2 -6
  64. zenml/integrations/feast/__init__.py +3 -1
  65. zenml/integrations/feast/feature_stores/feast_feature_store.py +0 -23
  66. zenml/integrations/gcp/__init__.py +1 -1
  67. zenml/integrations/gcp/flavors/vertex_orchestrator_flavor.py +1 -1
  68. zenml/integrations/gcp/flavors/vertex_step_operator_flavor.py +1 -1
  69. zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +234 -103
  70. zenml/integrations/gcp/service_connectors/gcp_service_connector.py +57 -42
  71. zenml/integrations/github/code_repositories/github_code_repository.py +1 -1
  72. zenml/integrations/github/plugins/event_sources/github_webhook_event_source.py +9 -13
  73. zenml/integrations/great_expectations/__init__.py +1 -1
  74. zenml/integrations/great_expectations/data_validators/ge_data_validator.py +44 -44
  75. zenml/integrations/great_expectations/flavors/great_expectations_data_validator_flavor.py +35 -2
  76. zenml/integrations/great_expectations/ge_store_backend.py +24 -11
  77. zenml/integrations/great_expectations/materializers/ge_materializer.py +3 -3
  78. zenml/integrations/great_expectations/utils.py +5 -5
  79. zenml/integrations/huggingface/__init__.py +3 -0
  80. zenml/integrations/huggingface/flavors/huggingface_model_deployer_flavor.py +1 -1
  81. zenml/integrations/huggingface/steps/__init__.py +3 -0
  82. zenml/integrations/huggingface/steps/accelerate_runner.py +149 -0
  83. zenml/integrations/huggingface/steps/huggingface_deployer.py +2 -2
  84. zenml/integrations/hyperai/flavors/hyperai_orchestrator_flavor.py +1 -1
  85. zenml/integrations/hyperai/service_connectors/hyperai_service_connector.py +4 -3
  86. zenml/integrations/kubeflow/__init__.py +1 -1
  87. zenml/integrations/kubeflow/flavors/kubeflow_orchestrator_flavor.py +48 -81
  88. zenml/integrations/kubeflow/orchestrators/kubeflow_orchestrator.py +295 -245
  89. zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py +1 -1
  90. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py +11 -2
  91. zenml/integrations/kubernetes/pod_settings.py +17 -31
  92. zenml/integrations/kubernetes/service_connectors/kubernetes_service_connector.py +8 -7
  93. zenml/integrations/label_studio/__init__.py +1 -3
  94. zenml/integrations/label_studio/annotators/label_studio_annotator.py +3 -4
  95. zenml/integrations/label_studio/flavors/label_studio_annotator_flavor.py +2 -2
  96. zenml/integrations/langchain/materializers/document_materializer.py +44 -8
  97. zenml/integrations/mlflow/__init__.py +9 -3
  98. zenml/integrations/mlflow/experiment_trackers/mlflow_experiment_tracker.py +1 -1
  99. zenml/integrations/mlflow/flavors/mlflow_experiment_tracker_flavor.py +29 -37
  100. zenml/integrations/mlflow/model_registries/mlflow_model_registry.py +4 -4
  101. zenml/integrations/mlflow/steps/mlflow_deployer.py +1 -1
  102. zenml/integrations/neptune/flavors/neptune_experiment_tracker_flavor.py +1 -1
  103. zenml/integrations/pigeon/flavors/pigeon_annotator_flavor.py +1 -1
  104. zenml/integrations/s3/flavors/s3_artifact_store_flavor.py +9 -8
  105. zenml/integrations/seldon/seldon_client.py +52 -67
  106. zenml/integrations/seldon/services/seldon_deployment.py +3 -3
  107. zenml/integrations/seldon/steps/seldon_deployer.py +4 -4
  108. zenml/integrations/skypilot/flavors/skypilot_orchestrator_base_vm_config.py +15 -5
  109. zenml/integrations/skypilot_aws/__init__.py +1 -1
  110. zenml/integrations/skypilot_aws/flavors/skypilot_orchestrator_aws_vm_flavor.py +1 -1
  111. zenml/integrations/skypilot_azure/__init__.py +1 -1
  112. zenml/integrations/skypilot_azure/flavors/skypilot_orchestrator_azure_vm_flavor.py +1 -1
  113. zenml/integrations/skypilot_gcp/__init__.py +2 -1
  114. zenml/integrations/skypilot_gcp/flavors/skypilot_orchestrator_gcp_vm_flavor.py +1 -1
  115. zenml/integrations/skypilot_lambda/flavors/skypilot_orchestrator_lambda_vm_flavor.py +2 -2
  116. zenml/integrations/spark/flavors/spark_step_operator_flavor.py +1 -1
  117. zenml/integrations/tekton/__init__.py +1 -1
  118. zenml/integrations/tekton/flavors/tekton_orchestrator_flavor.py +66 -23
  119. zenml/integrations/tekton/orchestrators/tekton_orchestrator.py +547 -233
  120. zenml/integrations/tensorboard/__init__.py +1 -12
  121. zenml/integrations/tensorboard/services/tensorboard_service.py +3 -5
  122. zenml/integrations/tensorboard/visualizers/tensorboard_visualizer.py +6 -6
  123. zenml/integrations/tensorflow/__init__.py +2 -10
  124. zenml/integrations/tensorflow/materializers/keras_materializer.py +17 -9
  125. zenml/integrations/wandb/flavors/wandb_experiment_tracker_flavor.py +9 -14
  126. zenml/integrations/whylogs/flavors/whylogs_data_validator_flavor.py +1 -1
  127. zenml/lineage_graph/lineage_graph.py +1 -1
  128. zenml/materializers/built_in_materializer.py +3 -3
  129. zenml/materializers/pydantic_materializer.py +2 -2
  130. zenml/metadata/lazy_load.py +4 -4
  131. zenml/metadata/metadata_types.py +64 -4
  132. zenml/model/model.py +79 -54
  133. zenml/model_deployers/base_model_deployer.py +14 -12
  134. zenml/model_registries/base_model_registry.py +17 -15
  135. zenml/models/__init__.py +79 -206
  136. zenml/models/v2/base/base.py +54 -41
  137. zenml/models/v2/base/base_plugin_flavor.py +2 -6
  138. zenml/models/v2/base/filter.py +91 -76
  139. zenml/models/v2/base/page.py +2 -12
  140. zenml/models/v2/base/scoped.py +4 -7
  141. zenml/models/v2/core/api_key.py +22 -8
  142. zenml/models/v2/core/artifact.py +2 -2
  143. zenml/models/v2/core/artifact_version.py +74 -40
  144. zenml/models/v2/core/code_repository.py +37 -10
  145. zenml/models/v2/core/component.py +65 -16
  146. zenml/models/v2/core/device.py +14 -4
  147. zenml/models/v2/core/event_source.py +1 -2
  148. zenml/models/v2/core/flavor.py +74 -8
  149. zenml/models/v2/core/logs.py +68 -8
  150. zenml/models/v2/core/model.py +8 -4
  151. zenml/models/v2/core/model_version.py +25 -6
  152. zenml/models/v2/core/model_version_artifact.py +51 -21
  153. zenml/models/v2/core/model_version_pipeline_run.py +45 -13
  154. zenml/models/v2/core/pipeline.py +37 -72
  155. zenml/models/v2/core/pipeline_build.py +29 -17
  156. zenml/models/v2/core/pipeline_deployment.py +18 -6
  157. zenml/models/v2/core/pipeline_namespace.py +113 -0
  158. zenml/models/v2/core/pipeline_run.py +50 -22
  159. zenml/models/v2/core/run_metadata.py +59 -36
  160. zenml/models/v2/core/schedule.py +37 -24
  161. zenml/models/v2/core/secret.py +31 -12
  162. zenml/models/v2/core/service.py +64 -36
  163. zenml/models/v2/core/service_account.py +24 -11
  164. zenml/models/v2/core/service_connector.py +219 -44
  165. zenml/models/v2/core/stack.py +45 -17
  166. zenml/models/v2/core/step_run.py +28 -8
  167. zenml/models/v2/core/tag.py +8 -4
  168. zenml/models/v2/core/trigger.py +2 -2
  169. zenml/models/v2/core/trigger_execution.py +1 -0
  170. zenml/models/v2/core/user.py +18 -21
  171. zenml/models/v2/core/workspace.py +13 -3
  172. zenml/models/v2/misc/build_item.py +3 -3
  173. zenml/models/v2/misc/external_user.py +2 -6
  174. zenml/models/v2/misc/hub_plugin_models.py +9 -9
  175. zenml/models/v2/misc/loaded_visualization.py +2 -2
  176. zenml/models/v2/misc/service_connector_type.py +8 -17
  177. zenml/models/v2/misc/user_auth.py +7 -2
  178. zenml/new/pipelines/build_utils.py +3 -3
  179. zenml/new/pipelines/pipeline.py +17 -13
  180. zenml/new/pipelines/run_utils.py +103 -1
  181. zenml/orchestrators/base_orchestrator.py +10 -7
  182. zenml/orchestrators/local_docker/local_docker_orchestrator.py +1 -1
  183. zenml/orchestrators/step_runner.py +3 -6
  184. zenml/orchestrators/utils.py +1 -1
  185. zenml/plugins/base_plugin_flavor.py +6 -10
  186. zenml/plugins/plugin_flavor_registry.py +3 -7
  187. zenml/secret/base_secret.py +7 -8
  188. zenml/service_connectors/docker_service_connector.py +4 -3
  189. zenml/service_connectors/service_connector.py +5 -12
  190. zenml/service_connectors/service_connector_registry.py +2 -4
  191. zenml/services/container/container_service.py +1 -1
  192. zenml/services/container/container_service_endpoint.py +1 -1
  193. zenml/services/local/local_service.py +1 -1
  194. zenml/services/local/local_service_endpoint.py +1 -1
  195. zenml/services/service.py +16 -10
  196. zenml/services/service_type.py +4 -5
  197. zenml/services/terraform/terraform_service.py +1 -1
  198. zenml/stack/flavor.py +1 -5
  199. zenml/stack/flavor_registry.py +4 -4
  200. zenml/stack/stack.py +4 -1
  201. zenml/stack/stack_component.py +55 -31
  202. zenml/steps/base_step.py +34 -28
  203. zenml/steps/entrypoint_function_utils.py +3 -5
  204. zenml/steps/utils.py +12 -14
  205. zenml/utils/cuda_utils.py +50 -0
  206. zenml/utils/deprecation_utils.py +18 -20
  207. zenml/utils/dict_utils.py +1 -1
  208. zenml/utils/filesync_model.py +65 -28
  209. zenml/utils/function_utils.py +260 -0
  210. zenml/utils/json_utils.py +131 -0
  211. zenml/utils/mlstacks_utils.py +2 -2
  212. zenml/utils/pydantic_utils.py +270 -62
  213. zenml/utils/secret_utils.py +65 -12
  214. zenml/utils/source_utils.py +2 -2
  215. zenml/utils/typed_model.py +5 -3
  216. zenml/utils/typing_utils.py +243 -0
  217. zenml/utils/yaml_utils.py +1 -1
  218. zenml/zen_server/auth.py +2 -2
  219. zenml/zen_server/cloud_utils.py +6 -6
  220. zenml/zen_server/deploy/base_provider.py +1 -1
  221. zenml/zen_server/deploy/deployment.py +6 -8
  222. zenml/zen_server/deploy/docker/docker_zen_server.py +3 -4
  223. zenml/zen_server/deploy/local/local_provider.py +0 -1
  224. zenml/zen_server/deploy/local/local_zen_server.py +6 -6
  225. zenml/zen_server/deploy/terraform/terraform_zen_server.py +4 -6
  226. zenml/zen_server/exceptions.py +4 -1
  227. zenml/zen_server/feature_gate/zenml_cloud_feature_gate.py +1 -1
  228. zenml/zen_server/pipeline_deployment/utils.py +48 -68
  229. zenml/zen_server/rbac/models.py +2 -5
  230. zenml/zen_server/rbac/utils.py +11 -14
  231. zenml/zen_server/routers/auth_endpoints.py +2 -2
  232. zenml/zen_server/routers/pipeline_builds_endpoints.py +1 -1
  233. zenml/zen_server/routers/runs_endpoints.py +1 -1
  234. zenml/zen_server/routers/secrets_endpoints.py +3 -2
  235. zenml/zen_server/routers/server_endpoints.py +1 -1
  236. zenml/zen_server/routers/steps_endpoints.py +1 -1
  237. zenml/zen_server/routers/workspaces_endpoints.py +1 -1
  238. zenml/zen_stores/base_zen_store.py +46 -9
  239. zenml/zen_stores/migrations/utils.py +42 -46
  240. zenml/zen_stores/migrations/versions/0701da9951a0_added_service_table.py +1 -1
  241. zenml/zen_stores/migrations/versions/1041bc644e0d_remove_secrets_manager.py +5 -3
  242. zenml/zen_stores/migrations/versions/10a907dad202_delete_mlmd_tables.py +1 -1
  243. zenml/zen_stores/migrations/versions/26b776ad583e_redesign_artifacts.py +8 -10
  244. zenml/zen_stores/migrations/versions/37835ce041d2_optimizing_database.py +3 -3
  245. zenml/zen_stores/migrations/versions/46506f72f0ed_add_server_settings.py +10 -12
  246. zenml/zen_stores/migrations/versions/5994f9ad0489_introduce_role_permissions.py +3 -2
  247. zenml/zen_stores/migrations/versions/6917bce75069_add_pipeline_run_unique_constraint.py +4 -4
  248. zenml/zen_stores/migrations/versions/728c6369cfaa_add_name_column_to_input_artifact_pk.py +3 -2
  249. zenml/zen_stores/migrations/versions/743ec82b1b3c_update_size_of_build_images.py +2 -2
  250. zenml/zen_stores/migrations/versions/7500f434b71c_remove_shared_columns.py +3 -2
  251. zenml/zen_stores/migrations/versions/7834208cc3f6_artifact_project_scoping.py +8 -7
  252. zenml/zen_stores/migrations/versions/7b651bf6822e_track_secrets_in_db.py +6 -4
  253. zenml/zen_stores/migrations/versions/7e4a481d17f7_add_identity_table.py +2 -2
  254. zenml/zen_stores/migrations/versions/7f603e583dd7_fixed_migration.py +1 -1
  255. zenml/zen_stores/migrations/versions/a39c4184c8ce_remove_secrets_manager_flavors.py +2 -2
  256. zenml/zen_stores/migrations/versions/a91762e6be36_artifact_version_table.py +4 -4
  257. zenml/zen_stores/migrations/versions/alembic_start.py +1 -1
  258. zenml/zen_stores/migrations/versions/fbd7f18ced1e_increase_step_run_field_lengths.py +4 -4
  259. zenml/zen_stores/rest_zen_store.py +109 -49
  260. zenml/zen_stores/schemas/api_key_schemas.py +1 -1
  261. zenml/zen_stores/schemas/artifact_schemas.py +8 -8
  262. zenml/zen_stores/schemas/artifact_visualization_schemas.py +3 -3
  263. zenml/zen_stores/schemas/code_repository_schemas.py +1 -1
  264. zenml/zen_stores/schemas/component_schemas.py +8 -3
  265. zenml/zen_stores/schemas/device_schemas.py +8 -6
  266. zenml/zen_stores/schemas/event_source_schemas.py +3 -4
  267. zenml/zen_stores/schemas/flavor_schemas.py +5 -3
  268. zenml/zen_stores/schemas/model_schemas.py +26 -1
  269. zenml/zen_stores/schemas/pipeline_build_schemas.py +1 -1
  270. zenml/zen_stores/schemas/pipeline_deployment_schemas.py +4 -4
  271. zenml/zen_stores/schemas/pipeline_run_schemas.py +6 -6
  272. zenml/zen_stores/schemas/pipeline_schemas.py +5 -2
  273. zenml/zen_stores/schemas/run_metadata_schemas.py +2 -2
  274. zenml/zen_stores/schemas/secret_schemas.py +8 -5
  275. zenml/zen_stores/schemas/server_settings_schemas.py +3 -1
  276. zenml/zen_stores/schemas/service_connector_schemas.py +1 -1
  277. zenml/zen_stores/schemas/service_schemas.py +11 -2
  278. zenml/zen_stores/schemas/stack_schemas.py +1 -1
  279. zenml/zen_stores/schemas/step_run_schemas.py +11 -11
  280. zenml/zen_stores/schemas/tag_schemas.py +6 -2
  281. zenml/zen_stores/schemas/trigger_schemas.py +2 -2
  282. zenml/zen_stores/schemas/user_schemas.py +2 -2
  283. zenml/zen_stores/schemas/workspace_schemas.py +3 -1
  284. zenml/zen_stores/secrets_stores/aws_secrets_store.py +19 -20
  285. zenml/zen_stores/secrets_stores/azure_secrets_store.py +17 -20
  286. zenml/zen_stores/secrets_stores/base_secrets_store.py +79 -12
  287. zenml/zen_stores/secrets_stores/gcp_secrets_store.py +17 -20
  288. zenml/zen_stores/secrets_stores/hashicorp_secrets_store.py +4 -8
  289. zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +10 -7
  290. zenml/zen_stores/secrets_stores/sql_secrets_store.py +5 -6
  291. zenml/zen_stores/sql_zen_store.py +196 -120
  292. zenml/zen_stores/zen_store_interface.py +33 -0
  293. {zenml_nightly-0.58.2.dev20240618.dist-info → zenml_nightly-0.58.2.dev20240619.dist-info}/METADATA +8 -7
  294. {zenml_nightly-0.58.2.dev20240618.dist-info → zenml_nightly-0.58.2.dev20240619.dist-info}/RECORD +297 -294
  295. zenml/integrations/kubeflow/utils.py +0 -95
  296. zenml/models/v2/base/internal.py +0 -37
  297. zenml/models/v2/base/update.py +0 -44
  298. {zenml_nightly-0.58.2.dev20240618.dist-info → zenml_nightly-0.58.2.dev20240619.dist-info}/LICENSE +0 -0
  299. {zenml_nightly-0.58.2.dev20240618.dist-info → zenml_nightly-0.58.2.dev20240619.dist-info}/WHEEL +0 -0
  300. {zenml_nightly-0.58.2.dev20240618.dist-info → zenml_nightly-0.58.2.dev20240619.dist-info}/entry_points.txt +0 -0
@@ -18,10 +18,11 @@ from datetime import datetime
18
18
  from typing import Any, ClassVar, Dict, List, Optional, Union
19
19
  from uuid import UUID
20
20
 
21
- from pydantic import Field, SecretStr, root_validator
21
+ from pydantic import Field, SecretStr, ValidationError, model_validator
22
22
 
23
23
  from zenml.constants import STR_FIELD_MAX_LENGTH
24
24
  from zenml.logger import get_logger
25
+ from zenml.models.v2.base.base import BaseUpdate
25
26
  from zenml.models.v2.base.scoped import (
26
27
  WorkspaceScopedFilter,
27
28
  WorkspaceScopedRequest,
@@ -30,10 +31,10 @@ from zenml.models.v2.base.scoped import (
30
31
  WorkspaceScopedResponseMetadata,
31
32
  WorkspaceScopedResponseResources,
32
33
  )
33
- from zenml.models.v2.base.update import update_model
34
34
  from zenml.models.v2.misc.service_connector_type import (
35
35
  ServiceConnectorTypeModel,
36
36
  )
37
+ from zenml.utils.secret_utils import PlainSerializedSecretStr
37
38
 
38
39
  logger = get_logger(__name__)
39
40
 
@@ -49,6 +50,7 @@ class ServiceConnectorRequest(WorkspaceScopedRequest):
49
50
  )
50
51
  connector_type: Union[str, "ServiceConnectorTypeModel"] = Field(
51
52
  title="The type of service connector.",
53
+ union_mode="left_to_right",
52
54
  )
53
55
  description: str = Field(
54
56
  default="",
@@ -99,7 +101,7 @@ class ServiceConnectorRequest(WorkspaceScopedRequest):
99
101
  default_factory=dict,
100
102
  title="The service connector configuration, not including secrets.",
101
103
  )
102
- secrets: Dict[str, Optional[SecretStr]] = Field(
104
+ secrets: Dict[str, Optional[PlainSerializedSecretStr]] = Field(
103
105
  default_factory=dict,
104
106
  title="The service connector secrets.",
105
107
  )
@@ -204,8 +206,7 @@ class ServiceConnectorRequest(WorkspaceScopedRequest):
204
206
  # ------------------ Update Model ------------------
205
207
 
206
208
 
207
- @update_model
208
- class ServiceConnectorUpdate(ServiceConnectorRequest):
209
+ class ServiceConnectorUpdate(BaseUpdate):
209
210
  """Model used for service connector updates.
210
211
 
211
212
  Most fields in the update model are optional and will not be updated if
@@ -232,24 +233,169 @@ class ServiceConnectorUpdate(ServiceConnectorRequest):
232
233
  have a None default value.
233
234
  """
234
235
 
235
- resource_types: Optional[List[str]] = Field( # type: ignore[assignment]
236
+ name: Optional[str] = Field(
237
+ title="The service connector name.",
238
+ max_length=STR_FIELD_MAX_LENGTH,
239
+ default=None,
240
+ )
241
+ connector_type: Optional[Union[str, "ServiceConnectorTypeModel"]] = Field(
242
+ title="The type of service connector.",
243
+ default=None,
244
+ union_mode="left_to_right",
245
+ )
246
+ description: Optional[str] = Field(
247
+ title="The service connector instance description.",
236
248
  default=None,
249
+ )
250
+ auth_method: Optional[str] = Field(
251
+ title="The authentication method that the connector instance uses to "
252
+ "access the resources.",
253
+ max_length=STR_FIELD_MAX_LENGTH,
254
+ default=None,
255
+ )
256
+ resource_types: Optional[List[str]] = Field(
237
257
  title="The type(s) of resource that the connector instance can be used "
238
258
  "to gain access to.",
259
+ default=None,
239
260
  )
240
- configuration: Optional[Dict[str, Any]] = Field( # type: ignore[assignment]
261
+ resource_id: Optional[str] = Field(
262
+ title="Uniquely identifies a specific resource instance that the "
263
+ "connector instance can be used to access. If omitted, the "
264
+ "connector instance can be used to access any and all resource "
265
+ "instances that the authentication method and resource type(s) "
266
+ "allow.",
267
+ max_length=STR_FIELD_MAX_LENGTH,
241
268
  default=None,
242
- title="The service connector configuration, not including secrets.",
243
269
  )
244
- secrets: Optional[Dict[str, Optional[SecretStr]]] = Field( # type: ignore[assignment]
270
+ supports_instances: Optional[bool] = Field(
271
+ title="Indicates whether the connector instance can be used to access "
272
+ "multiple instances of the configured resource type.",
273
+ default=None,
274
+ )
275
+ expires_at: Optional[datetime] = Field(
276
+ title="Time when the authentication credentials configured for the "
277
+ "connector expire. If omitted, the credentials do not expire.",
245
278
  default=None,
246
- title="The service connector secrets.",
247
279
  )
248
- labels: Optional[Dict[str, str]] = Field( # type: ignore[assignment]
280
+ expires_skew_tolerance: Optional[int] = Field(
281
+ title="The number of seconds of tolerance to apply when checking "
282
+ "whether the authentication credentials configured for the "
283
+ "connector have expired. If omitted, no tolerance is applied.",
249
284
  default=None,
285
+ )
286
+ expiration_seconds: Optional[int] = Field(
287
+ title="The duration, in seconds, that the temporary credentials "
288
+ "generated by this connector should remain valid. Only "
289
+ "applicable for connectors and authentication methods that "
290
+ "involve generating temporary credentials from the ones "
291
+ "configured in the connector.",
292
+ default=None,
293
+ )
294
+ configuration: Optional[Dict[str, Any]] = Field(
295
+ title="The service connector configuration, not including secrets.",
296
+ default=None,
297
+ )
298
+ secrets: Optional[Dict[str, Optional[PlainSerializedSecretStr]]] = Field(
299
+ title="The service connector secrets.",
300
+ default=None,
301
+ )
302
+ labels: Optional[Dict[str, str]] = Field(
250
303
  title="Service connector labels.",
304
+ default=None,
251
305
  )
252
306
 
307
+ # Analytics
308
+ ANALYTICS_FIELDS: ClassVar[List[str]] = [
309
+ "connector_type",
310
+ "auth_method",
311
+ "resource_types",
312
+ ]
313
+
314
+ def get_analytics_metadata(self) -> Dict[str, Any]:
315
+ """Format the resource types in the analytics metadata.
316
+
317
+ Returns:
318
+ Dict of analytics metadata.
319
+ """
320
+ metadata = super().get_analytics_metadata()
321
+
322
+ if self.resource_types is not None:
323
+ if len(self.resource_types) == 1:
324
+ metadata["resource_types"] = self.resource_types[0]
325
+ else:
326
+ metadata["resource_types"] = ", ".join(self.resource_types)
327
+
328
+ if self.connector_type is not None:
329
+ metadata["connector_type"] = self.type
330
+
331
+ return metadata
332
+
333
+ # Helper methods
334
+ @property
335
+ def type(self) -> Optional[str]:
336
+ """Get the connector type.
337
+
338
+ Returns:
339
+ The connector type.
340
+ """
341
+ if self.connector_type is not None:
342
+ if isinstance(self.connector_type, str):
343
+ return self.connector_type
344
+ return self.connector_type.connector_type
345
+ return None
346
+
347
+ def validate_and_configure_resources(
348
+ self,
349
+ connector_type: "ServiceConnectorTypeModel",
350
+ resource_types: Optional[Union[str, List[str]]] = None,
351
+ resource_id: Optional[str] = None,
352
+ configuration: Optional[Dict[str, Any]] = None,
353
+ secrets: Optional[Dict[str, Optional[SecretStr]]] = None,
354
+ ) -> None:
355
+ """Validate and configure the resources that the connector can be used to access.
356
+
357
+ Args:
358
+ connector_type: The connector type specification used to validate
359
+ the connector configuration.
360
+ resource_types: The type(s) of resource that the connector instance
361
+ can be used to access. If omitted, a multi-type connector is
362
+ configured.
363
+ resource_id: Uniquely identifies a specific resource instance that
364
+ the connector instance can be used to access.
365
+ configuration: The connector configuration.
366
+ secrets: The connector secrets.
367
+ """
368
+ _validate_and_configure_resources(
369
+ connector=self,
370
+ connector_type=connector_type,
371
+ resource_types=resource_types,
372
+ resource_id=resource_id,
373
+ configuration=configuration,
374
+ secrets=secrets,
375
+ )
376
+
377
+ def convert_to_request(self) -> "ServiceConnectorRequest":
378
+ """Method to generate a service connector request object from self.
379
+
380
+ For certain operations, the service connector update model need to
381
+ adhere to the limitations set by the request model. In order to use
382
+ update models in such situations, we need to be able to convert an
383
+ update model into a request model.
384
+
385
+ Returns:
386
+ The equivalent request model
387
+
388
+ Raises:
389
+ RuntimeError: if the model can not be converted to a request model.
390
+ """
391
+ try:
392
+ return ServiceConnectorRequest.model_validate(self.model_dump())
393
+ except ValidationError as e:
394
+ raise RuntimeError(
395
+ "The service connector update model can not be converted into "
396
+ f"an equivalent request model: {e}"
397
+ )
398
+
253
399
 
254
400
  # ------------------ Response Model ------------------
255
401
 
@@ -262,7 +408,7 @@ class ServiceConnectorResponseBody(WorkspaceScopedResponseBody):
262
408
  title="The service connector instance description.",
263
409
  )
264
410
  connector_type: Union[str, "ServiceConnectorTypeModel"] = Field(
265
- title="The type of service connector.",
411
+ title="The type of service connector.", union_mode="left_to_right"
266
412
  )
267
413
  auth_method: str = Field(
268
414
  title="The authentication method that the connector instance uses to "
@@ -319,7 +465,7 @@ class ServiceConnectorResponseMetadata(WorkspaceScopedResponseMetadata):
319
465
  "connectors and authentication methods that involve generating "
320
466
  "temporary credentials from the ones configured in the connector.",
321
467
  )
322
- secrets: Dict[str, Optional[SecretStr]] = Field(
468
+ secrets: Dict[str, Optional[PlainSerializedSecretStr]] = Field(
323
469
  default_factory=dict,
324
470
  title="The service connector secrets.",
325
471
  )
@@ -644,10 +790,14 @@ class ServiceConnectorFilter(WorkspaceScopedFilter):
644
790
  description="The type of service connector to filter by",
645
791
  )
646
792
  workspace_id: Optional[Union[UUID, str]] = Field(
647
- default=None, description="Workspace to filter by"
793
+ default=None,
794
+ description="Workspace to filter by",
795
+ union_mode="left_to_right",
648
796
  )
649
797
  user_id: Optional[Union[UUID, str]] = Field(
650
- default=None, description="User to filter by"
798
+ default=None,
799
+ description="User to filter by",
800
+ union_mode="left_to_right",
651
801
  )
652
802
  auth_method: Optional[str] = Field(
653
803
  default=None,
@@ -678,56 +828,49 @@ class ServiceConnectorFilter(WorkspaceScopedFilter):
678
828
  default=None,
679
829
  title="Filter by the ID of the secret that contains the service "
680
830
  "connector's credentials",
831
+ union_mode="left_to_right",
681
832
  )
682
833
 
683
834
  # Use this internally to configure and access the labels as a dictionary
684
835
  labels: Optional[Dict[str, Optional[str]]] = Field(
685
836
  default=None,
686
837
  title="The labels to filter by, as a dictionary",
838
+ exclude=True,
687
839
  )
688
840
 
689
- @root_validator
690
- def validate_labels(cls, values: Dict[str, Any]) -> Dict[str, Any]:
841
+ @model_validator(mode="after")
842
+ def validate_labels(self) -> "ServiceConnectorFilter":
691
843
  """Parse the labels string into a label dictionary and vice-versa.
692
844
 
693
- Args:
694
- values: The values to validate.
695
-
696
845
  Returns:
697
846
  The validated values.
698
847
  """
699
- labels_str = values.get("labels_str")
700
- labels = values.get("labels")
701
- if labels_str is not None:
848
+ if self.labels_str is not None:
702
849
  try:
703
- values["labels"] = json.loads(labels_str)
850
+ self.labels = json.loads(self.labels_str)
704
851
  except json.JSONDecodeError:
705
852
  # Interpret as comma-separated values instead
706
- values["labels"] = {
853
+ self.labels = {
707
854
  label.split("=", 1)[0]: label.split("=", 1)[1]
708
855
  if "=" in label
709
856
  else None
710
- for label in labels_str.split(",")
857
+ for label in self.labels_str.split(",")
711
858
  }
712
- elif labels is not None:
713
- values["labels_str"] = json.dumps(values["labels"])
714
-
715
- return values
859
+ elif self.labels is not None:
860
+ self.labels_str = json.dumps(self.labels)
716
861
 
717
- class Config:
718
- """Pydantic config class."""
719
-
720
- # Exclude the labels field from the serialized response
721
- # (it is only used internally). The labels_str field is a string
722
- # representation of the labels that can be used in the API.
723
- exclude = ["labels"]
862
+ return self
724
863
 
725
864
 
726
865
  # ------------------ Helper Functions ------------------
727
866
 
728
867
 
729
868
  def _validate_and_configure_resources(
730
- connector: Union[ServiceConnectorRequest, ServiceConnectorResponse],
869
+ connector: Union[
870
+ ServiceConnectorRequest,
871
+ ServiceConnectorUpdate,
872
+ ServiceConnectorResponse,
873
+ ],
731
874
  connector_type: "ServiceConnectorTypeModel",
732
875
  resource_types: Optional[Union[str, List[str]]] = None,
733
876
  resource_id: Optional[str] = None,
@@ -757,17 +900,24 @@ def _validate_and_configure_resources(
757
900
  # connector model itself, while for the response model, they are in the
758
901
  # metadata field.
759
902
  update_connector_metadata: Union[
760
- ServiceConnectorRequest, ServiceConnectorResponseMetadata
903
+ ServiceConnectorRequest,
904
+ ServiceConnectorUpdate,
905
+ ServiceConnectorResponseMetadata,
761
906
  ]
762
907
  update_connector_body: Union[
763
- ServiceConnectorRequest, ServiceConnectorResponseBody
908
+ ServiceConnectorRequest,
909
+ ServiceConnectorUpdate,
910
+ ServiceConnectorResponseBody,
764
911
  ]
765
912
  if isinstance(connector, ServiceConnectorRequest):
766
913
  update_connector_metadata = connector
767
914
  update_connector_body = connector
915
+ elif isinstance(connector, ServiceConnectorUpdate):
916
+ update_connector_metadata = connector
917
+ update_connector_body = connector
768
918
  else:
769
919
  # Updating service connector responses must only be done on hydrated
770
- # instances, otherwise the metadata will be missing and we risk calling
920
+ # instances, otherwise the metadata will be missing, and we risk calling
771
921
  # the ZenML store to update the connector with additional information.
772
922
  # This is just a safety measure, but it will never happen because
773
923
  # this method will always be called on a hydrated response.
@@ -792,6 +942,7 @@ def _validate_and_configure_resources(
792
942
  try:
793
943
  # Validate the connector configuration and retrieve the resource
794
944
  # specification
945
+ assert connector.auth_method is not None
795
946
  (
796
947
  auth_method_spec,
797
948
  resource_spec,
@@ -835,8 +986,27 @@ def _validate_and_configure_resources(
835
986
  required = attr_name in auth_method_spec.config_schema.get(
836
987
  "required", []
837
988
  )
838
- secret = attr_schema.get("format", "") == "password"
839
- attr_type = attr_schema.get("type", "string")
989
+
990
+ attr_any_of = attr_schema.get("anyOf", [])
991
+
992
+ if attr_any_of:
993
+ no_null_attr_any_of = [
994
+ a for a in attr_any_of if a.get("type", "string") != "null"
995
+ ]
996
+
997
+ if len(no_null_attr_any_of) == 1:
998
+ secret = no_null_attr_any_of[0].get("format", "") == "password"
999
+ attr_type = no_null_attr_any_of[0].get("type", "string")
1000
+ else:
1001
+ # TODO: Still not sure what needs to happen here. We will
1002
+ # only end up here if the auth method config schema has a
1003
+ # field with a Union[SecretStr, int] or something.
1004
+ raise RuntimeError("Service connector schema error.")
1005
+
1006
+ else:
1007
+ secret = attr_schema.get("format", "") == "password"
1008
+ attr_type = attr_schema.get("type", "string")
1009
+
840
1010
  value = configuration.get(attr_name, secrets.get(attr_name))
841
1011
  if required:
842
1012
  if value is None:
@@ -869,7 +1039,12 @@ def _validate_and_configure_resources(
869
1039
  f"{supported_attrs}",
870
1040
  )
871
1041
  # Warn about secrets that are not part of the configuration schema
872
- for attr_name in set(secrets.keys()) - connector.secrets.keys():
1042
+ connector_secrets = (
1043
+ set(connector.secrets.keys())
1044
+ if connector.secrets is not None
1045
+ else set()
1046
+ )
1047
+ for attr_name in set(secrets.keys()) - connector_secrets:
873
1048
  logger.warning(
874
1049
  f"Ignoring unknown attribute in connector '{connector.name}' "
875
1050
  f"configuration {attr_name}. Supported attributes are: "
@@ -14,16 +14,15 @@
14
14
  """Models representing stacks."""
15
15
 
16
16
  import json
17
- from typing import Any, ClassVar, Dict, List, Optional, Union
17
+ from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Optional, Union
18
18
  from uuid import UUID
19
19
 
20
20
  from pydantic import Field
21
- from sqlalchemy import and_
22
- from sqlalchemy.sql.elements import BinaryExpression, BooleanClauseList
21
+ from sqlmodel import and_
23
22
 
24
23
  from zenml.constants import STR_FIELD_MAX_LENGTH
25
24
  from zenml.enums import StackComponentType
26
- from zenml.models.v2.base.internal import server_owned_request_model
25
+ from zenml.models.v2.base.base import BaseUpdate
27
26
  from zenml.models.v2.base.scoped import (
28
27
  WorkspaceScopedFilter,
29
28
  WorkspaceScopedRequest,
@@ -32,9 +31,11 @@ from zenml.models.v2.base.scoped import (
32
31
  WorkspaceScopedResponseMetadata,
33
32
  WorkspaceScopedResponseResources,
34
33
  )
35
- from zenml.models.v2.base.update import update_model
36
34
  from zenml.models.v2.core.component import ComponentResponse
37
35
 
36
+ if TYPE_CHECKING:
37
+ from sqlalchemy.sql.elements import ColumnElement
38
+
38
39
  # ------------------ Request Model ------------------
39
40
 
40
41
 
@@ -74,20 +75,41 @@ class StackRequest(WorkspaceScopedRequest):
74
75
  )
75
76
 
76
77
 
77
- @server_owned_request_model
78
78
  class InternalStackRequest(StackRequest):
79
79
  """Internal stack request model."""
80
80
 
81
- pass
81
+ user: Optional[UUID] = Field( # type: ignore[assignment]
82
+ title="The id of the user that created this resource.",
83
+ default=None,
84
+ )
82
85
 
83
86
 
84
87
  # ------------------ Update Model ------------------
85
88
 
86
89
 
87
- @update_model
88
- class StackUpdate(StackRequest):
90
+ class StackUpdate(BaseUpdate):
89
91
  """Update model for stacks."""
90
92
 
93
+ name: Optional[str] = Field(
94
+ title="The name of the stack.",
95
+ max_length=STR_FIELD_MAX_LENGTH,
96
+ default=None,
97
+ )
98
+ description: Optional[str] = Field(
99
+ title="The description of the stack",
100
+ max_length=STR_FIELD_MAX_LENGTH,
101
+ default=None,
102
+ )
103
+ stack_spec_path: Optional[str] = Field(
104
+ title="The path to the stack spec used for mlstacks deployments.",
105
+ default=None,
106
+ )
107
+ components: Optional[Dict[StackComponentType, List[UUID]]] = Field(
108
+ title="A mapping of stack component types to the actual"
109
+ "instances of components of this type.",
110
+ default=None,
111
+ )
112
+
91
113
 
92
114
  # ------------------ Response Model ------------------
93
115
 
@@ -167,7 +189,9 @@ class StackResponse(
167
189
  flavor=component.flavor,
168
190
  )
169
191
  configuration = json.loads(
170
- component.get_metadata().json(include={"configuration"})
192
+ component.get_metadata().model_dump_json(
193
+ include={"configuration"}
194
+ )
171
195
  )
172
196
  component_dict.update(configuration)
173
197
 
@@ -248,18 +272,22 @@ class StackFilter(WorkspaceScopedFilter):
248
272
  default=None, description="Description of the stack"
249
273
  )
250
274
  workspace_id: Optional[Union[UUID, str]] = Field(
251
- default=None, description="Workspace of the stack"
275
+ default=None,
276
+ description="Workspace of the stack",
277
+ union_mode="left_to_right",
252
278
  )
253
279
  user_id: Optional[Union[UUID, str]] = Field(
254
- default=None, description="User of the stack"
280
+ default=None,
281
+ description="User of the stack",
282
+ union_mode="left_to_right",
255
283
  )
256
284
  component_id: Optional[Union[UUID, str]] = Field(
257
- default=None, description="Component in the stack"
285
+ default=None,
286
+ description="Component in the stack",
287
+ union_mode="left_to_right",
258
288
  )
259
289
 
260
- def get_custom_filters(
261
- self,
262
- ) -> List[Union["BinaryExpression[Any]", "BooleanClauseList[Any]"]]:
290
+ def get_custom_filters(self) -> List["ColumnElement[bool]"]:
263
291
  """Get custom filters.
264
292
 
265
293
  Returns:
@@ -273,7 +301,7 @@ class StackFilter(WorkspaceScopedFilter):
273
301
  )
274
302
 
275
303
  if self.component_id:
276
- component_id_filter = and_( # type: ignore[type-var]
304
+ component_id_filter = and_(
277
305
  StackCompositionSchema.stack_id == StackSchema.id,
278
306
  StackCompositionSchema.component_id == self.component_id,
279
307
  )
@@ -17,7 +17,7 @@ from datetime import datetime
17
17
  from typing import TYPE_CHECKING, Dict, List, Optional, Union
18
18
  from uuid import UUID
19
19
 
20
- from pydantic import BaseModel, Field
20
+ from pydantic import BaseModel, ConfigDict, Field
21
21
 
22
22
  from zenml.config.step_configurations import StepConfiguration, StepSpec
23
23
  from zenml.constants import STR_FIELD_MAX_LENGTH, TEXT_FIELD_MAX_LENGTH
@@ -220,7 +220,15 @@ class StepRunResponseMetadata(WorkspaceScopedResponseMetadata):
220
220
  class StepRunResponseResources(WorkspaceScopedResponseResources):
221
221
  """Class for all resource models associated with the step run entity."""
222
222
 
223
- model_version: Optional[ModelVersionResponse]
223
+ model_version: Optional[ModelVersionResponse] = None
224
+
225
+ # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
226
+ # fields defined under base models. If not handled, this raises a warning.
227
+ # It is possible to suppress this warning message with the following
228
+ # configuration, however the ultimate solution is to rename these fields.
229
+ # Even though they do not cause any problems right now, if we are not
230
+ # careful we might overwrite some fields protected by pydantic.
231
+ model_config = ConfigDict(protected_namespaces=())
224
232
 
225
233
 
226
234
  class StepRunResponse(
@@ -471,20 +479,32 @@ class StepRunFilter(WorkspaceScopedFilter):
471
479
  description="Status of the Step Run",
472
480
  )
473
481
  start_time: Optional[Union[datetime, str]] = Field(
474
- default=None, description="Start time for this run"
482
+ default=None,
483
+ description="Start time for this run",
484
+ union_mode="left_to_right",
475
485
  )
476
486
  end_time: Optional[Union[datetime, str]] = Field(
477
- default=None, description="End time for this run"
487
+ default=None,
488
+ description="End time for this run",
489
+ union_mode="left_to_right",
478
490
  )
479
491
  pipeline_run_id: Optional[Union[UUID, str]] = Field(
480
- default=None, description="Pipeline run of this step run"
492
+ default=None,
493
+ description="Pipeline run of this step run",
494
+ union_mode="left_to_right",
481
495
  )
482
496
  original_step_run_id: Optional[Union[UUID, str]] = Field(
483
- default=None, description="Original id for this step run"
497
+ default=None,
498
+ description="Original id for this step run",
499
+ union_mode="left_to_right",
484
500
  )
485
501
  user_id: Optional[Union[UUID, str]] = Field(
486
- default=None, description="User that produced this step run"
502
+ default=None,
503
+ description="User that produced this step run",
504
+ union_mode="left_to_right",
487
505
  )
488
506
  workspace_id: Optional[Union[UUID, str]] = Field(
489
- default=None, description="Workspace of this step run"
507
+ default=None,
508
+ description="Workspace of this step run",
509
+ union_mode="left_to_right",
490
510
  )
@@ -51,8 +51,8 @@ class TagRequest(BaseRequest):
51
51
  class TagUpdate(BaseModel):
52
52
  """Update model for tags."""
53
53
 
54
- name: Optional[str]
55
- color: Optional[ColorVariants]
54
+ name: Optional[str] = None
55
+ color: Optional[ColorVariants] = None
56
56
 
57
57
 
58
58
  # ------------------ Response Model ------------------
@@ -121,5 +121,9 @@ class TagResponse(
121
121
  class TagFilter(BaseFilter):
122
122
  """Model to enable advanced filtering of all tags."""
123
123
 
124
- name: Optional[str]
125
- color: Optional[ColorVariants]
124
+ name: Optional[str] = Field(
125
+ description="The unique title of the tag.", default=None
126
+ )
127
+ color: Optional[ColorVariants] = Field(
128
+ description="The color variant assigned to the tag.", default=None
129
+ )
@@ -68,7 +68,6 @@ class TriggerBase(BaseModel):
68
68
  )
69
69
  action_subtype: PluginSubType = Field(
70
70
  title="The subtype of the action that is executed by this trigger.",
71
- max_length=STR_FIELD_MAX_LENGTH,
72
71
  )
73
72
  service_account_id: UUID = Field(
74
73
  title="The service account that is used to execute the action.",
@@ -164,7 +163,6 @@ class TriggerResponseBody(WorkspaceScopedResponseBody):
164
163
  )
165
164
  action_subtype: PluginSubType = Field(
166
165
  title="The subtype of the action that is executed by this trigger.",
167
- max_length=STR_FIELD_MAX_LENGTH,
168
166
  )
169
167
  is_active: bool = Field(
170
168
  title="Whether the trigger is active.",
@@ -341,6 +339,7 @@ class TriggerFilter(WorkspaceScopedFilter):
341
339
  event_source_id: Optional[Union[UUID, str]] = Field(
342
340
  default=None,
343
341
  description="By the event source this trigger is attached to.",
342
+ union_mode="left_to_right",
344
343
  )
345
344
  is_active: Optional[bool] = Field(
346
345
  default=None,
@@ -358,6 +357,7 @@ class TriggerFilter(WorkspaceScopedFilter):
358
357
  resource_id: Optional[Union[UUID, str]] = Field(
359
358
  default=None,
360
359
  description="By the resource this trigger references.",
360
+ union_mode="left_to_right",
361
361
  )
362
362
  resource_type: Optional[str] = Field(
363
363
  default=None,
@@ -115,4 +115,5 @@ class TriggerExecutionFilter(WorkspaceScopedFilter):
115
115
  trigger_id: Optional[Union[UUID, str]] = Field(
116
116
  default=None,
117
117
  description="ID of the trigger of the execution.",
118
+ union_mode="left_to_right",
118
119
  )