pyfect-dev 0.1.0__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 (1265) hide show
  1. pyfect/__init__.py +729 -0
  2. pyfect/_all.py +242 -0
  3. pyfect/_background.py +28 -0
  4. pyfect/_binary_codecs.py +124 -0
  5. pyfect/_cached.py +165 -0
  6. pyfect/_catch.py +128 -0
  7. pyfect/_catch_reason.py +574 -0
  8. pyfect/_concurrency.py +291 -0
  9. pyfect/_context_effects.py +163 -0
  10. pyfect/_context_managers.py +76 -0
  11. pyfect/_core.py +368 -0
  12. pyfect/_digits.py +71 -0
  13. pyfect/_effect_args.py +46 -0
  14. pyfect/_effect_base.py +71 -0
  15. pyfect/_effect_concurrency.py +133 -0
  16. pyfect/_effect_eager.py +103 -0
  17. pyfect/_effect_errors.py +344 -0
  18. pyfect/_effect_folding.py +110 -0
  19. pyfect/_effect_hash.py +140 -0
  20. pyfect/_effect_logging.py +57 -0
  21. pyfect/_effect_metrics.py +102 -0
  22. pyfect/_effect_resources.py +179 -0
  23. pyfect/_effect_services.py +25 -0
  24. pyfect/_effect_timing.py +199 -0
  25. pyfect/_effect_tracing.py +99 -0
  26. pyfect/_equal.py +195 -0
  27. pyfect/_extras.py +43 -0
  28. pyfect/_fiber.py +969 -0
  29. pyfect/_fiber_all.py +134 -0
  30. pyfect/_fiber_collections.py +106 -0
  31. pyfect/_fn.py +706 -0
  32. pyfect/_hamt.py +174 -0
  33. pyfect/_interrupt_reason.py +33 -0
  34. pyfect/_isaac.py +149 -0
  35. pyfect/_iterables.py +231 -0
  36. pyfect/_js.py +263 -0
  37. pyfect/_js_date.py +87 -0
  38. pyfect/_json_text.py +286 -0
  39. pyfect/_json_value.py +9 -0
  40. pyfect/_layer_core.py +403 -0
  41. pyfect/_layer_for_life.py +33 -0
  42. pyfect/_layer_tracing.py +70 -0
  43. pyfect/_locked_ref.py +147 -0
  44. pyfect/_loop_thread.py +152 -0
  45. pyfect/_metric_ref.py +29 -0
  46. pyfect/_one_or_many.py +14 -0
  47. pyfect/_os_wait.py +118 -0
  48. pyfect/_path_posix.py +129 -0
  49. pyfect/_primitives.py +434 -0
  50. pyfect/_public.py +36 -0
  51. pyfect/_reasons.py +64 -0
  52. pyfect/_released.py +67 -0
  53. pyfect/_root.py +87 -0
  54. pyfect/_round_robin.py +73 -0
  55. pyfect/_some.py +17 -0
  56. pyfect/_stack.py +52 -0
  57. pyfect/_stack_frame.py +114 -0
  58. pyfect/_string_hash.py +35 -0
  59. pyfect/_subscriber_queue.py +47 -0
  60. pyfect/_tags.py +14 -0
  61. pyfect/_tracer_ref.py +21 -0
  62. pyfect/_tx_ops.py +77 -0
  63. pyfect/_unsubscripted.py +23 -0
  64. pyfect/_url.py +54 -0
  65. pyfect/_waiters.py +127 -0
  66. pyfect/_wake_tracking.py +98 -0
  67. pyfect/_wire_codec.py +123 -0
  68. pyfect/ai/__init__.py +73 -0
  69. pyfect/ai/_approvals.py +249 -0
  70. pyfect/ai/_decision_answers.py +185 -0
  71. pyfect/ai/_generated_client.py +298 -0
  72. pyfect/ai/_generated_support.py +84 -0
  73. pyfect/ai/_mcp/__init__.py +1 -0
  74. pyfect/ai/_mcp/batch.py +68 -0
  75. pyfect/ai/_mcp/client_transport.py +412 -0
  76. pyfect/ai/_mcp/client_wire.py +284 -0
  77. pyfect/ai/_mcp/core.py +490 -0
  78. pyfect/ai/_mcp/dispatch.py +1048 -0
  79. pyfect/ai/_mcp/http.py +462 -0
  80. pyfect/ai/_mcp/http_admission.py +269 -0
  81. pyfect/ai/_mcp/http_status.py +27 -0
  82. pyfect/ai/_mcp/input_wire.py +226 -0
  83. pyfect/ai/_mcp/log_levels.py +55 -0
  84. pyfect/ai/_mcp/param_headers.py +63 -0
  85. pyfect/ai/_mcp/projection.py +248 -0
  86. pyfect/ai/_mcp/register.py +683 -0
  87. pyfect/ai/_mcp/reverse_policy.py +155 -0
  88. pyfect/ai/_mcp/routing_header.py +24 -0
  89. pyfect/ai/_mcp/sessions.py +114 -0
  90. pyfect/ai/_mcp/stdio.py +110 -0
  91. pyfect/ai/_mcp/subscriptions.py +134 -0
  92. pyfect/ai/_mcp/tool_schema.py +35 -0
  93. pyfect/ai/_noul_answers.py +64 -0
  94. pyfect/ai/_openai_all_of.py +137 -0
  95. pyfect/ai/_openai_errors.py +233 -0
  96. pyfect/ai/_provider.py +439 -0
  97. pyfect/ai/_provider_tools.py +129 -0
  98. pyfect/ai/_stream_resolution.py +231 -0
  99. pyfect/ai/_structured_output_checks.py +138 -0
  100. pyfect/ai/_structured_output_codec.py +229 -0
  101. pyfect/ai/_structured_output_json.py +109 -0
  102. pyfect/ai/_tool_call_ids.py +80 -0
  103. pyfect/ai/ai_error.py +785 -0
  104. pyfect/ai/anthropic/__init__.py +28 -0
  105. pyfect/ai/anthropic/_errors.py +164 -0
  106. pyfect/ai/anthropic/_prompt.py +375 -0
  107. pyfect/ai/anthropic/_response.py +443 -0
  108. pyfect/ai/anthropic/_schema.py +206 -0
  109. pyfect/ai/anthropic/_stream.py +377 -0
  110. pyfect/ai/anthropic/_tools.py +248 -0
  111. pyfect/ai/anthropic/client.py +289 -0
  112. pyfect/ai/anthropic/config.py +32 -0
  113. pyfect/ai/anthropic/error.py +27 -0
  114. pyfect/ai/anthropic/language_model.py +366 -0
  115. pyfect/ai/anthropic/telemetry.py +51 -0
  116. pyfect/ai/anthropic/tool.py +570 -0
  117. pyfect/ai/anthropic_structured_output.py +138 -0
  118. pyfect/ai/chat.py +548 -0
  119. pyfect/ai/cloudflare/__init__.py +15 -0
  120. pyfect/ai/cloudflare/_errors.py +108 -0
  121. pyfect/ai/cloudflare/client.py +174 -0
  122. pyfect/ai/cloudflare/decision_model.py +117 -0
  123. pyfect/ai/cloudflare/schema.py +144 -0
  124. pyfect/ai/decision.py +290 -0
  125. pyfect/ai/decision_model.py +283 -0
  126. pyfect/ai/embedding_model.py +177 -0
  127. pyfect/ai/id_generator.py +79 -0
  128. pyfect/ai/language_model.py +1077 -0
  129. pyfect/ai/mcp_client.py +682 -0
  130. pyfect/ai/mcp_client_error.py +223 -0
  131. pyfect/ai/mcp_protocol.py +205 -0
  132. pyfect/ai/mcp_schema.py +1300 -0
  133. pyfect/ai/mcp_server.py +404 -0
  134. pyfect/ai/model.py +56 -0
  135. pyfect/ai/openai/__init__.py +49 -0
  136. pyfect/ai/openai/_errors.py +89 -0
  137. pyfect/ai/openai/_prompt.py +527 -0
  138. pyfect/ai/openai/_requests.py +34 -0
  139. pyfect/ai/openai/_response.py +569 -0
  140. pyfect/ai/openai/_schema.py +769 -0
  141. pyfect/ai/openai/_stream.py +771 -0
  142. pyfect/ai/openai/_tools.py +128 -0
  143. pyfect/ai/openai/_web_socket.py +295 -0
  144. pyfect/ai/openai/client.py +296 -0
  145. pyfect/ai/openai/client_generated.py +123 -0
  146. pyfect/ai/openai/config.py +34 -0
  147. pyfect/ai/openai/decision_model.py +177 -0
  148. pyfect/ai/openai/embedding_model.py +116 -0
  149. pyfect/ai/openai/error.py +8 -0
  150. pyfect/ai/openai/generated/__init__.py +7213 -0
  151. pyfect/ai/openai/generated/_recursive.py +18 -0
  152. pyfect/ai/openai/generated/_schemas_0.py +1015 -0
  153. pyfect/ai/openai/generated/_schemas_1.py +1016 -0
  154. pyfect/ai/openai/generated/_schemas_2.py +1017 -0
  155. pyfect/ai/openai/generated/_schemas_3.py +615 -0
  156. pyfect/ai/openai/generated/client.py +5298 -0
  157. pyfect/ai/openai/generated/types.py +8123 -0
  158. pyfect/ai/openai/language_model.py +304 -0
  159. pyfect/ai/openai/telemetry.py +19 -0
  160. pyfect/ai/openai/tool.py +391 -0
  161. pyfect/ai/openai_compat/__init__.py +25 -0
  162. pyfect/ai/openai_compat/_prompt.py +191 -0
  163. pyfect/ai/openai_compat/_request.py +153 -0
  164. pyfect/ai/openai_compat/_response.py +407 -0
  165. pyfect/ai/openai_compat/_schema.py +97 -0
  166. pyfect/ai/openai_compat/client.py +234 -0
  167. pyfect/ai/openai_compat/config.py +32 -0
  168. pyfect/ai/openai_compat/embedding_model.py +139 -0
  169. pyfect/ai/openai_compat/error.py +7 -0
  170. pyfect/ai/openai_compat/language_model.py +245 -0
  171. pyfect/ai/openai_compat/telemetry.py +51 -0
  172. pyfect/ai/openai_structured_output.py +118 -0
  173. pyfect/ai/openrouter/__init__.py +36 -0
  174. pyfect/ai/openrouter/_errors.py +186 -0
  175. pyfect/ai/openrouter/_prompt.py +272 -0
  176. pyfect/ai/openrouter/_response.py +226 -0
  177. pyfect/ai/openrouter/_stream.py +320 -0
  178. pyfect/ai/openrouter/client.py +283 -0
  179. pyfect/ai/openrouter/config.py +36 -0
  180. pyfect/ai/openrouter/decision_model.py +161 -0
  181. pyfect/ai/openrouter/error.py +23 -0
  182. pyfect/ai/openrouter/generated/__init__.py +3029 -0
  183. pyfect/ai/openrouter/generated/_recursive.py +15 -0
  184. pyfect/ai/openrouter/generated/_schemas_0.py +1015 -0
  185. pyfect/ai/openrouter/generated/_schemas_1.py +522 -0
  186. pyfect/ai/openrouter/generated/client.py +1445 -0
  187. pyfect/ai/openrouter/generated/types.py +4769 -0
  188. pyfect/ai/openrouter/language_model.py +345 -0
  189. pyfect/ai/openrouter/schema.py +165 -0
  190. pyfect/ai/prompt.py +664 -0
  191. pyfect/ai/response.py +768 -0
  192. pyfect/ai/response_id_tracker.py +82 -0
  193. pyfect/ai/telemetry.py +126 -0
  194. pyfect/ai/tokenizer.py +61 -0
  195. pyfect/ai/tool.py +536 -0
  196. pyfect/ai/toolkit.py +490 -0
  197. pyfect/ai/typesafe/__init__.py +17 -0
  198. pyfect/ai/typesafe/_errors.py +120 -0
  199. pyfect/ai/typesafe/client.py +146 -0
  200. pyfect/ai/typesafe/config.py +34 -0
  201. pyfect/ai/typesafe/decision_model.py +90 -0
  202. pyfect/ai/typesafe/schema.py +140 -0
  203. pyfect/batching/__init__.py +58 -0
  204. pyfect/batching/_api.py +71 -0
  205. pyfect/batching/_engine.py +229 -0
  206. pyfect/batching/_from_effect.py +76 -0
  207. pyfect/batching/_persisted.py +98 -0
  208. pyfect/batching/_request.py +133 -0
  209. pyfect/batching/_resolver.py +477 -0
  210. pyfect/batching/_with_cache.py +90 -0
  211. pyfect/big_decimal.py +500 -0
  212. pyfect/brand.py +114 -0
  213. pyfect/byte_size.py +354 -0
  214. pyfect/cache/__init__.py +29 -0
  215. pyfect/cache/_cache.py +426 -0
  216. pyfect/cache/_expiry.py +69 -0
  217. pyfect/cache/_scoped_cache.py +546 -0
  218. pyfect/case.py +174 -0
  219. pyfect/cause.py +462 -0
  220. pyfect/channel/__init__.py +155 -0
  221. pyfect/channel/_base.py +92 -0
  222. pyfect/channel/_catch.py +158 -0
  223. pyfect/channel/_catch_reason.py +572 -0
  224. pyfect/channel/_channel.py +158 -0
  225. pyfect/channel/_combinators.py +220 -0
  226. pyfect/channel/_concurrency_methods.py +217 -0
  227. pyfect/channel/_concurrent_map.py +118 -0
  228. pyfect/channel/_constructors.py +349 -0
  229. pyfect/channel/_context.py +232 -0
  230. pyfect/channel/_error_methods.py +336 -0
  231. pyfect/channel/_errors.py +180 -0
  232. pyfect/channel/_filters.py +225 -0
  233. pyfect/channel/_lifecycle.py +71 -0
  234. pyfect/channel/_lifecycle_methods.py +206 -0
  235. pyfect/channel/_loop.py +100 -0
  236. pyfect/channel/_merge.py +246 -0
  237. pyfect/channel/_repeat.py +154 -0
  238. pyfect/channel/_run.py +149 -0
  239. pyfect/channel/_run_methods.py +341 -0
  240. pyfect/channel/_sinks.py +88 -0
  241. pyfect/channel/_sources.py +238 -0
  242. pyfect/channel/_text.py +176 -0
  243. pyfect/channel/_transform_methods.py +415 -0
  244. pyfect/channel/_upstream.py +67 -0
  245. pyfect/channel_schema.py +131 -0
  246. pyfect/cli/__init__.py +79 -0
  247. pyfect/cli/_ansi.py +82 -0
  248. pyfect/cli/_command.py +469 -0
  249. pyfect/cli/_config.py +164 -0
  250. pyfect/cli/_environment.py +10 -0
  251. pyfect/cli/_help.py +195 -0
  252. pyfect/cli/_lexer.py +81 -0
  253. pyfect/cli/_parser.py +465 -0
  254. pyfect/cli/_settings.py +85 -0
  255. pyfect/cli/_suggest.py +33 -0
  256. pyfect/cli/_width.py +134 -0
  257. pyfect/cli/_wizard.py +317 -0
  258. pyfect/cli/argument.py +212 -0
  259. pyfect/cli/cli_config.py +40 -0
  260. pyfect/cli/cli_error.py +242 -0
  261. pyfect/cli/cli_output.py +305 -0
  262. pyfect/cli/command.py +440 -0
  263. pyfect/cli/completions/__init__.py +50 -0
  264. pyfect/cli/completions/_completer.ps1 +190 -0
  265. pyfect/cli/completions/_descriptor.py +182 -0
  266. pyfect/cli/completions/bash.py +300 -0
  267. pyfect/cli/completions/fish.py +164 -0
  268. pyfect/cli/completions/powershell.py +156 -0
  269. pyfect/cli/completions/zsh.py +189 -0
  270. pyfect/cli/flag.py +246 -0
  271. pyfect/cli/global_flag.py +99 -0
  272. pyfect/cli/help_doc.py +63 -0
  273. pyfect/cli/param.py +789 -0
  274. pyfect/cli/primitive.py +308 -0
  275. pyfect/cli/prompt/__init__.py +75 -0
  276. pyfect/cli/prompt/_auto_complete.py +205 -0
  277. pyfect/cli/prompt/_choices.py +104 -0
  278. pyfect/cli/prompt/_confirm.py +195 -0
  279. pyfect/cli/prompt/_core.py +512 -0
  280. pyfect/cli/prompt/_date.py +173 -0
  281. pyfect/cli/prompt/_date_parts.py +387 -0
  282. pyfect/cli/prompt/_file.py +372 -0
  283. pyfect/cli/prompt/_multi_select.py +204 -0
  284. pyfect/cli/prompt/_number.py +257 -0
  285. pyfect/cli/prompt/_select.py +117 -0
  286. pyfect/cli/prompt/_text.py +239 -0
  287. pyfect/cli/terminal_capabilities.py +118 -0
  288. pyfect/clock.py +150 -0
  289. pyfect/cluster/__init__.py +155 -0
  290. pyfect/cluster/_cluster_abandon.py +36 -0
  291. pyfect/cluster/_cluster_layer.py +122 -0
  292. pyfect/cluster/_entity_activation.py +16 -0
  293. pyfect/cluster/_entity_manager/__init__.py +22 -0
  294. pyfect/cluster/_entity_manager/_activation.py +540 -0
  295. pyfect/cluster/_entity_manager/_core.py +186 -0
  296. pyfect/cluster/_entity_manager/_decode.py +60 -0
  297. pyfect/cluster/_entity_manager/_manager.py +423 -0
  298. pyfect/cluster/_entity_manager/_state.py +113 -0
  299. pyfect/cluster/_entity_reaper.py +94 -0
  300. pyfect/cluster/_hash.py +13 -0
  301. pyfect/cluster/_interruptors.py +88 -0
  302. pyfect/cluster/_resource_map.py +179 -0
  303. pyfect/cluster/_resource_ref.py +266 -0
  304. pyfect/cluster/_shard_lock.py +14 -0
  305. pyfect/cluster/cluster_cron.py +230 -0
  306. pyfect/cluster/cluster_error.py +81 -0
  307. pyfect/cluster/cluster_http.py +210 -0
  308. pyfect/cluster/cluster_metrics.py +54 -0
  309. pyfect/cluster/cluster_schema.py +137 -0
  310. pyfect/cluster/cluster_socket.py +197 -0
  311. pyfect/cluster/cluster_workflow_engine/__init__.py +24 -0
  312. pyfect/cluster/cluster_workflow_engine/_engine.py +1099 -0
  313. pyfect/cluster/cluster_workflow_engine/_entities.py +298 -0
  314. pyfect/cluster/deliver_at.py +31 -0
  315. pyfect/cluster/entity/__init__.py +39 -0
  316. pyfect/cluster/entity/_entity.py +332 -0
  317. pyfect/cluster/entity/_handlers.py +168 -0
  318. pyfect/cluster/entity/_keep_alive.py +74 -0
  319. pyfect/cluster/entity/_queue.py +103 -0
  320. pyfect/cluster/entity/_request.py +34 -0
  321. pyfect/cluster/entity/_services.py +23 -0
  322. pyfect/cluster/entity/_test_client.py +237 -0
  323. pyfect/cluster/entity_address.py +25 -0
  324. pyfect/cluster/entity_id.py +20 -0
  325. pyfect/cluster/entity_proxy.py +161 -0
  326. pyfect/cluster/entity_proxy_server.py +103 -0
  327. pyfect/cluster/entity_resource.py +122 -0
  328. pyfect/cluster/entity_type.py +20 -0
  329. pyfect/cluster/envelope.py +307 -0
  330. pyfect/cluster/http_runner.py +254 -0
  331. pyfect/cluster/k8s_http_client.py +281 -0
  332. pyfect/cluster/k8s_types.py +1394 -0
  333. pyfect/cluster/machine_id.py +21 -0
  334. pyfect/cluster/message.py +219 -0
  335. pyfect/cluster/message_storage/__init__.py +67 -0
  336. pyfect/cluster/message_storage/_encoded.py +393 -0
  337. pyfect/cluster/message_storage/_memory.py +386 -0
  338. pyfect/cluster/message_storage/_noop.py +109 -0
  339. pyfect/cluster/message_storage/_service.py +388 -0
  340. pyfect/cluster/reply.py +236 -0
  341. pyfect/cluster/runner.py +32 -0
  342. pyfect/cluster/runner_address.py +23 -0
  343. pyfect/cluster/runner_health.py +93 -0
  344. pyfect/cluster/runner_server.py +286 -0
  345. pyfect/cluster/runner_storage.py +212 -0
  346. pyfect/cluster/runners/__init__.py +55 -0
  347. pyfect/cluster/runners/_local.py +460 -0
  348. pyfect/cluster/runners/_noop.py +57 -0
  349. pyfect/cluster/runners/_rpc.py +290 -0
  350. pyfect/cluster/runners/_service.py +113 -0
  351. pyfect/cluster/shard_id.py +39 -0
  352. pyfect/cluster/sharding/__init__.py +12 -0
  353. pyfect/cluster/sharding/_acquisition.py +490 -0
  354. pyfect/cluster/sharding/_clients.py +271 -0
  355. pyfect/cluster/sharding/_make.py +388 -0
  356. pyfect/cluster/sharding/_routing.py +296 -0
  357. pyfect/cluster/sharding/_runners_sync.py +198 -0
  358. pyfect/cluster/sharding/_service.py +91 -0
  359. pyfect/cluster/sharding/_singletons.py +183 -0
  360. pyfect/cluster/sharding/_state.py +296 -0
  361. pyfect/cluster/sharding/_storage_loop.py +421 -0
  362. pyfect/cluster/sharding_config.py +230 -0
  363. pyfect/cluster/sharding_registration_event.py +28 -0
  364. pyfect/cluster/single_runner.py +49 -0
  365. pyfect/cluster/singleton.py +36 -0
  366. pyfect/cluster/singleton_address.py +20 -0
  367. pyfect/cluster/snowflake.py +133 -0
  368. pyfect/cluster/socket_runner.py +67 -0
  369. pyfect/cluster/sql_message_storage.py +1001 -0
  370. pyfect/cluster/sql_runner_storage.py +841 -0
  371. pyfect/cluster/test_runner.py +23 -0
  372. pyfect/config/__init__.py +93 -0
  373. pyfect/config/_all.py +96 -0
  374. pyfect/config/_collections.py +291 -0
  375. pyfect/config/_config.py +261 -0
  376. pyfect/config/_constructors.py +106 -0
  377. pyfect/config/_error.py +27 -0
  378. pyfect/config/_leaf.py +92 -0
  379. pyfect/config/_scalars.py +193 -0
  380. pyfect/config/_schema.py +340 -0
  381. pyfect/config_provider/__init__.py +60 -0
  382. pyfect/config_provider/_dir.py +84 -0
  383. pyfect/config_provider/_dotenv.py +127 -0
  384. pyfect/config_provider/_env.py +79 -0
  385. pyfect/config_provider/_layers.py +80 -0
  386. pyfect/config_provider/_node.py +90 -0
  387. pyfect/config_provider/_provider.py +118 -0
  388. pyfect/config_provider/_unknown.py +62 -0
  389. pyfect/console/__init__.py +63 -0
  390. pyfect/console/_effects.py +134 -0
  391. pyfect/console/_live.py +156 -0
  392. pyfect/console/_service.py +49 -0
  393. pyfect/console/_table.py +90 -0
  394. pyfect/context.py +414 -0
  395. pyfect/cron/__init__.py +30 -0
  396. pyfect/cron/_model.py +183 -0
  397. pyfect/cron/_search.py +268 -0
  398. pyfect/cron/_text.py +202 -0
  399. pyfect/cron/_wall.py +42 -0
  400. pyfect/crypto.py +257 -0
  401. pyfect/date_time/__init__.py +77 -0
  402. pyfect/date_time/_calendar.py +209 -0
  403. pyfect/date_time/_current.py +118 -0
  404. pyfect/date_time/_epoch.py +22 -0
  405. pyfect/date_time/_iso.py +80 -0
  406. pyfect/date_time/_zones.py +135 -0
  407. pyfect/date_time/intl.py +144 -0
  408. pyfect/deferred.py +145 -0
  409. pyfect/devtools/__init__.py +24 -0
  410. pyfect/devtools/client.py +323 -0
  411. pyfect/devtools/layers.py +32 -0
  412. pyfect/devtools/schema.py +301 -0
  413. pyfect/devtools/server.py +72 -0
  414. pyfect/duration.py +295 -0
  415. pyfect/effect.py +565 -0
  416. pyfect/effectable.py +37 -0
  417. pyfect/encoding/__init__.py +62 -0
  418. pyfect/encoding/_archive.py +197 -0
  419. pyfect/encoding/_json_array_scanner.py +477 -0
  420. pyfect/encoding/base64.py +23 -0
  421. pyfect/encoding/base64_url.py +19 -0
  422. pyfect/encoding/encoding_error.py +17 -0
  423. pyfect/encoding/hex.py +28 -0
  424. pyfect/encoding/ini.py +188 -0
  425. pyfect/encoding/json_array.py +246 -0
  426. pyfect/encoding/ndjson.py +461 -0
  427. pyfect/encoding/schema_binary/__init__.py +257 -0
  428. pyfect/encoding/schema_binary/_channels.py +173 -0
  429. pyfect/encoding/schema_binary/_compile.py +584 -0
  430. pyfect/encoding/schema_binary/_decode.py +848 -0
  431. pyfect/encoding/schema_binary/_dictionary.py +90 -0
  432. pyfect/encoding/schema_binary/_encode.py +838 -0
  433. pyfect/encoding/schema_binary/_fingerprint.py +168 -0
  434. pyfect/encoding/schema_binary/_layout.py +350 -0
  435. pyfect/encoding/schema_binary/_literals.py +47 -0
  436. pyfect/encoding/schema_binary/_parser.py +163 -0
  437. pyfect/encoding/schema_binary/_reader.py +148 -0
  438. pyfect/encoding/schema_binary/_target.py +310 -0
  439. pyfect/encoding/schema_binary/_values.py +133 -0
  440. pyfect/encoding/schema_binary/_wire.py +253 -0
  441. pyfect/encoding/sse.py +476 -0
  442. pyfect/encoding/tar/__init__.py +396 -0
  443. pyfect/encoding/tar/_decoder.py +220 -0
  444. pyfect/encoding/tar/_encoder.py +83 -0
  445. pyfect/encoding/tar/_header.py +494 -0
  446. pyfect/encoding/tar/_model.py +82 -0
  447. pyfect/encoding/toml.py +375 -0
  448. pyfect/encoding/xml/__init__.py +222 -0
  449. pyfect/encoding/xml/_chars.py +119 -0
  450. pyfect/encoding/xml/_collector.py +106 -0
  451. pyfect/encoding/xml/_inputs.py +126 -0
  452. pyfect/encoding/xml/_model.py +114 -0
  453. pyfect/encoding/xml/_parser.py +694 -0
  454. pyfect/encoding/xml/_scanner.py +180 -0
  455. pyfect/encoding/xml/_writer.py +238 -0
  456. pyfect/encoding/yaml.py +739 -0
  457. pyfect/encoding/zip/__init__.py +392 -0
  458. pyfect/encoding/zip/_decoder.py +378 -0
  459. pyfect/encoding/zip/_format.py +122 -0
  460. pyfect/encoding/zip/_inflate.py +65 -0
  461. pyfect/encoding/zip/_model.py +86 -0
  462. pyfect/encoding/zip/_writer.py +311 -0
  463. pyfect/error_reporter.py +240 -0
  464. pyfect/errors.py +321 -0
  465. pyfect/eventlog/__init__.py +77 -0
  466. pyfect/eventlog/_conflicts.py +94 -0
  467. pyfect/eventlog/_crypto.py +64 -0
  468. pyfect/eventlog/_identity.py +26 -0
  469. pyfect/eventlog/_identity_derivation.py +79 -0
  470. pyfect/eventlog/_transferable_bytes.py +55 -0
  471. pyfect/eventlog/_uuid.py +33 -0
  472. pyfect/eventlog/event.py +115 -0
  473. pyfect/eventlog/event_group.py +55 -0
  474. pyfect/eventlog/event_journal.py +630 -0
  475. pyfect/eventlog/event_log.py +1039 -0
  476. pyfect/eventlog/event_log_encryption.py +219 -0
  477. pyfect/eventlog/event_log_message.py +357 -0
  478. pyfect/eventlog/event_log_remote.py +465 -0
  479. pyfect/eventlog/event_log_server.py +442 -0
  480. pyfect/eventlog/event_log_server_encrypted.py +322 -0
  481. pyfect/eventlog/event_log_server_unencrypted.py +814 -0
  482. pyfect/eventlog/event_log_session_auth.py +250 -0
  483. pyfect/eventlog/event_row.py +423 -0
  484. pyfect/eventlog/sql_event_journal.py +692 -0
  485. pyfect/eventlog/sql_event_log_server_encrypted.py +440 -0
  486. pyfect/eventlog/sql_event_log_server_unencrypted.py +568 -0
  487. pyfect/execution_plan/__init__.py +42 -0
  488. pyfect/execution_plan/_events.py +128 -0
  489. pyfect/execution_plan/_model.py +108 -0
  490. pyfect/execution_plan/_run.py +176 -0
  491. pyfect/exit.py +205 -0
  492. pyfect/fiber_handle.py +305 -0
  493. pyfect/fiber_map.py +350 -0
  494. pyfect/fiber_set.py +232 -0
  495. pyfect/file_system/__init__.py +69 -0
  496. pyfect/file_system/_copy.py +116 -0
  497. pyfect/file_system/_errors.py +32 -0
  498. pyfect/file_system/_file.py +177 -0
  499. pyfect/file_system/_live.py +351 -0
  500. pyfect/file_system/_model.py +72 -0
  501. pyfect/file_system/_noop.py +189 -0
  502. pyfect/file_system/_service.py +336 -0
  503. pyfect/file_system/_stat.py +69 -0
  504. pyfect/file_system/_watch.py +107 -0
  505. pyfect/filters.py +245 -0
  506. pyfect/graph/__init__.py +101 -0
  507. pyfect/graph/_all_pairs.py +150 -0
  508. pyfect/graph/_combine.py +259 -0
  509. pyfect/graph/_compact.py +143 -0
  510. pyfect/graph/_components.py +200 -0
  511. pyfect/graph/_cycles.py +144 -0
  512. pyfect/graph/_enumerate.py +168 -0
  513. pyfect/graph/_errors.py +51 -0
  514. pyfect/graph/_flow.py +164 -0
  515. pyfect/graph/_forest.py +109 -0
  516. pyfect/graph/_graph.py +269 -0
  517. pyfect/graph/_lowlink.py +98 -0
  518. pyfect/graph/_matching.py +101 -0
  519. pyfect/graph/_mutate.py +211 -0
  520. pyfect/graph/_query.py +138 -0
  521. pyfect/graph/_records.py +119 -0
  522. pyfect/graph/_render.py +109 -0
  523. pyfect/graph/_shortest.py +274 -0
  524. pyfect/graph/_snapshot.py +50 -0
  525. pyfect/graph/_store.py +136 -0
  526. pyfect/graph/_traverse.py +289 -0
  527. pyfect/graph/_view.py +384 -0
  528. pyfect/graph/_walker.py +70 -0
  529. pyfect/graphql/__init__.py +87 -0
  530. pyfect/graphql/_codec.py +117 -0
  531. pyfect/graphql/_http.py +309 -0
  532. pyfect/graphql/_schemas.py +39 -0
  533. pyfect/graphql/_slices.py +110 -0
  534. pyfect/graphql/_template.py +111 -0
  535. pyfect/graphql/_types.py +115 -0
  536. pyfect/graphql/_ws.py +395 -0
  537. pyfect/graphql/_ws_messages.py +120 -0
  538. pyfect/graphql/client.py +428 -0
  539. pyfect/graphql/client_error.py +285 -0
  540. pyfect/graphql/group.py +142 -0
  541. pyfect/graphql/middleware.py +98 -0
  542. pyfect/graphql/operation.py +409 -0
  543. pyfect/graphql/protocol.py +119 -0
  544. pyfect/graphql/resolver.py +574 -0
  545. pyfect/graphql/template.py +61 -0
  546. pyfect/hash_map.py +317 -0
  547. pyfect/hash_ring.py +206 -0
  548. pyfect/hash_set.py +163 -0
  549. pyfect/http/__init__.py +125 -0
  550. pyfect/http/_asgi_listener.py +272 -0
  551. pyfect/http/_authority.py +63 -0
  552. pyfect/http/_brotli.py +27 -0
  553. pyfect/http/_compression.py +52 -0
  554. pyfect/http/_field.py +18 -0
  555. pyfect/http/_foreign_path.py +27 -0
  556. pyfect/http/_form_data.py +34 -0
  557. pyfect/http/_httpx_options.py +120 -0
  558. pyfect/http/_in_memory.py +76 -0
  559. pyfect/http/_request_state.py +59 -0
  560. pyfect/http/_vary.py +14 -0
  561. pyfect/http/abort.py +65 -0
  562. pyfect/http/asgi/__init__.py +59 -0
  563. pyfect/http/asgi/_app.py +155 -0
  564. pyfect/http/asgi/_http.py +201 -0
  565. pyfect/http/asgi/_mount.py +263 -0
  566. pyfect/http/asgi/_scope.py +86 -0
  567. pyfect/http/asgi/_serve.py +72 -0
  568. pyfect/http/asgi/_types.py +13 -0
  569. pyfect/http/asgi/_web_socket.py +325 -0
  570. pyfect/http/body.py +437 -0
  571. pyfect/http/client/__init__.py +111 -0
  572. pyfect/http/client/_circuit_breaker.py +113 -0
  573. pyfect/http/client/_cookie_jar.py +120 -0
  574. pyfect/http/client/_make.py +252 -0
  575. pyfect/http/client/_rate_limit.py +423 -0
  576. pyfect/http/client/_redirects.py +93 -0
  577. pyfect/http/client/_retry.py +115 -0
  578. pyfect/http/client/_service.py +497 -0
  579. pyfect/http/cookies.py +444 -0
  580. pyfect/http/error.py +188 -0
  581. pyfect/http/etag.py +96 -0
  582. pyfect/http/file_like.py +49 -0
  583. pyfect/http/find_my_way/__init__.py +10 -0
  584. pyfect/http/find_my_way/_nodes.py +186 -0
  585. pyfect/http/find_my_way/_paths.py +43 -0
  586. pyfect/http/find_my_way/_query_string.py +67 -0
  587. pyfect/http/find_my_way/_router.py +401 -0
  588. pyfect/http/headers.py +343 -0
  589. pyfect/http/http_effect.py +198 -0
  590. pyfect/http/httpx_client.py +291 -0
  591. pyfect/http/hypercorn_server.py +122 -0
  592. pyfect/http/incoming_message.py +140 -0
  593. pyfect/http/live_server/__init__.py +191 -0
  594. pyfect/http/live_server/_body.py +164 -0
  595. pyfect/http/live_server/_exchange.py +321 -0
  596. pyfect/http/live_server/_head.py +194 -0
  597. pyfect/http/live_server/_inbound.py +156 -0
  598. pyfect/http/live_server/_listener.py +211 -0
  599. pyfect/http/live_server/_serve.py +225 -0
  600. pyfect/http/live_server/_timers.py +20 -0
  601. pyfect/http/live_server/_upgrade.py +108 -0
  602. pyfect/http/live_server/_websocket.py +286 -0
  603. pyfect/http/live_server/_ws_frames.py +242 -0
  604. pyfect/http/method.py +30 -0
  605. pyfect/http/middleware/__init__.py +61 -0
  606. pyfect/http/middleware/_compression.py +156 -0
  607. pyfect/http/middleware/_cors.py +129 -0
  608. pyfect/http/middleware/_decompression.py +274 -0
  609. pyfect/http/middleware/_forwarded.py +113 -0
  610. pyfect/http/middleware/_logger.py +73 -0
  611. pyfect/http/middleware/_search_params.py +34 -0
  612. pyfect/http/middleware/_tracer.py +153 -0
  613. pyfect/http/middleware/_types.py +16 -0
  614. pyfect/http/mime/__init__.py +69 -0
  615. pyfect/http/mime/_types.py +361 -0
  616. pyfect/http/multipart.py +613 -0
  617. pyfect/http/multipart_parser/__init__.py +348 -0
  618. pyfect/http/multipart_parser/_content_type.py +109 -0
  619. pyfect/http/multipart_parser/_headers.py +206 -0
  620. pyfect/http/multipart_parser/_search.py +85 -0
  621. pyfect/http/origin.py +146 -0
  622. pyfect/http/platform.py +593 -0
  623. pyfect/http/prometheus.py +34 -0
  624. pyfect/http/request.py +384 -0
  625. pyfect/http/response.py +474 -0
  626. pyfect/http/router/__init__.py +82 -0
  627. pyfect/http/router/_api.py +462 -0
  628. pyfect/http/router/_in_memory.py +76 -0
  629. pyfect/http/router/_markers.py +47 -0
  630. pyfect/http/router/_middleware.py +181 -0
  631. pyfect/http/router/_middleware_stack.py +51 -0
  632. pyfect/http/router/_provided.py +31 -0
  633. pyfect/http/router/_route.py +114 -0
  634. pyfect/http/router/_router.py +308 -0
  635. pyfect/http/schema.py +276 -0
  636. pyfect/http/server.py +199 -0
  637. pyfect/http/server_error.py +261 -0
  638. pyfect/http/server_request.py +729 -0
  639. pyfect/http/server_respondable.py +77 -0
  640. pyfect/http/server_response.py +569 -0
  641. pyfect/http/static_server/__init__.py +257 -0
  642. pyfect/http/static_server/_conditional.py +72 -0
  643. pyfect/http/static_server/_mime.py +55 -0
  644. pyfect/http/static_server/_range.py +53 -0
  645. pyfect/http/status.py +51 -0
  646. pyfect/http/template.py +161 -0
  647. pyfect/http/trace_context.py +91 -0
  648. pyfect/http/url.py +442 -0
  649. pyfect/http/url_params.py +304 -0
  650. pyfect/http/uvicorn_server.py +119 -0
  651. pyfect/http/web.py +171 -0
  652. pyfect/http/web_handler.py +463 -0
  653. pyfect/http/wire.py +209 -0
  654. pyfect/http_api/__init__.py +83 -0
  655. pyfect/http_api/_assets/scalar.js +8 -0
  656. pyfect/http_api/_assets/swagger-ui.css +3 -0
  657. pyfect/http_api/_assets/swagger-ui.js +4 -0
  658. pyfect/http_api/_client_method.py +220 -0
  659. pyfect/http_api/_client_payload.py +144 -0
  660. pyfect/http_api/_client_response.py +377 -0
  661. pyfect/http_api/_handlers.py +282 -0
  662. pyfect/http_api/_html.py +38 -0
  663. pyfect/http_api/_media_type.py +6 -0
  664. pyfect/http_api/_openapi_responses.py +164 -0
  665. pyfect/http_api/_openapi_schemas.py +163 -0
  666. pyfect/http_api/_path.py +102 -0
  667. pyfect/http_api/_payload.py +260 -0
  668. pyfect/http_api/_response.py +363 -0
  669. pyfect/http_api/_security.py +174 -0
  670. pyfect/http_api/api.py +265 -0
  671. pyfect/http_api/builder.py +447 -0
  672. pyfect/http_api/client.py +474 -0
  673. pyfect/http_api/endpoint.py +969 -0
  674. pyfect/http_api/error.py +280 -0
  675. pyfect/http_api/group.py +215 -0
  676. pyfect/http_api/middleware.py +232 -0
  677. pyfect/http_api/openapi.py +396 -0
  678. pyfect/http_api/scalar.py +143 -0
  679. pyfect/http_api/schema.py +713 -0
  680. pyfect/http_api/security.py +91 -0
  681. pyfect/http_api/swagger.py +69 -0
  682. pyfect/http_api/test.py +105 -0
  683. pyfect/json_patch.py +255 -0
  684. pyfect/json_pointer.py +100 -0
  685. pyfect/json_schema/__init__.py +66 -0
  686. pyfect/json_schema/_api.py +96 -0
  687. pyfect/json_schema/_converter.py +258 -0
  688. pyfect/json_schema/_draft04.py +198 -0
  689. pyfect/json_schema/_draft07.py +203 -0
  690. pyfect/json_schema/_keywords.py +202 -0
  691. pyfect/json_schema/_model.py +201 -0
  692. pyfect/json_schema/_openapi.py +208 -0
  693. pyfect/latch.py +127 -0
  694. pyfect/layer.py +479 -0
  695. pyfect/layer_map.py +279 -0
  696. pyfect/layer_ref.py +208 -0
  697. pyfect/logger/__init__.py +91 -0
  698. pyfect/logger/_batched.py +49 -0
  699. pyfect/logger/_console.py +116 -0
  700. pyfect/logger/_file.py +31 -0
  701. pyfect/logger/_formats.py +104 -0
  702. pyfect/logger/_layer.py +50 -0
  703. pyfect/logger/_level.py +53 -0
  704. pyfect/logger/_log.py +142 -0
  705. pyfect/logger/_model.py +163 -0
  706. pyfect/logger/_refs.py +78 -0
  707. pyfect/logger/_stdlib.py +54 -0
  708. pyfect/logger/_text.py +263 -0
  709. pyfect/logger/_tracer.py +35 -0
  710. pyfect/managed_runtime.py +393 -0
  711. pyfect/metric/__init__.py +119 -0
  712. pyfect/metric/_boundaries.py +27 -0
  713. pyfect/metric/_kinds.py +417 -0
  714. pyfect/metric/_metric.py +302 -0
  715. pyfect/metric/_prometheus.py +150 -0
  716. pyfect/metric/_refs.py +78 -0
  717. pyfect/metric/_runtime.py +75 -0
  718. pyfect/metric/_snapshot.py +97 -0
  719. pyfect/metric/_state.py +74 -0
  720. pyfect/msgspec.py +98 -0
  721. pyfect/mutable_hash_map.py +140 -0
  722. pyfect/mutable_hash_set.py +95 -0
  723. pyfect/net/__init__.py +18 -0
  724. pyfect/net/_errors.py +29 -0
  725. pyfect/net/address_resolver.py +179 -0
  726. pyfect/net/dns/__init__.py +92 -0
  727. pyfect/net/dns/_error.py +43 -0
  728. pyfect/net/dns/_records.py +335 -0
  729. pyfect/net/dns/_service.py +287 -0
  730. pyfect/net/dns/_system.py +89 -0
  731. pyfect/net/host.py +311 -0
  732. pyfect/net/ip_interface.py +202 -0
  733. pyfect/net/ip_network.py +250 -0
  734. pyfect/net/net_address/__init__.py +245 -0
  735. pyfect/net/net_address/_inet.py +412 -0
  736. pyfect/net/net_address/_ip.py +348 -0
  737. pyfect/net/net_address/_mac.py +119 -0
  738. pyfect/optic/__init__.py +50 -0
  739. pyfect/optic/_builtins.py +90 -0
  740. pyfect/optic/_data.py +97 -0
  741. pyfect/optic/_optic.py +422 -0
  742. pyfect/optic/_steps.py +151 -0
  743. pyfect/option.py +362 -0
  744. pyfect/otel/__init__.py +22 -0
  745. pyfect/otel/_attributes.py +67 -0
  746. pyfect/otel/_producer.py +322 -0
  747. pyfect/otel/_shutdown.py +26 -0
  748. pyfect/otel/_span.py +292 -0
  749. pyfect/otel/_wrapper.py +92 -0
  750. pyfect/otel/logger.py +154 -0
  751. pyfect/otel/metrics.py +126 -0
  752. pyfect/otel/resource.py +111 -0
  753. pyfect/otel/sdk.py +195 -0
  754. pyfect/otel/tracer.py +157 -0
  755. pyfect/partitioned_semaphore.py +211 -0
  756. pyfect/path.py +304 -0
  757. pyfect/persistence/__init__.py +77 -0
  758. pyfect/persistence/_columns.py +32 -0
  759. pyfect/persistence/_error.py +14 -0
  760. pyfect/persistence/_seconds.py +68 -0
  761. pyfect/persistence/_sql_keys.py +47 -0
  762. pyfect/persistence/circuit_breaker/__init__.py +120 -0
  763. pyfect/persistence/circuit_breaker/_breaker.py +317 -0
  764. pyfect/persistence/circuit_breaker/_errors.py +67 -0
  765. pyfect/persistence/circuit_breaker/_memory.py +243 -0
  766. pyfect/persistence/circuit_breaker/_redis.py +509 -0
  767. pyfect/persistence/circuit_breaker/_store.py +60 -0
  768. pyfect/persistence/circuit_breaker/_types.py +191 -0
  769. pyfect/persistence/key_value_store/__init__.py +51 -0
  770. pyfect/persistence/key_value_store/_layers.py +216 -0
  771. pyfect/persistence/key_value_store/_schema_store.py +91 -0
  772. pyfect/persistence/key_value_store/_sql.py +197 -0
  773. pyfect/persistence/key_value_store/_store.py +212 -0
  774. pyfect/persistence/persistable.py +164 -0
  775. pyfect/persistence/persisted_cache.py +159 -0
  776. pyfect/persistence/persisted_queue/__init__.py +75 -0
  777. pyfect/persistence/persisted_queue/_error.py +42 -0
  778. pyfect/persistence/persisted_queue/_mailbox.py +101 -0
  779. pyfect/persistence/persisted_queue/_memory.py +182 -0
  780. pyfect/persistence/persisted_queue/_queue.py +272 -0
  781. pyfect/persistence/persisted_queue/_redis.py +455 -0
  782. pyfect/persistence/persisted_queue/_redis_scripts.py +395 -0
  783. pyfect/persistence/persisted_queue/_sql.py +334 -0
  784. pyfect/persistence/persisted_queue/_sql_migrations.py +319 -0
  785. pyfect/persistence/persisted_queue/_sql_statements.py +441 -0
  786. pyfect/persistence/persisted_queue/_store.py +147 -0
  787. pyfect/persistence/persistence/__init__.py +84 -0
  788. pyfect/persistence/persistence/_kvs.py +135 -0
  789. pyfect/persistence/persistence/_memory.py +62 -0
  790. pyfect/persistence/persistence/_redis.py +162 -0
  791. pyfect/persistence/persistence/_service.py +276 -0
  792. pyfect/persistence/persistence/_sql.py +499 -0
  793. pyfect/persistence/rate_limiter/__init__.py +82 -0
  794. pyfect/persistence/rate_limiter/_errors.py +59 -0
  795. pyfect/persistence/rate_limiter/_limiter.py +325 -0
  796. pyfect/persistence/rate_limiter/_memory.py +217 -0
  797. pyfect/persistence/rate_limiter/_redis.py +485 -0
  798. pyfect/persistence/rate_limiter/_store.py +89 -0
  799. pyfect/persistence/redis/__init__.py +52 -0
  800. pyfect/persistence/redis/_error.py +12 -0
  801. pyfect/persistence/redis/_make.py +234 -0
  802. pyfect/persistence/redis/_script.py +78 -0
  803. pyfect/persistence/redis/_service.py +104 -0
  804. pyfect/persistence/redis_py.py +303 -0
  805. pyfect/persistence/user_directories.py +195 -0
  806. pyfect/platform.py +26 -0
  807. pyfect/platform_error.py +256 -0
  808. pyfect/pool/__init__.py +36 -0
  809. pyfect/pool/_pool.py +707 -0
  810. pyfect/pool/_state.py +161 -0
  811. pyfect/pool/_ttl.py +105 -0
  812. pyfect/pool/_waiters.py +116 -0
  813. pyfect/primary_key.py +35 -0
  814. pyfect/process/__init__.py +82 -0
  815. pyfect/process/_child.py +213 -0
  816. pyfect/process/_command.py +358 -0
  817. pyfect/process/_handle.py +77 -0
  818. pyfect/process/_live.py +455 -0
  819. pyfect/process/_os.py +78 -0
  820. pyfect/process/_pipes.py +291 -0
  821. pyfect/process/_spawner.py +75 -0
  822. pyfect/pubsub/__init__.py +33 -0
  823. pyfect/pubsub/_atomic.py +181 -0
  824. pyfect/pubsub/_hub.py +214 -0
  825. pyfect/pubsub/_pubsub.py +214 -0
  826. pyfect/pubsub/_replay.py +107 -0
  827. pyfect/pubsub/_subscription.py +226 -0
  828. pyfect/pull.py +132 -0
  829. pyfect/py.typed +0 -0
  830. pyfect/pydantic.py +188 -0
  831. pyfect/queue/__init__.py +33 -0
  832. pyfect/queue/_queue.py +525 -0
  833. pyfect/queue/_state.py +111 -0
  834. pyfect/queue/_views.py +55 -0
  835. pyfect/random.py +146 -0
  836. pyfect/rc_map.py +363 -0
  837. pyfect/rc_ref.py +271 -0
  838. pyfect/reactivity/__init__.py +53 -0
  839. pyfect/reactivity/_async_result_schema.py +227 -0
  840. pyfect/reactivity/_hydration.py +18 -0
  841. pyfect/reactivity/_live.py +21 -0
  842. pyfect/reactivity/_reactivity.py +256 -0
  843. pyfect/reactivity/_result_effect.py +17 -0
  844. pyfect/reactivity/_time.py +11 -0
  845. pyfect/reactivity/async_result.py +679 -0
  846. pyfect/reactivity/atom/__init__.py +143 -0
  847. pyfect/reactivity/atom/_combinators.py +223 -0
  848. pyfect/reactivity/atom/_constructors.py +80 -0
  849. pyfect/reactivity/atom/_conversions.py +79 -0
  850. pyfect/reactivity/atom/_effect.py +252 -0
  851. pyfect/reactivity/atom/_fn.py +341 -0
  852. pyfect/reactivity/atom/_kvs.py +101 -0
  853. pyfect/reactivity/atom/_optimistic.py +162 -0
  854. pyfect/reactivity/atom/_runtime.py +323 -0
  855. pyfect/reactivity/atom/_serializable.py +65 -0
  856. pyfect/reactivity/atom/_subscription_ref.py +102 -0
  857. pyfect/reactivity/atom/_swr.py +69 -0
  858. pyfect/reactivity/atom/_types.py +435 -0
  859. pyfect/reactivity/atom_http_api.py +667 -0
  860. pyfect/reactivity/atom_ref.py +260 -0
  861. pyfect/reactivity/atom_registry/__init__.py +219 -0
  862. pyfect/reactivity/atom_registry/_batch.py +96 -0
  863. pyfect/reactivity/atom_registry/_dispatcher.py +60 -0
  864. pyfect/reactivity/atom_registry/_lifetime.py +202 -0
  865. pyfect/reactivity/atom_registry/_node.py +423 -0
  866. pyfect/reactivity/atom_registry/_registry.py +380 -0
  867. pyfect/reactivity/atom_rpc.py +283 -0
  868. pyfect/reactivity/hydration.py +200 -0
  869. pyfect/redacted.py +83 -0
  870. pyfect/ref.py +129 -0
  871. pyfect/resource.py +98 -0
  872. pyfect/result.py +306 -0
  873. pyfect/rpc/__init__.py +64 -0
  874. pyfect/rpc/_encoded_schema.py +86 -0
  875. pyfect/rpc/_json_rpc.py +246 -0
  876. pyfect/rpc/_methods.py +177 -0
  877. pyfect/rpc/_rpc.py +498 -0
  878. pyfect/rpc/client/__init__.py +100 -0
  879. pyfect/rpc/client/_core.py +449 -0
  880. pyfect/rpc/client/_http.py +257 -0
  881. pyfect/rpc/client/_protocol.py +171 -0
  882. pyfect/rpc/client/_serialized.py +321 -0
  883. pyfect/rpc/client/_transports.py +328 -0
  884. pyfect/rpc/client/_worker.py +283 -0
  885. pyfect/rpc/client_error.py +35 -0
  886. pyfect/rpc/group.py +296 -0
  887. pyfect/rpc/message.py +299 -0
  888. pyfect/rpc/middleware.py +182 -0
  889. pyfect/rpc/schema.py +89 -0
  890. pyfect/rpc/serialization.py +366 -0
  891. pyfect/rpc/server/__init__.py +181 -0
  892. pyfect/rpc/server/_core.py +549 -0
  893. pyfect/rpc/server/_protocol.py +123 -0
  894. pyfect/rpc/server/_serialized.py +363 -0
  895. pyfect/rpc/server/_stdio.py +101 -0
  896. pyfect/rpc/server/_transports.py +427 -0
  897. pyfect/rpc/server/_worker.py +108 -0
  898. pyfect/rpc/test.py +74 -0
  899. pyfect/rpc/worker.py +92 -0
  900. pyfect/run.py +393 -0
  901. pyfect/schedule/__init__.py +91 -0
  902. pyfect/schedule/_combinators.py +168 -0
  903. pyfect/schedule/_constructors.py +223 -0
  904. pyfect/schedule/_cron.py +49 -0
  905. pyfect/schedule/_drive.py +191 -0
  906. pyfect/schedule/_model.py +405 -0
  907. pyfect/scheduler.py +575 -0
  908. pyfect/schema/__init__.py +866 -0
  909. pyfect/schema/_adapters.py +39 -0
  910. pyfect/schema/_arbitrary_constraint.py +242 -0
  911. pyfect/schema/_arbitrary_graph.py +325 -0
  912. pyfect/schema/_arbitrary_links.py +179 -0
  913. pyfect/schema/_arbitrary_number.py +112 -0
  914. pyfect/schema/_arrays.py +287 -0
  915. pyfect/schema/_assignable.py +118 -0
  916. pyfect/schema/_boolean_literals.py +31 -0
  917. pyfect/schema/_checks_number.py +216 -0
  918. pyfect/schema/_checks_order.py +140 -0
  919. pyfect/schema/_checks_size.py +277 -0
  920. pyfect/schema/_checks_string.py +241 -0
  921. pyfect/schema/_class.py +569 -0
  922. pyfect/schema/_codec_derivation.py +227 -0
  923. pyfect/schema/_codec_links.py +221 -0
  924. pyfect/schema/_codecs.py +316 -0
  925. pyfect/schema/_collections.py +172 -0
  926. pyfect/schema/_constructor_default.py +89 -0
  927. pyfect/schema/_data.py +440 -0
  928. pyfect/schema/_data_codecs.py +145 -0
  929. pyfect/schema/_decimal_regexp.py +243 -0
  930. pyfect/schema/_declare.py +68 -0
  931. pyfect/schema/_derive.py +292 -0
  932. pyfect/schema/_duration_codecs.py +27 -0
  933. pyfect/schema/_ecma_pattern.py +416 -0
  934. pyfect/schema/_error.py +26 -0
  935. pyfect/schema/_error_instance.py +222 -0
  936. pyfect/schema/_graph.py +271 -0
  937. pyfect/schema/_instances.py +240 -0
  938. pyfect/schema/_jsonschema/__init__.py +90 -0
  939. pyfect/schema/_jsonschema/_annotations.py +114 -0
  940. pyfect/schema/_jsonschema/_checks.py +253 -0
  941. pyfect/schema/_jsonschema/_compile.py +346 -0
  942. pyfect/schema/_jsonschema/_exact.py +19 -0
  943. pyfect/schema/_jsonschema/_merge.py +211 -0
  944. pyfect/schema/_jsonschema/_objects.py +231 -0
  945. pyfect/schema/_jsonschema/_references.py +221 -0
  946. pyfect/schema/_jsonschema/_template.py +69 -0
  947. pyfect/schema/_literals.py +147 -0
  948. pyfect/schema/_middleware.py +209 -0
  949. pyfect/schema/_net.py +522 -0
  950. pyfect/schema/_options.py +49 -0
  951. pyfect/schema/_parse.py +351 -0
  952. pyfect/schema/_parsed_text.py +37 -0
  953. pyfect/schema/_primitives.py +48 -0
  954. pyfect/schema/_record.py +41 -0
  955. pyfect/schema/_refine.py +81 -0
  956. pyfect/schema/_schema.py +158 -0
  957. pyfect/schema/_semver.py +144 -0
  958. pyfect/schema/_strategy/__init__.py +258 -0
  959. pyfect/schema/_strategy/_big_decimal.py +203 -0
  960. pyfect/schema/_strategy/_composites.py +119 -0
  961. pyfect/schema/_strategy/_leaves.py +94 -0
  962. pyfect/schema/_strategy/_net.py +133 -0
  963. pyfect/schema/_struct.py +87 -0
  964. pyfect/schema/_struct_keys.py +128 -0
  965. pyfect/schema/_tagged.py +254 -0
  966. pyfect/schema/_template_literal.py +172 -0
  967. pyfect/schema/_to_codec_array_from_single.py +115 -0
  968. pyfect/schema/_to_codec_go_json.py +174 -0
  969. pyfect/schema/_to_codec_json.py +73 -0
  970. pyfect/schema/_to_codec_string_tree.py +115 -0
  971. pyfect/schema/_to_differ_json_patch.py +44 -0
  972. pyfect/schema/_to_encoder_xml.py +119 -0
  973. pyfect/schema/_to_equivalence.py +186 -0
  974. pyfect/schema/_to_formatter.py +180 -0
  975. pyfect/schema/_to_iso.py +73 -0
  976. pyfect/schema/_to_strategy.py +31 -0
  977. pyfect/schema/_transform.py +210 -0
  978. pyfect/schema/_tree.py +27 -0
  979. pyfect/schema/_type_walk.py +53 -0
  980. pyfect/schema/_undefined.py +58 -0
  981. pyfect/schema/_value_codecs.py +84 -0
  982. pyfect/schema/_values.py +123 -0
  983. pyfect/schema/_void.py +86 -0
  984. pyfect/schema/ast/__init__.py +227 -0
  985. pyfect/schema/ast/_annotations.py +43 -0
  986. pyfect/schema/ast/_arrays.py +210 -0
  987. pyfect/schema/ast/_base.py +295 -0
  988. pyfect/schema/ast/_candidates.py +309 -0
  989. pyfect/schema/ast/_check.py +181 -0
  990. pyfect/schema/ast/_class.py +159 -0
  991. pyfect/schema/ast/_constructors.py +65 -0
  992. pyfect/schema/ast/_declaration.py +97 -0
  993. pyfect/schema/ast/_encoding.py +111 -0
  994. pyfect/schema/ast/_json.py +129 -0
  995. pyfect/schema/ast/_keywords.py +125 -0
  996. pyfect/schema/ast/_literal.py +157 -0
  997. pyfect/schema/ast/_objects.py +356 -0
  998. pyfect/schema/ast/_record.py +36 -0
  999. pyfect/schema/ast/_result.py +116 -0
  1000. pyfect/schema/ast/_steps.py +209 -0
  1001. pyfect/schema/ast/_suspend.py +65 -0
  1002. pyfect/schema/ast/_template_literal.py +256 -0
  1003. pyfect/schema/ast/_union.py +172 -0
  1004. pyfect/schema/getter/__init__.py +136 -0
  1005. pyfect/schema/getter/_binary.py +104 -0
  1006. pyfect/schema/getter/_coerce.py +196 -0
  1007. pyfect/schema/getter/_getter.py +243 -0
  1008. pyfect/schema/getter/_make.py +151 -0
  1009. pyfect/schema/getter/_text.py +141 -0
  1010. pyfect/schema/getter/_tree_record.py +170 -0
  1011. pyfect/schema/issue.py +420 -0
  1012. pyfect/schema/model/__init__.py +120 -0
  1013. pyfect/schema/model/_class.py +245 -0
  1014. pyfect/schema/model/_dates.py +103 -0
  1015. pyfect/schema/model/_fields.py +77 -0
  1016. pyfect/schema/model/_toolkit.py +114 -0
  1017. pyfect/schema/model/_uuid.py +69 -0
  1018. pyfect/schema/representation/__init__.py +424 -0
  1019. pyfect/schema/representation/_builtin_revivers.py +331 -0
  1020. pyfect/schema/representation/_code.py +106 -0
  1021. pyfect/schema/representation/_code_builtins.py +281 -0
  1022. pyfect/schema/representation/_code_document.py +563 -0
  1023. pyfect/schema/representation/_code_sort.py +111 -0
  1024. pyfect/schema/representation/_from.py +278 -0
  1025. pyfect/schema/representation/_import/__init__.py +78 -0
  1026. pyfect/schema/representation/_import/_finalize.py +121 -0
  1027. pyfect/schema/representation/_import/_intersect.py +467 -0
  1028. pyfect/schema/representation/_import/_js_order.py +66 -0
  1029. pyfect/schema/representation/_import/_keywords.py +224 -0
  1030. pyfect/schema/representation/_import/_nodes.py +199 -0
  1031. pyfect/schema/representation/_import/_translate.py +455 -0
  1032. pyfect/schema/representation/_json.py +520 -0
  1033. pyfect/schema/representation/_json_schema.py +178 -0
  1034. pyfect/schema/representation/_model.py +284 -0
  1035. pyfect/schema/representation/_revivers.py +89 -0
  1036. pyfect/schema/representation/_to.py +249 -0
  1037. pyfect/schema/transformation/__init__.py +99 -0
  1038. pyfect/schema/transformation/_builtins.py +314 -0
  1039. pyfect/schema/transformation/_durations.py +150 -0
  1040. pyfect/schema/transformation/_transformation.py +177 -0
  1041. pyfect/schema/variant_schema/__init__.py +69 -0
  1042. pyfect/schema/variant_schema/_class.py +188 -0
  1043. pyfect/schema/variant_schema/_defaults.py +30 -0
  1044. pyfect/schema/variant_schema/_field.py +32 -0
  1045. pyfect/schema/variant_schema/_struct.py +130 -0
  1046. pyfect/schema/variant_schema/_toolkit.py +160 -0
  1047. pyfect/scope.py +374 -0
  1048. pyfect/scoped_ref.py +124 -0
  1049. pyfect/semaphore.py +276 -0
  1050. pyfect/semver.py +403 -0
  1051. pyfect/semver_range.py +420 -0
  1052. pyfect/sink/__init__.py +131 -0
  1053. pyfect/sink/_combinators.py +151 -0
  1054. pyfect/sink/_constructors.py +187 -0
  1055. pyfect/sink/_context.py +87 -0
  1056. pyfect/sink/_folds.py +336 -0
  1057. pyfect/sink/_for_each.py +87 -0
  1058. pyfect/sink/_sink.py +265 -0
  1059. pyfect/sink/_steps.py +34 -0
  1060. pyfect/sink/_taking.py +183 -0
  1061. pyfect/socket/__init__.py +146 -0
  1062. pyfect/socket/_accepted.py +65 -0
  1063. pyfect/socket/_connection.py +384 -0
  1064. pyfect/socket/_errors.py +135 -0
  1065. pyfect/socket/_loop.py +66 -0
  1066. pyfect/socket/_net.py +281 -0
  1067. pyfect/socket/_socket.py +245 -0
  1068. pyfect/socket/_tls.py +88 -0
  1069. pyfect/socket/_tls_session.py +117 -0
  1070. pyfect/socket/_web_socket.py +555 -0
  1071. pyfect/socket/datagram/__init__.py +110 -0
  1072. pyfect/socket/datagram/_core.py +460 -0
  1073. pyfect/socket/datagram/_errors.py +102 -0
  1074. pyfect/socket/datagram/_live.py +675 -0
  1075. pyfect/socket/datagram/_model.py +217 -0
  1076. pyfect/socket/server.py +258 -0
  1077. pyfect/socket/ws.py +484 -0
  1078. pyfect/sql/__init__.py +60 -0
  1079. pyfect/sql/_loop.py +134 -0
  1080. pyfect/sql/clickhouse/__init__.py +74 -0
  1081. pyfect/sql/clickhouse/_connection.py +237 -0
  1082. pyfect/sql/clickhouse/_rows.py +87 -0
  1083. pyfect/sql/clickhouse/client.py +322 -0
  1084. pyfect/sql/clickhouse/config.py +241 -0
  1085. pyfect/sql/clickhouse/driver.py +434 -0
  1086. pyfect/sql/clickhouse/error.py +106 -0
  1087. pyfect/sql/clickhouse/migrator.py +47 -0
  1088. pyfect/sql/clickhouse/params.py +168 -0
  1089. pyfect/sql/client/__init__.py +35 -0
  1090. pyfect/sql/client/_client.py +309 -0
  1091. pyfect/sql/client/_sqlite_acquirers.py +130 -0
  1092. pyfect/sql/client/_transaction.py +410 -0
  1093. pyfect/sql/connection.py +87 -0
  1094. pyfect/sql/d1/__init__.py +48 -0
  1095. pyfect/sql/d1/api.py +270 -0
  1096. pyfect/sql/d1/client.py +344 -0
  1097. pyfect/sql/d1/config.py +55 -0
  1098. pyfect/sql/error.py +311 -0
  1099. pyfect/sql/libsql/__init__.py +58 -0
  1100. pyfect/sql/libsql/_connection.py +110 -0
  1101. pyfect/sql/libsql/_hrana.py +258 -0
  1102. pyfect/sql/libsql/_local.py +251 -0
  1103. pyfect/sql/libsql/_targets.py +28 -0
  1104. pyfect/sql/libsql/_values.py +46 -0
  1105. pyfect/sql/libsql/client.py +225 -0
  1106. pyfect/sql/libsql/config.py +170 -0
  1107. pyfect/sql/libsql/migrator.py +43 -0
  1108. pyfect/sql/libsql/sdk.py +123 -0
  1109. pyfect/sql/migrator.py +434 -0
  1110. pyfect/sql/model.py +324 -0
  1111. pyfect/sql/mssql/__init__.py +79 -0
  1112. pyfect/sql/mssql/_connection.py +169 -0
  1113. pyfect/sql/mssql/_driver.py +103 -0
  1114. pyfect/sql/mssql/_names.py +9 -0
  1115. pyfect/sql/mssql/_pool.py +125 -0
  1116. pyfect/sql/mssql/_tds.py +447 -0
  1117. pyfect/sql/mssql/_tds_params.py +155 -0
  1118. pyfect/sql/mssql/_worker.py +155 -0
  1119. pyfect/sql/mssql/client.py +344 -0
  1120. pyfect/sql/mssql/config.py +118 -0
  1121. pyfect/sql/mssql/error.py +111 -0
  1122. pyfect/sql/mssql/migrator.py +43 -0
  1123. pyfect/sql/mssql/parameter.py +44 -0
  1124. pyfect/sql/mssql/procedure.py +119 -0
  1125. pyfect/sql/mssql/types.py +137 -0
  1126. pyfect/sql/mysql/__init__.py +60 -0
  1127. pyfect/sql/mysql/_asyncmy.py +168 -0
  1128. pyfect/sql/mysql/_bind.py +76 -0
  1129. pyfect/sql/mysql/_connection.py +156 -0
  1130. pyfect/sql/mysql/_pool.py +63 -0
  1131. pyfect/sql/mysql/_session.py +262 -0
  1132. pyfect/sql/mysql/client.py +244 -0
  1133. pyfect/sql/mysql/config.py +108 -0
  1134. pyfect/sql/mysql/error.py +104 -0
  1135. pyfect/sql/mysql/migrator.py +44 -0
  1136. pyfect/sql/pg/__init__.py +82 -0
  1137. pyfect/sql/pg/_resolve.py +284 -0
  1138. pyfect/sql/pg/_session.py +380 -0
  1139. pyfect/sql/pg/client.py +398 -0
  1140. pyfect/sql/pg/config.py +142 -0
  1141. pyfect/sql/pg/connection.py +585 -0
  1142. pyfect/sql/pg/error.py +131 -0
  1143. pyfect/sql/pg/migrator.py +139 -0
  1144. pyfect/sql/pg/pool.py +265 -0
  1145. pyfect/sql/resolver.py +294 -0
  1146. pyfect/sql/result.py +24 -0
  1147. pyfect/sql/schema.py +116 -0
  1148. pyfect/sql/sqlite/__init__.py +26 -0
  1149. pyfect/sql/sqlite/_connection.py +230 -0
  1150. pyfect/sql/sqlite/_worker.py +71 -0
  1151. pyfect/sql/sqlite/client.py +248 -0
  1152. pyfect/sql/sqlite/migrator.py +43 -0
  1153. pyfect/sql/statement/__init__.py +144 -0
  1154. pyfect/sql/statement/_compiler.py +384 -0
  1155. pyfect/sql/statement/_segments.py +487 -0
  1156. pyfect/sql/statement/_statement.py +526 -0
  1157. pyfect/sql/statement/_transforms.py +93 -0
  1158. pyfect/sql/stream.py +88 -0
  1159. pyfect/stdio.py +206 -0
  1160. pyfect/stream/__init__.py +151 -0
  1161. pyfect/stream/_async_iterable.py +129 -0
  1162. pyfect/stream/_base.py +69 -0
  1163. pyfect/stream/_bridge_methods.py +139 -0
  1164. pyfect/stream/_catch.py +135 -0
  1165. pyfect/stream/_catch_reason.py +558 -0
  1166. pyfect/stream/_channel_methods.py +61 -0
  1167. pyfect/stream/_chunk_methods.py +169 -0
  1168. pyfect/stream/_chunking.py +310 -0
  1169. pyfect/stream/_concat.py +65 -0
  1170. pyfect/stream/_constructors.py +341 -0
  1171. pyfect/stream/_context.py +147 -0
  1172. pyfect/stream/_error_methods.py +254 -0
  1173. pyfect/stream/_execution_plan.py +199 -0
  1174. pyfect/stream/_fanout.py +154 -0
  1175. pyfect/stream/_fanout_methods.py +183 -0
  1176. pyfect/stream/_filter_methods.py +203 -0
  1177. pyfect/stream/_grouping.py +168 -0
  1178. pyfect/stream/_many.py +65 -0
  1179. pyfect/stream/_map_methods.py +233 -0
  1180. pyfect/stream/_mapping.py +126 -0
  1181. pyfect/stream/_run.py +114 -0
  1182. pyfect/stream/_run_methods.py +114 -0
  1183. pyfect/stream/_service_methods.py +36 -0
  1184. pyfect/stream/_sink_methods.py +151 -0
  1185. pyfect/stream/_sinking.py +277 -0
  1186. pyfect/stream/_sources.py +124 -0
  1187. pyfect/stream/_stream.py +162 -0
  1188. pyfect/stream/_taking.py +330 -0
  1189. pyfect/stream/_text.py +43 -0
  1190. pyfect/stream/_timing.py +294 -0
  1191. pyfect/stream/_timing_methods.py +252 -0
  1192. pyfect/stream/_zip_methods.py +279 -0
  1193. pyfect/stream/_zipping.py +213 -0
  1194. pyfect/subscription_ref.py +66 -0
  1195. pyfect/synchronized_ref.py +38 -0
  1196. pyfect/take.py +36 -0
  1197. pyfect/terminal/__init__.py +41 -0
  1198. pyfect/terminal/_keys.py +113 -0
  1199. pyfect/terminal/_live.py +223 -0
  1200. pyfect/terminal/_service.py +73 -0
  1201. pyfect/testing/__init__.py +122 -0
  1202. pyfect/testing/_assertions.py +92 -0
  1203. pyfect/testing/_clock.py +309 -0
  1204. pyfect/testing/_console.py +164 -0
  1205. pyfect/testing/_crypto.py +44 -0
  1206. pyfect/testing/_decorators.py +211 -0
  1207. pyfect/testing/_flaky.py +34 -0
  1208. pyfect/testing/_layers.py +153 -0
  1209. pyfect/testing/_prop.py +255 -0
  1210. pyfect/testing/_runners.py +84 -0
  1211. pyfect/testing/_runtime.py +174 -0
  1212. pyfect/testing/_schema.py +238 -0
  1213. pyfect/testing/plugin.py +59 -0
  1214. pyfect/tracer/__init__.py +107 -0
  1215. pyfect/tracer/_model.py +176 -0
  1216. pyfect/tracer/_native.py +172 -0
  1217. pyfect/tracer/_refs.py +87 -0
  1218. pyfect/tracer/_spans.py +269 -0
  1219. pyfect/transaction.py +340 -0
  1220. pyfect/trie.py +317 -0
  1221. pyfect/tx_chunk.py +127 -0
  1222. pyfect/tx_deferred.py +75 -0
  1223. pyfect/tx_hash_map.py +265 -0
  1224. pyfect/tx_hash_set.py +151 -0
  1225. pyfect/tx_priority_queue.py +224 -0
  1226. pyfect/tx_pubsub.py +194 -0
  1227. pyfect/tx_queue/__init__.py +27 -0
  1228. pyfect/tx_queue/_queue.py +359 -0
  1229. pyfect/tx_queue/_views.py +60 -0
  1230. pyfect/tx_reentrant_lock.py +201 -0
  1231. pyfect/tx_ref.py +79 -0
  1232. pyfect/tx_semaphore.py +136 -0
  1233. pyfect/tx_subscription_ref.py +118 -0
  1234. pyfect/workers/__init__.py +62 -0
  1235. pyfect/workers/_frames.py +82 -0
  1236. pyfect/workers/_mailbox.py +51 -0
  1237. pyfect/workers/_port.py +106 -0
  1238. pyfect/workers/_process.py +155 -0
  1239. pyfect/workers/_thread.py +100 -0
  1240. pyfect/workers/python_worker.py +133 -0
  1241. pyfect/workers/python_worker_runner.py +112 -0
  1242. pyfect/workers/transferable.py +103 -0
  1243. pyfect/workers/worker.py +273 -0
  1244. pyfect/workers/worker_error.py +86 -0
  1245. pyfect/workers/worker_runner.py +85 -0
  1246. pyfect/workflow/__init__.py +78 -0
  1247. pyfect/workflow/_crypto.py +23 -0
  1248. pyfect/workflow/_encoded.py +381 -0
  1249. pyfect/workflow/_memory.py +424 -0
  1250. pyfect/workflow/_result.py +43 -0
  1251. pyfect/workflow/_services.py +241 -0
  1252. pyfect/workflow/_suspension.py +153 -0
  1253. pyfect/workflow/activity.py +427 -0
  1254. pyfect/workflow/durable_clock.py +72 -0
  1255. pyfect/workflow/durable_deferred.py +403 -0
  1256. pyfect/workflow/durable_queue.py +259 -0
  1257. pyfect/workflow/workflow.py +509 -0
  1258. pyfect/workflow/workflow_engine.py +42 -0
  1259. pyfect/workflow/workflow_proxy.py +161 -0
  1260. pyfect/workflow/workflow_proxy_server.py +146 -0
  1261. pyfect_dev-0.1.0.dist-info/METADATA +296 -0
  1262. pyfect_dev-0.1.0.dist-info/RECORD +1265 -0
  1263. pyfect_dev-0.1.0.dist-info/WHEEL +4 -0
  1264. pyfect_dev-0.1.0.dist-info/entry_points.txt +3 -0
  1265. pyfect_dev-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1099 @@
