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
pyfect/_fiber.py ADDED
@@ -0,0 +1,969 @@
1
+ """The fiber runtime.
2
+
3
+ A fiber runs one effect. It keeps an explicit stack of continuation frames
4
+ (so deep chains never hit Python's recursion limit) and runs on a
5
+ ``Scheduler``. It never blocks: when it has to wait, it registers a resume
6
+ callback and parks (``SUSPEND``).
7
+
8
+ Resumes follow Effect's ``evaluate``: a resume, an interrupt or a start
9
+ called on the thread running the fiber's run runs the fiber at once,
10
+ nested in the caller, up to its next wait or yield, before the call
11
+ returns. A fork with ``start_immediately`` runs the child before the fork
12
+ returns. Nesting is bounded (``_MAX_NESTED_RUNS``): deeper than that, the
13
+ fiber runs right after the innermost running fiber's run instead, so a
14
+ chain of wake-ups cannot overflow the stack. Calls from other threads go
15
+ through the fiber's scheduler.
16
+
17
+ Interruption follows Effect's rules:
18
+
19
+ - Interrupting a fiber records an ``Interrupt`` at once when the caller is
20
+ on the thread of the fiber's run (otherwise via the scheduler). If the
21
+ fiber is interruptible and not running, it is unwound right away: a fiber
22
+ that has not started never runs its body, a parked fiber has its wait
23
+ cancelled (running its canceler), and a fiber queued after a yield or a
24
+ step-budget pause is unwound instead of resuming. A running fiber,
25
+ including one that interrupts itself, stops at its next step. A fiber
26
+ whose resume another thread already queued gets the interrupt after that
27
+ resumed run, since in Effect the resume would already have run.
28
+ - While interruptible and interrupted, the loop turns whatever comes next
29
+ into a failure, so the stack unwinds. Recovery handlers are skipped;
30
+ finalizers run, because they run in uninterruptible regions. The exit a
31
+ step returns reaches its continuation with no pause in between, so a
32
+ result the step decided (a taken item, an applied update) is never
33
+ dropped by an interrupt landing at a yield.
34
+ - Inside an uninterruptible region the interrupt waits until the region
35
+ ends.
36
+
37
+ Supervision: a fiber's children (from ``fork``) are interrupted and awaited
38
+ before the fiber completes.
39
+ """
40
+ # pyright: reportPrivateUsage=false
41
+
42
+ from __future__ import annotations
43
+
44
+ import contextvars
45
+ import itertools
46
+ import math
47
+ import threading
48
+ from collections import deque
49
+ from collections.abc import Callable, Iterable
50
+ from dataclasses import dataclass
51
+ from functools import partial
52
+ from typing import TYPE_CHECKING, Any, Generic, Literal, Never, TypeVar
53
+
54
+ from pyfect._core import (
55
+ SUSPEND,
56
+ Effect,
57
+ Frame,
58
+ Register,
59
+ Step,
60
+ _Callback,
61
+ _FromExit,
62
+ _RestoreInterruptible,
63
+ _Succeed,
64
+ _Sync,
65
+ _WithFiber,
66
+ )
67
+ from pyfect._interrupt_reason import closed
68
+ from pyfect._metric_ref import FiberRuntimeMetrics
69
+ from pyfect._stack_frame import CurrentStackFrame, InterruptorStackTrace, StackFrame, StackTrace
70
+ from pyfect._tracer_ref import CurrentTracer
71
+ from pyfect._wake_tracking import Tracking
72
+ from pyfect.cause import Cause
73
+ from pyfect.cause import interrupt as interrupt_cause
74
+ from pyfect.context import Context, Reference, Tag
75
+ from pyfect.exit import Exit, Failure, Success
76
+ from pyfect.exit import die as exit_die
77
+ from pyfect.scheduler import (
78
+ BoundScheduler,
79
+ CurrentScheduler,
80
+ EffectScheduler,
81
+ MaxOpsBeforeYield,
82
+ PreventSchedulerYield,
83
+ Scheduler,
84
+ )
85
+
86
+ if TYPE_CHECKING:
87
+ from pyfect._metric_ref import FiberRuntimeMetricsService
88
+ from pyfect.scope import CloseableScope
89
+ from pyfect.tracer import ContextHook
90
+
91
+ A_co = TypeVar("A_co", covariant=True)
92
+ E_co = TypeVar("E_co", covariant=True, default=Never)
93
+
94
+ # Effect's ``maxInlineSteps``: how many continuations run back to back
95
+ # before the loop may yield.
96
+ _INLINE_STEPS = 32
97
+
98
+ # How many fiber runs may nest on one thread (a resume running the woken
99
+ # fiber inside the resumer's step, and so on). Past it, a run waits for the
100
+ # innermost one to finish, so the Python stack stays bounded.
101
+ _MAX_NESTED_RUNS = 16
102
+
103
+ _fiber_ids = itertools.count(1)
104
+ _resume_lock = threading.Lock()
105
+
106
+
107
+ type _Run = tuple[Fiber[Any, Any], Step]
108
+
109
+
110
+ class _Drain:
111
+ """Fiber runs of one run scheduler on this thread, nested ``depth``
112
+ runs deep: the fiber running now, then ``queue``, the runs that came in
113
+ while it ran but could not nest any deeper. ``first`` collects the runs
114
+ the current run hands over that way (children started immediately,
115
+ then the rest of the forking fiber), which go before everything
116
+ queued."""
117
+
118
+ __slots__ = ("current", "depth", "first", "queue", "run_scheduler")
119
+
120
+ def __init__(self, run_scheduler: Scheduler, depth: int) -> None:
121
+ self.run_scheduler = run_scheduler
122
+ self.depth = depth
123
+ self.current: Fiber[Any, Any] | None = None
124
+ # Made on first use: most drains run one fiber once.
125
+ self.queue: deque[_Run] | None = None
126
+ self.first: list[_Run] | None = None
127
+
128
+ def push(self, run: _Run) -> None:
129
+ if self.queue is None:
130
+ self.queue = deque()
131
+ self.queue.append(run)
132
+
133
+ def push_first(self, run: _Run) -> None:
134
+ if self.first is None:
135
+ self.first = []
136
+ self.first.append(run)
137
+
138
+
139
+ class _ThreadState(threading.local):
140
+ """The drain running fibers on this thread, if any. It also knows the
141
+ fiber running now, so a fiber switch costs no thread-local writes."""
142
+
143
+ drain: _Drain | None = None
144
+
145
+
146
+ _thread = _ThreadState()
147
+
148
+
149
+ def current_fiber() -> Fiber[Any, Any] | None:
150
+ """The fiber running on this thread, if any."""
151
+ drain = _thread.drain
152
+ return None if drain is None else drain.current
153
+
154
+
155
+ def current_run_scheduler() -> Scheduler | None:
156
+ """The scheduler of the run whose fiber is running on this thread."""
157
+ drain = _thread.drain
158
+ return None if drain is None or drain.current is None else drain.run_scheduler
159
+
160
+
161
+ type Uninterruptible = bool | Literal["inherit"]
162
+ """A forked fiber's starting interruptibility: ``False`` (interruptible),
163
+ ``True``, or ``"inherit"`` the forking fiber's."""
164
+
165
+ type _Phase = Literal["pending", "running", "idle"]
166
+ """``pending``: forked, first run not yet started. ``running``: inside
167
+ ``_run``. ``idle``: parked in a wait, or queued to run again."""
168
+
169
+
170
+ class _Wait:
171
+ """One suspension. ``resume`` is safe to call from any thread, any
172
+ number of times; only the first call counts. ``done``, ``registering``
173
+ and ``sync_result`` change together under ``_resume_lock``: a resume
174
+ racing the end of registration on another thread (free-threaded
175
+ builds have no GIL to order them) either lands in ``sync_result``
176
+ before registration reads it, or sees registration over and resumes
177
+ the parked fiber.
178
+
179
+ The wait lets go of its fiber once claimed: ``resume`` is handed to the
180
+ outside (a future's callbacks, a listener list), which may keep it
181
+ after it fired, and must not keep the fiber, and its result, alive."""
182
+
183
+ __slots__ = ("canceler", "done", "fiber", "registering", "sync_result")
184
+
185
+ def __init__(self, fiber: Fiber[Any, Any]) -> None:
186
+ self.fiber: Fiber[Any, Any] | None = fiber
187
+ self.done = False
188
+ self.registering = True
189
+ self.sync_result: Effect[Any, Any, Any] | None = None
190
+ self.canceler: Effect[Any, Any, Any] | None = None
191
+
192
+ def claim(self) -> bool:
193
+ with _resume_lock:
194
+ if self.done:
195
+ return False
196
+ self.done = True
197
+ self.fiber = None
198
+ return True
199
+
200
+ def end_registration(self) -> Effect[Any, Any, Any] | None:
201
+ """Registration is over; the effect a resume during it left."""
202
+ with _resume_lock:
203
+ self.registering = False
204
+ result, self.sync_result = self.sync_result, None
205
+ return result
206
+
207
+ def resume(self, effect: Effect[Any, Any, Any]) -> None:
208
+ with _resume_lock:
209
+ fiber = self.fiber
210
+ if fiber is None:
211
+ return
212
+ self.done = True
213
+ self.fiber = None
214
+ self.canceler = None
215
+ if self.registering:
216
+ self.sync_result = effect
217
+ return
218
+ if fiber._on_run_thread():
219
+ fiber._resume(self, effect)
220
+ else:
221
+ fiber._scheduler.schedule(lambda: fiber._resume(self, effect))
222
+
223
+
224
+ class _Yielded:
225
+ """A run queued on the scheduler after a yield or a step-budget pause.
226
+ An interrupt takes it over (``Fiber._deliver_interrupt``); the queued
227
+ task then finds it gone and does nothing."""
228
+
229
+ __slots__ = ("step",)
230
+
231
+ def __init__(self, step: Step) -> None:
232
+ self.step = step
233
+
234
+
235
+ class _ReturnExit(Frame):
236
+ """Finish with a stored exit, ignoring whatever ran above it."""
237
+
238
+ __slots__ = ("exit",)
239
+
240
+ def __init__(self, ex: Exit[Any, Any]) -> None:
241
+ self.exit = ex
242
+
243
+ def _on_success(self, value: Any, fiber: Fiber[Any, Any]) -> Step:
244
+ return self.exit
245
+
246
+ def _on_failure(self, cause: Cause[Any], fiber: Fiber[Any, Any]) -> Step:
247
+ return self.exit
248
+
249
+
250
+ class Fiber(Generic[A_co, E_co]):
251
+ """A running effect. Obtain one with ``eff.fork()``."""
252
+
253
+ __slots__ = (
254
+ "__weakref__",
255
+ "_async_context",
256
+ "_children",
257
+ "_ctx",
258
+ "_exit",
259
+ "_interrupt",
260
+ "_interruptible",
261
+ "_interrupts_after_resume",
262
+ "_observers",
263
+ "_ops_budget",
264
+ "_parent",
265
+ "_phase",
266
+ "_run_scheduler",
267
+ "_runtime_metrics",
268
+ "_scheduler",
269
+ "_should_yield",
270
+ "_stack",
271
+ "_stack_frame",
272
+ "_tracer_hook",
273
+ "_waiting",
274
+ "_yielded",
275
+ "current_op_count",
276
+ "id",
277
+ )
278
+
279
+ def __init__(
280
+ self,
281
+ run_scheduler: Scheduler,
282
+ context: Context,
283
+ parent: Fiber[Any, Any] | None,
284
+ *,
285
+ interruptible: bool = True,
286
+ ) -> None:
287
+ """A fiber of the run driven by ``run_scheduler``. It runs on
288
+ ``context``'s ``CurrentScheduler``."""
289
+ self.id = next(_fiber_ids)
290
+ self._run_scheduler = run_scheduler
291
+ self.current_op_count = 0
292
+ self._parent = parent
293
+ self._stack: list[Frame] = []
294
+ self._interruptible = interruptible
295
+ self._interrupt: Cause[Never] | None = None
296
+ # Interrupts that arrived while a resume was queued (see _resume).
297
+ self._interrupts_after_resume: list[tuple[int | None, Context | None]] = []
298
+ # A dict, not a set: children are interrupted in fork order, as in Effect.
299
+ self._children: dict[Fiber[Any, Any], None] = {}
300
+ self._observers: list[Callable[[Exit[Any, Any]], None]] = []
301
+ self._exit: Exit[Any, Any] | None = None
302
+ self._waiting: _Wait | None = None
303
+ self._yielded: _Yielded | None = None
304
+ self._phase: _Phase = "pending"
305
+ # The ``contextvars`` context the fiber parked or paused in, which
306
+ # it resumes in (Effect's captured async context).
307
+ self._async_context: contextvars.Context | None = None
308
+ self._set_context(context)
309
+ if self._runtime_metrics is not None:
310
+ self._runtime_metrics.record_fiber_start(self._ctx)
311
+
312
+ def __repr__(self) -> str:
313
+ return f"Fiber(#{self.id})"
314
+
315
+ # --- public API (all effects, except the ``unsafe_`` reads) ------------
316
+
317
+ def await_exit(self) -> Effect[Exit[A_co, E_co], Never, Never]:
318
+ """Wait for the fiber and succeed with its ``Exit``."""
319
+
320
+ def register(resume: Callable[[Effect[Any, Any, Any]], None]) -> Effect[None] | None:
321
+ if self._exit is not None:
322
+ resume(_Succeed(self._exit))
323
+ return None
324
+
325
+ def observer(ex: Exit[Any, Any]) -> None:
326
+ resume(_Succeed(ex))
327
+
328
+ self._observers.append(observer)
329
+ if self._exit is not None:
330
+ # It finished on another thread (a fiber of another run)
331
+ # between the check and the append; resume counts once.
332
+ resume(_Succeed(self._exit))
333
+ return None
334
+ return _Sync(lambda: self._remove_observer(observer))
335
+
336
+ return _Callback(register)
337
+
338
+ def join(self) -> Effect[A_co, E_co, Never]:
339
+ """Wait for the fiber and take on its result: its value, or its
340
+ failure."""
341
+ return self.await_exit().flat_map(_FromExit)
342
+
343
+ def interrupt(self) -> Effect[None, Never, Never]:
344
+ """Interrupt the fiber and wait until it has finished cleaning up.
345
+ Read the outcome with ``await_exit``."""
346
+ return _WithFiber(lambda me: self._interrupt_from(me, me.id))
347
+
348
+ def interrupt_as(self, by: int | None) -> Effect[None, Never, Never]:
349
+ """``interrupt``, attributed to the fiber with id ``by``."""
350
+ return _WithFiber(lambda me: self._interrupt_from(me, by))
351
+
352
+ def _interrupt_from(self, me: Fiber[Any, Any], by: int | None) -> Effect[None, Never, Never]:
353
+ self.interrupt_as_unsafe(by, me._interruptor_annotations())
354
+ return self.await_exit().as_void()
355
+
356
+ def run_in(self, scope: CloseableScope) -> Fiber[A_co, E_co]:
357
+ """Tie the fiber to ``scope``: closing it interrupts the fiber, and
358
+ the fiber leaves the scope when it exits. Registering again moves
359
+ the fiber's finalizer to the end, so it runs first. A fiber in an
360
+ already closed scope is interrupted. Call on the scheduler thread."""
361
+ if self._exit is not None:
362
+ return self
363
+ if scope._closed is not None:
364
+ self.interrupt_as_unsafe(self.id, closed("Scope"))
365
+ else:
366
+ scope._watch(self)
367
+ return self
368
+
369
+ def get_ref[S](self, reference: type[Reference[S]]) -> S:
370
+ """The value of ``reference`` in this fiber's current context (its
371
+ default when nobody provided one). Loggers read the log annotations
372
+ and spans with it."""
373
+ return self._ctx.get_unsafe(reference)
374
+
375
+ @staticmethod
376
+ def get_current() -> Fiber[Any, Any] | None:
377
+ """The fiber running on this thread, if any."""
378
+ return current_fiber()
379
+
380
+ @staticmethod
381
+ def await_all[A, E](fibers: Iterable[Fiber[A, E]]) -> Effect[list[Exit[A, E]], Never, Never]:
382
+ """Wait for every fiber; succeed with their exits in order."""
383
+ from pyfect._fiber_all import await_all
384
+
385
+ return await_all(fibers)
386
+
387
+ @staticmethod
388
+ def join_all[A, E](fibers: Iterable[Fiber[A, E]]) -> Effect[list[A], E, Never]:
389
+ """Wait for every fiber and succeed with their values in order, or
390
+ fail with the first failure (the others keep running)."""
391
+ from pyfect._fiber_all import join_all
392
+
393
+ return join_all(fibers)
394
+
395
+ @staticmethod
396
+ def interrupt_all(fibers: Iterable[Fiber[Any, Any]]) -> Effect[None, Never, Never]:
397
+ """Interrupt every fiber and wait for all of them to finish."""
398
+ from pyfect._fiber_all import interrupt_all
399
+
400
+ return interrupt_all(fibers)
401
+
402
+ @staticmethod
403
+ def interrupt_all_as(
404
+ fibers: Iterable[Fiber[Any, Any]], by: int | None
405
+ ) -> Effect[None, Never, Never]:
406
+ """``interrupt_all``, attributed to the fiber with id ``by``."""
407
+ from pyfect._fiber_all import interrupt_all_as
408
+
409
+ return interrupt_all_as(fibers, by)
410
+
411
+ def poll_unsafe(self) -> Exit[A_co, E_co] | None:
412
+ """The exit if the fiber is done. Only meaningful on the fiber's
413
+ scheduler thread."""
414
+ return self._exit
415
+
416
+ def interrupt_as_unsafe(self, by: int | None, annotations: Context | None = None) -> None:
417
+ """Ask the fiber to stop. Safe from any thread; does not wait.
418
+
419
+ From the thread running the fiber's run (a fiber of it, or code
420
+ outside any fiber there) it takes effect at once (as Effect's
421
+ ``interruptUnsafe``); from other threads it goes through the
422
+ scheduler. The interruption carries ``annotations`` (the
423
+ interrupting fiber's ``InterruptorStackTrace``) and the frame this
424
+ fiber is in (``StackTrace``)."""
425
+ if self._on_run_thread():
426
+ self._deliver_interrupt(by, annotations)
427
+ else:
428
+ self._scheduler.schedule(lambda: self._deliver_interrupt(by, annotations))
429
+
430
+ def add_observer_unsafe(
431
+ self, observer: Callable[[Exit[A_co, E_co]], None]
432
+ ) -> Callable[[], None]:
433
+ """Call ``observer`` with the exit once the fiber is done (at once if
434
+ it already is). Returns a function that removes the observer. Must
435
+ be called on the scheduler thread."""
436
+ if self._exit is not None:
437
+ observer(self._exit)
438
+ return _no_op
439
+ self._observers.append(observer)
440
+ return lambda: self._remove_observer(observer)
441
+
442
+ # --- runtime internals --------------------------------------------------
443
+
444
+ @property
445
+ def _context(self) -> Context:
446
+ return self._ctx
447
+
448
+ def _set_context(self, context: Context) -> None:
449
+ """Switch context, and with it the scheduler and step budget read
450
+ from it (Effect's fiber context cache)."""
451
+ view = _last_view[0]
452
+ if (
453
+ view is None
454
+ or view.given is not context
455
+ or view.run_scheduler is not self._run_scheduler
456
+ ):
457
+ view = _last_view[0] = _RunView.of(context, self._run_scheduler)
458
+ self._ctx = view.context
459
+ self._scheduler: Scheduler = view.scheduler
460
+ self._ops_budget: float = view.ops_budget
461
+ self._should_yield: EffectScheduler | None = view.should_yield
462
+ self._tracer_hook: ContextHook | None = view.tracer_hook
463
+ self._runtime_metrics: FiberRuntimeMetricsService | None = view.runtime_metrics
464
+ self._stack_frame: StackFrame | None = view.stack_frame
465
+
466
+ def _on_run_thread(self) -> bool:
467
+ """Whether this thread runs this fiber's run now: one of its fibers
468
+ is running here, or its scheduler is running tasks here. Resumes
469
+ and interrupts from here run the fiber at once."""
470
+ run = self._run_scheduler
471
+ return current_run_scheduler() is run or (isinstance(run, Tracking) and run.runs_here())
472
+
473
+ def _interruptor_annotations(self) -> Context | None:
474
+ """What an interruption this fiber sends records about it."""
475
+ frame = self._stack_frame
476
+ return None if frame is None else Context.make(InterruptorStackTrace, frame)
477
+
478
+ def _start(self, effect: Effect[Any, Any, Any]) -> None:
479
+ self._scheduler.schedule(lambda: self._drive(effect))
480
+
481
+ def _push(self, frame: Frame) -> None:
482
+ self._stack.append(frame)
483
+
484
+ def _interrupted_and_interruptible(self) -> bool:
485
+ return self._interrupt is not None and self._interruptible
486
+
487
+ def _run(self, start: Step) -> None:
488
+ if self._exit is not None:
489
+ return # finished early by an interrupt; a stale start or resume
490
+ self._phase = "running"
491
+ parked_in, self._async_context = self._async_context, None
492
+ try:
493
+ if parked_in is None:
494
+ self._loop(start)
495
+ else:
496
+ parked_in.run(self._loop, start)
497
+ finally:
498
+ self._phase = "idle"
499
+ if self._exit is None:
500
+ # Parked or paused: resume in this context, not the waker's.
501
+ self._async_context = contextvars.copy_context() if parked_in is None else parked_in
502
+
503
+ def _loop(self, start: Step) -> None:
504
+ cur: Step = start
505
+ ops = 0
506
+ # Whether ``cur`` is the exit a step (or a frame that ``claims``)
507
+ # just returned: a result it decided (a taken item, an applied
508
+ # update) reaches its continuation with no pause in between, where
509
+ # an interrupt could drop it.
510
+ decided = False
511
+ while True:
512
+ if self._interrupt is not None and self._interruptible:
513
+ cur = self._with_interrupt(cur, self._interrupt)
514
+
515
+ if isinstance(cur, Effect):
516
+ ops += 1
517
+ if ops > self._ops_budget and self._pause_due(cur, ops):
518
+ return
519
+ try:
520
+ hook = self._tracer_hook
521
+ cur = cur._step(self) if hook is None else _run_hooked(hook, cur, self)
522
+ except BaseException as exc:
523
+ cur = self._raised(exc)
524
+ decided = True
525
+ elif isinstance(cur, Success | Failure):
526
+ if not self._stack:
527
+ if self._stack_frame is not None and isinstance(cur, Failure):
528
+ cur = self._in_frame(cur, self._stack_frame)
529
+ nxt = self._finish(cur)
530
+ if nxt is None:
531
+ return
532
+ cur = nxt
533
+ continue
534
+ # A continuation counts as a step, but as in Effect a fiber
535
+ # may yield before one only every ``_INLINE_STEPS`` steps: a
536
+ # long chain of ``map``s still yields, while a primitive's
537
+ # result normally reaches its continuation in the same step.
538
+ ops += 1
539
+ if (
540
+ not decided
541
+ and ops % _INLINE_STEPS == 0
542
+ and ops > self._ops_budget
543
+ and self._pause_due(cur, ops)
544
+ ):
545
+ return
546
+ frame = self._stack.pop()
547
+ decided = frame.claims
548
+ cur = self._continue(frame, cur)
549
+ elif cur is SUSPEND:
550
+ return # a resume callback will call _run again
551
+ else: # untyped user code handed back something that is not an effect
552
+ cur = exit_die(TypeError(f"not a valid effect: {cur!r}"))
553
+
554
+ def _pause_due(self, cur: Step, ops: int) -> bool:
555
+ """Past the budget: pause before ``cur``, unless an
556
+ ``EffectScheduler`` (asked before each step, as Effect) says not to. A raising
557
+ ``should_yield`` is a defect, which the fiber goes on with after the
558
+ pause."""
559
+ check = self._should_yield
560
+ if check is not None:
561
+ self.current_op_count = ops
562
+ try:
563
+ if not check.should_yield(self):
564
+ return False
565
+ except BaseException as exc:
566
+ cur = self._raised(exc)
567
+ self._pause(cur)
568
+ return True
569
+
570
+ def _pause(self, cur: Step) -> None:
571
+ """The step budget is spent: let other fibers run, then go on with
572
+ ``cur``."""
573
+ self._queue_yielded(_Yielded(cur))
574
+
575
+ def _queue_yielded(self, yielded: _Yielded, priority: int = 0) -> None:
576
+ self._yielded = yielded
577
+
578
+ def go_on() -> None:
579
+ if self._yielded is yielded:
580
+ self._yielded = None
581
+ self._drive(yielded.step)
582
+
583
+ self._scheduler.schedule(go_on, priority)
584
+
585
+ def _continue(self, frame: Frame, ex: Exit[Any, Any]) -> Step:
586
+ hook = self._tracer_hook
587
+ try:
588
+ if isinstance(ex, Success):
589
+ if hook is None:
590
+ return frame._on_success(ex.value, self)
591
+ else:
592
+ # A failure meets its next handler (or the end of the fiber,
593
+ # in _loop) annotated with the frame it failed in, as
594
+ # Effect's failure exits are.
595
+ if self._stack_frame is not None:
596
+ ex = self._in_frame(ex, self._stack_frame)
597
+ if hook is None:
598
+ return frame._on_failure(ex.cause, self)
599
+ step: Callable[[], Step] = partial(_hand_over, frame, ex, self)
600
+ return hook(step, self)
601
+ except BaseException as exc:
602
+ return self._raised(exc)
603
+
604
+ def _raised(self, exc: BaseException) -> Step:
605
+ """What the fiber goes on with when user code (a step or a
606
+ continuation) raised ``exc``: a defect, as Effect makes anything
607
+ thrown, whatever the exception's class.
608
+
609
+ Ctrl-C is not the program's own error: the step it cut short ends
610
+ as interrupted (the fiber goes on with that on its next turn), and
611
+ the ``KeyboardInterrupt`` goes on to the runner, which interrupts
612
+ the main fiber and waits for its finalizers, as when Ctrl-C lands
613
+ while every fiber is parked."""
614
+ if isinstance(exc, KeyboardInterrupt):
615
+ self._pause(Failure(self._record_interrupt(None, None)))
616
+ raise exc
617
+ return exit_die(exc)
618
+
619
+ @staticmethod
620
+ def _in_frame(failure: Failure[Any], frame: StackFrame) -> Failure[Any]:
621
+ """Effect's failure annotation: reasons without a ``StackTrace`` get
622
+ the frame the fiber fails in."""
623
+ annotated = failure.cause.annotate(Context.make(StackTrace, frame))
624
+ return failure if annotated is failure.cause else Failure(annotated)
625
+
626
+ @staticmethod
627
+ def _with_interrupt(cur: Step, cause: Cause[Never]) -> Step:
628
+ if isinstance(cur, Failure):
629
+ with_interrupts = cur.cause.add_interrupts(cause)
630
+ return cur if with_interrupts is cur.cause else Failure(with_interrupts)
631
+ return Failure(cause)
632
+
633
+ def _finish(self, ex: Exit[Any, Any]) -> Step | None:
634
+ """The stack is empty. Interrupt children first; then complete."""
635
+ if self._children:
636
+ children = list(self._children)
637
+ self._interruptible = False
638
+ self._push(_ReturnExit(ex))
639
+ return interrupt_all(children, self.id, self._interruptor_annotations())
640
+ self._exit = ex
641
+ if self._runtime_metrics is not None:
642
+ self._runtime_metrics.record_fiber_end(self._ctx, ex)
643
+ view = _last_view[0]
644
+ if view is not None and view.context is self._ctx:
645
+ parent = self._parent
646
+ if parent is None or parent._ctx is not self._ctx:
647
+ # Keep the context of a fiber that is done alive no longer
648
+ # than a fiber that still uses it (a closed scope's exit,
649
+ # say), as Effect, whose cache is per fiber.
650
+ _last_view[0] = None
651
+ if self._parent is not None:
652
+ self._parent._children.pop(self, None)
653
+ observers, self._observers = self._observers, []
654
+ for observer in observers:
655
+ # As Effect: a raise stops the observers after it.
656
+ observer(ex)
657
+ return None
658
+
659
+ def _remove_observer(self, observer: Callable[[Exit[Any, Any]], None]) -> None:
660
+ if self._exit is None and observer in self._observers:
661
+ self._observers.remove(observer)
662
+
663
+ def _fork(
664
+ self,
665
+ effect: Effect[Any, Any, Any],
666
+ *,
667
+ daemon: bool,
668
+ start_immediately: bool,
669
+ uninterruptible: Uninterruptible = False,
670
+ ) -> Fiber[Any, Any]:
671
+ """A fiber running ``effect``, a child of this one unless ``daemon``.
672
+ With ``start_immediately`` it runs now, up to its first wait or
673
+ yield, before this fiber goes on (Effect's ``runForkWith``, and
674
+ ``fork*`` with ``startImmediately``); otherwise it is scheduled.
675
+ Required, so each port states which of the two Effect does."""
676
+ interruptible = self._interruptible if uninterruptible == "inherit" else not uninterruptible
677
+ child: Fiber[Any, Any] = Fiber(
678
+ self._run_scheduler, self._ctx, None if daemon else self, interruptible=interruptible
679
+ )
680
+ if not daemon:
681
+ self._children[child] = None
682
+ if start_immediately:
683
+ child._drive_first(effect)
684
+ else:
685
+ child._start(effect)
686
+ return child
687
+
688
+ def _after_started(self, then: Step) -> Step:
689
+ """Go on with ``then`` once the fibers this run started immediately
690
+ have run (up to their first wait or yield)."""
691
+ drain = _thread.drain
692
+ if drain is None or not drain.first:
693
+ return then
694
+ drain.push_first((self, then))
695
+ return SUSPEND
696
+
697
+ def _yield_now(self, priority: int = 0) -> Step:
698
+ self._queue_yielded(_Yielded(Success(None)), priority)
699
+ return SUSPEND
700
+
701
+ def _suspend(self, register: Register[Any, Any, Any]) -> Step:
702
+ wait = _Wait(self)
703
+ try:
704
+ canceler = register(wait.resume)
705
+ except BaseException:
706
+ wait.claim()
707
+ raise
708
+ sync_result = wait.end_registration()
709
+ if sync_result is not None:
710
+ return sync_result
711
+ wait.canceler = canceler
712
+ self._waiting = wait
713
+ if self._interrupted_and_interruptible():
714
+ return self._cancel_wait(wait)
715
+ return SUSPEND
716
+
717
+ def _resume(self, wait: _Wait, effect: Effect[Any, Any, Any]) -> None:
718
+ """Run a claimed resume now. In Effect a resume runs the fiber at
719
+ once, so an interrupt that arrived while another thread's resume
720
+ was queued lands only once the resumed run has finished, parked or
721
+ yielded."""
722
+ if self._waiting is wait:
723
+ self._waiting = None
724
+ self._evaluate(effect)
725
+ deferred, self._interrupts_after_resume = self._interrupts_after_resume, []
726
+ for by, interruptor in deferred:
727
+ self._deliver_interrupt(by, interruptor)
728
+
729
+ def _deliver_interrupt(self, by: int | None, annotations: Context | None) -> None:
730
+ if self._exit is not None:
731
+ return
732
+ wait = self._waiting
733
+ if wait is not None and self._interruptible and self._phase != "running":
734
+ if not wait.claim():
735
+ self._interrupts_after_resume.append((by, annotations))
736
+ return
737
+ self._record_interrupt(by, annotations)
738
+ step = self._abandon_wait(wait)
739
+ self._evaluate(step)
740
+ return
741
+ if wait is not None and wait.done:
742
+ self._interrupts_after_resume.append((by, annotations))
743
+ return
744
+ interrupt = self._record_interrupt(by, annotations)
745
+ if not self._interruptible or self._phase == "running":
746
+ return # the loop raises it at its next interruptible step
747
+ yielded = self._yielded
748
+ if yielded is not None:
749
+ # Queued after a yield or a pause: unwind now (Effect's
750
+ # evaluate of a yielded fiber); the queued task does nothing.
751
+ self._yielded = None
752
+ self._evaluate(yielded.step)
753
+ elif self._phase == "pending":
754
+ self._evaluate(Failure(interrupt))
755
+ # Otherwise it is queued to run on this thread, nested deeper than
756
+ # runs may go, and meets the interrupt at its first step.
757
+
758
+ def _record_interrupt(self, by: int | None, annotations: Context | None) -> Cause[Never]:
759
+ cause = interrupt_cause(by)
760
+ if self._stack_frame is not None:
761
+ cause = cause.annotate(Context.make(StackTrace, self._stack_frame))
762
+ if annotations is not None:
763
+ cause = cause.annotate(annotations)
764
+ if self._interrupt is not None:
765
+ cause = self._interrupt.add_interrupts(cause)
766
+ self._interrupt = cause
767
+ return cause
768
+
769
+ def _evaluate(self, step: Step) -> None:
770
+ """Run this fiber with ``step`` now, nested in whatever runs on this
771
+ thread (Effect's ``evaluate``). Past ``_MAX_NESTED_RUNS`` nested
772
+ runs of this run it runs right after the innermost one instead."""
773
+ outer = _thread.drain
774
+ if outer is None:
775
+ self._drain((self, step), 0)
776
+ elif outer.depth >= _MAX_NESTED_RUNS and outer.run_scheduler is self._run_scheduler:
777
+ outer.push((self, step))
778
+ else:
779
+ self._drain((self, step), outer.depth + 1)
780
+
781
+ def _drive(self, step: Step) -> None:
782
+ """Run this fiber from a scheduled task: now, or, if the scheduler
783
+ runs its tasks inside a fiber of the run, right after that fiber's
784
+ run."""
785
+ outer = _thread.drain
786
+ if outer is not None and outer.run_scheduler is self._run_scheduler:
787
+ outer.push((self, step))
788
+ else:
789
+ self._evaluate(step)
790
+
791
+ def _drain(self, start: _Run, depth: int) -> None:
792
+ outer = _thread.drain
793
+ _thread.drain = drain = _Drain(self._run_scheduler, depth)
794
+ fiber, nxt = start
795
+ try:
796
+ while True:
797
+ drain.current = fiber
798
+ fiber._run(nxt)
799
+ drain.current = None
800
+ first = drain.first
801
+ if first:
802
+ drain.first = None
803
+ if drain.queue is None:
804
+ drain.queue = deque(first)
805
+ else:
806
+ drain.queue.extendleft(reversed(first))
807
+ queue = drain.queue
808
+ if not queue:
809
+ break
810
+ fiber, nxt = queue.popleft()
811
+ finally:
812
+ _thread.drain = outer
813
+ # Only left over if a run raised (Ctrl-C): queue the rest, so no
814
+ # fiber is lost.
815
+ for fiber, nxt in [*(drain.first or ()), *(drain.queue or ())]:
816
+ fiber._scheduler.schedule(lambda f=fiber, n=nxt: f._drive(n))
817
+
818
+ def _drive_first(self, step: Step) -> None:
819
+ """Start this fiber now, nested in the running one (Effect's
820
+ ``startImmediately``); past ``_MAX_NESTED_RUNS`` nested runs, right
821
+ after the current run, before anything else queued."""
822
+ drain = _thread.drain
823
+ if (
824
+ drain is not None
825
+ and drain.run_scheduler is self._run_scheduler
826
+ and drain.depth >= _MAX_NESTED_RUNS
827
+ ):
828
+ drain.push_first((self, step))
829
+ else:
830
+ self._evaluate(step)
831
+
832
+ def _cancel_wait(self, wait: _Wait) -> Step:
833
+ """An interrupted fiber just parked: abandon the wait, unless another
834
+ thread resumed it meanwhile (that run then meets the interrupt at
835
+ its first step)."""
836
+ if not wait.claim():
837
+ return SUSPEND
838
+ return self._abandon_wait(wait)
839
+
840
+ def _abandon_wait(self, wait: _Wait) -> Step:
841
+ """Give up a claimed wait because of an interrupt. Returns the step
842
+ to continue with (the canceler, then the interrupt)."""
843
+ self._waiting = None
844
+ assert self._interrupt is not None
845
+ if wait.canceler is None:
846
+ return Failure(self._interrupt)
847
+ # Run the canceler uninterruptibly; restoring interruptibility
848
+ # afterwards makes the loop raise the interrupt.
849
+ self._push(_RestoreInterruptible(True))
850
+ self._interruptible = False
851
+ return wait.canceler
852
+
853
+
854
+ def _no_op() -> None:
855
+ pass
856
+
857
+
858
+ def _run_hooked(hook: ContextHook, cur: Effect[Any, Any, Any], fiber: Fiber[Any, Any]) -> Step:
859
+ step: Callable[[], Step] = partial(cur._step, fiber)
860
+ return hook(step, fiber)
861
+
862
+
863
+ def _hand_over(frame: Frame, ex: Exit[Any, Any], fiber: Fiber[Any, Any]) -> Step:
864
+ if isinstance(ex, Success):
865
+ return frame._on_success(ex.value, fiber)
866
+ return frame._on_failure(ex.cause, fiber)
867
+
868
+
869
+ class _RunScheduler(Tag[Scheduler]):
870
+ """The scheduler of the run a context was made in."""
871
+
872
+
873
+ @dataclass(frozen=True, slots=True)
874
+ class _RunView:
875
+ """What a fiber of the run on ``run_scheduler`` reads from ``given``.
876
+ Contexts are immutable, so the last one computed is kept for the next
877
+ fiber switching to the same context (every fork does)."""
878
+
879
+ given: Context
880
+ run_scheduler: Scheduler
881
+ context: Context
882
+ scheduler: Scheduler
883
+ ops_budget: float
884
+ should_yield: EffectScheduler | None
885
+ tracer_hook: ContextHook | None
886
+ runtime_metrics: FiberRuntimeMetricsService | None
887
+ stack_frame: StackFrame | None
888
+
889
+ @staticmethod
890
+ def of(given: Context, run_scheduler: Scheduler) -> _RunView:
891
+ context = given
892
+ if context.lookup(_RunScheduler)[1] is not run_scheduler:
893
+ context = _into_run(context, run_scheduler)
894
+ scheduler = context.lookup(CurrentScheduler)[1]
895
+ if isinstance(scheduler, BoundScheduler) and scheduler.run is not run_scheduler:
896
+ scheduler = scheduler.effect_scheduler
897
+ if isinstance(scheduler, EffectScheduler):
898
+ scheduler = BoundScheduler(scheduler, run_scheduler)
899
+ context = context.add(CurrentScheduler, scheduler)
900
+ should_yield = scheduler.effect_scheduler if isinstance(scheduler, BoundScheduler) else None
901
+ if context.lookup(PreventSchedulerYield)[1]:
902
+ budget = math.inf
903
+ should_yield = None
904
+ elif should_yield is not None:
905
+ budget = 0
906
+ else:
907
+ budget = max(1, context.lookup(MaxOpsBeforeYield)[1])
908
+ hook = context.lookup(CurrentTracer)[1].context
909
+ runtime_metrics = context.lookup(FiberRuntimeMetrics)[1]
910
+ frame = context.lookup(CurrentStackFrame)[1]
911
+ return _RunView(
912
+ given,
913
+ run_scheduler,
914
+ context,
915
+ scheduler,
916
+ budget,
917
+ should_yield,
918
+ hook,
919
+ runtime_metrics,
920
+ frame,
921
+ )
922
+
923
+
924
+ # One entry: the view the last fiber switch computed.
925
+ _last_view: list[_RunView | None] = [None]
926
+
927
+
928
+ def _into_run(context: Context, run_scheduler: Scheduler) -> Context:
929
+ """``context`` for a fiber of the run on ``run_scheduler``. A context
930
+ from another run (kept by a finalizer, say) keeps a scheduler it was
931
+ explicitly given, but not that run's own, which may no longer run."""
932
+ found, earlier = context.lookup(_RunScheduler)
933
+ in_run = context.add(_RunScheduler, run_scheduler)
934
+ if CurrentScheduler in context.tags():
935
+ given = context.lookup(CurrentScheduler)[1]
936
+ if not found or given is not earlier:
937
+ return in_run
938
+ return in_run.add(CurrentScheduler, run_scheduler)
939
+
940
+
941
+ def root_fiber(scheduler: Scheduler, context: Context) -> Fiber[Any, Any]:
942
+ """A fiber with no parent, running on ``scheduler`` unless an effect
943
+ provides another ``CurrentScheduler``."""
944
+ return Fiber(scheduler, context, None)
945
+
946
+
947
+ def interrupt_all(
948
+ fibers: list[Fiber[Any, Any]], by: int | None, annotations: Context | None
949
+ ) -> Effect[None, Never, Never]:
950
+ """Interrupt every fiber and wait for all of them to finish."""
951
+
952
+ def register(resume: Callable[[Effect[Any, Any, Any]], None]) -> None:
953
+ remaining = len(fibers)
954
+ if remaining == 0:
955
+ resume(_Succeed(None))
956
+ return
957
+
958
+ def observer(_: Exit[Any, Any]) -> None:
959
+ nonlocal remaining
960
+ remaining -= 1
961
+ if remaining == 0:
962
+ resume(_Succeed(None))
963
+
964
+ for f in fibers:
965
+ f.interrupt_as_unsafe(by, annotations)
966
+ for f in fibers:
967
+ f.add_observer_unsafe(observer)
968
+
969
+ return _Callback(register)