zenml-nightly 0.58.2.dev20240614__py3-none-any.whl → 0.58.2.dev20240622__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 (314) 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/base.py +2 -2
  13. zenml/cli/served_model.py +0 -1
  14. zenml/cli/server.py +3 -3
  15. zenml/cli/utils.py +36 -40
  16. zenml/cli/web_login.py +2 -2
  17. zenml/client.py +198 -24
  18. zenml/client_lazy_loader.py +20 -14
  19. zenml/config/base_settings.py +5 -6
  20. zenml/config/build_configuration.py +1 -1
  21. zenml/config/compiler.py +3 -3
  22. zenml/config/docker_settings.py +27 -28
  23. zenml/config/global_config.py +33 -37
  24. zenml/config/pipeline_configurations.py +8 -11
  25. zenml/config/pipeline_run_configuration.py +6 -2
  26. zenml/config/pipeline_spec.py +3 -4
  27. zenml/config/resource_settings.py +8 -9
  28. zenml/config/schedule.py +16 -20
  29. zenml/config/secret_reference_mixin.py +6 -3
  30. zenml/config/secrets_store_config.py +16 -23
  31. zenml/config/server_config.py +50 -46
  32. zenml/config/settings_resolver.py +1 -1
  33. zenml/config/source.py +45 -35
  34. zenml/config/step_configurations.py +53 -31
  35. zenml/config/step_run_info.py +3 -0
  36. zenml/config/store_config.py +20 -19
  37. zenml/config/strict_base_model.py +2 -6
  38. zenml/constants.py +26 -2
  39. zenml/container_registries/base_container_registry.py +3 -2
  40. zenml/container_registries/default_container_registry.py +3 -3
  41. zenml/event_hub/base_event_hub.py +1 -1
  42. zenml/event_sources/base_event_source.py +11 -16
  43. zenml/exceptions.py +4 -0
  44. zenml/integrations/airflow/__init__.py +2 -6
  45. zenml/integrations/airflow/flavors/airflow_orchestrator_flavor.py +6 -7
  46. zenml/integrations/airflow/orchestrators/airflow_orchestrator.py +13 -249
  47. zenml/integrations/airflow/orchestrators/dag_generator.py +5 -3
  48. zenml/integrations/argilla/flavors/argilla_annotator_flavor.py +5 -4
  49. zenml/integrations/aws/__init__.py +1 -1
  50. zenml/integrations/aws/flavors/aws_container_registry_flavor.py +3 -2
  51. zenml/integrations/aws/flavors/sagemaker_orchestrator_flavor.py +11 -5
  52. zenml/integrations/aws/flavors/sagemaker_step_operator_flavor.py +6 -2
  53. zenml/integrations/aws/service_connectors/aws_service_connector.py +5 -4
  54. zenml/integrations/aws/step_operators/sagemaker_step_operator.py +1 -1
  55. zenml/integrations/azure/flavors/azureml_step_operator_flavor.py +4 -4
  56. zenml/integrations/azure/service_connectors/azure_service_connector.py +4 -3
  57. zenml/integrations/azure/step_operators/azureml_step_operator.py +2 -1
  58. zenml/integrations/bentoml/steps/bentoml_deployer.py +1 -1
  59. zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +8 -12
  60. zenml/integrations/comet/flavors/comet_experiment_tracker_flavor.py +1 -1
  61. zenml/integrations/constants.py +0 -1
  62. zenml/integrations/deepchecks/__init__.py +1 -0
  63. zenml/integrations/evidently/__init__.py +5 -3
  64. zenml/integrations/evidently/column_mapping.py +11 -3
  65. zenml/integrations/evidently/data_validators/evidently_data_validator.py +21 -3
  66. zenml/integrations/evidently/metrics.py +5 -6
  67. zenml/integrations/evidently/tests.py +5 -6
  68. zenml/integrations/facets/models.py +2 -6
  69. zenml/integrations/feast/__init__.py +3 -1
  70. zenml/integrations/feast/feature_stores/feast_feature_store.py +0 -23
  71. zenml/integrations/gcp/__init__.py +1 -1
  72. zenml/integrations/gcp/flavors/vertex_orchestrator_flavor.py +1 -1
  73. zenml/integrations/gcp/flavors/vertex_step_operator_flavor.py +1 -1
  74. zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +234 -103
  75. zenml/integrations/gcp/service_connectors/gcp_service_connector.py +57 -42
  76. zenml/integrations/gcp/step_operators/vertex_step_operator.py +1 -0
  77. zenml/integrations/github/code_repositories/github_code_repository.py +1 -1
  78. zenml/integrations/github/plugins/event_sources/github_webhook_event_source.py +9 -13
  79. zenml/integrations/great_expectations/__init__.py +1 -1
  80. zenml/integrations/great_expectations/data_validators/ge_data_validator.py +44 -44
  81. zenml/integrations/great_expectations/flavors/great_expectations_data_validator_flavor.py +35 -2
  82. zenml/integrations/great_expectations/ge_store_backend.py +24 -11
  83. zenml/integrations/great_expectations/materializers/ge_materializer.py +3 -3
  84. zenml/integrations/great_expectations/utils.py +5 -5
  85. zenml/integrations/huggingface/__init__.py +3 -0
  86. zenml/integrations/huggingface/flavors/huggingface_model_deployer_flavor.py +1 -1
  87. zenml/integrations/huggingface/steps/__init__.py +3 -0
  88. zenml/integrations/huggingface/steps/accelerate_runner.py +149 -0
  89. zenml/integrations/huggingface/steps/huggingface_deployer.py +2 -2
  90. zenml/integrations/hyperai/flavors/hyperai_orchestrator_flavor.py +1 -1
  91. zenml/integrations/hyperai/service_connectors/hyperai_service_connector.py +4 -3
  92. zenml/integrations/kubeflow/__init__.py +1 -1
  93. zenml/integrations/kubeflow/flavors/kubeflow_orchestrator_flavor.py +48 -81
  94. zenml/integrations/kubeflow/orchestrators/kubeflow_orchestrator.py +295 -245
  95. zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py +1 -1
  96. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py +11 -2
  97. zenml/integrations/kubernetes/pod_settings.py +17 -31
  98. zenml/integrations/kubernetes/service_connectors/kubernetes_service_connector.py +8 -7
  99. zenml/integrations/label_studio/__init__.py +1 -3
  100. zenml/integrations/label_studio/annotators/label_studio_annotator.py +3 -4
  101. zenml/integrations/label_studio/flavors/label_studio_annotator_flavor.py +2 -2
  102. zenml/integrations/langchain/__init__.py +5 -1
  103. zenml/integrations/langchain/materializers/document_materializer.py +44 -8
  104. zenml/integrations/mlflow/__init__.py +9 -3
  105. zenml/integrations/mlflow/experiment_trackers/mlflow_experiment_tracker.py +1 -1
  106. zenml/integrations/mlflow/flavors/mlflow_experiment_tracker_flavor.py +29 -37
  107. zenml/integrations/mlflow/model_registries/mlflow_model_registry.py +4 -4
  108. zenml/integrations/mlflow/steps/mlflow_deployer.py +1 -1
  109. zenml/integrations/neptune/flavors/neptune_experiment_tracker_flavor.py +1 -1
  110. zenml/integrations/neural_prophet/__init__.py +5 -1
  111. zenml/integrations/pigeon/flavors/pigeon_annotator_flavor.py +1 -1
  112. zenml/integrations/s3/flavors/s3_artifact_store_flavor.py +9 -8
  113. zenml/integrations/seldon/seldon_client.py +52 -67
  114. zenml/integrations/seldon/services/seldon_deployment.py +3 -3
  115. zenml/integrations/seldon/steps/seldon_deployer.py +4 -4
  116. zenml/integrations/skypilot/flavors/skypilot_orchestrator_base_vm_config.py +15 -5
  117. zenml/integrations/skypilot_aws/__init__.py +1 -1
  118. zenml/integrations/skypilot_aws/flavors/skypilot_orchestrator_aws_vm_flavor.py +1 -1
  119. zenml/integrations/skypilot_azure/__init__.py +1 -1
  120. zenml/integrations/skypilot_azure/flavors/skypilot_orchestrator_azure_vm_flavor.py +1 -1
  121. zenml/integrations/skypilot_gcp/__init__.py +2 -1
  122. zenml/integrations/skypilot_gcp/flavors/skypilot_orchestrator_gcp_vm_flavor.py +1 -1
  123. zenml/integrations/skypilot_lambda/flavors/skypilot_orchestrator_lambda_vm_flavor.py +2 -2
  124. zenml/integrations/spark/flavors/spark_step_operator_flavor.py +1 -1
  125. zenml/integrations/spark/step_operators/spark_step_operator.py +2 -0
  126. zenml/integrations/tekton/__init__.py +1 -1
  127. zenml/integrations/tekton/flavors/tekton_orchestrator_flavor.py +66 -23
  128. zenml/integrations/tekton/orchestrators/tekton_orchestrator.py +547 -233
  129. zenml/integrations/tensorboard/__init__.py +1 -12
  130. zenml/integrations/tensorboard/services/tensorboard_service.py +3 -5
  131. zenml/integrations/tensorboard/visualizers/tensorboard_visualizer.py +6 -6
  132. zenml/integrations/tensorflow/__init__.py +2 -10
  133. zenml/integrations/tensorflow/materializers/keras_materializer.py +17 -9
  134. zenml/integrations/wandb/flavors/wandb_experiment_tracker_flavor.py +9 -14
  135. zenml/integrations/whylogs/flavors/whylogs_data_validator_flavor.py +1 -1
  136. zenml/lineage_graph/lineage_graph.py +1 -1
  137. zenml/logging/step_logging.py +15 -7
  138. zenml/materializers/built_in_materializer.py +3 -3
  139. zenml/materializers/pydantic_materializer.py +2 -2
  140. zenml/metadata/lazy_load.py +4 -4
  141. zenml/metadata/metadata_types.py +64 -4
  142. zenml/model/model.py +79 -54
  143. zenml/model_deployers/base_model_deployer.py +14 -12
  144. zenml/model_registries/base_model_registry.py +17 -15
  145. zenml/models/__init__.py +79 -206
  146. zenml/models/v2/base/base.py +54 -41
  147. zenml/models/v2/base/base_plugin_flavor.py +2 -6
  148. zenml/models/v2/base/filter.py +91 -76
  149. zenml/models/v2/base/page.py +2 -12
  150. zenml/models/v2/base/scoped.py +4 -7
  151. zenml/models/v2/core/api_key.py +22 -8
  152. zenml/models/v2/core/artifact.py +2 -2
  153. zenml/models/v2/core/artifact_version.py +74 -40
  154. zenml/models/v2/core/code_repository.py +37 -10
  155. zenml/models/v2/core/component.py +65 -16
  156. zenml/models/v2/core/device.py +14 -4
  157. zenml/models/v2/core/event_source.py +1 -2
  158. zenml/models/v2/core/flavor.py +74 -8
  159. zenml/models/v2/core/logs.py +68 -8
  160. zenml/models/v2/core/model.py +8 -4
  161. zenml/models/v2/core/model_version.py +25 -6
  162. zenml/models/v2/core/model_version_artifact.py +51 -21
  163. zenml/models/v2/core/model_version_pipeline_run.py +45 -13
  164. zenml/models/v2/core/pipeline.py +37 -72
  165. zenml/models/v2/core/pipeline_build.py +29 -17
  166. zenml/models/v2/core/pipeline_deployment.py +18 -6
  167. zenml/models/v2/core/pipeline_namespace.py +113 -0
  168. zenml/models/v2/core/pipeline_run.py +50 -22
  169. zenml/models/v2/core/run_metadata.py +59 -36
  170. zenml/models/v2/core/schedule.py +37 -24
  171. zenml/models/v2/core/secret.py +31 -12
  172. zenml/models/v2/core/service.py +64 -36
  173. zenml/models/v2/core/service_account.py +24 -11
  174. zenml/models/v2/core/service_connector.py +219 -44
  175. zenml/models/v2/core/stack.py +45 -17
  176. zenml/models/v2/core/step_run.py +28 -8
  177. zenml/models/v2/core/tag.py +8 -4
  178. zenml/models/v2/core/trigger.py +2 -2
  179. zenml/models/v2/core/trigger_execution.py +1 -0
  180. zenml/models/v2/core/user.py +18 -21
  181. zenml/models/v2/core/workspace.py +13 -3
  182. zenml/models/v2/misc/build_item.py +3 -3
  183. zenml/models/v2/misc/external_user.py +2 -6
  184. zenml/models/v2/misc/hub_plugin_models.py +9 -9
  185. zenml/models/v2/misc/loaded_visualization.py +2 -2
  186. zenml/models/v2/misc/service_connector_type.py +8 -17
  187. zenml/models/v2/misc/user_auth.py +7 -2
  188. zenml/new/pipelines/build_utils.py +3 -3
  189. zenml/new/pipelines/pipeline.py +17 -13
  190. zenml/new/pipelines/run_utils.py +103 -1
  191. zenml/orchestrators/base_orchestrator.py +10 -7
  192. zenml/orchestrators/local_docker/local_docker_orchestrator.py +1 -1
  193. zenml/orchestrators/step_launcher.py +28 -4
  194. zenml/orchestrators/step_runner.py +3 -6
  195. zenml/orchestrators/utils.py +1 -1
  196. zenml/plugins/base_plugin_flavor.py +6 -10
  197. zenml/plugins/plugin_flavor_registry.py +3 -7
  198. zenml/secret/base_secret.py +7 -8
  199. zenml/service_connectors/docker_service_connector.py +4 -3
  200. zenml/service_connectors/service_connector.py +5 -12
  201. zenml/service_connectors/service_connector_registry.py +2 -4
  202. zenml/services/container/container_service.py +1 -1
  203. zenml/services/container/container_service_endpoint.py +1 -1
  204. zenml/services/local/local_service.py +1 -1
  205. zenml/services/local/local_service_endpoint.py +1 -1
  206. zenml/services/service.py +16 -10
  207. zenml/services/service_type.py +4 -5
  208. zenml/services/terraform/terraform_service.py +1 -1
  209. zenml/stack/flavor.py +2 -6
  210. zenml/stack/flavor_registry.py +4 -4
  211. zenml/stack/stack.py +4 -1
  212. zenml/stack/stack_component.py +55 -31
  213. zenml/step_operators/step_operator_entrypoint_configuration.py +1 -0
  214. zenml/steps/base_step.py +34 -28
  215. zenml/steps/entrypoint_function_utils.py +3 -5
  216. zenml/steps/utils.py +12 -14
  217. zenml/utils/cuda_utils.py +50 -0
  218. zenml/utils/deprecation_utils.py +18 -20
  219. zenml/utils/dict_utils.py +1 -1
  220. zenml/utils/filesync_model.py +65 -28
  221. zenml/utils/function_utils.py +260 -0
  222. zenml/utils/json_utils.py +131 -0
  223. zenml/utils/mlstacks_utils.py +2 -2
  224. zenml/utils/package_utils.py +1 -1
  225. zenml/utils/pipeline_docker_image_builder.py +9 -0
  226. zenml/utils/pydantic_utils.py +270 -62
  227. zenml/utils/secret_utils.py +65 -12
  228. zenml/utils/source_utils.py +2 -2
  229. zenml/utils/typed_model.py +5 -3
  230. zenml/utils/typing_utils.py +243 -0
  231. zenml/utils/yaml_utils.py +1 -1
  232. zenml/zen_server/auth.py +2 -2
  233. zenml/zen_server/cloud_utils.py +6 -6
  234. zenml/zen_server/deploy/base_provider.py +1 -1
  235. zenml/zen_server/deploy/deployment.py +6 -8
  236. zenml/zen_server/deploy/docker/docker_zen_server.py +3 -4
  237. zenml/zen_server/deploy/local/local_provider.py +0 -1
  238. zenml/zen_server/deploy/local/local_zen_server.py +6 -6
  239. zenml/zen_server/deploy/terraform/terraform_zen_server.py +4 -6
  240. zenml/zen_server/exceptions.py +4 -1
  241. zenml/zen_server/feature_gate/zenml_cloud_feature_gate.py +1 -1
  242. zenml/zen_server/pipeline_deployment/utils.py +48 -68
  243. zenml/zen_server/rbac/models.py +2 -5
  244. zenml/zen_server/rbac/utils.py +11 -14
  245. zenml/zen_server/routers/auth_endpoints.py +2 -2
  246. zenml/zen_server/routers/pipeline_builds_endpoints.py +1 -1
  247. zenml/zen_server/routers/runs_endpoints.py +1 -1
  248. zenml/zen_server/routers/secrets_endpoints.py +3 -2
  249. zenml/zen_server/routers/server_endpoints.py +1 -1
  250. zenml/zen_server/routers/steps_endpoints.py +1 -1
  251. zenml/zen_server/routers/workspaces_endpoints.py +1 -1
  252. zenml/zen_stores/base_zen_store.py +46 -9
  253. zenml/zen_stores/migrations/utils.py +42 -46
  254. zenml/zen_stores/migrations/versions/0701da9951a0_added_service_table.py +1 -1
  255. zenml/zen_stores/migrations/versions/1041bc644e0d_remove_secrets_manager.py +5 -3
  256. zenml/zen_stores/migrations/versions/10a907dad202_delete_mlmd_tables.py +1 -1
  257. zenml/zen_stores/migrations/versions/26b776ad583e_redesign_artifacts.py +8 -10
  258. zenml/zen_stores/migrations/versions/37835ce041d2_optimizing_database.py +3 -3
  259. zenml/zen_stores/migrations/versions/46506f72f0ed_add_server_settings.py +10 -12
  260. zenml/zen_stores/migrations/versions/5994f9ad0489_introduce_role_permissions.py +3 -2
  261. zenml/zen_stores/migrations/versions/6917bce75069_add_pipeline_run_unique_constraint.py +4 -4
  262. zenml/zen_stores/migrations/versions/728c6369cfaa_add_name_column_to_input_artifact_pk.py +3 -2
  263. zenml/zen_stores/migrations/versions/743ec82b1b3c_update_size_of_build_images.py +2 -2
  264. zenml/zen_stores/migrations/versions/7500f434b71c_remove_shared_columns.py +3 -2
  265. zenml/zen_stores/migrations/versions/7834208cc3f6_artifact_project_scoping.py +8 -7
  266. zenml/zen_stores/migrations/versions/7b651bf6822e_track_secrets_in_db.py +6 -4
  267. zenml/zen_stores/migrations/versions/7e4a481d17f7_add_identity_table.py +2 -2
  268. zenml/zen_stores/migrations/versions/7f603e583dd7_fixed_migration.py +1 -1
  269. zenml/zen_stores/migrations/versions/a39c4184c8ce_remove_secrets_manager_flavors.py +2 -2
  270. zenml/zen_stores/migrations/versions/a91762e6be36_artifact_version_table.py +4 -4
  271. zenml/zen_stores/migrations/versions/alembic_start.py +1 -1
  272. zenml/zen_stores/migrations/versions/fbd7f18ced1e_increase_step_run_field_lengths.py +4 -4
  273. zenml/zen_stores/rest_zen_store.py +109 -49
  274. zenml/zen_stores/schemas/api_key_schemas.py +1 -1
  275. zenml/zen_stores/schemas/artifact_schemas.py +8 -8
  276. zenml/zen_stores/schemas/artifact_visualization_schemas.py +3 -3
  277. zenml/zen_stores/schemas/code_repository_schemas.py +1 -1
  278. zenml/zen_stores/schemas/component_schemas.py +8 -3
  279. zenml/zen_stores/schemas/device_schemas.py +8 -6
  280. zenml/zen_stores/schemas/event_source_schemas.py +3 -4
  281. zenml/zen_stores/schemas/flavor_schemas.py +5 -3
  282. zenml/zen_stores/schemas/model_schemas.py +26 -1
  283. zenml/zen_stores/schemas/pipeline_build_schemas.py +1 -1
  284. zenml/zen_stores/schemas/pipeline_deployment_schemas.py +4 -4
  285. zenml/zen_stores/schemas/pipeline_run_schemas.py +6 -6
  286. zenml/zen_stores/schemas/pipeline_schemas.py +5 -2
  287. zenml/zen_stores/schemas/run_metadata_schemas.py +2 -2
  288. zenml/zen_stores/schemas/secret_schemas.py +8 -5
  289. zenml/zen_stores/schemas/server_settings_schemas.py +3 -1
  290. zenml/zen_stores/schemas/service_connector_schemas.py +1 -1
  291. zenml/zen_stores/schemas/service_schemas.py +11 -2
  292. zenml/zen_stores/schemas/stack_schemas.py +1 -1
  293. zenml/zen_stores/schemas/step_run_schemas.py +11 -11
  294. zenml/zen_stores/schemas/tag_schemas.py +6 -2
  295. zenml/zen_stores/schemas/trigger_schemas.py +2 -2
  296. zenml/zen_stores/schemas/user_schemas.py +2 -2
  297. zenml/zen_stores/schemas/workspace_schemas.py +3 -1
  298. zenml/zen_stores/secrets_stores/aws_secrets_store.py +19 -20
  299. zenml/zen_stores/secrets_stores/azure_secrets_store.py +17 -20
  300. zenml/zen_stores/secrets_stores/base_secrets_store.py +79 -12
  301. zenml/zen_stores/secrets_stores/gcp_secrets_store.py +17 -20
  302. zenml/zen_stores/secrets_stores/hashicorp_secrets_store.py +4 -8
  303. zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +10 -7
  304. zenml/zen_stores/secrets_stores/sql_secrets_store.py +5 -6
  305. zenml/zen_stores/sql_zen_store.py +196 -120
  306. zenml/zen_stores/zen_store_interface.py +33 -0
  307. {zenml_nightly-0.58.2.dev20240614.dist-info → zenml_nightly-0.58.2.dev20240622.dist-info}/METADATA +9 -7
  308. {zenml_nightly-0.58.2.dev20240614.dist-info → zenml_nightly-0.58.2.dev20240622.dist-info}/RECORD +311 -308
  309. zenml/integrations/kubeflow/utils.py +0 -95
  310. zenml/models/v2/base/internal.py +0 -37
  311. zenml/models/v2/base/update.py +0 -44
  312. {zenml_nightly-0.58.2.dev20240614.dist-info → zenml_nightly-0.58.2.dev20240622.dist-info}/LICENSE +0 -0
  313. {zenml_nightly-0.58.2.dev20240614.dist-info → zenml_nightly-0.58.2.dev20240622.dist-info}/WHEEL +0 -0
  314. {zenml_nightly-0.58.2.dev20240614.dist-info → zenml_nightly-0.58.2.dev20240622.dist-info}/entry_points.txt +0 -0