1
+ """The cluster workflow engine (Effect's ``ClusterWorkflowEngine.make``):
2
+ workflow executions, activities, deferred completions, resumes, interrupts
3
+ and durable clocks are persisted entity messages, so a durable workflow
4
+ survives the runner that started it."""
5
+ # pyright: reportPrivateUsage=false
6
+
7
+ from __future__ import annotations
8
+
9
+ import builtins
10
+ from collections.abc import Callable, Generator
11
+ from dataclasses import dataclass, field
12
+ from datetime import UTC, datetime, timedelta
13
+ from math import ceil
14
+ from typing import Any, Literal, Never, cast
15
+
16
+ from pyfect._catch import catch_tag
17
+ from pyfect._core import Effect, _WithFiber
18
+ from pyfect._fiber import Fiber
19
+ from pyfect._json_text import stringify
20
+ from pyfect.cause import Cause, Interrupt
21
+ from pyfect.cluster import _cluster_abandon as cluster_abandon
22
+ from pyfect.cluster._entity_activation import CurrentActivationScope
23
+ from pyfect.cluster.cluster_error import EntityNotAssignedToRunner, PersistenceError
24
+ from pyfect.cluster.cluster_schema import Dynamic, ShardGroup, WithTransaction
25
+ from pyfect.cluster.cluster_workflow_engine._entities import (
26
+ ActivityPayload,
27
+ AnyWorkflow,
28
+ ClockEntity,
29
+ ClockPayload,
30
+ ClockRpc,
31
+ DeferredPayload,
32
+ DeferredRpc,
33
+ Parent,
34
+ ResumePayload,
35
+ RunPayload,
36
+ activity_primary_key,
37
+ make_partial_workflow_entity,
38
+ make_workflow_entity,
39
+ run_payload,
40
+ run_rpc_of,
41
+ workflow_payload,
42
+ )
43
+ from pyfect.cluster.entity import CurrentAddress, Entity, EntityHandlers, EntityOptions, Request
44
+ from pyfect.cluster.entity_address import EntityAddress
45
+ from pyfect.cluster.entity_id import EntityId
46
+ from pyfect.cluster.entity_type import EntityType
47
+ from pyfect.cluster.envelope import Interrupt as InterruptEnvelope
48
+ from pyfect.cluster.envelope import Request as EnvelopeRequest
49
+ from pyfect.cluster.envelope import make_request
50
+ from pyfect.cluster.message import OutgoingEnvelope, OutgoingRequest
51
+ from pyfect.cluster.message_storage import MessageStorage, MessageStorageService
52
+ from pyfect.cluster.reply import with_exit_schema
53
+ from pyfect.cluster.sharding import Sharding, ShardingService
54
+ from pyfect.cluster.snowflake import Snowflake
55
+ from pyfect.context import Context
56
+ from pyfect.date_time import now
57
+ from pyfect.deferred import Deferred
58
+ from pyfect.duration import Seconds, to_millis
59
+ from pyfect.effect import (
60
+ context,
61
+ die,
62
+ fail,
63
+ fail_cause,
64
+ from_exit,
65
+ gen,
66
+ never,
67
+ provide_context,
68
+ provide_service,
69
+ service_option,
70
+ succeed,
71
+ suspend,
72
+ sync,
73
+ void,
74
+ )
75
+ from pyfect.exit import Exit, Failure, Success
76
+ from pyfect.logger import log_warning
77
+ from pyfect.rc_map import RcMap
78
+ from pyfect.rpc import wrap as rpc_wrap
79
+ from pyfect.rpc._rpc import AnyRpc, exit_schema
80
+ from pyfect.rpc.schema import ClientAbort
81
+ from pyfect.schedule import exponential, min, spaced
82
+ from pyfect.schema import decode_unknown_effect, decode_unknown_sync, to_codec_json
83
+ from pyfect.schema import to_json_schema_document as json_schema_document
84
+ from pyfect.scope import CloseableScope, Scope, scoped
85
+ from pyfect.semaphore import Semaphore
86
+ from pyfect.tracer import annotate_current_span, current_span
87
+ from pyfect.workflow._encoded import DeferredState, Encoded, Handler, make_deferred_state
88
+ from pyfect.workflow._encoded import make_unsafe as make_engine_unsafe
89
+ from pyfect.workflow._result import Result, Suspended
90
+ from pyfect.workflow._services import (
91
+ WorkflowEngine,
92
+ WorkflowEngineService,
93
+ WorkflowInstance,
94
+ WorkflowInstanceService,
95
+ )
96
+ from pyfect.workflow.activity import Activity, CurrentAttempt
97
+ from pyfect.workflow.durable_clock import DurableClock
98
+ from pyfect.workflow.durable_clock import make as make_clock
99
+ from pyfect.workflow.durable_deferred import DurableDeferred
100
+ from pyfect.workflow.durable_deferred import make as make_deferred
101
+ from pyfect.workflow.workflow import SuspendOnFailure, into_result
102
+
103
+ type WakeMode = Literal["explicit", "automatic"]
104
+ type ReplyEncoded = dict[str, Any]
105
+
106
+ INTERRUPT_SIGNAL: DurableDeferred[None, Never] = make_deferred("Workflow/InterruptSignal")
107
+
108
+ # Workflow state is durable, so an idle entity (completed or suspended) can be
109
+ # released quickly and is rebuilt from storage when the next message arrives.
110
+ # This keeps completed and suspended executions from holding
111
+ # ``max_resident_entities`` slots for the full ``entity_max_idle_time``.
112
+ ENTITY_MAX_IDLE_TIME = Seconds(10)
113
+
114
+ _EPOCH = datetime(1970, 1, 1, tzinfo=UTC)
115
+
116
+ _retry_policy = min(exponential(0.2, 1.5), spaced(60))
117
+
118
+
119
+ def ensure_success[A](effect: Effect[A, Any, Any]) -> Effect[A, Never, Any]:
120
+ """Retry ``effect`` until it succeeds. A cluster abandonment means this
121
+ owner can no longer complete it, so retrying would only wait on a
122
+ retired run: it is raised again as an annotated interrupt, so the
123
+ activation can unwind and its shard can be released."""
124
+
125
+ def retryable(cause: Cause[Any]) -> bool:
126
+ return not cluster_abandon.is_cause(cause)
127
+
128
+ def abandon(_: Cause[Any]) -> Effect[Never]:
129
+ return cluster_abandon.interrupt
130
+
131
+ return (
132
+ effect.sandbox()
133
+ .retry(schedule=_retry_policy, while_=retryable)
134
+ .catch_if(cluster_abandon.is_cause, abandon)
135
+ .or_die()
136
+ )
137
+
138
+
139
+ def _retry_persistence[A](effect: Effect[A, Any, Any]) -> Effect[A, Never, Any]:
140
+ return effect.retry(
141
+ times=3,
142
+ schedule=exponential(0.25),
143
+ while_=lambda e: isinstance(e, PersistenceError),
144
+ ).or_die()
145
+
146
+
147
+ def _is_suspended_reply(reply: ReplyEncoded) -> bool:
148
+ exit = reply["exit"]
149
+ return exit.get("_tag") == "Success" and exit["value"].get("_tag") == "Suspended"
150
+
151
+
152
+ def _is_failed_reply(reply: ReplyEncoded) -> bool:
153
+ return _is_suspended_reply(reply) and reply["exit"]["value"].get("failed") is True
154
+
155
+
156
+ _decode_deferred_with_exit = decode_unknown_sync(
157
+ to_codec_json(with_exit_schema(exit_schema(DeferredRpc)))
158
+ )
159
+
160
+
161
+ def _deferred_exit(reply: ReplyEncoded) -> Exit[Any, Any]:
162
+ decoded = _decode_deferred_with_exit(reply)
163
+ exit = decoded.exit
164
+ return cast("Exit[Any, Any]", exit.value) if isinstance(exit, Success) else exit
165
+
166
+
167
+ def payload_shape(workflow: AnyWorkflow) -> str:
168
+ """The JSON Schema of ``workflow``'s payload, for a warning."""
169
+ try:
170
+ document = json_schema_document(workflow.payload_schema)
171
+ schema: dict[str, object] = dict(document.schema)
172
+ definitions = document.definitions
173
+ shown = schema if not definitions else {**schema, "$defs": definitions}
174
+ return stringify(shown)
175
+ except Exception:
176
+ return "<unavailable>"
177
+
178
+
179
+ @dataclass(slots=True, eq=False)
180
+ class _ActivationState:
181
+ workflow_name: str
182
+ execution_id: str
183
+ results: dict[str, Exit[Any, Any]]
184
+ # Every run forks its scope from here, so runs that suspended keep their
185
+ # resources and durable finalizers until the execution finishes.
186
+ scope: CloseableScope
187
+ instances: set[WorkflowInstanceService] = field(default_factory=set[WorkflowInstanceService])
188
+
189
+
190
+ @dataclass(slots=True, eq=False)
191
+ class _CurrentRun:
192
+ request: Request[Any]
193
+ instance: WorkflowInstanceService
194
+ # Activity awaits must wake the run after suspension without preempting it.
195
+ activity_awaits: dict[str, int]
196
+
197
+
198
+ @dataclass(frozen=True, slots=True)
199
+ class _ActivityEntry:
200
+ activity: Activity[Any, Any, Any]
201
+ context: Context[Any]
202
+
203
+
204
+ class ClusterEngine:
205
+ """The state of one cluster workflow engine and its ``Encoded``
206
+ operations."""
207
+
208
+ def __init__(
209
+ self,
210
+ sharding: ShardingService,
211
+ storage: MessageStorageService,
212
+ clients: RcMap[str, Callable[[str], Any], Never],
213
+ clients_partial: RcMap[str, Callable[[str], Any], Never],
214
+ holder: dict[str, ClusterEngine],
215
+ ) -> None:
216
+ self.sharding = sharding
217
+ self.storage = storage
218
+ self.clients = clients
219
+ self.clients_partial = clients_partial
220
+ holder["engine"] = self
221
+ self.workflows: dict[str, AnyWorkflow] = {}
222
+ self.entities: dict[str, builtins.type[Entity]] = {}
223
+ self.partial_entities: dict[str, builtins.type[Entity]] = {}
224
+ self.activities: dict[str, _ActivityEntry] = {}
225
+ self.interrupted_activities: set[str] = set()
226
+ self.deferred_state: DeferredState = make_deferred_state()
227
+ # Rebuilds share an activation; overlapping activations have separate
228
+ # results. Removed once the activation has closed its runs.
229
+ self.pending_by_activation: dict[int, tuple[CloseableScope, _ActivationState]] = {}
230
+ self.service: WorkflowEngineService = make_engine_unsafe(
231
+ Encoded(
232
+ register=self.register,
233
+ execute=self.execute,
234
+ poll=self.poll,
235
+ interrupt=lambda workflow, execution_id: self.interrupt(
236
+ workflow, execution_id
237
+ ).as_void(),
238
+ interrupt_unsafe=self.interrupt_unsafe,
239
+ resume=lambda workflow, execution_id: ensure_success(
240
+ self.resume(workflow, execution_id, "explicit")
241
+ ),
242
+ activity_execute=self.activity_execute,
243
+ deferred_result=self.deferred_result,
244
+ deferred_done=self.deferred_done,
245
+ schedule_clock=self.schedule_clock,
246
+ await_complete=self.await_complete,
247
+ )
248
+ )
249
+
250
+ # --- entities and addresses ----------------------------------------------------------
251
+
252
+ def ensure_entity(self, workflow: AnyWorkflow) -> builtins.type[Entity]:
253
+ entity = self.entities.get(workflow.tag)
254
+ if entity is None:
255
+ entity = make_workflow_entity(workflow)
256
+ self.workflows[workflow.tag] = workflow
257
+ self.entities[workflow.tag] = entity
258
+ return entity
259
+
260
+ def ensure_partial_entity(self, workflow_name: str) -> builtins.type[Entity]:
261
+ entity = self.partial_entities.get(workflow_name)
262
+ if entity is None:
263
+ entity = make_partial_workflow_entity(workflow_name)
264
+ self.partial_entities[workflow_name] = entity
265
+ return entity
266
+
267
+ def entity_address_for(
268
+ self, workflow: AnyWorkflow, entity_type: str, execution_id: str
269
+ ) -> EntityAddress:
270
+ entity_id = EntityId(execution_id)
271
+ shard_group = workflow.annotations.get(ShardGroup)(entity_id)
272
+ return EntityAddress(
273
+ entity_type=EntityType(entity_type),
274
+ entity_id=entity_id,
275
+ shard_id=self.sharding.get_shard_id(entity_id, shard_group),
276
+ )
277
+
278
+ def run_address(self, workflow: AnyWorkflow, execution_id: str) -> EntityAddress:
279
+ return self.entity_address_for(workflow, f"Workflow/{workflow.tag}", execution_id)
280
+
281
+ def activation_state(self, activation: CloseableScope | None) -> _ActivationState | None:
282
+ if activation is None:
283
+ return None
284
+ entry = self.pending_by_activation.get(id(activation))
285
+ return entry[1] if entry is not None and entry[0] is activation else None
286
+
287
+ def current_state(self) -> Effect[_ActivationState | None]:
288
+ return service_option(CurrentActivationScope).map(
289
+ lambda found: None if found is None else self.activation_state(found.value)
290
+ )
291
+
292
+ # --- storage ------------------------------------------------------------------------
293
+
294
+ def send_discard(
295
+ self, rpc: AnyRpc, address: EntityAddress, payload: object
296
+ ) -> Effect[None, Any]:
297
+ def body() -> Generator[Effect[Any, Any, Any], Any]:
298
+ span = yield from current_span().or_die()
299
+ envelope = make_request(
300
+ request_id=(yield from self.sharding.get_snowflake),
301
+ address=address,
302
+ tag=rpc.tag,
303
+ payload=payload,
304
+ trace_id=span.trace_id,
305
+ span_id=span.span_id,
306
+ sampled=span.sampled,
307
+ )
308
+ message = OutgoingRequest(
309
+ envelope=envelope,
310
+ context=Context.empty(),
311
+ last_received_reply=None,
312
+ rpc=rpc,
313
+ respond=lambda _: void,
314
+ annotations=rpc.annotations.get(Dynamic)(rpc.annotations, envelope),
315
+ )
316
+ yield from self.sharding.send_outgoing(message, True)
317
+
318
+ return gen(body)
319
+
320
+ def request_id_for(
321
+ self, workflow: AnyWorkflow, entity_type: str, execution_id: str, tag: str, id: str
322
+ ) -> Effect[Snowflake | None, PersistenceError]:
323
+ address = self.entity_address_for(workflow, entity_type, execution_id)
324
+ return self.storage.request_id_for_primary_key(address=address, tag=tag, id=id)
325
+
326
+ def reply_for_request_id(self, request_id: Snowflake) -> Effect[ReplyEncoded | None, Any]:
327
+ def last(replies: list[Any]) -> ReplyEncoded | None:
328
+ if replies and replies[-1].get("_tag") == "WithExit":
329
+ return cast("ReplyEncoded", replies[-1])
330
+ return None
331
+
332
+ return self.storage.replies_for_unfiltered([request_id]).map(last)
333
+
334
+ def request_reply(
335
+ self, workflow: AnyWorkflow, entity_type: str, execution_id: str, tag: str, id: str
336
+ ) -> Effect[ReplyEncoded | None, Any]:
337
+ def found(request_id: Snowflake | None) -> Effect[ReplyEncoded | None, Any]:
338
+ if request_id is None:
339
+ return succeed(None)
340
+ return self.reply_for_request_id(request_id)
341
+
342
+ return self.request_id_for(workflow, entity_type, execution_id, tag, id).flat_map(found)
343
+
344
+ def run_reply(
345
+ self, workflow: AnyWorkflow, execution_id: str
346
+ ) -> Effect[ReplyEncoded | None, Any]:
347
+ return self.request_reply(workflow, f"Workflow/{workflow.tag}", execution_id, "run", "")
348
+
349
+ def reset_activity_attempt(
350
+ self,
351
+ workflow: AnyWorkflow,
352
+ execution_id: str,
353
+ activity: Activity[Any, Any, Any],
354
+ attempt: int,
355
+ ) -> Effect[None]:
356
+ def body() -> Generator[Effect[Any, Any, Any], Any]:
357
+ request_id = yield from self.request_id_for(
358
+ workflow,
359
+ f"Workflow/{workflow.tag}",
360
+ execution_id,
361
+ "activity",
362
+ activity_primary_key(activity.name, attempt),
363
+ )
364
+ if request_id is None:
365
+ return
366
+ yield from self.sharding.reset(request_id)
367
+
368
+ return gen(body).retry(times=3, schedule=exponential(0.25)).or_die()
369
+
370
+ def clear_clock(self, workflow: AnyWorkflow, execution_id: str) -> Effect[None, Any]:
371
+ address = self.entity_address_for(workflow, ClockEntity.type, execution_id)
372
+ return self.storage.clear_address(address)
373
+
374
+ def resume(self, workflow: AnyWorkflow, execution_id: str, mode: WakeMode) -> Effect[None, Any]:
375
+ def body() -> Generator[Effect[Any, Any, Any], Any]:
376
+ reply = yield from self.run_reply(workflow, execution_id)
377
+ if reply is None or not _is_suspended_reply(reply):
378
+ return
379
+ # Replies without ``failed`` retain automatic wakes for compatibility.
380
+ if mode == "automatic" and _is_failed_reply(reply):
381
+ return
382
+ reset = yield from self.sharding.reset(
383
+ Snowflake(int(reply["requestId"])),
384
+ expected_reply_id=Snowflake(int(reply["id"])),
385
+ )
386
+ if not reset:
387
+ return (yield from fail(RuntimeError("Failed to reset workflow run")))
388
+ yield from self.sharding.poll_storage
389
+
390
+ return gen(body)
391
+
392
+ def interrupt_pending(self, instance: WorkflowInstanceService) -> Effect[bool]:
393
+ """Whether a persisted interrupt is pending for ``instance``:
394
+ activations load it when they start, so this reads only memory."""
395
+
396
+ def check(state: _ActivationState | None) -> bool:
397
+ return (
398
+ state is not None
399
+ and state.workflow_name == instance.workflow.tag
400
+ and state.execution_id == instance.execution_id
401
+ and INTERRUPT_SIGNAL.name in state.results
402
+ )
403
+
404
+ return self.current_state().map(check)
405
+
406
+ def send_resume_parent(self, parent: Parent, child_execution_id: str) -> Effect[None, Any]:
407
+ def body() -> Generator[Effect[Any, Any, Any], Any]:
408
+ workflow_name = parent["workflowName"]
409
+ request_id = yield from self.request_id_for(
410
+ self.workflows[workflow_name],
411
+ f"Workflow/{workflow_name}",
412
+ parent["executionId"],
413
+ "resume",
414
+ child_execution_id,
415
+ )
416
+ if request_id is None:
417
+ make_client = yield from self.clients_partial.get(workflow_name)
418
+ client: Any = make_client(parent["executionId"])
419
+ discard: Effect[None, Any] = client.resume.discard(
420
+ ResumePayload(childExecutionId=child_execution_id)
421
+ )
422
+ return (yield from discard)
423
+ reply = yield from self.reply_for_request_id(request_id)
424
+ if reply is None:
425
+ return
426
+ yield from self.sharding.reset(request_id)
427
+
428
+ return scoped(gen(body))
429
+
430
+ def await_run_reply(
431
+ self,
432
+ workflow: AnyWorkflow,
433
+ request: EnvelopeRequest[Any],
434
+ is_settled: Callable[[ReplyEncoded], bool],
435
+ ) -> Effect[bool, Any]:
436
+ """Wait for the run's next reply, subscribing before reading
437
+ storage, so a reply cannot fall between the read and the
438
+ subscription: ``True`` when the stored reply already settles the
439
+ wait, ``False`` when a new reply arrived."""
440
+
441
+ def body() -> Generator[Effect[Any, Any, Any], Any, bool]:
442
+ waiter: Fiber[None, Any] = yield from self.storage.register_reply_handler(
443
+ OutgoingRequest(
444
+ envelope=request,
445
+ context=Context.empty(),
446
+ rpc=run_rpc_of(self.ensure_entity(workflow)),
447
+ last_received_reply=None,
448
+ respond=lambda _: void,
449
+ annotations=Context.empty(),
450
+ )
451
+ ).fork_scoped(start_immediately=True)
452
+ reply = yield from self.reply_for_request_id(request.request_id)
453
+ if reply is not None and is_settled(reply):
454
+ return True
455
+ yield from waiter.join()
456
+ return False
457
+
458
+ return scoped(gen(body))
459
+
460
+ def wait_for_run_reply(self, workflow: AnyWorkflow, request: Request[Any]) -> Effect[None]:
461
+ """A child or deferred may complete while a run is still unwinding:
462
+ wait for the run's reply, so the wake cannot fall between the run's
463
+ last read and its suspended reply."""
464
+
465
+ def on_cause(cause: Cause[Any]) -> Effect[None, Any]:
466
+ if cluster_abandon.is_cause(cause):
467
+ return cluster_abandon.interrupt
468
+ return fail_cause(cause)
469
+
470
+ return cast(
471
+ "Effect[None]",
472
+ self.await_run_reply(workflow, request, lambda _: True)
473
+ .as_void()
474
+ .pipe(catch_tag(EntityNotAssignedToRunner, lambda _: cluster_abandon.interrupt))
475
+ .catch_cause(on_cause),
476
+ )
477
+
478
+ def await_complete(self, workflow: AnyWorkflow, execution_id: str) -> Effect[None]:
479
+ """Wake an external caller once its run publishes a reply other than
480
+ ``Suspended``. Replies are only observed on the runner that saves
481
+ them, so callers on other runners, and any failure here, leave
482
+ delivery to the caller's retry schedule."""
483
+
484
+ def body() -> Generator[Effect[Any, Any, Any], Any]:
485
+ address = self.run_address(workflow, execution_id)
486
+ if not self.sharding.has_shard_id(address.shard_id):
487
+ return (yield from never)
488
+ request_id = yield from self.storage.request_id_for_primary_key(
489
+ address=address, tag="run", id=""
490
+ )
491
+ if request_id is None:
492
+ return (yield from never)
493
+ request = make_request(
494
+ request_id=request_id, address=address, tag="run", payload=RunPayload()
495
+ )
496
+ # A replay that suspends again re-arms the wait, so it does not
497
+ # spend a step of the caller's retry schedule.
498
+ settled = False
499
+ while not settled:
500
+ settled = yield from self.await_run_reply(
501
+ workflow, request, lambda reply: not _is_suspended_reply(reply)
502
+ )
503
+
504
+ return gen(body).catch_cause(lambda _: never)
505
+
506
+ def interrupt(self, workflow: AnyWorkflow, execution_id: str) -> Effect[Snowflake | None]:
507
+ def body() -> Generator[Effect[Any, Any, Any], Any, Snowflake | None]:
508
+ self.ensure_entity(workflow)
509
+ request_id = yield from self.request_id_for(
510
+ workflow, f"Workflow/{workflow.tag}", execution_id, "run", ""
511
+ )
512
+ if request_id is None:
513
+ return None
514
+ reply = yield from self.reply_for_request_id(request_id)
515
+ if reply is not None and not _is_suspended_reply(reply):
516
+ return None
517
+ yield from self.service.deferred_done(
518
+ INTERRUPT_SIGNAL,
519
+ workflow_name=workflow.tag,
520
+ execution_id=execution_id,
521
+ deferred_name=INTERRUPT_SIGNAL.name,
522
+ exit=Success(None),
523
+ )
524
+ return request_id
525
+
526
+ return _retry_persistence(gen(body))
527
+
528
+ def interrupt_unsafe(self, workflow: AnyWorkflow, execution_id: str) -> Effect[None]:
529
+ def body() -> Generator[Effect[Any, Any, Any], Any]:
530
+ request_id = yield from self.interrupt(workflow, execution_id)
531
+ if request_id is None:
532
+ return
533
+ entity = self.ensure_entity(workflow)
534
+ envelope = InterruptEnvelope(
535
+ id=(yield from self.sharding.get_snowflake),
536
+ address=self.run_address(workflow, execution_id),
537
+ request_id=request_id,
538
+ )
539
+ yield from self.sharding.send_outgoing(
540
+ OutgoingEnvelope(envelope=envelope, rpc=run_rpc_of(entity)), False
541
+ ).or_die()
542
+
543
+ return gen(body)
544
+
545
+ # --- registration -------------------------------------------------------------------
546
+
547
+ def register(self, workflow: AnyWorkflow, execute: Handler, /) -> Effect[None, Never, Scope]:
548
+ def body() -> Effect[None, Never, Scope]:
549
+ existing = self.workflows.get(workflow.tag)
550
+ registration = self.sharding.register_entity(
551
+ self.ensure_entity(workflow),
552
+ gen(lambda: self._build_handlers(workflow, execute)),
553
+ # Alongside the run, let deferred handlers briefly acquire a
554
+ # permit to fork their wake and return an asynchronous reply.
555
+ EntityOptions(concurrency=2, max_idle_time=ENTITY_MAX_IDLE_TIME),
556
+ )
557
+ if existing is None or existing is workflow:
558
+ return registration
559
+ return log_warning(
560
+ f'Workflow "{workflow.tag}" is already registered with payload shape '
561
+ f"{payload_shape(existing)}; ignoring duplicate definition with payload "
562
+ f"shape {payload_shape(workflow)}"
563
+ ).and_then(registration)
564
+
565
+ return suspend(body)
566
+
567
+ def _load_activation(
568
+ self, workflow: AnyWorkflow, execution_id: str, activation: CloseableScope
569
+ ) -> Generator[Effect[Any, Any, Any], Any, _ActivationState]:
570
+ pending = self.activation_state(activation)
571
+ if pending is not None:
572
+ return pending
573
+ results: dict[str, Exit[Any, Any]] = {}
574
+ # A new owner must see an interrupt persisted before it took over.
575
+ # Publish the cache only once loaded, so a retried build repeats a
576
+ # failed lookup.
577
+ interrupt = yield from self.request_reply(
578
+ workflow,
579
+ f"Workflow/{workflow.tag}",
580
+ execution_id,
581
+ "deferred",
582
+ INTERRUPT_SIGNAL.name,
583
+ ).or_die()
584
+ if interrupt is not None:
585
+ results[INTERRUPT_SIGNAL.name] = _deferred_exit(interrupt)
586
+ pending = _ActivationState(workflow.tag, execution_id, results, CloseableScope())
587
+ key = id(activation)
588
+
589
+ def forget() -> None:
590
+ entry = self.pending_by_activation.get(key)
591
+ if entry is not None and entry[1] is pending:
592
+ del self.pending_by_activation[key]
593
+
594
+ yield from activation.add_finalizer(
595
+ lambda _: self.close_runs(pending, abandoned=True).and_then(sync(forget))
596
+ )
597
+ self.pending_by_activation[key] = (activation, pending)
598
+ return pending
599
+
600
+ def close_runs(self, state: _ActivationState, *, abandoned: bool) -> Effect[None]:
601
+ """Close the scopes retained by suspended runs. The latest run
602
+ already closed its own scope with its real exit, so earlier
603
+ finalizers observe success and skip superseded compensations.
604
+ Abandonment releases owner-local resources without running durable
605
+ finalizers, so the run can replay elsewhere."""
606
+
607
+ def run() -> Effect[None]:
608
+ scope = state.scope
609
+ if abandoned:
610
+ for instance in state.instances:
611
+ instance.abandoned = True
612
+ state.instances.clear()
613
+ state.scope = CloseableScope()
614
+ return scope.close(Success(None))
615
+
616
+ return suspend(run)
617
+
618
+ def _build_handlers(
619
+ self, workflow: AnyWorkflow, execute: Handler
620
+ ) -> Generator[Effect[Any, Any, Any], Any, EntityHandlers[Any, Any]]:
621
+ address = yield from CurrentAddress()
622
+ execution_id = str(address.entity_id)
623
+ activation = yield from CurrentActivationScope()
624
+ pending = yield from self._load_activation(workflow, execution_id, activation)
625
+ return _Handlers(
626
+ self,
627
+ workflow=workflow,
628
+ execute=execute,
629
+ execution_id=execution_id,
630
+ activation=activation,
631
+ pending=pending,
632
+ ).build()
633
+
634
+ # --- execution ----------------------------------------------------------------------
635
+
636
+ def execute(
637
+ self,
638
+ workflow: AnyWorkflow,
639
+ /,
640
+ *,
641
+ execution_id: str,
642
+ payload: object,
643
+ discard: bool,
644
+ parent: WorkflowInstanceService | None,
645
+ detached: bool,
646
+ ) -> Effect[Result[Any, Any] | None]:
647
+ self.ensure_entity(workflow)
648
+ parent_key: Parent | None = None
649
+ if parent is not None:
650
+ # A detached child keeps its parent for observability only.
651
+ parent_key = Parent(workflowName=parent.workflow.tag, executionId=parent.execution_id)
652
+ if detached:
653
+ parent_key["detached"] = True
654
+ run = run_payload(workflow, payload, parent_key)
655
+
656
+ def call(make_client: Callable[[str], Any]) -> Effect[Any, Any]:
657
+ client = make_client(execution_id)
658
+ return client.run.discard(run) if discard else client.run(run)
659
+
660
+ return scoped(self.clients.get(workflow.tag).flat_map(call).or_die())
661
+
662
+ def poll(self, workflow: AnyWorkflow, execution_id: str) -> Effect[Result[Any, Any] | None]:
663
+ def body() -> Generator[Effect[Any, Any, Any], Any, Result[Any, Any] | None]:
664
+ entity = self.ensure_entity(workflow)
665
+ schema = to_codec_json(exit_schema(run_rpc_of(entity)))
666
+ reply = yield from self.run_reply(workflow, execution_id)
667
+ if reply is None:
668
+ return None
669
+ exit = yield from decode_unknown_effect(schema)(reply["exit"])
670
+ return (yield from from_exit(cast("Exit[Result[Any, Any], Any]", exit)))
671
+
672
+ return gen(body).or_die()
673
+
674
+ def activity_execute(
675
+ self, activity: Activity[Any, Any, Any], attempt: int
676
+ ) -> Effect[Result[Any, Any], Never, WorkflowInstance]:
677
+ def body() -> Generator[Effect[Any, Any, Any], Any, Result[Any, Any]]:
678
+ services = yield from context()
679
+ instance = services.get_unsafe(WorkflowInstance)
680
+ yield from annotate_current_span("executionId", instance.execution_id)
681
+ activity_id = f"{instance.execution_id}/{activity.name}"
682
+ # A pending interrupt replays only to rebuild compensations, so it
683
+ # must not run new activities. Finalizers run once ``interrupted``
684
+ # is set.
685
+ if not instance.interrupted and (yield from self.interrupt_pending(instance)):
686
+ reply = yield from self.request_reply(
687
+ instance.workflow,
688
+ f"Workflow/{instance.workflow.tag}",
689
+ instance.execution_id,
690
+ "activity",
691
+ activity_primary_key(activity.name, attempt),
692
+ ).or_die()
693
+ # Suspend so ``on_exit`` applies the interrupt to the run.
694
+ if reply is None or _is_suspended_reply(reply):
695
+ return Suspended()
696
+ make_client = yield from self.clients_partial.get(instance.workflow.tag)
697
+ client: Any = make_client(instance.execution_id)
698
+ while True:
699
+ if activity_id not in self.activities:
700
+ self.activities[activity_id] = _ActivityEntry(activity, services)
701
+ call: Effect[Result[Any, Any], Any] = client.activity(
702
+ ActivityPayload(
703
+ name=activity.name,
704
+ attempt=attempt,
705
+ withTransaction=activity.annotations.get(WithTransaction),
706
+ )
707
+ )
708
+ result = yield from call.or_die()
709
+ # If the activity has suspended and did not execute, resume it
710
+ # by resetting the attempt and executing it again.
711
+ if isinstance(result, Suspended) and (
712
+ activity_id in self.activities or activity_id in self.interrupted_activities
713
+ ):
714
+ yield from self.reset_activity_attempt(
715
+ instance.workflow, instance.execution_id, activity, attempt
716
+ )
717
+ continue
718
+ self.activities.pop(activity_id, None)
719
+ return result
720
+
721
+ return cast("Effect[Result[Any, Any], Never, WorkflowInstance]", scoped(gen(body)))
722
+
723
+ def deferred_result(
724
+ self, deferred: DurableDeferred[Any, Any]
725
+ ) -> Effect[Exit[Any, Any] | None, Never, WorkflowInstance]:
726
+ def body() -> Generator[Effect[Any, Any, Any], Any, Exit[Any, Any] | None]:
727
+ instance = yield from WorkflowInstance()
728
+ state = yield from self.current_state()
729
+ # Captured contexts can cross workflow boundaries. Never use another
730
+ # execution's completion, even if its deferred has the same name.
731
+ if (
732
+ state is not None
733
+ and state.workflow_name == instance.workflow.tag
734
+ and state.execution_id == instance.execution_id
735
+ ):
736
+ found = state.results.get(deferred.name)
737
+ if found is not None:
738
+ return found
739
+ reply = yield from self.request_reply(
740
+ instance.workflow,
741
+ f"Workflow/{instance.workflow.tag}",
742
+ instance.execution_id,
743
+ "deferred",
744
+ deferred.name,
745
+ )
746
+ return None if reply is None else _deferred_exit(reply)
747
+
748
+ return cast(
749
+ "Effect[Exit[Any, Any] | None, Never, WorkflowInstance]",
750
+ _retry_persistence(gen(body)),
751
+ )
752
+
753
+ def deferred_done(
754
+ self, *, workflow_name: str, execution_id: str, deferred_name: str, exit: Exit[Any, Any]
755
+ ) -> Effect[None]:
756
+ def body() -> Generator[Effect[Any, Any, Any], Any]:
757
+ found = yield from service_option(WorkflowInstance)
758
+ # Activities run with their own instance, so their completions
759
+ # still wake a run that suspended before reaching the await. An
760
+ # interrupt must wake the run even when it signals itself.
761
+ if (
762
+ found is not None
763
+ and found.value.execution_id == execution_id
764
+ and deferred_name != INTERRUPT_SIGNAL.name
765
+ ):
766
+ found.value.completed_deferreds.add(deferred_name)
767
+ workflow = self.workflows.get(workflow_name)
768
+ payload = DeferredPayload(name=deferred_name, exit=exit)
769
+ if workflow is not None:
770
+ address = self.entity_address_for(
771
+ workflow, f"Workflow/{workflow_name}", execution_id
772
+ )
773
+ return (yield from self.send_discard(DeferredRpc, address, payload).or_die())
774
+ make_client = yield from self.clients_partial.get(workflow_name)
775
+ yield from make_client(execution_id).deferred.discard(payload).or_die()
776
+
777
+ return scoped(gen(body))
778
+
779
+ def schedule_clock(
780
+ self, workflow: AnyWorkflow, execution_id: str, clock: DurableClock
781
+ ) -> Effect[None]:
782
+ def send(at: Any) -> Effect[None, Any]:
783
+ millis = (at - _EPOCH) / timedelta(milliseconds=1) + to_millis(clock.duration)
784
+ wake_up = _EPOCH + timedelta(milliseconds=ceil(millis))
785
+ payload = ClockPayload(name=clock.name, workflowName=workflow.tag, wakeUp=wake_up)
786
+ address = self.entity_address_for(workflow, ClockEntity.type, execution_id)
787
+ return self.send_discard(ClockRpc, address, payload)
788
+
789
+ return now().flat_map(send).or_die()
790
+
791
+
792
+ class _Handlers:
793
+ """The handlers of one workflow entity activation (Effect's
794
+ ``register`` build)."""
795
+
796
+ def __init__(
797
+ self,
798
+ engine: ClusterEngine,
799
+ *,
800
+ workflow: AnyWorkflow,
801
+ execute: Handler,
802
+ execution_id: str,
803
+ activation: CloseableScope,
804
+ pending: _ActivationState,
805
+ ) -> None:
806
+ self.engine = engine
807
+ self.workflow = workflow
808
+ self.execute = execute
809
+ self.execution_id = execution_id
810
+ self.activation = activation
811
+ self.pending = pending
812
+ # Retain awaited names through reply persistence, including
813
+ # suspension. Replays reuse the request id but track a fresh set of
814
+ # awaits.
815
+ self.current_run: _CurrentRun | None = None
816
+ # Concurrent automatic wakes share one wait for the current run to
817
+ # publish its reply. Explicit wakes cannot be dropped, because an
818
+ # automatic wake skips the reset of a failure suspension, so they
819
+ # wait outside the gate. Operator resume does not use the gate.
820
+ self.resume_gate = Semaphore(1)
821
+
822
+ def build(self) -> EntityHandlers[Any, Any]:
823
+ entity = self.engine.ensure_entity(self.workflow)
824
+ rpcs = entity.rpcs
825
+ handlers: Any = entity.handlers()
826
+ handlers = handlers.handle(rpcs["run"])(self.run)
827
+ handlers = handlers.handle(rpcs["activity"])(self.activity)
828
+ handlers = handlers.handle(rpcs["deferred"])(self.deferred)
829
+ handlers = handlers.handle(rpcs["resume"])(self.resume)
830
+ return cast("EntityHandlers[Any, Any]", handlers)
831
+
832
+ def wait_for_current_run_reply(self) -> Effect[None]:
833
+ return suspend(
834
+ lambda: (
835
+ void
836
+ if self.current_run is None
837
+ else self.engine.wait_for_run_reply(self.workflow, self.current_run.request)
838
+ )
839
+ )
840
+
841
+ def resume_current_run(self, mode: WakeMode) -> Effect[None]:
842
+ engine = self.engine
843
+ if mode == "explicit":
844
+ return ensure_success(
845
+ self.wait_for_current_run_reply().and_then(
846
+ engine.resume(self.workflow, self.execution_id, mode)
847
+ )
848
+ )
849
+ # Release the gate before reset can start another run, so later
850
+ # completions can wake that replay.
851
+ return ensure_success(
852
+ self.resume_gate.with_permits_if_available(self.wait_for_current_run_reply()).flat_map(
853
+ lambda waited: (
854
+ void
855
+ if waited is None
856
+ else engine.resume(self.workflow, self.execution_id, mode)
857
+ )
858
+ )
859
+ )
860
+
861
+ def run(self, request: Request[RunPayload]) -> Effect[Any, Any, Any]:
862
+ engine = self.engine
863
+ workflow = self.workflow
864
+ execution_id = self.execution_id
865
+ pending = self.pending
866
+ # Each run gets a fresh scope under the activation's parent, so
867
+ # replays rebuild compensations while suspended runs keep theirs.
868
+ instance = WorkflowInstanceService.initial(
869
+ workflow, execution_id, scope=pending.scope.fork_unsafe()
870
+ )
871
+ pending.instances.add(instance)
872
+ self.current_run = _CurrentRun(request, instance, {})
873
+ parent = request.payload.parent
874
+ suspend_on_failure = workflow.annotations.get_unsafe(SuspendOnFailure)
875
+
876
+ def on_run_exit(exit: Exit[Any, Any]) -> Effect[None, Never, Any]:
877
+ # An annotated cluster abandonment means this owner can no longer
878
+ # finish the run. Do not resume the parent, but still allow a
879
+ # pending durable interrupt to take effect.
880
+ instance.abandoned = instance.abandoned or (
881
+ isinstance(exit, Failure) and cluster_abandon.is_cause(exit.cause)
882
+ )
883
+ if instance.abandoned:
884
+ instance.suspended = False
885
+ if (
886
+ not instance.suspended
887
+ and not instance.abandoned
888
+ and not (suspend_on_failure and isinstance(exit, Failure))
889
+ ):
890
+ resume_parent: Effect[None] = (
891
+ ensure_success(engine.send_resume_parent(parent, execution_id))
892
+ if parent is not None and not parent.get("detached", False)
893
+ else void
894
+ )
895
+ if isinstance(exit, Success) or not exit.cause.has_interrupts_only:
896
+ return resume_parent
897
+
898
+ # ``interrupt_unsafe`` cuts the run off without a result and its
899
+ # replay applies the interrupt. Retain the scope like a
900
+ # suspended run, so ``close_runs`` supersedes it and only the
901
+ # final run's compensations observe the interrupt.
902
+ def after_interrupt(found: Exit[Any, Any] | None) -> Effect[None]:
903
+ if found is None:
904
+ return resume_parent
905
+ instance.suspended = True
906
+ return void
907
+
908
+ return engine.service.deferred_result(INTERRUPT_SIGNAL).flat_map(after_interrupt)
909
+
910
+ def apply_interrupt(found: Exit[Any, Any] | None) -> Effect[None]:
911
+ if found is None:
912
+ return void
913
+ instance.suspended = False
914
+ instance.interrupted = True
915
+ return (
916
+ engine.clear_clock(workflow, execution_id)
917
+ .ignore()
918
+ .and_then(_WithFiber(lambda fiber: fiber.interrupt().interruptible()))
919
+ )
920
+
921
+ return engine.service.deferred_result(INTERRUPT_SIGNAL).flat_map(apply_interrupt)
922
+
923
+ def close(exit: Exit[Result[Any, Any], Any]) -> Effect[None]:
924
+ if isinstance(exit, Success) and isinstance(exit.value, Suspended):
925
+ return void
926
+ return engine.close_runs(pending, abandoned=instance.abandoned)
927
+
928
+ body = into_result(
929
+ self.execute(workflow_payload(workflow, request.payload), execution_id).on_exit(
930
+ on_run_exit
931
+ )
932
+ ).on_exit(close)
933
+ return engine.deferred_state.track_run(instance, body).pipe(
934
+ # Request middleware and local callers may carry another entity's context.
935
+ provide_service(CurrentActivationScope, self.activation)
936
+ )
937
+
938
+ def activity(self, request: Request[ActivityPayload]) -> Effect[Any, Any, Any]:
939
+ engine = self.engine
940
+ payload = request.payload
941
+ activity_id = f"{self.execution_id}/{payload.name}"
942
+ current = self.current_run
943
+ instance = WorkflowInstanceService.initial(
944
+ self.workflow,
945
+ self.execution_id,
946
+ awaited_deferreds=None if current is None else current.activity_awaits,
947
+ )
948
+ engine.interrupted_activities.discard(activity_id)
949
+ entry = engine.activities.get(activity_id)
950
+ if entry is None:
951
+ # Replay may never register a losing race activity. Answer it
952
+ # without waiting; a later registration can reset this reply.
953
+ return rpc_wrap(fork=True)(succeed(Suspended()))
954
+ services = (
955
+ entry.context.add(WorkflowInstance, instance)
956
+ .add(CurrentActivationScope, self.activation)
957
+ .add(CurrentAttempt, payload.attempt)
958
+ )
959
+
960
+ def on_cause(cause: Cause[Any]) -> Effect[Result[Any, Any], Any]:
961
+ # Store interrupts as suspensions only when the client asked.
962
+ if any(
963
+ isinstance(reason, Interrupt) and ClientAbort in reason.annotations
964
+ for reason in cause.reasons
965
+ ):
966
+ engine.interrupted_activities.add(activity_id)
967
+ return succeed(Suspended())
968
+ return fail_cause(cause)
969
+
970
+ def forget() -> None:
971
+ engine.activities.pop(activity_id, None)
972
+
973
+ effect = (
974
+ into_result(entry.activity.execute_encoded.pipe(provide_context(services)))
975
+ .catch_cause(on_cause)
976
+ .pipe(provide_service(WorkflowInstance, instance))
977
+ .pipe(provide_service(CurrentAttempt, payload.attempt))
978
+ .ensuring(sync(forget))
979
+ )
980
+ return rpc_wrap(fork=True, uninterruptible=True)(effect)
981
+
982
+ def deferred(self, request: Request[DeferredPayload]) -> Effect[Any, Any, Any]:
983
+ payload = request.payload
984
+ name = payload.name
985
+ self.pending.results[name] = payload.exit
986
+ mode: WakeMode = "explicit" if name == INTERRUPT_SIGNAL.name else "automatic"
987
+ engine = self.engine
988
+
989
+ # Await registers before reading the cache. If this run has not
990
+ # registered yet, a later await will see the result just stored.
991
+ # Check when the wake runs and skip preemption too: interrupting a
992
+ # later await would require waiting for its reply before reset. A
993
+ # run completing its own deferred also reads it from the cache when
994
+ # it awaits later, unless an activity is already parked on it. A run
995
+ # only reads ``INTERRUPT_SIGNAL`` while suspending, so an interrupt
996
+ # always waits for the current run's reply before it resets the run.
997
+ def wake() -> Effect[None]:
998
+ current = self.current_run
999
+ if (
1000
+ current is not None
1001
+ and mode == "automatic"
1002
+ and name not in current.instance.awaited_deferreds
1003
+ ):
1004
+ if name in current.activity_awaits:
1005
+ # Hold an activity wake until the run has published its reply.
1006
+ return self.resume_current_run(mode)
1007
+ if name in current.instance.completed_deferreds:
1008
+ return void
1009
+ return ensure_success(engine.resume(self.workflow, self.execution_id, mode))
1010
+ return engine.deferred_state.deferred_done(self.execution_id, name).and_then(
1011
+ self.resume_current_run(mode)
1012
+ )
1013
+
1014
+ # An asynchronous reply releases the RPC concurrency permit while the
1015
+ # wake waits; the pending request still occupies mailbox capacity.
1016
+ # The activation owns the wake so it survives handler rebuilds, but
1017
+ # activation shutdown still interrupts it for durable redelivery.
1018
+ reply = Deferred[Any, Any]()
1019
+ return (
1020
+ reply.into(suspend(wake).as_(payload.exit))
1021
+ .fork_in(self.activation, start_immediately=True)
1022
+ .as_(reply)
1023
+ )
1024
+
1025
+ def resume(self, _: Request[ResumePayload]) -> Effect[Any, Any, Any]:
1026
+ return rpc_wrap(fork=True, uninterruptible=True)(self.resume_current_run("automatic"))
1027
+
1028
+
1029
+ # --- the durable clock entity -----------------------------------------------------------
1030
+
1031
+
1032
+ def _clock_handlers() -> Generator[Effect[Any, Any, Any], Any, EntityHandlers[Any, Any]]:
1033
+ engine = yield from WorkflowEngine()
1034
+ address = yield from CurrentAddress()
1035
+ execution_id = str(address.entity_id)
1036
+
1037
+ def run(request: Request[ClockPayload]) -> Effect[None]:
1038
+ deferred = make_clock(name=request.payload.name, duration=0).deferred
1039
+ return ensure_success(
1040
+ engine.deferred_done(
1041
+ deferred,
1042
+ workflow_name=request.payload.workflowName,
1043
+ execution_id=execution_id,
1044
+ deferred_name=deferred.name,
1045
+ exit=Success(None),
1046
+ )
1047
+ )
1048
+
1049
+ return ClockEntity.handlers().handle(ClockEntity.run)(run)
1050
+
1051
+
1052
+ clock_entity_layer = ClockEntity.to_layer_effect(
1053
+ gen(_clock_handlers), max_idle_time=ENTITY_MAX_IDLE_TIME
1054
+ )
1055
+
1056
+
1057
+ def make() -> Effect[WorkflowEngineService, Never, Sharding | MessageStorage | Scope]:
1058
+ """A ``WorkflowEngineService`` backed by cluster sharding and message
1059
+ storage (Effect's ``ClusterWorkflowEngine.make``)."""
1060
+
1061
+ def body() -> Generator[Effect[Any, Any, Any], Any, WorkflowEngineService]:
1062
+ sharding = yield from Sharding()
1063
+ storage = yield from MessageStorage()
1064
+ holder: dict[str, ClusterEngine] = {}
1065
+
1066
+ def lookup(workflow_name: str) -> Effect[Callable[[str], Any]]:
1067
+ engine = holder["engine"]
1068
+ entity = engine.entities.get(workflow_name)
1069
+ if entity is None:
1070
+ return die(RuntimeError(f"Workflow {workflow_name} not registered"))
1071
+ return engine.clients_partial.invalidate(workflow_name).and_then(
1072
+ cast("Effect[Callable[[str], Any]]", entity.client())
1073
+ )
1074
+
1075
+ def lookup_partial(workflow_name: str) -> Effect[Callable[[str], Any]]:
1076
+ engine = holder["engine"]
1077
+ entity = engine.entities.get(workflow_name) or engine.ensure_partial_entity(
1078
+ workflow_name
1079
+ )
1080
+ return cast("Effect[Callable[[str], Any]]", entity.client())
1081
+
1082
+ clients = yield from RcMap.make(lookup, idle_time_to_live=300)
1083
+ clients_partial = yield from RcMap.make(lookup_partial, idle_time_to_live=300)
1084
+ return ClusterEngine(sharding, storage, clients, clients_partial, holder).service
1085
+
1086
+ return cast(
1087
+ "Effect[WorkflowEngineService, Never, Sharding | MessageStorage | Scope]", gen(body)
1088
+ )
1089
+
1090
+
1091
+ __all__ = [
1092
+ "ENTITY_MAX_IDLE_TIME",
1093
+ "INTERRUPT_SIGNAL",
1094
+ "ClusterEngine",
1095
+ "clock_entity_layer",
1096
+ "ensure_success",
1097
+ "make",
1098
+ "payload_shape",
1099
+ ]