prefect-client 3.6.28.dev1__tar.gz → 3.6.28.dev2__tar.gz

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 (421) hide show
  1. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/PKG-INFO +1 -1
  2. prefect_client-3.6.28.dev2/src/prefect/_build_info.py +5 -0
  3. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/bundles/__init__.py +44 -31
  4. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/blocks/notifications.py +19 -7
  5. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/blocks/webhook.py +16 -4
  6. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/task_runners.py +11 -3
  7. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/urls.py +230 -8
  8. prefect_client-3.6.28.dev1/src/prefect/_build_info.py +0 -5
  9. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/.gitignore +0 -0
  10. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/LICENSE +0 -0
  11. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/README.md +0 -0
  12. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/pyproject.toml +0 -0
  13. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/.prefectignore +0 -0
  14. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/AGENTS.md +0 -0
  15. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/__init__.py +0 -0
  16. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/__main__.py +0 -0
  17. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/__init__.py +0 -0
  18. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/_launchers.py +0 -0
  19. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/bundles/_file_collector.py +0 -0
  20. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/bundles/_ignore_filter.py +0 -0
  21. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/bundles/_path_resolver.py +0 -0
  22. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/bundles/_zip_builder.py +0 -0
  23. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/bundles/_zip_extractor.py +0 -0
  24. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/bundles/execute.py +0 -0
  25. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/plugins/__init__.py +0 -0
  26. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/plugins/apply.py +0 -0
  27. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/plugins/diagnostics.py +0 -0
  28. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/plugins/manager.py +0 -0
  29. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/plugins/spec.py +0 -0
  30. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/sla/__init__.py +0 -0
  31. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/sla/client.py +0 -0
  32. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_experimental/sla/objects.py +0 -0
  33. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/__init__.py +0 -0
  34. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/_logging.py +0 -0
  35. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/analytics/__init__.py +0 -0
  36. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/analytics/ci_detection.py +0 -0
  37. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/analytics/client.py +0 -0
  38. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/analytics/device_id.py +0 -0
  39. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/analytics/emit.py +0 -0
  40. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/analytics/enabled.py +0 -0
  41. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/analytics/events.py +0 -0
  42. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/analytics/milestones.py +0 -0
  43. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/analytics/notice.py +0 -0
  44. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/analytics/service.py +0 -0
  45. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/compatibility/__init__.py +0 -0
  46. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/compatibility/async_dispatch.py +0 -0
  47. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/compatibility/backports.py +0 -0
  48. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/compatibility/blocks.py +0 -0
  49. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/compatibility/deprecated.py +0 -0
  50. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/compatibility/migration.py +0 -0
  51. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/compatibility/starlette.py +0 -0
  52. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/concurrency/__init__.py +0 -0
  53. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/concurrency/api.py +0 -0
  54. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/concurrency/calls.py +0 -0
  55. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/concurrency/cancellation.py +0 -0
  56. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/concurrency/event_loop.py +0 -0
  57. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/concurrency/inspection.py +0 -0
  58. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/concurrency/primitives.py +0 -0
  59. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/concurrency/services.py +0 -0
  60. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/concurrency/threads.py +0 -0
  61. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/concurrency/waiters.py +0 -0
  62. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/control_listener.py +0 -0
  63. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/installation.py +0 -0
  64. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/integrations.py +0 -0
  65. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/lazy.py +0 -0
  66. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/observability.py +0 -0
  67. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/pydantic/__init__.py +0 -0
  68. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/pydantic/schemas.py +0 -0
  69. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/pydantic/v1_schema.py +0 -0
  70. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/pydantic/v2_schema.py +0 -0
  71. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/pydantic/validated_func.py +0 -0
  72. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/pytz.py +0 -0
  73. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/retries.py +0 -0
  74. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/schemas/__init__.py +0 -0
  75. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/schemas/bases.py +0 -0
  76. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/schemas/fields.py +0 -0
  77. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/schemas/serializers.py +0 -0
  78. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/schemas/validators.py +0 -0
  79. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/send_entrypoint_logs.py +0 -0
  80. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/testing.py +0 -0
  81. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/urls.py +0 -0
  82. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/uuid7.py +0 -0
  83. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_internal/websockets.py +0 -0
  84. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_observers.py +0 -0
  85. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_result_records.py +0 -0
  86. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_sdk/__init__.py +0 -0
  87. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_sdk/fetcher.py +0 -0
  88. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_sdk/generator.py +0 -0
  89. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_sdk/models.py +0 -0
  90. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_sdk/naming.py +0 -0
  91. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_sdk/renderer.py +0 -0
  92. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_sdk/schema_converter.py +0 -0
  93. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_sdk/templates/__init__.py +0 -0
  94. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_sdk/templates/sdk.py.jinja +0 -0
  95. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_sdk/types.py +0 -0
  96. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_sdk/unions.py +0 -0
  97. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_states.py +0 -0
  98. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_vendor/croniter/__init__.py +0 -0
  99. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_vendor/croniter/croniter.py +0 -0
  100. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_versioning.py +0 -0
  101. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/_waiters.py +0 -0
  102. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/agent.py +0 -0
  103. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/analytics/__init__.py +0 -0
  104. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/artifacts.py +0 -0
  105. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/assets/__init__.py +0 -0
  106. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/assets/core.py +0 -0
  107. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/assets/materialize.py +0 -0
  108. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/automations.py +0 -0
  109. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/blocks/AGENTS.md +0 -0
  110. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/blocks/__init__.py +0 -0
  111. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/blocks/abstract.py +0 -0
  112. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/blocks/core.py +0 -0
  113. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/blocks/fields.py +0 -0
  114. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/blocks/redis.py +0 -0
  115. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/blocks/system.py +0 -0
  116. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/cache_policies.py +0 -0
  117. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/AGENTS.md +0 -0
  118. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/__init__.py +0 -0
  119. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/_version_checking.py +0 -0
  120. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/attribution.py +0 -0
  121. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/base.py +0 -0
  122. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/cloud.py +0 -0
  123. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/collections.py +0 -0
  124. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/constants.py +0 -0
  125. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/__init__.py +0 -0
  126. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_artifacts/__init__.py +0 -0
  127. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_artifacts/client.py +0 -0
  128. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_automations/__init__.py +0 -0
  129. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_automations/client.py +0 -0
  130. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_blocks_documents/__init__.py +0 -0
  131. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_blocks_documents/client.py +0 -0
  132. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_blocks_schemas/__init__.py +0 -0
  133. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_blocks_schemas/client.py +0 -0
  134. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_blocks_types/__init__.py +0 -0
  135. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_blocks_types/client.py +0 -0
  136. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_concurrency_limits/__init__.py +0 -0
  137. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_concurrency_limits/client.py +0 -0
  138. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_deployments/__init__.py +0 -0
  139. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_deployments/client.py +0 -0
  140. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_events/__init__.py +0 -0
  141. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_events/client.py +0 -0
  142. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_flow_runs/__init__.py +0 -0
  143. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_flow_runs/client.py +0 -0
  144. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_flows/__init__.py +0 -0
  145. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_flows/client.py +0 -0
  146. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_logs/__init__.py +0 -0
  147. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_logs/client.py +0 -0
  148. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_variables/__init__.py +0 -0
  149. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_variables/client.py +0 -0
  150. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_work_pools/__init__.py +0 -0
  151. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/_work_pools/client.py +0 -0
  152. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/base.py +0 -0
  153. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/orchestration/routes.py +0 -0
  154. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/schemas/__init__.py +0 -0
  155. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/schemas/actions.py +0 -0
  156. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/schemas/events.py +0 -0
  157. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/schemas/filters.py +0 -0
  158. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/schemas/objects.py +0 -0
  159. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/schemas/responses.py +0 -0
  160. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/schemas/schedules.py +0 -0
  161. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/schemas/sorting.py +0 -0
  162. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/subscriptions.py +0 -0
  163. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/types/__init__.py +0 -0
  164. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/types/flexible_schedule_list.py +0 -0
  165. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/client/utilities.py +0 -0
  166. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/AGENTS.md +0 -0
  167. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/__init__.py +0 -0
  168. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/_asyncio.py +0 -0
  169. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/_events.py +0 -0
  170. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/_leases.py +0 -0
  171. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/_sync.py +0 -0
  172. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/asyncio.py +0 -0
  173. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/context.py +0 -0
  174. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/services.py +0 -0
  175. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/sync.py +0 -0
  176. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/v1/__init__.py +0 -0
  177. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/v1/_asyncio.py +0 -0
  178. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/v1/_events.py +0 -0
  179. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/v1/asyncio.py +0 -0
  180. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/v1/context.py +0 -0
  181. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/v1/services.py +0 -0
  182. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/concurrency/v1/sync.py +0 -0
  183. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/context.py +0 -0
  184. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/deployments/AGENTS.md +0 -0
  185. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/deployments/__init__.py +0 -0
  186. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/deployments/base.py +0 -0
  187. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/deployments/deployments.py +0 -0
  188. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/deployments/flow_runs.py +0 -0
  189. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/deployments/runner.py +0 -0
  190. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/deployments/schedules.py +0 -0
  191. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/deployments/steps/__init__.py +0 -0
  192. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/deployments/steps/core.py +0 -0
  193. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/deployments/steps/pull.py +0 -0
  194. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/deployments/steps/utility.py +0 -0
  195. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/docker/__init__.py +0 -0
  196. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/docker/_buildx.py +0 -0
  197. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/docker/docker_image.py +0 -0
  198. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/engine.py +0 -0
  199. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/events/AGENTS.md +0 -0
  200. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/events/__init__.py +0 -0
  201. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/events/actions.py +0 -0
  202. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/events/clients.py +0 -0
  203. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/events/filters.py +0 -0
  204. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/events/related.py +0 -0
  205. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/events/schemas/__init__.py +0 -0
  206. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/events/schemas/automations.py +0 -0
  207. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/events/schemas/deployment_triggers.py +0 -0
  208. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/events/schemas/events.py +0 -0
  209. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/events/schemas/labelling.py +0 -0
  210. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/events/subscribers.py +0 -0
  211. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/events/utilities.py +0 -0
  212. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/events/worker.py +0 -0
  213. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/exceptions.py +0 -0
  214. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/filesystems.py +0 -0
  215. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/flow_engine.py +0 -0
  216. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/flow_runs.py +0 -0
  217. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/flows.py +0 -0
  218. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/futures.py +0 -0
  219. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/infrastructure/__init__.py +0 -0
  220. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/infrastructure/base.py +0 -0
  221. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/infrastructure/provisioners/__init__.py +0 -0
  222. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/infrastructure/provisioners/cloud_run.py +0 -0
  223. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/infrastructure/provisioners/coiled.py +0 -0
  224. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/infrastructure/provisioners/container_instance.py +0 -0
  225. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/infrastructure/provisioners/ecs.py +0 -0
  226. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/infrastructure/provisioners/modal.py +0 -0
  227. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/input/__init__.py +0 -0
  228. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/input/actions.py +0 -0
  229. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/input/run_input.py +0 -0
  230. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/locking/__init__.py +0 -0
  231. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/locking/filesystem.py +0 -0
  232. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/locking/memory.py +0 -0
  233. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/locking/protocol.py +0 -0
  234. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/logging/AGENTS.md +0 -0
  235. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/logging/__init__.py +0 -0
  236. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/logging/clients.py +0 -0
  237. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/logging/configuration.py +0 -0
  238. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/logging/filters.py +0 -0
  239. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/logging/formatters.py +0 -0
  240. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/logging/handlers.py +0 -0
  241. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/logging/highlighters.py +0 -0
  242. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/logging/loggers.py +0 -0
  243. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/logging/logging.yml +0 -0
  244. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/main.py +0 -0
  245. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/plugins.py +0 -0
  246. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/py.typed +0 -0
  247. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/results.py +0 -0
  248. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/AGENTS.md +0 -0
  249. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/__init__.py +0 -0
  250. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_cancel_finalizer.py +0 -0
  251. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_cancellation_manager.py +0 -0
  252. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_control_channel.py +0 -0
  253. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_deployment_registry.py +0 -0
  254. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_event_emitter.py +0 -0
  255. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_flow_resolver.py +0 -0
  256. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_flow_run_executor.py +0 -0
  257. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_hook_runner.py +0 -0
  258. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_limit_manager.py +0 -0
  259. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_process_manager.py +0 -0
  260. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_scheduled_run_poller.py +0 -0
  261. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_starter_bundle.py +0 -0
  262. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_starter_direct.py +0 -0
  263. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_starter_engine.py +0 -0
  264. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/_state_proposer.py +0 -0
  265. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/runner.py +0 -0
  266. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/server.py +0 -0
  267. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runner/storage.py +0 -0
  268. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runtime/__init__.py +0 -0
  269. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runtime/deployment.py +0 -0
  270. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runtime/flow_run.py +0 -0
  271. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/runtime/task_run.py +0 -0
  272. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/schedules.py +0 -0
  273. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/serializers.py +0 -0
  274. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/__init__.py +0 -0
  275. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/admin.py +0 -0
  276. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/artifacts.py +0 -0
  277. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/automations.py +0 -0
  278. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/background_workers.py +0 -0
  279. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/block_capabilities.py +0 -0
  280. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/block_documents.py +0 -0
  281. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/block_schemas.py +0 -0
  282. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/block_types.py +0 -0
  283. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/clients.py +0 -0
  284. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/collections.py +0 -0
  285. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/collections_data/views/aggregate-worker-metadata.json +0 -0
  286. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/concurrency_limits.py +0 -0
  287. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/concurrency_limits_v2.py +0 -0
  288. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/csrf_token.py +0 -0
  289. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/dependencies.py +0 -0
  290. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/deployments.py +0 -0
  291. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/events.py +0 -0
  292. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/flow_run_states.py +0 -0
  293. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/flow_runs.py +0 -0
  294. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/flows.py +0 -0
  295. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/logs.py +0 -0
  296. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/middleware.py +0 -0
  297. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/root.py +0 -0
  298. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/run_history.py +0 -0
  299. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/saved_searches.py +0 -0
  300. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/server.py +0 -0
  301. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/static/prefect-logo-mark-gradient.png +0 -0
  302. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/task_run_states.py +0 -0
  303. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/task_runs.py +0 -0
  304. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/task_workers.py +0 -0
  305. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/templates.py +0 -0
  306. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/ui/__init__.py +0 -0
  307. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/ui/flow_runs.py +0 -0
  308. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/ui/flows.py +0 -0
  309. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/ui/schemas.py +0 -0
  310. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/ui/task_runs.py +0 -0
  311. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/validation.py +0 -0
  312. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/variables.py +0 -0
  313. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/work_queues.py +0 -0
  314. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/server/api/workers.py +0 -0
  315. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/AGENTS.md +0 -0
  316. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/__init__.py +0 -0
  317. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/base.py +0 -0
  318. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/constants.py +0 -0
  319. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/context.py +0 -0
  320. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/legacy.py +0 -0
  321. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/__init__.py +0 -0
  322. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/_defaults.py +0 -0
  323. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/api.py +0 -0
  324. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/cli.py +0 -0
  325. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/client.py +0 -0
  326. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/cloud.py +0 -0
  327. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/deployments.py +0 -0
  328. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/events.py +0 -0
  329. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/experiments.py +0 -0
  330. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/flows.py +0 -0
  331. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/internal.py +0 -0
  332. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/logging.py +0 -0
  333. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/results.py +0 -0
  334. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/root.py +0 -0
  335. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/runner.py +0 -0
  336. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/server/__init__.py +0 -0
  337. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/server/api.py +0 -0
  338. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/server/concurrency.py +0 -0
  339. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/server/database.py +0 -0
  340. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/server/deployments.py +0 -0
  341. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/server/docket.py +0 -0
  342. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/server/ephemeral.py +0 -0
  343. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/server/events.py +0 -0
  344. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/server/flow_run_graph.py +0 -0
  345. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/server/logs.py +0 -0
  346. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/server/root.py +0 -0
  347. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/server/services.py +0 -0
  348. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/server/tasks.py +0 -0
  349. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/server/ui.py +0 -0
  350. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/tasks.py +0 -0
  351. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/telemetry.py +0 -0
  352. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/testing.py +0 -0
  353. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/models/worker.py +0 -0
  354. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/profiles.py +0 -0
  355. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/profiles.toml +0 -0
  356. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/settings/sources.py +0 -0
  357. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/states.py +0 -0
  358. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/task_engine.py +0 -0
  359. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/task_runs.py +0 -0
  360. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/task_worker.py +0 -0
  361. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/tasks.py +0 -0
  362. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/telemetry/__init__.py +0 -0
  363. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/telemetry/_metrics.py +0 -0
  364. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/telemetry/run_telemetry.py +0 -0
  365. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/transactions.py +0 -0
  366. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/types/__init__.py +0 -0
  367. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/types/_concurrency.py +0 -0
  368. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/types/_datetime.py +0 -0
  369. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/types/_schema.py +0 -0
  370. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/types/entrypoint.py +0 -0
  371. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/types/names.py +0 -0
  372. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/AGENTS.md +0 -0
  373. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/__init__.py +0 -0
  374. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/_ast.py +0 -0
  375. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/_deprecated.py +0 -0
  376. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/_engine.py +0 -0
  377. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/_git.py +0 -0
  378. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/_infrastructure_exit_codes.py +0 -0
  379. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/annotations.py +0 -0
  380. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/asyncutils/AGENTS.md +0 -0
  381. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/asyncutils/__init__.py +0 -0
  382. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/callables/AGENTS.md +0 -0
  383. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/callables/__init__.py +0 -0
  384. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/collections.py +0 -0
  385. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/compat.py +0 -0
  386. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/context.py +0 -0
  387. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/dispatch.py +0 -0
  388. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/dockerutils.py +0 -0
  389. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/engine/AGENTS.md +0 -0
  390. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/engine/__init__.py +0 -0
  391. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/filesystem/AGENTS.md +0 -0
  392. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/filesystem/__init__.py +0 -0
  393. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/generics.py +0 -0
  394. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/hashing.py +0 -0
  395. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/importtools.py +0 -0
  396. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/math.py +0 -0
  397. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/names.py +0 -0
  398. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/processutils/AGENTS.md +0 -0
  399. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/processutils/__init__.py +0 -0
  400. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/pydantic.py +0 -0
  401. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/render_swagger.py +0 -0
  402. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/schema_tools/AGENTS.md +0 -0
  403. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/schema_tools/__init__.py +0 -0
  404. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/schema_tools/hydration.py +0 -0
  405. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/schema_tools/validation.py +0 -0
  406. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/services.py +0 -0
  407. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/slugify.py +0 -0
  408. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/templating/AGENTS.md +0 -0
  409. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/templating/__init__.py +0 -0
  410. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/text.py +0 -0
  411. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/timeout.py +0 -0
  412. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/utilities/visualization.py +0 -0
  413. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/variables.py +0 -0
  414. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/workers/AGENTS.md +0 -0
  415. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/workers/__init__.py +0 -0
  416. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/workers/base.py +0 -0
  417. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/workers/block.py +0 -0
  418. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/workers/cloud.py +0 -0
  419. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/workers/process.py +0 -0
  420. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/workers/server.py +0 -0
  421. {prefect_client-3.6.28.dev1 → prefect_client-3.6.28.dev2}/src/prefect/workers/utilities.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prefect-client