@@ -16,11 +16,13 @@
16
16
  from enum import Enum
17
17
  from typing import Any, Dict, List, Optional, Union
18
18
 
19
- from pydantic import Extra, root_validator
19
+ from pydantic import Field, model_validator
20
+ from pydantic_settings import SettingsConfigDict
20
21
 
21
22
  from zenml.config.base_settings import BaseSettings
22
23
  from zenml.logger import get_logger
23
24
  from zenml.utils import deprecation_utils
25
+ from zenml.utils.pydantic_utils import before_validator_handler
24
26
 
25
27
  logger = get_logger(__name__)
26
28
 
@@ -70,7 +72,7 @@ class DockerSettings(BaseSettings):
70
72
  --------------
71
73
  * No `dockerfile` specified: If any of the options regarding
72
74
  requirements, environment variables or copying files require us to build an
73
- image, ZenML will build this image. Otherwise the `parent_image` will be
75
+ image, ZenML will build this image. Otherwise, the `parent_image` will be
74
76
  used to run the pipeline.
75
77
  * `dockerfile` specified: ZenML will first build an image based on the
76
78
  specified Dockerfile. If any of the options regarding
@@ -190,8 +192,10 @@ class DockerSettings(BaseSettings):
190
192
  python_package_installer_args: Dict[str, Any] = {}
