prefect-client 3.0.0rc18__py3-none-any.whl → 3.0.0rc20__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 (55) hide show
  1. prefect/__init__.py +0 -3
  2. prefect/_internal/concurrency/services.py +14 -0
  3. prefect/_internal/schemas/bases.py +1 -0
  4. prefect/blocks/core.py +41 -30
  5. prefect/blocks/system.py +48 -12
  6. prefect/client/cloud.py +56 -7
  7. prefect/client/collections.py +1 -1
  8. prefect/client/orchestration.py +111 -8
  9. prefect/client/schemas/objects.py +40 -2
  10. prefect/concurrency/asyncio.py +8 -2
  11. prefect/concurrency/services.py +16 -6
  12. prefect/concurrency/sync.py +4 -1
  13. prefect/concurrency/v1/__init__.py +0 -0
  14. prefect/concurrency/v1/asyncio.py +143 -0
  15. prefect/concurrency/v1/context.py +27 -0
  16. prefect/concurrency/v1/events.py +61 -0
  17. prefect/concurrency/v1/services.py +116 -0
  18. prefect/concurrency/v1/sync.py +92 -0
  19. prefect/context.py +2 -2
  20. prefect/deployments/flow_runs.py +0 -7
  21. prefect/deployments/runner.py +11 -0
  22. prefect/events/clients.py +41 -0
  23. prefect/events/related.py +72 -73
  24. prefect/events/utilities.py +2 -0
  25. prefect/events/worker.py +12 -3
  26. prefect/exceptions.py +6 -0
  27. prefect/flow_engine.py +5 -0
  28. prefect/flows.py +9 -2
  29. prefect/logging/handlers.py +4 -1
  30. prefect/main.py +8 -6
  31. prefect/records/base.py +74 -18
  32. prefect/records/filesystem.py +207 -0
  33. prefect/records/memory.py +16 -3
  34. prefect/records/result_store.py +19 -14
  35. prefect/results.py +232 -169
  36. prefect/runner/runner.py +7 -4
  37. prefect/settings.py +14 -15
  38. prefect/states.py +73 -18
  39. prefect/task_engine.py +127 -221
  40. prefect/task_worker.py +7 -39
  41. prefect/tasks.py +0 -7
  42. prefect/transactions.py +89 -27
  43. prefect/utilities/annotations.py +4 -3
  44. prefect/utilities/asyncutils.py +4 -4
  45. prefect/utilities/callables.py +1 -3
  46. prefect/utilities/dispatch.py +16 -11
  47. prefect/utilities/engine.py +1 -4
  48. prefect/utilities/schema_tools/hydration.py +13 -0
  49. prefect/workers/base.py +78 -18
  50. {prefect_client-3.0.0rc18.dist-info → prefect_client-3.0.0rc20.dist-info}/METADATA +3 -4
  51. {prefect_client-3.0.0rc18.dist-info → prefect_client-3.0.0rc20.dist-info}/RECORD +54 -48
  52. prefect/manifests.py +0 -21
  53. {prefect_client-3.0.0rc18.dist-info → prefect_client-3.0.0rc20.dist-info}/LICENSE +0 -0
  54. {prefect_client-3.0.0rc18.dist-info → prefect_client-3.0.0rc20.dist-info}/WHEEL +0 -0
  55. {prefect_client-3.0.0rc18.dist-info → prefect_client-3.0.0rc20.dist-info}/top_level.txt +0 -0
prefect/results.py CHANGED
@@ -17,7 +17,15 @@ from typing import (
17
17
  )
18
18
  from uuid import UUID
19
19
 
20
- from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, ValidationError
20
+ from pydantic import (
21
+ BaseModel,
22
+ ConfigDict,
23
+ Field,
24
+ PrivateAttr,
25
+ ValidationError,
26
+ model_serializer,
27
+ model_validator,
28
+ )
21
29
  from pydantic_core import PydanticUndefinedType
22
30
  from pydantic_extra_types.pendulum_dt import DateTime
23
31
  from typing_extensions import ParamSpec, Self
@@ -25,13 +33,13 @@ from typing_extensions import ParamSpec, Self
25
33
  import prefect
26
34
  from prefect.blocks.core import Block
27
35
  from prefect.client.utilities import inject_client
28
- from prefect.exceptions import MissingResult
36
+ from prefect.exceptions import SerializationError
29
37
  from prefect.filesystems import (
30
38
  LocalFileSystem,
31
39
  WritableFileSystem,
32
40
  )
