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
pyfect/sink/_sink.py
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"""The ``Sink`` type, its ``End`` and its methods.
|
|
2
|
+
|
|
3
|
+
A sink is a function from an upstream pull of non-empty tuples (and a
|
|
4
|
+
``CloseableScope``) to an effect that consumes some of that input and
|
|
5
|
+
succeeds with an ``End``: the sink's value and the input it read but did
|
|
6
|
+
not use (Effect v4's ``Sink.transform``). The upstream fails only with
|
|
7
|
+
``Done()``; a stream's own failures reach a sink as hidden defects, so no
|
|
8
|
+
sink error handler sees them (``Stream.run``).
|
|
9
|
+
|
|
10
|
+
The methods give their work to ``pyfect.sink._combinators``, imported when
|
|
11
|
+
called (it builds ``Sink`` values, so it loads after this module).
|
|
12
|
+
"""
|
|
13
|
+
# pyright: reportPrivateUsage=false
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from collections.abc import Callable
|
|
18
|
+
from typing import TYPE_CHECKING, Any, Generic, Never, Self, TypeVar, overload
|
|
19
|
+
|
|
20
|
+
from pyfect._core import Effect, _Suspend
|
|
21
|
+
from pyfect._effect_args import wrong_argument
|
|
22
|
+
from pyfect.errors import Done
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from pyfect.cause import Cause
|
|
26
|
+
from pyfect.exit import Exit
|
|
27
|
+
from pyfect.scope import CloseableScope
|
|
28
|
+
|
|
29
|
+
A_co = TypeVar("A_co", covariant=True)
|
|
30
|
+
In_contra = TypeVar("In_contra", contravariant=True, default=object)
|
|
31
|
+
L_co = TypeVar("L_co", covariant=True, default=Never)
|
|
32
|
+
E_co = TypeVar("E_co", covariant=True, default=Never)
|
|
33
|
+
R_co = TypeVar("R_co", covariant=True, default=Never)
|
|
34
|
+
|
|
35
|
+
type End[A, L = Never] = tuple[A, tuple[L, ...] | None]
|
|
36
|
+
"""What a sink ends with: its value, and the input it read but did not
|
|
37
|
+
use (a non-empty tuple, or ``None``). Effect's ``Sink.End``."""
|
|
38
|
+
|
|
39
|
+
type Upstream[In] = Effect[tuple[In, ...], Done]
|
|
40
|
+
"""What a sink reads: a pull of non-empty tuples that ends with
|
|
41
|
+
``Done()``."""
|
|
42
|
+
|
|
43
|
+
type Transform[A, In, L, E, R] = Callable[[Upstream[In], CloseableScope], Effect[End[A, L], E, R]]
|
|
44
|
+
"""What a sink is made of (see ``sink.from_transform``)."""
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Sink(Generic[A_co, In_contra, L_co, E_co, R_co]):
|
|
48
|
+
"""``Sink[A, In, L, E, R]``: reads ``In`` items until it has what it
|
|
49
|
+
needs, then succeeds with ``A`` and leaves over the ``L`` items it read
|
|
50
|
+
but did not use; or fails with ``E``. Needs the services ``R``.
|
|
51
|
+
|
|
52
|
+
Build sinks with the functions in ``pyfect.sink`` and run them with
|
|
53
|
+
``Stream.run``. Methods keep or add to the type parameters; the
|
|
54
|
+
combinators that remove services (``provide_service``,
|
|
55
|
+
``provide_context``) are functions in ``pyfect.sink``, used with
|
|
56
|
+
``.pipe``.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
__slots__ = ("_build",)
|
|
60
|
+
|
|
61
|
+
def __init__(self, transform: Transform[A_co, In_contra, L_co, E_co, R_co]) -> None:
|
|
62
|
+
self._build: Transform[Any, Any, Any, Any, Any] = transform
|
|
63
|
+
|
|
64
|
+
def _transform(self, upstream: Upstream[Any], scope: CloseableScope) -> Effect[End[Any, Any]]:
|
|
65
|
+
"""The effect consuming ``upstream``. Built when it runs, so a
|
|
66
|
+
raising transform is a defect of the run."""
|
|
67
|
+
build = self._build
|
|
68
|
+
return _Suspend(lambda: build(upstream, scope))
|
|
69
|
+
|
|
70
|
+
def pipe[B](self, f: Callable[[Self], B], /) -> B:
|
|
71
|
+
"""Apply ``f`` to this sink (one step; see ``Effect.pipe``)."""
|
|
72
|
+
return f(self)
|
|
73
|
+
|
|
74
|
+
# --- the value ---------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
def map[B](self, f: Callable[[A_co], B]) -> Sink[B, In_contra, L_co, E_co, R_co]:
|
|
77
|
+
"""The sink with its value replaced by ``f(value)``."""
|
|
78
|
+
from pyfect.sink import _combinators
|
|
79
|
+
|
|
80
|
+
return _combinators.map_end(self, lambda end: (f(end[0]), end[1]))
|
|
81
|
+
|
|
82
|
+
def as_[B](self, value: B) -> Sink[B, In_contra, L_co, E_co, R_co]:
|
|
83
|
+
"""The sink with its value replaced by ``value``."""
|
|
84
|
+
from pyfect.sink import _combinators
|
|
85
|
+
|
|
86
|
+
return _combinators.map_end(self, lambda end: (value, end[1]))
|
|
87
|
+
|
|
88
|
+
def map_effect[B, E2 = Never, R2 = Never](
|
|
89
|
+
self, f: Callable[[A_co], Effect[B, E2, R2]]
|
|
90
|
+
) -> Sink[B, In_contra, L_co, E_co | E2, R_co | R2]:
|
|
91
|
+
"""The sink with its value replaced by what ``f(value)`` succeeds
|
|
92
|
+
with."""
|
|
93
|
+
from pyfect.sink import _combinators
|
|
94
|
+
|
|
95
|
+
return _combinators.map_effect_end(self, lambda end: f(end[0]).map(lambda b: (b, end[1])))
|
|
96
|
+
|
|
97
|
+
def map_end[B, L2 = Never](
|
|
98
|
+
self, f: Callable[[End[A_co, L_co]], End[B, L2]]
|
|
99
|
+
) -> Sink[B, In_contra, L2, E_co, R_co]:
|
|
100
|
+
"""The sink with its whole ``End`` (value and leftovers) replaced by
|
|
101
|
+
``f(end)``."""
|
|
102
|
+
from pyfect.sink import _combinators
|
|
103
|
+
|
|
104
|
+
return _combinators.map_end(self, f)
|
|
105
|
+
|
|
106
|
+
def map_effect_end[B, L2 = Never, E2 = Never, R2 = Never](
|
|
107
|
+
self, f: Callable[[End[A_co, L_co]], Effect[End[B, L2], E2, R2]]
|
|
108
|
+
) -> Sink[B, In_contra, L2, E_co | E2, R_co | R2]:
|
|
109
|
+
"""``map_end`` with an effectful ``f``."""
|
|
110
|
+
from pyfect.sink import _combinators
|
|
111
|
+
|
|
112
|
+
return _combinators.map_effect_end(self, f)
|
|
113
|
+
|
|
114
|
+
def summarized[S, B, E2 = Never, R2 = Never](
|
|
115
|
+
self, summary: Effect[S, E2, R2], f: Callable[[S, S], B]
|
|
116
|
+
) -> Sink[tuple[A_co, B], In_contra, L_co, E_co | E2, R_co | R2]:
|
|
117
|
+
"""Run ``summary`` before and after the sink and pair its value with
|
|
118
|
+
``f(before, after)``."""
|
|
119
|
+
from pyfect._effect_args import require_effect
|
|
120
|
+
from pyfect.sink import _combinators
|
|
121
|
+
|
|
122
|
+
require_effect(summary, "summary")
|
|
123
|
+
return _combinators.summarized(self, summary, f)
|
|
124
|
+
|
|
125
|
+
def with_duration(self) -> Sink[tuple[A_co, float], In_contra, L_co, E_co, R_co]:
|
|
126
|
+
"""Pair the value with how long the sink ran, in seconds, measured in
|
|
127
|
+
whole monotonic nanoseconds."""
|
|
128
|
+
from pyfect.sink import _combinators
|
|
129
|
+
|
|
130
|
+
return _combinators.with_duration(self)
|
|
131
|
+
|
|
132
|
+
# --- the input and the leftovers ---------------------------------------
|
|
133
|
+
|
|
134
|
+
def map_input[In0](self, f: Callable[[In0], In_contra]) -> Sink[A_co, In0, L_co, E_co, R_co]:
|
|
135
|
+
"""A sink reading ``In0`` items, each given to this sink as
|
|
136
|
+
``f(item)``."""
|
|
137
|
+
from pyfect.sink import _combinators
|
|
138
|
+
|
|
139
|
+
return _combinators.map_input_array(self, lambda chunk: tuple(map(f, chunk)))
|
|
140
|
+
|
|
141
|
+
def map_input_effect[In0, E2 = Never, R2 = Never](
|
|
142
|
+
self, f: Callable[[In0], Effect[In_contra, E2, R2]]
|
|
143
|
+
) -> Sink[A_co, In0, L_co, E_co | E2, R_co | R2]:
|
|
144
|
+
"""``map_input`` with an effectful ``f``, run on each item in
|
|
145
|
+
order."""
|
|
146
|
+
from pyfect.sink import _combinators
|
|
147
|
+
|
|
148
|
+
return _combinators.map_input_effect(self, f)
|
|
149
|
+
|
|
150
|
+
def map_input_array[In0](
|
|
151
|
+
self, f: Callable[[tuple[In0, ...]], tuple[In_contra, ...]]
|
|
152
|
+
) -> Sink[A_co, In0, L_co, E_co, R_co]:
|
|
153
|
+
"""A sink reading ``In0`` chunks, each given to this sink as
|
|
154
|
+
``f(chunk)``, which must be non-empty."""
|
|
155
|
+
from pyfect.sink import _combinators
|
|
156
|
+
|
|
157
|
+
return _combinators.map_input_array(self, f)
|
|
158
|
+
|
|
159
|
+
def map_input_array_effect[In0, E2 = Never, R2 = Never](
|
|
160
|
+
self, f: Callable[[tuple[In0, ...]], Effect[tuple[In_contra, ...], E2, R2]]
|
|
161
|
+
) -> Sink[A_co, In0, L_co, E_co | E2, R_co | R2]:
|
|
162
|
+
"""``map_input_array`` with an effectful ``f``."""
|
|
163
|
+
from pyfect.sink import _combinators
|
|
164
|
+
|
|
165
|
+
return _combinators.map_input_array_effect(self, f)
|
|
166
|
+
|
|
167
|
+
def map_leftover[L2](self, f: Callable[[L_co], L2]) -> Sink[A_co, In_contra, L2, E_co, R_co]:
|
|
168
|
+
"""The sink with each leftover item replaced by ``f(item)``."""
|
|
169
|
+
from pyfect.sink import _combinators
|
|
170
|
+
|
|
171
|
+
return _combinators.map_end(
|
|
172
|
+
self, lambda end: (end[0], None if end[1] is None else tuple(map(f, end[1])))
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
def ignore_leftover(self) -> Sink[A_co, In_contra, Never, E_co, R_co]:
|
|
176
|
+
"""The sink without its leftovers: what it read but did not use is
|
|
177
|
+
dropped."""
|
|
178
|
+
from pyfect.sink import _combinators
|
|
179
|
+
|
|
180
|
+
return _combinators.map_end(self, lambda end: (end[0], None))
|
|
181
|
+
|
|
182
|
+
# A sink without leftovers has none to feed on; the overload keeps
|
|
183
|
+
# pyright from reading the input type off ``L = Never``.
|
|
184
|
+
@overload
|
|
185
|
+
def flat_map[I, B, L2 = Never, E2 = Never, R2 = Never](
|
|
186
|
+
self: Sink[A_co, I, Never, E_co, R_co], f: Callable[[A_co], Sink[B, I, L2, E2, R2]]
|
|
187
|
+
) -> Sink[B, I, L2, E_co | E2, R_co | R2]: ...
|
|
188
|
+
@overload
|
|
189
|
+
def flat_map[I, B, L2 = Never, E2 = Never, R2 = Never](
|
|
190
|
+
self: Sink[A_co, I, I, E_co, R_co], f: Callable[[A_co], Sink[B, I, L2, E2, R2]]
|
|
191
|
+
) -> Sink[B, I, I | L2, E_co | E2, R_co | R2]: ...
|
|
192
|
+
def flat_map(
|
|
193
|
+
self, f: Callable[[A_co], Sink[Any, Any, Any, Any, Any]]
|
|
194
|
+
) -> Sink[Any, Any, Any, Any, Any]:
|
|
195
|
+
"""Run this sink, then ``f(value)`` on the rest of the input, its
|
|
196
|
+
leftovers first. Leftovers the second sink does not read stay
|
|
197
|
+
leftovers."""
|
|
198
|
+
from pyfect.sink import _combinators
|
|
199
|
+
|
|
200
|
+
return _combinators.flat_map(self, f)
|
|
201
|
+
|
|
202
|
+
# --- failures ----------------------------------------------------------
|
|
203
|
+
|
|
204
|
+
def map_error[E2](self, f: Callable[[E_co], E2]) -> Sink[A_co, In_contra, L_co, E2, R_co]:
|
|
205
|
+
"""The sink with its typed error replaced by ``f(error)``."""
|
|
206
|
+
from pyfect.sink import _combinators
|
|
207
|
+
|
|
208
|
+
return _combinators.transform_effect(self, lambda eff: eff.map_error(f))
|
|
209
|
+
|
|
210
|
+
def catch_all[B, E2 = Never, R2 = Never](
|
|
211
|
+
self, f: Callable[[E_co], Effect[B, E2, R2]]
|
|
212
|
+
) -> Sink[A_co | B, In_contra, L_co, E2, R_co | R2]:
|
|
213
|
+
"""Recover from a typed failure with the value of ``f(error)``
|
|
214
|
+
(Effect's ``Sink.catch``). The stream's own failures pass by."""
|
|
215
|
+
from pyfect.sink import _combinators
|
|
216
|
+
|
|
217
|
+
return _combinators.catch_all(self, f)
|
|
218
|
+
|
|
219
|
+
def catch_cause[B, E2 = Never, R2 = Never](
|
|
220
|
+
self, f: Callable[[Cause[E_co]], Effect[B, E2, R2]]
|
|
221
|
+
) -> Sink[A_co | B, In_contra, L_co, E2, R_co | R2]:
|
|
222
|
+
"""Recover from any failure of the sink with the value of
|
|
223
|
+
``f(cause)``. The stream's own failures pass by."""
|
|
224
|
+
from pyfect.sink import _combinators
|
|
225
|
+
|
|
226
|
+
return _combinators.catch_cause(self, f)
|
|
227
|
+
|
|
228
|
+
def or_else[I, B, L2 = Never, E2 = Never, R2 = Never](
|
|
229
|
+
self: Sink[A_co, I, L_co, E_co, R_co], f: Callable[[E_co], Sink[B, I, L2, E2, R2]]
|
|
230
|
+
) -> Sink[A_co | B, I, L_co | L2, E2, R_co | R2]:
|
|
231
|
+
"""After a typed failure, go on with ``f(error)`` on the rest of
|
|
232
|
+
the input. The stream's own failures pass by."""
|
|
233
|
+
from pyfect.sink import _combinators
|
|
234
|
+
|
|
235
|
+
return _combinators.or_else(self, f)
|
|
236
|
+
|
|
237
|
+
# --- finalizers --------------------------------------------------------
|
|
238
|
+
|
|
239
|
+
def on_exit[R2 = Never](
|
|
240
|
+
self, f: Callable[[Exit[A_co, E_co]], Effect[object, Never, R2]]
|
|
241
|
+
) -> Sink[A_co, In_contra, L_co, E_co, R_co | R2]:
|
|
242
|
+
"""Run ``f(exit)`` when the sink ends. A stream failure stops the
|
|
243
|
+
sink as an interruption would, so ``f`` sees an interrupt."""
|
|
244
|
+
from pyfect.sink import _combinators
|
|
245
|
+
|
|
246
|
+
return _combinators.on_exit(self, f)
|
|
247
|
+
|
|
248
|
+
def ensuring[R2 = Never](
|
|
249
|
+
self, finalizer: Effect[object, Never, R2]
|
|
250
|
+
) -> Sink[A_co, In_contra, L_co, E_co, R_co | R2]:
|
|
251
|
+
"""Run ``finalizer`` however the sink ends."""
|
|
252
|
+
from pyfect._effect_args import require_effect
|
|
253
|
+
from pyfect.sink import _combinators
|
|
254
|
+
|
|
255
|
+
require_effect(finalizer, "finalizer")
|
|
256
|
+
return _combinators.on_exit(self, lambda _: finalizer)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
type AnySink = Sink[Any, Any, Any, Any, Any]
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def require_sink(value: object, name: str) -> None:
|
|
263
|
+
"""Raise ``TypeError`` naming ``name`` unless ``value`` is a ``Sink``."""
|
|
264
|
+
if not isinstance(value, Sink):
|
|
265
|
+
raise TypeError(wrong_argument(value, name, "a Sink", "build one with pyfect.sink"))
|
pyfect/sink/_steps.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""What the sinks' read loops share: the effects a step returns to go on
|
|
2
|
+
or to stop reading, and ending a loop with the sink's ``End``."""
|
|
3
|
+
# pyright: reportPrivateUsage=false
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from pyfect._core import Effect, _Succeed, _Sync
|
|
11
|
+
from pyfect.channel._base import end_with
|
|
12
|
+
from pyfect.channel._loop import PullLoop
|
|
13
|
+
from pyfect.pull import catch_done
|
|
14
|
+
from pyfect.sink._sink import End
|
|
15
|
+
|
|
16
|
+
type AnyEffect = Effect[Any, Any, Any]
|
|
17
|
+
|
|
18
|
+
VOID: Effect[None] = _Succeed(None)
|
|
19
|
+
"""A step's way to read on."""
|
|
20
|
+
|
|
21
|
+
ENDED: Effect[Any, Any] = end_with(None)
|
|
22
|
+
"""A step's way to stop reading; also an upstream that has ended."""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def ignore(_: object) -> None:
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def read_until_done(
|
|
30
|
+
step: AnyEffect, end: Callable[[], End[Any, Any]]
|
|
31
|
+
) -> Effect[End[Any, Any], Any, Any]:
|
|
32
|
+
"""Run ``step`` (a pull and what is done with each chunk) until it ends
|
|
33
|
+
with ``Done``, then succeed with ``end()``."""
|
|
34
|
+
return catch_done(PullLoop(step, ignore), lambda _: _Sync(end))
|
pyfect/sink/_taking.py
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""Sinks that take items: ``take``, the ``take_while`` family and the
|
|
2
|
+
``take_until`` family.
|
|
3
|
+
|
|
4
|
+
``take_while`` reads the first item that fails its predicate and drops
|
|
5
|
+
it, as Effect's does; ``take_until`` keeps the item that matches. What
|
|
6
|
+
follows in the same chunk is left over.
|
|
7
|
+
"""
|
|
8
|
+
# pyright: reportPrivateUsage=false
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from collections.abc import Callable, Generator
|
|
13
|
+
from typing import Any, Never, TypeIs, overload
|
|
14
|
+
|
|
15
|
+
from pyfect._core import Effect, _Gen, _Succeed
|
|
16
|
+
from pyfect.result import Err, Ok, Result
|
|
17
|
+
from pyfect.scope import CloseableScope
|
|
18
|
+
from pyfect.sink._sink import Sink, Upstream
|
|
19
|
+
from pyfect.sink._steps import ENDED, VOID, read_until_done
|
|
20
|
+
|
|
21
|
+
type AnyEffect = Effect[Any, Any, Any]
|
|
22
|
+
type Chunk = tuple[Any, ...]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
_REJECTED: Result[Never, None] = Err(None)
|
|
26
|
+
"""What a predicate that fails gives the shared ``take_while`` loop."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _rest(chunk: Chunk, start: int) -> Chunk | None:
|
|
30
|
+
return chunk[start:] or None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def take[In](n: int) -> Sink[list[In], In, In]:
|
|
34
|
+
"""A sink taking the first ``n`` items (none for ``n`` 0 or less); the
|
|
35
|
+
rest of the chunk that reaches ``n`` is left over."""
|
|
36
|
+
count = max(n, 0)
|
|
37
|
+
|
|
38
|
+
def transform(upstream: Upstream[In], _scope: CloseableScope) -> AnyEffect:
|
|
39
|
+
taken: list[In] = []
|
|
40
|
+
if count == 0:
|
|
41
|
+
return _Succeed((taken, None))
|
|
42
|
+
leftover: Chunk | None = None
|
|
43
|
+
|
|
44
|
+
def step(chunk: tuple[In, ...]) -> AnyEffect:
|
|
45
|
+
nonlocal leftover
|
|
46
|
+
room = count - len(taken)
|
|
47
|
+
if len(chunk) < room:
|
|
48
|
+
taken.extend(chunk)
|
|
49
|
+
return VOID
|
|
50
|
+
taken.extend(chunk[:room])
|
|
51
|
+
leftover = _rest(chunk, room)
|
|
52
|
+
return ENDED
|
|
53
|
+
|
|
54
|
+
return read_until_done(upstream.flat_map(step), lambda: (taken, leftover))
|
|
55
|
+
|
|
56
|
+
return Sink(transform)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _taking_while[In](
|
|
60
|
+
keep: Callable[[In], Result[Any, object]],
|
|
61
|
+
) -> Sink[list[Any], In, In]:
|
|
62
|
+
def transform(upstream: Upstream[In], _scope: CloseableScope) -> AnyEffect:
|
|
63
|
+
taken: list[Any] = []
|
|
64
|
+
leftover: Chunk | None = None
|
|
65
|
+
|
|
66
|
+
def step(chunk: tuple[In, ...]) -> AnyEffect:
|
|
67
|
+
nonlocal leftover
|
|
68
|
+
for i, item in enumerate(chunk):
|
|
69
|
+
kept = keep(item)
|
|
70
|
+
if not isinstance(kept, Ok):
|
|
71
|
+
leftover = _rest(chunk, i + 1)
|
|
72
|
+
return ENDED
|
|
73
|
+
taken.append(kept.value)
|
|
74
|
+
return VOID
|
|
75
|
+
|
|
76
|
+
return read_until_done(upstream.flat_map(step), lambda: (taken, leftover))
|
|
77
|
+
|
|
78
|
+
return Sink(transform)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@overload
|
|
82
|
+
def take_while[In, B](predicate: Callable[[In], TypeIs[B]]) -> Sink[list[B], In, In]: ...
|
|
83
|
+
@overload
|
|
84
|
+
def take_while[In](predicate: Callable[[In], bool]) -> Sink[list[In], In, In]: ...
|
|
85
|
+
def take_while(predicate: Callable[[Any], bool]) -> Sink[list[Any], Any, Any]:
|
|
86
|
+
"""A sink taking items while ``predicate`` holds."""
|
|
87
|
+
return _taking_while(lambda item: Ok(item) if predicate(item) else _REJECTED)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def take_while_filter[In, B](f: Callable[[In], Result[B, object]]) -> Sink[list[B], In, In]:
|
|
91
|
+
"""A sink taking the ``Ok`` values of ``f(item)`` until it gives an
|
|
92
|
+
``Err``."""
|
|
93
|
+
return _taking_while(f)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _taking_while_effect[In](
|
|
97
|
+
keep: Callable[[In], Effect[Result[Any, object], Any, Any]],
|
|
98
|
+
) -> Sink[list[Any], In, In, Any, Any]:
|
|
99
|
+
def transform(upstream: Upstream[In], _scope: CloseableScope) -> AnyEffect:
|
|
100
|
+
taken: list[Any] = []
|
|
101
|
+
leftover: Chunk | None = None
|
|
102
|
+
|
|
103
|
+
def step(chunk: tuple[In, ...]) -> AnyEffect:
|
|
104
|
+
def body() -> Generator[AnyEffect, Any, AnyEffect]:
|
|
105
|
+
nonlocal leftover
|
|
106
|
+
for i, item in enumerate(chunk):
|
|
107
|
+
kept: Result[Any, object] = yield keep(item)
|
|
108
|
+
if not isinstance(kept, Ok):
|
|
109
|
+
leftover = _rest(chunk, i + 1)
|
|
110
|
+
return ENDED
|
|
111
|
+
taken.append(kept.value)
|
|
112
|
+
return VOID
|
|
113
|
+
|
|
114
|
+
return _Gen(body).flatten()
|
|
115
|
+
|
|
116
|
+
return read_until_done(upstream.flat_map(step), lambda: (taken, leftover))
|
|
117
|
+
|
|
118
|
+
return Sink(transform)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def take_while_effect[In, E = Never, R = Never](
|
|
122
|
+
predicate: Callable[[In], Effect[bool, E, R]],
|
|
123
|
+
) -> Sink[list[In], In, In, E, R]:
|
|
124
|
+
"""``take_while`` with an effectful ``predicate``."""
|
|
125
|
+
return _taking_while_effect(
|
|
126
|
+
lambda item: predicate(item).map(lambda ok: Ok(item) if ok else _REJECTED)
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def take_while_filter_effect[In, B, E = Never, R = Never](
|
|
131
|
+
f: Callable[[In], Effect[Result[B, object], E, R]],
|
|
132
|
+
) -> Sink[list[B], In, In, E, R]:
|
|
133
|
+
"""``take_while_filter`` with an effectful ``f``."""
|
|
134
|
+
return _taking_while_effect(f)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def take_until[In](predicate: Callable[[In], bool]) -> Sink[list[In], In, In]:
|
|
138
|
+
"""A sink taking items up to and including the first one
|
|
139
|
+
``predicate`` holds for."""
|
|
140
|
+
|
|
141
|
+
def transform(upstream: Upstream[In], _scope: CloseableScope) -> AnyEffect:
|
|
142
|
+
taken: list[In] = []
|
|
143
|
+
leftover: Chunk | None = None
|
|
144
|
+
|
|
145
|
+
def step(chunk: tuple[In, ...]) -> AnyEffect:
|
|
146
|
+
nonlocal leftover
|
|
147
|
+
for i, item in enumerate(chunk):
|
|
148
|
+
taken.append(item)
|
|
149
|
+
if predicate(item):
|
|
150
|
+
leftover = _rest(chunk, i + 1)
|
|
151
|
+
return ENDED
|
|
152
|
+
return VOID
|
|
153
|
+
|
|
154
|
+
return read_until_done(upstream.flat_map(step), lambda: (taken, leftover))
|
|
155
|
+
|
|
156
|
+
return Sink(transform)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def take_until_effect[In, E = Never, R = Never](
|
|
160
|
+
predicate: Callable[[In], Effect[bool, E, R]],
|
|
161
|
+
) -> Sink[list[In], In, In, E, R]:
|
|
162
|
+
"""``take_until`` with an effectful ``predicate``."""
|
|
163
|
+
|
|
164
|
+
def transform(upstream: Upstream[In], _scope: CloseableScope) -> AnyEffect:
|
|
165
|
+
taken: list[In] = []
|
|
166
|
+
leftover: Chunk | None = None
|
|
167
|
+
|
|
168
|
+
def step(chunk: tuple[In, ...]) -> AnyEffect:
|
|
169
|
+
def body() -> Generator[AnyEffect, Any, AnyEffect]:
|
|
170
|
+
nonlocal leftover
|
|
171
|
+
for i, item in enumerate(chunk):
|
|
172
|
+
matched = yield predicate(item)
|
|
173
|
+
taken.append(item)
|
|
174
|
+
if matched:
|
|
175
|
+
leftover = _rest(chunk, i + 1)
|
|
176
|
+
return ENDED
|
|
177
|
+
return VOID
|
|
178
|
+
|
|
179
|
+
return _Gen(body).flatten()
|
|
180
|
+
|
|
181
|
+
return read_until_done(upstream.flat_map(step), lambda: (taken, leftover))
|
|
182
|
+
|
|
183
|
+
return Sink(transform)
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""Sockets (Effect's ``Socket`` and ``NodeSocket``).
|
|
2
|
+
|
|
3
|
+
A ``SocketService`` has a ``reader`` and a ``writer``, both acquired in a
|
|
4
|
+
scope. Acquiring the reader opens the connection (closed with the scope);
|
|
5
|
+
its ``pull`` waits for the next batch of chunks and fails with a
|
|
6
|
+
``SocketError`` once the socket closes (a ``SocketCloseError`` with code
|
|
7
|
+
1000 when the peer ended the stream). The writer writes to the open
|
|
8
|
+
connection; writing a ``CloseEvent`` closes it::
|
|
9
|
+
|
|
10
|
+
socket = make_net(8080, "127.0.0.1")
|
|
11
|
+
|
|
12
|
+
def talk():
|
|
13
|
+
writer = yield socket.writer
|
|
14
|
+
reader = yield socket.reader
|
|
15
|
+
yield writer.write_all([b"ping"])
|
|
16
|
+
return (yield reader.pull)
|
|
17
|
+
|
|
18
|
+
reply = yield from scoped(gen(talk))
|
|
19
|
+
|
|
20
|
+
``to_channel`` and ``to_stream`` turn a socket into a channel (input
|
|
21
|
+
written, output read) or a stream. The live sockets run on an asyncio loop
|
|
22
|
+
of their own, on a background thread, so they work under ``run_blocking`` too.
|
|
23
|
+
``pyfect.socket.server`` listens for connections and
|
|
24
|
+
``pyfect.socket.datagram`` sends and receives UDP packets. ``from_web_socket``
|
|
25
|
+
adapts a browser-style WebSocket and ``make_web_socket`` opens a client
|
|
26
|
+
through the ``WebSocketConstructor`` service, which ``pyfect.socket.ws``
|
|
27
|
+
provides on the ``websockets`` library (extra ``pyfect-dev[websockets]``).
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from pyfect._public import publish
|
|
31
|
+
from pyfect.socket import datagram, server
|
|
32
|
+
from pyfect.socket._errors import (
|
|
33
|
+
CloseEvent,
|
|
34
|
+
OpenErrorKind,
|
|
35
|
+
SocketCloseError,
|
|
36
|
+
SocketError,
|
|
37
|
+
SocketErrorReason,
|
|
38
|
+
SocketOpenError,
|
|
39
|
+
SocketReadError,
|
|
40
|
+
SocketUpgradeError,
|
|
41
|
+
SocketWriteError,
|
|
42
|
+
is_clean_close,
|
|
43
|
+
)
|
|
44
|
+
from pyfect.socket._net import (
|
|
45
|
+
from_socket,
|
|
46
|
+
layer_net,
|
|
47
|
+
layer_tls,
|
|
48
|
+
make_net,
|
|
49
|
+
make_net_channel,
|
|
50
|
+
make_tls,
|
|
51
|
+
make_tls_channel,
|
|
52
|
+
make_unix,
|
|
53
|
+
)
|
|
54
|
+
from pyfect.socket._socket import (
|
|
55
|
+
Chunk,
|
|
56
|
+
PemInput,
|
|
57
|
+
Reader,
|
|
58
|
+
Socket,
|
|
59
|
+
SocketChannel,
|
|
60
|
+
SocketService,
|
|
61
|
+
TlsUpgradeOptions,
|
|
62
|
+
Upgrade,
|
|
63
|
+
Write,
|
|
64
|
+
WriteAll,
|
|
65
|
+
Writer,
|
|
66
|
+
make,
|
|
67
|
+
make_channel,
|
|
68
|
+
reader_bytes,
|
|
69
|
+
reader_string,
|
|
70
|
+
to_channel,
|
|
71
|
+
to_channel_string,
|
|
72
|
+
to_stream,
|
|
73
|
+
unsupported_upgrade,
|
|
74
|
+
)
|
|
75
|
+
from pyfect.socket._web_socket import (
|
|
76
|
+
Listener,
|
|
77
|
+
Pausable,
|
|
78
|
+
WebSocket,
|
|
79
|
+
WebSocketClientOptions,
|
|
80
|
+
WebSocketConstructor,
|
|
81
|
+
WebSocketConstructorService,
|
|
82
|
+
WebSocketEvent,
|
|
83
|
+
WebSocketEventType,
|
|
84
|
+
WebSocketLike,
|
|
85
|
+
from_web_socket,
|
|
86
|
+
layer_web_socket,
|
|
87
|
+
make_web_socket,
|
|
88
|
+
make_web_socket_channel,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
__all__ = [
|
|
92
|
+
"Chunk",
|
|
93
|
+
"CloseEvent",
|
|
94
|
+
"Listener",
|
|
95
|
+
"OpenErrorKind",
|
|
96
|
+
"Pausable",
|
|
97
|
+
"PemInput",
|
|
98
|
+
"Reader",
|
|
99
|
+
"Socket",
|
|
100
|
+
"SocketChannel",
|
|
101
|
+
"SocketCloseError",
|
|
102
|
+
"SocketError",
|
|
103
|
+
"SocketErrorReason",
|
|
104
|
+
"SocketOpenError",
|
|
105
|
+
"SocketReadError",
|
|
106
|
+
"SocketService",
|
|
107
|
+
"SocketUpgradeError",
|
|
108
|
+
"SocketWriteError",
|
|
109
|
+
"TlsUpgradeOptions",
|
|
110
|
+
"Upgrade",
|
|
111
|
+
"WebSocket",
|
|
112
|
+
"WebSocketClientOptions",
|
|
113
|
+
"WebSocketConstructor",
|
|
114
|
+
"WebSocketConstructorService",
|
|
115
|
+
"WebSocketEvent",
|
|
116
|
+
"WebSocketEventType",
|
|
117
|
+
"WebSocketLike",
|
|
118
|
+
"Write",
|
|
119
|
+
"WriteAll",
|
|
120
|
+
"Writer",
|
|
121
|
+
"datagram",
|
|
122
|
+
"from_socket",
|
|
123
|
+
"from_web_socket",
|
|
124
|
+
"is_clean_close",
|
|
125
|
+
"layer_net",
|
|
126
|
+
"layer_tls",
|
|
127
|
+
"layer_web_socket",
|
|
128
|
+
"make",
|
|
129
|
+
"make_channel",
|
|
130
|
+
"make_net",
|
|
131
|
+
"make_net_channel",
|
|
132
|
+
"make_tls",
|
|
133
|
+
"make_tls_channel",
|
|
134
|
+
"make_unix",
|
|
135
|
+
"make_web_socket",
|
|
136
|
+
"make_web_socket_channel",
|
|
137
|
+
"reader_bytes",
|
|
138
|
+
"reader_string",
|
|
139
|
+
"server",
|
|
140
|
+
"to_channel",
|
|
141
|
+
"to_channel_string",
|
|
142
|
+
"to_stream",
|
|
143
|
+
"unsupported_upgrade",
|
|
144
|
+
]
|
|
145
|
+
|
|
146
|
+
publish(globals())
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Connections a server accepted that no ``run`` has taken yet."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import threading
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from typing import Never, Protocol
|
|
8
|
+
|
|
9
|
+
from pyfect._core import Effect
|
|
10
|
+
from pyfect.socket._connection import Signal
|
|
11
|
+
from pyfect.socket._socket import SocketService
|
|
12
|
+
|
|
13
|
+
type Handler[E, R] = Callable[[SocketService], Effect[object, E, R]]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Incoming(Protocol):
|
|
17
|
+
"""An accepted connection: ``handle`` runs the handler on its socket;
|
|
18
|
+
``release`` closes it once the handler's fiber is done (gracefully);
|
|
19
|
+
``abort`` closes it at once."""
|
|
20
|
+
|
|
21
|
+
def handle[E, R](self, handler: Handler[E, R]) -> Effect[None, Never, R]: ...
|
|
22
|
+
|
|
23
|
+
def release(self) -> None: ...
|
|
24
|
+
|
|
25
|
+
def abort(self) -> None: ...
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Accepted:
|
|
29
|
+
"""Connections the server accepted that no run has taken yet. Once
|
|
30
|
+
closed (with the server), a connection made late is aborted."""
|
|
31
|
+
|
|
32
|
+
__slots__ = ("_closed", "_pending", "lock", "signal")
|
|
33
|
+
|
|
34
|
+
def __init__(self) -> None:
|
|
35
|
+
self.lock = threading.Lock()
|
|
36
|
+
self.signal = Signal(self.lock)
|
|
37
|
+
self._pending: list[Incoming] = []
|
|
38
|
+
self._closed = False
|
|
39
|
+
|
|
40
|
+
def add(self, incoming: Incoming) -> None:
|
|
41
|
+
with self.lock:
|
|
42
|
+
closed = self._closed
|
|
43
|
+
if not closed:
|
|
44
|
+
self._pending.append(incoming)
|
|
45
|
+
waiters = self.signal.notify_locked()
|
|
46
|
+
if closed:
|
|
47
|
+
incoming.abort()
|
|
48
|
+
for wake in waiters:
|
|
49
|
+
wake()
|
|
50
|
+
|
|
51
|
+
def has_pending(self) -> bool:
|
|
52
|
+
return bool(self._pending)
|
|
53
|
+
|
|
54
|
+
def take(self) -> list[Incoming]:
|
|
55
|
+
with self.lock:
|
|
56
|
+
taken, self._pending = self._pending, []
|
|
57
|
+
return taken
|
|
58
|
+
|
|
59
|
+
def close(self) -> None:
|
|
60
|
+
"""Abort the pending connections and every later one."""
|
|
61
|
+
with self.lock:
|
|
62
|
+
self._closed = True
|
|
63
|
+
taken, self._pending = self._pending, []
|
|
64
|
+
for incoming in taken:
|
|
65
|
+
incoming.abort()
|