191
193
  replicate_local_python_environment: Optional[
192
194
  Union[List[str], PythonEnvironmentExportMethod]
193
- ] = None
194
- requirements: Union[None, str, List[str]] = None
195
+ ] = Field(default=None, union_mode="left_to_right")
196
+ requirements: Union[None, str, List[str]] = Field(
197
+ default=None, union_mode="left_to_right"
198
+ )
195
199
  required_integrations: List[str] = []
196
200
  required_hub_plugins: List[str] = []
197
201
  install_stack_requirements: bool = True
@@ -208,41 +212,40 @@ class DockerSettings(BaseSettings):
208
212
  "copy_files", "copy_global_config"
209
213
  )
210
214
 
211
- @root_validator(pre=True)
212
- def _migrate_copy_files(cls, values: Dict[str, Any]) -> Dict[str, Any]:
215
+ @model_validator(mode="before")
216
+ @classmethod
217
+ @before_validator_handler
218
+ def _migrate_copy_files(cls, data: Dict[str, Any]) -> Dict[str, Any]:
213
219
  """Migrates the value from the old copy_files attribute.
214
220
 
215
221
  Args:
216
- values: The settings values.
222
+ data: The settings values.
217
223
 
218
224
  Returns:
219
225
  The migrated settings values.
220
226
  """