33
41
  from prefect.logging import get_logger
34
- from prefect.serializers import Serializer
42
+ from prefect.serializers import PickleSerializer, Serializer
35
43
  from prefect.settings import (
36
44
  PREFECT_DEFAULT_RESULT_STORAGE_BLOCK,
37
45
  PREFECT_LOCAL_STORAGE_PATH,
@@ -332,22 +340,15 @@ class ResultFactory(BaseModel):
332
340
  obj: R,
333
341
  key: Optional[str] = None,
334
342
  expiration: Optional[DateTime] = None,
335
- defer_persistence: bool = False,
336
343
  ) -> Union[R, "BaseResult[R]"]:
337
344
  """
338
345
  Create a result type for the given object.
339
346
 
340
- If persistence is disabled, the object is wrapped in an `UnpersistedResult` and
341
- returned.
342
-
343
347
  If persistence is enabled the object is serialized, persisted to storage, and a reference is returned.
344
348
  """
345
349
  # Null objects are "cached" in memory at no cost
346
350
  should_cache_object = self.cache_result_in_memory or obj is None
347
351
 
348
- if not self.persist_result:
349
- return await UnpersistedResult.create(obj, cache_object=should_cache_object)
350
-
351
352
  if key:
352
353
 
353
354
  def key_fn():
@@ -365,23 +366,198 @@ class ResultFactory(BaseModel):
365
366
  serializer=self.serializer,
366
367
  cache_object=should_cache_object,
367
368
  expiration=expiration,
368
- defer_persistence=defer_persistence,
369
+ serialize_to_none=not self.persist_result,
369
370
  )
370
371
 
372
+ # TODO: These two methods need to find a new home
373
+
371
374
  @sync_compatible
372
375
  async def store_parameters(self, identifier: UUID, parameters: Dict[str, Any]):
373
- data = self.serializer.dumps(parameters)
374
- blob = PersistedResultBlob(serializer=self.serializer, data=data)
376
+ record = ResultRecord(
377
+ result=parameters,
378
+ metadata=ResultRecordMetadata(
379
+ serializer=self.serializer, storage_key=str(identifier)
380
+ ),
381
+ )
375
382
  await self.storage_block.write_path(
376
- f"parameters/{identifier}", content=blob.to_bytes()
383
+ f"parameters/{identifier}", content=record.serialize()
377
384
  )
378
385
 
379
386
  @sync_compatible
380
387
  async def read_parameters(self, identifier: UUID) -> Dict[str, Any]:
