prefect-client 3.0.3__py3-none-any.whl → 3.0.5__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.
@@ -2,11 +2,9 @@ import asyncio
2
2
  from functools import wraps
3
3
  from typing import Any, Callable, Tuple, Type
4
4
 
5
- from prefect.logging.loggers import get_logger
5
+ from prefect._internal._logging import logger
6
6
  from prefect.utilities.math import clamped_poisson_interval
7
7
 
8
- logger = get_logger("retries")
9
-
10
8
 
11
9
  def exponential_backoff_with_jitter(
12
10
  attempt: int, base_delay: float, max_delay: float
@@ -70,7 +70,7 @@ def validate_schema(schema: dict):
70
70
  try:
71
71
  if schema is not None:
72
72
  # Most closely matches the schemas generated by pydantic
73
- jsonschema.Draft4Validator.check_schema(schema)
73
+ jsonschema.Draft202012Validator.check_schema(schema)
74
74
  except jsonschema.SchemaError as exc:
75
75
  raise ValueError(
76
76
  "The provided schema is not a valid json schema. Schema error:"
prefect/cache_policies.py CHANGED
@@ -219,7 +219,7 @@ class TaskSource(CachePolicy):
219
219
  except TypeError:
220
220
  lines = inspect.getsource(task_ctx.task.fn.__class__)
221
221
  except OSError as exc:
222
- if "could not get source code" in str(exc):
222
+ if "source code" in str(exc):
223
223
  lines = task_ctx.task.fn.__code__.co_code
224
224
  else:
225
225
  raise
prefect/client/cloud.py CHANGED
@@ -17,6 +17,7 @@ from prefect.client.schemas.objects import (
17
17
  from prefect.exceptions import ObjectNotFound, PrefectException
18
18
  from prefect.settings import (
19
19
  PREFECT_API_KEY,
20
+ PREFECT_API_URL,
20
21
  PREFECT_CLOUD_API_URL,
21
22
  PREFECT_UNIT_TEST_MODE,
22
23
  )
@@ -110,6 +111,14 @@ class CloudClient:
110
111
  )
111
112
  return workspaces
112
113
 
114
+ async def read_current_workspace(self) -> Workspace:
115
+ workspaces = await self.read_workspaces()
116
+ current_api_url = PREFECT_API_URL.value()
117
+ for workspace in workspaces:
118
+ if workspace.api_url() == current_api_url.rstrip("/"):
119
+ return workspace
120
+ raise ValueError("Current workspace not found")
121
+
113
122
  async def read_worker_metadata(self) -> Dict[str, Any]:
114
123
  response = await self.get(
115
124
  f"{self.workspace_base_url}/collections/work_pool_types"
@@ -1813,7 +1813,35 @@ class PrefectClient:
1813
1813
  response = await self._client.get(f"/deployments/name/{name}")
1814
1814
  except httpx.HTTPStatusError as e:
1815
1815
  if e.response.status_code == status.HTTP_404_NOT_FOUND:
1816
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1816
+ from prefect.utilities.text import fuzzy_match_string
1817
+
1818
+ deployments = await self.read_deployments()
1819
+ flow_name_map = {
1820
+ flow.id: flow.name
1821
+ for flow in await asyncio.gather(
1822
+ *[
1823
+ self.read_flow(flow_id)
1824
+ for flow_id in {d.flow_id for d in deployments}
1825
+ ]
1826
+ )
1827
+ }
1828
+
1829
+ raise prefect.exceptions.ObjectNotFound(
1830
+ http_exc=e,
1831
+ help_message=(
1832
+ f"Deployment {name!r} not found; did you mean {fuzzy_match!r}?"
1833
+ if (
1834
+ fuzzy_match := fuzzy_match_string(
1835
+ name,
1836
+ [
1837
+ f"{flow_name_map[d.flow_id]}/{d.name}"
1838
+ for d in deployments
1839
+ ],
1840
+ )
1841
+ )
1842
+ else f"Deployment {name!r} not found. Try `prefect deployment ls` to find available deployments."
1843
+ ),
1844
+ ) from e
1817
1845
  else:
1818
1846
  raise
1819
1847
 
@@ -2543,7 +2571,7 @@ class PrefectClient:
2543
2571
 
2544
2572
  async def read_logs(
2545
2573
  self,
2546
- log_filter: LogFilter = None,
2574
+ log_filter: Optional[LogFilter] = None,
2547
2575
  limit: Optional[int] = None,
2548
2576
  offset: Optional[int] = None,
2549
2577
  sort: LogSort = LogSort.TIMESTAMP_ASC,
@@ -231,7 +231,9 @@ class State(ObjectBaseModel, Generic[R]):
231
231
 
232
232
  Args:
233
233
  raise_on_failure: a boolean specifying whether to raise an exception
234
- if the state is of type `FAILED` and the underlying data is an exception
234
+ if the state is of type `FAILED` and the underlying data is an exception. When flow
235
+ was run in a different memory space (using `run_deployment`), this will only raise
236
+ if `fetch` is `True`.
235
237
  fetch: a boolean specifying whether to resolve references to persisted
236
238
  results into data. For synchronous users, this defaults to `True`.
237
239
  For asynchronous users, this defaults to `False` for backwards
@@ -297,6 +299,15 @@ class State(ObjectBaseModel, Generic[R]):
297
299
  >>> state = await my_flow(return_state=True)
298
300
  >>> await state.result()
299
301
  hello
302
+
303
+ Get the result with `raise_on_failure` from a flow run in a different memory space
304
+
305
+ >>> @flow
306
+ >>> async def my_flow():
307
+ >>> raise ValueError("oh no!")
308
+ >>> my_flow.deploy("my_deployment/my_flow")
309
+ >>> flow_run = run_deployment("my_deployment/my_flow")
310
+ >>> await flow_run.state.result(raise_on_failure=True, fetch=True) # Raises `ValueError("oh no!")`
300
311
  """
301
312
  from prefect.states import get_state_result
302
313
 
@@ -316,7 +327,11 @@ class State(ObjectBaseModel, Generic[R]):
316
327
  results should be sent to the API. Other data is only available locally.
317
328
  """
318
329
  from prefect.client.schemas.actions import StateCreate
319
- from prefect.results import BaseResult, ResultRecord, should_persist_result
330
+ from prefect.results import (
331
+ BaseResult,
332
+ ResultRecord,
333
+ should_persist_result,
334
+ )
320
335
 
321
336
  if isinstance(self.data, BaseResult):
322
337
  data = self.data
@@ -84,13 +84,13 @@ class Subscription(Generic[S]):
84
84
  AssertionError,
85
85
  websockets.exceptions.ConnectionClosedError,
86
86
  ) as e:
87
- if isinstance(e, AssertionError) or e.code == WS_1008_POLICY_VIOLATION:
87
+ if isinstance(e, AssertionError) or e.rcvd.code == WS_1008_POLICY_VIOLATION:
88
88
  if isinstance(e, AssertionError):
89
89
  reason = e.args[0]
90
90
  elif isinstance(e, websockets.exceptions.ConnectionClosedError):
91
- reason = e.reason
91
+ reason = e.rcvd.reason
92
92
 
93
- if isinstance(e, AssertionError) or e.code == WS_1008_POLICY_VIOLATION:
93
+ if isinstance(e, AssertionError) or e.rcvd.code == WS_1008_POLICY_VIOLATION:
94
94
  raise Exception(
95
95
  "Unable to authenticate to the subscription. Please "
96
96
  "ensure the provided `PREFECT_API_KEY` you are using is "
prefect/context.py CHANGED
@@ -11,7 +11,6 @@ import sys
11
11
  import warnings
12
12
  from contextlib import ExitStack, asynccontextmanager, contextmanager
13
13
  from contextvars import ContextVar, Token
14
- from pathlib import Path
15
14
  from typing import (
16
15
  TYPE_CHECKING,
17
16
  Any,
@@ -40,7 +39,7 @@ from prefect.client.schemas import FlowRun, TaskRun
40
39
  from prefect.events.worker import EventsWorker
41
40
  from prefect.exceptions import MissingContextError
42
41
  from prefect.results import ResultStore, get_default_persist_setting
43
- from prefect.settings import PREFECT_HOME, Profile, Settings
42
+ from prefect.settings import Profile, Settings
44
43
  from prefect.states import State
45
44
  from prefect.task_runners import TaskRunner
46
45
  from prefect.utilities.services import start_client_metrics_server
@@ -166,11 +165,13 @@ class ContextModel(BaseModel):
166
165
  new._token = None
167
166
  return new
168
167
 
169
- def serialize(self) -> Dict[str, Any]:
168
+ def serialize(self, include_secrets: bool = True) -> Dict[str, Any]:
170
169
  """
171
170
  Serialize the context model to a dictionary that can be pickled with cloudpickle.
172
171
  """
173
- return self.model_dump(exclude_unset=True)
172
+ return self.model_dump(
173
+ exclude_unset=True, context={"include_secrets": include_secrets}
174
+ )
174
175
 
175
176
 
176
177
  class SyncClientContext(ContextModel):
@@ -430,7 +431,7 @@ class TagsContext(ContextModel):
430
431
  # Return an empty `TagsContext` instead of `None` if no context exists
431
432
  return cls.__var__.get(TagsContext())
432
433
 
433
- __var__ = ContextVar("tags")
434
+ __var__: ContextVar = ContextVar("tags")
434
435
 
435
436
 
436
437
  class SettingsContext(ContextModel):
@@ -447,7 +448,7 @@ class SettingsContext(ContextModel):
447
448
  profile: Profile
448
449
  settings: Settings
449
450
 
450
- __var__ = ContextVar("settings")
451
+ __var__: ContextVar = ContextVar("settings")
451
452
 
452
453
  def __hash__(self) -> int:
453
454
  return hash(self.settings)
@@ -459,14 +460,11 @@ class SettingsContext(ContextModel):
459
460
  return_value = super().__enter__()
460
461
 
461
462
  try:
462
- prefect_home = Path(self.settings.value_of(PREFECT_HOME))
463
+ prefect_home = self.settings.home
463
464
  prefect_home.mkdir(mode=0o0700, exist_ok=True)
464
465
  except OSError:
465
466
  warnings.warn(
466
- (
467
- "Failed to create the Prefect home directory at "
468
- f"{self.settings.value_of(PREFECT_HOME)}"
469
- ),
467
+ (f"Failed to create the Prefect home directory at {prefect_home}"),
470
468
  stacklevel=2,
471
469
  )
472
470
 
@@ -609,12 +607,11 @@ def use_profile(
609
607
 
610
608
  # Create a copy of the profiles settings as we will mutate it
611
609
  profile_settings = profile.settings.copy()
612
-
613
610
  existing_context = SettingsContext.get()
614
611
  if existing_context and include_current_context:
615
612
  settings = existing_context.settings
616
613
  else:
617
- settings = prefect.settings.get_settings_from_env()
614
+ settings = Settings()
618
615
 
619
616
  if not override_environment_variables:
620
617
  for key in os.environ:
@@ -662,12 +659,7 @@ def root_settings_context():
662
659
  )
663
660
  active_name = "ephemeral"
664
661
 
665
- with use_profile(
666
- profiles[active_name],
667
- # Override environment variables if the profile was set by the CLI
668
- override_environment_variables=profile_source == "by command line argument",
669
- ) as settings_context:
670
- return settings_context
662
+ return SettingsContext(profile=profiles[active_name], settings=Settings())
671
663
 
672
664
  # Note the above context is exited and the global settings context is used by
673
665
  # an override in the `SettingsContext.get` method.
@@ -20,6 +20,7 @@ import yaml
20
20
  from ruamel.yaml import YAML
21
21
 
22
22
  from prefect.client.schemas.actions import DeploymentScheduleCreate
23
+ from prefect.client.schemas.objects import ConcurrencyLimitStrategy
23
24
  from prefect.client.schemas.schedules import IntervalSchedule
24
25
  from prefect.logging import get_logger
25
26
  from prefect.settings import PREFECT_DEBUG_MODE
@@ -277,6 +278,17 @@ def _format_deployment_for_saving_to_prefect_file(
277
278
 
278
279
  deployment["schedules"] = schedules
279
280
 
281
+ if deployment.get("concurrency_limit"):
282
+ concurrency_limit = deployment["concurrency_limit"]
283
+ if isinstance(concurrency_limit, dict):
284
+ if isinstance(
285
+ concurrency_limit["collision_strategy"], ConcurrencyLimitStrategy
286
+ ):
287
+ concurrency_limit["collision_strategy"] = str(
288
+ concurrency_limit["collision_strategy"].value
289
+ )
290
+ deployment["concurrency_limit"] = concurrency_limit
291
+
280
292
  return deployment
281
293
 
282
294
 
@@ -5,10 +5,12 @@ from uuid import UUID
5
5
  import anyio
6
6
  import pendulum
7
7
 
8
+ import prefect
8
9
  from prefect.client.schemas import FlowRun
9
10
  from prefect.client.utilities import inject_client
10
11
  from prefect.context import FlowRunContext, TaskRunContext
11
12
  from prefect.logging import get_logger
13
+ from prefect.results import BaseResult, ResultRecordMetadata
12
14
  from prefect.states import Pending, Scheduled
13
15
  from prefect.tasks import Task
14
16
  from prefect.utilities.asyncutils import sync_compatible
@@ -18,6 +20,12 @@ if TYPE_CHECKING:
18
20
  from prefect.client.orchestration import PrefectClient
19
21
  from prefect.client.schemas.objects import FlowRun
20
22
 
23
+ prefect.client.schemas.StateCreate.model_rebuild(
24
+ _types_namespace={
25
+ "BaseResult": BaseResult,
26
+ "ResultRecordMetadata": ResultRecordMetadata,
27
+ }
28
+ )
21
29
 
22
30
  logger = get_logger(__name__)
23
31
 
prefect/events/clients.py CHANGED
@@ -34,6 +34,7 @@ from prefect.settings import (
34
34
  PREFECT_API_KEY,
35
35
  PREFECT_API_URL,
36
36
  PREFECT_CLOUD_API_URL,
37
+ PREFECT_DEBUG_MODE,
37
38
  PREFECT_SERVER_ALLOW_EPHEMERAL_MODE,
38
39
  )
39
40
 
@@ -67,6 +68,18 @@ EVENT_WEBSOCKET_CHECKPOINTS = Counter(
67
68
  logger = get_logger(__name__)
68
69
 
69
70
 
71
+ def http_to_ws(url: str):
72
+ return url.replace("https://", "wss://").replace("http://", "ws://").rstrip("/")
73
+
74
+
75
+ def events_in_socket_from_api_url(url: str):
76
+ return http_to_ws(url) + "/events/in"
77
+
78
+
79
+ def events_out_socket_from_api_url(url: str):
80
+ return http_to_ws(url) + "/events/out"
81
+
82
+
70
83
  def get_events_client(
71
84
  reconnection_attempts: int = 10,
72
85
  checkpoint_every: int = 700,
@@ -251,12 +264,7 @@ class PrefectEventsClient(EventsClient):
251
264
  "api_url must be provided or set in the Prefect configuration"
252
265
  )
253
266
 
254
- self._events_socket_url = (
255
- api_url.replace("https://", "wss://")
256
- .replace("http://", "ws://")
257
- .rstrip("/")
258
- + "/events/in"
259
- )
267
+ self._events_socket_url = events_in_socket_from_api_url(api_url)
260
268
  self._connect = connect(self._events_socket_url)
261
269
  self._websocket = None
262
270
  self._reconnection_attempts = reconnection_attempts
@@ -285,11 +293,26 @@ class PrefectEventsClient(EventsClient):
285
293
  self._websocket = None
286
294
  await self._connect.__aexit__(None, None, None)
287
295
 
288
- self._websocket = await self._connect.__aenter__()
289
-
290
- # make sure we have actually connected
291
- pong = await self._websocket.ping()
292
- await pong
296
+ try:
297
+ self._websocket = await self._connect.__aenter__()
298
+ # make sure we have actually connected
299
+ pong = await self._websocket.ping()
300
+ await pong
301
+ except Exception as e:
302
+ # The client is frequently run in a background thread
303
+ # so we log an additional warning to ensure
304
+ # surfacing the error to the user.
305
+ logger.warning(
306
+ "Unable to connect to %r. "
307
+ "Please check your network settings to ensure websocket connections "
308
+ "to the API are allowed. Otherwise event data (including task run data) may be lost. "
309
+ "Reason: %s. "
310
+ "Set PREFECT_DEBUG_MODE=1 to see the full error.",
311
+ self._events_socket_url,
312
+ str(e),
313
+ exc_info=PREFECT_DEBUG_MODE,
314
+ )
315
+ raise
293
316
 
294
317
  events_to_resend = self._unconfirmed_events
295
318
  # Clear the unconfirmed events here, because they are going back through emit
@@ -412,7 +435,6 @@ class PrefectCloudEventsClient(PrefectEventsClient):
412
435
  reconnection_attempts=reconnection_attempts,
413
436
  checkpoint_every=checkpoint_every,
414
437
  )
415
-
416
438
  self._connect = connect(
417
439
  self._events_socket_url,
418
440
  extra_headers={"Authorization": f"bearer {api_key}"},
@@ -468,11 +490,7 @@ class PrefectEventSubscriber:
468
490
  self._filter = filter or EventFilter() # type: ignore[call-arg]
469
491
  self._seen_events = TTLCache(maxsize=SEEN_EVENTS_SIZE, ttl=SEEN_EVENTS_TTL)
470
492
 
471
- socket_url = (
472
- api_url.replace("https://", "wss://")
473
- .replace("http://", "ws://")
474
- .rstrip("/")
475
- ) + "/events/out"
493
+ socket_url = events_out_socket_from_api_url(api_url)
476
494
 
477
495
  logger.debug("Connecting to %s", socket_url)
478
496
 
@@ -527,11 +545,11 @@ class PrefectEventSubscriber:
527
545
  f"Reason: {e.args[0]}"
528
546
  )
529
547
  except ConnectionClosedError as e:
530
- raise Exception(
531
- "Unable to authenticate to the event stream. Please ensure the "
532
- "provided api_key you are using is valid for this environment. "
533
- f"Reason: {e.reason}"
534
- ) from e
548
+ reason = getattr(e.rcvd, "reason", None)
549
+ msg = "Unable to authenticate to the event stream. Please ensure the "
550
+ msg += "provided api_key you are using is valid for this environment. "
551
+ msg += f"Reason: {reason}" if reason else ""
552
+ raise Exception(msg) from e
535
553
 
536
554
  from prefect.events.filters import EventOccurredFilter
537
555
 
prefect/exceptions.py CHANGED
@@ -5,7 +5,7 @@ Prefect-specific exceptions.
5
5
  import inspect
6
6
  import traceback
7
7
  from types import ModuleType, TracebackType
8
- from typing import Callable, Dict, Iterable, List, Optional, Type
8
+ from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Type
9
9
 
10
10
  from httpx._exceptions import HTTPStatusError
11
11
  from pydantic import ValidationError
@@ -227,9 +227,19 @@ class ObjectNotFound(PrefectException):
227
227
  Raised when the client receives a 404 (not found) from the API.
228
228
  """
229
229
 
230
- def __init__(self, http_exc: Exception, *args, **kwargs):
230
+ def __init__(
231
+ self,
232
+ http_exc: Exception,
233
+ help_message: Optional[str] = None,
234
+ *args,
235
+ **kwargs,
236
+ ):
231
237
  self.http_exc = http_exc
232
- super().__init__(*args, **kwargs)
238
+ self.help_message = help_message
239
+ super().__init__(help_message, *args, **kwargs)
240
+
241
+ def __str__(self):
242
+ return self.help_message or super().__str__()
233
243
 
234
244
 
235
245
  class ObjectAlreadyExists(PrefectException):
@@ -424,3 +434,12 @@ class ConfigurationError(PrefectException):
424
434
  """
425
435
  Raised when a configuration is invalid.
426
436
  """
437
+
438
+
439
+ class ProfileSettingsValidationError(PrefectException):
440
+ """
441
+ Raised when a profile settings are invalid.
442
+ """
443
+
444
+ def __init__(self, errors: List[Tuple[Any, ValidationError]]) -> None:
445
+ self.errors = errors
prefect/filesystems.py CHANGED
@@ -5,7 +5,7 @@ from typing import Any, Dict, Optional
5
5
 
6
6
  import anyio
7
7
  import fsspec
8
- from pydantic import Field, SecretStr, field_validator
8
+ from pydantic import BaseModel, Field, SecretStr, field_validator
9
9
 
10
10
  from prefect._internal.schemas.validators import (
11
11
  stringify_path,
@@ -519,4 +519,29 @@ class SMB(WritableFileSystem, WritableDeploymentStorage):
519
519
  return await self.filesystem.write_path(path=path, content=content)
520
520
 
521
521
 
522
+ class NullFileSystem(BaseModel):
523
+ """
524
+ A file system that does not store any data.
525
+ """
526
+
527
+ async def read_path(self, path: str) -> None:
528
+ pass
529
+
530
+ async def write_path(self, path: str, content: bytes) -> None:
531
+ pass
532
+
533
+ async def get_directory(
534
+ self, from_path: Optional[str] = None, local_path: Optional[str] = None
535
+ ) -> None:
536
+ pass
537
+
538
+ async def put_directory(
539
+ self,
540
+ local_path: Optional[str] = None,
541
+ to_path: Optional[str] = None,
542
+ ignore_file: Optional[str] = None,
543
+ ) -> None:
544
+ pass
545
+
546
+
522
547
  __getattr__ = getattr_migration(__name__)
prefect/flow_engine.py CHANGED
@@ -290,13 +290,16 @@ class FlowRunEngine(Generic[P, R]):
290
290
  result_store: Optional[ResultStore] = None,
291
291
  ) -> State:
292
292
  context = FlowRunContext.get()
293
- terminal_state = run_coro_as_sync(
294
- exception_to_failed_state(
295
- exc,
296
- message=msg or "Flow run encountered an exception:",
297
- result_store=result_store or getattr(context, "result_store", None),
298
- write_result=True,
299
- )
293
+ terminal_state = cast(
294
+ State,
295
+ run_coro_as_sync(
296
+ exception_to_failed_state(
297
+ exc,
298
+ message=msg or "Flow run encountered an exception:",
299
+ result_store=result_store or getattr(context, "result_store", None),
300
+ write_result=True,
301
+ )
302
+ ),
300
303
  )
301
304
  state = self.set_state(terminal_state)
302
305
  if self.state.is_scheduled():
prefect/flows.py CHANGED
@@ -535,7 +535,7 @@ class Flow(Generic[P, R]):
535
535
 
536
536
  def resolve_block_reference(data: Any) -> Any:
537
537
  if isinstance(data, dict) and "$ref" in data:
538
- return Block.load_from_ref(data["$ref"])
538
+ return Block.load_from_ref(data["$ref"], _sync=True)
539
539
  return data
540
540
 
541
541
  try:
@@ -593,7 +593,7 @@ class Flow(Generic[P, R]):
593
593
  # Get the updated parameter dict with cast values from the model
594
594
  cast_parameters = {
595
595
  k: v
596
- for k, v in dict(model).items()
596
+ for k, v in model.__dict__.items()
597
597
  if k in model.model_fields_set or model.model_fields[k].default_factory
598
598
  }
599
599
  return cast_parameters
@@ -1256,6 +1256,15 @@ class Flow(Generic[P, R]):
1256
1256
  ) -> T:
1257
1257
  ...
1258
1258
 
1259
+ @overload
1260
+ def __call__(
1261
+ self: "Flow[P, Coroutine[Any, Any, T]]",
1262
+ *args: P.args,
1263
+ return_state: Literal[True],
1264
+ **kwargs: P.kwargs,
1265
+ ) -> Awaitable[State[T]]:
1266
+ ...
1267
+
1259
1268
  @overload
1260
1269
  def __call__(
1261
1270
  self: "Flow[P, T]",
@@ -13,7 +13,7 @@ import yaml
13
13
  from prefect.settings import (
14
14
  PREFECT_LOGGING_EXTRA_LOGGERS,
15
15
  PREFECT_LOGGING_SETTINGS_PATH,
16
- SETTING_VARIABLES,
16
+ get_current_settings,
17
17
  )
18
18
  from prefect.utilities.collections import dict_to_flatdict, flatdict_to_dict
19
19
 
@@ -31,18 +31,14 @@ def load_logging_config(path: Path) -> dict:
31
31
  """
32
32
  Loads logging configuration from a path allowing override from the environment
33
33
  """
34
+ current_settings = get_current_settings()
34
35
  template = string.Template(path.read_text())
36
+
35
37
  with warnings.catch_warnings():
36
38
  warnings.filterwarnings("ignore", category=DeprecationWarning)
37
39
  config = yaml.safe_load(
38
40
  # Substitute settings into the template in format $SETTING / ${SETTING}
39
- template.substitute(
40
- {
41
- setting.name: str(setting.value())
42
- for setting in SETTING_VARIABLES.values()
43
- if setting.value() is not None
44
- }
45
- )
41
+ template.substitute(current_settings.to_environment_variables())
46
42
  )
47
43
 
48
44
  # Load overrides from the environment
@@ -6,7 +6,7 @@ import traceback
6
6
  import uuid
7
7
  import warnings
8
8
  from contextlib import asynccontextmanager
9
- from typing import Any, Dict, List, Type, Union
9
+ from typing import Any, Dict, List, Optional, Type, Union
10
10
 
11
11
  import pendulum
12
12
  from rich.console import Console
@@ -30,7 +30,6 @@ from prefect.settings import (
30
30
  PREFECT_LOGGING_MARKUP,
31
31
  PREFECT_LOGGING_TO_API_BATCH_INTERVAL,
32
32
  PREFECT_LOGGING_TO_API_BATCH_SIZE,
33
- PREFECT_LOGGING_TO_API_ENABLED,
34
33
  PREFECT_LOGGING_TO_API_MAX_LOG_SIZE,
35
34
  PREFECT_LOGGING_TO_API_WHEN_MISSING_FLOW,
36
35
  )
@@ -134,7 +133,7 @@ class APILogHandler(logging.Handler):
134
133
  try:
135
134
  profile = prefect.context.get_settings_context()
136
135
 
137
- if not PREFECT_LOGGING_TO_API_ENABLED.value_from(profile.settings):
136
+ if not profile.settings.logging_to_api_enabled:
138
137
  return # Respect the global settings toggle
139
138
  if not getattr(record, "send_to_api", True):
140
139
  return # Do not send records that have opted out
@@ -242,7 +241,7 @@ class PrefectConsoleHandler(logging.StreamHandler):
242
241
  self,
243
242
  stream=None,
244
243
  highlighter: Highlighter = PrefectConsoleHighlighter,
245
- styles: Dict[str, str] = None,
244
+ styles: Optional[Dict[str, str]] = None,
246
245
  level: Union[int, str] = logging.NOTSET,
247
246
  ):
248
247
  """