3
- Version: 3.6.28.dev1
3
+ Version: 3.6.28.dev2
4
4
  Summary: Workflow orchestration and management.
5
5
  Project-URL: Changelog, https://github.com/PrefectHQ/prefect/releases
6
6
  Project-URL: Documentation, https://docs.prefect.io
@@ -0,0 +1,5 @@
1
+ # Generated by versioningit
2
+ __version__ = "3.6.28.dev2"
3
+ __build_date__ = "2026-04-21 08:44:07.216635+00:00"
4
+ __git_commit__ = "6f89b6d66878624ed5e572f85370cb518b630208"
5
+ __dirty__ = False
@@ -36,7 +36,10 @@ from prefect.settings.models.root import Settings
36
36
  from prefect.utilities.processutils import sanitize_subprocess_env
37
37
  from prefect.utilities.slugify import slugify
38
38
 
39
- from prefect._experimental._launchers import validate_bundle_step_launcher
39
+ from prefect._experimental._launchers import (
40
+ get_launcher_for_side,
41
+ validate_bundle_step_launcher,
42
+ )
40
43
 
41
44
  from .execute import execute_bundle_from_file
42
45
  from ._file_collector import FileCollector
@@ -411,38 +414,48 @@ def create_bundle_for_flow_run(
411
414
  """
412
415
  context = context or serialize_context()
413
416
 
414
- dependencies = (
415
- subprocess.check_output(
416
- [
417
- _get_uv_path(),
418
- "pip",
419
- "freeze",
420
- # Exclude editable installs because we won't be able to install them in the execution environment
421
- "--exclude-editable",
422
- ]
417
+ # Skip `uv pip freeze` when the execution side of the flow's launcher
418
+ # opts out of uv-based launchers. The `dependencies` field is only
419
+ # consumed by `execute_bundle_in_subprocess` (which uses `uv pip install`);
420
+ # custom execution launchers are responsible for their own environment.
421
+ # Upload-only launcher overrides still use `uv run` at execution time and
422
+ # therefore still need the dependency snapshot.
423
+ flow_launcher = getattr(flow, "launcher", None)
424
+ if get_launcher_for_side(flow_launcher, "execution") is None:
425
+ dependencies = (
426
+ subprocess.check_output(
427
+ [
428
+ _get_uv_path(),
429
+ "pip",
430
+ "freeze",
431
+ # Exclude editable installs because we won't be able to install them in the execution environment
432
+ "--exclude-editable",
433
+ ]
434
+ )
435
+ .decode()
436
+ .strip()
423
437
  )
424
- .decode()
425
- .strip()
426
- )
427
438
 
428
- # Remove dependencies installed from a local file path because we won't be able
429
- # to install them in the execution environment. The user will be responsible for
430
- # making sure they are available in the execution environment
431
- filtered_dependencies: list[str] = []
432
- file_dependencies: list[str] = []
433
- for line in dependencies.split("\n"):
434
- if "file://" in line:
435
- file_dependencies.append(line)
436
- else:
437
- filtered_dependencies.append(line)
438
- dependencies = "\n".join(filtered_dependencies)
439
- if file_dependencies:
440
- logger.warning(
441
- "The following dependencies were installed from a local file path and will not be "
442
- "automatically installed in the execution environment: %s. If these dependencies "
443
- "are not available in the execution environment, your flow run may fail.",
444
- "\n".join(file_dependencies),
445
- )
439
+ # Remove dependencies installed from a local file path because we won't be able
440
+ # to install them in the execution environment. The user will be responsible for
441
+ # making sure they are available in the execution environment
442
+ filtered_dependencies: list[str] = []
443
+ file_dependencies: list[str] = []
444
+ for line in dependencies.split("\n"):
445
+ if "file://" in line:
446
+ file_dependencies.append(line)
447
+ else:
448
+ filtered_dependencies.append(line)
449
+ dependencies = "\n".join(filtered_dependencies)
450
+ if file_dependencies:
451
+ logger.warning(
452
+ "The following dependencies were installed from a local file path and will not be "
453
+ "automatically installed in the execution environment: %s. If these dependencies "
454
+ "are not available in the execution environment, your flow run may fail.",
455
+ "\n".join(file_dependencies),
456
+ )
457
+ else:
458
+ dependencies = ""
446
459
 
447
460
  # Collect and package included files if specified
448
461
  files_key: str | None = None
@@ -13,7 +13,11 @@ from prefect.blocks.abstract import NotificationBlock, NotificationError
13
13
  from prefect.logging import LogEavesdropper
14
14
  from prefect.types import SecretDict
15
15
  from prefect.utilities.templating import apply_values, find_placeholders
16
- from prefect.utilities.urls import validate_restricted_url
16
+ from prefect.utilities.urls import (
17
+ SSRFProtectedAsyncHTTPTransport,
18
+ SSRFProtectedHTTPTransport,
19
+ validate_restricted_url,
20
+ )
17
21
 
18
22
  PREFECT_NOTIFY_TYPE_DEFAULT = "info" # Use a valid apprise type as default
19
23
 
@@ -987,13 +991,18 @@ class CustomWebhookNotificationBlock(NotificationBlock):
987
991
  import httpx
988
992
 
989
993
  request_args = self._build_request_args(body, subject)
994
+ client_kwargs: dict[str, Any] = {
995
+ "headers": {"user-agent": "Prefect Notifications"},
996
+ }
990
997
  if not self.allow_private_urls:
991
998
  validate_restricted_url(request_args["url"])
999
+ # Re-validate at connection time and pin the resolved IP to close
1000
+ # the DNS-rebinding TOCTOU window.
1001
+ client_kwargs["transport"] = SSRFProtectedAsyncHTTPTransport()
992
1002
  cookies = request_args.pop("cookies", dict())
1003
+ client_kwargs["cookies"] = cookies
993
1004
  # make request with httpx
994
- async with httpx.AsyncClient(
995
- headers={"user-agent": "Prefect Notifications"}, cookies=cookies
996
- ) as client:
1005
+ async with httpx.AsyncClient(**client_kwargs) as client:
997
1006
  resp = await client.request(**request_args)
998
1007
  resp.raise_for_status()
999
1008
 
@@ -1002,13 +1011,16 @@ class CustomWebhookNotificationBlock(NotificationBlock):
1002
1011
  import httpx
1003
1012
 
1004
1013
  request_args = self._build_request_args(body, subject)
1014
+ client_kwargs: dict[str, Any] = {
1015
+ "headers": {"user-agent": "Prefect Notifications"},
1016
+ }
1005
1017
  if not self.allow_private_urls:
1006
1018
  validate_restricted_url(request_args["url"])
1019
+ client_kwargs["transport"] = SSRFProtectedHTTPTransport()
1007
1020
  cookies = request_args.pop("cookies", dict())
1021
+ client_kwargs["cookies"] = cookies
1008
1022
  # make request with httpx
1009
- with httpx.Client(
1010
- headers={"user-agent": "Prefect Notifications"}, cookies=cookies
1011
- ) as client:
1023
+ with httpx.Client(**client_kwargs) as client:
1012
1024
  resp = client.request(**request_args)
1013
1025
  resp.raise_for_status()
1014
1026
 
@@ -8,12 +8,21 @@ from typing_extensions import Literal
8
8
 
9
9
  from prefect.blocks.core import Block
10
10
  from prefect.types import SecretDict
11
- from prefect.utilities.urls import validate_restricted_url
11
+ from prefect.utilities.urls import (
12
+ SSRFProtectedAsyncHTTPTransport,
13
+ validate_restricted_url,
14
+ )
12
15
 
13
16
  # Use a global HTTP transport to maintain a process-wide connection pool for
14
17
  # interservice requests
15
18
  _http_transport = AsyncHTTPTransport()
16
19
  _insecure_http_transport = AsyncHTTPTransport(verify=False)
20
+ # Separate pools for calls that must be protected from DNS-rebinding SSRF. The
21
+ # protected transport validates the resolved IP at connection time and connects
22
+ # to the pre-resolved address, closing the TOCTOU window exploited by DNS
23
+ # rebinding attacks.
24
+ _safe_http_transport = SSRFProtectedAsyncHTTPTransport()
25
+ _safe_insecure_http_transport = SSRFProtectedAsyncHTTPTransport(verify=False)
17
26
 
18
27
 
19
28
  class Webhook(Block):
@@ -53,10 +62,13 @@ class Webhook(Block):
53
62
  )
54
63
 
55
64
  def block_initialization(self) -> None:
56
- if self.verify:
57
- self._client = AsyncClient(transport=_http_transport)
65
+ if self.allow_private_urls:
66
+ transport = _http_transport if self.verify else _insecure_http_transport
58
67
  else:
59
- self._client = AsyncClient(transport=_insecure_http_transport)
68
+ transport = (
69
+ _safe_http_transport if self.verify else _safe_insecure_http_transport
70
+ )
71
+ self._client = AsyncClient(transport=transport)
60
72
 
61
73
  async def call(self, payload: dict[str, Any] | str | None = None) -> Response:
62
74
  """
@@ -616,14 +616,19 @@ class _UnpicklingFuture(concurrent.futures.Future[R]):
616
616
 
617
617
  def __init__(self, wrapped_future: concurrent.futures.Future[bytes]):
618
618
  self.wrapped_future = wrapped_future
619
+ self._deserialization_error: BaseException | None = None
619
620
 
620
621
  def result(self, timeout: float | None = None) -> R:
622
+ if self._deserialization_error is not None:
623
+ raise self._deserialization_error
621
624
  pickled_result = self.wrapped_future.result(timeout)
622
625
  import cloudpickle
623
626
 
624
627
  return cloudpickle.loads(pickled_result)
625
628
 
626
629
  def exception(self, timeout: float | None = None) -> BaseException | None:
630
+ if self._deserialization_error is not None:
631
+ return self._deserialization_error
627
632
  return self.wrapped_future.exception(timeout)
628
633
 
629
634
  def done(self) -> bool:
@@ -639,10 +644,13 @@ class _UnpicklingFuture(concurrent.futures.Future[R]):
639
644
  self, fn: Callable[[concurrent.futures.Future[R]], object]
640
645
  ) -> None:
