zenml-nightly 0.58.2.dev20240615__py3-none-any.whl → 0.58.2.dev20240623__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/_hub/client.py +8 -5
- zenml/actions/base_action.py +8 -10
- zenml/artifact_stores/base_artifact_store.py +20 -15
- zenml/artifact_stores/local_artifact_store.py +3 -2
- zenml/artifacts/artifact_config.py +34 -19
- zenml/artifacts/external_artifact.py +18 -8
- zenml/artifacts/external_artifact_config.py +14 -6
- zenml/artifacts/unmaterialized_artifact.py +2 -11
- zenml/cli/__init__.py +6 -0
- zenml/cli/artifact.py +20 -2
- zenml/cli/base.py +1 -1
- zenml/cli/served_model.py +0 -1
- zenml/cli/server.py +3 -3
- zenml/cli/utils.py +36 -40
- zenml/cli/web_login.py +2 -2
- zenml/client.py +198 -24
- zenml/client_lazy_loader.py +20 -14
- zenml/config/base_settings.py +5 -6
- zenml/config/build_configuration.py +1 -1
- zenml/config/compiler.py +3 -3
- zenml/config/docker_settings.py +27 -28
- zenml/config/global_config.py +33 -37
- zenml/config/pipeline_configurations.py +8 -11
- zenml/config/pipeline_run_configuration.py +6 -2
- zenml/config/pipeline_spec.py +3 -4
- zenml/config/resource_settings.py +8 -9
- zenml/config/schedule.py +16 -20
- zenml/config/secret_reference_mixin.py +6 -3
- zenml/config/secrets_store_config.py +16 -23
- zenml/config/server_config.py +50 -46
- zenml/config/settings_resolver.py +1 -1
- zenml/config/source.py +45 -35
- zenml/config/step_configurations.py +53 -31
- zenml/config/step_run_info.py +3 -0
- zenml/config/store_config.py +20 -19
- zenml/config/strict_base_model.py +2 -6
- zenml/constants.py +26 -2
- zenml/container_registries/base_container_registry.py +3 -2
- zenml/container_registries/default_container_registry.py +3 -3
- zenml/event_hub/base_event_hub.py +1 -1
- zenml/event_sources/base_event_source.py +11 -16
- zenml/exceptions.py +4 -0
- zenml/integrations/airflow/__init__.py +2 -6
- zenml/integrations/airflow/flavors/airflow_orchestrator_flavor.py +6 -7
- zenml/integrations/airflow/orchestrators/airflow_orchestrator.py +13 -249
- zenml/integrations/airflow/orchestrators/dag_generator.py +5 -3
- zenml/integrations/argilla/flavors/argilla_annotator_flavor.py +5 -4
- zenml/integrations/aws/__init__.py +1 -1
- zenml/integrations/aws/flavors/aws_container_registry_flavor.py +3 -2
- zenml/integrations/aws/flavors/sagemaker_orchestrator_flavor.py +11 -5
- zenml/integrations/aws/flavors/sagemaker_step_operator_flavor.py +6 -2
- zenml/integrations/aws/service_connectors/aws_service_connector.py +5 -4
- zenml/integrations/aws/step_operators/sagemaker_step_operator.py +1 -1
- zenml/integrations/azure/flavors/azureml_step_operator_flavor.py +4 -4
- zenml/integrations/azure/service_connectors/azure_service_connector.py +4 -3
- zenml/integrations/azure/step_operators/azureml_step_operator.py +2 -1
- zenml/integrations/bentoml/steps/bentoml_deployer.py +1 -1
- zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +8 -12
- zenml/integrations/comet/flavors/comet_experiment_tracker_flavor.py +1 -1
- zenml/integrations/constants.py +0 -1
- zenml/integrations/deepchecks/__init__.py +1 -0
- zenml/integrations/evidently/__init__.py +5 -3
- zenml/integrations/evidently/column_mapping.py +11 -3
- zenml/integrations/evidently/data_validators/evidently_data_validator.py +21 -3
- zenml/integrations/evidently/metrics.py +5 -6
- zenml/integrations/evidently/tests.py +5 -6
- zenml/integrations/facets/models.py +2 -6
- zenml/integrations/feast/__init__.py +3 -1
- zenml/integrations/feast/feature_stores/feast_feature_store.py +0 -23
- zenml/integrations/gcp/__init__.py +1 -1
- zenml/integrations/gcp/flavors/vertex_orchestrator_flavor.py +1 -1
- zenml/integrations/gcp/flavors/vertex_step_operator_flavor.py +1 -1
- zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +234 -103
- zenml/integrations/gcp/service_connectors/gcp_service_connector.py +57 -42
- zenml/integrations/gcp/step_operators/vertex_step_operator.py +1 -0
- zenml/integrations/github/code_repositories/github_code_repository.py +1 -1
- zenml/integrations/github/plugins/event_sources/github_webhook_event_source.py +9 -13
- zenml/integrations/great_expectations/__init__.py +1 -1
- zenml/integrations/great_expectations/data_validators/ge_data_validator.py +44 -44
- zenml/integrations/great_expectations/flavors/great_expectations_data_validator_flavor.py +35 -2
- zenml/integrations/great_expectations/ge_store_backend.py +24 -11
- zenml/integrations/great_expectations/materializers/ge_materializer.py +3 -3
- zenml/integrations/great_expectations/utils.py +5 -5
- zenml/integrations/huggingface/__init__.py +3 -0
- zenml/integrations/huggingface/flavors/huggingface_model_deployer_flavor.py +1 -1
- zenml/integrations/huggingface/steps/__init__.py +3 -0
- zenml/integrations/huggingface/steps/accelerate_runner.py +149 -0
- zenml/integrations/huggingface/steps/huggingface_deployer.py +2 -2
- zenml/integrations/hyperai/flavors/hyperai_orchestrator_flavor.py +1 -1
- zenml/integrations/hyperai/service_connectors/hyperai_service_connector.py +4 -3
- zenml/integrations/kubeflow/__init__.py +1 -1
- zenml/integrations/kubeflow/flavors/kubeflow_orchestrator_flavor.py +48 -81
- zenml/integrations/kubeflow/orchestrators/kubeflow_orchestrator.py +295 -245
- zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py +1 -1
- zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py +11 -2
- zenml/integrations/kubernetes/pod_settings.py +17 -31
- zenml/integrations/kubernetes/service_connectors/kubernetes_service_connector.py +8 -7
- zenml/integrations/label_studio/__init__.py +1 -3
- zenml/integrations/label_studio/annotators/label_studio_annotator.py +3 -4
- zenml/integrations/label_studio/flavors/label_studio_annotator_flavor.py +2 -2
- zenml/integrations/langchain/__init__.py +5 -1
- zenml/integrations/langchain/materializers/document_materializer.py +44 -8
- zenml/integrations/mlflow/__init__.py +9 -3
- zenml/integrations/mlflow/experiment_trackers/mlflow_experiment_tracker.py +1 -1
- zenml/integrations/mlflow/flavors/mlflow_experiment_tracker_flavor.py +29 -37
- zenml/integrations/mlflow/model_registries/mlflow_model_registry.py +4 -4
- zenml/integrations/mlflow/steps/mlflow_deployer.py +1 -1
- zenml/integrations/neptune/flavors/neptune_experiment_tracker_flavor.py +1 -1
- zenml/integrations/neural_prophet/__init__.py +5 -1
- zenml/integrations/pigeon/flavors/pigeon_annotator_flavor.py +1 -1
- zenml/integrations/s3/flavors/s3_artifact_store_flavor.py +9 -8
- zenml/integrations/seldon/seldon_client.py +52 -67
- zenml/integrations/seldon/services/seldon_deployment.py +3 -3
- zenml/integrations/seldon/steps/seldon_deployer.py +4 -4
- zenml/integrations/skypilot/flavors/skypilot_orchestrator_base_vm_config.py +15 -5
- zenml/integrations/skypilot_aws/__init__.py +1 -1
- zenml/integrations/skypilot_aws/flavors/skypilot_orchestrator_aws_vm_flavor.py +1 -1
- zenml/integrations/skypilot_azure/__init__.py +1 -1
- zenml/integrations/skypilot_azure/flavors/skypilot_orchestrator_azure_vm_flavor.py +1 -1
- zenml/integrations/skypilot_gcp/__init__.py +2 -1
- zenml/integrations/skypilot_gcp/flavors/skypilot_orchestrator_gcp_vm_flavor.py +1 -1
- zenml/integrations/skypilot_lambda/flavors/skypilot_orchestrator_lambda_vm_flavor.py +2 -2
- zenml/integrations/spark/flavors/spark_step_operator_flavor.py +1 -1
- zenml/integrations/spark/step_operators/spark_step_operator.py +2 -0
- zenml/integrations/tekton/__init__.py +1 -1
- zenml/integrations/tekton/flavors/tekton_orchestrator_flavor.py +66 -23
- zenml/integrations/tekton/orchestrators/tekton_orchestrator.py +547 -233
- zenml/integrations/tensorboard/__init__.py +1 -12
- zenml/integrations/tensorboard/services/tensorboard_service.py +3 -5
- zenml/integrations/tensorboard/visualizers/tensorboard_visualizer.py +6 -6
- zenml/integrations/tensorflow/__init__.py +2 -10
- zenml/integrations/tensorflow/materializers/keras_materializer.py +17 -9
- zenml/integrations/wandb/flavors/wandb_experiment_tracker_flavor.py +9 -14
- zenml/integrations/whylogs/flavors/whylogs_data_validator_flavor.py +1 -1
- zenml/lineage_graph/lineage_graph.py +1 -1
- zenml/logging/step_logging.py +15 -7
- zenml/materializers/built_in_materializer.py +3 -3
- zenml/materializers/pydantic_materializer.py +2 -2
- zenml/metadata/lazy_load.py +4 -4
- zenml/metadata/metadata_types.py +64 -4
- zenml/model/model.py +79 -54
- zenml/model_deployers/base_model_deployer.py +14 -12
- zenml/model_registries/base_model_registry.py +17 -15
- zenml/models/__init__.py +79 -206
- zenml/models/v2/base/base.py +54 -41
- zenml/models/v2/base/base_plugin_flavor.py +2 -6
- zenml/models/v2/base/filter.py +91 -76
- zenml/models/v2/base/page.py +2 -12
- zenml/models/v2/base/scoped.py +4 -7
- zenml/models/v2/core/api_key.py +22 -8
- zenml/models/v2/core/artifact.py +2 -2
- zenml/models/v2/core/artifact_version.py +74 -40
- zenml/models/v2/core/code_repository.py +37 -10
- zenml/models/v2/core/component.py +65 -16
- zenml/models/v2/core/device.py +14 -4
- zenml/models/v2/core/event_source.py +1 -2
- zenml/models/v2/core/flavor.py +74 -8
- zenml/models/v2/core/logs.py +68 -8
- zenml/models/v2/core/model.py +8 -4
- zenml/models/v2/core/model_version.py +25 -6
- zenml/models/v2/core/model_version_artifact.py +51 -21
- zenml/models/v2/core/model_version_pipeline_run.py +45 -13
- zenml/models/v2/core/pipeline.py +37 -72
- zenml/models/v2/core/pipeline_build.py +29 -17
- zenml/models/v2/core/pipeline_deployment.py +18 -6
- zenml/models/v2/core/pipeline_namespace.py +113 -0
- zenml/models/v2/core/pipeline_run.py +50 -22
- zenml/models/v2/core/run_metadata.py +59 -36
- zenml/models/v2/core/schedule.py +37 -24
- zenml/models/v2/core/secret.py +31 -12
- zenml/models/v2/core/service.py +64 -36
- zenml/models/v2/core/service_account.py +24 -11
- zenml/models/v2/core/service_connector.py +219 -44
- zenml/models/v2/core/stack.py +45 -17
- zenml/models/v2/core/step_run.py +28 -8
- zenml/models/v2/core/tag.py +8 -4
- zenml/models/v2/core/trigger.py +2 -2
- zenml/models/v2/core/trigger_execution.py +1 -0
- zenml/models/v2/core/user.py +18 -21
- zenml/models/v2/core/workspace.py +13 -3
- zenml/models/v2/misc/build_item.py +3 -3
- zenml/models/v2/misc/external_user.py +2 -6
- zenml/models/v2/misc/hub_plugin_models.py +9 -9
- zenml/models/v2/misc/loaded_visualization.py +2 -2
- zenml/models/v2/misc/service_connector_type.py +8 -17
- zenml/models/v2/misc/user_auth.py +7 -2
- zenml/new/pipelines/build_utils.py +3 -3
- zenml/new/pipelines/pipeline.py +17 -13
- zenml/new/pipelines/run_utils.py +103 -1
- zenml/orchestrators/base_orchestrator.py +10 -7
- zenml/orchestrators/local_docker/local_docker_orchestrator.py +1 -1
- zenml/orchestrators/step_launcher.py +28 -4
- zenml/orchestrators/step_runner.py +3 -6
- zenml/orchestrators/utils.py +1 -1
- zenml/plugins/base_plugin_flavor.py +6 -10
- zenml/plugins/plugin_flavor_registry.py +3 -7
- zenml/secret/base_secret.py +7 -8
- zenml/service_connectors/docker_service_connector.py +4 -3
- zenml/service_connectors/service_connector.py +5 -12
- zenml/service_connectors/service_connector_registry.py +2 -4
- zenml/services/container/container_service.py +1 -1
- zenml/services/container/container_service_endpoint.py +1 -1
- zenml/services/local/local_service.py +1 -1
- zenml/services/local/local_service_endpoint.py +1 -1
- zenml/services/service.py +16 -10
- zenml/services/service_type.py +4 -5
- zenml/services/terraform/terraform_service.py +1 -1
- zenml/stack/flavor.py +1 -5
- zenml/stack/flavor_registry.py +4 -4
- zenml/stack/stack.py +4 -1
- zenml/stack/stack_component.py +55 -31
- zenml/step_operators/step_operator_entrypoint_configuration.py +1 -0
- zenml/steps/base_step.py +34 -28
- zenml/steps/entrypoint_function_utils.py +3 -5
- zenml/steps/utils.py +12 -14
- zenml/utils/cuda_utils.py +50 -0
- zenml/utils/deprecation_utils.py +18 -20
- zenml/utils/dict_utils.py +1 -1
- zenml/utils/filesync_model.py +65 -28
- zenml/utils/function_utils.py +260 -0
- zenml/utils/json_utils.py +131 -0
- zenml/utils/mlstacks_utils.py +2 -2
- zenml/utils/pipeline_docker_image_builder.py +9 -0
- zenml/utils/pydantic_utils.py +270 -62
- zenml/utils/secret_utils.py +65 -12
- zenml/utils/source_utils.py +2 -2
- zenml/utils/typed_model.py +5 -3
- zenml/utils/typing_utils.py +243 -0
- zenml/utils/yaml_utils.py +1 -1
- zenml/zen_server/auth.py +2 -2
- zenml/zen_server/cloud_utils.py +6 -6
- zenml/zen_server/deploy/base_provider.py +1 -1
- zenml/zen_server/deploy/deployment.py +6 -8
- zenml/zen_server/deploy/docker/docker_zen_server.py +3 -4
- zenml/zen_server/deploy/local/local_provider.py +0 -1
- zenml/zen_server/deploy/local/local_zen_server.py +6 -6
- zenml/zen_server/deploy/terraform/terraform_zen_server.py +4 -6
- zenml/zen_server/exceptions.py +4 -1
- zenml/zen_server/feature_gate/zenml_cloud_feature_gate.py +1 -1
- zenml/zen_server/pipeline_deployment/utils.py +48 -68
- zenml/zen_server/rbac/models.py +2 -5
- zenml/zen_server/rbac/utils.py +11 -14
- zenml/zen_server/routers/auth_endpoints.py +2 -2
- zenml/zen_server/routers/pipeline_builds_endpoints.py +1 -1
- zenml/zen_server/routers/runs_endpoints.py +1 -1
- zenml/zen_server/routers/secrets_endpoints.py +3 -2
- zenml/zen_server/routers/server_endpoints.py +1 -1
- zenml/zen_server/routers/steps_endpoints.py +1 -1
- zenml/zen_server/routers/workspaces_endpoints.py +1 -1
- zenml/zen_stores/base_zen_store.py +46 -9
- zenml/zen_stores/migrations/utils.py +42 -46
- zenml/zen_stores/migrations/versions/0701da9951a0_added_service_table.py +1 -1
- zenml/zen_stores/migrations/versions/1041bc644e0d_remove_secrets_manager.py +5 -3
- zenml/zen_stores/migrations/versions/10a907dad202_delete_mlmd_tables.py +1 -1
- zenml/zen_stores/migrations/versions/26b776ad583e_redesign_artifacts.py +8 -10
- zenml/zen_stores/migrations/versions/37835ce041d2_optimizing_database.py +3 -3
- zenml/zen_stores/migrations/versions/46506f72f0ed_add_server_settings.py +10 -12
- zenml/zen_stores/migrations/versions/5994f9ad0489_introduce_role_permissions.py +3 -2
- zenml/zen_stores/migrations/versions/6917bce75069_add_pipeline_run_unique_constraint.py +4 -4
- zenml/zen_stores/migrations/versions/728c6369cfaa_add_name_column_to_input_artifact_pk.py +3 -2
- zenml/zen_stores/migrations/versions/743ec82b1b3c_update_size_of_build_images.py +2 -2
- zenml/zen_stores/migrations/versions/7500f434b71c_remove_shared_columns.py +3 -2
- zenml/zen_stores/migrations/versions/7834208cc3f6_artifact_project_scoping.py +8 -7
- zenml/zen_stores/migrations/versions/7b651bf6822e_track_secrets_in_db.py +6 -4
- zenml/zen_stores/migrations/versions/7e4a481d17f7_add_identity_table.py +2 -2
- zenml/zen_stores/migrations/versions/7f603e583dd7_fixed_migration.py +1 -1
- zenml/zen_stores/migrations/versions/a39c4184c8ce_remove_secrets_manager_flavors.py +2 -2
- zenml/zen_stores/migrations/versions/a91762e6be36_artifact_version_table.py +4 -4
- zenml/zen_stores/migrations/versions/alembic_start.py +1 -1
- zenml/zen_stores/migrations/versions/fbd7f18ced1e_increase_step_run_field_lengths.py +4 -4
- zenml/zen_stores/rest_zen_store.py +109 -49
- zenml/zen_stores/schemas/api_key_schemas.py +1 -1
- zenml/zen_stores/schemas/artifact_schemas.py +8 -8
- zenml/zen_stores/schemas/artifact_visualization_schemas.py +3 -3
- zenml/zen_stores/schemas/code_repository_schemas.py +1 -1
- zenml/zen_stores/schemas/component_schemas.py +8 -3
- zenml/zen_stores/schemas/device_schemas.py +8 -6
- zenml/zen_stores/schemas/event_source_schemas.py +3 -4
- zenml/zen_stores/schemas/flavor_schemas.py +5 -3
- zenml/zen_stores/schemas/model_schemas.py +26 -1
- zenml/zen_stores/schemas/pipeline_build_schemas.py +1 -1
- zenml/zen_stores/schemas/pipeline_deployment_schemas.py +4 -4
- zenml/zen_stores/schemas/pipeline_run_schemas.py +6 -6
- zenml/zen_stores/schemas/pipeline_schemas.py +5 -2
- zenml/zen_stores/schemas/run_metadata_schemas.py +2 -2
- zenml/zen_stores/schemas/secret_schemas.py +8 -5
- zenml/zen_stores/schemas/server_settings_schemas.py +3 -1
- zenml/zen_stores/schemas/service_connector_schemas.py +1 -1
- zenml/zen_stores/schemas/service_schemas.py +11 -2
- zenml/zen_stores/schemas/stack_schemas.py +1 -1
- zenml/zen_stores/schemas/step_run_schemas.py +11 -11
- zenml/zen_stores/schemas/tag_schemas.py +6 -2
- zenml/zen_stores/schemas/trigger_schemas.py +2 -2
- zenml/zen_stores/schemas/user_schemas.py +2 -2
- zenml/zen_stores/schemas/workspace_schemas.py +3 -1
- zenml/zen_stores/secrets_stores/aws_secrets_store.py +19 -20
- zenml/zen_stores/secrets_stores/azure_secrets_store.py +17 -20
- zenml/zen_stores/secrets_stores/base_secrets_store.py +79 -12
- zenml/zen_stores/secrets_stores/gcp_secrets_store.py +17 -20
- zenml/zen_stores/secrets_stores/hashicorp_secrets_store.py +4 -8
- zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +10 -7
- zenml/zen_stores/secrets_stores/sql_secrets_store.py +5 -6
- zenml/zen_stores/sql_zen_store.py +196 -120
- zenml/zen_stores/zen_store_interface.py +33 -0
- {zenml_nightly-0.58.2.dev20240615.dist-info → zenml_nightly-0.58.2.dev20240623.dist-info}/METADATA +9 -7
- {zenml_nightly-0.58.2.dev20240615.dist-info → zenml_nightly-0.58.2.dev20240623.dist-info}/RECORD +310 -307
- zenml/integrations/kubeflow/utils.py +0 -95
- zenml/models/v2/base/internal.py +0 -37
- zenml/models/v2/base/update.py +0 -44
- {zenml_nightly-0.58.2.dev20240615.dist-info → zenml_nightly-0.58.2.dev20240623.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.58.2.dev20240615.dist-info → zenml_nightly-0.58.2.dev20240623.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.58.2.dev20240615.dist-info → zenml_nightly-0.58.2.dev20240623.dist-info}/entry_points.txt +0 -0
zenml/utils/pydantic_utils.py
CHANGED
@@ -15,15 +15,28 @@
|
|
15
15
|
|
16
16
|
import inspect
|
17
17
|
import json
|
18
|
+
from json.decoder import JSONDecodeError
|
18
19
|
from typing import Any, Callable, Dict, Optional, Type, TypeVar, Union, cast
|
19
20
|
|
20
21
|
import yaml
|
21
|
-
from pydantic import
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
from pydantic import (
|
23
|
+
AfterValidator,
|
24
|
+
BaseModel,
|
25
|
+
BeforeValidator,
|
26
|
+
ConfigDict,
|
27
|
+
PlainValidator,
|
28
|
+
ValidationInfo,
|
29
|
+
WrapValidator,
|
30
|
+
validate_call,
|
31
|
+
)
|
32
|
+
from pydantic._internal import _repr as pydantic_repr
|
33
|
+
from pydantic.v1.utils import sequence_like
|
34
|
+
|
35
|
+
from zenml.logger import get_logger
|
36
|
+
from zenml.utils import dict_utils, typing_utils, yaml_utils
|
37
|
+
from zenml.utils.json_utils import pydantic_encoder
|
38
|
+
|
39
|
+
logger = get_logger(__name__)
|
27
40
|
|
28
41
|
M = TypeVar("M", bound="BaseModel")
|
29
42
|
|
@@ -54,9 +67,9 @@ def update_model(
|
|
54
67
|
else:
|
55
68
|
update_dict = update
|
56
69
|
else:
|
57
|
-
update_dict = update.
|
70
|
+
update_dict = update.model_dump(exclude_unset=True)
|
58
71
|
|
59
|
-
original_dict = original.
|
72
|
+
original_dict = original.model_dump(exclude_unset=True)
|
60
73
|
if recursive:
|
61
74
|
values = dict_utils.recursive_update(original_dict, update_dict)
|
62
75
|
else:
|
@@ -94,7 +107,7 @@ class TemplateGenerator:
|
|
94
107
|
self.instance_or_class
|
95
108
|
)
|
96
109
|
|
97
|
-
# Convert to json in an intermediate step so we can leverage Pydantic's
|
110
|
+
# Convert to json in an intermediate step, so we can leverage Pydantic's
|
98
111
|
# encoder to support types like UUID and datetime
|
99
112
|
json_string = json.dumps(template, default=pydantic_encoder)
|
100
113
|
return cast(Dict[str, Any], json.loads(json_string))
|
@@ -110,7 +123,7 @@ class TemplateGenerator:
|
|
110
123
|
"""
|
111
124
|
template = self._generate_template_for_model_class(model.__class__)
|
112
125
|
|
113
|
-
for name in model.
|
126
|
+
for name in model.model_fields_set:
|
114
127
|
value = getattr(model, name)
|
115
128
|
template[name] = self._generate_template_for_value(value)
|
116
129
|
|
@@ -130,19 +143,25 @@ class TemplateGenerator:
|
|
130
143
|
"""
|
131
144
|
template: Dict[str, Any] = {}
|
132
145
|
|
133
|
-
for name, field in model_class.
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
)
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
+
for name, field in model_class.model_fields.items():
|
147
|
+
annotation = field.annotation
|
148
|
+
|
149
|
+
if annotation is not None:
|
150
|
+
if self._is_model_class(annotation):
|
151
|
+
template[name] = self._generate_template_for_model_class(
|
152
|
+
annotation
|
153
|
+
)
|
154
|
+
|
155
|
+
elif typing_utils.is_optional(
|
156
|
+
annotation
|
157
|
+
) and self._is_model_class(
|
158
|
+
typing_utils.get_args(annotation)[0]
|
159
|
+
):
|
160
|
+
template[name] = self._generate_template_for_model_class(
|
161
|
+
typing_utils.get_args(annotation)[0]
|
162
|
+
)
|
163
|
+
else:
|
164
|
+
template[name] = pydantic_repr.display_as_type(annotation)
|
146
165
|
|
147
166
|
return template
|
148
167
|
|
@@ -188,12 +207,16 @@ class YAMLSerializationMixin(BaseModel):
|
|
188
207
|
|
189
208
|
Args:
|
190
209
|
sort_keys: Whether to sort the keys in the YAML representation.
|
191
|
-
**kwargs: Kwargs to pass to the pydantic
|
210
|
+
**kwargs: Kwargs to pass to the pydantic model_dump(...) method.
|
192
211
|
|
193
212
|
Returns:
|
194
213
|
YAML string representation.
|
195
214
|
"""
|
196
|
-
dict_ = json.loads(
|
215
|
+
dict_ = json.loads(
|
216
|
+
json.dumps(
|
217
|
+
self.model_dump(mode="json", **kwargs), sort_keys=sort_keys
|
218
|
+
)
|
219
|
+
)
|
197
220
|
return yaml.dump(dict_, sort_keys=sort_keys)
|
198
221
|
|
199
222
|
@classmethod
|
@@ -207,12 +230,12 @@ class YAMLSerializationMixin(BaseModel):
|
|
207
230
|
The model instance.
|
208
231
|
"""
|
209
232
|
dict_ = yaml_utils.read_yaml(path)
|
210
|
-
return cls.
|
233
|
+
return cls.model_validate(dict_)
|
211
234
|
|
212
235
|
|
213
236
|
def validate_function_args(
|
214
237
|
__func: Callable[..., Any],
|
215
|
-
__config:
|
238
|
+
__config: Optional[ConfigDict],
|
216
239
|
*args: Any,
|
217
240
|
**kwargs: Any,
|
218
241
|
) -> Dict[str, Any]:
|
@@ -233,40 +256,225 @@ def validate_function_args(
|
|
233
256
|
Returns:
|
234
257
|
The validated arguments.
|
235
258
|
"""
|
236
|
-
parameter_prefix = "zenml__"
|
237
|
-
|
238
259
|
signature = inspect.signature(__func)
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
#
|
260
|
+
|
261
|
+
validated_args = ()
|
262
|
+
validated_kwargs = {}
|
263
|
+
|
264
|
+
def f(*args: Any, **kwargs: Dict[Any, Any]) -> None:
|
265
|
+
nonlocal validated_args
|
266
|
+
nonlocal validated_kwargs
|
267
|
+
|
268
|
+
validated_args = args
|
269
|
+
validated_kwargs = kwargs
|
270
|
+
|
271
|
+
# We create a dummy function with the original function signature to run
|
272
|
+
# pydantic validation without actually running the function code
|
251
273
|
f.__signature__ = signature # type: ignore[attr-defined]
|
252
|
-
f.__annotations__ =
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
kwargs
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
274
|
+
f.__annotations__ = __func.__annotations__
|
275
|
+
|
276
|
+
validated_function = validate_call(config=__config, validate_return=False)(
|
277
|
+
f
|
278
|
+
)
|
279
|
+
|
280
|
+
# This raises a pydantic.ValidatonError in case the arguments are not valid
|
281
|
+
validated_function(*args, **kwargs)
|
282
|
+
|
283
|
+
return signature.bind(*validated_args, **validated_kwargs).arguments
|
284
|
+
|
285
|
+
|
286
|
+
def model_validator_data_handler(
|
287
|
+
raw_data: Any,
|
288
|
+
base_class: Type[BaseModel],
|
289
|
+
validation_info: ValidationInfo,
|
290
|
+
) -> Dict[str, Any]:
|
291
|
+
"""Utility function to parse raw input data of varying types to a dict.
|
292
|
+
|
293
|
+
With the change to pydantic v2, validators which operate with "before"
|
294
|
+
(or previously known as the "pre" parameter) are getting "Any" types of raw
|
295
|
+
input instead of a "Dict[str, Any]" as before. Depending on the use-case,
|
296
|
+
this can create conflicts after the migration and this function will be
|
297
|
+
used as a helper function to handle different types of raw input data.
|
298
|
+
|
299
|
+
A code snippet to showcase how the behaviour changes. The "before" validator
|
300
|
+
prints the type of the input:
|
301
|
+
|
302
|
+
class Base(BaseModel):
|
303
|
+
a: int = 3
|
304
|
+
|
305
|
+
class MyClass(Base):
|
306
|
+
@model_validator(mode="before")
|
307
|
+
@classmethod
|
308
|
+
def before_validator(cls, data: Any) -> Any:
|
309
|
+
print(type(data))
|
310
|
+
return {}
|
311
|
+
|
312
|
+
one = MyClass() # prints "<class 'dict'>"
|
313
|
+
MyClass.model_validate(one) # prints NOTHING, it is already validated
|
314
|
+
MyClass.model_validate("asdf") # prints "<class 'str'>", fails without the modified return.
|
315
|
+
MyClass.model_validate(RandomClass()) # prints "<class 'RandomClass'>", fails without the modified return.
|
316
|
+
MyClass.model_validate(Base()) # prints "<class 'Base'>", fails without the modified return.
|
317
|
+
MyClass.model_validate_json(json.dumps("aria")) # prints "<class 'str'>", fails without the modified return.
|
318
|
+
MyClass.model_validate_json(json.dumps([1])) # prints "<class 'list'>", fails without the modified return.
|
319
|
+
MyClass.model_validate_json(one.model_dump_json()) # prints "<class 'dict'>"
|
320
|
+
|
321
|
+
Args:
|
322
|
+
raw_data: The raw data passed to the validator, can be "Any" type.
|
323
|
+
base_class: The class that the validator belongs to
|
324
|
+
validation_info: Extra information about the validation process.
|
325
|
+
|
326
|
+
Raises:
|
327
|
+
TypeError: if the type of the data is not processable.
|
328
|
+
ValueError: in case of an unknown validation mode.
|
329
|
+
|
330
|
+
Returns:
|
331
|
+
A dictionary which will be passed to the eventual validator of pydantic.
|
332
|
+
"""
|
333
|
+
if validation_info.mode == "python":
|
334
|
+
# This is mode is only active if people validate objects using pythonic
|
335
|
+
# raw data such as MyClass(...) or MyClass.model_validate()
|
336
|
+
|
337
|
+
if isinstance(raw_data, dict):
|
338
|
+
# In most cases, this is the behaviour as the raw input is a dict
|
339
|
+
return raw_data
|
340
|
+
|
341
|
+
elif isinstance(raw_data, base_class):
|
342
|
+
# In some cases, we pass the same object type to the validation
|
343
|
+
# in such cases, it is critical we keep the original structure of
|
344
|
+
# fields that are already set.
|
345
|
+
return dict(raw_data)
|
346
|
+
|
347
|
+
elif issubclass(base_class, raw_data.__class__):
|
348
|
+
# There are a few occurrences where the annotation of the field is
|
349
|
+
# denoted by a subclass, and we use the instance of its super class
|
350
|
+
# as the raw input. In such cases we will use the same approach as
|
351
|
+
# before, while raising a debug message.
|
352
|
+
logger.debug(
|
353
|
+
f"During the validation of a `{base_class}` object, an instance"
|
354
|
+
f"of `{raw_data.__class__}` (super class of `{base_class}`) "
|
355
|
+
f"has been passed as raw input. This might lead to unexpected "
|
356
|
+
f"behaviour in case `{base_class}` have features which can not"
|
357
|
+
f"be extracted from an instance of a `{raw_data.__class__}`."
|
358
|
+
)
|
359
|
+
return dict(raw_data)
|
360
|
+
|
361
|
+
elif isinstance(raw_data, str):
|
362
|
+
# If the raw input is a raw string, we can try to use the `json`
|
363
|
+
# module to parse it. The resulting data needs to be a proper
|
364
|
+
# dict for us to pass it to the validation process.
|
365
|
+
try:
|
366
|
+
json_data = json.loads(raw_data)
|
367
|
+
|
368
|
+
if isinstance(json_data, dict):
|
369
|
+
return json_data
|
370
|
+
else:
|
371
|
+
raise TypeError("The resulting json data is not a dict!")
|
372
|
+
|
373
|
+
except (TypeError, JSONDecodeError) as e:
|
374
|
+
raise TypeError(
|
375
|
+
"The raw json input string can not be converted to a "
|
376
|
+
f"dict: {e}"
|
377
|
+
)
|
378
|
+
else:
|
379
|
+
raise TypeError(
|
380
|
+
"Unsupported type of raw input data for the `python` validation"
|
381
|
+
"mode of the pydantic class. Please consider changing the way "
|
382
|
+
f"you are creating using the `{base_class}` or instead use"
|
383
|
+
f"`{base_class}.model_validate_json()`."
|
384
|
+
)
|
385
|
+
|
386
|
+
elif validation_info.mode == "json":
|
387
|
+
# This is mode is only active if people validate objects using json
|
388
|
+
# input data such as MyClass.model_validate_json()
|
389
|
+
if isinstance(raw_data, dict):
|
390
|
+
return raw_data
|
391
|
+
else:
|
392
|
+
raise TypeError(
|
393
|
+
f"The resulting JSON data {raw_data} is not a dict, therefore"
|
394
|
+
f"can not be used by the validation process."
|
395
|
+
)
|
396
|
+
else:
|
397
|
+
# Unknown validation mode
|
398
|
+
raise ValueError(f"Unknown validation mode. {validation_info.mode}")
|
399
|
+
|
400
|
+
|
401
|
+
def before_validator_handler(
|
402
|
+
method: Callable[..., Any],
|
403
|
+
) -> Callable[[Any, Any, Any], Any]:
|
404
|
+
"""Decorator to handle the raw input data for pydantic model validators.
|
405
|
+
|
406
|
+
Args:
|
407
|
+
method: the class method with the actual validation logic.
|
408
|
+
|
409
|
+
Returns:
|
410
|
+
the validator method
|
411
|
+
"""
|
412
|
+
|
413
|
+
def before_validator(
|
414
|
+
cls: Type[BaseModel], data: Any, validation_info: ValidationInfo
|
415
|
+
) -> Any:
|
416
|
+
"""Wrapper method to handle the raw data.
|
417
|
+
|
418
|
+
Args:
|
419
|
+
cls: the class handler
|
420
|
+
data: the raw input data
|
421
|
+
validation_info: the context of the validation.
|
422
|
+
|
423
|
+
Returns:
|
424
|
+
the validated data
|
425
|
+
"""
|
426
|
+
data = model_validator_data_handler(
|
427
|
+
raw_data=data, base_class=cls, validation_info=validation_info
|
428
|
+
)
|
429
|
+
return method(cls=cls, data=data)
|
430
|
+
|
431
|
+
return before_validator
|
432
|
+
|
433
|
+
|
434
|
+
def has_validators(
|
435
|
+
pydantic_class: Type[BaseModel],
|
436
|
+
field_name: Optional[str] = None,
|
437
|
+
) -> bool:
|
438
|
+
"""Function to check if a Pydantic model or a pydantic field has validators.
|
439
|
+
|
440
|
+
Args:
|
441
|
+
pydantic_class: The class defining the pydantic model.
|
442
|
+
field_name: Optional, field info. If specified, this function will focus
|
443
|
+
on a singular field within the class. If not specified, it will
|
444
|
+
check model validators.
|
445
|
+
|
446
|
+
Returns:
|
447
|
+
Whether the specified field or class has a validator or not.
|
448
|
+
"""
|
449
|
+
# If field is not specified check model validators
|
450
|
+
if field_name is None:
|
451
|
+
if pydantic_class.__pydantic_decorators__.model_validators:
|
452
|
+
return True
|
453
|
+
|
454
|
+
# Else, check field validators
|
455
|
+
else:
|
456
|
+
# 1. Field validators can be defined through @field_validator decorators
|
457
|
+
f_validators = pydantic_class.__pydantic_decorators__.field_validators
|
458
|
+
|
459
|
+
for name, f_v in f_validators.items():
|
460
|
+
if field_name in f_v.info.fields:
|
461
|
+
return True
|
462
|
+
|
463
|
+
# 2. Field validators can be defined through the Annotation[.....]
|
464
|
+
field_info = pydantic_class.model_fields[field_name]
|
465
|
+
if metadata := field_info.metadata:
|
466
|
+
if any(
|
467
|
+
isinstance(
|
468
|
+
m,
|
469
|
+
(
|
470
|
+
AfterValidator,
|
471
|
+
BeforeValidator,
|
472
|
+
PlainValidator,
|
473
|
+
WrapValidator,
|
474
|
+
),
|
475
|
+
)
|
476
|
+
for m in metadata
|
477
|
+
):
|
478
|
+
return True
|
479
|
+
|
480
|
+
return False
|
zenml/utils/secret_utils.py
CHANGED
@@ -16,16 +16,29 @@
|
|
16
16
|
import re
|
17
17
|
from typing import TYPE_CHECKING, Any, NamedTuple
|
18
18
|
|
19
|
-
from pydantic import Field
|
19
|
+
from pydantic import Field, PlainSerializer, SecretStr
|
20
|
+
from typing_extensions import Annotated
|
21
|
+
|
22
|
+
from zenml.logger import get_logger
|
20
23
|
|
21
24
|
if TYPE_CHECKING:
|
22
|
-
from pydantic.fields import
|
25
|
+
from pydantic.fields import FieldInfo
|
23
26
|
|
24
27
|
_secret_reference_expression = re.compile(r"\{\{\s*\S+?\.\S+\s*\}\}")
|
25
28
|
|
26
29
|
PYDANTIC_SENSITIVE_FIELD_MARKER = "sensitive"
|
27
30
|
PYDANTIC_CLEAR_TEXT_FIELD_MARKER = "prevent_secret_reference"
|
28
31
|
|
32
|
+
PlainSerializedSecretStr = Annotated[
|
33
|
+
SecretStr,
|
34
|
+
PlainSerializer(
|
35
|
+
lambda v: v.get_secret_value() if v is not None else None,
|
36
|
+
when_used="json",
|
37
|
+
),
|
38
|
+
]
|
39
|
+
|
40
|
+
logger = get_logger(__name__)
|
41
|
+
|
29
42
|
|
30
43
|
def is_secret_reference(value: Any) -> bool:
|
31
44
|
"""Checks whether any value is a secret reference.
|
@@ -87,8 +100,9 @@ def SecretField(*args: Any, **kwargs: Any) -> Any:
|
|
87
100
|
Returns:
|
88
101
|
Pydantic field info.
|
89
102
|
"""
|
90
|
-
|
91
|
-
|
103
|
+
json_schema_extra = kwargs.get("json_schema_extra", {})
|
104
|
+
json_schema_extra.update({PYDANTIC_SENSITIVE_FIELD_MARKER: True})
|
105
|
+
return Field(json_schema_extra=json_schema_extra, *args, **kwargs) # type: ignore[pydantic-field]
|
92
106
|
|
93
107
|
|
94
108
|
def ClearTextField(*args: Any, **kwargs: Any) -> Any:
|
@@ -103,11 +117,12 @@ def ClearTextField(*args: Any, **kwargs: Any) -> Any:
|
|
103
117
|
Returns:
|
104
118
|
Pydantic field info.
|
105
119
|
"""
|
106
|
-
|
107
|
-
|
120
|
+
json_schema_extra = kwargs.get("json_schema_extra", {})
|
121
|
+
json_schema_extra.update({PYDANTIC_CLEAR_TEXT_FIELD_MARKER: True})
|
122
|
+
return Field(json_schema_extra=json_schema_extra, *args, **kwargs) # type: ignore[pydantic-field]
|
108
123
|
|
109
124
|
|
110
|
-
def is_secret_field(field: "
|
125
|
+
def is_secret_field(field: "FieldInfo") -> bool:
|
111
126
|
"""Returns whether a pydantic field contains sensitive information or not.
|
112
127
|
|
113
128
|
Args:
|
@@ -116,10 +131,29 @@ def is_secret_field(field: "ModelField") -> bool:
|
|
116
131
|
Returns:
|
117
132
|
`True` if the field contains sensitive information, `False` otherwise.
|
118
133
|
"""
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
134
|
+
if field.json_schema_extra is not None:
|
135
|
+
if isinstance(field.json_schema_extra, dict):
|
136
|
+
if marker := field.json_schema_extra.get(
|
137
|
+
PYDANTIC_SENSITIVE_FIELD_MARKER
|
138
|
+
):
|
139
|
+
assert isinstance(marker, bool), (
|
140
|
+
f"The parameter `{PYDANTIC_SENSITIVE_FIELD_MARKER}` in the "
|
141
|
+
f"field definition can only be a boolean value."
|
142
|
+
)
|
143
|
+
return marker
|
144
|
+
|
145
|
+
else:
|
146
|
+
logger.warning(
|
147
|
+
f"The 'json_schema_extra' of the field '{field.title}' is "
|
148
|
+
"not defined as a dict. This might lead to unexpected "
|
149
|
+
"behaviour as we are checking it is a secret text field. "
|
150
|
+
"Returning 'False' as default..."
|
151
|
+
)
|
152
|
+
|
153
|
+
return False
|
154
|
+
|
155
|
+
|
156
|
+
def is_clear_text_field(field: "FieldInfo") -> bool:
|
123
157
|
"""Returns whether a pydantic field prevents secret references or not.
|
124
158
|
|
125
159
|
Args:
|
@@ -128,4 +162,23 @@ def is_clear_text_field(field: "ModelField") -> bool:
|
|
128
162
|
Returns:
|
129
163
|
`True` if the field prevents secret references, `False` otherwise.
|
130
164
|
"""
|
131
|
-
|
165
|
+
if field.json_schema_extra is not None:
|
166
|
+
if isinstance(field.json_schema_extra, dict):
|
167
|
+
if marker := field.json_schema_extra.get(
|
168
|
+
PYDANTIC_CLEAR_TEXT_FIELD_MARKER
|
169
|
+
):
|
170
|
+
assert isinstance(marker, bool), (
|
171
|
+
f"The parameter `{PYDANTIC_CLEAR_TEXT_FIELD_MARKER}` in the "
|
172
|
+
f"field definition can only be a boolean value."
|
173
|
+
)
|
174
|
+
return marker
|
175
|
+
|
176
|
+
else:
|
177
|
+
logger.warning(
|
178
|
+
f"The 'json_schema_extra' of the field '{field.title}' is "
|
179
|
+
"not defined as a dict. This might lead to unexpected "
|
180
|
+
"behaviour as we are checking it is a clear text field. "
|
181
|
+
"Returning 'False' as default..."
|
182
|
+
)
|
183
|
+
|
184
|
+
return False
|
zenml/utils/source_utils.py
CHANGED
@@ -83,11 +83,11 @@ def load(source: Union[Source, str]) -> Any:
|
|
83
83
|
|
84
84
|
import_root = None
|
85
85
|
if source.type == SourceType.CODE_REPOSITORY:
|
86
|
-
source = CodeRepositorySource.
|
86
|
+
source = CodeRepositorySource.model_validate(dict(source))
|
87
87
|
_warn_about_potential_source_loading_issues(source=source)
|
88
88
|
import_root = get_source_root()
|
89
89
|
elif source.type == SourceType.DISTRIBUTION_PACKAGE:
|
90
|
-
source = DistributionPackageSource.
|
90
|
+
source = DistributionPackageSource.model_validate(dict(source))
|
91
91
|
if source.version:
|
92
92
|
current_package_version = _get_package_version(
|
93
93
|
package_name=source.package_name
|
zenml/utils/typed_model.py
CHANGED
@@ -17,7 +17,9 @@ import json
|
|
17
17
|
from typing import Any, Dict, Tuple, Type, cast
|
18
18
|
|
19
19
|
from pydantic import BaseModel, Field
|
20
|
-
|
20
|
+
|
21
|
+
# TODO: Investigate if we can solve this import a different way.
|
22
|
+
from pydantic._internal._model_construction import ModelMetaclass
|
21
23
|
from typing_extensions import Literal
|
22
24
|
|
23
25
|
from zenml.utils import source_utils
|
@@ -85,7 +87,7 @@ class BaseTypedModel(BaseModel, metaclass=BaseTypedModelMeta):
|
|
85
87
|
|
86
88
|
matrix = TheMatrix(choice=RedPill())
|
87
89
|
d = matrix.dict()
|
88
|
-
new_matrix = TheMatrix.
|
90
|
+
new_matrix = TheMatrix.model_validate(d)
|
89
91
|
assert isinstance(new_matrix.choice, RedPill)
|
90
92
|
```
|
91
93
|
|
@@ -126,7 +128,7 @@ class BaseTypedModel(BaseModel, metaclass=BaseTypedModelMeta):
|
|
126
128
|
f"Class `{cls}` is not a ZenML BaseTypedModel subclass."
|
127
129
|
)
|
128
130
|
|
129
|
-
return cls.
|
131
|
+
return cls.model_validate(model_dict)
|
130
132
|
|
131
133
|
@classmethod
|
132
134
|
def from_json(
|