221
- copy_files = values.get("copy_files", None)
227
+ copy_files = data.get("copy_files", None)
222
228
 
223
229
  if copy_files is None:
224
- return values
230
+ return data
225
231
 
226
- if values.get("source_files", None):
232
+ if data.get("source_files", None):
227
233
  # Ignore the copy files value in favor of the new source files
228
234
  logger.warning(
229
235
  "Both `copy_files` and `source_files` specified for the "
230
236
  "DockerSettings, ignoring the `copy_files` value."
231
237
  )
232
238
  elif copy_files is True:
233
- values["source_files"] = SourceFileMode.INCLUDE
239
+ data["source_files"] = SourceFileMode.INCLUDE
234
240
  elif copy_files is False:
235
- values["source_files"] = SourceFileMode.IGNORE
241
+ data["source_files"] = SourceFileMode.IGNORE
236
242
 
237
- return values
243
+ return data
238
244
 
239
- @root_validator
240
- def _validate_skip_build(cls, values: Dict[str, Any]) -> Dict[str, Any]:
245
+ @model_validator(mode="after")
246
+ def _validate_skip_build(self) -> "DockerSettings":
241
247
  """Ensures that a parent image is passed when trying to skip the build.
242
248
 
243
- Args:
244
- values: The settings values.
245
-
246
249
  Returns:
247
250
  The validated settings values.
248
251
 
@@ -250,10 +253,7 @@ class DockerSettings(BaseSettings):
250
253
  ValueError: If the build should be skipped but no parent image
251
254
  was specified.
252
255
  """