381
- blob = PersistedResultBlob.model_validate_json(
388
+ record = ResultRecord.deserialize(
382
389
  await self.storage_block.read_path(f"parameters/{identifier}")
383
390
  )
384
- return self.serializer.loads(blob.data)
391
+ return record.result
392
+
393
+
394
+ class ResultRecordMetadata(BaseModel):
395
+ """
396
+ Metadata for a result record.
397
+ """
398
+
399
+ storage_key: Optional[str] = Field(
400
+ default=None
401
+ ) # optional for backwards compatibility
402
+ expiration: Optional[DateTime] = Field(default=None)
403
+ serializer: Serializer = Field(default_factory=PickleSerializer)
404
+ prefect_version: str = Field(default=prefect.__version__)
405
+
406
+ def dump_bytes(self) -> bytes:
407
+ """
408
+ Serialize the metadata to bytes.
409
+
410
+ Returns:
411
+ bytes: the serialized metadata
412
+ """
413
+ return self.model_dump_json(serialize_as_any=True).encode()
414
+
415
+ @classmethod
416
+ def load_bytes(cls, data: bytes) -> "ResultRecordMetadata":
417
+ """
418
+ Deserialize metadata from bytes.
419
+
420
+ Args:
421
+ data: the serialized metadata
422
+
423
+ Returns:
424
+ ResultRecordMetadata: the deserialized metadata
425
+ """
426
+ return cls.model_validate_json(data)
427
+
428
+
429
+ class ResultRecord(BaseModel, Generic[R]):
430
+ """
431
+ A record of a result.
432
+ """
433
+
434
+ metadata: ResultRecordMetadata
435
+ result: R
436
+
437
+ @property
438
+ def expiration(self) -> Optional[DateTime]:
439
+ return self.metadata.expiration
440
+
441
+ @property
442
+ def serializer(self) -> Serializer:
443
+ return self.metadata.serializer
444
+
445
+ def serialize_result(self) -> bytes:
446
+ try:
447
+ data = self.serializer.dumps(self.result)
448
+ except Exception as exc:
449
+ extra_info = (
450
+ 'You can try a different serializer (e.g. result_serializer="json") '
451
+ "or disabling persistence (persist_result=False) for this flow or task."
452
+ )
453
+ # check if this is a known issue with cloudpickle and pydantic
454
+ # and add extra information to help the user recover
455
+
456
+ if (
457
+ isinstance(exc, TypeError)
458
+ and isinstance(self.result, BaseModel)
459
+ and str(exc).startswith("cannot pickle")
460
+ ):
461
+ try:
462
+ from IPython import get_ipython
463
+
464
+ if get_ipython() is not None:
465
+ extra_info = inspect.cleandoc(
466
+ """
467
+ This is a known issue in Pydantic that prevents
468
+ locally-defined (non-imported) models from being
469
+ serialized by cloudpickle in IPython/Jupyter
470
+ environments. Please see
471
+ https://github.com/pydantic/pydantic/issues/8232 for
472
+ more information. To fix the issue, either: (1) move
473
+ your Pydantic class definition to an importable
474
+ location, (2) use the JSON serializer for your flow
475
+ or task (`result_serializer="json"`), or (3)
476
+ disable result persistence for your flow or task
477
+ (`persist_result=False`).
478
+ """
479
+ ).replace("\n", " ")
480
+ except ImportError:
481
+ pass
482
+ raise SerializationError(
483
+ f"Failed to serialize object of type {type(self.result).__name__!r} with "
484
+ f"serializer {self.serializer.type!r}. {extra_info}"
485
+ ) from exc
486
+
487
+ return data
488
+
489
+ @model_validator(mode="before")
490
+ @classmethod
491
+ def coerce_old_format(cls, value: Any):
492
+ if isinstance(value, dict):
493
+ if "data" in value:
494
+ value["result"] = value.pop("data")
495
+ if "metadata" not in value:
496
+ value["metadata"] = {}
497
+ if "expiration" in value:
498
+ value["metadata"]["expiration"] = value.pop("expiration")
499
+ if "serializer" in value:
500
+ value["metadata"]["serializer"] = value.pop("serializer")
501
+ if "prefect_version" in value:
502
+ value["metadata"]["prefect_version"] = value.pop("prefect_version")
503
+ return value
504
+
505
+ def serialize_metadata(self) -> bytes:
506
+ return self.metadata.dump_bytes()
507
+
508
+ def serialize(
509
+ self,
510
+ ) -> bytes:
511
+ """
512
+ Serialize the record to bytes.
513
+
514
+ Returns:
515
+ bytes: the serialized record
516
+
517
+ """
518
+ return (
519
+ self.model_copy(update={"result": self.serialize_result()})
520
+ .model_dump_json(serialize_as_any=True)
521
+ .encode()
522
+ )
523
+
524
+ @classmethod
525
+ def deserialize(cls, data: bytes) -> "ResultRecord[R]":
526
+ """
527
+ Deserialize a record from bytes.
528
+
529
+ Args:
530
+ data: the serialized record
531
+
532
+ Returns:
533
+ ResultRecord: the deserialized record
534
+ """
535
+ instance = cls.model_validate_json(data)
536
+ if isinstance(instance.result, bytes):
537
+ instance.result = instance.serializer.loads(instance.result)
538
+ elif isinstance(instance.result, str):
539
+ instance.result = instance.serializer.loads(instance.result.encode())
540
+ return instance
541
+
542
+ @classmethod
543
+ def deserialize_from_result_and_metadata(
544
+ cls, result: bytes, metadata: bytes
545
+ ) -> "ResultRecord[R]":
546
+ """
547
+ Deserialize a record from separate result and metadata bytes.
548
+
549
+ Args:
550
+ result: the result
551
+ metadata: the serialized metadata
552
+
553
+ Returns:
554
+ ResultRecord: the deserialized record
555
+ """
556
+ result_record_metadata = ResultRecordMetadata.load_bytes(metadata)
557
+ return cls(
558
+ metadata=result_record_metadata,
559
+ result=result_record_metadata.serializer.loads(result),
560
+ )
385
561
 
386
562
 
387
563
  @register_base_type
@@ -432,40 +608,12 @@ class BaseResult(BaseModel, abc.ABC, Generic[R]):
432
608
  return cls.__name__ if isinstance(default, PydanticUndefinedType) else default
433
609
 
434
610
 
435
- class UnpersistedResult(BaseResult):
436
- """
437
- Result type for results that are not persisted outside of local memory.
438
- """
439
-
440
- type: str = "unpersisted"
441
-
442
- @sync_compatible
443
- async def get(self) -> R:
444
- if self.has_cached_object():
445
- return self._cache
446
-
447
- raise MissingResult("The result was not persisted and is no longer available.")
448
-
449
- @classmethod
450
- @sync_compatible
451
- async def create(
452
- cls: "Type[UnpersistedResult]",
453
- obj: R,
454
- cache_object: bool = True,
455
- ) -> "UnpersistedResult[R]":
456
- result = cls()
457
- # Only store the object in local memory, it will not be sent to the API
458
- if cache_object:
459
- result._cache_object(obj)
460
- return result
461
-
462
-
463
611
  class PersistedResult(BaseResult):
464
612
  """
465
613
  Result type which stores a reference to a persisted result.
466
614
 
467
615
  When created, the user's object is serialized and stored. The format for the content
468
- is defined by `PersistedResultBlob`. This reference contains metadata necessary for retrieval
616
+ is defined by `ResultRecord`. This reference contains metadata necessary for retrieval
469
617
  of the object, such as a reference to the storage block and the key where the
470
618
  content was written.
471
619
  """
@@ -476,12 +624,19 @@ class PersistedResult(BaseResult):
476
624
  storage_key: str
477
625
  storage_block_id: Optional[uuid.UUID] = None
478
626
  expiration: Optional[DateTime] = None
627
+ serialize_to_none: bool = False
479
628
 
480
- _should_cache_object: bool = PrivateAttr(default=True)
481
629
  _persisted: bool = PrivateAttr(default=False)
630
+ _should_cache_object: bool = PrivateAttr(default=True)
482
631
  _storage_block: WritableFileSystem = PrivateAttr(default=None)
483
632
  _serializer: Serializer = PrivateAttr(default=None)
484
633
 
634
+ @model_serializer(mode="wrap")
635
+ def serialize_model(self, handler, info):
636
+ if self.serialize_to_none:
637
+ return None
638
+ return handler(self, info)
639
+
485
640
  def _cache_object(
486
641
  self,
487
642
  obj: Any,
@@ -512,21 +667,20 @@ class PersistedResult(BaseResult):
512
667
  if self.has_cached_object():
513
668
  return self._cache
514
669
 
515
- blob = await self._read_blob(client=client)
516
- obj = blob.load()
517
- self.expiration = blob.expiration
670
+ record = await self._read_result_record(client=client)
671
+ self.expiration = record.expiration
518
672
 
519
673
  if self._should_cache_object:
520
- self._cache_object(obj)
674
+ self._cache_object(record.result)
521
675
 
522
- return obj
676
+ return record.result
523
677
 
524
678
  @inject_client
525
- async def _read_blob(self, client: "PrefectClient") -> "PersistedResultBlob":
679
+ async def _read_result_record(self, client: "PrefectClient") -> "ResultRecord":
526
680
  block = await self._get_storage_block(client=client)
527
681
  content = await block.read_path(self.storage_key)
528
- blob = PersistedResultBlob.model_validate_json(content)
529
- return blob
682
+ record = ResultRecord.deserialize(content)
683
+ return record
530
684
 
531
685
  @staticmethod
532
686
  def _infer_path(storage_block, key) -> str:
@@ -547,7 +701,7 @@ class PersistedResult(BaseResult):
547
701
  Write the result to the storage block.
548
702
  """
549
703
 
550
- if self._persisted:
704
+ if self._persisted or self.serialize_to_none:
551
705
  # don't double write or overwrite
552
706
  return
553
707
 
@@ -567,50 +721,15 @@ class PersistedResult(BaseResult):
567
721
  # this could error if the serializer requires kwargs
568
722
  serializer = Serializer(type=self.serializer_type)
569
723
 
570
- try:
571
- data = serializer.dumps(obj)
572
- except Exception as exc:
573
- extra_info = (
574
- 'You can try a different serializer (e.g. result_serializer="json") '
575
- "or disabling persistence (persist_result=False) for this flow or task."
576
- )
577
- # check if this is a known issue with cloudpickle and pydantic
578
- # and add extra information to help the user recover
579
-
580
- if (
581
- isinstance(exc, TypeError)
582
- and isinstance(obj, BaseModel)
583
- and str(exc).startswith("cannot pickle")
584
- ):
585
- try:
586
- from IPython import get_ipython
587
-
588
- if get_ipython() is not None:
589
- extra_info = inspect.cleandoc(
590
- """
591
- This is a known issue in Pydantic that prevents
592
- locally-defined (non-imported) models from being
593
- serialized by cloudpickle in IPython/Jupyter
594
- environments. Please see
595
- https://github.com/pydantic/pydantic/issues/8232 for
596
- more information. To fix the issue, either: (1) move
597
- your Pydantic class definition to an importable
598
- location, (2) use the JSON serializer for your flow
599
- or task (`result_serializer="json"`), or (3)
600
- disable result persistence for your flow or task
601
- (`persist_result=False`).
602
- """
603
- ).replace("\n", " ")
604
- except ImportError:
605
- pass
606
- raise ValueError(
607
- f"Failed to serialize object of type {type(obj).__name__!r} with "
608
- f"serializer {serializer.type!r}. {extra_info}"
609
- ) from exc
610
- blob = PersistedResultBlob(
611
- serializer=serializer, data=data, expiration=self.expiration
724
+ record = ResultRecord(
725
+ result=obj,
726
+ metadata=ResultRecordMetadata(
727
+ storage_key=self.storage_key,
728
+ expiration=self.expiration,
729
+ serializer=serializer,
730
+ ),
612
731
  )
613
- await storage_block.write_path(self.storage_key, content=blob.to_bytes())
732
+ await storage_block.write_path(self.storage_key, content=record.serialize())
614
733
  self._persisted = True
615
734
 
616
735
  if not self._should_cache_object:
@@ -627,7 +746,7 @@ class PersistedResult(BaseResult):
627
746
  storage_block_id: Optional[uuid.UUID] = None,
628
747
  cache_object: bool = True,
629
748
  expiration: Optional[DateTime] = None,
630
- defer_persistence: bool = False,
749
+ serialize_to_none: bool = False,
631
750
  ) -> "PersistedResult[R]":
632
751
  """
633
752
  Create a new result reference from a user's object.
@@ -651,79 +770,23 @@ class PersistedResult(BaseResult):
651
770
  storage_block_id=storage_block_id,
652
771
  storage_key=key,
653
772
  expiration=expiration,
773
+ serialize_to_none=serialize_to_none,
654
774
  )
655
775
 
656
- if cache_object and not defer_persistence:
657
- # Attach the object to the result so it's available without deserialization
658
- result._cache_object(
659
- obj, storage_block=storage_block, serializer=serializer
660
- )
661
-
662
776
  object.__setattr__(result, "_should_cache_object", cache_object)
663
-
664
- if not defer_persistence:
665
- await result.write(obj=obj)
666
- else:
667
- # we must cache temporarily to allow for writing later
668
- # the cache will be removed on write
669
- result._cache_object(
670
- obj, storage_block=storage_block, serializer=serializer
671
- )
777
+ # we must cache temporarily to allow for writing later
778
+ # the cache will be removed on write
779
+ result._cache_object(obj, storage_block=storage_block, serializer=serializer)
672
780
 
673
781
  return result
674
782
 
675
-
676
- class PersistedResultBlob(BaseModel):
677
- """
678
- The format of the content stored by a persisted result.
679
-
680
- Typically, this is written to a file as bytes.
681
- """
682
-
683
- serializer: Serializer
684
- data: bytes
685
- prefect_version: str = Field(default=prefect.__version__)
686
- expiration: Optional[DateTime] = None
687
-
688
- def load(self) -> Any:
689
- return self.serializer.loads(self.data)
690
-
691
- def to_bytes(self) -> bytes:
692
- return self.model_dump_json(serialize_as_any=True).encode()
693
-
694
-
695
- class UnknownResult(BaseResult):
696
- """
697
- Result type for unknown results. Typically used to represent the result
698
- of tasks that were forced from a failure state into a completed state.
699
-
700
- The value for this result is always None and is not persisted to external
701
- result storage, but orchestration treats the result the same as persisted
702
- results when determining orchestration rules, such as whether to rerun a
703
- completed task.
704
- """
705
-
706
- type: str = "unknown"
707
- value: None
708
-
709
- def has_cached_object(self) -> bool:
710
- # This result type always has the object cached in memory
711
- return True
712
-
713
- @sync_compatible
714
- async def get(self) -> R:
715
- return self.value
716
-
717
- @classmethod
718
- @sync_compatible
719
- async def create(
720
- cls: "Type[UnknownResult]",
721
- obj: R = None,
722
- ) -> "UnknownResult[R]":
723
- if obj is not None:
724
- raise TypeError(
725
- f"Unsupported type {type(obj).__name__!r} for unknown result. "
726
- "Only None is supported."
727
- )
728
-
729
- return cls(value=obj)
783
+ def __eq__(self, other):
784
+ if not isinstance(other, PersistedResult):
785
+ return False
786
+ return (
787
+ self.type == other.type
788
+ and self.serializer_type == other.serializer_type
789
+ and self.storage_key == other.storage_key
790
+ and self.storage_block_id == other.storage_block_id
791
+ and self.expiration == other.expiration
792
+ )
prefect/runner/runner.py CHANGED
@@ -35,7 +35,6 @@ import datetime
35
35
  import inspect
36
36
  import logging
37
37
  import os
38
- import shlex
39
38
  import shutil
40
39
  import signal
41
40
  import subprocess
@@ -90,7 +89,11 @@ from prefect.utilities.asyncutils import (
90
89
  sync_compatible,
91
90
  )
92
91
  from prefect.utilities.engine import propose_state
93
- from prefect.utilities.processutils import _register_signal, run_process
92
+ from prefect.utilities.processutils import (
93
+ _register_signal,
94
+ get_sys_executable,
95
+ run_process,
96
+ )
94
97
  from prefect.utilities.services import (
95
98
  critical_service_loop,
96
99
  start_client_metrics_server,
@@ -527,7 +530,7 @@ class Runner:
527
530
  task_status: anyio task status used to send a message to the caller
528
531
  than the flow run process has started.
529
532
  """
530
- command = f"{shlex.quote(sys.executable)} -m prefect.engine"
533
+ command = [get_sys_executable(), "-m", "prefect.engine"]
531
534
 
532
535
  flow_run_logger = self._get_flow_run_logger(flow_run)
533
536
 
@@ -574,7 +577,7 @@ class Runner:
574
577
  setattr(storage, "last_adhoc_pull", datetime.datetime.now())
575
578
 
576
579
  process = await run_process(
577
- shlex.split(command),
580
+ command=command,
578
581
  stream_output=True,
579
582
  task_status=task_status,
580
583
  env=env,
prefect/settings.py CHANGED
@@ -425,13 +425,20 @@ def default_database_connection_url(settings: "Settings", value: Optional[str]):
425
425
  f"Missing required database connection settings: {', '.join(missing)}"
426
426
  )
427
427
 
428
- host = PREFECT_API_DATABASE_HOST.value_from(settings)
429
- port = PREFECT_API_DATABASE_PORT.value_from(settings) or 5432
430
- user = PREFECT_API_DATABASE_USER.value_from(settings)
431
- name = PREFECT_API_DATABASE_NAME.value_from(settings)
432
- password = PREFECT_API_DATABASE_PASSWORD.value_from(settings)
433
-
434
- return f"{driver}://{user}:{password}@{host}:{port}/{name}"
428
+ # We only need SQLAlchemy here if we're parsing a remote database connection
429
+ # string. Import it here so that we don't require the prefect-client package
430
+ # to have SQLAlchemy installed.
431
+ from sqlalchemy import URL
432
+
433
+ return URL(
434
+ drivername=driver,
435
+ host=PREFECT_API_DATABASE_HOST.value_from(settings),
436
+ port=PREFECT_API_DATABASE_PORT.value_from(settings) or 5432,
437
+ username=PREFECT_API_DATABASE_USER.value_from(settings),
438
+ password=PREFECT_API_DATABASE_PASSWORD.value_from(settings),
439
+ database=PREFECT_API_DATABASE_NAME.value_from(settings),
440
+ query=[],
441
+ ).render_as_string(hide_password=False)
435
442
 
436
443
  elif driver == "sqlite+aiosqlite":
437
444
  path = PREFECT_API_DATABASE_NAME.value_from(settings)
@@ -1379,14 +1386,6 @@ PREFECT_API_MAX_FLOW_RUN_GRAPH_ARTIFACTS = Setting(int, default=10000)
1379
1386
  The maximum number of artifacts to show on a flow run graph on the v2 API
1380
1387
  """
1381
1388
 
1382
-
1383
- PREFECT_EXPERIMENTAL_ENABLE_CLIENT_SIDE_TASK_ORCHESTRATION = Setting(
1384
- bool, default=False
1385
- )
1386
- """
1387
- Whether or not to enable experimental client side task run orchestration.
1388
- """
1389
-
1390
1389
  # Prefect Events feature flags
1391
1390
 
1392
1391
  PREFECT_RUNNER_PROCESS_LIMIT = Setting(int, default=5)