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.
- pyfect/__init__.py +729 -0
- pyfect/_all.py +242 -0
- pyfect/_background.py +28 -0
- pyfect/_binary_codecs.py +124 -0
- pyfect/_cached.py +165 -0
- pyfect/_catch.py +128 -0
- pyfect/_catch_reason.py +574 -0
- pyfect/_concurrency.py +291 -0
- pyfect/_context_effects.py +163 -0
- pyfect/_context_managers.py +76 -0
- pyfect/_core.py +368 -0
- pyfect/_digits.py +71 -0
- pyfect/_effect_args.py +46 -0
- pyfect/_effect_base.py +71 -0
- pyfect/_effect_concurrency.py +133 -0
- pyfect/_effect_eager.py +103 -0
- pyfect/_effect_errors.py +344 -0
- pyfect/_effect_folding.py +110 -0
- pyfect/_effect_hash.py +140 -0
- pyfect/_effect_logging.py +57 -0
- pyfect/_effect_metrics.py +102 -0
- pyfect/_effect_resources.py +179 -0
- pyfect/_effect_services.py +25 -0
- pyfect/_effect_timing.py +199 -0
- pyfect/_effect_tracing.py +99 -0
- pyfect/_equal.py +195 -0
- pyfect/_extras.py +43 -0
- pyfect/_fiber.py +969 -0
- pyfect/_fiber_all.py +134 -0
- pyfect/_fiber_collections.py +106 -0
- pyfect/_fn.py +706 -0
- pyfect/_hamt.py +174 -0
- pyfect/_interrupt_reason.py +33 -0
- pyfect/_isaac.py +149 -0
- pyfect/_iterables.py +231 -0
- pyfect/_js.py +263 -0
- pyfect/_js_date.py +87 -0
- pyfect/_json_text.py +286 -0
- pyfect/_json_value.py +9 -0
- pyfect/_layer_core.py +403 -0
- pyfect/_layer_for_life.py +33 -0
- pyfect/_layer_tracing.py +70 -0
- pyfect/_locked_ref.py +147 -0
- pyfect/_loop_thread.py +152 -0
- pyfect/_metric_ref.py +29 -0
- pyfect/_one_or_many.py +14 -0
- pyfect/_os_wait.py +118 -0
- pyfect/_path_posix.py +129 -0
- pyfect/_primitives.py +434 -0
- pyfect/_public.py +36 -0
- pyfect/_reasons.py +64 -0
- pyfect/_released.py +67 -0
- pyfect/_root.py +87 -0
- pyfect/_round_robin.py +73 -0
- pyfect/_some.py +17 -0
- pyfect/_stack.py +52 -0
- pyfect/_stack_frame.py +114 -0
- pyfect/_string_hash.py +35 -0
- pyfect/_subscriber_queue.py +47 -0
- pyfect/_tags.py +14 -0
- pyfect/_tracer_ref.py +21 -0
- pyfect/_tx_ops.py +77 -0
- pyfect/_unsubscripted.py +23 -0
- pyfect/_url.py +54 -0
- pyfect/_waiters.py +127 -0
- pyfect/_wake_tracking.py +98 -0
- pyfect/_wire_codec.py +123 -0
- pyfect/ai/__init__.py +73 -0
- pyfect/ai/_approvals.py +249 -0
- pyfect/ai/_decision_answers.py +185 -0
- pyfect/ai/_generated_client.py +298 -0
- pyfect/ai/_generated_support.py +84 -0
- pyfect/ai/_mcp/__init__.py +1 -0
- pyfect/ai/_mcp/batch.py +68 -0
- pyfect/ai/_mcp/client_transport.py +412 -0
- pyfect/ai/_mcp/client_wire.py +284 -0
- pyfect/ai/_mcp/core.py +490 -0
- pyfect/ai/_mcp/dispatch.py +1048 -0
- pyfect/ai/_mcp/http.py +462 -0
- pyfect/ai/_mcp/http_admission.py +269 -0
- pyfect/ai/_mcp/http_status.py +27 -0
- pyfect/ai/_mcp/input_wire.py +226 -0
- pyfect/ai/_mcp/log_levels.py +55 -0
- pyfect/ai/_mcp/param_headers.py +63 -0
- pyfect/ai/_mcp/projection.py +248 -0
- pyfect/ai/_mcp/register.py +683 -0
- pyfect/ai/_mcp/reverse_policy.py +155 -0
- pyfect/ai/_mcp/routing_header.py +24 -0
- pyfect/ai/_mcp/sessions.py +114 -0
- pyfect/ai/_mcp/stdio.py +110 -0
- pyfect/ai/_mcp/subscriptions.py +134 -0
- pyfect/ai/_mcp/tool_schema.py +35 -0
- pyfect/ai/_noul_answers.py +64 -0
- pyfect/ai/_openai_all_of.py +137 -0
- pyfect/ai/_openai_errors.py +233 -0
- pyfect/ai/_provider.py +439 -0
- pyfect/ai/_provider_tools.py +129 -0
- pyfect/ai/_stream_resolution.py +231 -0
- pyfect/ai/_structured_output_checks.py +138 -0
- pyfect/ai/_structured_output_codec.py +229 -0
- pyfect/ai/_structured_output_json.py +109 -0
- pyfect/ai/_tool_call_ids.py +80 -0
- pyfect/ai/ai_error.py +785 -0
- pyfect/ai/anthropic/__init__.py +28 -0
- pyfect/ai/anthropic/_errors.py +164 -0
- pyfect/ai/anthropic/_prompt.py +375 -0
- pyfect/ai/anthropic/_response.py +443 -0
- pyfect/ai/anthropic/_schema.py +206 -0
- pyfect/ai/anthropic/_stream.py +377 -0
- pyfect/ai/anthropic/_tools.py +248 -0
- pyfect/ai/anthropic/client.py +289 -0
- pyfect/ai/anthropic/config.py +32 -0
- pyfect/ai/anthropic/error.py +27 -0
- pyfect/ai/anthropic/language_model.py +366 -0
- pyfect/ai/anthropic/telemetry.py +51 -0
- pyfect/ai/anthropic/tool.py +570 -0
- pyfect/ai/anthropic_structured_output.py +138 -0
- pyfect/ai/chat.py +548 -0
- pyfect/ai/cloudflare/__init__.py +15 -0
- pyfect/ai/cloudflare/_errors.py +108 -0
- pyfect/ai/cloudflare/client.py +174 -0
- pyfect/ai/cloudflare/decision_model.py +117 -0
- pyfect/ai/cloudflare/schema.py +144 -0
- pyfect/ai/decision.py +290 -0
- pyfect/ai/decision_model.py +283 -0
- pyfect/ai/embedding_model.py +177 -0
- pyfect/ai/id_generator.py +79 -0
- pyfect/ai/language_model.py +1077 -0
- pyfect/ai/mcp_client.py +682 -0
- pyfect/ai/mcp_client_error.py +223 -0
- pyfect/ai/mcp_protocol.py +205 -0
- pyfect/ai/mcp_schema.py +1300 -0
- pyfect/ai/mcp_server.py +404 -0
- pyfect/ai/model.py +56 -0
- pyfect/ai/openai/__init__.py +49 -0
- pyfect/ai/openai/_errors.py +89 -0
- pyfect/ai/openai/_prompt.py +527 -0
- pyfect/ai/openai/_requests.py +34 -0
- pyfect/ai/openai/_response.py +569 -0
- pyfect/ai/openai/_schema.py +769 -0
- pyfect/ai/openai/_stream.py +771 -0
- pyfect/ai/openai/_tools.py +128 -0
- pyfect/ai/openai/_web_socket.py +295 -0
- pyfect/ai/openai/client.py +296 -0
- pyfect/ai/openai/client_generated.py +123 -0
- pyfect/ai/openai/config.py +34 -0
- pyfect/ai/openai/decision_model.py +177 -0
- pyfect/ai/openai/embedding_model.py +116 -0
- pyfect/ai/openai/error.py +8 -0
- pyfect/ai/openai/generated/__init__.py +7213 -0
- pyfect/ai/openai/generated/_recursive.py +18 -0
- pyfect/ai/openai/generated/_schemas_0.py +1015 -0
- pyfect/ai/openai/generated/_schemas_1.py +1016 -0
- pyfect/ai/openai/generated/_schemas_2.py +1017 -0
- pyfect/ai/openai/generated/_schemas_3.py +615 -0
- pyfect/ai/openai/generated/client.py +5298 -0
- pyfect/ai/openai/generated/types.py +8123 -0
- pyfect/ai/openai/language_model.py +304 -0
- pyfect/ai/openai/telemetry.py +19 -0
- pyfect/ai/openai/tool.py +391 -0
- pyfect/ai/openai_compat/__init__.py +25 -0
- pyfect/ai/openai_compat/_prompt.py +191 -0
- pyfect/ai/openai_compat/_request.py +153 -0
- pyfect/ai/openai_compat/_response.py +407 -0
- pyfect/ai/openai_compat/_schema.py +97 -0
- pyfect/ai/openai_compat/client.py +234 -0
- pyfect/ai/openai_compat/config.py +32 -0
- pyfect/ai/openai_compat/embedding_model.py +139 -0
- pyfect/ai/openai_compat/error.py +7 -0
- pyfect/ai/openai_compat/language_model.py +245 -0
- pyfect/ai/openai_compat/telemetry.py +51 -0
- pyfect/ai/openai_structured_output.py +118 -0
- pyfect/ai/openrouter/__init__.py +36 -0
- pyfect/ai/openrouter/_errors.py +186 -0
- pyfect/ai/openrouter/_prompt.py +272 -0
- pyfect/ai/openrouter/_response.py +226 -0
- pyfect/ai/openrouter/_stream.py +320 -0
- pyfect/ai/openrouter/client.py +283 -0
- pyfect/ai/openrouter/config.py +36 -0
- pyfect/ai/openrouter/decision_model.py +161 -0
- pyfect/ai/openrouter/error.py +23 -0
- pyfect/ai/openrouter/generated/__init__.py +3029 -0
- pyfect/ai/openrouter/generated/_recursive.py +15 -0
- pyfect/ai/openrouter/generated/_schemas_0.py +1015 -0
- pyfect/ai/openrouter/generated/_schemas_1.py +522 -0
- pyfect/ai/openrouter/generated/client.py +1445 -0
- pyfect/ai/openrouter/generated/types.py +4769 -0
- pyfect/ai/openrouter/language_model.py +345 -0
- pyfect/ai/openrouter/schema.py +165 -0
- pyfect/ai/prompt.py +664 -0
- pyfect/ai/response.py +768 -0
- pyfect/ai/response_id_tracker.py +82 -0
- pyfect/ai/telemetry.py +126 -0
- pyfect/ai/tokenizer.py +61 -0
- pyfect/ai/tool.py +536 -0
- pyfect/ai/toolkit.py +490 -0
- pyfect/ai/typesafe/__init__.py +17 -0
- pyfect/ai/typesafe/_errors.py +120 -0
- pyfect/ai/typesafe/client.py +146 -0
- pyfect/ai/typesafe/config.py +34 -0
- pyfect/ai/typesafe/decision_model.py +90 -0
- pyfect/ai/typesafe/schema.py +140 -0
- pyfect/batching/__init__.py +58 -0
- pyfect/batching/_api.py +71 -0
- pyfect/batching/_engine.py +229 -0
- pyfect/batching/_from_effect.py +76 -0
- pyfect/batching/_persisted.py +98 -0
- pyfect/batching/_request.py +133 -0
- pyfect/batching/_resolver.py +477 -0
- pyfect/batching/_with_cache.py +90 -0
- pyfect/big_decimal.py +500 -0
- pyfect/brand.py +114 -0
- pyfect/byte_size.py +354 -0
- pyfect/cache/__init__.py +29 -0
- pyfect/cache/_cache.py +426 -0
- pyfect/cache/_expiry.py +69 -0
- pyfect/cache/_scoped_cache.py +546 -0
- pyfect/case.py +174 -0
- pyfect/cause.py +462 -0
- pyfect/channel/__init__.py +155 -0
- pyfect/channel/_base.py +92 -0
- pyfect/channel/_catch.py +158 -0
- pyfect/channel/_catch_reason.py +572 -0
- pyfect/channel/_channel.py +158 -0
- pyfect/channel/_combinators.py +220 -0
- pyfect/channel/_concurrency_methods.py +217 -0
- pyfect/channel/_concurrent_map.py +118 -0
- pyfect/channel/_constructors.py +349 -0
- pyfect/channel/_context.py +232 -0
- pyfect/channel/_error_methods.py +336 -0
- pyfect/channel/_errors.py +180 -0
- pyfect/channel/_filters.py +225 -0
- pyfect/channel/_lifecycle.py +71 -0
- pyfect/channel/_lifecycle_methods.py +206 -0
- pyfect/channel/_loop.py +100 -0
- pyfect/channel/_merge.py +246 -0
- pyfect/channel/_repeat.py +154 -0
- pyfect/channel/_run.py +149 -0
- pyfect/channel/_run_methods.py +341 -0
- pyfect/channel/_sinks.py +88 -0
- pyfect/channel/_sources.py +238 -0
- pyfect/channel/_text.py +176 -0
- pyfect/channel/_transform_methods.py +415 -0
- pyfect/channel/_upstream.py +67 -0
- pyfect/channel_schema.py +131 -0
- pyfect/cli/__init__.py +79 -0
- pyfect/cli/_ansi.py +82 -0
- pyfect/cli/_command.py +469 -0
- pyfect/cli/_config.py +164 -0
- pyfect/cli/_environment.py +10 -0
- pyfect/cli/_help.py +195 -0
- pyfect/cli/_lexer.py +81 -0
- pyfect/cli/_parser.py +465 -0
- pyfect/cli/_settings.py +85 -0
- pyfect/cli/_suggest.py +33 -0
- pyfect/cli/_width.py +134 -0
- pyfect/cli/_wizard.py +317 -0
- pyfect/cli/argument.py +212 -0
- pyfect/cli/cli_config.py +40 -0
- pyfect/cli/cli_error.py +242 -0
- pyfect/cli/cli_output.py +305 -0
- pyfect/cli/command.py +440 -0
- pyfect/cli/completions/__init__.py +50 -0
- pyfect/cli/completions/_completer.ps1 +190 -0
- pyfect/cli/completions/_descriptor.py +182 -0
- pyfect/cli/completions/bash.py +300 -0
- pyfect/cli/completions/fish.py +164 -0
- pyfect/cli/completions/powershell.py +156 -0
- pyfect/cli/completions/zsh.py +189 -0
- pyfect/cli/flag.py +246 -0
- pyfect/cli/global_flag.py +99 -0
- pyfect/cli/help_doc.py +63 -0
- pyfect/cli/param.py +789 -0
- pyfect/cli/primitive.py +308 -0
- pyfect/cli/prompt/__init__.py +75 -0
- pyfect/cli/prompt/_auto_complete.py +205 -0
- pyfect/cli/prompt/_choices.py +104 -0
- pyfect/cli/prompt/_confirm.py +195 -0
- pyfect/cli/prompt/_core.py +512 -0
- pyfect/cli/prompt/_date.py +173 -0
- pyfect/cli/prompt/_date_parts.py +387 -0
- pyfect/cli/prompt/_file.py +372 -0
- pyfect/cli/prompt/_multi_select.py +204 -0
- pyfect/cli/prompt/_number.py +257 -0
- pyfect/cli/prompt/_select.py +117 -0
- pyfect/cli/prompt/_text.py +239 -0
- pyfect/cli/terminal_capabilities.py +118 -0
- pyfect/clock.py +150 -0
- pyfect/cluster/__init__.py +155 -0
- pyfect/cluster/_cluster_abandon.py +36 -0
- pyfect/cluster/_cluster_layer.py +122 -0
- pyfect/cluster/_entity_activation.py +16 -0
- pyfect/cluster/_entity_manager/__init__.py +22 -0
- pyfect/cluster/_entity_manager/_activation.py +540 -0
- pyfect/cluster/_entity_manager/_core.py +186 -0
- pyfect/cluster/_entity_manager/_decode.py +60 -0
- pyfect/cluster/_entity_manager/_manager.py +423 -0
- pyfect/cluster/_entity_manager/_state.py +113 -0
- pyfect/cluster/_entity_reaper.py +94 -0
- pyfect/cluster/_hash.py +13 -0
- pyfect/cluster/_interruptors.py +88 -0
- pyfect/cluster/_resource_map.py +179 -0
- pyfect/cluster/_resource_ref.py +266 -0
- pyfect/cluster/_shard_lock.py +14 -0
- pyfect/cluster/cluster_cron.py +230 -0
- pyfect/cluster/cluster_error.py +81 -0
- pyfect/cluster/cluster_http.py +210 -0
- pyfect/cluster/cluster_metrics.py +54 -0
- pyfect/cluster/cluster_schema.py +137 -0
- pyfect/cluster/cluster_socket.py +197 -0
- pyfect/cluster/cluster_workflow_engine/__init__.py +24 -0
- pyfect/cluster/cluster_workflow_engine/_engine.py +1099 -0
- pyfect/cluster/cluster_workflow_engine/_entities.py +298 -0
- pyfect/cluster/deliver_at.py +31 -0
- pyfect/cluster/entity/__init__.py +39 -0
- pyfect/cluster/entity/_entity.py +332 -0
- pyfect/cluster/entity/_handlers.py +168 -0
- pyfect/cluster/entity/_keep_alive.py +74 -0
- pyfect/cluster/entity/_queue.py +103 -0
- pyfect/cluster/entity/_request.py +34 -0
- pyfect/cluster/entity/_services.py +23 -0
- pyfect/cluster/entity/_test_client.py +237 -0
- pyfect/cluster/entity_address.py +25 -0
- pyfect/cluster/entity_id.py +20 -0
- pyfect/cluster/entity_proxy.py +161 -0
- pyfect/cluster/entity_proxy_server.py +103 -0
- pyfect/cluster/entity_resource.py +122 -0
- pyfect/cluster/entity_type.py +20 -0
- pyfect/cluster/envelope.py +307 -0
- pyfect/cluster/http_runner.py +254 -0
- pyfect/cluster/k8s_http_client.py +281 -0
- pyfect/cluster/k8s_types.py +1394 -0
- pyfect/cluster/machine_id.py +21 -0
- pyfect/cluster/message.py +219 -0
- pyfect/cluster/message_storage/__init__.py +67 -0
- pyfect/cluster/message_storage/_encoded.py +393 -0
- pyfect/cluster/message_storage/_memory.py +386 -0
- pyfect/cluster/message_storage/_noop.py +109 -0
- pyfect/cluster/message_storage/_service.py +388 -0
- pyfect/cluster/reply.py +236 -0
- pyfect/cluster/runner.py +32 -0
- pyfect/cluster/runner_address.py +23 -0
- pyfect/cluster/runner_health.py +93 -0
- pyfect/cluster/runner_server.py +286 -0
- pyfect/cluster/runner_storage.py +212 -0
- pyfect/cluster/runners/__init__.py +55 -0
- pyfect/cluster/runners/_local.py +460 -0
- pyfect/cluster/runners/_noop.py +57 -0
- pyfect/cluster/runners/_rpc.py +290 -0
- pyfect/cluster/runners/_service.py +113 -0
- pyfect/cluster/shard_id.py +39 -0
- pyfect/cluster/sharding/__init__.py +12 -0
- pyfect/cluster/sharding/_acquisition.py +490 -0
- pyfect/cluster/sharding/_clients.py +271 -0
- pyfect/cluster/sharding/_make.py +388 -0
- pyfect/cluster/sharding/_routing.py +296 -0
- pyfect/cluster/sharding/_runners_sync.py +198 -0
- pyfect/cluster/sharding/_service.py +91 -0
- pyfect/cluster/sharding/_singletons.py +183 -0
- pyfect/cluster/sharding/_state.py +296 -0
- pyfect/cluster/sharding/_storage_loop.py +421 -0
- pyfect/cluster/sharding_config.py +230 -0
- pyfect/cluster/sharding_registration_event.py +28 -0
- pyfect/cluster/single_runner.py +49 -0
- pyfect/cluster/singleton.py +36 -0
- pyfect/cluster/singleton_address.py +20 -0
- pyfect/cluster/snowflake.py +133 -0
- pyfect/cluster/socket_runner.py +67 -0
- pyfect/cluster/sql_message_storage.py +1001 -0
- pyfect/cluster/sql_runner_storage.py +841 -0
- pyfect/cluster/test_runner.py +23 -0
- pyfect/config/__init__.py +93 -0
- pyfect/config/_all.py +96 -0
- pyfect/config/_collections.py +291 -0
- pyfect/config/_config.py +261 -0
- pyfect/config/_constructors.py +106 -0
- pyfect/config/_error.py +27 -0
- pyfect/config/_leaf.py +92 -0
- pyfect/config/_scalars.py +193 -0
- pyfect/config/_schema.py +340 -0
- pyfect/config_provider/__init__.py +60 -0
- pyfect/config_provider/_dir.py +84 -0
- pyfect/config_provider/_dotenv.py +127 -0
- pyfect/config_provider/_env.py +79 -0
- pyfect/config_provider/_layers.py +80 -0
- pyfect/config_provider/_node.py +90 -0
- pyfect/config_provider/_provider.py +118 -0
- pyfect/config_provider/_unknown.py +62 -0
- pyfect/console/__init__.py +63 -0
- pyfect/console/_effects.py +134 -0
- pyfect/console/_live.py +156 -0
- pyfect/console/_service.py +49 -0
- pyfect/console/_table.py +90 -0
- pyfect/context.py +414 -0
- pyfect/cron/__init__.py +30 -0
- pyfect/cron/_model.py +183 -0
- pyfect/cron/_search.py +268 -0
- pyfect/cron/_text.py +202 -0
- pyfect/cron/_wall.py +42 -0
- pyfect/crypto.py +257 -0
- pyfect/date_time/__init__.py +77 -0
- pyfect/date_time/_calendar.py +209 -0
- pyfect/date_time/_current.py +118 -0
- pyfect/date_time/_epoch.py +22 -0
- pyfect/date_time/_iso.py +80 -0
- pyfect/date_time/_zones.py +135 -0
- pyfect/date_time/intl.py +144 -0
- pyfect/deferred.py +145 -0
- pyfect/devtools/__init__.py +24 -0
- pyfect/devtools/client.py +323 -0
- pyfect/devtools/layers.py +32 -0
- pyfect/devtools/schema.py +301 -0
- pyfect/devtools/server.py +72 -0
- pyfect/duration.py +295 -0
- pyfect/effect.py +565 -0
- pyfect/effectable.py +37 -0
- pyfect/encoding/__init__.py +62 -0
- pyfect/encoding/_archive.py +197 -0
- pyfect/encoding/_json_array_scanner.py +477 -0
- pyfect/encoding/base64.py +23 -0
- pyfect/encoding/base64_url.py +19 -0
- pyfect/encoding/encoding_error.py +17 -0
- pyfect/encoding/hex.py +28 -0
- pyfect/encoding/ini.py +188 -0
- pyfect/encoding/json_array.py +246 -0
- pyfect/encoding/ndjson.py +461 -0
- pyfect/encoding/schema_binary/__init__.py +257 -0
- pyfect/encoding/schema_binary/_channels.py +173 -0
- pyfect/encoding/schema_binary/_compile.py +584 -0
- pyfect/encoding/schema_binary/_decode.py +848 -0
- pyfect/encoding/schema_binary/_dictionary.py +90 -0
- pyfect/encoding/schema_binary/_encode.py +838 -0
- pyfect/encoding/schema_binary/_fingerprint.py +168 -0
- pyfect/encoding/schema_binary/_layout.py +350 -0
- pyfect/encoding/schema_binary/_literals.py +47 -0
- pyfect/encoding/schema_binary/_parser.py +163 -0
- pyfect/encoding/schema_binary/_reader.py +148 -0
- pyfect/encoding/schema_binary/_target.py +310 -0
- pyfect/encoding/schema_binary/_values.py +133 -0
- pyfect/encoding/schema_binary/_wire.py +253 -0
- pyfect/encoding/sse.py +476 -0
- pyfect/encoding/tar/__init__.py +396 -0
- pyfect/encoding/tar/_decoder.py +220 -0
- pyfect/encoding/tar/_encoder.py +83 -0
- pyfect/encoding/tar/_header.py +494 -0
- pyfect/encoding/tar/_model.py +82 -0
- pyfect/encoding/toml.py +375 -0
- pyfect/encoding/xml/__init__.py +222 -0
- pyfect/encoding/xml/_chars.py +119 -0
- pyfect/encoding/xml/_collector.py +106 -0
- pyfect/encoding/xml/_inputs.py +126 -0
- pyfect/encoding/xml/_model.py +114 -0
- pyfect/encoding/xml/_parser.py +694 -0
- pyfect/encoding/xml/_scanner.py +180 -0
- pyfect/encoding/xml/_writer.py +238 -0
- pyfect/encoding/yaml.py +739 -0
- pyfect/encoding/zip/__init__.py +392 -0
- pyfect/encoding/zip/_decoder.py +378 -0
- pyfect/encoding/zip/_format.py +122 -0
- pyfect/encoding/zip/_inflate.py +65 -0
- pyfect/encoding/zip/_model.py +86 -0
- pyfect/encoding/zip/_writer.py +311 -0
- pyfect/error_reporter.py +240 -0
- pyfect/errors.py +321 -0
- pyfect/eventlog/__init__.py +77 -0
- pyfect/eventlog/_conflicts.py +94 -0
- pyfect/eventlog/_crypto.py +64 -0
- pyfect/eventlog/_identity.py +26 -0
- pyfect/eventlog/_identity_derivation.py +79 -0
- pyfect/eventlog/_transferable_bytes.py +55 -0
- pyfect/eventlog/_uuid.py +33 -0
- pyfect/eventlog/event.py +115 -0
- pyfect/eventlog/event_group.py +55 -0
- pyfect/eventlog/event_journal.py +630 -0
- pyfect/eventlog/event_log.py +1039 -0
- pyfect/eventlog/event_log_encryption.py +219 -0
- pyfect/eventlog/event_log_message.py +357 -0
- pyfect/eventlog/event_log_remote.py +465 -0
- pyfect/eventlog/event_log_server.py +442 -0
- pyfect/eventlog/event_log_server_encrypted.py +322 -0
- pyfect/eventlog/event_log_server_unencrypted.py +814 -0
- pyfect/eventlog/event_log_session_auth.py +250 -0
- pyfect/eventlog/event_row.py +423 -0
- pyfect/eventlog/sql_event_journal.py +692 -0
- pyfect/eventlog/sql_event_log_server_encrypted.py +440 -0
- pyfect/eventlog/sql_event_log_server_unencrypted.py +568 -0
- pyfect/execution_plan/__init__.py +42 -0
- pyfect/execution_plan/_events.py +128 -0
- pyfect/execution_plan/_model.py +108 -0
- pyfect/execution_plan/_run.py +176 -0
- pyfect/exit.py +205 -0
- pyfect/fiber_handle.py +305 -0
- pyfect/fiber_map.py +350 -0
- pyfect/fiber_set.py +232 -0
- pyfect/file_system/__init__.py +69 -0
- pyfect/file_system/_copy.py +116 -0
- pyfect/file_system/_errors.py +32 -0
- pyfect/file_system/_file.py +177 -0
- pyfect/file_system/_live.py +351 -0
- pyfect/file_system/_model.py +72 -0
- pyfect/file_system/_noop.py +189 -0
- pyfect/file_system/_service.py +336 -0
- pyfect/file_system/_stat.py +69 -0
- pyfect/file_system/_watch.py +107 -0
- pyfect/filters.py +245 -0
- pyfect/graph/__init__.py +101 -0
- pyfect/graph/_all_pairs.py +150 -0
- pyfect/graph/_combine.py +259 -0
- pyfect/graph/_compact.py +143 -0
- pyfect/graph/_components.py +200 -0
- pyfect/graph/_cycles.py +144 -0
- pyfect/graph/_enumerate.py +168 -0
- pyfect/graph/_errors.py +51 -0
- pyfect/graph/_flow.py +164 -0
- pyfect/graph/_forest.py +109 -0
- pyfect/graph/_graph.py +269 -0
- pyfect/graph/_lowlink.py +98 -0
- pyfect/graph/_matching.py +101 -0
- pyfect/graph/_mutate.py +211 -0
- pyfect/graph/_query.py +138 -0
- pyfect/graph/_records.py +119 -0
- pyfect/graph/_render.py +109 -0
- pyfect/graph/_shortest.py +274 -0
- pyfect/graph/_snapshot.py +50 -0
- pyfect/graph/_store.py +136 -0
- pyfect/graph/_traverse.py +289 -0
- pyfect/graph/_view.py +384 -0
- pyfect/graph/_walker.py +70 -0
- pyfect/graphql/__init__.py +87 -0
- pyfect/graphql/_codec.py +117 -0
- pyfect/graphql/_http.py +309 -0
- pyfect/graphql/_schemas.py +39 -0
- pyfect/graphql/_slices.py +110 -0
- pyfect/graphql/_template.py +111 -0
- pyfect/graphql/_types.py +115 -0
- pyfect/graphql/_ws.py +395 -0
- pyfect/graphql/_ws_messages.py +120 -0
- pyfect/graphql/client.py +428 -0
- pyfect/graphql/client_error.py +285 -0
- pyfect/graphql/group.py +142 -0
- pyfect/graphql/middleware.py +98 -0
- pyfect/graphql/operation.py +409 -0
- pyfect/graphql/protocol.py +119 -0
- pyfect/graphql/resolver.py +574 -0
- pyfect/graphql/template.py +61 -0
- pyfect/hash_map.py +317 -0
- pyfect/hash_ring.py +206 -0
- pyfect/hash_set.py +163 -0
- pyfect/http/__init__.py +125 -0
- pyfect/http/_asgi_listener.py +272 -0
- pyfect/http/_authority.py +63 -0
- pyfect/http/_brotli.py +27 -0
- pyfect/http/_compression.py +52 -0
- pyfect/http/_field.py +18 -0
- pyfect/http/_foreign_path.py +27 -0
- pyfect/http/_form_data.py +34 -0
- pyfect/http/_httpx_options.py +120 -0
- pyfect/http/_in_memory.py +76 -0
- pyfect/http/_request_state.py +59 -0
- pyfect/http/_vary.py +14 -0
- pyfect/http/abort.py +65 -0
- pyfect/http/asgi/__init__.py +59 -0
- pyfect/http/asgi/_app.py +155 -0
- pyfect/http/asgi/_http.py +201 -0
- pyfect/http/asgi/_mount.py +263 -0
- pyfect/http/asgi/_scope.py +86 -0
- pyfect/http/asgi/_serve.py +72 -0
- pyfect/http/asgi/_types.py +13 -0
- pyfect/http/asgi/_web_socket.py +325 -0
- pyfect/http/body.py +437 -0
- pyfect/http/client/__init__.py +111 -0
- pyfect/http/client/_circuit_breaker.py +113 -0
- pyfect/http/client/_cookie_jar.py +120 -0
- pyfect/http/client/_make.py +252 -0
- pyfect/http/client/_rate_limit.py +423 -0
- pyfect/http/client/_redirects.py +93 -0
- pyfect/http/client/_retry.py +115 -0
- pyfect/http/client/_service.py +497 -0
- pyfect/http/cookies.py +444 -0
- pyfect/http/error.py +188 -0
- pyfect/http/etag.py +96 -0
- pyfect/http/file_like.py +49 -0
- pyfect/http/find_my_way/__init__.py +10 -0
- pyfect/http/find_my_way/_nodes.py +186 -0
- pyfect/http/find_my_way/_paths.py +43 -0
- pyfect/http/find_my_way/_query_string.py +67 -0
- pyfect/http/find_my_way/_router.py +401 -0
- pyfect/http/headers.py +343 -0
- pyfect/http/http_effect.py +198 -0
- pyfect/http/httpx_client.py +291 -0
- pyfect/http/hypercorn_server.py +122 -0
- pyfect/http/incoming_message.py +140 -0
- pyfect/http/live_server/__init__.py +191 -0
- pyfect/http/live_server/_body.py +164 -0
- pyfect/http/live_server/_exchange.py +321 -0
- pyfect/http/live_server/_head.py +194 -0
- pyfect/http/live_server/_inbound.py +156 -0
- pyfect/http/live_server/_listener.py +211 -0
- pyfect/http/live_server/_serve.py +225 -0
- pyfect/http/live_server/_timers.py +20 -0
- pyfect/http/live_server/_upgrade.py +108 -0
- pyfect/http/live_server/_websocket.py +286 -0
- pyfect/http/live_server/_ws_frames.py +242 -0
- pyfect/http/method.py +30 -0
- pyfect/http/middleware/__init__.py +61 -0
- pyfect/http/middleware/_compression.py +156 -0
- pyfect/http/middleware/_cors.py +129 -0
- pyfect/http/middleware/_decompression.py +274 -0
- pyfect/http/middleware/_forwarded.py +113 -0
- pyfect/http/middleware/_logger.py +73 -0
- pyfect/http/middleware/_search_params.py +34 -0
- pyfect/http/middleware/_tracer.py +153 -0
- pyfect/http/middleware/_types.py +16 -0
- pyfect/http/mime/__init__.py +69 -0
- pyfect/http/mime/_types.py +361 -0
- pyfect/http/multipart.py +613 -0
- pyfect/http/multipart_parser/__init__.py +348 -0
- pyfect/http/multipart_parser/_content_type.py +109 -0
- pyfect/http/multipart_parser/_headers.py +206 -0
- pyfect/http/multipart_parser/_search.py +85 -0
- pyfect/http/origin.py +146 -0
- pyfect/http/platform.py +593 -0
- pyfect/http/prometheus.py +34 -0
- pyfect/http/request.py +384 -0
- pyfect/http/response.py +474 -0
- pyfect/http/router/__init__.py +82 -0
- pyfect/http/router/_api.py +462 -0
- pyfect/http/router/_in_memory.py +76 -0
- pyfect/http/router/_markers.py +47 -0
- pyfect/http/router/_middleware.py +181 -0
- pyfect/http/router/_middleware_stack.py +51 -0
- pyfect/http/router/_provided.py +31 -0
- pyfect/http/router/_route.py +114 -0
- pyfect/http/router/_router.py +308 -0
- pyfect/http/schema.py +276 -0
- pyfect/http/server.py +199 -0
- pyfect/http/server_error.py +261 -0
- pyfect/http/server_request.py +729 -0
- pyfect/http/server_respondable.py +77 -0
- pyfect/http/server_response.py +569 -0
- pyfect/http/static_server/__init__.py +257 -0
- pyfect/http/static_server/_conditional.py +72 -0
- pyfect/http/static_server/_mime.py +55 -0
- pyfect/http/static_server/_range.py +53 -0
- pyfect/http/status.py +51 -0
- pyfect/http/template.py +161 -0
- pyfect/http/trace_context.py +91 -0
- pyfect/http/url.py +442 -0
- pyfect/http/url_params.py +304 -0
- pyfect/http/uvicorn_server.py +119 -0
- pyfect/http/web.py +171 -0
- pyfect/http/web_handler.py +463 -0
- pyfect/http/wire.py +209 -0
- pyfect/http_api/__init__.py +83 -0
- pyfect/http_api/_assets/scalar.js +8 -0
- pyfect/http_api/_assets/swagger-ui.css +3 -0
- pyfect/http_api/_assets/swagger-ui.js +4 -0
- pyfect/http_api/_client_method.py +220 -0
- pyfect/http_api/_client_payload.py +144 -0
- pyfect/http_api/_client_response.py +377 -0
- pyfect/http_api/_handlers.py +282 -0
- pyfect/http_api/_html.py +38 -0
- pyfect/http_api/_media_type.py +6 -0
- pyfect/http_api/_openapi_responses.py +164 -0
- pyfect/http_api/_openapi_schemas.py +163 -0
- pyfect/http_api/_path.py +102 -0
- pyfect/http_api/_payload.py +260 -0
- pyfect/http_api/_response.py +363 -0
- pyfect/http_api/_security.py +174 -0
- pyfect/http_api/api.py +265 -0
- pyfect/http_api/builder.py +447 -0
- pyfect/http_api/client.py +474 -0
- pyfect/http_api/endpoint.py +969 -0
- pyfect/http_api/error.py +280 -0
- pyfect/http_api/group.py +215 -0
- pyfect/http_api/middleware.py +232 -0
- pyfect/http_api/openapi.py +396 -0
- pyfect/http_api/scalar.py +143 -0
- pyfect/http_api/schema.py +713 -0
- pyfect/http_api/security.py +91 -0
- pyfect/http_api/swagger.py +69 -0
- pyfect/http_api/test.py +105 -0
- pyfect/json_patch.py +255 -0
- pyfect/json_pointer.py +100 -0
- pyfect/json_schema/__init__.py +66 -0
- pyfect/json_schema/_api.py +96 -0
- pyfect/json_schema/_converter.py +258 -0
- pyfect/json_schema/_draft04.py +198 -0
- pyfect/json_schema/_draft07.py +203 -0
- pyfect/json_schema/_keywords.py +202 -0
- pyfect/json_schema/_model.py +201 -0
- pyfect/json_schema/_openapi.py +208 -0
- pyfect/latch.py +127 -0
- pyfect/layer.py +479 -0
- pyfect/layer_map.py +279 -0
- pyfect/layer_ref.py +208 -0
- pyfect/logger/__init__.py +91 -0
- pyfect/logger/_batched.py +49 -0
- pyfect/logger/_console.py +116 -0
- pyfect/logger/_file.py +31 -0
- pyfect/logger/_formats.py +104 -0
- pyfect/logger/_layer.py +50 -0
- pyfect/logger/_level.py +53 -0
- pyfect/logger/_log.py +142 -0
- pyfect/logger/_model.py +163 -0
- pyfect/logger/_refs.py +78 -0
- pyfect/logger/_stdlib.py +54 -0
- pyfect/logger/_text.py +263 -0
- pyfect/logger/_tracer.py +35 -0
- pyfect/managed_runtime.py +393 -0
- pyfect/metric/__init__.py +119 -0
- pyfect/metric/_boundaries.py +27 -0
- pyfect/metric/_kinds.py +417 -0
- pyfect/metric/_metric.py +302 -0
- pyfect/metric/_prometheus.py +150 -0
- pyfect/metric/_refs.py +78 -0
- pyfect/metric/_runtime.py +75 -0
- pyfect/metric/_snapshot.py +97 -0
- pyfect/metric/_state.py +74 -0
- pyfect/msgspec.py +98 -0
- pyfect/mutable_hash_map.py +140 -0
- pyfect/mutable_hash_set.py +95 -0
- pyfect/net/__init__.py +18 -0
- pyfect/net/_errors.py +29 -0
- pyfect/net/address_resolver.py +179 -0
- pyfect/net/dns/__init__.py +92 -0
- pyfect/net/dns/_error.py +43 -0
- pyfect/net/dns/_records.py +335 -0
- pyfect/net/dns/_service.py +287 -0
- pyfect/net/dns/_system.py +89 -0
- pyfect/net/host.py +311 -0
- pyfect/net/ip_interface.py +202 -0
- pyfect/net/ip_network.py +250 -0
- pyfect/net/net_address/__init__.py +245 -0
- pyfect/net/net_address/_inet.py +412 -0
- pyfect/net/net_address/_ip.py +348 -0
- pyfect/net/net_address/_mac.py +119 -0
- pyfect/optic/__init__.py +50 -0
- pyfect/optic/_builtins.py +90 -0
- pyfect/optic/_data.py +97 -0
- pyfect/optic/_optic.py +422 -0
- pyfect/optic/_steps.py +151 -0
- pyfect/option.py +362 -0
- pyfect/otel/__init__.py +22 -0
- pyfect/otel/_attributes.py +67 -0
- pyfect/otel/_producer.py +322 -0
- pyfect/otel/_shutdown.py +26 -0
- pyfect/otel/_span.py +292 -0
- pyfect/otel/_wrapper.py +92 -0
- pyfect/otel/logger.py +154 -0
- pyfect/otel/metrics.py +126 -0
- pyfect/otel/resource.py +111 -0
- pyfect/otel/sdk.py +195 -0
- pyfect/otel/tracer.py +157 -0
- pyfect/partitioned_semaphore.py +211 -0
- pyfect/path.py +304 -0
- pyfect/persistence/__init__.py +77 -0
- pyfect/persistence/_columns.py +32 -0
- pyfect/persistence/_error.py +14 -0
- pyfect/persistence/_seconds.py +68 -0
- pyfect/persistence/_sql_keys.py +47 -0
- pyfect/persistence/circuit_breaker/__init__.py +120 -0
- pyfect/persistence/circuit_breaker/_breaker.py +317 -0
- pyfect/persistence/circuit_breaker/_errors.py +67 -0
- pyfect/persistence/circuit_breaker/_memory.py +243 -0
- pyfect/persistence/circuit_breaker/_redis.py +509 -0
- pyfect/persistence/circuit_breaker/_store.py +60 -0
- pyfect/persistence/circuit_breaker/_types.py +191 -0
- pyfect/persistence/key_value_store/__init__.py +51 -0
- pyfect/persistence/key_value_store/_layers.py +216 -0
- pyfect/persistence/key_value_store/_schema_store.py +91 -0
- pyfect/persistence/key_value_store/_sql.py +197 -0
- pyfect/persistence/key_value_store/_store.py +212 -0
- pyfect/persistence/persistable.py +164 -0
- pyfect/persistence/persisted_cache.py +159 -0
- pyfect/persistence/persisted_queue/__init__.py +75 -0
- pyfect/persistence/persisted_queue/_error.py +42 -0
- pyfect/persistence/persisted_queue/_mailbox.py +101 -0
- pyfect/persistence/persisted_queue/_memory.py +182 -0
- pyfect/persistence/persisted_queue/_queue.py +272 -0
- pyfect/persistence/persisted_queue/_redis.py +455 -0
- pyfect/persistence/persisted_queue/_redis_scripts.py +395 -0
- pyfect/persistence/persisted_queue/_sql.py +334 -0
- pyfect/persistence/persisted_queue/_sql_migrations.py +319 -0
- pyfect/persistence/persisted_queue/_sql_statements.py +441 -0
- pyfect/persistence/persisted_queue/_store.py +147 -0
- pyfect/persistence/persistence/__init__.py +84 -0
- pyfect/persistence/persistence/_kvs.py +135 -0
- pyfect/persistence/persistence/_memory.py +62 -0
- pyfect/persistence/persistence/_redis.py +162 -0
- pyfect/persistence/persistence/_service.py +276 -0
- pyfect/persistence/persistence/_sql.py +499 -0
- pyfect/persistence/rate_limiter/__init__.py +82 -0
- pyfect/persistence/rate_limiter/_errors.py +59 -0
- pyfect/persistence/rate_limiter/_limiter.py +325 -0
- pyfect/persistence/rate_limiter/_memory.py +217 -0
- pyfect/persistence/rate_limiter/_redis.py +485 -0
- pyfect/persistence/rate_limiter/_store.py +89 -0
- pyfect/persistence/redis/__init__.py +52 -0
- pyfect/persistence/redis/_error.py +12 -0
- pyfect/persistence/redis/_make.py +234 -0
- pyfect/persistence/redis/_script.py +78 -0
- pyfect/persistence/redis/_service.py +104 -0
- pyfect/persistence/redis_py.py +303 -0
- pyfect/persistence/user_directories.py +195 -0
- pyfect/platform.py +26 -0
- pyfect/platform_error.py +256 -0
- pyfect/pool/__init__.py +36 -0
- pyfect/pool/_pool.py +707 -0
- pyfect/pool/_state.py +161 -0
- pyfect/pool/_ttl.py +105 -0
- pyfect/pool/_waiters.py +116 -0
- pyfect/primary_key.py +35 -0
- pyfect/process/__init__.py +82 -0
- pyfect/process/_child.py +213 -0
- pyfect/process/_command.py +358 -0
- pyfect/process/_handle.py +77 -0
- pyfect/process/_live.py +455 -0
- pyfect/process/_os.py +78 -0
- pyfect/process/_pipes.py +291 -0
- pyfect/process/_spawner.py +75 -0
- pyfect/pubsub/__init__.py +33 -0
- pyfect/pubsub/_atomic.py +181 -0
- pyfect/pubsub/_hub.py +214 -0
- pyfect/pubsub/_pubsub.py +214 -0
- pyfect/pubsub/_replay.py +107 -0
- pyfect/pubsub/_subscription.py +226 -0
- pyfect/pull.py +132 -0
- pyfect/py.typed +0 -0
- pyfect/pydantic.py +188 -0
- pyfect/queue/__init__.py +33 -0
- pyfect/queue/_queue.py +525 -0
- pyfect/queue/_state.py +111 -0
- pyfect/queue/_views.py +55 -0
- pyfect/random.py +146 -0
- pyfect/rc_map.py +363 -0
- pyfect/rc_ref.py +271 -0
- pyfect/reactivity/__init__.py +53 -0
- pyfect/reactivity/_async_result_schema.py +227 -0
- pyfect/reactivity/_hydration.py +18 -0
- pyfect/reactivity/_live.py +21 -0
- pyfect/reactivity/_reactivity.py +256 -0
- pyfect/reactivity/_result_effect.py +17 -0
- pyfect/reactivity/_time.py +11 -0
- pyfect/reactivity/async_result.py +679 -0
- pyfect/reactivity/atom/__init__.py +143 -0
- pyfect/reactivity/atom/_combinators.py +223 -0
- pyfect/reactivity/atom/_constructors.py +80 -0
- pyfect/reactivity/atom/_conversions.py +79 -0
- pyfect/reactivity/atom/_effect.py +252 -0
- pyfect/reactivity/atom/_fn.py +341 -0
- pyfect/reactivity/atom/_kvs.py +101 -0
- pyfect/reactivity/atom/_optimistic.py +162 -0
- pyfect/reactivity/atom/_runtime.py +323 -0
- pyfect/reactivity/atom/_serializable.py +65 -0
- pyfect/reactivity/atom/_subscription_ref.py +102 -0
- pyfect/reactivity/atom/_swr.py +69 -0
- pyfect/reactivity/atom/_types.py +435 -0
- pyfect/reactivity/atom_http_api.py +667 -0
- pyfect/reactivity/atom_ref.py +260 -0
- pyfect/reactivity/atom_registry/__init__.py +219 -0
- pyfect/reactivity/atom_registry/_batch.py +96 -0
- pyfect/reactivity/atom_registry/_dispatcher.py +60 -0
- pyfect/reactivity/atom_registry/_lifetime.py +202 -0
- pyfect/reactivity/atom_registry/_node.py +423 -0
- pyfect/reactivity/atom_registry/_registry.py +380 -0
- pyfect/reactivity/atom_rpc.py +283 -0
- pyfect/reactivity/hydration.py +200 -0
- pyfect/redacted.py +83 -0
- pyfect/ref.py +129 -0
- pyfect/resource.py +98 -0
- pyfect/result.py +306 -0
- pyfect/rpc/__init__.py +64 -0
- pyfect/rpc/_encoded_schema.py +86 -0
- pyfect/rpc/_json_rpc.py +246 -0
- pyfect/rpc/_methods.py +177 -0
- pyfect/rpc/_rpc.py +498 -0
- pyfect/rpc/client/__init__.py +100 -0
- pyfect/rpc/client/_core.py +449 -0
- pyfect/rpc/client/_http.py +257 -0
- pyfect/rpc/client/_protocol.py +171 -0
- pyfect/rpc/client/_serialized.py +321 -0
- pyfect/rpc/client/_transports.py +328 -0
- pyfect/rpc/client/_worker.py +283 -0
- pyfect/rpc/client_error.py +35 -0
- pyfect/rpc/group.py +296 -0
- pyfect/rpc/message.py +299 -0
- pyfect/rpc/middleware.py +182 -0
- pyfect/rpc/schema.py +89 -0
- pyfect/rpc/serialization.py +366 -0
- pyfect/rpc/server/__init__.py +181 -0
- pyfect/rpc/server/_core.py +549 -0
- pyfect/rpc/server/_protocol.py +123 -0
- pyfect/rpc/server/_serialized.py +363 -0
- pyfect/rpc/server/_stdio.py +101 -0
- pyfect/rpc/server/_transports.py +427 -0
- pyfect/rpc/server/_worker.py +108 -0
- pyfect/rpc/test.py +74 -0
- pyfect/rpc/worker.py +92 -0
- pyfect/run.py +393 -0
- pyfect/schedule/__init__.py +91 -0
- pyfect/schedule/_combinators.py +168 -0
- pyfect/schedule/_constructors.py +223 -0
- pyfect/schedule/_cron.py +49 -0
- pyfect/schedule/_drive.py +191 -0
- pyfect/schedule/_model.py +405 -0
- pyfect/scheduler.py +575 -0
- pyfect/schema/__init__.py +866 -0
- pyfect/schema/_adapters.py +39 -0
- pyfect/schema/_arbitrary_constraint.py +242 -0
- pyfect/schema/_arbitrary_graph.py +325 -0
- pyfect/schema/_arbitrary_links.py +179 -0
- pyfect/schema/_arbitrary_number.py +112 -0
- pyfect/schema/_arrays.py +287 -0
- pyfect/schema/_assignable.py +118 -0
- pyfect/schema/_boolean_literals.py +31 -0
- pyfect/schema/_checks_number.py +216 -0
- pyfect/schema/_checks_order.py +140 -0
- pyfect/schema/_checks_size.py +277 -0
- pyfect/schema/_checks_string.py +241 -0
- pyfect/schema/_class.py +569 -0
- pyfect/schema/_codec_derivation.py +227 -0
- pyfect/schema/_codec_links.py +221 -0
- pyfect/schema/_codecs.py +316 -0
- pyfect/schema/_collections.py +172 -0
- pyfect/schema/_constructor_default.py +89 -0
- pyfect/schema/_data.py +440 -0
- pyfect/schema/_data_codecs.py +145 -0
- pyfect/schema/_decimal_regexp.py +243 -0
- pyfect/schema/_declare.py +68 -0
- pyfect/schema/_derive.py +292 -0
- pyfect/schema/_duration_codecs.py +27 -0
- pyfect/schema/_ecma_pattern.py +416 -0
- pyfect/schema/_error.py +26 -0
- pyfect/schema/_error_instance.py +222 -0
- pyfect/schema/_graph.py +271 -0
- pyfect/schema/_instances.py +240 -0
- pyfect/schema/_jsonschema/__init__.py +90 -0
- pyfect/schema/_jsonschema/_annotations.py +114 -0
- pyfect/schema/_jsonschema/_checks.py +253 -0
- pyfect/schema/_jsonschema/_compile.py +346 -0
- pyfect/schema/_jsonschema/_exact.py +19 -0
- pyfect/schema/_jsonschema/_merge.py +211 -0
- pyfect/schema/_jsonschema/_objects.py +231 -0
- pyfect/schema/_jsonschema/_references.py +221 -0
- pyfect/schema/_jsonschema/_template.py +69 -0
- pyfect/schema/_literals.py +147 -0
- pyfect/schema/_middleware.py +209 -0
- pyfect/schema/_net.py +522 -0
- pyfect/schema/_options.py +49 -0
- pyfect/schema/_parse.py +351 -0
- pyfect/schema/_parsed_text.py +37 -0
- pyfect/schema/_primitives.py +48 -0
- pyfect/schema/_record.py +41 -0
- pyfect/schema/_refine.py +81 -0
- pyfect/schema/_schema.py +158 -0
- pyfect/schema/_semver.py +144 -0
- pyfect/schema/_strategy/__init__.py +258 -0
- pyfect/schema/_strategy/_big_decimal.py +203 -0
- pyfect/schema/_strategy/_composites.py +119 -0
- pyfect/schema/_strategy/_leaves.py +94 -0
- pyfect/schema/_strategy/_net.py +133 -0
- pyfect/schema/_struct.py +87 -0
- pyfect/schema/_struct_keys.py +128 -0
- pyfect/schema/_tagged.py +254 -0
- pyfect/schema/_template_literal.py +172 -0
- pyfect/schema/_to_codec_array_from_single.py +115 -0
- pyfect/schema/_to_codec_go_json.py +174 -0
- pyfect/schema/_to_codec_json.py +73 -0
- pyfect/schema/_to_codec_string_tree.py +115 -0
- pyfect/schema/_to_differ_json_patch.py +44 -0
- pyfect/schema/_to_encoder_xml.py +119 -0
- pyfect/schema/_to_equivalence.py +186 -0
- pyfect/schema/_to_formatter.py +180 -0
- pyfect/schema/_to_iso.py +73 -0
- pyfect/schema/_to_strategy.py +31 -0
- pyfect/schema/_transform.py +210 -0
- pyfect/schema/_tree.py +27 -0
- pyfect/schema/_type_walk.py +53 -0
- pyfect/schema/_undefined.py +58 -0
- pyfect/schema/_value_codecs.py +84 -0
- pyfect/schema/_values.py +123 -0
- pyfect/schema/_void.py +86 -0
- pyfect/schema/ast/__init__.py +227 -0
- pyfect/schema/ast/_annotations.py +43 -0
- pyfect/schema/ast/_arrays.py +210 -0
- pyfect/schema/ast/_base.py +295 -0
- pyfect/schema/ast/_candidates.py +309 -0
- pyfect/schema/ast/_check.py +181 -0
- pyfect/schema/ast/_class.py +159 -0
- pyfect/schema/ast/_constructors.py +65 -0
- pyfect/schema/ast/_declaration.py +97 -0
- pyfect/schema/ast/_encoding.py +111 -0
- pyfect/schema/ast/_json.py +129 -0
- pyfect/schema/ast/_keywords.py +125 -0
- pyfect/schema/ast/_literal.py +157 -0
- pyfect/schema/ast/_objects.py +356 -0
- pyfect/schema/ast/_record.py +36 -0
- pyfect/schema/ast/_result.py +116 -0
- pyfect/schema/ast/_steps.py +209 -0
- pyfect/schema/ast/_suspend.py +65 -0
- pyfect/schema/ast/_template_literal.py +256 -0
- pyfect/schema/ast/_union.py +172 -0
- pyfect/schema/getter/__init__.py +136 -0
- pyfect/schema/getter/_binary.py +104 -0
- pyfect/schema/getter/_coerce.py +196 -0
- pyfect/schema/getter/_getter.py +243 -0
- pyfect/schema/getter/_make.py +151 -0
- pyfect/schema/getter/_text.py +141 -0
- pyfect/schema/getter/_tree_record.py +170 -0
- pyfect/schema/issue.py +420 -0
- pyfect/schema/model/__init__.py +120 -0
- pyfect/schema/model/_class.py +245 -0
- pyfect/schema/model/_dates.py +103 -0
- pyfect/schema/model/_fields.py +77 -0
- pyfect/schema/model/_toolkit.py +114 -0
- pyfect/schema/model/_uuid.py +69 -0
- pyfect/schema/representation/__init__.py +424 -0
- pyfect/schema/representation/_builtin_revivers.py +331 -0
- pyfect/schema/representation/_code.py +106 -0
- pyfect/schema/representation/_code_builtins.py +281 -0
- pyfect/schema/representation/_code_document.py +563 -0
- pyfect/schema/representation/_code_sort.py +111 -0
- pyfect/schema/representation/_from.py +278 -0
- pyfect/schema/representation/_import/__init__.py +78 -0
- pyfect/schema/representation/_import/_finalize.py +121 -0
- pyfect/schema/representation/_import/_intersect.py +467 -0
- pyfect/schema/representation/_import/_js_order.py +66 -0
- pyfect/schema/representation/_import/_keywords.py +224 -0
- pyfect/schema/representation/_import/_nodes.py +199 -0
- pyfect/schema/representation/_import/_translate.py +455 -0
- pyfect/schema/representation/_json.py +520 -0
- pyfect/schema/representation/_json_schema.py +178 -0
- pyfect/schema/representation/_model.py +284 -0
- pyfect/schema/representation/_revivers.py +89 -0
- pyfect/schema/representation/_to.py +249 -0
- pyfect/schema/transformation/__init__.py +99 -0
- pyfect/schema/transformation/_builtins.py +314 -0
- pyfect/schema/transformation/_durations.py +150 -0
- pyfect/schema/transformation/_transformation.py +177 -0
- pyfect/schema/variant_schema/__init__.py +69 -0
- pyfect/schema/variant_schema/_class.py +188 -0
- pyfect/schema/variant_schema/_defaults.py +30 -0
- pyfect/schema/variant_schema/_field.py +32 -0
- pyfect/schema/variant_schema/_struct.py +130 -0
- pyfect/schema/variant_schema/_toolkit.py +160 -0
- pyfect/scope.py +374 -0
- pyfect/scoped_ref.py +124 -0
- pyfect/semaphore.py +276 -0
- pyfect/semver.py +403 -0
- pyfect/semver_range.py +420 -0
- pyfect/sink/__init__.py +131 -0
- pyfect/sink/_combinators.py +151 -0
- pyfect/sink/_constructors.py +187 -0
- pyfect/sink/_context.py +87 -0
- pyfect/sink/_folds.py +336 -0
- pyfect/sink/_for_each.py +87 -0
- pyfect/sink/_sink.py +265 -0
- pyfect/sink/_steps.py +34 -0
- pyfect/sink/_taking.py +183 -0
- pyfect/socket/__init__.py +146 -0
- pyfect/socket/_accepted.py +65 -0
- pyfect/socket/_connection.py +384 -0
- pyfect/socket/_errors.py +135 -0
- pyfect/socket/_loop.py +66 -0
- pyfect/socket/_net.py +281 -0
- pyfect/socket/_socket.py +245 -0
- pyfect/socket/_tls.py +88 -0
- pyfect/socket/_tls_session.py +117 -0
- pyfect/socket/_web_socket.py +555 -0
- pyfect/socket/datagram/__init__.py +110 -0
- pyfect/socket/datagram/_core.py +460 -0
- pyfect/socket/datagram/_errors.py +102 -0
- pyfect/socket/datagram/_live.py +675 -0
- pyfect/socket/datagram/_model.py +217 -0
- pyfect/socket/server.py +258 -0
- pyfect/socket/ws.py +484 -0
- pyfect/sql/__init__.py +60 -0
- pyfect/sql/_loop.py +134 -0
- pyfect/sql/clickhouse/__init__.py +74 -0
- pyfect/sql/clickhouse/_connection.py +237 -0
- pyfect/sql/clickhouse/_rows.py +87 -0
- pyfect/sql/clickhouse/client.py +322 -0
- pyfect/sql/clickhouse/config.py +241 -0
- pyfect/sql/clickhouse/driver.py +434 -0
- pyfect/sql/clickhouse/error.py +106 -0
- pyfect/sql/clickhouse/migrator.py +47 -0
- pyfect/sql/clickhouse/params.py +168 -0
- pyfect/sql/client/__init__.py +35 -0
- pyfect/sql/client/_client.py +309 -0
- pyfect/sql/client/_sqlite_acquirers.py +130 -0
- pyfect/sql/client/_transaction.py +410 -0
- pyfect/sql/connection.py +87 -0
- pyfect/sql/d1/__init__.py +48 -0
- pyfect/sql/d1/api.py +270 -0
- pyfect/sql/d1/client.py +344 -0
- pyfect/sql/d1/config.py +55 -0
- pyfect/sql/error.py +311 -0
- pyfect/sql/libsql/__init__.py +58 -0
- pyfect/sql/libsql/_connection.py +110 -0
- pyfect/sql/libsql/_hrana.py +258 -0
- pyfect/sql/libsql/_local.py +251 -0
- pyfect/sql/libsql/_targets.py +28 -0
- pyfect/sql/libsql/_values.py +46 -0
- pyfect/sql/libsql/client.py +225 -0
- pyfect/sql/libsql/config.py +170 -0
- pyfect/sql/libsql/migrator.py +43 -0
- pyfect/sql/libsql/sdk.py +123 -0
- pyfect/sql/migrator.py +434 -0
- pyfect/sql/model.py +324 -0
- pyfect/sql/mssql/__init__.py +79 -0
- pyfect/sql/mssql/_connection.py +169 -0
- pyfect/sql/mssql/_driver.py +103 -0
- pyfect/sql/mssql/_names.py +9 -0
- pyfect/sql/mssql/_pool.py +125 -0
- pyfect/sql/mssql/_tds.py +447 -0
- pyfect/sql/mssql/_tds_params.py +155 -0
- pyfect/sql/mssql/_worker.py +155 -0
- pyfect/sql/mssql/client.py +344 -0
- pyfect/sql/mssql/config.py +118 -0
- pyfect/sql/mssql/error.py +111 -0
- pyfect/sql/mssql/migrator.py +43 -0
- pyfect/sql/mssql/parameter.py +44 -0
- pyfect/sql/mssql/procedure.py +119 -0
- pyfect/sql/mssql/types.py +137 -0
- pyfect/sql/mysql/__init__.py +60 -0
- pyfect/sql/mysql/_asyncmy.py +168 -0
- pyfect/sql/mysql/_bind.py +76 -0
- pyfect/sql/mysql/_connection.py +156 -0
- pyfect/sql/mysql/_pool.py +63 -0
- pyfect/sql/mysql/_session.py +262 -0
- pyfect/sql/mysql/client.py +244 -0
- pyfect/sql/mysql/config.py +108 -0
- pyfect/sql/mysql/error.py +104 -0
- pyfect/sql/mysql/migrator.py +44 -0
- pyfect/sql/pg/__init__.py +82 -0
- pyfect/sql/pg/_resolve.py +284 -0
- pyfect/sql/pg/_session.py +380 -0
- pyfect/sql/pg/client.py +398 -0
- pyfect/sql/pg/config.py +142 -0
- pyfect/sql/pg/connection.py +585 -0
- pyfect/sql/pg/error.py +131 -0
- pyfect/sql/pg/migrator.py +139 -0
- pyfect/sql/pg/pool.py +265 -0
- pyfect/sql/resolver.py +294 -0
- pyfect/sql/result.py +24 -0
- pyfect/sql/schema.py +116 -0
- pyfect/sql/sqlite/__init__.py +26 -0
- pyfect/sql/sqlite/_connection.py +230 -0
- pyfect/sql/sqlite/_worker.py +71 -0
- pyfect/sql/sqlite/client.py +248 -0
- pyfect/sql/sqlite/migrator.py +43 -0
- pyfect/sql/statement/__init__.py +144 -0
- pyfect/sql/statement/_compiler.py +384 -0
- pyfect/sql/statement/_segments.py +487 -0
- pyfect/sql/statement/_statement.py +526 -0
- pyfect/sql/statement/_transforms.py +93 -0
- pyfect/sql/stream.py +88 -0
- pyfect/stdio.py +206 -0
- pyfect/stream/__init__.py +151 -0
- pyfect/stream/_async_iterable.py +129 -0
- pyfect/stream/_base.py +69 -0
- pyfect/stream/_bridge_methods.py +139 -0
- pyfect/stream/_catch.py +135 -0
- pyfect/stream/_catch_reason.py +558 -0
- pyfect/stream/_channel_methods.py +61 -0
- pyfect/stream/_chunk_methods.py +169 -0
- pyfect/stream/_chunking.py +310 -0
- pyfect/stream/_concat.py +65 -0
- pyfect/stream/_constructors.py +341 -0
- pyfect/stream/_context.py +147 -0
- pyfect/stream/_error_methods.py +254 -0
- pyfect/stream/_execution_plan.py +199 -0
- pyfect/stream/_fanout.py +154 -0
- pyfect/stream/_fanout_methods.py +183 -0
- pyfect/stream/_filter_methods.py +203 -0
- pyfect/stream/_grouping.py +168 -0
- pyfect/stream/_many.py +65 -0
- pyfect/stream/_map_methods.py +233 -0
- pyfect/stream/_mapping.py +126 -0
- pyfect/stream/_run.py +114 -0
- pyfect/stream/_run_methods.py +114 -0
- pyfect/stream/_service_methods.py +36 -0
- pyfect/stream/_sink_methods.py +151 -0
- pyfect/stream/_sinking.py +277 -0
- pyfect/stream/_sources.py +124 -0
- pyfect/stream/_stream.py +162 -0
- pyfect/stream/_taking.py +330 -0
- pyfect/stream/_text.py +43 -0
- pyfect/stream/_timing.py +294 -0
- pyfect/stream/_timing_methods.py +252 -0
- pyfect/stream/_zip_methods.py +279 -0
- pyfect/stream/_zipping.py +213 -0
- pyfect/subscription_ref.py +66 -0
- pyfect/synchronized_ref.py +38 -0
- pyfect/take.py +36 -0
- pyfect/terminal/__init__.py +41 -0
- pyfect/terminal/_keys.py +113 -0
- pyfect/terminal/_live.py +223 -0
- pyfect/terminal/_service.py +73 -0
- pyfect/testing/__init__.py +122 -0
- pyfect/testing/_assertions.py +92 -0
- pyfect/testing/_clock.py +309 -0
- pyfect/testing/_console.py +164 -0
- pyfect/testing/_crypto.py +44 -0
- pyfect/testing/_decorators.py +211 -0
- pyfect/testing/_flaky.py +34 -0
- pyfect/testing/_layers.py +153 -0
- pyfect/testing/_prop.py +255 -0
- pyfect/testing/_runners.py +84 -0
- pyfect/testing/_runtime.py +174 -0
- pyfect/testing/_schema.py +238 -0
- pyfect/testing/plugin.py +59 -0
- pyfect/tracer/__init__.py +107 -0
- pyfect/tracer/_model.py +176 -0
- pyfect/tracer/_native.py +172 -0
- pyfect/tracer/_refs.py +87 -0
- pyfect/tracer/_spans.py +269 -0
- pyfect/transaction.py +340 -0
- pyfect/trie.py +317 -0
- pyfect/tx_chunk.py +127 -0
- pyfect/tx_deferred.py +75 -0
- pyfect/tx_hash_map.py +265 -0
- pyfect/tx_hash_set.py +151 -0
- pyfect/tx_priority_queue.py +224 -0
- pyfect/tx_pubsub.py +194 -0
- pyfect/tx_queue/__init__.py +27 -0
- pyfect/tx_queue/_queue.py +359 -0
- pyfect/tx_queue/_views.py +60 -0
- pyfect/tx_reentrant_lock.py +201 -0
- pyfect/tx_ref.py +79 -0
- pyfect/tx_semaphore.py +136 -0
- pyfect/tx_subscription_ref.py +118 -0
- pyfect/workers/__init__.py +62 -0
- pyfect/workers/_frames.py +82 -0
- pyfect/workers/_mailbox.py +51 -0
- pyfect/workers/_port.py +106 -0
- pyfect/workers/_process.py +155 -0
- pyfect/workers/_thread.py +100 -0
- pyfect/workers/python_worker.py +133 -0
- pyfect/workers/python_worker_runner.py +112 -0
- pyfect/workers/transferable.py +103 -0
- pyfect/workers/worker.py +273 -0
- pyfect/workers/worker_error.py +86 -0
- pyfect/workers/worker_runner.py +85 -0
- pyfect/workflow/__init__.py +78 -0
- pyfect/workflow/_crypto.py +23 -0
- pyfect/workflow/_encoded.py +381 -0
- pyfect/workflow/_memory.py +424 -0
- pyfect/workflow/_result.py +43 -0
- pyfect/workflow/_services.py +241 -0
- pyfect/workflow/_suspension.py +153 -0
- pyfect/workflow/activity.py +427 -0
- pyfect/workflow/durable_clock.py +72 -0
- pyfect/workflow/durable_deferred.py +403 -0
- pyfect/workflow/durable_queue.py +259 -0
- pyfect/workflow/workflow.py +509 -0
- pyfect/workflow/workflow_engine.py +42 -0
- pyfect/workflow/workflow_proxy.py +161 -0
- pyfect/workflow/workflow_proxy_server.py +146 -0
- pyfect_dev-0.1.0.dist-info/METADATA +296 -0
- pyfect_dev-0.1.0.dist-info/RECORD +1265 -0
- pyfect_dev-0.1.0.dist-info/WHEEL +4 -0
- pyfect_dev-0.1.0.dist-info/entry_points.txt +3 -0
- pyfect_dev-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"""``Subscription[A]``: one subscriber's view of a ``PubSub``.
|
|
2
|
+
|
|
3
|
+
A subscription reads its replayed messages first, then what was published
|
|
4
|
+
after it subscribed. Once the hub has ended, a subscription that has read
|
|
5
|
+
everything gets the final message from every ``take`` (``take_up_to`` never
|
|
6
|
+
waits, so it gets nothing). Once unsubscribed (its scope closed, or the hub
|
|
7
|
+
shut down), every take is interrupted, but for one already woken with a
|
|
8
|
+
message, which gets it (Effect runs that take before the unsubscribe).
|
|
9
|
+
|
|
10
|
+
The subscription only gives ``A``s, so it is covariant (Effect's ``out
|
|
11
|
+
A``): its state is kept as ``Any`` and typed by the methods, and batches
|
|
12
|
+
are typed ``Sequence`` (they are lists).
|
|
13
|
+
"""
|
|
14
|
+
# pyright: reportPrivateUsage=false
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from collections.abc import Callable, Generator, Sequence
|
|
19
|
+
from typing import TYPE_CHECKING, Any, Never, cast
|
|
20
|
+
|
|
21
|
+
from pyfect._core import (
|
|
22
|
+
Effect,
|
|
23
|
+
Frame,
|
|
24
|
+
Step,
|
|
25
|
+
_Callback,
|
|
26
|
+
_FailCause,
|
|
27
|
+
_Gen,
|
|
28
|
+
_Succeed,
|
|
29
|
+
_Suspend,
|
|
30
|
+
_Sync,
|
|
31
|
+
_WithFiber,
|
|
32
|
+
)
|
|
33
|
+
from pyfect.cause import Cause
|
|
34
|
+
from pyfect.cause import interrupt as interrupt_cause
|
|
35
|
+
from pyfect.exit import Failure, Success
|
|
36
|
+
from pyfect.pubsub._hub import Hub, Reader, Ticket
|
|
37
|
+
|
|
38
|
+
if TYPE_CHECKING:
|
|
39
|
+
from pyfect._fiber import Fiber
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _identity[T](value: T) -> T:
|
|
43
|
+
return value
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _interrupt() -> Effect[Never]:
|
|
47
|
+
return _WithFiber(lambda fiber: _FailCause(interrupt_cause(fiber.id)))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class Subscription[A]:
|
|
51
|
+
__slots__ = ("_hub", "_reader")
|
|
52
|
+
|
|
53
|
+
def __init__(self, hub: Hub[Any], reader: Reader[Any]) -> None:
|
|
54
|
+
self._hub = hub
|
|
55
|
+
self._reader = reader
|
|
56
|
+
|
|
57
|
+
def take(self) -> Effect[A]:
|
|
58
|
+
"""Wait for the next message."""
|
|
59
|
+
reader = self._reader
|
|
60
|
+
hub = self._hub
|
|
61
|
+
|
|
62
|
+
def attempt() -> Effect[A]:
|
|
63
|
+
if reader.unsubscribed:
|
|
64
|
+
return _interrupt()
|
|
65
|
+
replayed = reader.replay.take()
|
|
66
|
+
if replayed is not None:
|
|
67
|
+
return _Succeed(replayed.value)
|
|
68
|
+
polled = reader.read_up_to(1)
|
|
69
|
+
if polled:
|
|
70
|
+
hub.deliver()
|
|
71
|
+
return _Succeed(polled[0])
|
|
72
|
+
if hub.ended is not None:
|
|
73
|
+
return _Succeed(hub.ended.value)
|
|
74
|
+
return self._park(_identity, attempt)
|
|
75
|
+
|
|
76
|
+
return _Suspend(attempt)
|
|
77
|
+
|
|
78
|
+
def take_all(self) -> Effect[Sequence[A]]:
|
|
79
|
+
"""Wait for at least one message, then take every one there is."""
|
|
80
|
+
reader = self._reader
|
|
81
|
+
hub = self._hub
|
|
82
|
+
|
|
83
|
+
def more(first: A) -> list[A]:
|
|
84
|
+
rest = reader.read_up_to(reader.size())
|
|
85
|
+
hub.deliver()
|
|
86
|
+
return [first, *rest]
|
|
87
|
+
|
|
88
|
+
def attempt() -> Effect[list[A]]:
|
|
89
|
+
if reader.unsubscribed:
|
|
90
|
+
return _interrupt()
|
|
91
|
+
polled = reader.read_up_to(reader.size())
|
|
92
|
+
hub.deliver()
|
|
93
|
+
if reader.replay.remaining:
|
|
94
|
+
return _Succeed(reader.replay.take_all() + polled)
|
|
95
|
+
if polled:
|
|
96
|
+
return _Succeed(polled)
|
|
97
|
+
if hub.ended is not None:
|
|
98
|
+
return _Succeed([hub.ended.value])
|
|
99
|
+
return self._park(more, attempt)
|
|
100
|
+
|
|
101
|
+
return _Suspend(attempt)
|
|
102
|
+
|
|
103
|
+
def take_up_to(self, n: int) -> Effect[Sequence[A]]:
|
|
104
|
+
"""Take up to ``n`` messages without waiting (none if ``n`` is 0 or
|
|
105
|
+
less, or while other takes wait)."""
|
|
106
|
+
reader = self._reader
|
|
107
|
+
|
|
108
|
+
def attempt() -> Effect[list[A]]:
|
|
109
|
+
if reader.unsubscribed:
|
|
110
|
+
return _interrupt()
|
|
111
|
+
limit = max(n, 0)
|
|
112
|
+
if reader.replay.remaining >= limit:
|
|
113
|
+
return _Succeed(reader.replay.take_n(limit))
|
|
114
|
+
replayed = reader.replay.take_all()
|
|
115
|
+
polled = reader.read_up_to(limit - len(replayed))
|
|
116
|
+
self._hub.deliver()
|
|
117
|
+
return _Succeed(replayed + polled)
|
|
118
|
+
|
|
119
|
+
return _Suspend(attempt)
|
|
120
|
+
|
|
121
|
+
def take_between(self, minimum: int, maximum: int) -> Effect[Sequence[A]]:
|
|
122
|
+
"""Take at least ``minimum`` and at most ``maximum`` messages, waiting
|
|
123
|
+
for the minimum. Nothing, at once, if ``maximum < minimum``."""
|
|
124
|
+
|
|
125
|
+
def body() -> Generator[Effect[Any], Any, list[A]]:
|
|
126
|
+
low, high = max(minimum, 0), max(maximum, 0)
|
|
127
|
+
out: list[A] = []
|
|
128
|
+
while high >= low:
|
|
129
|
+
taken: Sequence[A] = yield self.take_up_to(high)
|
|
130
|
+
out.extend(taken)
|
|
131
|
+
missing = low - len(taken)
|
|
132
|
+
if missing <= 0:
|
|
133
|
+
break
|
|
134
|
+
out.append((yield self.take()))
|
|
135
|
+
low, high = missing - 1, high - len(taken) - 1
|
|
136
|
+
if low == 0:
|
|
137
|
+
break
|
|
138
|
+
return out
|
|
139
|
+
|
|
140
|
+
return _Gen(body)
|
|
141
|
+
|
|
142
|
+
def remaining(self) -> Effect[int]:
|
|
143
|
+
"""How many messages there are to take now."""
|
|
144
|
+
|
|
145
|
+
def attempt() -> Effect[int]:
|
|
146
|
+
count = self.remaining_unsafe()
|
|
147
|
+
return _interrupt() if count is None else _Succeed(count)
|
|
148
|
+
|
|
149
|
+
return _Suspend(attempt)
|
|
150
|
+
|
|
151
|
+
def remaining_unsafe(self) -> int | None:
|
|
152
|
+
"""``remaining`` now; ``None`` once unsubscribed."""
|
|
153
|
+
reader = self._reader
|
|
154
|
+
if reader.unsubscribed:
|
|
155
|
+
return None
|
|
156
|
+
return reader.size() + reader.replay.remaining
|
|
157
|
+
|
|
158
|
+
def _park[X](self, then: Callable[[A], X], again: Callable[[], Effect[X]]) -> Effect[X]:
|
|
159
|
+
"""Wait behind the takes already waiting. Woken with a message, end
|
|
160
|
+
with ``then(message)``; woken without one (the hub ended or the
|
|
161
|
+
subscription closed), look again with ``again()``. A take waiting
|
|
162
|
+
when the subscription closes is interrupted by the closing fiber, as
|
|
163
|
+
in Effect."""
|
|
164
|
+
reader = self._reader
|
|
165
|
+
hub = self._hub
|
|
166
|
+
ticket = Ticket(_ignore)
|
|
167
|
+
|
|
168
|
+
def register(resume: Callable[[Effect[None]], None]) -> Effect[None] | None:
|
|
169
|
+
if reader.unsubscribed or hub.ended is not None:
|
|
170
|
+
resume(_VOID)
|
|
171
|
+
return None
|
|
172
|
+
ticket.wake = lambda: resume(_VOID)
|
|
173
|
+
reader.waiting.append(ticket)
|
|
174
|
+
hub.deliver()
|
|
175
|
+
return _Sync(lambda: reader.discard(ticket))
|
|
176
|
+
|
|
177
|
+
def run(fiber: Fiber[Any, Any]) -> Effect[None]:
|
|
178
|
+
fiber._push(_Collect(hub, reader, ticket, then, again))
|
|
179
|
+
return _Callback(register)
|
|
180
|
+
|
|
181
|
+
return cast("Effect[X]", _WithFiber(run))
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
_VOID: Effect[None] = _Succeed(None)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _ignore() -> None:
|
|
188
|
+
pass
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class _Collect[A, X](Frame):
|
|
192
|
+
"""Below a parked take. Woken with a message, collect it in this same
|
|
193
|
+
step, so no interrupt can land between collecting and returning it.
|
|
194
|
+
Failing before that (interrupted while parked, or woken and interrupted
|
|
195
|
+
before collecting), leave the message to the next take."""
|
|
196
|
+
|
|
197
|
+
__slots__ = ("again", "hub", "reader", "then", "ticket")
|
|
198
|
+
# Collecting claims the message; it reaches the caller with no pause.
|
|
199
|
+
claims = True
|
|
200
|
+
|
|
201
|
+
def __init__(
|
|
202
|
+
self,
|
|
203
|
+
hub: Hub[A],
|
|
204
|
+
reader: Reader[A],
|
|
205
|
+
ticket: Ticket,
|
|
206
|
+
then: Callable[[A], X],
|
|
207
|
+
again: Callable[[], Effect[X]],
|
|
208
|
+
) -> None:
|
|
209
|
+
self.hub = hub
|
|
210
|
+
self.reader = reader
|
|
211
|
+
self.ticket = ticket
|
|
212
|
+
self.then = then
|
|
213
|
+
self.again = again
|
|
214
|
+
|
|
215
|
+
def _on_success(self, value: Any, fiber: Fiber[Any, Any]) -> Step:
|
|
216
|
+
reader = self.reader
|
|
217
|
+
if self.ticket.claimed:
|
|
218
|
+
return Success(self.then(reader.collect(self.ticket)))
|
|
219
|
+
if reader.unsubscribed:
|
|
220
|
+
return Failure(interrupt_cause(reader.closed_by))
|
|
221
|
+
return self.again()
|
|
222
|
+
|
|
223
|
+
def _on_failure(self, cause: Cause[Any], fiber: Fiber[Any, Any]) -> Step:
|
|
224
|
+
if self.reader.release(self.ticket):
|
|
225
|
+
self.hub.deliver()
|
|
226
|
+
return Failure(cause)
|
pyfect/pull.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""``Pull[A, E, L, R]``: one step of a pull-based producer (Effect's ``Pull``).
|
|
2
|
+
|
|
3
|
+
A pull is an effect that succeeds with the next item, fails with an ordinary
|
|
4
|
+
error ``E``, or fails with ``Done(leftover)`` when the producer has finished
|
|
5
|
+
normally. Keeping the end in the error channel lets a consumer tell normal
|
|
6
|
+
completion from failure while every effect combinator still applies::
|
|
7
|
+
|
|
8
|
+
item = yield from pull # Done(...) ends the surrounding loop
|
|
9
|
+
|
|
10
|
+
``filter_done`` and the helpers here separate ``Done`` from real failures:
|
|
11
|
+
``catch_done`` and ``match_effect`` handle it, ``done_exit_from_cause``
|
|
12
|
+
turns a cause into the producer's final ``Exit``.
|
|
13
|
+
|
|
14
|
+
Pyright cannot subtract ``Done`` from an error union, so the functions that
|
|
15
|
+
take ``Done`` out of a type are data-first (``catch_done(pull, f)``): their
|
|
16
|
+
overloads read ``E | Done[L]`` off the pull itself.
|
|
17
|
+
"""
|
|
18
|
+
# pyright: reportPrivateUsage=false
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from collections.abc import Callable
|
|
23
|
+
from typing import Any, Never, TypeIs, overload
|
|
24
|
+
|
|
25
|
+
from pyfect._core import Effect, _FailCause, _MatchCause
|
|
26
|
+
from pyfect._effect_args import require_effect
|
|
27
|
+
from pyfect.cause import Cause, Fail, Reason
|
|
28
|
+
from pyfect.errors import Done, _is_done, filter_done
|
|
29
|
+
from pyfect.exit import Exit, Failure, Success
|
|
30
|
+
from pyfect.result import Err, Ok, Result
|
|
31
|
+
|
|
32
|
+
type Pull[A, E = Never, L = None, R = Never] = Effect[A, E | Done[L], R]
|
|
33
|
+
"""An effect producing one ``A``, failing with ``E``, or ending with
|
|
34
|
+
``Done[L]``."""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def is_done_failure(reason: Reason[object]) -> TypeIs[Fail[Done[Any]]]:
|
|
38
|
+
"""Whether ``reason`` is a ``Fail`` holding a ``Done``."""
|
|
39
|
+
return _is_done(reason)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def is_done_cause(cause: Cause[object]) -> bool:
|
|
43
|
+
"""Whether ``cause`` holds any ``Done`` failure."""
|
|
44
|
+
return any(_is_done(r) for r in cause.reasons)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def filter_no_done[E](cause: Cause[E]) -> Result[Cause[E], Cause[E]]:
|
|
48
|
+
"""``Ok(cause)`` when it holds no ``Done`` failure, else ``Err(cause)``."""
|
|
49
|
+
return Err(cause) if is_done_cause(cause) else Ok(cause)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def filter_done_leftover[E](cause: Cause[E]) -> Result[Any, Cause[E]]:
|
|
53
|
+
"""``filter_done``, keeping only the ``Done``'s leftover value."""
|
|
54
|
+
found = filter_done(cause)
|
|
55
|
+
return Ok(found.value.value) if isinstance(found, Ok) else found
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def done_exit_from_cause[E](cause: Cause[E]) -> Exit[Any, E]:
|
|
59
|
+
"""The producer's final exit: success with the leftover when ``Done``
|
|
60
|
+
is the only failure, else a failure with the cause stripped of
|
|
61
|
+
``Done``."""
|
|
62
|
+
found = filter_done(cause)
|
|
63
|
+
return Success(found.value.value) if isinstance(found, Ok) else Failure(found.error)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@overload
|
|
67
|
+
def catch_done[A, L, B, EE = Never, RR = Never](
|
|
68
|
+
pull: Effect[A, Done[L], RR], f: Callable[[L], Effect[B, EE, RR]]
|
|
69
|
+
) -> Effect[A | B, EE, RR]: ...
|
|
70
|
+
@overload
|
|
71
|
+
def catch_done[A, L, B, EE = Never, RR = Never](
|
|
72
|
+
pull: Effect[A, EE | Done[L], RR], f: Callable[[L], Effect[B, EE, RR]]
|
|
73
|
+
) -> Effect[A | B, EE, RR]: ...
|
|
74
|
+
def catch_done(
|
|
75
|
+
pull: Effect[Any, Any, Any], f: Callable[[Any], Effect[Any, Any, Any]]
|
|
76
|
+
) -> Effect[Any, Any, Any]:
|
|
77
|
+
"""Recover from ``Done`` with ``f(leftover)``; other failures pass
|
|
78
|
+
through (a ``Done`` merged with a real failure is dropped from it)."""
|
|
79
|
+
require_effect(pull, "pull")
|
|
80
|
+
|
|
81
|
+
def on_failure(cause: Cause[Any]) -> Effect[Any, Any, Any]:
|
|
82
|
+
found = filter_done(cause)
|
|
83
|
+
return f(found.value.value) if isinstance(found, Ok) else _FailCause(found.error)
|
|
84
|
+
|
|
85
|
+
return _MatchCause(pull, on_failure, None)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@overload
|
|
89
|
+
def match_effect[A, L, B, EE = Never, RR = Never](
|
|
90
|
+
pull: Effect[A, Done[L], RR],
|
|
91
|
+
*,
|
|
92
|
+
on_success: Callable[[A], Effect[B, EE, RR]],
|
|
93
|
+
on_failure: Callable[[Cause[Never]], Effect[B, EE, RR]],
|
|
94
|
+
on_done: Callable[[L], Effect[B, EE, RR]],
|
|
95
|
+
) -> Effect[B, EE, RR]: ...
|
|
96
|
+
@overload
|
|
97
|
+
def match_effect[A, E, L, B, EE = Never, RR = Never](
|
|
98
|
+
pull: Effect[A, E | Done[L], RR],
|
|
99
|
+
*,
|
|
100
|
+
on_success: Callable[[A], Effect[B, EE, RR]],
|
|
101
|
+
on_failure: Callable[[Cause[E]], Effect[B, EE, RR]],
|
|
102
|
+
on_done: Callable[[L], Effect[B, EE, RR]],
|
|
103
|
+
) -> Effect[B, EE, RR]: ...
|
|
104
|
+
def match_effect(
|
|
105
|
+
pull: Effect[Any, Any, Any],
|
|
106
|
+
*,
|
|
107
|
+
on_success: Callable[[Any], Effect[Any, Any, Any]],
|
|
108
|
+
on_failure: Callable[[Cause[Any]], Effect[Any, Any, Any]],
|
|
109
|
+
on_done: Callable[[Any], Effect[Any, Any, Any]],
|
|
110
|
+
) -> Effect[Any, Any, Any]:
|
|
111
|
+
"""Handle each outcome of ``pull``: an item, a failure (without
|
|
112
|
+
``Done``), or the end with its leftover."""
|
|
113
|
+
require_effect(pull, "pull")
|
|
114
|
+
|
|
115
|
+
def failed(cause: Cause[Any]) -> Effect[Any, Any, Any]:
|
|
116
|
+
found = filter_done(cause)
|
|
117
|
+
return on_done(found.value.value) if isinstance(found, Ok) else on_failure(found.error)
|
|
118
|
+
|
|
119
|
+
return _MatchCause(pull, failed, on_success)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
__all__ = [
|
|
123
|
+
"Pull",
|
|
124
|
+
"catch_done",
|
|
125
|
+
"done_exit_from_cause",
|
|
126
|
+
"filter_done",
|
|
127
|
+
"filter_done_leftover",
|
|
128
|
+
"filter_no_done",
|
|
129
|
+
"is_done_cause",
|
|
130
|
+
"is_done_failure",
|
|
131
|
+
"match_effect",
|
|
132
|
+
]
|
pyfect/py.typed
ADDED
|
File without changes
|
pyfect/pydantic.py
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""Pydantic and pyfect schemas, each usable in the other. Needs the
|
|
2
|
+
``pydantic`` extra (``pyfect-dev[pydantic]``).
|
|
3
|
+
|
|
4
|
+
A pyfect schema is a pydantic field type: annotate the field with it::
|
|
5
|
+
|
|
6
|
+
from typing import Annotated
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
|
|
10
|
+
from pyfect import schema as S
|
|
11
|
+
|
|
12
|
+
class Order(BaseModel):
|
|
13
|
+
total: Annotated[float, S.FiniteFromString]
|
|
14
|
+
|
|
15
|
+
Python input the schema's decoded side accepts is kept as it is (so
|
|
16
|
+
pydantic's revalidation and ``validate_assignment`` never decode twice);
|
|
17
|
+
other Python input is decoded with the schema, JSON input with
|
|
18
|
+
``S.to_codec_json(schema)``;
|
|
19
|
+
dumping encodes the same way, and the JSON Schema is the schema's. A schema
|
|
20
|
+
class (``S.Class``) works as a field type directly. A failure is one
|
|
21
|
+
pydantic error, the pyfect message. Only schemas that need no services can
|
|
22
|
+
run inside pydantic.
|
|
23
|
+
|
|
24
|
+
``from_model(Model)`` goes the other way: a pyfect schema of a pydantic
|
|
25
|
+
model, decoding JSON values with ``Model.model_validate`` and encoding with
|
|
26
|
+
``model_dump(mode="json")``; pydantic's errors become a pyfect issue tree.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
from collections.abc import Mapping
|
|
32
|
+
from typing import Any, Never, cast
|
|
33
|
+
|
|
34
|
+
from pyfect._extras import missing_extra
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
from pydantic import BaseModel, GetCoreSchemaHandler, GetJsonSchemaHandler, ValidationError
|
|
38
|
+
from pydantic_core import CoreSchema, PydanticCustomError, core_schema
|
|
39
|
+
except ImportError as error: # pragma: no cover - depends on the environment
|
|
40
|
+
raise missing_extra("pyfect.pydantic", "pydantic") from error
|
|
41
|
+
|
|
42
|
+
from pyfect.exit import Exit, Failure, Success
|
|
43
|
+
from pyfect.exit import fail as fail_exit
|
|
44
|
+
from pyfect.result import Err, Ok, Result
|
|
45
|
+
from pyfect.schema import (
|
|
46
|
+
Bottom,
|
|
47
|
+
Codec,
|
|
48
|
+
Json,
|
|
49
|
+
JsonValue,
|
|
50
|
+
ParseOptions,
|
|
51
|
+
SchemaError,
|
|
52
|
+
decode_to,
|
|
53
|
+
decode_unknown_result,
|
|
54
|
+
encode_unknown_result,
|
|
55
|
+
instance_of,
|
|
56
|
+
to_codec_json,
|
|
57
|
+
to_json_schema_document,
|
|
58
|
+
)
|
|
59
|
+
from pyfect.schema import ast as schema_ast
|
|
60
|
+
from pyfect.schema import transformation as T
|
|
61
|
+
from pyfect.schema.issue import Composite, InvalidValue, Issue, MissingKey, Pointer
|
|
62
|
+
|
|
63
|
+
__all__ = [
|
|
64
|
+
"core_schema_of",
|
|
65
|
+
"from_model",
|
|
66
|
+
"get_pydantic_core_schema",
|
|
67
|
+
"get_pydantic_json_schema",
|
|
68
|
+
"json_schema_of",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
type _Codec = Codec[Any, Any, Never, Never]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def core_schema_of(schema: _Codec, /) -> CoreSchema:
|
|
75
|
+
"""The pydantic core schema validating and serializing with ``schema``
|
|
76
|
+
(what ``__get_pydantic_core_schema__`` of a pyfect schema returns)."""
|
|
77
|
+
json_codec = to_codec_json(schema)
|
|
78
|
+
decoded_side = schema.__codec__().ast.to_type()
|
|
79
|
+
|
|
80
|
+
def decode_python(input: object) -> object:
|
|
81
|
+
# A decoded value is kept first, so validating again (pydantic's
|
|
82
|
+
# revalidation and assignment) never decodes a value twice.
|
|
83
|
+
match schema_ast.run_now(decoded_side.parse(input, {})):
|
|
84
|
+
case Success(value):
|
|
85
|
+
return value
|
|
86
|
+
case Failure():
|
|
87
|
+
return _unwrap(decode_unknown_result(schema)(input))
|
|
88
|
+
|
|
89
|
+
def decode_json(input: object) -> object:
|
|
90
|
+
return _unwrap(decode_unknown_result(json_codec)(input))
|
|
91
|
+
|
|
92
|
+
def serialize(value: object, info: core_schema.SerializationInfo) -> object:
|
|
93
|
+
codec = json_codec if info.mode_is_json() else schema
|
|
94
|
+
return _unwrap(encode_unknown_result(codec)(value))
|
|
95
|
+
|
|
96
|
+
return core_schema.json_or_python_schema(
|
|
97
|
+
json_schema=core_schema.no_info_plain_validator_function(decode_json),
|
|
98
|
+
python_schema=core_schema.no_info_plain_validator_function(decode_python),
|
|
99
|
+
serialization=core_schema.plain_serializer_function_ser_schema(serialize, info_arg=True),
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def json_schema_of(schema: _Codec, /) -> dict[str, Any]:
|
|
104
|
+
"""``schema``'s JSON Schema for pydantic, with its definitions inlined
|
|
105
|
+
(pydantic keeps its own ``$defs``); a recursive reference is left
|
|
106
|
+
unconstrained."""
|
|
107
|
+
document = to_json_schema_document(schema)
|
|
108
|
+
return cast("dict[str, Any]", _inline(document.schema, document.definitions, ()))
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _inline(node: object, definitions: Mapping[str, object], seen: tuple[str, ...]) -> object:
|
|
112
|
+
if isinstance(node, list):
|
|
113
|
+
return [_inline(value, definitions, seen) for value in cast("list[object]", node)]
|
|
114
|
+
if not isinstance(node, dict):
|
|
115
|
+
return node
|
|
116
|
+
fields = cast("dict[str, object]", node)
|
|
117
|
+
out = {key: _inline(value, definitions, seen) for key, value in fields.items() if key != "$ref"}
|
|
118
|
+
ref = fields.get("$ref")
|
|
119
|
+
if not (isinstance(ref, str) and ref.startswith(_DEFS)):
|
|
120
|
+
return out if ref is None else {**out, "$ref": ref}
|
|
121
|
+
name = ref.removeprefix(_DEFS)
|
|
122
|
+
if name in seen:
|
|
123
|
+
return out
|
|
124
|
+
target = cast("dict[str, object]", _inline(definitions[name], definitions, (*seen, name)))
|
|
125
|
+
return {**target, **out}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
_DEFS = "#/$defs/"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def get_pydantic_core_schema(
|
|
132
|
+
schema: _Codec, _source: object, _handler: GetCoreSchemaHandler
|
|
133
|
+
) -> CoreSchema:
|
|
134
|
+
return core_schema_of(schema)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def get_pydantic_json_schema(
|
|
138
|
+
schema: _Codec, _core: CoreSchema, _handler: GetJsonSchemaHandler
|
|
139
|
+
) -> dict[str, Any]:
|
|
140
|
+
return json_schema_of(schema)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _unwrap(result: Result[object, SchemaError]) -> object:
|
|
144
|
+
match result:
|
|
145
|
+
case Ok(value):
|
|
146
|
+
return value
|
|
147
|
+
case Err(error):
|
|
148
|
+
return _raise(error)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _raise(error: SchemaError) -> Never:
|
|
152
|
+
raise PydanticCustomError("pyfect_schema", "{message}", {"message": str(error)})
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def from_model[M: BaseModel](model: type[M], /) -> Bottom[M, JsonValue]:
|
|
156
|
+
"""``model`` as a pyfect schema: decodes a JSON value with
|
|
157
|
+
``model.model_validate``, encodes with ``model_dump(mode="json")``.
|
|
158
|
+
Each pydantic error is an issue at its location (``Missing key`` for a
|
|
159
|
+
missing field)."""
|
|
160
|
+
target = instance_of(model)
|
|
161
|
+
node = target.ast
|
|
162
|
+
|
|
163
|
+
def decode(input: JsonValue, _options: ParseOptions) -> Exit[M, Issue]:
|
|
164
|
+
try:
|
|
165
|
+
return Success(model.model_validate(input))
|
|
166
|
+
except ValidationError as error:
|
|
167
|
+
return fail_exit(_issue_of(error, node))
|
|
168
|
+
|
|
169
|
+
def encode(value: M, _options: ParseOptions) -> Exit[JsonValue, Issue]:
|
|
170
|
+
return Success(cast("JsonValue", value.model_dump(mode="json")))
|
|
171
|
+
|
|
172
|
+
return Json.pipe(decode_to(target, T.transform_effect(decode=decode, encode=encode)))
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _issue_of(error: ValidationError, node: schema_ast.AST) -> Issue:
|
|
176
|
+
issues: list[Issue] = []
|
|
177
|
+
for detail in error.errors(include_url=False):
|
|
178
|
+
leaf: Issue = (
|
|
179
|
+
MissingKey()
|
|
180
|
+
if detail["type"] == "missing"
|
|
181
|
+
else InvalidValue({"message": detail["msg"]})
|
|
182
|
+
)
|
|
183
|
+
location = tuple(detail["loc"])
|
|
184
|
+
issues.append(Pointer(location, leaf) if location else leaf)
|
|
185
|
+
if len(issues) == 1:
|
|
186
|
+
return issues[0]
|
|
187
|
+
first, *rest = issues
|
|
188
|
+
return Composite(node, (first, *rest))
|
pyfect/queue/__init__.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""``Queue[A, E]``: an async queue fibers can share.
|
|
2
|
+
|
|
3
|
+
Capacity and overflow behavior are fixed at creation:
|
|
4
|
+
|
|
5
|
+
- ``"suspend"`` (default): ``offer`` waits while the queue is full.
|
|
6
|
+
Capacity 0 is a rendezvous: an offer completes when a taker takes it.
|
|
7
|
+
- ``"dropping"``: ``offer`` on a full queue drops the new item.
|
|
8
|
+
- ``"sliding"``: ``offer`` on a full queue drops the oldest item. As in
|
|
9
|
+
Effect, ``sliding(0)`` keeps the newest offered item without waking a
|
|
10
|
+
parked taker (the next take gets it), while ``offer_all`` to it keeps
|
|
11
|
+
nothing.
|
|
12
|
+
|
|
13
|
+
A queue can be finished. After ``fail(error)`` (or ``interrupt()``), new
|
|
14
|
+
offers return ``False``, but takers still drain the items and the offers
|
|
15
|
+
that were already waiting, and then fail with ``error``. A queue that should
|
|
16
|
+
be endable declares it in its type, ``Queue[int, Done]``; only then do
|
|
17
|
+
``end()`` and ``into(eff)`` type-check, takers fail with ``Done()`` once it
|
|
18
|
+
drains, and ``collect`` / ``clear`` / ``await_done`` take ``Done`` out of the
|
|
19
|
+
error type. ``shutdown()`` drops everything at once: items are cleared,
|
|
20
|
+
waiting offers return ``False`` and takers are interrupted.
|
|
21
|
+
|
|
22
|
+
``Enqueue`` and ``Dequeue`` are the write-only and read-only views of a
|
|
23
|
+
queue, for passing it to code that only offers or only takes.
|
|
24
|
+
|
|
25
|
+
The ``unsafe_*`` methods act at once, outside an effect; call them on the
|
|
26
|
+
scheduler thread of the fibers that use the queue.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from pyfect.errors import Done
|
|
30
|
+
from pyfect.queue._queue import Queue, Strategy
|
|
31
|
+
from pyfect.queue._views import Dequeue, Enqueue
|
|
32
|
+
|
|
33
|
+
__all__ = ["Dequeue", "Done", "Enqueue", "Queue", "Strategy"]
|