253
- skip_build = values.get("skip_build", False)
254
- parent_image = values.get("parent_image")
255
-
256
- if skip_build and not parent_image:
256
+ if self.skip_build and not self.parent_image:
257
257
  raise ValueError(
258
258
  "Docker settings that specify `skip_build=True` must always "
259
259
  "contain a `parent_image`. This parent image will be used "
@@ -261,12 +261,11 @@ class DockerSettings(BaseSettings):
261
261
  "Docker builds on top of it."
262
262
  )
263
263
 
264
- return values
265
-
266
- class Config:
267
- """Pydantic configuration class."""
264
+ return self
268
265
 
266
+ model_config = SettingsConfigDict(
269
267
  # public attributes are immutable
270
- allow_mutation = False
268
+ frozen=True,
271
269
  # prevent extra attributes during model initialization
272
- extra = Extra.forbid
270
+ extra="forbid",
271
+ )
@@ -13,7 +13,6 @@
13
13
  # permissions and limitations under the License.
14
14
  """Functionality to support ZenML GlobalConfiguration."""
15
15
 
16
- import json
17
16
  import os
18
17
  import uuid
19
18
  from pathlib import Path
@@ -21,8 +20,15 @@ from typing import TYPE_CHECKING, Any, Dict, Optional, cast
21
20
  from uuid import UUID
22
21
 
23
22
  from packaging import version
24
- from pydantic import BaseModel, Field, SecretStr, ValidationError, validator
25
- from pydantic.main import ModelMetaclass
23
+ from pydantic import (
24
+ BaseModel,
25
+ ConfigDict,
26
+ Field,
27
+ SerializeAsAny,
28
+ ValidationError,
29
+ field_validator,
30
+ )
31
+ from pydantic._internal._model_construction import ModelMetaclass
26
32
 
27
33
  from zenml import __version__
28
34
  from zenml.config.secrets_store_config import SecretsStoreConfiguration
@@ -108,17 +114,16 @@ class GlobalConfiguration(BaseModel, metaclass=GlobalConfigMetaClass):
108
114
  store: Store configuration.
109
115
  active_stack_id: The ID of the active stack.
110
116
  active_workspace_name: The name of the active workspace.
111
- jwt_secret_key: The secret key used to sign and verify JWT tokens.
112
117
  """
113
118
 
114
119
  user_id: uuid.UUID = Field(default_factory=uuid.uuid4)
115
120
  user_email: Optional[str] = None
116
121
  user_email_opt_in: Optional[bool] = None
117
122
  analytics_opt_in: bool = True
118
- version: Optional[str]
119
- store: Optional[StoreConfiguration]
120
- active_stack_id: Optional[uuid.UUID]
121
- active_workspace_name: Optional[str]
123
+ version: Optional[str] = None
124
+ store: Optional[SerializeAsAny[StoreConfiguration]] = None
125
+ active_stack_id: Optional[uuid.UUID] = None
126
+ active_workspace_name: Optional[str] = None
122
127
 
123
128
  _zen_store: Optional["BaseZenStore"] = None
124
129
  _active_workspace: Optional["WorkspaceResponse"] = None
@@ -169,12 +174,13 @@ class GlobalConfiguration(BaseModel, metaclass=GlobalConfigMetaClass):
169
174
  if config:
170
175
  config._write_config()
171
176
 
172
- @validator("version")
173
- def _validate_version(cls, v: Optional[str]) -> Optional[str]:
177
+ @field_validator("version")
178
+ @classmethod
179
+ def _validate_version(cls, value: Optional[str]) -> Optional[str]:
174
180
  """Validate the version attribute.
175
181
 
176
182
  Args:
177
- v: The version attribute value.
183
+ value: The version attribute value.
178
184
 
179
185
  Returns:
180
186
  The version attribute value.
@@ -182,18 +188,18 @@ class GlobalConfiguration(BaseModel, metaclass=GlobalConfigMetaClass):
182
188
  Raises:
183
189
  RuntimeError: If the version parsing fails.
