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,403 @@
1
+ """Named wait points of a workflow execution (Effect's
2
+ ``effect/workflow/DurableDeferred``)::
3
+
4
+ approval = durable_deferred.make("approval", success=S.Boolean)
5
+
6
+ # in the workflow: suspend until someone completes it
7
+ approved = yield from approval.wait()
8
+
9
+ # anywhere else, with the token the workflow handed out
10
+ yield from approval.succeed(token=token, value=True)
11
+
12
+ A deferred's result is stored by the engine, encoded by its schemas, so a
13
+ replay of the workflow reads it instead of waiting. A token names the
14
+ workflow, the execution and the deferred, so code outside the workflow
15
+ can complete the right wait point.
16
+ """
17
+ # pyright: reportPrivateUsage=false
18
+
19
+ from __future__ import annotations
20
+
21
+ import base64
22
+ from collections.abc import Generator, Mapping, Sequence
23
+ from typing import TYPE_CHECKING, Any, Never, NewType, cast
24
+ from weakref import WeakKeyDictionary
25
+
26
+ from pyfect import _json_text
27
+ from pyfect._concurrency import race_all as race_all_effects
28
+ from pyfect._core import Effect
29
+ from pyfect._effect_args import require_effect
30
+ from pyfect._js import text_encode
31
+ from pyfect.brand import Brand
32
+ from pyfect.cause import Cause, Interrupt, from_reasons
33
+ from pyfect.effect import from_exit, gen, provide_service, succeed, sync
34
+ from pyfect.exit import Exit, Failure, Success
35
+ from pyfect.schema import (
36
+ Class,
37
+ Codec,
38
+ Defect,
39
+ ExitSchema,
40
+ String,
41
+ StringFromBase64Url,
42
+ Tuple,
43
+ decode_sync,
44
+ decode_to,
45
+ encode_sync,
46
+ field,
47
+ from_brand,
48
+ from_json_string,
49
+ to_codec_json,
50
+ )
51
+ from pyfect.schema import Exit as ExitOf
52
+ from pyfect.schema import Never as NeverSchema
53
+ from pyfect.schema import Null as NullSchema
54
+ from pyfect.schema.transformation import transform
55
+ from pyfect.workflow._services import (
56
+ WorkflowEngine,
57
+ WorkflowEngineService,
58
+ WorkflowInstance,
59
+ WorkflowInstanceService,
60
+ )
61
+ from pyfect.workflow._suspension import suspend as suspend_run
62
+ from pyfect.workflow._suspension import wrap_activity_result
63
+ from pyfect.workflow.activity import CurrentAttempt, Exactly, codec_of
64
+
65
+ if TYPE_CHECKING:
66
+ from pyfect.workflow.workflow import Workflow
67
+
68
+ Token = NewType("Token", str)
69
+ """A string naming a workflow, an execution and a deferred."""
70
+
71
+ TokenSchema = String.pipe(from_brand(Brand[str, Token].nominal()))
72
+ """Tokens (Effect's ``DurableDeferred.Token``)."""
73
+
74
+
75
+ class TokenParsed(Class):
76
+ """A token taken apart."""
77
+
78
+ workflow_name: str = field(String, key="workflowName")
79
+ execution_id: str = field(String, key="executionId")
80
+ deferred_name: str = field(String, key="deferredName")
81
+
82
+ @property
83
+ def as_token(self) -> Token:
84
+ """The token: base64url of the JSON ``[workflow, execution,
85
+ deferred]``, as Effect writes it."""
86
+ text = _json_text.stringify([self.workflow_name, self.execution_id, self.deferred_name])
87
+ return Token(base64.urlsafe_b64encode(text_encode(text)).decode().rstrip("="))
88
+
89
+ @staticmethod
90
+ def from_string(token: str) -> TokenParsed:
91
+ """Parse ``token``; raises ``SchemaError`` if it is not one."""
92
+ return decode_sync(TOKEN_FROM_STRING)(token)
93
+
94
+ @staticmethod
95
+ def encode(parsed: TokenParsed) -> str:
96
+ return encode_sync(TOKEN_FROM_STRING)(parsed)
97
+
98
+
99
+ def _to_fields(parts: tuple[str, str, str]) -> Mapping[str, object]:
100
+ return {"workflowName": parts[0], "executionId": parts[1], "deferredName": parts[2]}
101
+
102
+
103
+ def _from_fields(fields: Mapping[str, object]) -> tuple[str, str, str]:
104
+ return (
105
+ cast("str", fields["workflowName"]),
106
+ cast("str", fields["executionId"]),
107
+ cast("str", fields["deferredName"]),
108
+ )
109
+
110
+
111
+ TOKEN_FROM_STRING = StringFromBase64Url.pipe(
112
+ decode_to(from_json_string(Tuple(String, String, String)))
113
+ ).pipe(decode_to(TokenParsed, transform(decode=_to_fields, encode=_from_fields)))
114
+ """Tokens as strings, decoded to ``TokenParsed`` (Effect's
115
+ ``TokenParsed.FromString``)."""
116
+
117
+
118
+ class DurableDeferred[A, E = Never]:
119
+ """A named wait point of a workflow execution whose result is an ``A``
120
+ or an ``E`` failure. Make one with ``make``."""
121
+
122
+ __slots__ = ("error_schema", "exit_schema", "name", "success_schema")
123
+
124
+ def __init__(
125
+ self,
126
+ name: str,
127
+ *,
128
+ success: Codec[A, Any, Never, Never],
129
+ error: Codec[E, Any, Never, Never],
130
+ ) -> None:
131
+ self.name = name
132
+ self.success_schema = success
133
+ self.error_schema = error
134
+ self.exit_schema: ExitSchema[A, E, Any, Any, Never, Never] = ExitOf(
135
+ to_codec_json(success), to_codec_json(error), to_codec_json(Defect())
136
+ )
137
+
138
+ def __repr__(self) -> str:
139
+ return f"DurableDeferred({self.name!r})"
140
+
141
+ @property
142
+ def with_activity_attempt(self) -> Effect[DurableDeferred[A, E]]:
143
+ """This deferred named for the current activity attempt
144
+ (``"{name}/{attempt}"``)."""
145
+ return CurrentAttempt().map(
146
+ lambda attempt: DurableDeferred(
147
+ f"{self.name}/{attempt}", success=self.success_schema, error=self.error_schema
148
+ )
149
+ )
150
+
151
+ def wait(self) -> Effect[A, E, WorkflowEngine | WorkflowInstance]:
152
+ """The deferred's result, suspending the execution until it has one
153
+ (Effect's ``DurableDeferred.await``)."""
154
+ return await_(self)
155
+
156
+ def into[R](
157
+ self, effect: Effect[A, E, R]
158
+ ) -> Effect[A, E, R | WorkflowEngine | WorkflowInstance]:
159
+ """Run ``effect`` and record its exit as this deferred's result,
160
+ waking executions waiting on it.
161
+
162
+ ``effect`` and the write count as one in-flight activity of the
163
+ workflow, so siblings parked on durable waits do not suspend the
164
+ run until the exit is recorded. If ``effect`` parks on a durable
165
+ wait itself, the run suspends once the other activities finish and
166
+ nothing is recorded. Completing a deferred the run waits on still
167
+ replays the run."""
168
+ require_effect(effect, "effect")
169
+ return _record_held(effect, self, check_cache=False)
170
+
171
+ def token(self) -> Effect[Token, Never, WorkflowInstance]:
172
+ """The token of this deferred in the current execution."""
173
+ return WorkflowInstance().map(
174
+ lambda instance: (
175
+ TokenParsed(
176
+ workflow_name=instance.workflow.tag,
177
+ execution_id=instance.execution_id,
178
+ deferred_name=self.name,
179
+ ).as_token
180
+ )
181
+ )
182
+
183
+ def token_from_execution_id(
184
+ self, *, workflow: Workflow[Any, Any, Any], execution_id: str
185
+ ) -> Token:
186
+ return TokenParsed(
187
+ workflow_name=workflow.tag, execution_id=execution_id, deferred_name=self.name
188
+ ).as_token
189
+
190
+ def token_from_payload[P](
191
+ self, *, workflow: Workflow[P, Any, Any], payload: P
192
+ ) -> Effect[Token]:
193
+ return workflow.execution_id(payload).map(
194
+ lambda execution_id: self.token_from_execution_id(
195
+ workflow=workflow, execution_id=execution_id
196
+ )
197
+ )
198
+
199
+ def done(self, *, token: str, exit: Exit[A, E]) -> Effect[None, Never, WorkflowEngine]:
200
+ """Record ``exit`` as the result of the deferred ``token`` names,
201
+ waking its execution. A token naming another deferred is a defect
202
+ (Effect writes ``exit`` into that deferred, with this one's schema)."""
203
+
204
+ def body() -> Generator[Effect[Any, Never, Any], Any]:
205
+ engine = yield from WorkflowEngine()
206
+ parsed = TokenParsed.from_string(token)
207
+ if parsed.deferred_name != self.name:
208
+ raise ValueError(
209
+ f"token names the deferred {parsed.deferred_name!r}, not {self.name!r}"
210
+ )
211
+ yield from engine.deferred_done(
212
+ self,
213
+ workflow_name=parsed.workflow_name,
214
+ execution_id=parsed.execution_id,
215
+ deferred_name=parsed.deferred_name,
216
+ exit=exit,
217
+ )
218
+
219
+ return gen(body)
220
+
221
+ def succeed(self, *, token: str, value: A) -> Effect[None, Never, WorkflowEngine]:
222
+ return self.done(token=token, exit=Success(value))
223
+
224
+ def fail(self, *, token: str, error: E) -> Effect[None, Never, WorkflowEngine]:
225
+ from pyfect.cause import fail as fail_cause_of
226
+
227
+ return self.done(token=token, exit=Failure(fail_cause_of(error)))
228
+
229
+ def fail_cause(self, *, token: str, cause: Cause[E]) -> Effect[None, Never, WorkflowEngine]:
230
+ return self.done(token=token, exit=Failure(cause))
231
+
232
+
233
+ def make[A = None, E = Never](
234
+ name: str,
235
+ *,
236
+ success: Codec[A, Any, Never, Never] | None = None,
237
+ error: Codec[E, Any, Never, Never] | None = None,
238
+ ) -> DurableDeferred[A, E]:
239
+ """A deferred named ``name`` (unique within its workflow). ``success``
240
+ defaults to ``None`` (Effect's ``Void``), ``error`` to none."""
241
+ return DurableDeferred(
242
+ name,
243
+ success=cast("Codec[A, Any, Never, Never]", NullSchema) if success is None else success,
244
+ error=cast("Codec[E, Any, Never, Never]", NeverSchema) if error is None else error,
245
+ )
246
+
247
+
248
+ # --- waits and the runs that own them ---------------------------------------------------
249
+
250
+ _await_owners: WeakKeyDictionary[WorkflowInstanceService, list[str]] = WeakKeyDictionary()
251
+ """The waits registered under the instance copy of a ``_record_held`` body."""
252
+
253
+
254
+ def _register_await(instance: WorkflowInstanceService, name: str) -> None:
255
+ instance.awaited_deferreds[name] = instance.awaited_deferreds.get(name, 0) + 1
256
+ owned = _await_owners.get(instance)
257
+ if owned is not None:
258
+ owned.append(name)
259
+
260
+
261
+ def _release_awaits(instance: WorkflowInstanceService, names: list[str]) -> None:
262
+ for name in names:
263
+ count = instance.awaited_deferreds[name] - 1
264
+ if count == 0:
265
+ del instance.awaited_deferreds[name]
266
+ else:
267
+ instance.awaited_deferreds[name] = count
268
+
269
+
270
+ def await_[A, E](self: DurableDeferred[A, E]) -> Effect[A, E, WorkflowEngine | WorkflowInstance]:
271
+ """``self``'s result, suspending the execution until there is one."""
272
+
273
+ def body() -> Generator[Effect[Any, Any, Any], Any, A]:
274
+ engine = yield from WorkflowEngine()
275
+ instance = yield from WorkflowInstance()
276
+ # Register before the read, so any later completion can preempt the run.
277
+ _register_await(instance, self.name)
278
+ found = yield from wrap_activity_result(engine.deferred_result(self), lambda e: e is None)
279
+ if found is None:
280
+ return (yield from suspend_run(instance))
281
+ return (yield from from_exit(found))
282
+
283
+ return gen(body)
284
+
285
+
286
+ def _record_exit(
287
+ engine: WorkflowEngineService,
288
+ instance: WorkflowInstanceService,
289
+ self: DurableDeferred[Any, Any],
290
+ ex: Exit[Any, Any],
291
+ ) -> Effect[None]:
292
+ """Record ``ex`` into ``self``. An exit of interrupts only is no result
293
+ (the effect suspended, was preempted or interrupted); interrupts mixed
294
+ into a failure are dropped from the recorded cause."""
295
+ if isinstance(ex, Failure):
296
+ if ex.cause.has_interrupts_only:
297
+ return succeed(None)
298
+ if ex.cause.has_interrupts:
299
+ ex = Failure(from_reasons(r for r in ex.cause.reasons if not isinstance(r, Interrupt)))
300
+ return engine.deferred_done(
301
+ self,
302
+ workflow_name=instance.workflow.tag,
303
+ execution_id=instance.execution_id,
304
+ deferred_name=self.name,
305
+ exit=ex,
306
+ )
307
+
308
+
309
+ def _record_held[A, E, R](
310
+ effect: Effect[A, E, R], self: DurableDeferred[Any, Any], *, check_cache: bool
311
+ ) -> Effect[A, E, R | WorkflowEngine | WorkflowInstance]:
312
+ """Run ``effect`` as one activity of the workflow and record its exit
313
+ into ``self`` (with ``check_cache``, a recorded exit is returned
314
+ instead). The hold spans the lookup, ``effect`` and the write, so a
315
+ parked sibling cannot suspend the run before the continuation starts."""
316
+
317
+ def body() -> Generator[Effect[Any, Any, Any], Any, A]:
318
+ engine = yield from WorkflowEngine()
319
+ instance = yield from WorkflowInstance()
320
+
321
+ def held() -> Generator[Effect[Any, Any, Any], Any, Exit[A, E] | None]:
322
+ if check_cache:
323
+ cached = yield from engine.deferred_result(self)
324
+ if cached is not None:
325
+ return cached
326
+ # ``effect`` counts on its own activity state, so a durable wait
327
+ # inside it waits for its own siblings, not for this hold. The
328
+ # copy starts unsuspended: a parked arm of an enclosing race
329
+ # leaves that copy marked suspended.
330
+ local = instance.copy()
331
+ # A losing branch parked on a durable wait has exited when the
332
+ # race settles, so this body owns the waits registered beneath it.
333
+ owned: list[str] = []
334
+ _await_owners[local] = owned
335
+ # A parked ``effect`` interrupts the fiber it runs on; the child
336
+ # keeps that from skipping the suspension handling below.
337
+ fiber = yield from (
338
+ effect.pipe(provide_service(WorkflowInstance, local))
339
+ .on_exit(lambda ex: _record_exit(engine, instance, self, ex))
340
+ .fork(start_immediately=True)
341
+ )
342
+
343
+ def settle(ex: Exit[A, E]) -> Exit[A, E] | None:
344
+ if local.suspended and isinstance(ex, Failure) and ex.cause.has_interrupts_only:
345
+ return None
346
+ return ex
347
+
348
+ def release(result: Exit[Exit[A, E] | None, Never]) -> Effect[None]:
349
+ def run() -> None:
350
+ if isinstance(result, Success) and result.value is not None:
351
+ _release_awaits(instance, owned)
352
+ else:
353
+ parent = _await_owners.get(instance)
354
+ if parent is not None:
355
+ parent.extend(owned)
356
+
357
+ return sync(run)
358
+
359
+ return (
360
+ yield from fiber.await_exit()
361
+ .on_interrupt(fiber.interrupt())
362
+ .map(settle)
363
+ .on_exit(release)
364
+ )
365
+
366
+ # Every branch parked: release the hold and let the enclosing
367
+ # activities finish before suspending.
368
+ found = yield from wrap_activity_result(gen(held), lambda e: e is None)
369
+ if found is None:
370
+ return (yield from suspend_run(instance))
371
+ return (yield from from_exit(found))
372
+
373
+ return gen(body)
374
+
375
+
376
+ def race_all[A, E, R](
377
+ *,
378
+ name: str,
379
+ success: Exactly[A],
380
+ error: Exactly[E],
381
+ effects: Sequence[Effect[A, E, R]],
382
+ ) -> Effect[A, E, R | WorkflowEngine | WorkflowInstance]:
383
+ """Race ``effects`` durably: the first to succeed wins (or the last
384
+ failure), its exit is recorded, and a replay gets the recorded exit
385
+ without running them again."""
386
+ if not effects:
387
+ raise ValueError("race_all needs at least one effect")
388
+ deferred: DurableDeferred[A, E] = DurableDeferred(
389
+ f"raceAll/{name}", success=codec_of(success), error=codec_of(error)
390
+ )
391
+ return _record_held(race_all_effects(*effects), deferred, check_cache=True)
392
+
393
+
394
+ __all__ = [
395
+ "TOKEN_FROM_STRING",
396
+ "DurableDeferred",
397
+ "Token",
398
+ "TokenParsed",
399
+ "TokenSchema",
400
+ "await_",
401
+ "make",
402
+ "race_all",
403
+ ]
@@ -0,0 +1,259 @@
1
+ """Work a workflow hands to persisted background workers (Effect's
2
+ ``effect/workflow/DurableQueue``)::
3
+
4
+ Emails = durable_queue.make(
5
+ name="emails",
6
+ payload=S.Struct(Email),
7
+ idempotency_key=lambda email: email["id"],
8
+ )
9
+
10
+ # in a workflow: offer the item and suspend until a worker is done
11
+ yield from Emails.process({"id": "welcome-ada", "to": "ada@example.com"})
12
+
13
+ # in a worker process
14
+ EmailWorker = Emails.worker(send_email, concurrency=5)
15
+
16
+ ``process`` offers the item to the ``PersistedQueue`` named
17
+ ``DurableQueue/<name>`` with a ``DurableDeferred`` token, then suspends;
18
+ a worker takes it, runs the handler and records the handler's ``Exit``
19
+ through the token, which resumes the workflow with the typed success or
20
+ error.
21
+
22
+ Delivery is at-least-once: a crash between the handler's success and the
23
+ acknowledgement delivers the item again, so handlers must be idempotent.
24
+ An item out of attempts is dead-lettered: its deferred never resolves and
25
+ the workflow stays parked until the item is requeued out of band (the
26
+ id-based de-duplication keeps replays from resurrecting it). Run
27
+ ``persisted_queue.layer_cleanup`` in one instance to prune old items.
28
+
29
+ A worker killed while it holds an item stalls that item until its lock
30
+ expires: 120 seconds by default with ``persisted_queue.layer_store_sql`` and
31
+ 90 with ``layer_store_redis``. Set it with ``lock_expiration=`` on the store.
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ from collections.abc import Callable, Generator
37
+ from typing import Any, Never, TypedDict, cast
38
+
39
+ from pyfect._core import Effect
40
+ from pyfect.effect import die, fail, gen, never
41
+ from pyfect.exit import Exit
42
+ from pyfect.layer import Layer, effect_discard
43
+ from pyfect.logger import log_warning
44
+ from pyfect.persistence import persisted_queue
45
+ from pyfect.persistence.persisted_queue import PersistedQueueError, PersistedQueueFactory
46
+ from pyfect.schedule import Schedule, exponential, min, spaced
47
+ from pyfect.schema import Bottom, Codec, SchemaError, Struct
48
+ from pyfect.scope import Scope
49
+ from pyfect.tracer import ExternalSpan, Span, use_span
50
+ from pyfect.workflow._services import WorkflowEngine, WorkflowInstance
51
+ from pyfect.workflow.activity import idempotency_key as activity_idempotency_key
52
+ from pyfect.workflow.durable_deferred import DurableDeferred, Token, TokenParsed, TokenSchema
53
+ from pyfect.workflow.durable_deferred import make as make_deferred
54
+
55
+
56
+ class _QueueItem(TypedDict):
57
+ token: Token
58
+ traceId: str
59
+ spanId: str
60
+ sampled: bool
61
+ payload: object
62
+
63
+
64
+ """What the queue stores: the item and the token and span to answer to."""
65
+
66
+ _queue_schemas: dict[int, tuple[object, Bottom[_QueueItem, Any, Never, Never]]] = {}
67
+
68
+
69
+ def _queue_schema(payload: Codec[Any, Any, Never, Never]) -> Bottom[_QueueItem, Any, Never, Never]:
70
+ cached = _queue_schemas.get(id(payload))
71
+ if cached is not None and cached[0] is payload:
72
+ return cached[1]
73
+ schema = Struct(_QueueItem, token=TokenSchema, payload=payload)
74
+ _queue_schemas[id(payload)] = (payload, schema)
75
+ return schema
76
+
77
+
78
+ DEFAULT_RETRY_SCHEDULE: Schedule[Any, Any, Any, Any] = min(exponential(0.5, 1.5), spaced(60))
79
+ """How ``process`` retries a failed offer: exponential from 500 ms, at most
80
+ a minute apart."""
81
+
82
+
83
+ class DurableQueue[P, A = None, E = Never]:
84
+ """A queue of ``P`` items whose workers succeed with ``A`` or fail with
85
+ ``E``. Make one with ``make``."""
86
+
87
+ __slots__ = ("deferred", "idempotency_key", "name", "payload_schema")
88
+
89
+ def __init__(
90
+ self,
91
+ *,
92
+ name: str,
93
+ payload_schema: Codec[P, Any, Never, Never],
94
+ idempotency_key: Callable[[P], str],
95
+ deferred: DurableDeferred[A, E],
96
+ ) -> None:
97
+ self.name = name
98
+ self.payload_schema = payload_schema
99
+ self.idempotency_key = idempotency_key
100
+ self.deferred = deferred
101
+
102
+ def __repr__(self) -> str:
103
+ return f"DurableQueue({self.name!r})"
104
+
105
+ def _item_deferred(self, name: str) -> DurableDeferred[A, E]:
106
+ """The deferred one queued item answers through."""
107
+ return DurableDeferred(
108
+ name, success=self.deferred.success_schema, error=self.deferred.error_schema
109
+ )
110
+
111
+ def _item_done(self, token: Token, exit: Exit[A, E]) -> Effect[None, Never, WorkflowEngine]:
112
+ """Answer the item ``token`` names, through its own deferred (a
113
+ deferred refuses a token naming another one)."""
114
+ return self._item_deferred(TokenParsed.from_string(token).deferred_name).done(
115
+ token=token, exit=exit
116
+ )
117
+
118
+ def process(
119
+ self, payload: P, *, retry_schedule: Schedule[Any, Any, Any, Any] | None = None
120
+ ) -> Effect[A, E, WorkflowEngine | WorkflowInstance | PersistedQueueFactory]:
121
+ """Offer ``payload`` and wait (suspended) for a worker to process
122
+ it. A failed offer is retried on ``retry_schedule`` (logged), then
123
+ is a defect."""
124
+
125
+ def body() -> Generator[Effect[Any, Any, Any], Any, A]:
126
+ made = self.payload_schema.__codec__().make(payload)
127
+ queue_name = f"DurableQueue/{self.name}"
128
+ queue = yield from persisted_queue.make(
129
+ name=queue_name, schema=_queue_schema(self.payload_schema)
130
+ )
131
+ item_id = yield from activity_idempotency_key(
132
+ f"{queue_name}/{self.idempotency_key(made)}"
133
+ )
134
+ deferred = self._item_deferred(f"{self.deferred.name}/{item_id}")
135
+ token = yield from deferred.token()
136
+
137
+ def offer(span: Span) -> Effect[None]:
138
+ item: _QueueItem = {
139
+ "token": token,
140
+ "payload": made,
141
+ "traceId": span.trace_id,
142
+ "spanId": span.span_id,
143
+ "sampled": span.sampled,
144
+ }
145
+
146
+ def schema_defect(
147
+ error: PersistedQueueError | SchemaError,
148
+ ) -> Effect[Never, PersistedQueueError]:
149
+ return die(error) if isinstance(error, SchemaError) else fail(error)
150
+
151
+ return (
152
+ queue.offer(item, id=item_id)
153
+ .tap_cause(log_warning)
154
+ .catch_all(schema_defect)
155
+ .retry(DEFAULT_RETRY_SCHEDULE if retry_schedule is None else retry_schedule)
156
+ .or_die()
157
+ .as_void()
158
+ .annotate_logs(
159
+ {
160
+ "package": "effect",
161
+ "module": "DurableQueue",
162
+ "fiber": "process",
163
+ "queueName": self.name,
164
+ }
165
+ )
166
+ )
167
+
168
+ yield from use_span(
169
+ f"DurableQueue/{self.name}/process", offer, attributes={"id": item_id}
170
+ )
171
+ return (yield from deferred.wait())
172
+
173
+ return gen(body)
174
+
175
+ def make_worker[R = Never](
176
+ self,
177
+ f: Callable[[P], Effect[A, E, R]],
178
+ *,
179
+ concurrency: int = 1,
180
+ ) -> Effect[Never, Never, WorkflowEngine | PersistedQueueFactory | R]:
181
+ """Take items forever, ``concurrency`` at a time, recording each
182
+ handler's exit for the workflow that offered it. A failure is
183
+ logged and the worker goes on."""
184
+
185
+ def body() -> Generator[Effect[Any, Any, Any], Any, Any]:
186
+ queue = yield from persisted_queue.make(
187
+ name=f"DurableQueue/{self.name}", schema=_queue_schema(self.payload_schema)
188
+ )
189
+
190
+ def handle(
191
+ item: _QueueItem, _meta: persisted_queue.Metadata
192
+ ) -> Effect[None, Never, Any]:
193
+ payload = cast("P", item["payload"])
194
+ return (
195
+ f(payload)
196
+ .exit()
197
+ .flat_map(lambda ex: self._item_done(item["token"], ex))
198
+ .with_span(
199
+ f"DurableQueue/{self.name}/worker",
200
+ capture_stack_trace=False,
201
+ parent=ExternalSpan(
202
+ trace_id=item["traceId"],
203
+ span_id=item["spanId"],
204
+ sampled=item["sampled"],
205
+ ),
206
+ )
207
+ )
208
+
209
+ worker = (
210
+ queue.take(handle)
211
+ .catch_cause(log_warning)
212
+ .forever()
213
+ .annotate_logs(
214
+ {
215
+ "package": "effect",
216
+ "module": "DurableQueue",
217
+ "fiber": "worker",
218
+ "queueName": self.name,
219
+ }
220
+ )
221
+ )
222
+ yield from worker.replicate_effect(concurrency, concurrency=concurrency, discard=True)
223
+ return (yield from never)
224
+
225
+ return gen(body)
226
+
227
+ def worker[R = Never](
228
+ self, f: Callable[[P], Effect[A, E, R]], *, concurrency: int = 1
229
+ ) -> Layer[Never, Never, WorkflowEngine | PersistedQueueFactory | R]:
230
+ """A layer running ``make_worker`` in the background."""
231
+ started: Effect[object, Never, Any] = self.make_worker(
232
+ f, concurrency=concurrency
233
+ ).fork_scoped()
234
+ return cast(
235
+ "Layer[Never, Never, WorkflowEngine | PersistedQueueFactory | R]",
236
+ effect_discard(cast("Effect[object, Never, Scope]", started)),
237
+ )
238
+
239
+
240
+ def make[P, A = None, E = Never](
241
+ *,
242
+ name: str,
243
+ payload: Codec[P, Any, Never, Never],
244
+ idempotency_key: Callable[[P], str],
245
+ success: Codec[A, Any, Never, Never] | None = None,
246
+ error: Codec[E, Any, Never, Never] | None = None,
247
+ ) -> DurableQueue[P, A, E]:
248
+ """A queue named ``name`` of ``payload`` items; ``idempotency_key``
249
+ names an item within its workflow execution. ``success`` defaults to
250
+ ``None``, ``error`` to none."""
251
+ return DurableQueue(
252
+ name=name,
253
+ payload_schema=payload,
254
+ idempotency_key=idempotency_key,
255
+ deferred=make_deferred(f"DurableQueue/{name}", success=success, error=error),
256
+ )
257
+
258
+
259
+ __all__ = ["DEFAULT_RETRY_SCHEDULE", "DurableQueue", "make"]