641
646
  def _fn(wrapped_future: concurrent.futures.Future[bytes]) -> None:
642
- import cloudpickle
647
+ try:
648
+ import cloudpickle
643
649
 
644
- result = cloudpickle.loads(wrapped_future.result())
645
- fn(result)
650
+ cloudpickle.loads(wrapped_future.result())
651
+ except Exception as e:
652
+ self._deserialization_error = e
653
+ fn(self)
646
654
 
647
655
  return self.wrapped_future.add_done_callback(_fn)
648
656
 
@@ -1,13 +1,18 @@
1
1
  import inspect
2
2
  import ipaddress
3
3
  import socket
4
+ import time
4
5
  import urllib.parse
6
+ from collections.abc import Iterable
5
7
  from logging import Logger
6
8
  from string import Formatter
7
9
  from typing import TYPE_CHECKING, Any, Literal, Optional, Union, cast
8
10
  from urllib.parse import urlparse
9
11
  from uuid import UUID
10
12
 
13
+ import anyio.to_thread
14
+ import httpcore
15
+ import httpx
11
16
  from pydantic import BaseModel
12
17
 
13
18
  from prefect import settings
@@ -71,7 +76,14 @@ def validate_restricted_url(url: str) -> None:
71
76
  Validate that the provided URL is safe for outbound requests. This prevents
