prefect-client 2.16.7__py3-none-any.whl → 2.16.9__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 (62) hide show
  1. prefect/_internal/compatibility/experimental.py +9 -8
  2. prefect/_internal/concurrency/api.py +23 -42
  3. prefect/_internal/concurrency/waiters.py +25 -22
  4. prefect/_internal/pydantic/__init__.py +12 -3
  5. prefect/_internal/pydantic/_base_model.py +7 -4
  6. prefect/_internal/pydantic/_compat.py +39 -453
  7. prefect/_internal/pydantic/_flags.py +2 -0
  8. prefect/_internal/pydantic/_types.py +8 -0
  9. prefect/_internal/pydantic/utilities/__init__.py +0 -0
  10. prefect/_internal/pydantic/utilities/model_construct.py +56 -0
  11. prefect/_internal/pydantic/utilities/model_copy.py +55 -0
  12. prefect/_internal/pydantic/utilities/model_dump.py +136 -0
  13. prefect/_internal/pydantic/utilities/model_dump_json.py +112 -0
  14. prefect/_internal/pydantic/utilities/model_fields.py +50 -0
  15. prefect/_internal/pydantic/utilities/model_json_schema.py +82 -0
  16. prefect/_internal/pydantic/utilities/model_rebuild.py +80 -0
  17. prefect/_internal/pydantic/utilities/model_validate.py +75 -0
  18. prefect/_internal/pydantic/utilities/model_validate_json.py +68 -0
  19. prefect/_internal/pydantic/utilities/type_adapter.py +71 -0
  20. prefect/_internal/schemas/bases.py +1 -17
  21. prefect/_internal/schemas/validators.py +425 -4
  22. prefect/blocks/kubernetes.py +7 -3
  23. prefect/client/cloud.py +1 -1
  24. prefect/client/orchestration.py +8 -8
  25. prefect/client/schemas/actions.py +348 -285
  26. prefect/client/schemas/objects.py +47 -126
  27. prefect/client/schemas/responses.py +231 -57
  28. prefect/concurrency/events.py +2 -2
  29. prefect/context.py +2 -1
  30. prefect/deployments/base.py +4 -3
  31. prefect/deployments/runner.py +7 -25
  32. prefect/deprecated/packaging/base.py +5 -6
  33. prefect/deprecated/packaging/docker.py +19 -25
  34. prefect/deprecated/packaging/file.py +10 -5
  35. prefect/deprecated/packaging/orion.py +9 -4
  36. prefect/deprecated/packaging/serializers.py +8 -58
  37. prefect/engine.py +23 -22
  38. prefect/events/actions.py +16 -1
  39. prefect/events/related.py +4 -4
  40. prefect/events/schemas/automations.py +13 -2
  41. prefect/events/schemas/deployment_triggers.py +73 -5
  42. prefect/events/schemas/events.py +1 -1
  43. prefect/flows.py +3 -0
  44. prefect/infrastructure/provisioners/ecs.py +1 -0
  45. prefect/logging/configuration.py +2 -2
  46. prefect/pydantic/__init__.py +48 -2
  47. prefect/pydantic/main.py +2 -2
  48. prefect/serializers.py +6 -31
  49. prefect/settings.py +40 -17
  50. prefect/software/python.py +3 -5
  51. prefect/utilities/callables.py +1 -1
  52. prefect/utilities/collections.py +2 -1
  53. prefect/utilities/schema_tools/validation.py +2 -2
  54. prefect/workers/base.py +19 -10
  55. prefect/workers/block.py +3 -7
  56. prefect/workers/process.py +2 -5
  57. {prefect_client-2.16.7.dist-info → prefect_client-2.16.9.dist-info}/METADATA +3 -2
  58. {prefect_client-2.16.7.dist-info → prefect_client-2.16.9.dist-info}/RECORD +61 -50
  59. prefect/_internal/schemas/transformations.py +0 -106
  60. {prefect_client-2.16.7.dist-info → prefect_client-2.16.9.dist-info}/LICENSE +0 -0
  61. {prefect_client-2.16.7.dist-info → prefect_client-2.16.9.dist-info}/WHEEL +0 -0
  62. {prefect_client-2.16.7.dist-info → prefect_client-2.16.9.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Utilities for creating and working with Prefect REST API schemas.
3
3
  """
4
+
4
5
  import datetime
5
6
  import json
6
7
  import os
@@ -23,7 +24,6 @@ else:
23
24
  from pydantic import BaseModel, Field, SecretField
24
25
  from pydantic.json import custom_pydantic_encoder
25
26
 
26
- from prefect._internal.compatibility.experimental import experiment_enabled
27
27
  from prefect._internal.schemas.fields import DateTimeTZ
28
28
  from prefect._internal.schemas.serializers import orjson_dumps_extra_compatible
29
29
 
@@ -131,22 +131,6 @@ class PrefectBaseModel(BaseModel):
131
131
  dict
132
132
  """
133
133
 
134
- experimental_fields = [
135
- field
136
- for _, field in self.__fields__.items()
137
- if field.field_info.extra.get("experimental")
138
- ]
139
- experimental_fields_to_exclude = [
140
- field.name
141
- for field in experimental_fields
142
- if not experiment_enabled(field.field_info.extra["experimental-group"])
143
- ]
144
-
145
- if experimental_fields_to_exclude:
146
- kwargs["exclude"] = (kwargs.get("exclude") or set()).union(
147
- experimental_fields_to_exclude
148
- )
149
-
150
134
  if json_compatible and shallow:
151
135
  raise ValueError(
152
136
  "`json_compatible` can only be applied to the entire object."
@@ -1,18 +1,33 @@
1
+ """
2
+ This module contains a collection of functions that are used to validate the
3
+ values of fields in Pydantic models. These functions are used as validators in
4
+ Pydantic models to ensure that the values of fields conform to the expected
5
+ format.
6
+ This will be subject to consolidation and refactoring over the next few months.
7
+ """
8
+
1
9
  import datetime
2
10
  import json
3
11
  import logging
4
12
  import re
13
+ import sys
5
14
  import urllib.parse
15
+ import warnings
16
+ from copy import copy
6
17
  from pathlib import Path
7
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
18
+ from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional, Tuple, Union
8
19
 
9
20
  import jsonschema
10
21
  import pendulum
22
+ import yaml
11
23
 
12
24
  from prefect._internal.pydantic import HAS_PYDANTIC_V2
25
+ from prefect._internal.pydantic._flags import USE_PYDANTIC_V2
13
26
  from prefect._internal.schemas.fields import DateTimeTZ
14
27
  from prefect.exceptions import InvalidNameError, InvalidRepositoryURLError
15
28
  from prefect.utilities.annotations import NotSet
29
+ from prefect.utilities.dockerutils import get_prefect_image_name
30
+ from prefect.utilities.filesystem import relative_path_to_current_platform
16
31
  from prefect.utilities.importtools import from_qualified_name
17
32
  from prefect.utilities.names import generate_slug
18
33
  from prefect.utilities.pydantic import JsonPatch
@@ -27,9 +42,11 @@ if TYPE_CHECKING:
27
42
  from prefect.utilities.callables import ParameterSchema
28
43
 
29
44
  if HAS_PYDANTIC_V2:
30
- from pydantic.v1.fields import ModelField
31
- else:
32
- from pydantic.fields import ModelField
45
+ if USE_PYDANTIC_V2:
46
+ # TODO: we need to account for rewriting the validator to not use ModelField
47
+ pass
48
+ if not USE_PYDANTIC_V2:
49
+ from pydantic.v1.fields import ModelField
33
50
 
34
51
 
35
52
  def raise_on_name_with_banned_characters(name: str) -> str:
@@ -191,6 +208,30 @@ def handle_openapi_schema(value: Optional["ParameterSchema"]) -> "ParameterSchem
191
208
  return value
192
209
 
193
210
 
211
+ def validate_parameters_conform_to_schema(value: dict, values: dict) -> dict:
212
+ """Validate that the parameters conform to the parameter schema."""
213
+ if values.get("enforce_parameter_schema"):
214
+ validate_values_conform_to_schema(
215
+ value, values.get("parameter_openapi_schema"), ignore_required=True
216
+ )
217
+ return value
218
+
219
+
220
+ def validate_parameter_openapi_schema(value: dict, values: dict) -> dict:
221
+ """Validate that the parameter_openapi_schema is a valid json schema."""
222
+ if values.get("enforce_parameter_schema"):
223
+ validate_schema(value)
224
+ return value
225
+
226
+
227
+ def return_none_schedule(v: Optional[Union[str, dict]]) -> Optional[Union[str, dict]]:
228
+ from prefect.client.schemas.schedules import NoSchedule
229
+
230
+ if isinstance(v, NoSchedule):
231
+ return None
232
+ return v
233
+
234
+
194
235
  ### SCHEDULE SCHEMA VALIDATORS ###
195
236
 
196
237
 
@@ -246,6 +287,91 @@ def reconcile_schedules(cls, values: dict) -> dict:
246
287
  return values
247
288
 
248
289
 
290
+ # TODO: consolidate with above if possible
291
+ def reconcile_schedules_runner(values: dict) -> dict:
292
+ """
293
+ Similar to above, we reconcile the `schedule` and `schedules` fields in a deployment.
294
+ """
295
+ from prefect.deployments.schedules import (
296
+ create_minimal_deployment_schedule,
297
+ normalize_to_minimal_deployment_schedules,
298
+ )
299
+
300
+ schedule = values.get("schedule")
301
+ schedules = values.get("schedules")
302
+
303
+ if schedules is None and schedule is not None:
304
+ values["schedules"] = [create_minimal_deployment_schedule(schedule)]
305
+ elif schedules is not None and len(schedules) > 0:
306
+ values["schedules"] = normalize_to_minimal_deployment_schedules(schedules)
307
+
308
+ return values
309
+
310
+
311
+ def set_deployment_schedules(values: dict) -> dict:
312
+ from prefect.server.schemas.actions import DeploymentScheduleCreate
313
+
314
+ if not values.get("schedules") and values.get("schedule"):
315
+ values["schedules"] = [
316
+ DeploymentScheduleCreate(
317
+ schedule=values["schedule"],
318
+ active=values["is_schedule_active"],
319
+ )
320
+ ]
321
+
322
+ return values
323
+
324
+
325
+ def remove_old_deployment_fields(values: dict) -> dict:
326
+ # 2.7.7 removed worker_pool_queue_id in lieu of worker_pool_name and
327
+ # worker_pool_queue_name. Those fields were later renamed to work_pool_name
328
+ # and work_queue_name. This validator removes old fields provided
329
+ # by older clients to avoid 422 errors.
330
+ values_copy = copy(values)
331
+ worker_pool_queue_id = values_copy.pop("worker_pool_queue_id", None)
332
+ worker_pool_name = values_copy.pop("worker_pool_name", None)
333
+ worker_pool_queue_name = values_copy.pop("worker_pool_queue_name", None)
334
+ work_pool_queue_name = values_copy.pop("work_pool_queue_name", None)
335
+ if worker_pool_queue_id:
336
+ warnings.warn(
337
+ (
338
+ "`worker_pool_queue_id` is no longer supported for creating or updating "
339
+ "deployments. Please use `work_pool_name` and "
340
+ "`work_queue_name` instead."
341
+ ),
342
+ UserWarning,
343
+ )
344
+ if worker_pool_name or worker_pool_queue_name or work_pool_queue_name:
345
+ warnings.warn(
346
+ (
347
+ "`worker_pool_name`, `worker_pool_queue_name`, and "
348
+ "`work_pool_name` are"
349
+ "no longer supported for creating or updating "
350
+ "deployments. Please use `work_pool_name` and "
351
+ "`work_queue_name` instead."
352
+ ),
353
+ UserWarning,
354
+ )
355
+ return values_copy
356
+
357
+
358
+ def reconcile_paused_deployment(values):
359
+ paused = values.get("paused")
360
+ is_schedule_active = values.get("is_schedule_active")
361
+
362
+ if paused is not None:
363
+ values["paused"] = paused
364
+ values["is_schedule_active"] = not paused
365
+ elif is_schedule_active is not None:
366
+ values["paused"] = not is_schedule_active
367
+ values["is_schedule_active"] = is_schedule_active
368
+ else:
369
+ values["paused"] = False
370
+ values["is_schedule_active"] = True
371
+
372
+ return values
373
+
374
+
249
375
  def interval_schedule_must_be_positive(v: datetime.timedelta) -> datetime.timedelta:
250
376
  if v.total_seconds() <= 0:
251
377
  raise ValueError("The interval must be positive")
@@ -473,6 +599,9 @@ def set_default_image(values: dict) -> dict:
473
599
  return values
474
600
 
475
601
 
602
+ ### STATE SCHEMA VALIDATORS ###
603
+
604
+
476
605
  def get_or_create_state_name(v: str, values: dict) -> str:
477
606
  """If a name is not provided, use the type"""
478
607
 
@@ -483,6 +612,23 @@ def get_or_create_state_name(v: str, values: dict) -> str:
483
612
  return v
484
613
 
485
614
 
615
+ def set_default_scheduled_time(cls, values: dict) -> dict:
616
+ """
617
+ TODO: This should throw an error instead of setting a default but is out of
618
+ scope for https://github.com/PrefectHQ/orion/pull/174/ and can be rolled
619
+ into work refactoring state initialization
620
+ """
621
+ from prefect.server.schemas.states import StateType
622
+
623
+ if values.get("type") == StateType.SCHEDULED:
624
+ state_details = values.setdefault(
625
+ "state_details", cls.__fields__["state_details"].get_default()
626
+ )
627
+ if not state_details.scheduled_time:
628
+ state_details.scheduled_time = pendulum.now("utc")
629
+ return values
630
+
631
+
486
632
  def get_or_create_run_name(name):
487
633
  return name or generate_slug(2)
488
634
 
@@ -558,6 +704,48 @@ def validate_picklelib(value: str) -> str:
558
704
  return value
559
705
 
560
706
 
707
+ def validate_picklelib_version(values: dict) -> dict:
708
+ """
709
+ Infers a default value for `picklelib_version` if null or ensures it matches
710
+ the version retrieved from the `pickelib`.
711
+ """
712
+ picklelib = values.get("picklelib")
713
+ picklelib_version = values.get("picklelib_version")
714
+
715
+ if not picklelib:
716
+ raise ValueError("Unable to check version of unrecognized picklelib module")
717
+
718
+ pickler = from_qualified_name(picklelib)
719
+ pickler_version = getattr(pickler, "__version__", None)
720
+
721
+ if not picklelib_version:
722
+ values["picklelib_version"] = pickler_version
723
+ elif picklelib_version != pickler_version:
724
+ warnings.warn(
725
+ (
726
+ f"Mismatched {picklelib!r} versions. Found {pickler_version} in the"
727
+ f" environment but {picklelib_version} was requested. This may"
728
+ " cause the serializer to fail."
729
+ ),
730
+ RuntimeWarning,
731
+ stacklevel=3,
732
+ )
733
+
734
+ return values
735
+
736
+
737
+ def validate_picklelib_and_modules(values: dict) -> dict:
738
+ """
739
+ Prevents modules from being specified if picklelib is not cloudpickle
740
+ """
741
+ if values.get("picklelib") != "cloudpickle" and values.get("pickle_modules"):
742
+ raise ValueError(
743
+ "`pickle_modules` cannot be used without 'cloudpickle'. Got"
744
+ f" {values.get('picklelib')!r}."
745
+ )
746
+ return values
747
+
748
+
561
749
  def validate_dump_kwargs(value: dict) -> dict:
562
750
  # `default` is set by `object_encoder`. A user provided callable would make this
563
751
  # class unserializable anyway.
@@ -607,3 +795,236 @@ def validate_compressionlib(value: str) -> str:
607
795
  )
608
796
 
609
797
  return value
798
+
799
+
800
+ # TODO: if we use this elsewhere we can change the error message to be more generic
801
+ def list_length_50_or_less(v: Optional[List[float]]) -> Optional[List[float]]:
802
+ if isinstance(v, list) and (len(v) > 50):
803
+ raise ValueError("Can not configure more than 50 retry delays per task.")
804
+ return v
805
+
806
+
807
+ # TODO: if we use this elsewhere we can change the error message to be more generic
808
+ def validate_not_negative(v: Optional[float]) -> Optional[float]:
809
+ if v is not None and v < 0:
810
+ raise ValueError("`retry_jitter_factor` must be >= 0.")
811
+ return v
812
+
813
+
814
+ def validate_message_template_variables(v: Optional[str]) -> Optional[str]:
815
+ from prefect.client.schemas.objects import FLOW_RUN_NOTIFICATION_TEMPLATE_KWARGS
816
+
817
+ if v is not None:
818
+ try:
819
+ v.format(**{k: "test" for k in FLOW_RUN_NOTIFICATION_TEMPLATE_KWARGS})
820
+ except KeyError as exc:
821
+ raise ValueError(f"Invalid template variable provided: '{exc.args[0]}'")
822
+ return v
823
+
824
+
825
+ def validate_default_queue_id_not_none(v: Optional[str]) -> Optional[str]:
826
+ if v is None:
827
+ raise ValueError(
828
+ "`default_queue_id` is a required field. If you are "
829
+ "creating a new WorkPool and don't have a queue "
830
+ "ID yet, use the `actions.WorkPoolCreate` model instead."
831
+ )
832
+ return v
833
+
834
+
835
+ def validate_max_metadata_length(
836
+ v: Optional[Dict[str, Any]],
837
+ ) -> Optional[Dict[str, Any]]:
838
+ max_metadata_length = 500
839
+ if not isinstance(v, dict):
840
+ return v
841
+ for key in v.keys():
842
+ if len(str(v[key])) > max_metadata_length:
843
+ v[key] = str(v[key])[:max_metadata_length] + "..."
844
+ return v
845
+
846
+
847
+ ### DOCKER SCHEMA VALIDATORS ###
848
+
849
+
850
+ def validate_registry_url(value: Optional[str]) -> Optional[str]:
851
+ if isinstance(value, str):
852
+ if "://" not in value:
853
+ return "https://" + value
854
+ return value
855
+
856
+
857
+ def convert_labels_to_docker_format(labels: Dict[str, str]) -> Dict[str, str]:
858
+ labels = labels or {}
859
+ new_labels = {}
860
+ for name, value in labels.items():
861
+ if "/" in name:
862
+ namespace, key = name.split("/", maxsplit=1)
863
+ new_namespace = ".".join(reversed(namespace.split(".")))
864
+ new_labels[f"{new_namespace}.{key}"] = value
865
+ else:
866
+ new_labels[name] = value
867
+ return new_labels
868
+
869
+
870
+ def check_volume_format(volumes: List[str]) -> List[str]:
871
+ for volume in volumes:
872
+ if ":" not in volume:
873
+ raise ValueError(
874
+ "Invalid volume specification. "
875
+ f"Expected format 'path:container_path', but got {volume!r}"
876
+ )
877
+
878
+ return volumes
879
+
880
+
881
+ def assign_default_base_image(values: Mapping[str, Any]) -> Mapping[str, Any]:
882
+ from prefect.software.conda import CondaEnvironment
883
+
884
+ if not values.get("base_image") and not values.get("dockerfile"):
885
+ values["base_image"] = get_prefect_image_name(
886
+ flavor=(
887
+ "conda"
888
+ if isinstance(values.get("python_environment"), CondaEnvironment)
889
+ else None
890
+ )
891
+ )
892
+ return values
893
+
894
+
895
+ def base_image_xor_dockerfile(values: Mapping[str, Any]):
896
+ if values.get("base_image") and values.get("dockerfile"):
897
+ raise ValueError(
898
+ "Either `base_image` or `dockerfile` should be provided, but not both"
899
+ )
900
+ return values
901
+
902
+
903
+ def set_default_python_environment(values: Mapping[str, Any]) -> Mapping[str, Any]:
904
+ from prefect.software.python import PythonEnvironment
905
+
906
+ if values.get("base_image") and not values.get("python_environment"):
907
+ values["python_environment"] = PythonEnvironment.from_environment()
908
+ return values
909
+
910
+
911
+ ### SETTINGS SCHEMA VALIDATORS ###
912
+
913
+
914
+ def validate_settings(value: dict) -> dict:
915
+ from prefect.settings import SETTING_VARIABLES, Setting
916
+
917
+ if value is None:
918
+ return value
919
+
920
+ # Cast string setting names to variables
921
+ validated = {}
922
+ for setting, val in value.items():
923
+ if isinstance(setting, str) and setting in SETTING_VARIABLES:
924
+ validated[SETTING_VARIABLES[setting]] = val
925
+ elif isinstance(setting, Setting):
926
+ validated[setting] = val
927
+ else:
928
+ raise ValueError(f"Unknown setting {setting!r}.")
929
+
930
+ return validated
931
+
932
+
933
+ def validate_yaml(value: Union[str, dict]) -> dict:
934
+ if isinstance(value, str):
935
+ return yaml.safe_load(value)
936
+ return value
937
+
938
+
939
+ ### TASK RUN SCHEMA VALIDATORS ###
940
+
941
+
942
+ def validate_cache_key_length(cache_key: Optional[str]) -> Optional[str]:
943
+ from prefect.settings import (
944
+ PREFECT_API_TASK_CACHE_KEY_MAX_LENGTH,
945
+ )
946
+
947
+ if cache_key and len(cache_key) > PREFECT_API_TASK_CACHE_KEY_MAX_LENGTH.value():
948
+ raise ValueError(
949
+ "Cache key exceeded maximum allowed length of"
950
+ f" {PREFECT_API_TASK_CACHE_KEY_MAX_LENGTH.value()} characters."
951
+ )
952
+ return cache_key
953
+
954
+
955
+ def set_run_policy_deprecated_fields(values: dict) -> dict:
956
+ """
957
+ If deprecated fields are provided, populate the corresponding new fields
958
+ to preserve orchestration behavior.
959
+ """
960
+ if not values.get("retries", None) and values.get("max_retries", 0) != 0:
961
+ values["retries"] = values["max_retries"]
962
+
963
+ if (
964
+ not values.get("retry_delay", None)
965
+ and values.get("retry_delay_seconds", 0) != 0
966
+ ):
967
+ values["retry_delay"] = values["retry_delay_seconds"]
968
+
969
+ return values
970
+
971
+
972
+ ### PYTHON ENVIRONMENT SCHEMA VALIDATORS ###
973
+
974
+
975
+ def infer_python_version(value: Optional[str]) -> Optional[str]:
976
+ if value is None:
977
+ return f"{sys.version_info.major}.{sys.version_info.minor}"
978
+ return value
979
+
980
+
981
+ def return_v_or_none(v: Optional[str]) -> Optional[str]:
982
+ """Make sure that empty strings are treated as None"""
983
+ if not v:
984
+ return None
985
+ return v
986
+
987
+
988
+ ### INFRASTRUCTURE BLOCK SCHEMA VALIDATORS ###
989
+
990
+
991
+ def validate_block_is_infrastructure(v: "Block") -> "Block":
992
+ from prefect.infrastructure.base import Infrastructure
993
+
994
+ print("v: ", v)
995
+ if not isinstance(v, Infrastructure):
996
+ raise TypeError("Provided block is not a valid infrastructure block.")
997
+
998
+ return v
999
+
1000
+
1001
+ ### BLOCK SCHEMA VALIDATORS ###
1002
+
1003
+
1004
+ def validate_parent_and_ref_diff(values: dict) -> dict:
1005
+ parent_id = values.get("parent_block_document_id")
1006
+ ref_id = values.get("reference_block_document_id")
1007
+ if parent_id and ref_id and parent_id == ref_id:
1008
+ raise ValueError(
1009
+ "`parent_block_document_id` and `reference_block_document_id` cannot be"
1010
+ " the same"
1011
+ )
1012
+ return values
1013
+
1014
+
1015
+ def validate_name_present_on_nonanonymous_blocks(values: dict) -> dict:
1016
+ # anonymous blocks may have no name prior to actually being
1017
+ # stored in the database
1018
+ if not values.get("is_anonymous") and not values.get("name"):
1019
+ raise ValueError("Names must be provided for block documents.")
1020
+ return values
1021
+
1022
+
1023
+ ### PROCESS JOB CONFIGURATION VALIDATORS ###
1024
+
1025
+
1026
+ def validate_command(v: str) -> Path:
1027
+ """Make sure that the working directory is formatted for the current platform."""
1028
+ if v:
1029
+ return relative_path_to_current_platform(v)
1030
+ return v
@@ -3,7 +3,9 @@ from typing import TYPE_CHECKING, Dict, Type
3
3
 
4
4
  import yaml
5
5
 
6
+ from prefect._internal.compatibility.deprecated import deprecated_class
6
7
  from prefect._internal.pydantic import HAS_PYDANTIC_V2
8
+ from prefect._internal.schemas.validators import validate_yaml
7
9
 
8
10
  if HAS_PYDANTIC_V2:
9
11
  from pydantic.v1 import Field, validator
@@ -23,6 +25,10 @@ else:
23
25
  kubernetes = lazy_import("kubernetes")
24
26
 
25
27
 
28
+ @deprecated_class(
29
+ start_date="Mar 2024",
30
+ help="Use the KubernetesClusterConfig block from prefect-kubernetes instead.",
31
+ )
26
32
  class KubernetesClusterConfig(Block):
27
33
  """
28
34
  Stores configuration for interaction with Kubernetes clusters.
@@ -55,9 +61,7 @@ class KubernetesClusterConfig(Block):
55
61
 
56
62
  @validator("config", pre=True)
57
63
  def parse_yaml_config(cls, value):
58
- if isinstance(value, str):
59
- return yaml.safe_load(value)
60
- return value
64
+ return validate_yaml(value)
61
65
 
62
66
  @classmethod
63
67
  def from_file(cls: Type[Self], path: Path = None, context_name: str = None) -> Self:
prefect/client/cloud.py CHANGED
@@ -63,7 +63,7 @@ class CloudClient:
63
63
  self,
64
64
  host: str,
65
65
  api_key: str,
66
- httpx_settings: dict = None,
66
+ httpx_settings: Optional[Dict[str, Any]] = None,
67
67
  ) -> None:
68
68
  httpx_settings = httpx_settings or dict()
69
69
  httpx_settings.setdefault("headers", dict())
@@ -216,7 +216,7 @@ class PrefectClient:
216
216
  *,
217
217
  api_key: str = None,
218
218
  api_version: str = None,
219
- httpx_settings: dict = None,
219
+ httpx_settings: Optional[Dict[str, Any]] = None,
220
220
  ) -> None:
221
221
  httpx_settings = httpx_settings.copy() if httpx_settings else {}
222
222
  httpx_settings.setdefault("headers", {})
@@ -523,8 +523,8 @@ class PrefectClient:
523
523
  self,
524
524
  deployment_id: UUID,
525
525
  *,
526
- parameters: Dict[str, Any] = None,
527
- context: dict = None,
526
+ parameters: Optional[Dict[str, Any]] = None,
527
+ context: Optional[Dict[str, Any]] = None,
528
528
  state: prefect.states.State = None,
529
529
  name: str = None,
530
530
  tags: Iterable[str] = None,
@@ -608,8 +608,8 @@ class PrefectClient:
608
608
  self,
609
609
  flow: "FlowObject",
610
610
  name: str = None,
611
- parameters: Dict[str, Any] = None,
612
- context: dict = None,
611
+ parameters: Optional[Dict[str, Any]] = None,
612
+ context: Optional[Dict[str, Any]] = None,
613
613
  tags: Iterable[str] = None,
614
614
  parent_task_run_id: UUID = None,
615
615
  state: "prefect.states.State" = None,
@@ -1578,7 +1578,7 @@ class PrefectClient:
1578
1578
  version: str = None,
1579
1579
  schedule: SCHEDULE_TYPES = None,
1580
1580
  schedules: List[DeploymentScheduleCreate] = None,
1581
- parameters: Dict[str, Any] = None,
1581
+ parameters: Optional[Dict[str, Any]] = None,
1582
1582
  description: str = None,
1583
1583
  work_queue_name: str = None,
1584
1584
  work_pool_name: str = None,
@@ -1588,8 +1588,8 @@ class PrefectClient:
1588
1588
  path: str = None,
1589
1589
  entrypoint: str = None,
1590
1590
  infrastructure_document_id: UUID = None,
1591
- infra_overrides: Dict[str, Any] = None,
1592
- parameter_openapi_schema: dict = None,
1591
+ infra_overrides: Optional[Dict[str, Any]] = None,
1592
+ parameter_openapi_schema: Optional[Dict[str, Any]] = None,
1593
1593
  is_schedule_active: Optional[bool] = None,
1594
1594
  paused: Optional[bool] = None,
1595
1595
  pull_steps: Optional[List[dict]] = None,