184
190
  """
185
- if v is None:
186
- return v
191
+ if value is None:
192
+ return value
187
193
 
188
- if not isinstance(version.parse(v), version.Version):
194
+ if not isinstance(version.parse(value), version.Version):
189
195
  # If the version parsing fails, it returns a `LegacyVersion`
190
196
  # instead. Check to make sure it's an actual `Version` object
191
197
  # which represents a valid version.
192
198
  raise RuntimeError(
193
- f"Invalid version in global configuration: {v}."
199
+ f"Invalid version in global configuration: {value}."
194
200
  )
195
201
 
196
- return v
202
+ return value
197
203
 
198
204
  def __setattr__(self, key: str, value: Any) -> None:
199
205
  """Sets an attribute and persists it in the global configuration.
@@ -222,7 +228,7 @@ class GlobalConfiguration(BaseModel, metaclass=GlobalConfigMetaClass):
222
228
  The attribute value.
223
229
  """
224
230
  value = super().__getattribute__(key)
225
- if key.startswith("_") or key not in type(self).__fields__:
231
+ if key.startswith("_") or key not in type(self).model_fields:
226
232
  return value
227
233
 
228
234
  environment_variable_name = f"{CONFIG_ENV_VAR_PREFIX}{key.upper()}"
@@ -321,7 +327,7 @@ class GlobalConfiguration(BaseModel, metaclass=GlobalConfigMetaClass):
321
327
  return
322
328
 
323
329
  config_file = self._config_file
324
- yaml_dict = json.loads(self.json(exclude_none=True))
330
+ yaml_dict = self.model_dump(mode="json", exclude_none=True)
325
331
  logger.debug(f"Writing config to {config_file}")
326
332
 
327
333
  if not fileio.exists(config_file):
@@ -436,7 +442,7 @@ class GlobalConfiguration(BaseModel, metaclass=GlobalConfigMetaClass):
436
442
  """
437
443
  environment_vars = {}
438
444
 
439
- for key in self.__fields__.keys():
445
+ for key in self.model_fields.keys():
440
446
  if key == "store":
441
447
  # The store configuration uses its own environment variable
442
448
  # naming scheme
@@ -448,7 +454,7 @@ class GlobalConfiguration(BaseModel, metaclass=GlobalConfigMetaClass):
448
454
  value
449
455
  )
450
456
 
451
- store_dict = self.store_configuration.dict(exclude_none=True)
457
+ store_dict = self.store_configuration.model_dump(exclude_none=True)
452
458
 
453
459
  # The secrets store and backup secrets store configurations use their
454
460
  # own environment variables naming scheme
@@ -556,7 +562,7 @@ class GlobalConfiguration(BaseModel, metaclass=GlobalConfigMetaClass):
556
562
  logger.debug(
557
563
  "Using environment variables to update the default store"
558
564
  )
559
- store = store.copy(update=env_store_config, deep=True)
565
+ store = store.model_copy(update=env_store_config, deep=True)
560
566
 
561
567
  # Step 3: Replace or update the baseline secrets store configuration
562
568
  # with the environment variables. This only applies to SQL stores.
@@ -586,7 +592,7 @@ class GlobalConfiguration(BaseModel, metaclass=GlobalConfigMetaClass):
586
592
  "Using environment variables to update the secrets "
587
593
  "store"
588
594
  )
589
- store.secrets_store = store.secrets_store.copy(
595
+ store.secrets_store = store.secrets_store.model_copy(
590
596
  update=env_secrets_store_config, deep=True
591
597
  )
592
598
 
@@ -605,7 +611,7 @@ class GlobalConfiguration(BaseModel, metaclass=GlobalConfigMetaClass):
605
611
  "secrets store"
606
612
  )