72
77
  attacks like SSRF (Server Side Request Forgery), where an attacker can make
73
78
  requests to internal services (like the GCP metadata service, localhost addresses,
74
- or in-cluster Kubernetes services)
79
+ or in-cluster Kubernetes services).
80
+
81
+ This is a pre-flight check that validates every address the hostname resolves
82
+ to via `getaddrinfo`. Because DNS can change between this check and the
83
+ actual HTTP connection, callers that need hardened SSRF protection should
84
+ also use `SSRFProtectedAsyncHTTPTransport` / `SSRFProtectedHTTPTransport`,
85
+ which re-validate at connection time and connect to the pre-resolved IP to
86
+ close the TOCTOU window exploited by DNS rebinding attacks.
75
87
 
76
88
  Args:
77
89
  url: The URL to validate.
@@ -100,17 +112,227 @@ def validate_restricted_url(url: str) -> None:
100
112
  raise ValueError(f"{url!r} is not a valid URL.")
101
113
 
102
114
  try:
103
- ip_address = socket.gethostbyname(hostname)
104
- ip = ipaddress.ip_address(ip_address)
115
+ _validate_resolved_hostname(hostname)
116
+ except _RestrictedHostError as exc:
117
+ raise ValueError(f"{url!r} is not a valid URL. {exc}")
118
+
119
+
120
+ class _RestrictedHostError(Exception):
121
+ """Internal exception raised when a hostname resolves to a restricted address."""
122
+
123
+
124
+ def _validate_resolved_hostname(hostname: str) -> list[str]:
125
+ """Resolve `hostname` and validate every returned address.
126
+
127
+ Returns the list of resolved IPs (as strings) in resolution order. Raises
128
+ `_RestrictedHostError` if any resolved address is private, or if the
129
+ hostname cannot be resolved.
130
+
131
+ Using `getaddrinfo` (rather than `gethostbyname`, which returns only the
132
+ first A record) closes an SSRF bypass where a hostname publishes both a
133
+ public and a private A/AAAA record: every resolved address is checked.
134
+ """
135
+ # IP literal: validate directly.
136
+ try:
137
+ ip = ipaddress.ip_address(hostname)
138
+ except ValueError:
139
+ pass
140
+ else:
141
+ if ip.is_private:
142
+ raise _RestrictedHostError(f"It resolves to the private address {ip}.")
143
+ return [str(ip)]
144
+
145
+ try:
146
+ addrinfos = socket.getaddrinfo(hostname, None, type=socket.SOCK_STREAM)
105
147
  except socket.gaierror:
