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,279 @@
|
|
|
1
|
+
"""``Stream`` methods that combine two streams: zipping them item by item,
|
|
2
|
+
pairing their latest items, crossing them, merging them as their items
|
|
3
|
+
come, interleaving them and racing them."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Never, overload
|
|
9
|
+
|
|
10
|
+
from pyfect.stream._base import A_co, E_co, R_co, StreamBase, require_stream
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pyfect._core import Effect
|
|
14
|
+
from pyfect.channel._concurrency_methods import HaltStrategy
|
|
15
|
+
from pyfect.errors import Done
|
|
16
|
+
from pyfect.pull import Pull
|
|
17
|
+
from pyfect.result import Result
|
|
18
|
+
from pyfect.stream._stream import Stream
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ZipMethods(StreamBase[A_co, E_co, R_co]):
|
|
22
|
+
__slots__ = ()
|
|
23
|
+
|
|
24
|
+
# --- zipping --------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
def zip[B, E2 = Never, R2 = Never](
|
|
27
|
+
self, that: Stream[B, E2, R2]
|
|
28
|
+
) -> Stream[tuple[A_co, B], E_co | E2, R_co | R2]:
|
|
29
|
+
"""Pair the items of both streams in order, pulling both at once;
|
|
30
|
+
end when either ends."""
|
|
31
|
+
require_stream(that, "that")
|
|
32
|
+
return self.zip_with(that, _pair)
|
|
33
|
+
|
|
34
|
+
def zip_with[B, C, E2 = Never, R2 = Never](
|
|
35
|
+
self, that: Stream[B, E2, R2], f: Callable[[A_co, B], C]
|
|
36
|
+
) -> Stream[C, E_co | E2, R_co | R2]:
|
|
37
|
+
"""``zip``, writing ``f(left, right)`` for each pair."""
|
|
38
|
+
from pyfect.stream import _zipping
|
|
39
|
+
|
|
40
|
+
require_stream(that, "that")
|
|
41
|
+
return _zipping.zip_with(self, that, f)
|
|
42
|
+
|
|
43
|
+
def zip_with_array[B, C, E2 = Never, R2 = Never](
|
|
44
|
+
self,
|
|
45
|
+
that: Stream[B, E2, R2],
|
|
46
|
+
f: Callable[
|
|
47
|
+
[tuple[A_co, ...], tuple[B, ...]],
|
|
48
|
+
tuple[tuple[C, ...], tuple[A_co, ...], tuple[B, ...]],
|
|
49
|
+
],
|
|
50
|
+
) -> Stream[C, E_co | E2, R_co | R2]:
|
|
51
|
+
"""Zip chunk by chunk: ``f(left, right)`` gives the chunk to write
|
|
52
|
+
and the left and right items it left over, which the next call gets
|
|
53
|
+
before anything new is pulled from that side."""
|
|
54
|
+
from pyfect.stream import _zipping
|
|
55
|
+
|
|
56
|
+
require_stream(that, "that")
|
|
57
|
+
return _zipping.zip_with_array(self, that, f)
|
|
58
|
+
|
|
59
|
+
def zip_left[E2 = Never, R2 = Never](
|
|
60
|
+
self, that: Stream[object, E2, R2]
|
|
61
|
+
) -> Stream[A_co, E_co | E2, R_co | R2]:
|
|
62
|
+
"""``zip``, keeping the left items."""
|
|
63
|
+
require_stream(that, "that")
|
|
64
|
+
return self.zip_with(that, _left)
|
|
65
|
+
|
|
66
|
+
def zip_right[B, E2 = Never, R2 = Never](
|
|
67
|
+
self, that: Stream[B, E2, R2]
|
|
68
|
+
) -> Stream[B, E_co | E2, R_co | R2]:
|
|
69
|
+
"""``zip``, keeping the right items."""
|
|
70
|
+
require_stream(that, "that")
|
|
71
|
+
return self.zip_with(that, _right)
|
|
72
|
+
|
|
73
|
+
def zip_flatten[*Ts, B, E2 = Never, R2 = Never](
|
|
74
|
+
self: ZipMethods[tuple[*Ts], E_co, R_co], that: Stream[B, E2, R2]
|
|
75
|
+
) -> Stream[tuple[*Ts, B], E_co | E2, R_co | R2]:
|
|
76
|
+
"""``zip`` for a stream of tuples: append each right item to its
|
|
77
|
+
left tuple."""
|
|
78
|
+
require_stream(that, "that")
|
|
79
|
+
return self.zip_with(that, lambda left, right: (*left, right))
|
|
80
|
+
|
|
81
|
+
def zip_latest[B, E2 = Never, R2 = Never](
|
|
82
|
+
self, that: Stream[B, E2, R2]
|
|
83
|
+
) -> Stream[tuple[A_co, B], E_co | E2, R_co | R2]:
|
|
84
|
+
"""Once both streams have written, pair each new item with the
|
|
85
|
+
other stream's latest; end when either ends."""
|
|
86
|
+
from pyfect.stream import _zipping
|
|
87
|
+
|
|
88
|
+
require_stream(that, "that")
|
|
89
|
+
return _zipping.zip_latest_all(self, that)
|
|
90
|
+
|
|
91
|
+
def zip_latest_with[B, C, E2 = Never, R2 = Never](
|
|
92
|
+
self, that: Stream[B, E2, R2], f: Callable[[A_co, B], C]
|
|
93
|
+
) -> Stream[C, E_co | E2, R_co | R2]:
|
|
94
|
+
"""``zip_latest``, writing ``f(left, right)`` for each pair."""
|
|
95
|
+
require_stream(that, "that")
|
|
96
|
+
return self.zip_latest(that).map(lambda pair: f(*pair))
|
|
97
|
+
|
|
98
|
+
def cross[B, E2 = Never, R2 = Never](
|
|
99
|
+
self, that: Stream[B, E2, R2]
|
|
100
|
+
) -> Stream[tuple[A_co, B], E_co | E2, R_co | R2]:
|
|
101
|
+
"""Every pair of a left and a right item: ``that`` runs again for
|
|
102
|
+
each left item."""
|
|
103
|
+
require_stream(that, "that")
|
|
104
|
+
return self.cross_with(that, _pair)
|
|
105
|
+
|
|
106
|
+
def cross_with[B, C, E2 = Never, R2 = Never](
|
|
107
|
+
self, that: Stream[B, E2, R2], f: Callable[[A_co, B], C]
|
|
108
|
+
) -> Stream[C, E_co | E2, R_co | R2]:
|
|
109
|
+
"""``cross``, writing ``f(left, right)`` for each pair."""
|
|
110
|
+
from pyfect.stream._base import as_stream
|
|
111
|
+
|
|
112
|
+
require_stream(that, "that")
|
|
113
|
+
return as_stream(self).flat_map(lambda left: that.map(lambda right: f(left, right)))
|
|
114
|
+
|
|
115
|
+
# --- merging --------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
def merge[B, E2 = Never, R2 = Never](
|
|
118
|
+
self, that: Stream[B, E2, R2], *, halt_strategy: HaltStrategy = "both"
|
|
119
|
+
) -> Stream[A_co | B, E_co | E2, R_co | R2]:
|
|
120
|
+
"""Run both streams at once, writing items as either writes them.
|
|
121
|
+
The merge ends when both have ended, or just the ``"left"`` (this)
|
|
122
|
+
or ``"right"`` one, or ``"either"``; a failure of either fails it."""
|
|
123
|
+
from pyfect.stream._stream import Stream
|
|
124
|
+
|
|
125
|
+
require_stream(that, "that")
|
|
126
|
+
return Stream(self._channel.merge(that._channel, halt_strategy=halt_strategy))
|
|
127
|
+
|
|
128
|
+
def merge_effect[E2 = Never, R2 = Never](
|
|
129
|
+
self, eff: Effect[object, E2, R2]
|
|
130
|
+
) -> Stream[A_co, E_co | E2, R_co | R2]:
|
|
131
|
+
"""Run ``eff`` alongside the stream: its failure fails the stream;
|
|
132
|
+
it is interrupted when the stream ends."""
|
|
133
|
+
from pyfect._effect_args import require_effect
|
|
134
|
+
from pyfect.stream._stream import Stream
|
|
135
|
+
|
|
136
|
+
require_effect(eff, "eff")
|
|
137
|
+
return Stream(self._channel.merge_effect(eff))
|
|
138
|
+
|
|
139
|
+
def merge_result[B, E2 = Never, R2 = Never](
|
|
140
|
+
self, that: Stream[B, E2, R2]
|
|
141
|
+
) -> Stream[Result[A_co, B], E_co | E2, R_co | R2]:
|
|
142
|
+
"""``merge``, writing this stream's items as ``Ok`` and ``that``'s as
|
|
143
|
+
``Err``."""
|
|
144
|
+
from pyfect.result import Err, Ok
|
|
145
|
+
from pyfect.stream._base import as_stream
|
|
146
|
+
|
|
147
|
+
require_stream(that, "that")
|
|
148
|
+
lefts: Stream[Result[A_co, B], E_co, R_co] = as_stream(self).map(Ok)
|
|
149
|
+
return lefts.merge(that.map(Err))
|
|
150
|
+
|
|
151
|
+
def merge_left[E2 = Never, R2 = Never](
|
|
152
|
+
self, that: Stream[object, E2, R2]
|
|
153
|
+
) -> Stream[A_co, E_co | E2, R_co | R2]:
|
|
154
|
+
"""Run ``that`` alongside for its effects, writing this stream's
|
|
155
|
+
items."""
|
|
156
|
+
require_stream(that, "that")
|
|
157
|
+
return self.merge_effect(that.run_drain())
|
|
158
|
+
|
|
159
|
+
def merge_right[B, E2 = Never, R2 = Never](
|
|
160
|
+
self, that: Stream[B, E2, R2]
|
|
161
|
+
) -> Stream[B, E_co | E2, R_co | R2]:
|
|
162
|
+
"""Run this stream alongside for its effects, writing ``that``'s
|
|
163
|
+
items."""
|
|
164
|
+
from pyfect.stream._base import as_stream
|
|
165
|
+
|
|
166
|
+
require_stream(that, "that")
|
|
167
|
+
return that.merge_effect(as_stream(self).run_drain())
|
|
168
|
+
|
|
169
|
+
# --- combining with state ---------------------------------------------------
|
|
170
|
+
|
|
171
|
+
@overload
|
|
172
|
+
def combine[B, E2, S, C, RR = Never](
|
|
173
|
+
self,
|
|
174
|
+
that: Stream[B, E2, RR],
|
|
175
|
+
initial: Callable[[], S],
|
|
176
|
+
f: Callable[[S, Pull[A_co, E_co], Pull[B, E2]], Effect[tuple[C, S], Done, RR]],
|
|
177
|
+
) -> Stream[C, Never, R_co | RR]: ...
|
|
178
|
+
@overload
|
|
179
|
+
def combine[B, E2, S, C, EE = Never, RR = Never](
|
|
180
|
+
self,
|
|
181
|
+
that: Stream[B, E2, RR],
|
|
182
|
+
initial: Callable[[], S],
|
|
183
|
+
f: Callable[[S, Pull[A_co, E_co], Pull[B, E2]], Effect[tuple[C, S], EE | Done, RR]],
|
|
184
|
+
) -> Stream[C, EE, R_co | RR]: ...
|
|
185
|
+
def combine(
|
|
186
|
+
self,
|
|
187
|
+
that: Stream[Any, Any, Any],
|
|
188
|
+
initial: Callable[[], Any],
|
|
189
|
+
f: Callable[[Any, Any, Any], Effect[tuple[Any, Any], Any, Any]],
|
|
190
|
+
) -> Stream[Any, Any, Any]:
|
|
191
|
+
"""Write what ``f(state, pull_left, pull_right)`` makes, threading
|
|
192
|
+
its state; ``f`` pulls single items from either side as it likes and
|
|
193
|
+
ends the stream by failing with ``Done`` (as a pull of an ended side
|
|
194
|
+
does)."""
|
|
195
|
+
from pyfect.stream._mapping import one
|
|
196
|
+
from pyfect.stream._stream import Stream
|
|
197
|
+
|
|
198
|
+
require_stream(that, "that")
|
|
199
|
+
items = self._channel.flatten_array()
|
|
200
|
+
combined = items.combine(that._channel.flatten_array(), initial, f)
|
|
201
|
+
return Stream(combined.map(one))
|
|
202
|
+
|
|
203
|
+
@overload
|
|
204
|
+
def combine_array[B, E2, S, C, RR = Never](
|
|
205
|
+
self,
|
|
206
|
+
that: Stream[B, E2, RR],
|
|
207
|
+
initial: Callable[[], S],
|
|
208
|
+
f: Callable[
|
|
209
|
+
[S, Pull[tuple[A_co, ...], E_co], Pull[tuple[B, ...], E2]],
|
|
210
|
+
Effect[tuple[tuple[C, ...], S], Done, RR],
|
|
211
|
+
],
|
|
212
|
+
) -> Stream[C, Never, R_co | RR]: ...
|
|
213
|
+
@overload
|
|
214
|
+
def combine_array[B, E2, S, C, EE = Never, RR = Never](
|
|
215
|
+
self,
|
|
216
|
+
that: Stream[B, E2, RR],
|
|
217
|
+
initial: Callable[[], S],
|
|
218
|
+
f: Callable[
|
|
219
|
+
[S, Pull[tuple[A_co, ...], E_co], Pull[tuple[B, ...], E2]],
|
|
220
|
+
Effect[tuple[tuple[C, ...], S], EE | Done, RR],
|
|
221
|
+
],
|
|
222
|
+
) -> Stream[C, EE, R_co | RR]: ...
|
|
223
|
+
def combine_array(
|
|
224
|
+
self,
|
|
225
|
+
that: Stream[Any, Any, Any],
|
|
226
|
+
initial: Callable[[], Any],
|
|
227
|
+
f: Callable[[Any, Any, Any], Effect[tuple[Any, Any], Any, Any]],
|
|
228
|
+
) -> Stream[Any, Any, Any]:
|
|
229
|
+
"""``combine`` a chunk at a time: the pulls give chunks, and ``f``
|
|
230
|
+
makes a non-empty tuple of items to write."""
|
|
231
|
+
from pyfect.stream._stream import Stream
|
|
232
|
+
|
|
233
|
+
require_stream(that, "that")
|
|
234
|
+
return Stream(self._channel.combine(that._channel, initial, f))
|
|
235
|
+
|
|
236
|
+
# --- interleaving and racing ----------------------------------------------
|
|
237
|
+
|
|
238
|
+
def interleave[B, E2 = Never, R2 = Never](
|
|
239
|
+
self, that: Stream[B, E2, R2]
|
|
240
|
+
) -> Stream[A_co | B, E_co | E2, R_co | R2]:
|
|
241
|
+
"""Alternate items from this stream and ``that``, starting here; when
|
|
242
|
+
one ends, write the rest of the other."""
|
|
243
|
+
from pyfect.stream import _zipping
|
|
244
|
+
|
|
245
|
+
require_stream(that, "that")
|
|
246
|
+
return _zipping.interleave_with(self, that, _zipping.alternating())
|
|
247
|
+
|
|
248
|
+
def interleave_with[B, EE = Never, RR = Never](
|
|
249
|
+
self, that: Stream[B, EE, RR], decider: Stream[bool, EE, RR]
|
|
250
|
+
) -> Stream[A_co | B, E_co | EE, R_co | RR]:
|
|
251
|
+
"""Take the next item from this stream when ``decider`` writes
|
|
252
|
+
``True`` and from ``that`` when it writes ``False``, skipping a side
|
|
253
|
+
that has ended; end when both have ended or ``decider`` does."""
|
|
254
|
+
from pyfect.stream import _zipping
|
|
255
|
+
|
|
256
|
+
require_stream(that, "that")
|
|
257
|
+
require_stream(decider, "decider")
|
|
258
|
+
return _zipping.interleave_with(self, that, decider)
|
|
259
|
+
|
|
260
|
+
def race[B, E2 = Never, R2 = Never](
|
|
261
|
+
self, that: Stream[B, E2, R2]
|
|
262
|
+
) -> Stream[A_co | B, E_co | E2, R_co | R2]:
|
|
263
|
+
"""The stream that writes first; the other is interrupted."""
|
|
264
|
+
from pyfect.stream import _zipping
|
|
265
|
+
|
|
266
|
+
require_stream(that, "that")
|
|
267
|
+
return _zipping.race_all(self, that)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _pair[A, B](left: A, right: B) -> tuple[A, B]:
|
|
271
|
+
return (left, right)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def _left[A](left: A, _: object) -> A:
|
|
275
|
+
return left
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def _right[B](_: object, right: B) -> B:
|
|
279
|
+
return right
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""The work behind zipping, ``zip_latest_all``, interleaving and racing
|
|
2
|
+
streams."""
|
|
3
|
+
# pyright: reportPrivateUsage=false
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import itertools
|
|
8
|
+
from collections.abc import Callable, Generator
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from pyfect import channel
|
|
12
|
+
from pyfect._core import Effect, _Gen, _Succeed, _Suspend, _Sync
|
|
13
|
+
from pyfect._fiber_all import join_all
|
|
14
|
+
from pyfect.channel import Channel
|
|
15
|
+
from pyfect.channel._base import end_with
|
|
16
|
+
from pyfect.exit import Exit, Success
|
|
17
|
+
from pyfect.latch import Latch
|
|
18
|
+
from pyfect.pull import catch_done
|
|
19
|
+
from pyfect.scope import CloseableScope
|
|
20
|
+
from pyfect.stream._base import AnyStream
|
|
21
|
+
from pyfect.stream._stream import Stream
|
|
22
|
+
|
|
23
|
+
type AnyEffect = Effect[Any, Any, Any]
|
|
24
|
+
type Chunk = tuple[Any, ...]
|
|
25
|
+
type AnyStream_ = Stream[Any, Any, Any]
|
|
26
|
+
type AnyChannel = Channel[Any, Any, Any, Any, Any, Any, Any]
|
|
27
|
+
|
|
28
|
+
_ENDED: AnyEffect = end_with(None)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# --- zipping ------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def zip_with_array(
|
|
35
|
+
left: AnyStream,
|
|
36
|
+
right: AnyStream,
|
|
37
|
+
f: Callable[[Chunk, Chunk], tuple[Chunk, Chunk, Chunk]],
|
|
38
|
+
) -> AnyStream_:
|
|
39
|
+
def transform(_up: AnyEffect, scope: CloseableScope, _forked: CloseableScope) -> AnyEffect:
|
|
40
|
+
def body() -> Generator[AnyEffect, Any, AnyEffect]:
|
|
41
|
+
pull_left: AnyEffect = yield left._channel.to_pull_scoped(scope)
|
|
42
|
+
pull_right: AnyEffect = yield right._channel.to_pull_scoped(scope)
|
|
43
|
+
|
|
44
|
+
def both() -> Generator[AnyEffect, Any, list[Chunk]]:
|
|
45
|
+
fiber_left = yield pull_left.fork_in(scope)
|
|
46
|
+
fiber_right = yield pull_right.fork_in(scope)
|
|
47
|
+
return (yield join_all([fiber_left, fiber_right]))
|
|
48
|
+
|
|
49
|
+
pull_both = _Gen(both)
|
|
50
|
+
held_left: Chunk = ()
|
|
51
|
+
held_right: Chunk = ()
|
|
52
|
+
|
|
53
|
+
def pull() -> Generator[AnyEffect, Any, Chunk]:
|
|
54
|
+
nonlocal held_left, held_right
|
|
55
|
+
if held_left:
|
|
56
|
+
pair = (held_left, held_right or (yield pull_right))
|
|
57
|
+
elif held_right:
|
|
58
|
+
pair = ((yield pull_left), held_right)
|
|
59
|
+
else:
|
|
60
|
+
pair = tuple((yield pull_both))
|
|
61
|
+
output, held_left, held_right = f(*pair)
|
|
62
|
+
return output
|
|
63
|
+
|
|
64
|
+
return _Gen(pull)
|
|
65
|
+
|
|
66
|
+
return _Gen(body)
|
|
67
|
+
|
|
68
|
+
return Stream(channel.from_transform_bracket(transform))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def zip_with(left: AnyStream, right: AnyStream, f: Callable[[Any, Any], Any]) -> AnyStream_:
|
|
72
|
+
from pyfect.stream._constructors import suspend
|
|
73
|
+
|
|
74
|
+
def make() -> AnyStream_:
|
|
75
|
+
# Cursors into the current chunks, so a long chunk is not copied on
|
|
76
|
+
# every pull.
|
|
77
|
+
left_index = 0
|
|
78
|
+
right_index = 0
|
|
79
|
+
|
|
80
|
+
def step(lefts: Chunk, rights: Chunk) -> tuple[Chunk, Chunk, Chunk]:
|
|
81
|
+
nonlocal left_index, right_index
|
|
82
|
+
length = min(len(lefts) - left_index, len(rights) - right_index)
|
|
83
|
+
output = tuple(f(lefts[left_index + i], rights[right_index + i]) for i in range(length))
|
|
84
|
+
left_index += length
|
|
85
|
+
right_index += length
|
|
86
|
+
left_done = left_index == len(lefts)
|
|
87
|
+
right_done = right_index == len(rights)
|
|
88
|
+
if left_done:
|
|
89
|
+
left_index = 0
|
|
90
|
+
if right_done:
|
|
91
|
+
right_index = 0
|
|
92
|
+
return output, () if left_done else lefts, () if right_done else rights
|
|
93
|
+
|
|
94
|
+
return zip_with_array(left, right, step)
|
|
95
|
+
|
|
96
|
+
return suspend(make)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
_NOTHING: Any = object()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def zip_latest_all(*streams: AnyStream) -> AnyStream_:
|
|
103
|
+
def make() -> AnyChannel:
|
|
104
|
+
count = len(streams)
|
|
105
|
+
latest: list[Any] = [None] * count
|
|
106
|
+
emitted: set[int] = set()
|
|
107
|
+
ready = Latch()
|
|
108
|
+
empty = Latch()
|
|
109
|
+
|
|
110
|
+
def side(index: int, stream: AnyStream) -> AnyChannel:
|
|
111
|
+
def on_item(item: Any) -> AnyEffect:
|
|
112
|
+
latest[index] = item
|
|
113
|
+
if index in emitted:
|
|
114
|
+
return _Succeed((tuple(latest),))
|
|
115
|
+
emitted.add(index)
|
|
116
|
+
if len(emitted) < count:
|
|
117
|
+
return ready.wait().as_(_NOTHING)
|
|
118
|
+
return ready.open().as_((tuple(latest),))
|
|
119
|
+
|
|
120
|
+
# A side ending without an item makes a full tuple impossible.
|
|
121
|
+
return (
|
|
122
|
+
stream._channel.flatten_array()
|
|
123
|
+
.map_effect(on_item)
|
|
124
|
+
.filter(lambda chunk: chunk is not _NOTHING)
|
|
125
|
+
.map_done_effect(lambda _: _Succeed(None) if index in emitted else empty.open())
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
sides = channel.from_iterable([side(i, s) for i, s in enumerate(streams)])
|
|
129
|
+
merged = sides.merge_all(concurrency="unbounded", buffer_size=0)
|
|
130
|
+
return merged.interrupt_when(empty.wait())
|
|
131
|
+
|
|
132
|
+
return Stream(channel.suspend(make))
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
# --- interleaving -------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def alternating() -> AnyStream_:
|
|
139
|
+
from pyfect.stream._constructors import from_iterable
|
|
140
|
+
|
|
141
|
+
return from_iterable(itertools.cycle((True, False)))
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
_RETRY: Any = object()
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def interleave_with(left: AnyStream, right: AnyStream, decider: AnyStream) -> AnyStream_:
|
|
148
|
+
def transform(_up: AnyEffect, scope: CloseableScope) -> AnyEffect:
|
|
149
|
+
def body() -> Generator[AnyEffect, Any, AnyEffect]:
|
|
150
|
+
pull_decider: AnyEffect = yield decider._channel.flatten_array().to_pull_scoped(scope)
|
|
151
|
+
pull_left: AnyEffect = yield left._channel.flatten_array().to_pull_scoped(scope)
|
|
152
|
+
pull_right: AnyEffect = yield right._channel.flatten_array().to_pull_scoped(scope)
|
|
153
|
+
done = [False, False]
|
|
154
|
+
|
|
155
|
+
def ending(index: int) -> Callable[[object], AnyEffect]:
|
|
156
|
+
def end(_: object) -> AnyEffect:
|
|
157
|
+
done[index] = True
|
|
158
|
+
return _Succeed(_RETRY)
|
|
159
|
+
|
|
160
|
+
return end
|
|
161
|
+
|
|
162
|
+
sides = (catch_done(pull_left, ending(0)), catch_done(pull_right, ending(1)))
|
|
163
|
+
|
|
164
|
+
def pull() -> Generator[AnyEffect, Any, Chunk]:
|
|
165
|
+
while True:
|
|
166
|
+
if done[0] and done[1]:
|
|
167
|
+
return (yield _ENDED)
|
|
168
|
+
use_left: bool = yield pull_decider
|
|
169
|
+
index = 0 if use_left else 1
|
|
170
|
+
if done[index]:
|
|
171
|
+
continue
|
|
172
|
+
item = yield sides[index]
|
|
173
|
+
if item is _RETRY:
|
|
174
|
+
continue
|
|
175
|
+
return (item,)
|
|
176
|
+
|
|
177
|
+
return _Gen(pull)
|
|
178
|
+
|
|
179
|
+
return _Gen(body)
|
|
180
|
+
|
|
181
|
+
return Stream(channel.from_transform(transform))
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
# --- racing -------------------------------------------------------------------
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def race_all(*streams: AnyStream) -> AnyStream_:
|
|
188
|
+
from pyfect._concurrency import race_all as race_effects
|
|
189
|
+
|
|
190
|
+
def transform(_up: AnyEffect, scope: CloseableScope) -> AnyEffect:
|
|
191
|
+
def make() -> AnyEffect:
|
|
192
|
+
winner: list[AnyEffect] = []
|
|
193
|
+
|
|
194
|
+
def contender(stream: AnyStream) -> AnyEffect:
|
|
195
|
+
child = scope.fork_unsafe()
|
|
196
|
+
|
|
197
|
+
def settle(ex: Exit[Any, Any]) -> AnyEffect:
|
|
198
|
+
if isinstance(ex, Success) and not winner:
|
|
199
|
+
winner.append(ex.value[0])
|
|
200
|
+
return _Succeed(None)
|
|
201
|
+
return child.close(ex)
|
|
202
|
+
|
|
203
|
+
started = stream._channel.to_pull_scoped(child).flat_map(
|
|
204
|
+
lambda pull: pull.map(lambda chunk: (pull, chunk))
|
|
205
|
+
)
|
|
206
|
+
return started.on_exit(settle).map(lambda pair: pair[1])
|
|
207
|
+
|
|
208
|
+
race = race_effects(*(contender(s) for s in streams))
|
|
209
|
+
return _Suspend(lambda: winner[0] if winner else race)
|
|
210
|
+
|
|
211
|
+
return _Sync(make)
|
|
212
|
+
|
|
213
|
+
return Stream(channel.from_transform(transform))
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""``SubscriptionRef[A]``: a ``SynchronizedRef`` that publishes every value
|
|
2
|
+
it stores.
|
|
3
|
+
|
|
4
|
+
``subscribe()`` gives a ``pubsub.Subscription`` for the current scope: its
|
|
5
|
+
first ``take`` is the current value, then every value stored after it, in
|
|
6
|
+
order. Each update stores (and publishes) once, under the ref's lock, so
|
|
7
|
+
subscribers see the values in the order they were set; a ``*_some``
|
|
8
|
+
update that keeps the value publishes nothing.
|
|
9
|
+
|
|
10
|
+
``changes()`` is the same as a ``Stream``: the current value, then every
|
|
11
|
+
later one, from a subscription made when the stream starts.
|
|
12
|
+
"""
|
|
13
|
+
# pyright: reportPrivateUsage=false
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import TYPE_CHECKING, Never, overload
|
|
18
|
+
|
|
19
|
+
from pyfect._core import Effect, _Sync
|
|
20
|
+
from pyfect._locked_ref import LockedRef
|
|
21
|
+
from pyfect._unsubscripted import Unsubscripted
|
|
22
|
+
from pyfect.pubsub import Atomic, PubSub, Subscription
|
|
23
|
+
from pyfect.scope import Scope
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from pyfect.stream import Stream
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SubscriptionRef[A = Unsubscripted](LockedRef[A]):
|
|
30
|
+
__slots__ = ("_pubsub",)
|
|
31
|
+
|
|
32
|
+
def __init__(self, value: A) -> None:
|
|
33
|
+
super().__init__(value)
|
|
34
|
+
self._pubsub = PubSub(Atomic[A].unbounded(replay=1), "dropping")
|
|
35
|
+
self._pubsub.publish_unsafe(value)
|
|
36
|
+
|
|
37
|
+
@overload
|
|
38
|
+
@classmethod
|
|
39
|
+
def make[T](
|
|
40
|
+
cls: type[SubscriptionRef[Unsubscripted]], value: T
|
|
41
|
+
) -> Effect[SubscriptionRef[T]]: ...
|
|
42
|
+
@overload
|
|
43
|
+
@classmethod
|
|
44
|
+
def make(cls, value: A) -> Effect[SubscriptionRef[A]]: ...
|
|
45
|
+
@classmethod
|
|
46
|
+
def make[T](cls, value: T) -> Effect[SubscriptionRef[T]]:
|
|
47
|
+
return _Sync(lambda: SubscriptionRef(value))
|
|
48
|
+
|
|
49
|
+
def _store(self, value: A) -> None:
|
|
50
|
+
self._value = value
|
|
51
|
+
self._pubsub.publish_unsafe(value)
|
|
52
|
+
|
|
53
|
+
def subscribe(self) -> Effect[Subscription[A], Never, Scope]:
|
|
54
|
+
"""Subscribe until the current scope closes: the current value, then
|
|
55
|
+
every later one."""
|
|
56
|
+
return self._pubsub.subscribe()
|
|
57
|
+
|
|
58
|
+
def changes(self) -> Stream[A]:
|
|
59
|
+
"""A stream of the current value, then every later one (Effect's
|
|
60
|
+
``SubscriptionRef.changes``). Each run subscribes anew."""
|
|
61
|
+
from pyfect.stream import from_pubsub
|
|
62
|
+
|
|
63
|
+
return from_pubsub(self._pubsub)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
__all__ = ["SubscriptionRef"]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""``SynchronizedRef[A]``: a ``Ref`` whose updates can run effects.
|
|
2
|
+
|
|
3
|
+
Updates take turns: each holds the ref's one-permit lock from reading the
|
|
4
|
+
value to storing the new one, so ``update_effect(f)`` never loses a
|
|
5
|
+
concurrent update while ``f``'s effect runs. If the effect fails or is
|
|
6
|
+
interrupted, the value is unchanged. ``get`` never waits. An update
|
|
7
|
+
started from inside another update's effect waits forever, as in Effect.
|
|
8
|
+
"""
|
|
9
|
+
# pyright: reportPrivateUsage=false
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import overload
|
|
14
|
+
|
|
15
|
+
from pyfect._core import Effect, _Sync
|
|
16
|
+
from pyfect._locked_ref import LockedRef
|
|
17
|
+
from pyfect._unsubscripted import Unsubscripted
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SynchronizedRef[A = Unsubscripted](LockedRef[A]):
|
|
21
|
+
"""``SynchronizedRef(value)`` is Effect's ``makeUnsafe``."""
|
|
22
|
+
|
|
23
|
+
__slots__ = ()
|
|
24
|
+
|
|
25
|
+
@overload
|
|
26
|
+
@classmethod
|
|
27
|
+
def make[T](
|
|
28
|
+
cls: type[SynchronizedRef[Unsubscripted]], value: T
|
|
29
|
+
) -> Effect[SynchronizedRef[T]]: ...
|
|
30
|
+
@overload
|
|
31
|
+
@classmethod
|
|
32
|
+
def make(cls, value: A) -> Effect[SynchronizedRef[A]]: ...
|
|
33
|
+
@classmethod
|
|
34
|
+
def make[T](cls, value: T) -> Effect[SynchronizedRef[T]]:
|
|
35
|
+
return _Sync(lambda: SynchronizedRef(value))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
__all__ = ["SynchronizedRef"]
|
pyfect/take.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""``Take[A, E, L]``: one stored pull result (Effect's ``Take``).
|
|
2
|
+
|
|
3
|
+
A take is a non-empty tuple of items, a ``Failure`` holding the producer's
|
|
4
|
+
error, or a ``Success`` holding its ``Done`` leftover. Store or send takes
|
|
5
|
+
(through a queue, say) and replay them later with ``to_pull``.
|
|
6
|
+
"""
|
|
7
|
+
# pyright: reportPrivateUsage=false
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Never
|
|
12
|
+
|
|
13
|
+
from pyfect._core import Effect, _FailCause, _Succeed
|
|
14
|
+
from pyfect.cause import fail
|
|
15
|
+
from pyfect.errors import Done
|
|
16
|
+
from pyfect.exit import Exit, Failure, Success
|
|
17
|
+
from pyfect.pull import Pull
|
|
18
|
+
|
|
19
|
+
type Take[A, E = Never, L = None] = tuple[A, ...] | Exit[L, E]
|
|
20
|
+
"""Items (never an empty tuple), a failure, or the end with its leftover."""
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def to_pull[A = Never, E = Never, L = None](take: Take[A, E, L]) -> Pull[tuple[A, ...], E, L]:
|
|
24
|
+
"""The pull step ``take`` stands for: succeed with its items, fail with
|
|
25
|
+
its failure, or end with ``Done(leftover)``."""
|
|
26
|
+
match take:
|
|
27
|
+
case Success(value):
|
|
28
|
+
return _FailCause(fail(Done(value)))
|
|
29
|
+
case Failure(cause):
|
|
30
|
+
fails: Effect[Never, E] = _FailCause(cause)
|
|
31
|
+
return fails
|
|
32
|
+
case items:
|
|
33
|
+
return _Succeed(items)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
__all__ = ["Take", "to_pull"]
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""The terminal as a service (Effect's ``Terminal``): its size, a line or
|
|
2
|
+
key presses from the user, and text shown to them::
|
|
3
|
+
|
|
4
|
+
term = yield from Terminal()
|
|
5
|
+
yield from term.display("Name? ")
|
|
6
|
+
name = yield from term.read_line # QuitError at the end of input
|
|
7
|
+
|
|
8
|
+
``layer`` is standard input and output (``live(should_quit=...)`` for
|
|
9
|
+
another quit key); ``TerminalService(...)`` builds one for tests.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from pyfect._public import publish
|
|
13
|
+
from pyfect.layer import Layer
|
|
14
|
+
from pyfect.layer import sync as _layer_sync
|
|
15
|
+
from pyfect.terminal._keys import decode
|
|
16
|
+
from pyfect.terminal._live import live
|
|
17
|
+
from pyfect.terminal._service import (
|
|
18
|
+
Key,
|
|
19
|
+
QuitError,
|
|
20
|
+
Terminal,
|
|
21
|
+
TerminalService,
|
|
22
|
+
UserInput,
|
|
23
|
+
default_should_quit,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
layer: Layer[Terminal] = _layer_sync(Terminal, live)
|
|
27
|
+
"""Standard input and output."""
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"Key",
|
|
31
|
+
"QuitError",
|
|
32
|
+
"Terminal",
|
|
33
|
+
"TerminalService",
|
|
34
|
+
"UserInput",
|
|
35
|
+
"decode",
|
|
36
|
+
"default_should_quit",
|
|
37
|
+
"layer",
|
|
38
|
+
"live",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
publish(globals())
|