607
613
  store.backup_secrets_store = (
608
- store.backup_secrets_store.copy(
614
+ store.backup_secrets_store.model_copy(
609
615
  update=env_backup_secrets_store_config, deep=True
610
616
  )
611
617
  )
@@ -769,21 +775,11 @@ class GlobalConfiguration(BaseModel, metaclass=GlobalConfigMetaClass):
769
775
 
770
776
  return self.active_stack_id
771
777
 
772
- class Config:
773
- """Pydantic configuration class."""
774
-
778
+ model_config = ConfigDict(
775
779
  # Validate attributes when assigning them. We need to set this in order
776
780
  # to have a mix of mutable and immutable attributes
777
- validate_assignment = True
781
+ validate_assignment=True,
778
782
  # Allow extra attributes from configs of previous ZenML versions to
779
783
  # permit downgrading
780
- extra = "allow"
781
- # all attributes with leading underscore are private and therefore
782
- # are mutable and not included in serialization
783
- underscore_attrs_are_private = True
784
-
785
- # This is needed to allow correct handling of SecretStr values during
786
- # serialization.
787
- json_encoders = {
788
- SecretStr: lambda v: v.get_secret_value() if v else None
789
- }
784
+ extra="allow",
785
+ )
@@ -15,11 +15,11 @@
15
15
 
16
16
  from typing import TYPE_CHECKING, Any, Dict, Optional
17
17
 
18
- from pydantic import validator
18
+ from pydantic import SerializeAsAny, field_validator
19
19
 
20
20
  from zenml.config.constants import DOCKER_SETTINGS_KEY
21
21
  from zenml.config.retry_config import StepRetryConfig
22
- from zenml.config.source import Source, convert_source_validator
22
+ from zenml.config.source import SourceWithValidator
23
23
  from zenml.config.strict_base_model import StrictBaseModel
24
24
  from zenml.model.model import Model
25
25
 
@@ -38,25 +38,22 @@ class PipelineConfigurationUpdate(StrictBaseModel):
38
38
  enable_artifact_metadata: Optional[bool] = None
39
39
  enable_artifact_visualization: Optional[bool] = None
40
40
  enable_step_logs: Optional[bool] = None
41
- settings: Dict[str, BaseSettings] = {}
41
+ settings: Dict[str, SerializeAsAny[BaseSettings]] = {}
42
42
  extra: Dict[str, Any] = {}
43
- failure_hook_source: Optional[Source] = None
44
- success_hook_source: Optional[Source] = None
43
+ failure_hook_source: Optional[SourceWithValidator] = None
44
+ success_hook_source: Optional[SourceWithValidator] = None
45
45
  model: Optional[Model] = None
46
46
  parameters: Optional[Dict[str, Any]] = None
47
47
  retry: Optional[StepRetryConfig] = None
48
48
 
49
- _convert_source = convert_source_validator(
50
- "failure_hook_source", "success_hook_source"
51
- )
52
-
53
49
 
54
50
  class PipelineConfiguration(PipelineConfigurationUpdate):
55
51
  """Pipeline configuration class."""
56
52
 
57
53
  name: str
58
54
 
59
- @validator("name")
55
+ @field_validator("name")
56
+ @classmethod
60
57
  def ensure_pipeline_name_allowed(cls, name: str) -> str:
61
58
  """Ensures the pipeline name is allowed.
62
59
 
@@ -88,4 +85,4 @@ class PipelineConfiguration(PipelineConfigurationUpdate):
88
85
  model_or_dict: SettingsOrDict = self.settings.get(
89
86
  DOCKER_SETTINGS_KEY, {}
90
87
  )
91
- return DockerSettings.parse_obj(model_or_dict)
88
+ return DockerSettings.model_validate(model_or_dict)
@@ -16,6 +16,8 @@
16
16
  from typing import Any, Dict, Optional, Union
17
17
  from uuid import UUID
18
18
 
19
+ from pydantic import Field, SerializeAsAny
20
+
19
21
  from zenml.config.base_settings import BaseSettings
20
22
  from zenml.config.retry_config import StepRetryConfig
21
23
  from zenml.config.schedule import Schedule
@@ -37,9 +39,11 @@ class PipelineRunConfiguration(
37
39
  enable_artifact_visualization: Optional[bool] = None
38
40
  enable_step_logs: Optional[bool] = None
39
41
  schedule: Optional[Schedule] = None
40
- build: Union[PipelineBuildBase, UUID, None] = None
42
+ build: Union[PipelineBuildBase, UUID, None] = Field(
43
+ default=None, union_mode="left_to_right"
44
+ )
41
45
  steps: Dict[str, StepConfigurationUpdate] = {}
42
- settings: Dict[str, BaseSettings] = {}
46
+ settings: Dict[str, SerializeAsAny[BaseSettings]] = {}
43
47
  extra: Dict[str, Any] = {}
44
48
  model: Optional[Model] = None
45
49
  parameters: Optional[Dict[str, Any]] = None
@@ -16,11 +16,10 @@
16
16
  import json
17
17
  from typing import Any, Dict, List, Optional
18
18
 
19
- from pydantic.json import pydantic_encoder
20
-
21
19
  from zenml.config.source import Source
22
20
  from zenml.config.step_configurations import StepSpec
23
21
  from zenml.config.strict_base_model import StrictBaseModel
22
+ from zenml.utils.json_utils import pydantic_encoder
24
23
 
25
24
 
26
25
  class PipelineSpec(StrictBaseModel):
@@ -61,13 +60,13 @@ class PipelineSpec(StrictBaseModel):
61
60
  """
62
61
  from packaging import version
63
62
 
64
- dict_ = self.dict()
63
+ dict_ = self.model_dump()
65
64
 
66
65
  if self.source:
67
66
  dict_["source"] = self.source.import_path
68
67
 
69
68
  for step_dict in dict_["steps"]:
70
- step_dict["source"] = Source.parse_obj(
69
+ step_dict["source"] = Source.model_validate(
71
70
  step_dict["source"]
72
71
  ).import_path
73
72
 
@@ -16,7 +16,8 @@
16
16
  from enum import Enum
17
17
  from typing import Optional, Union
18
18
 
19
- from pydantic import Extra, Field, NonNegativeInt, PositiveFloat
19
+ from pydantic import Field, NonNegativeInt, PositiveFloat
20
+ from pydantic_settings import SettingsConfigDict
20
21
 
21
22
  from zenml.config.base_settings import BaseSettings
22
23
 
@@ -70,7 +71,7 @@ class ResourceSettings(BaseSettings):
70
71
 
71
72
  cpu_count: Optional[PositiveFloat] = None
72
73
  gpu_count: Optional[NonNegativeInt] = None
73
- memory: Optional[str] = Field(regex=MEMORY_REGEX)
74
+ memory: Optional[str] = Field(pattern=MEMORY_REGEX, default=None)
74
75
 
75
76
  @property
76
77
  def empty(self) -> bool:
@@ -82,7 +83,7 @@ class ResourceSettings(BaseSettings):
82
83
  # To detect whether this config is empty (= no values specified), we
83
84
  # check if there are any attributes which are explicitly set to any
84
85
  # value other than `None`.
85
- return len(self.dict(exclude_unset=True, exclude_none=True)) == 0
86
+ return len(self.model_dump(exclude_unset=True, exclude_none=True)) == 0
86
87
 
87
88
  def get_memory(
88
89
  self, unit: Union[str, ByteUnit] = ByteUnit.GB
@@ -114,11 +115,9 @@ class ResourceSettings(BaseSettings):
114
115
  # Should never happen due to the regex validation
115
116
  raise ValueError(f"Unable to parse memory unit from '{memory}'.")
116
117
 
117
- class Config:
118
- """Pydantic configuration class."""
119
-
118
+ model_config = SettingsConfigDict(
120
119
  # public attributes are immutable
121
- allow_mutation = False
122
-
120
+ frozen=True,
123
121
  # prevent extra attributes during model initialization
124
- extra = Extra.forbid
122
+ extra="forbid",
123
+ )
zenml/config/schedule.py CHANGED
@@ -14,9 +14,9 @@
14
14
  """Class for defining a pipeline schedule."""
15
15
 
16
16
  import datetime
17
- from typing import Any, Dict, Optional
17
+ from typing import Optional
18
18
 
19
- from pydantic import BaseModel, root_validator
19
+ from pydantic import BaseModel, model_validator
20
20
 
21
21
  from zenml.logger import get_logger
22
22
 
@@ -55,15 +55,10 @@ class Schedule(BaseModel):
55
55
  catchup: bool = False
56
56
  run_once_start_time: Optional[datetime.datetime] = None
57
57
 
58
- @root_validator
59
- def _ensure_cron_or_periodic_schedule_configured(
60
- cls, values: Dict[str, Any]
61
- ) -> Dict[str, Any]:
58
+ @model_validator(mode="after")
59
+ def _ensure_cron_or_periodic_schedule_configured(self) -> "Schedule":
62
60
  """Ensures that the cron expression or start time + interval are set.
63
61
 
64
- Args:
65
- values: All attributes of the schedule.
66
-
67
62
  Returns:
68
63
  All schedule attributes.
69
64
 
@@ -71,13 +66,9 @@ class Schedule(BaseModel):
71
66
  ValueError: If no cron expression or start time + interval were
72
67
  provided.
73
68
  """
74
- cron_expression = values.get("cron_expression")
75
- periodic_schedule = values.get("start_time") and values.get(
76
- "interval_second"
77
- )
78
- run_once_starts_at = values.get("run_once_start_time")
69
+ periodic_schedule = self.start_time and self.interval_second
79
70
 
80
- if cron_expression and periodic_schedule:
71
+ if self.cron_expression and periodic_schedule:
81
72
  logger.warning(
82
73
  "This schedule was created with a cron expression as well as "
83
74
  "values for `start_time` and `interval_seconds`. The resulting "
@@ -85,17 +76,22 @@ class Schedule(BaseModel):
85
76
  "but will usually ignore the interval and use the cron "
86
77
  "expression."
87
78
  )
88
- return values
89
- elif cron_expression and run_once_starts_at:
79
+
80
+ return self
81
+ elif self.cron_expression and self.run_once_start_time:
90
82
  logger.warning(
91
83
  "This schedule was created with a cron expression as well as "
92
84
  "a value for `run_once_start_time`. The resulting behavior "
93
85
  "depends on the concrete orchestrator implementation but will "
94
86
  "usually ignore the `run_once_start_time`."
95
87
  )
96
- return values
97
- elif cron_expression or periodic_schedule or run_once_starts_at:
98
- return values
88
+ return self
89
+ elif (
90
+ self.cron_expression
91
+ or periodic_schedule
92
+ or self.run_once_start_time
93
+ ):
94
+ return self
99
95
  else:
100
96
  raise ValueError(
101
97
  "Either a cron expression, a start time and interval seconds "
@@ -19,6 +19,7 @@ from pydantic import BaseModel
19
19
 
20
20
  from zenml.logger import get_logger
21
21
  from zenml.utils import secret_utils
22
+ from zenml.utils.pydantic_utils import has_validators
22
23
 
23
24
  logger = get_logger(__name__)
24
25
 
@@ -45,7 +46,7 @@ class SecretReferenceMixin(BaseModel):
45
46
  """
46
47
  for key, value in kwargs.items():
47
48
  try:
48
- field = self.__class__.__fields__[key]
49
+ field = self.__class__.model_fields[key]
49
50
  except KeyError:
50
51
  # Value for a private attribute or non-existing field, this
51
52
  # will fail during the upcoming pydantic validation
@@ -75,7 +76,9 @@ class SecretReferenceMixin(BaseModel):
75
76
  "not allowed."
76
77
  )
77
78
 
78
- requires_validation = field.pre_validators or field.post_validators
79
+ requires_validation = has_validators(
80
+ pydantic_class=self.__class__, field_name=key
81
+ )
79
82
  if requires_validation:
80
83
  raise ValueError(
81
84
  f"Passing the attribute `{key}` as a secret reference is "
@@ -146,6 +149,6 @@ class SecretReferenceMixin(BaseModel):
146
149
  """
147
150
  return {
148
151
  secret_utils.parse_secret_reference(v)
149
- for v in self.dict().values()
152
+ for v in self.model_dump().values()
150
153
  if secret_utils.is_secret_reference(v)
151
154
  }
@@ -13,9 +13,9 @@
13
13
  # permissions and limitations under the License.
14
14
  """Functionality to support ZenML secrets store configurations."""
15
15
 
16
- from typing import Any, Dict, Optional
16
+ from typing import Optional
17
17
 
18
- from pydantic import BaseModel, root_validator
18
+ from pydantic import BaseModel, ConfigDict, model_validator
19
19
 
20
20
  from zenml.enums import SecretsStoreType
21
21
  from zenml.logger import get_logger
@@ -41,45 +41,38 @@ class SecretsStoreConfiguration(BaseModel):
41
41
  type: SecretsStoreType
42
42
  class_path: Optional[str] = None
43
43
 
44
- @root_validator
45
- def validate_custom(cls, values: Dict[str, Any]) -> Dict[str, Any]:
44
+ @model_validator(mode="after")
45
+ def validate_custom(self) -> "SecretsStoreConfiguration":
46
46
  """Validate that class_path is set for custom secrets stores.
47
47
 
48
- Args:
49
- values: Dict representing user-specified runtime settings.
50
-
51
48
  Returns:
52
49
  Validated settings.
53
50
 
54
51
  Raises:
55
- ValueError: If class_path is not set when using an custom secrets
52
+ ValueError: If class_path is not set when using a custom secrets
56
53
  store.
57
54
  """
58
- if not values.get("type"):
59
- return values
60
- if values["type"] == SecretsStoreType.CUSTOM:
61
- if values["class_path"] is None:
55
+ if not self.type:
56
+ return self
57
+ if self.type == SecretsStoreType.CUSTOM:
58
+ if self.class_path is None:
62
59
  raise ValueError(
63
60
  "A class_path must be set when using a custom secrets "
64
61
  "store implementation."
65
62
  )
66
- elif values["class_path"] is not None:
63
+ elif self.class_path is not None:
67
64
  raise ValueError(
68
65
  f"The class_path attribute is not supported for the "
69
- f"{values['type']} secrets store type."
66
+ f"{self.type} secrets store type."
70
67
  )
71
68
 
72
- return values
73
-
74
- class Config:
75
- """Pydantic configuration class."""
69
+ return self
76
70
 
71
+ model_config = ConfigDict(
77
72
  # Validate attributes when assigning them. We need to set this in order
78
73
  # to have a mix of mutable and immutable attributes
79
- validate_assignment = True
74
+ validate_assignment=True,
80
75
  # Allow extra attributes to be set in the base class. The concrete
81
76
  # classes are responsible for validating the attributes.
82
- extra = "allow"
83
- # all attributes with leading underscore are private and therefore
84
- # are mutable and not included in serialization
85
- underscore_attrs_are_private = True
77
+ extra="allow",
78
+ )