148
+ raise _RestrictedHostError("It could not be resolved.")
149
+
150
+ resolved: list[str] = []
151
+ for addrinfo in addrinfos:
152
+ sockaddr = addrinfo[4]
153
+ ip_str = sockaddr[0]
154
+ # Strip IPv6 zone identifier if present (e.g. "fe80::1%eth0")
155
+ ip_str = ip_str.split("%", 1)[0]
106
156
  try:
107
- ip = ipaddress.ip_address(hostname)
157
+ ip = ipaddress.ip_address(ip_str)
108
158
  except ValueError:
109
- raise ValueError(f"{url!r} is not a valid URL. It could not be resolved.")
159
+ continue
160
+ if ip.is_private:
161
+ raise _RestrictedHostError(f"It resolves to the private address {ip}.")
162
+ if ip_str not in resolved:
163
+ resolved.append(ip_str)
110
164
 
111
- if ip.is_private:
112
- raise ValueError(
113
- f"{url!r} is not a valid URL. It resolves to the private address {ip}."
165
+ if not resolved:
166
+ raise _RestrictedHostError("It could not be resolved.")
167
+
168
+ return resolved
169
+
170
+
171
+ class _SSRFProtectedAsyncBackend(httpcore.AsyncNetworkBackend):
172
+ """An `httpcore.AsyncNetworkBackend` that validates resolved addresses.
173
+
174
+ Wraps an existing backend and, on each `connect_tcp` call, resolves the
175
+ hostname itself, rejects any resolved address that is private, and then
176
+ connects to the validated IP directly (rather than the hostname) so that
177
+ the underlying backend cannot re-resolve to a different address.
178
+
179
+ TLS SNI / certificate validation is unaffected because httpcore passes the
180
+ original hostname to `start_tls` via `server_hostname`, independently of
181
+ the host used for the TCP connection.
182
+ """
183
+
184
+ def __init__(self, wrapped: httpcore.AsyncNetworkBackend) -> None:
185
+ self._wrapped = wrapped
186
+
187
+ async def connect_tcp(
188
+ self,
189
+ host: str,
190
+ port: int,
191
+ timeout: Optional[float] = None,
192
+ local_address: Optional[str] = None,
193
+ socket_options: Optional[Iterable[Any]] = None,
194
+ ) -> httpcore.AsyncNetworkStream:
195
+ # Resolve in a worker thread so the event loop is not blocked during
196
+ # DNS lookups (which can be slow or intermittently failing).
197
+ validated_ips = await anyio.to_thread.run_sync(
198
+ _resolve_and_validate_for_connect, host
199
+ )
200
+ last_exc: Optional[BaseException] = None
201
+ deadline = time.monotonic() + timeout if timeout is not None else None
202
+ for ip in validated_ips:
203
+ remaining = _remaining_timeout(deadline)
204
+ if remaining == 0.0:
205
+ break
206
+ try:
207
+ return await self._wrapped.connect_tcp(
208
+ ip,
209
+ port,
210
+ timeout=remaining,
211
+ local_address=local_address,
212
+ socket_options=socket_options,
213
+ )
214
+ except (httpcore.ConnectError, httpcore.ConnectTimeout, OSError) as exc:
215
+ last_exc = exc
216
+ assert last_exc is not None
217
+ raise last_exc
218
+
219
+ async def connect_unix_socket(
220
+ self,
221
+ path: str,
222
+ timeout: Optional[float] = None,
223
+ socket_options: Optional[Iterable[Any]] = None,
224
+ ) -> httpcore.AsyncNetworkStream:
225
+ return await self._wrapped.connect_unix_socket(
226
+ path, timeout=timeout, socket_options=socket_options
227
+ )
228
+
229
+ async def sleep(self, seconds: float) -> None:
230
+ await self._wrapped.sleep(seconds)
231
+
232
+
233
+ class _SSRFProtectedSyncBackend(httpcore.NetworkBackend):
234
+ """Synchronous counterpart of `_SSRFProtectedAsyncBackend`."""
235
+
236
+ def __init__(self, wrapped: httpcore.NetworkBackend) -> None:
237
+ self._wrapped = wrapped
238
+
239
+ def connect_tcp(
240
+ self,
241
+ host: str,
242
+ port: int,
243
+ timeout: Optional[float] = None,
244
+ local_address: Optional[str] = None,
245
+ socket_options: Optional[Iterable[Any]] = None,
246
+ ) -> httpcore.NetworkStream:
247
+ validated_ips = _resolve_and_validate_for_connect(host)
248
+ last_exc: Optional[BaseException] = None
249
+ deadline = time.monotonic() + timeout if timeout is not None else None
250
+ for ip in validated_ips:
251
+ remaining = _remaining_timeout(deadline)
252
+ if remaining == 0.0:
253
+ break
254
+ try:
255
+ return self._wrapped.connect_tcp(
256
+ ip,
257
+ port,
258
+ timeout=remaining,
259
+ local_address=local_address,
260
+ socket_options=socket_options,
261
+ )
262
+ except (httpcore.ConnectError, httpcore.ConnectTimeout, OSError) as exc:
263
+ last_exc = exc
264
+ assert last_exc is not None
265
+ raise last_exc
266
+
267
+ def connect_unix_socket(
268
+ self,
269
+ path: str,
270
+ timeout: Optional[float] = None,
271
+ socket_options: Optional[Iterable[Any]] = None,
272
+ ) -> httpcore.NetworkStream:
273
+ return self._wrapped.connect_unix_socket(
274
+ path, timeout=timeout, socket_options=socket_options
275
+ )
276
+
277
+ def sleep(self, seconds: float) -> None:
278
+ self._wrapped.sleep(seconds)
279
+
280
+
281
+ def _remaining_timeout(deadline: Optional[float]) -> Optional[float]:
282
+ """Return the time left until `deadline`, or `None` if no deadline is set.
283
+
284
+ Clamps to `0.0` when the deadline has already passed. Callers use this to
285
+ share a single connect-timeout budget across multiple per-IP retries so
286
+ that connect time stays bounded (roughly) by the caller's timeout rather
287
+ than scaling with the number of resolved addresses.
288
+ """
289
+ if deadline is None:
290
+ return None
291
+ return max(0.0, deadline - time.monotonic())
292
+
293
+
294
+ def _resolve_and_validate_for_connect(host: str) -> list[str]:
295
+ """Resolve `host` and return all safe IPs to connect to.
296
+
297
+ Every returned IP has been validated against the private-address blocklist;
298
+ callers iterate them in order and retry on connect failures so that dual-
299
+ stack hostnames still work in single-stack environments.
300
+
301
+ Raises `httpcore.ConnectError` if any resolved address is private or if the
302
+ hostname cannot be resolved. The returned IPs are passed to the underlying
303
+ network backend as IP literals, so it will not perform further DNS
304
+ resolution — eliminating the DNS rebinding TOCTOU window.
305
+ """
306
+ try:
307
+ return _validate_resolved_hostname(host)
308
+ except _RestrictedHostError as exc:
309
+ raise httpcore.ConnectError(f"Refusing to connect to {host!r}: {exc}") from None
310
+
311
+
312
+ class SSRFProtectedAsyncHTTPTransport(httpx.AsyncHTTPTransport):
313
+ """An `httpx.AsyncHTTPTransport` that guards against DNS rebinding SSRF.
314
+
315
+ Behaves identically to `httpx.AsyncHTTPTransport` except that, for every
316
+ request, the hostname is resolved, every resolved address is checked
317
+ against the private-address blocklist, and the connection is made to the
318
+ specific validated IP. This closes the TOCTOU window between a pre-flight
319
+ `validate_restricted_url` check and the actual HTTP connection.
320
+ """
321
+
322
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
323
+ super().__init__(*args, **kwargs)
324
+ self._pool._network_backend = _SSRFProtectedAsyncBackend(
325
+ self._pool._network_backend
326
+ )
327
+
328
+
329
+ class SSRFProtectedHTTPTransport(httpx.HTTPTransport):
330
+ """Synchronous counterpart of `SSRFProtectedAsyncHTTPTransport`."""
331
+
332
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
333
+ super().__init__(*args, **kwargs)
334
+ self._pool._network_backend = _SSRFProtectedSyncBackend(
335
+ self._pool._network_backend
114
336
  )
115
337
 
116
338
 
@@ -1,5 +0,0 @@
1
- # Generated by versioningit
2
- __version__ = "3.6.28.dev1"
3
- __build_date__ = "2026-04-20 08:52:09.547211+00:00"
4
- __git_commit__ = "6373056dad307ad9526f0257987e885e30934f87"
5
- __dirty__ = False