prefect-client 3.0.7__py3-none-any.whl → 3.0.8__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.
- prefect/_version.py +3 -3
- prefect/settings.py +126 -194
- prefect/utilities/collections.py +0 -70
- {prefect_client-3.0.7.dist-info → prefect_client-3.0.8.dist-info}/METADATA +1 -1
- {prefect_client-3.0.7.dist-info → prefect_client-3.0.8.dist-info}/RECORD +8 -8
- {prefect_client-3.0.7.dist-info → prefect_client-3.0.8.dist-info}/LICENSE +0 -0
- {prefect_client-3.0.7.dist-info → prefect_client-3.0.8.dist-info}/WHEEL +0 -0
- {prefect_client-3.0.7.dist-info → prefect_client-3.0.8.dist-info}/top_level.txt +0 -0
prefect/_version.py
CHANGED
@@ -8,11 +8,11 @@ import json
|
|
8
8
|
|
9
9
|
version_json = '''
|
10
10
|
{
|
11
|
-
"date": "2024-10-
|
11
|
+
"date": "2024-10-10T10:17:25-0500",
|
12
12
|
"dirty": true,
|
13
13
|
"error": null,
|
14
|
-
"full-revisionid": "
|
15
|
-
"version": "3.0.
|
14
|
+
"full-revisionid": "0894bad49e256657cab8208205623c4c7b75ad1f",
|
15
|
+
"version": "3.0.8"
|
16
16
|
}
|
17
17
|
''' # END VERSION_JSON
|
18
18
|
|
prefect/settings.py
CHANGED
@@ -10,7 +10,6 @@ After https://github.com/pydantic/pydantic/issues/9789 is resolved, we will be a
|
|
10
10
|
for settings, at which point we will not need to use the "after" model_validator.
|
11
11
|
"""
|
12
12
|
|
13
|
-
import inspect
|
14
13
|
import os
|
15
14
|
import re
|
16
15
|
import sys
|
@@ -63,11 +62,7 @@ from typing_extensions import Literal, Self
|
|
63
62
|
|
64
63
|
from prefect.exceptions import ProfileSettingsValidationError
|
65
64
|
from prefect.types import ClientRetryExtraCodes, LogLevel
|
66
|
-
from prefect.utilities.collections import
|
67
|
-
deep_merge_dicts,
|
68
|
-
set_in_dict,
|
69
|
-
visit_collection,
|
70
|
-
)
|
65
|
+
from prefect.utilities.collections import visit_collection
|
71
66
|
from prefect.utilities.pydantic import handle_secret_render
|
72
67
|
|
73
68
|
T = TypeVar("T")
|
@@ -77,12 +72,10 @@ DEFAULT_PROFILES_PATH = Path(__file__).parent.joinpath("profiles.toml")
|
|
77
72
|
_SECRET_TYPES: Tuple[Type, ...] = (Secret, SecretStr)
|
78
73
|
|
79
74
|
|
80
|
-
def
|
75
|
+
def env_var_to_attr_name(env_var: str) -> str:
|
81
76
|
"""
|
82
|
-
Convert an environment variable name to
|
77
|
+
Convert an environment variable name to an attribute name.
|
83
78
|
"""
|
84
|
-
if SETTING_VARIABLES.get(env_var) is not None:
|
85
|
-
return SETTING_VARIABLES[env_var].accessor
|
86
79
|
return env_var.replace("PREFECT_", "").lower()
|
87
80
|
|
88
81
|
|
@@ -94,21 +87,19 @@ def is_test_mode() -> bool:
|
|
94
87
|
class Setting:
|
95
88
|
"""Mimics the old Setting object for compatibility with existing code."""
|
96
89
|
|
97
|
-
def __init__(
|
98
|
-
self, name: str, default: Any, type_: Any, accessor: Optional[str] = None
|
99
|
-
):
|
90
|
+
def __init__(self, name: str, default: Any, type_: Any):
|
100
91
|
self._name = name
|
101
92
|
self._default = default
|
102
93
|
self._type = type_
|
103
|
-
if accessor is None:
|
104
|
-
self.accessor = env_var_to_accessor(name)
|
105
|
-
else:
|
106
|
-
self.accessor = accessor
|
107
94
|
|
108
95
|
@property
|
109
96
|
def name(self):
|
110
97
|
return self._name
|
111
98
|
|
99
|
+
@property
|
100
|
+
def field_name(self):
|
101
|
+
return env_var_to_attr_name(self.name)
|
102
|
+
|
112
103
|
@property
|
113
104
|
def is_secret(self):
|
114
105
|
if self._type in _SECRET_TYPES:
|
@@ -128,19 +119,13 @@ class Setting:
|
|
128
119
|
else:
|
129
120
|
return None
|
130
121
|
|
131
|
-
|
132
|
-
current_value = get_current_settings()
|
133
|
-
for key in path:
|
134
|
-
current_value = getattr(current_value, key, None)
|
122
|
+
current_value = getattr(get_current_settings(), self.field_name)
|
135
123
|
if isinstance(current_value, _SECRET_TYPES):
|
136
124
|
return current_value.get_secret_value()
|
137
125
|
return current_value
|
138
126
|
|
139
127
|
def value_from(self: Self, settings: "Settings") -> Any:
|
140
|
-
|
141
|
-
current_value = settings
|
142
|
-
for key in path:
|
143
|
-
current_value = getattr(current_value, key, None)
|
128
|
+
current_value = getattr(settings, self.field_name)
|
144
129
|
if isinstance(current_value, _SECRET_TYPES):
|
145
130
|
return current_value.get_secret_value()
|
146
131
|
return current_value
|
@@ -172,7 +157,7 @@ def default_ui_url(settings: "Settings") -> Optional[str]:
|
|
172
157
|
return value
|
173
158
|
|
174
159
|
# Otherwise, infer a value from the API URL
|
175
|
-
ui_url = api_url = settings.
|
160
|
+
ui_url = api_url = settings.api_url
|
176
161
|
|
177
162
|
if not api_url:
|
178
163
|
return None
|
@@ -258,7 +243,7 @@ def warn_on_misconfigured_api_url(values):
|
|
258
243
|
"""
|
259
244
|
Validator for settings warning if the API URL is misconfigured.
|
260
245
|
"""
|
261
|
-
api_url = values
|
246
|
+
api_url = values["api_url"]
|
262
247
|
if api_url is not None:
|
263
248
|
misconfigured_mappings = {
|
264
249
|
"app.prefect.cloud": (
|
@@ -403,9 +388,7 @@ class ProfileSettingsTomlLoader(PydanticBaseSettingsSource):
|
|
403
388
|
self, field: FieldInfo, field_name: str
|
404
389
|
) -> Tuple[Any, str, bool]:
|
405
390
|
"""Concrete implementation to get the field value from the profile settings"""
|
406
|
-
value = self.profile_settings.get(
|
407
|
-
f"{self.config.get('env_prefix','')}{field_name.upper()}"
|
408
|
-
)
|
391
|
+
value = self.profile_settings.get(f"PREFECT_{field_name.upper()}")
|
409
392
|
return value, field_name, self.field_is_complex(field)
|
410
393
|
|
411
394
|
def __call__(self) -> Dict[str, Any]:
|
@@ -425,7 +408,21 @@ class ProfileSettingsTomlLoader(PydanticBaseSettingsSource):
|
|
425
408
|
|
426
409
|
###########################################################################
|
427
410
|
# Settings
|
428
|
-
|
411
|
+
|
412
|
+
|
413
|
+
class Settings(BaseSettings):
|
414
|
+
"""
|
415
|
+
Settings for Prefect using Pydantic settings.
|
416
|
+
|
417
|
+
See https://docs.pydantic.dev/latest/concepts/pydantic_settings
|
418
|
+
"""
|
419
|
+
|
420
|
+
model_config = SettingsConfigDict(
|
421
|
+
env_file=".env",
|
422
|
+
env_prefix="PREFECT_",
|
423
|
+
extra="ignore",
|
424
|
+
)
|
425
|
+
|
429
426
|
@classmethod
|
430
427
|
def settings_customise_sources(
|
431
428
|
cls,
|
@@ -450,104 +447,6 @@ class PrefectBaseSettings(BaseSettings):
|
|
450
447
|
ProfileSettingsTomlLoader(settings_cls),
|
451
448
|
)
|
452
449
|
|
453
|
-
@classmethod
|
454
|
-
def valid_setting_names(cls) -> Set[str]:
|
455
|
-
"""
|
456
|
-
A set of valid setting names, e.g. "PREFECT_API_URL" or "PREFECT_API_KEY".
|
457
|
-
"""
|
458
|
-
settings_fields = set()
|
459
|
-
for field_name, field in cls.model_fields.items():
|
460
|
-
if inspect.isclass(field.annotation) and issubclass(
|
461
|
-
field.annotation, PrefectBaseSettings
|
462
|
-
):
|
463
|
-
settings_fields.update(field.annotation.valid_setting_names())
|
464
|
-
else:
|
465
|
-
settings_fields.add(
|
466
|
-
f"{cls.model_config.get('env_prefix')}{field_name.upper()}"
|
467
|
-
)
|
468
|
-
return settings_fields
|
469
|
-
|
470
|
-
def to_environment_variables(
|
471
|
-
self,
|
472
|
-
exclude_unset: bool = False,
|
473
|
-
include_secrets: bool = True,
|
474
|
-
) -> Dict[str, str]:
|
475
|
-
"""Convert the settings object to a dictionary of environment variables."""
|
476
|
-
|
477
|
-
env: Dict[str, Any] = self.model_dump(
|
478
|
-
exclude_unset=exclude_unset,
|
479
|
-
mode="json",
|
480
|
-
context={"include_secrets": include_secrets},
|
481
|
-
)
|
482
|
-
env_variables = {}
|
483
|
-
for key, value in env.items():
|
484
|
-
if isinstance(value, dict) and isinstance(
|
485
|
-
child_settings := getattr(self, key), PrefectBaseSettings
|
486
|
-
):
|
487
|
-
child_env = child_settings.to_environment_variables(
|
488
|
-
exclude_unset=exclude_unset,
|
489
|
-
include_secrets=include_secrets,
|
490
|
-
)
|
491
|
-
env_variables.update(child_env)
|
492
|
-
elif value is not None:
|
493
|
-
env_variables[
|
494
|
-
f"{self.model_config.get('env_prefix')}{key.upper()}"
|
495
|
-
] = str(value)
|
496
|
-
return env_variables
|
497
|
-
|
498
|
-
|
499
|
-
class APISettings(PrefectBaseSettings):
|
500
|
-
"""
|
501
|
-
Settings for interacting with the Prefect API
|
502
|
-
"""
|
503
|
-
|
504
|
-
model_config = SettingsConfigDict(
|
505
|
-
env_prefix="PREFECT_API_", env_file=".env", extra="ignore"
|
506
|
-
)
|
507
|
-
url: Optional[str] = Field(
|
508
|
-
default=None,
|
509
|
-
description="The URL of the Prefect API. If not set, the client will attempt to infer it.",
|
510
|
-
)
|
511
|
-
key: Optional[SecretStr] = Field(
|
512
|
-
default=None,
|
513
|
-
description="The API key used for authentication with the Prefect API. Should be kept secret.",
|
514
|
-
)
|
515
|
-
tls_insecure_skip_verify: bool = Field(
|
516
|
-
default=False,
|
517
|
-
description="If `True`, disables SSL checking to allow insecure requests. This is recommended only during development, e.g. when using self-signed certificates.",
|
518
|
-
)
|
519
|
-
ssl_cert_file: Optional[str] = Field(
|
520
|
-
default=os.environ.get("SSL_CERT_FILE"),
|
521
|
-
description="This configuration settings option specifies the path to an SSL certificate file.",
|
522
|
-
)
|
523
|
-
enable_http2: bool = Field(
|
524
|
-
default=False,
|
525
|
-
description="If true, enable support for HTTP/2 for communicating with an API. If the API does not support HTTP/2, this will have no effect and connections will be made via HTTP/1.1.",
|
526
|
-
)
|
527
|
-
request_timeout: float = Field(
|
528
|
-
default=60.0,
|
529
|
-
description="The default timeout for requests to the API",
|
530
|
-
)
|
531
|
-
default_limit: int = Field(
|
532
|
-
default=200,
|
533
|
-
description="The default limit applied to queries that can return multiple objects, such as `POST /flow_runs/filter`.",
|
534
|
-
)
|
535
|
-
|
536
|
-
|
537
|
-
class Settings(PrefectBaseSettings):
|
538
|
-
"""
|
539
|
-
Settings for Prefect using Pydantic settings.
|
540
|
-
|
541
|
-
See https://docs.pydantic.dev/latest/concepts/pydantic_settings
|
542
|
-
"""
|
543
|
-
|
544
|
-
model_config = SettingsConfigDict(
|
545
|
-
env_file=".env",
|
546
|
-
env_prefix="PREFECT_",
|
547
|
-
env_nested_delimiter=None,
|
548
|
-
extra="ignore",
|
549
|
-
)
|
550
|
-
|
551
450
|
###########################################################################
|
552
451
|
# CLI
|
553
452
|
|
@@ -605,9 +504,33 @@ class Settings(PrefectBaseSettings):
|
|
605
504
|
###########################################################################
|
606
505
|
# API settings
|
607
506
|
|
608
|
-
|
609
|
-
|
610
|
-
description="
|
507
|
+
api_url: Optional[str] = Field(
|
508
|
+
default=None,
|
509
|
+
description="The URL of the Prefect API. If not set, the client will attempt to infer it.",
|
510
|
+
)
|
511
|
+
api_key: Optional[SecretStr] = Field(
|
512
|
+
default=None,
|
513
|
+
description="The API key used for authentication with the Prefect API. Should be kept secret.",
|
514
|
+
)
|
515
|
+
|
516
|
+
api_tls_insecure_skip_verify: bool = Field(
|
517
|
+
default=False,
|
518
|
+
description="If `True`, disables SSL checking to allow insecure requests. This is recommended only during development, e.g. when using self-signed certificates.",
|
519
|
+
)
|
520
|
+
|
521
|
+
api_ssl_cert_file: Optional[str] = Field(
|
522
|
+
default=os.environ.get("SSL_CERT_FILE"),
|
523
|
+
description="This configuration settings option specifies the path to an SSL certificate file.",
|
524
|
+
)
|
525
|
+
|
526
|
+
api_enable_http2: bool = Field(
|
527
|
+
default=False,
|
528
|
+
description="If true, enable support for HTTP/2 for communicating with an API. If the API does not support HTTP/2, this will have no effect and connections will be made via HTTP/1.1.",
|
529
|
+
)
|
530
|
+
|
531
|
+
api_request_timeout: float = Field(
|
532
|
+
default=60.0,
|
533
|
+
description="The default timeout for requests to the API",
|
611
534
|
)
|
612
535
|
|
613
536
|
api_blocks_register_on_start: bool = Field(
|
@@ -1506,7 +1429,7 @@ class Settings(PrefectBaseSettings):
|
|
1506
1429
|
|
1507
1430
|
def __getattribute__(self, name: str) -> Any:
|
1508
1431
|
if name.startswith("PREFECT_"):
|
1509
|
-
field_name =
|
1432
|
+
field_name = env_var_to_attr_name(name)
|
1510
1433
|
warnings.warn(
|
1511
1434
|
f"Accessing `Settings().{name}` is deprecated. Use `Settings().{field_name}` instead.",
|
1512
1435
|
DeprecationWarning,
|
@@ -1533,10 +1456,8 @@ class Settings(PrefectBaseSettings):
|
|
1533
1456
|
self.ui_url = default_ui_url(self)
|
1534
1457
|
self.__pydantic_fields_set__.remove("ui_url")
|
1535
1458
|
if self.ui_api_url is None:
|
1536
|
-
if self.
|
1537
|
-
self.ui_api_url = self.
|
1538
|
-
if self.api.url:
|
1539
|
-
self.ui_api_url = self.api.url
|
1459
|
+
if self.api_url:
|
1460
|
+
self.ui_api_url = self.api_url
|
1540
1461
|
self.__pydantic_fields_set__.remove("ui_api_url")
|
1541
1462
|
else:
|
1542
1463
|
self.ui_api_url = (
|
@@ -1600,6 +1521,16 @@ class Settings(PrefectBaseSettings):
|
|
1600
1521
|
##########################################################################
|
1601
1522
|
# Settings methods
|
1602
1523
|
|
1524
|
+
@classmethod
|
1525
|
+
def valid_setting_names(cls) -> Set[str]:
|
1526
|
+
"""
|
1527
|
+
A set of valid setting names, e.g. "PREFECT_API_URL" or "PREFECT_API_KEY".
|
1528
|
+
"""
|
1529
|
+
return set(
|
1530
|
+
f"{cls.model_config.get('env_prefix')}{key.upper()}"
|
1531
|
+
for key in cls.model_fields.keys()
|
1532
|
+
)
|
1533
|
+
|
1603
1534
|
def copy_with_update(
|
1604
1535
|
self: Self,
|
1605
1536
|
updates: Optional[Mapping[Setting, Any]] = None,
|
@@ -1619,26 +1550,14 @@ class Settings(PrefectBaseSettings):
|
|
1619
1550
|
Returns:
|
1620
1551
|
A new Settings object.
|
1621
1552
|
"""
|
1622
|
-
|
1623
|
-
for r in restore_defaults or []:
|
1624
|
-
set_in_dict(restore_defaults_obj, r.accessor, True)
|
1553
|
+
restore_defaults_names = set(r.field_name for r in restore_defaults or [])
|
1625
1554
|
updates = updates or {}
|
1626
1555
|
set_defaults = set_defaults or {}
|
1627
1556
|
|
1628
|
-
set_defaults_obj = {}
|
1629
|
-
for setting, value in set_defaults.items():
|
1630
|
-
set_in_dict(set_defaults_obj, setting.accessor, value)
|
1631
|
-
|
1632
|
-
updates_obj = {}
|
1633
|
-
for setting, value in updates.items():
|
1634
|
-
set_in_dict(updates_obj, setting.accessor, value)
|
1635
|
-
|
1636
1557
|
new_settings = self.__class__(
|
1637
|
-
**
|
1638
|
-
|
1639
|
-
|
1640
|
-
updates_obj,
|
1641
|
-
)
|
1558
|
+
**{setting.field_name: value for setting, value in set_defaults.items()}
|
1559
|
+
| self.model_dump(exclude_unset=True, exclude=restore_defaults_names)
|
1560
|
+
| {setting.field_name: value for setting, value in updates.items()}
|
1642
1561
|
)
|
1643
1562
|
return new_settings
|
1644
1563
|
|
@@ -1650,6 +1569,37 @@ class Settings(PrefectBaseSettings):
|
|
1650
1569
|
env_variables = self.to_environment_variables()
|
1651
1570
|
return str(hash(tuple((key, value) for key, value in env_variables.items())))
|
1652
1571
|
|
1572
|
+
def to_environment_variables(
|
1573
|
+
self,
|
1574
|
+
include: Optional[Iterable[Setting]] = None,
|
1575
|
+
exclude: Optional[Iterable[Setting]] = None,
|
1576
|
+
exclude_unset: bool = False,
|
1577
|
+
include_secrets: bool = True,
|
1578
|
+
) -> Dict[str, str]:
|
1579
|
+
"""Convert the settings object to a dictionary of environment variables."""
|
1580
|
+
included_names = {s.field_name for s in include} if include else None
|
1581
|
+
excluded_names = {s.field_name for s in exclude} if exclude else None
|
1582
|
+
|
1583
|
+
if exclude_unset:
|
1584
|
+
if included_names is None:
|
1585
|
+
included_names = set(self.model_dump(exclude_unset=True).keys())
|
1586
|
+
else:
|
1587
|
+
included_names.intersection_update(
|
1588
|
+
{key for key in self.model_dump(exclude_unset=True)}
|
1589
|
+
)
|
1590
|
+
|
1591
|
+
env: Dict[str, Any] = self.model_dump(
|
1592
|
+
include=included_names,
|
1593
|
+
exclude=excluded_names,
|
1594
|
+
mode="json",
|
1595
|
+
context={"include_secrets": include_secrets},
|
1596
|
+
)
|
1597
|
+
return {
|
1598
|
+
f"{self.model_config.get('env_prefix')}{key.upper()}": str(value)
|
1599
|
+
for key, value in env.items()
|
1600
|
+
if value is not None
|
1601
|
+
}
|
1602
|
+
|
1653
1603
|
@model_serializer(
|
1654
1604
|
mode="wrap", when_used="always"
|
1655
1605
|
) # TODO: reconsider `when_used` default for more control
|
@@ -1659,11 +1609,7 @@ class Settings(PrefectBaseSettings):
|
|
1659
1609
|
ctx = info.context
|
1660
1610
|
jsonable_self = handler(self)
|
1661
1611
|
if ctx and ctx.get("include_secrets") is True:
|
1662
|
-
dump_kwargs = dict(
|
1663
|
-
include=info.include,
|
1664
|
-
exclude=info.exclude,
|
1665
|
-
exclude_unset=info.exclude_unset,
|
1666
|
-
)
|
1612
|
+
dump_kwargs = dict(include=info.include, exclude=info.exclude)
|
1667
1613
|
jsonable_self.update(
|
1668
1614
|
{
|
1669
1615
|
field_name: visit_collection(
|
@@ -1693,7 +1639,12 @@ def _cast_settings(
|
|
1693
1639
|
for k, value in settings.items():
|
1694
1640
|
try:
|
1695
1641
|
if isinstance(k, str):
|
1696
|
-
|
1642
|
+
field = Settings.model_fields[env_var_to_attr_name(k)]
|
1643
|
+
setting = Setting(
|
1644
|
+
name=k,
|
1645
|
+
default=field.default,
|
1646
|
+
type_=field.annotation,
|
1647
|
+
)
|
1697
1648
|
else:
|
1698
1649
|
setting = k
|
1699
1650
|
casted_settings[setting] = value
|
@@ -1788,16 +1739,9 @@ class Profile(BaseModel):
|
|
1788
1739
|
errors: List[Tuple[Setting, ValidationError]] = []
|
1789
1740
|
for setting, value in self.settings.items():
|
1790
1741
|
try:
|
1791
|
-
|
1792
|
-
|
1793
|
-
|
1794
|
-
annotation = model_fields[section].annotation
|
1795
|
-
if inspect.isclass(annotation) and issubclass(
|
1796
|
-
annotation, BaseSettings
|
1797
|
-
):
|
1798
|
-
model_fields = annotation.model_fields
|
1799
|
-
|
1800
|
-
TypeAdapter(annotation).validate_python(value)
|
1742
|
+
TypeAdapter(
|
1743
|
+
Settings.model_fields[setting.field_name].annotation
|
1744
|
+
).validate_python(value)
|
1801
1745
|
except ValidationError as e:
|
1802
1746
|
errors.append((setting, e))
|
1803
1747
|
if errors:
|
@@ -2114,38 +2058,26 @@ def update_current_profile(
|
|
2114
2058
|
# Allow traditional env var access
|
2115
2059
|
|
2116
2060
|
|
2117
|
-
|
2118
|
-
|
2119
|
-
|
2120
|
-
|
2121
|
-
|
2122
|
-
|
2123
|
-
|
2124
|
-
|
2125
|
-
|
2126
|
-
|
2127
|
-
|
2128
|
-
else f"{accessor_prefix}.{field_name}"
|
2129
|
-
)
|
2130
|
-
settings_fields.update(_collect_settings_fields(field.annotation, accessor))
|
2131
|
-
else:
|
2132
|
-
accessor = (
|
2133
|
-
field_name
|
2134
|
-
if accessor_prefix is None
|
2135
|
-
else f"{accessor_prefix}.{field_name}"
|
2136
|
-
)
|
2061
|
+
class _SettingsDict(dict):
|
2062
|
+
"""allow either `field_name` or `ENV_VAR_NAME` access
|
2063
|
+
```
|
2064
|
+
d = _SettingsDict(Settings)
|
2065
|
+
d["api_url"] == d["PREFECT_API_URL"]
|
2066
|
+
```
|
2067
|
+
"""
|
2068
|
+
|
2069
|
+
def __init__(self: Self, settings_cls: Type[BaseSettings]):
|
2070
|
+
super().__init__()
|
2071
|
+
for field_name, field in settings_cls.model_fields.items():
|
2137
2072
|
setting = Setting(
|
2138
2073
|
name=f"{settings_cls.model_config.get('env_prefix')}{field_name.upper()}",
|
2139
2074
|
default=field.default,
|
2140
2075
|
type_=field.annotation,
|
2141
|
-
accessor=accessor,
|
2142
2076
|
)
|
2143
|
-
|
2144
|
-
settings_fields[setting.accessor] = setting
|
2145
|
-
return settings_fields
|
2077
|
+
self[field_name] = self[setting.name] = setting
|
2146
2078
|
|
2147
2079
|
|
2148
|
-
SETTING_VARIABLES: dict[str, Setting] =
|
2080
|
+
SETTING_VARIABLES: dict[str, Setting] = _SettingsDict(Settings)
|
2149
2081
|
|
2150
2082
|
|
2151
2083
|
def __getattr__(name: str) -> Setting:
|
prefect/utilities/collections.py
CHANGED
@@ -513,73 +513,3 @@ def get_from_dict(dct: Dict, keys: Union[str, List[str]], default: Any = None) -
|
|
513
513
|
return dct
|
514
514
|
except (TypeError, KeyError, IndexError):
|
515
515
|
return default
|
516
|
-
|
517
|
-
|
518
|
-
def set_in_dict(dct: Dict, keys: Union[str, List[str]], value: Any):
|
519
|
-
"""
|
520
|
-
Sets a value in a nested dictionary using a sequence of keys.
|
521
|
-
|
522
|
-
This function allows to set a value in a deeply nested structure
|
523
|
-
of dictionaries and lists using either a dot-separated string or a list
|
524
|
-
of keys. If a requested key does not exist, the function will create it as
|
525
|
-
a new dictionary.
|
526
|
-
|
527
|
-
Args:
|
528
|
-
dct: The dictionary to set the value in.
|
529
|
-
keys: The sequence of keys to use for access. Can be a
|
530
|
-
dot-separated string or a list of keys.
|
531
|
-
value: The value to set in the dictionary.
|
532
|
-
|
533
|
-
Returns:
|
534
|
-
The modified dictionary with the value set at the specified key path.
|
535
|
-
|
536
|
-
Raises:
|
537
|
-
KeyError: If the key path exists and is not a dictionary.
|
538
|
-
"""
|
539
|
-
if isinstance(keys, str):
|
540
|
-
keys = keys.replace("[", ".").replace("]", "").split(".")
|
541
|
-
for k in keys[:-1]:
|
542
|
-
if not isinstance(dct.get(k, {}), dict):
|
543
|
-
raise KeyError(f"Key path exists and contains a non-dict value: {keys}")
|
544
|
-
if k not in dct:
|
545
|
-
dct[k] = {}
|
546
|
-
dct = dct[k]
|
547
|
-
dct[keys[-1]] = value
|
548
|
-
|
549
|
-
|
550
|
-
def deep_merge(dct: Dict, merge: Dict):
|
551
|
-
"""
|
552
|
-
Recursively merges `merge` into `dct`.
|
553
|
-
|
554
|
-
Args:
|
555
|
-
dct: The dictionary to merge into.
|
556
|
-
merge: The dictionary to merge from.
|
557
|
-
|
558
|
-
Returns:
|
559
|
-
A new dictionary with the merged contents.
|
560
|
-
"""
|
561
|
-
result = dct.copy() # Start with keys and values from `dct`
|
562
|
-
for key, value in merge.items():
|
563
|
-
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
|
564
|
-
# If both values are dictionaries, merge them recursively
|
565
|
-
result[key] = deep_merge(result[key], value)
|
566
|
-
else:
|
567
|
-
# Otherwise, overwrite with the new value
|
568
|
-
result[key] = value
|
569
|
-
return result
|
570
|
-
|
571
|
-
|
572
|
-
def deep_merge_dicts(*dicts):
|
573
|
-
"""
|
574
|
-
Recursively merges multiple dictionaries.
|
575
|
-
|
576
|
-
Args:
|
577
|
-
dicts: The dictionaries to merge.
|
578
|
-
|
579
|
-
Returns:
|
580
|
-
A new dictionary with the merged contents.
|
581
|
-
"""
|
582
|
-
result = {}
|
583
|
-
for dictionary in dicts:
|
584
|
-
result = deep_merge(result, dictionary)
|
585
|
-
return result
|
@@ -1,6 +1,6 @@
|
|
1
1
|
prefect/.prefectignore,sha256=awSprvKT0vI8a64mEOLrMxhxqcO-b0ERQeYpA2rNKVQ,390
|
2
2
|
prefect/__init__.py,sha256=2jnhqiLx5v3iQ2JeTVp4V85uSC_3Yg3HlE05JjjQSGc,3223
|
3
|
-
prefect/_version.py,sha256=
|
3
|
+
prefect/_version.py,sha256=KRrx9_zdQ4japuLlN9Lgz-NJqRSHpWPy5o2-HKoeKTU,496
|
4
4
|
prefect/agent.py,sha256=BOVVY5z-vUIQ2u8LwMTXDaNys2fjOZSS5YGDwJmTQjI,230
|
5
5
|
prefect/artifacts.py,sha256=dsxFWmdg2r9zbHM3KgKOR5YbJ29_dXUYF9kipJpbxkE,13009
|
6
6
|
prefect/automations.py,sha256=NlQ62GPJzy-gnWQqX7c6CQJKw7p60WLGDAFcy82vtg4,5613
|
@@ -19,7 +19,7 @@ prefect/profiles.toml,sha256=kTvqDNMzjH3fsm5OEI-NKY4dMmipor5EvQXRB6rPEjY,522
|
|
19
19
|
prefect/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
20
|
prefect/results.py,sha256=-V_JRaWeY2WXWhY2d_zL7KVIro660mIU6F3heNaih0o,47391
|
21
21
|
prefect/serializers.py,sha256=Lo41EM0_qGzcfB_63390Izeo3DdK6cY6VZfxa9hpSGQ,8712
|
22
|
-
prefect/settings.py,sha256=
|
22
|
+
prefect/settings.py,sha256=032alJnUkrWxXnHFyZD-p6cPN09x9bIoK7q7qi1VSxs,73558
|
23
23
|
prefect/states.py,sha256=2lysq6X5AvqPfE3eD3D0HYt-KpFA2OUgA0c4ZQ22A_U,24906
|
24
24
|
prefect/task_engine.py,sha256=gjSpoLecy1gyPavNPOw40DFZonvqXIzLLqiGooqyhM0,57945
|
25
25
|
prefect/task_runners.py,sha256=Ef8JENamKGWGyAGkuB_QwSLGWbWKRsmvemZGDkyRWCQ,15021
|
@@ -166,7 +166,7 @@ prefect/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
166
166
|
prefect/utilities/annotations.py,sha256=Ocj2s5zhnGr8uXUBnOli-OrybXVJdu4-uZvCRpKpV_Q,2820
|
167
167
|
prefect/utilities/asyncutils.py,sha256=jWj2bMx2yLOd2QTouMOQFOtqy2DLnfefJNlujbMZZYU,20198
|
168
168
|
prefect/utilities/callables.py,sha256=53yqDgkx7Zb_uS4v1_ltrPrvdqjwkHvqK8A0E958dFk,24859
|
169
|
-
prefect/utilities/collections.py,sha256=
|
169
|
+
prefect/utilities/collections.py,sha256=_YVHZfT49phrXq7aDUmn4pqWwEtJQTPy2nJD0M1sz0o,17264
|
170
170
|
prefect/utilities/compat.py,sha256=mNQZDnzyKaOqy-OV-DnmH_dc7CNF5nQgW_EsA4xMr7g,906
|
171
171
|
prefect/utilities/context.py,sha256=BThuUW94-IYgFYTeMIM9KMo8ShT3oiI7w5ajZHzU1j0,1377
|
172
172
|
prefect/utilities/dispatch.py,sha256=EthEmyRwv-4W8z2BJclrsOQHJ_pJoZYL0t2cyYPEa-E,6098
|
@@ -197,8 +197,8 @@ prefect/workers/cloud.py,sha256=BOVVY5z-vUIQ2u8LwMTXDaNys2fjOZSS5YGDwJmTQjI,230
|
|
197
197
|
prefect/workers/process.py,sha256=tcJ3fbiraLCfpVGpv8dOHwMSfVzeD_kyguUOvPuIz6I,19796
|
198
198
|
prefect/workers/server.py,sha256=lgh2FfSuaNU7b6HPxSFm8JtKvAvHsZGkiOo4y4tW1Cw,2022
|
199
199
|
prefect/workers/utilities.py,sha256=VfPfAlGtTuDj0-Kb8WlMgAuOfgXCdrGAnKMapPSBrwc,2483
|
200
|
-
prefect_client-3.0.
|
201
|
-
prefect_client-3.0.
|
202
|
-
prefect_client-3.0.
|
203
|
-
prefect_client-3.0.
|
204
|
-
prefect_client-3.0.
|
200
|
+
prefect_client-3.0.8.dist-info/LICENSE,sha256=MCxsn8osAkzfxKC4CC_dLcUkU8DZLkyihZ8mGs3Ah3Q,11357
|
201
|
+
prefect_client-3.0.8.dist-info/METADATA,sha256=J7oDkuYD2cIsUOZE0aupaZLCBb3r2s6ah04ZLt2K0Ks,7332
|
202
|
+
prefect_client-3.0.8.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
|
203
|
+
prefect_client-3.0.8.dist-info/top_level.txt,sha256=MJZYJgFdbRc2woQCeB4vM6T33tr01TmkEhRcns6H_H4,8
|
204
|
+
prefect_client-3.0.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|