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,43 @@
|
|
|
1
|
+
"""Reading a node's annotations and key context (Effect's
|
|
2
|
+
``SchemaAST.resolve*`` and ``isOptional``)."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
|
|
8
|
+
from pyfect.schema.ast._base import AST
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def resolve_at(key: str) -> Callable[[AST], object]:
|
|
12
|
+
"""The annotation ``key`` of the annotations describing a node (its last
|
|
13
|
+
check's when it has checks, else its own), or ``None`` (Effect's
|
|
14
|
+
``resolveAt``)."""
|
|
15
|
+
|
|
16
|
+
def at(ast: AST) -> object:
|
|
17
|
+
return (ast.resolve() or {}).get(key)
|
|
18
|
+
|
|
19
|
+
return at
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _text_at(key: str) -> Callable[[AST], str | None]:
|
|
23
|
+
at = resolve_at(key)
|
|
24
|
+
|
|
25
|
+
def text(ast: AST) -> str | None:
|
|
26
|
+
value = at(ast)
|
|
27
|
+
return value if isinstance(value, str) else None
|
|
28
|
+
|
|
29
|
+
return text
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
resolve_identifier = _text_at("identifier")
|
|
33
|
+
"""The node's ``identifier`` annotation (Effect's ``resolveIdentifier``)."""
|
|
34
|
+
resolve_title = _text_at("title")
|
|
35
|
+
"""The node's ``title`` annotation (Effect's ``resolveTitle``)."""
|
|
36
|
+
resolve_description = _text_at("description")
|
|
37
|
+
"""The node's ``description`` annotation (Effect's ``resolveDescription``)."""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def is_optional(ast: AST) -> bool:
|
|
41
|
+
"""A struct key holding ``ast`` may be missing (Effect's ``isOptional``:
|
|
42
|
+
the node is ``optional_key``)."""
|
|
43
|
+
return ast.optional_key
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"""``Arrays``: a sequence with leading elements and a rest (Effect's
|
|
2
|
+
``Arrays``): tuples, arrays and everything between.
|
|
3
|
+
|
|
4
|
+
The leading ``elements`` take the first positions, an optional one only at
|
|
5
|
+
the end of them. ``rest`` is empty for a fixed tuple; otherwise its first
|
|
6
|
+
node takes any number of values after the elements and the others take the
|
|
7
|
+
last positions, after them (``[*elements, *rest[0], *rest[1:]]``).
|
|
8
|
+
|
|
9
|
+
The input is a ``list`` or a ``tuple``; the output is a new ``tuple``, or a
|
|
10
|
+
``list`` when ``mutable``. A position past a fixed tuple's elements is an
|
|
11
|
+
``UnexpectedKey``.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from collections.abc import Callable, Sequence
|
|
17
|
+
from dataclasses import dataclass, replace
|
|
18
|
+
from typing import cast, final
|
|
19
|
+
|
|
20
|
+
from pyfect.exit import Exit, Failure, Success
|
|
21
|
+
from pyfect.exit import fail as fail_exit
|
|
22
|
+
from pyfect.schema._options import ParseOptions
|
|
23
|
+
from pyfect.schema.ast._base import (
|
|
24
|
+
AST,
|
|
25
|
+
at_key,
|
|
26
|
+
construct_missing,
|
|
27
|
+
invalid_type,
|
|
28
|
+
issue_of,
|
|
29
|
+
join_checks,
|
|
30
|
+
)
|
|
31
|
+
from pyfect.schema.ast._result import MISSING, ParseResult
|
|
32
|
+
from pyfect.schema.ast._steps import Abort, Pending, Steps, Stop, Suspended, run_steps
|
|
33
|
+
from pyfect.schema.ast._suspend import Suspend
|
|
34
|
+
from pyfect.schema.issue import Composite, Issue, MissingKey, Pointer, UnexpectedKey, reported
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass(frozen=True, slots=True)
|
|
38
|
+
class Element:
|
|
39
|
+
"""A leading position of values of ``type``; an ``optional`` one may be
|
|
40
|
+
missing (it is then missing from the output too)."""
|
|
41
|
+
|
|
42
|
+
type: AST
|
|
43
|
+
optional: bool = False
|
|
44
|
+
|
|
45
|
+
def optional_when_encoded(self) -> bool:
|
|
46
|
+
"""Whether the position may be missing from the encoded input (it is
|
|
47
|
+
optional, or a decoding default fills it)."""
|
|
48
|
+
return self.optional or self.type.flip().optional_key
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _check_order(elements: Sequence[Element], rest: Sequence[AST]) -> None:
|
|
52
|
+
optional = [e.optional for e in elements]
|
|
53
|
+
# A required position after the first optional one: a later element, or
|
|
54
|
+
# a position after the rest.
|
|
55
|
+
if True in optional and (not all(optional[optional.index(True) :]) or len(rest) > 1):
|
|
56
|
+
raise ValueError("A required element cannot follow an optional element. ts(1257)")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
60
|
+
class Arrays(AST):
|
|
61
|
+
"""A sequence of ``elements`` then ``rest`` (see the module)."""
|
|
62
|
+
|
|
63
|
+
elements: tuple[Element, ...] = ()
|
|
64
|
+
rest: tuple[AST, ...] = ()
|
|
65
|
+
mutable: bool = False
|
|
66
|
+
"""Decode to a ``list`` (else a ``tuple``)."""
|
|
67
|
+
tag = "Arrays"
|
|
68
|
+
|
|
69
|
+
def __post_init__(self) -> None:
|
|
70
|
+
_check_order(self.elements, self.rest)
|
|
71
|
+
|
|
72
|
+
def get_expected(self) -> str:
|
|
73
|
+
return "array"
|
|
74
|
+
|
|
75
|
+
def _parse(self, input: object, options: ParseOptions) -> ParseResult:
|
|
76
|
+
if not isinstance(input, list | tuple):
|
|
77
|
+
return invalid_type(self, input, options)
|
|
78
|
+
run = _Run(self, cast("Sequence[object]", input), options)
|
|
79
|
+
return run_steps(run, options.get("concurrency"))
|
|
80
|
+
|
|
81
|
+
def map_types(self, f: Callable[[AST], AST]) -> Arrays:
|
|
82
|
+
"""The node with ``f`` applied to each element and rest type (itself
|
|
83
|
+
when none changes)."""
|
|
84
|
+
elements = tuple(Element(f(e.type), e.optional) for e in self.elements)
|
|
85
|
+
rest = tuple(map(f, self.rest))
|
|
86
|
+
same = all(a.type is b.type for a, b in zip(elements, self.elements, strict=True)) and all(
|
|
87
|
+
a is b for a, b in zip(rest, self.rest, strict=True)
|
|
88
|
+
)
|
|
89
|
+
return self if same else replace(self, elements=elements, rest=rest)
|
|
90
|
+
|
|
91
|
+
def _flip(self) -> Arrays:
|
|
92
|
+
# Checks describe the decoded side: flipped, they check the input.
|
|
93
|
+
flipped = self.map_types(lambda t: t.flip())
|
|
94
|
+
if self.checks is None and self.encoding_checks is None:
|
|
95
|
+
return flipped
|
|
96
|
+
return replace(flipped, checks=self.encoding_checks, encoding_checks=self.checks)
|
|
97
|
+
|
|
98
|
+
def _to_type(self) -> Arrays:
|
|
99
|
+
typed = self.map_types(lambda t: t.to_type())
|
|
100
|
+
if self.encoding_checks is None:
|
|
101
|
+
return typed
|
|
102
|
+
# The encoded side's checks hold for the decoded one when no part
|
|
103
|
+
# transforms.
|
|
104
|
+
checks = join_checks(self.checks, self.encoding_checks) if typed is self else self.checks
|
|
105
|
+
return replace(typed, checks=checks, encoding_checks=None)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@final
|
|
109
|
+
class _Run(Steps["_Run"]):
|
|
110
|
+
"""One parse of a sequence (Effect's ``ArrayParserState``)."""
|
|
111
|
+
|
|
112
|
+
__slots__ = ("ast", "end", "input", "issues", "options", "out", "tail_threshold")
|
|
113
|
+
|
|
114
|
+
def __init__(self, ast: Arrays, input: Sequence[object], options: ParseOptions) -> None:
|
|
115
|
+
self.ast = ast
|
|
116
|
+
self.input = input
|
|
117
|
+
self.options = options
|
|
118
|
+
self.out: dict[int, object] = {}
|
|
119
|
+
"""The value at each position (positions finish in any order when
|
|
120
|
+
children run concurrently)."""
|
|
121
|
+
self.issues: list[Issue] = []
|
|
122
|
+
count = len(ast.elements)
|
|
123
|
+
tail = max(0, len(ast.rest) - 1)
|
|
124
|
+
self.tail_threshold = max(count, len(input) - tail)
|
|
125
|
+
self.end = max(len(input), count + tail) if ast.rest else count
|
|
126
|
+
|
|
127
|
+
def copy(self) -> _Run:
|
|
128
|
+
other = _Run.__new__(_Run)
|
|
129
|
+
other.ast, other.input, other.options = self.ast, self.input, self.options
|
|
130
|
+
other.end, other.tail_threshold = self.end, self.tail_threshold
|
|
131
|
+
other.out = dict(self.out)
|
|
132
|
+
other.issues = list(self.issues)
|
|
133
|
+
return other
|
|
134
|
+
|
|
135
|
+
def finish(self) -> Exit[object, Issue]:
|
|
136
|
+
if self.issues:
|
|
137
|
+
issues = self.issues
|
|
138
|
+
return fail_exit(
|
|
139
|
+
Composite(self.ast, (issues[0], *issues[1:]), reported(self.input, self.options))
|
|
140
|
+
)
|
|
141
|
+
out = self.out
|
|
142
|
+
values = [out[i] for i in sorted(out)]
|
|
143
|
+
return Success(values if self.ast.mutable else tuple(values))
|
|
144
|
+
|
|
145
|
+
def size(self) -> int:
|
|
146
|
+
return self.end
|
|
147
|
+
|
|
148
|
+
def _position(self, index: int) -> Element:
|
|
149
|
+
ast = self.ast
|
|
150
|
+
if index < len(ast.elements):
|
|
151
|
+
return ast.elements[index]
|
|
152
|
+
if index >= self.tail_threshold:
|
|
153
|
+
return Element(ast.rest[index - self.tail_threshold + 1])
|
|
154
|
+
return Element(ast.rest[0])
|
|
155
|
+
|
|
156
|
+
def run_from(self, start: int) -> Suspended[_Run] | None:
|
|
157
|
+
"""Steps: one per position, then the excess check."""
|
|
158
|
+
input, options, out = self.input, self.options, self.out
|
|
159
|
+
n = len(input)
|
|
160
|
+
for index in range(start, self.end):
|
|
161
|
+
position = self._position(index)
|
|
162
|
+
if index < n:
|
|
163
|
+
result = position.type.parse(input[index], options)
|
|
164
|
+
if type(result) is Success and result.value is not MISSING:
|
|
165
|
+
out[index] = result.value
|
|
166
|
+
continue
|
|
167
|
+
elif (constructed := construct_missing(position.type, options)) is not None:
|
|
168
|
+
result = constructed
|
|
169
|
+
elif position.type.encoding is not None or isinstance(position.type, Suspend):
|
|
170
|
+
result = position.type.parse(MISSING, options)
|
|
171
|
+
elif position.optional:
|
|
172
|
+
continue
|
|
173
|
+
else:
|
|
174
|
+
self._report(index, MissingKey(position.type.key_annotations))
|
|
175
|
+
continue
|
|
176
|
+
if isinstance(result, (Success, Failure)):
|
|
177
|
+
self._value(index, position, result)
|
|
178
|
+
else:
|
|
179
|
+
return index, Pending(result, _Run.value_at(index, position))
|
|
180
|
+
self._excess()
|
|
181
|
+
return None
|
|
182
|
+
|
|
183
|
+
@staticmethod
|
|
184
|
+
def value_at(index: int, position: Element) -> Callable[[_Run, Exit[object, Issue]], None]:
|
|
185
|
+
return lambda run, exit: run._value(index, position, exit)
|
|
186
|
+
|
|
187
|
+
def _excess(self) -> None:
|
|
188
|
+
ast, input = self.ast, self.input
|
|
189
|
+
if not ast.rest:
|
|
190
|
+
for index in range(len(ast.elements), len(input)):
|
|
191
|
+
self._report(index, UnexpectedKey(ast, reported(input[index], self.options)))
|
|
192
|
+
|
|
193
|
+
def _report(self, index: int, issue: Issue) -> None:
|
|
194
|
+
self.issues.append(Pointer((index,), issue))
|
|
195
|
+
if self.options.get("errors") != "all":
|
|
196
|
+
raise Stop
|
|
197
|
+
|
|
198
|
+
def _value(self, index: int, position: Element, exit: Exit[object, Issue]) -> None:
|
|
199
|
+
if type(exit) is Success:
|
|
200
|
+
value = exit.value
|
|
201
|
+
if value is not MISSING:
|
|
202
|
+
self.out[index] = value
|
|
203
|
+
elif not (position.optional or position.type.optional_key):
|
|
204
|
+
self._report(index, MissingKey(position.type.key_annotations))
|
|
205
|
+
return
|
|
206
|
+
failure = cast("Failure[Issue]", exit)
|
|
207
|
+
issue = issue_of(failure)
|
|
208
|
+
if issue is None:
|
|
209
|
+
raise Abort(at_key(self.ast, index, failure, self.input, self.options))
|
|
210
|
+
self._report(index, issue)
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
"""The node every schema AST extends, and the helpers that rebuild one."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from collections.abc import Hashable, Mapping
|
|
7
|
+
from dataclasses import dataclass, field, replace
|
|
8
|
+
from typing import TYPE_CHECKING, Any, ClassVar
|
|
9
|
+
|
|
10
|
+
from pyfect._effect_args import require_effect
|
|
11
|
+
from pyfect._primitives import known_exit
|
|
12
|
+
from pyfect.cause import Fail
|
|
13
|
+
from pyfect.exit import Exit, Failure, Success
|
|
14
|
+
from pyfect.exit import die as die_exit
|
|
15
|
+
from pyfect.exit import fail as fail_exit
|
|
16
|
+
from pyfect.schema._options import ParseOptions, is_constructing
|
|
17
|
+
from pyfect.schema.ast._check import collect_issues
|
|
18
|
+
from pyfect.schema.ast._encoding import Encoding, decode_chain, flip_encoding
|
|
19
|
+
from pyfect.schema.ast._result import MISSING, MISSING_EXIT, ParseResult, flat_map, map_issue
|
|
20
|
+
from pyfect.schema.issue import Composite, InvalidType, Issue, Pointer, is_issue, reported
|
|
21
|
+
from pyfect.schema.issue import Encoding as EncodingIssue
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from pyfect._core import Effect
|
|
25
|
+
from pyfect.schema.ast._check import Check
|
|
26
|
+
|
|
27
|
+
type Annotations = Mapping[str, object]
|
|
28
|
+
type Checks = tuple[Check[Any], *tuple[Check[Any], ...]]
|
|
29
|
+
"""The checks of a node, run in order on the value it parsed."""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
33
|
+
class AST(ABC):
|
|
34
|
+
"""A schema node. Nodes compare by identity, as in Effect.
|
|
35
|
+
|
|
36
|
+
``checks`` run on every value the node itself accepts (Effect's
|
|
37
|
+
``checks``); a subclass parses its own kind in ``_parse``.
|
|
38
|
+
``key_annotations`` describe the key holding the node in a struct.
|
|
39
|
+
``encoding`` says how the node decodes from other nodes (see
|
|
40
|
+
``_encoding.py``); a node without one parses its input itself.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
annotations: Annotations | None = field(default=None, kw_only=True)
|
|
44
|
+
checks: Checks | None = field(default=None, kw_only=True)
|
|
45
|
+
key_annotations: Annotations | None = field(default=None, kw_only=True)
|
|
46
|
+
"""Annotations of the key holding this node in a struct
|
|
47
|
+
(``message_missing_key``, ...): Effect's ``annotateKey``."""
|
|
48
|
+
encoding: Encoding | None = field(default=None, kw_only=True)
|
|
49
|
+
encoding_checks: Checks | None = field(default=None, kw_only=True)
|
|
50
|
+
"""Checks of the decoded side kept by a flipped composite: they run on
|
|
51
|
+
its input (Effect's ``encodingChecks``)."""
|
|
52
|
+
optional_key: bool = field(default=False, kw_only=True)
|
|
53
|
+
"""A struct key holding this node may be missing (Effect's
|
|
54
|
+
``optionalKey`` context): set on the source of a transformation, so a
|
|
55
|
+
key is optional on the encoded side only."""
|
|
56
|
+
constructor_default: Effect[object, Issue] | None = field(
|
|
57
|
+
default=None, kw_only=True, compare=False
|
|
58
|
+
)
|
|
59
|
+
"""What a constructor (``make``) gives a missing key or element holding
|
|
60
|
+
this node, parsed by the node (Effect's ``constructorDefault`` context,
|
|
61
|
+
``with_constructor_default``); decoding never uses it."""
|
|
62
|
+
context_owner: AST | None = field(default=None, init=False, repr=False, compare=False)
|
|
63
|
+
"""The node this one copies with only its key context changed (see
|
|
64
|
+
``replace_context``); any other ``replace`` drops it."""
|
|
65
|
+
body_owner: AST | None = field(default=None, init=False, repr=False, compare=False)
|
|
66
|
+
"""The node this one copies with an encoding added (``decode_to``):
|
|
67
|
+
the schema whose values a JSON string holds, say."""
|
|
68
|
+
_type_side: list[AST] = field(
|
|
69
|
+
default_factory=list["AST"], init=False, repr=False, compare=False
|
|
70
|
+
)
|
|
71
|
+
"""``to_type()``, made once: contextual copies of a node then share one
|
|
72
|
+
type side, so derivations see one schema (Effect memoizes ``toType``)."""
|
|
73
|
+
_flip_side: list[AST] = field(
|
|
74
|
+
default_factory=list["AST"], init=False, repr=False, compare=False
|
|
75
|
+
)
|
|
76
|
+
"""``flip()``, made once (Effect memoizes ``flip``): the flip of a
|
|
77
|
+
recursive schema then refers back to itself, a finite graph."""
|
|
78
|
+
tag: ClassVar[str]
|
|
79
|
+
|
|
80
|
+
def owner(self) -> AST:
|
|
81
|
+
"""The node whose body this one shares (Effect's
|
|
82
|
+
``getContextOwner``): copies that change only the key context are
|
|
83
|
+
one schema to derivations and JSON Schema definitions."""
|
|
84
|
+
return self.context_owner or self
|
|
85
|
+
|
|
86
|
+
@abstractmethod
|
|
87
|
+
def get_expected(self) -> str:
|
|
88
|
+
"""What the node itself expects (``"string"``)."""
|
|
89
|
+
|
|
90
|
+
def resolve(self) -> Annotations | None:
|
|
91
|
+
"""The annotations that describe the node: its last check's when it
|
|
92
|
+
has checks, else its own (Effect's ``resolveAnnotations``)."""
|
|
93
|
+
return self.checks[-1].annotations if self.checks else self.annotations
|
|
94
|
+
|
|
95
|
+
def expected(self) -> str:
|
|
96
|
+
"""The text ``"Expected <...>"`` messages use: the ``identifier``
|
|
97
|
+
annotation, else ``get_expected()`` (Effect's ``getExpected``)."""
|
|
98
|
+
identifier = (self.resolve() or {}).get("identifier")
|
|
99
|
+
return identifier if isinstance(identifier, str) else self.get_expected()
|
|
100
|
+
|
|
101
|
+
def parse(self, input: object, options: ParseOptions) -> ParseResult:
|
|
102
|
+
"""``input`` decoded through the node's encoding, then checked
|
|
103
|
+
against the node and its checks: an ``Exit``, or an ``Effect`` when
|
|
104
|
+
a transformation needs one."""
|
|
105
|
+
encoding = self.encoding
|
|
106
|
+
if encoding is not None:
|
|
107
|
+
return decode_chain(self, encoding, input, options)
|
|
108
|
+
# ``parse_local``, inlined: this is the hot path.
|
|
109
|
+
if input is MISSING:
|
|
110
|
+
return MISSING_EXIT
|
|
111
|
+
result = self._parse(input, options)
|
|
112
|
+
if (self.checks is None and self.encoding_checks is None) or options.get("disable_checks"):
|
|
113
|
+
return result
|
|
114
|
+
if type(result) is Success:
|
|
115
|
+
return self._run_checks(input, result.value, options)
|
|
116
|
+
return flat_map(result, lambda value: self._run_checks(input, value, options))
|
|
117
|
+
|
|
118
|
+
def parse_local(self, input: object, options: ParseOptions) -> ParseResult:
|
|
119
|
+
"""``input`` checked against the node itself (not its encoding) and
|
|
120
|
+
its checks. ``MISSING`` stays missing. A subclass overriding it
|
|
121
|
+
overrides ``parse`` too (``parse`` inlines this)."""
|
|
122
|
+
if input is MISSING:
|
|
123
|
+
return MISSING_EXIT
|
|
124
|
+
result = self._parse(input, options)
|
|
125
|
+
if (self.checks is None and self.encoding_checks is None) or options.get("disable_checks"):
|
|
126
|
+
return result
|
|
127
|
+
if type(result) is Success:
|
|
128
|
+
return self._run_checks(input, result.value, options)
|
|
129
|
+
return flat_map(result, lambda value: self._run_checks(input, value, options))
|
|
130
|
+
|
|
131
|
+
def _run_checks(self, input: object, value: object, options: ParseOptions) -> ParseResult:
|
|
132
|
+
try:
|
|
133
|
+
if self.encoding_checks is not None:
|
|
134
|
+
issues = collect_issues(self.encoding_checks, input, self, options)
|
|
135
|
+
if issues is not None:
|
|
136
|
+
return fail_exit(Composite(self, issues, reported(input, options)))
|
|
137
|
+
if self.checks is not None:
|
|
138
|
+
issues = collect_issues(self.checks, value, self, options)
|
|
139
|
+
if issues is not None:
|
|
140
|
+
return fail_exit(Composite(self, issues, reported(value, options)))
|
|
141
|
+
except Exception as defect:
|
|
142
|
+
# A check that raises is a defect, as in Effect.
|
|
143
|
+
return die_exit(defect)
|
|
144
|
+
return Success(value)
|
|
145
|
+
|
|
146
|
+
@abstractmethod
|
|
147
|
+
def _parse(self, input: object, options: ParseOptions) -> ParseResult:
|
|
148
|
+
"""``input`` checked against the node's own kind, without checks."""
|
|
149
|
+
|
|
150
|
+
def flip(self) -> AST:
|
|
151
|
+
"""The node that encodes what this one decodes. A node without an
|
|
152
|
+
encoding flips its parts; a leaf is its own flip."""
|
|
153
|
+
if not self._flip_side:
|
|
154
|
+
encoding = self.encoding
|
|
155
|
+
flipped = flip_encoding(self, encoding) if encoding is not None else self._flip()
|
|
156
|
+
self._flip_side.append(flipped)
|
|
157
|
+
return self._flip_side[0]
|
|
158
|
+
|
|
159
|
+
def _flip(self) -> AST:
|
|
160
|
+
"""The flip of the node's own parts (it has no encoding)."""
|
|
161
|
+
return self
|
|
162
|
+
|
|
163
|
+
def to_type(self) -> AST:
|
|
164
|
+
"""The node's decoded side: no encoding, its parts' decoded sides. A
|
|
165
|
+
contextual copy's is its owner's, with the copy's key context."""
|
|
166
|
+
owner = self.owner()
|
|
167
|
+
if owner is not self:
|
|
168
|
+
return _with_context(owner.to_type(), self)
|
|
169
|
+
if not self._type_side:
|
|
170
|
+
base = self if self.encoding is None else replace(self, encoding=None)
|
|
171
|
+
self._type_side.append(base._to_type())
|
|
172
|
+
return self._type_side[0]
|
|
173
|
+
|
|
174
|
+
def _to_type(self) -> AST:
|
|
175
|
+
"""The decoded side of the node's own parts (it has no encoding)."""
|
|
176
|
+
return self
|
|
177
|
+
|
|
178
|
+
def __str__(self) -> str:
|
|
179
|
+
return f"<{self.tag}>"
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def annotate[N: AST](ast: N, annotations: Annotations) -> N:
|
|
183
|
+
"""``ast`` with ``annotations`` merged over its own; on a node with
|
|
184
|
+
checks they go to the last check, which then describes the node."""
|
|
185
|
+
if ast.checks:
|
|
186
|
+
*rest, last = ast.checks
|
|
187
|
+
return replace(ast, checks=(*rest, last.annotate(**annotations)))
|
|
188
|
+
return replace(ast, annotations={**(ast.annotations or {}), **annotations})
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def append_checks[N: AST](ast: N, checks: Checks) -> N:
|
|
192
|
+
"""``ast`` with ``checks`` run after its own."""
|
|
193
|
+
return replace(ast, checks=(*ast.checks, *checks) if ast.checks else checks)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def join_checks(first: Checks | None, second: Checks | None) -> Checks | None:
|
|
197
|
+
if first is None:
|
|
198
|
+
return second
|
|
199
|
+
if second is None:
|
|
200
|
+
return first
|
|
201
|
+
return (*first, *second)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
205
|
+
class Refinement(AST):
|
|
206
|
+
"""A node accepting the values a predicate selects, unchanged."""
|
|
207
|
+
|
|
208
|
+
def _parse(self, input: object, options: ParseOptions) -> Exit[object, Issue]:
|
|
209
|
+
if self.accepts(input):
|
|
210
|
+
return Success(input)
|
|
211
|
+
return invalid_type(self, input, options)
|
|
212
|
+
|
|
213
|
+
@abstractmethod
|
|
214
|
+
def accepts(self, input: object) -> bool: ...
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def invalid_type(ast: AST, input: object, options: ParseOptions) -> Failure[Issue]:
|
|
218
|
+
return fail_exit(InvalidType(ast, reported(input, options)))
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def at_key(
|
|
222
|
+
ast: AST, key: Hashable, failure: Failure[Issue], input: object, options: ParseOptions
|
|
223
|
+
) -> Failure[Issue]:
|
|
224
|
+
"""A child's failure that is not only issues (a defect with them), its
|
|
225
|
+
issues placed at ``key`` of ``ast``'s input; the defects stay."""
|
|
226
|
+
shown = reported(input, options)
|
|
227
|
+
return Failure(
|
|
228
|
+
failure.cause.map(lambda issue: Composite(ast, (Pointer((key,), issue),), shown))
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def issue_of(failure: Failure[Issue]) -> Issue | None:
|
|
233
|
+
"""The issue of a failed parse, or ``None`` when its cause holds
|
|
234
|
+
anything else (a defect is never a mismatch)."""
|
|
235
|
+
reasons = failure.cause.reasons
|
|
236
|
+
if reasons and all(isinstance(r, Fail) and is_issue(r.error) for r in reasons):
|
|
237
|
+
first = reasons[0]
|
|
238
|
+
return first.error if isinstance(first, Fail) else None
|
|
239
|
+
return None
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def replace_context[A: AST](
|
|
243
|
+
node: A, *, key_annotations: Annotations | None = None, optional_key: bool | None = None
|
|
244
|
+
) -> A:
|
|
245
|
+
"""``node`` with another key context: the copy shares ``node``'s body
|
|
246
|
+
(its ``owner``)."""
|
|
247
|
+
out = replace(
|
|
248
|
+
node,
|
|
249
|
+
key_annotations=node.key_annotations if key_annotations is None else key_annotations,
|
|
250
|
+
optional_key=node.optional_key if optional_key is None else optional_key,
|
|
251
|
+
)
|
|
252
|
+
object.__setattr__(out, "context_owner", node.owner())
|
|
253
|
+
return out
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _with_context(typed: AST, source: AST) -> AST:
|
|
257
|
+
if (
|
|
258
|
+
typed.key_annotations == source.key_annotations
|
|
259
|
+
and typed.optional_key == source.optional_key
|
|
260
|
+
and typed.constructor_default is source.constructor_default
|
|
261
|
+
):
|
|
262
|
+
return typed
|
|
263
|
+
out = replace(
|
|
264
|
+
typed,
|
|
265
|
+
key_annotations=source.key_annotations,
|
|
266
|
+
optional_key=source.optional_key,
|
|
267
|
+
constructor_default=source.constructor_default,
|
|
268
|
+
)
|
|
269
|
+
object.__setattr__(out, "context_owner", typed.owner())
|
|
270
|
+
return out
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def with_constructor_default[A: AST](ast: A, default: Effect[object, Issue]) -> A:
|
|
274
|
+
"""``ast`` whose missing key or element a constructor fills with
|
|
275
|
+
``default``'s value (Effect's ``SchemaAST.withConstructorDefault``); the
|
|
276
|
+
copy shares ``ast``'s body."""
|
|
277
|
+
require_effect(default, "default")
|
|
278
|
+
out = replace_context(ast)
|
|
279
|
+
object.__setattr__(out, "constructor_default", default)
|
|
280
|
+
return out
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def construct_missing(ast: AST, options: ParseOptions) -> ParseResult | None:
|
|
284
|
+
"""The parse of a missing key or element holding ``ast`` under a
|
|
285
|
+
constructor: its constructor default's value, parsed by ``ast`` (a
|
|
286
|
+
failing default is an ``Encoding`` issue, as Effect's ``withDefault``);
|
|
287
|
+
``None`` without a default or outside a constructor."""
|
|
288
|
+
default = ast.constructor_default
|
|
289
|
+
if default is None or not is_constructing(options):
|
|
290
|
+
return None
|
|
291
|
+
known = known_exit(default)
|
|
292
|
+
if type(known) is Success:
|
|
293
|
+
return ast.parse(known.value, options)
|
|
294
|
+
wrapped = map_issue(default if known is None else known, lambda i: EncodingIssue(ast, i))
|
|
295
|
+
return flat_map(wrapped, lambda value: ast.parse(value, options))
|