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,183 @@
|
|
|
1
|
+
"""``Stream`` methods that split one stream into several: grouping by
|
|
2
|
+
key, partitioning, broadcasting and sharing."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from collections.abc import Callable, Hashable
|
|
7
|
+
from typing import TYPE_CHECKING, Literal, Never, overload
|
|
8
|
+
|
|
9
|
+
from pyfect.stream._base import A_co, E_co, R_co, StreamBase
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from pyfect._concurrency import Concurrency
|
|
13
|
+
from pyfect._core import Effect
|
|
14
|
+
from pyfect.duration import Duration
|
|
15
|
+
from pyfect.errors import Done
|
|
16
|
+
from pyfect.queue import Dequeue, Strategy
|
|
17
|
+
from pyfect.result import Result
|
|
18
|
+
from pyfect.scope import Scope
|
|
19
|
+
from pyfect.stream._stream import Stream
|
|
20
|
+
|
|
21
|
+
type Capacity = int | Literal["unbounded"]
|
|
22
|
+
|
|
23
|
+
GROUP_BUFFER_SIZE = 4096
|
|
24
|
+
"""How many items each ``group_by`` group holds before upstream waits."""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FanOutMethods(StreamBase[A_co, E_co, R_co]):
|
|
28
|
+
__slots__ = ()
|
|
29
|
+
|
|
30
|
+
# --- grouping -------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
def group_by[K: Hashable, V, E2 = Never, R2 = Never](
|
|
33
|
+
self,
|
|
34
|
+
f: Callable[[A_co], Effect[tuple[K, V], E2, R2]],
|
|
35
|
+
*,
|
|
36
|
+
buffer_size: int = GROUP_BUFFER_SIZE,
|
|
37
|
+
idle_time_to_live: Duration | None = None,
|
|
38
|
+
) -> Stream[tuple[K, Stream[V]], E_co | E2, R_co | R2]:
|
|
39
|
+
"""Write ``(key, group)`` once per new key ``f(item)`` gives, where
|
|
40
|
+
``group`` is the stream of that key's values. Upstream runs on a
|
|
41
|
+
fiber and waits while a group holds ``buffer_size`` values; a group
|
|
42
|
+
read by nobody for ``idle_time_to_live`` ends, and the key's next
|
|
43
|
+
value starts a new one. A group that stops early drops its values."""
|
|
44
|
+
from pyfect.stream import _grouping
|
|
45
|
+
|
|
46
|
+
return _grouping.group_by(self, f, buffer_size, idle_time_to_live)
|
|
47
|
+
|
|
48
|
+
def group_by_key[K: Hashable](
|
|
49
|
+
self,
|
|
50
|
+
f: Callable[[A_co], K],
|
|
51
|
+
*,
|
|
52
|
+
buffer_size: int = GROUP_BUFFER_SIZE,
|
|
53
|
+
idle_time_to_live: Duration | None = None,
|
|
54
|
+
) -> Stream[tuple[K, Stream[A_co]], E_co, R_co]:
|
|
55
|
+
"""``group_by`` with the items as values, keyed by ``f(item)``."""
|
|
56
|
+
from pyfect.stream import _grouping
|
|
57
|
+
|
|
58
|
+
return _grouping.group_by_key(self, f, buffer_size, idle_time_to_live)
|
|
59
|
+
|
|
60
|
+
def group_adjacent_by[K](
|
|
61
|
+
self, f: Callable[[A_co], K]
|
|
62
|
+
) -> Stream[tuple[K, tuple[A_co, ...]], E_co, R_co]:
|
|
63
|
+
"""Write each run of neighbouring items with equal keys ``f(item)``
|
|
64
|
+
as ``(key, items)``; a key that comes back later starts a new run."""
|
|
65
|
+
from pyfect.stream import _grouping
|
|
66
|
+
|
|
67
|
+
return _grouping.group_adjacent_by(self, f)
|
|
68
|
+
|
|
69
|
+
# --- partitioning ---------------------------------------------------------
|
|
70
|
+
|
|
71
|
+
def partition[P, F](
|
|
72
|
+
self, f: Callable[[A_co], Result[P, F]], *, capacity: Capacity = 16
|
|
73
|
+
) -> Effect[tuple[Stream[P, E_co], Stream[F, E_co]], Never, R_co | Scope]:
|
|
74
|
+
"""Split the items into the ``Ok`` values of ``f(item)`` and the
|
|
75
|
+
``Err`` ones. Upstream runs on a fiber in the current ``Scope``; the
|
|
76
|
+
faster reader gets at most ``capacity`` items ahead of the slower."""
|
|
77
|
+
from pyfect.stream import _fanout
|
|
78
|
+
|
|
79
|
+
return _fanout.partition(self, f, capacity)
|
|
80
|
+
|
|
81
|
+
def partition_effect[P, F, E2 = Never, R2 = Never](
|
|
82
|
+
self,
|
|
83
|
+
f: Callable[[A_co], Effect[Result[P, F], E2, R2]],
|
|
84
|
+
*,
|
|
85
|
+
capacity: Capacity = 4096,
|
|
86
|
+
concurrency: Concurrency = None,
|
|
87
|
+
) -> Effect[tuple[Stream[P, E_co | E2], Stream[F, E_co | E2]], Never, R_co | R2 | Scope]:
|
|
88
|
+
"""``partition`` with an effectful ``f``, run on up to
|
|
89
|
+
``concurrency`` items at once (in order)."""
|
|
90
|
+
from pyfect.stream import _fanout
|
|
91
|
+
|
|
92
|
+
return _fanout.partition_effect(self, f, capacity, concurrency)
|
|
93
|
+
|
|
94
|
+
def partition_queue[P, F](
|
|
95
|
+
self, f: Callable[[A_co], Result[P, F]], *, capacity: Capacity = 4096
|
|
96
|
+
) -> Effect[tuple[Dequeue[P, E_co | Done], Dequeue[F, E_co | Done]], Never, R_co | Scope]:
|
|
97
|
+
"""``partition`` into two queues, which end (or fail) as the stream
|
|
98
|
+
does."""
|
|
99
|
+
from pyfect.stream import _fanout
|
|
100
|
+
|
|
101
|
+
return _fanout.partition_queue(self, f, capacity)
|
|
102
|
+
|
|
103
|
+
# --- broadcasting ---------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
@overload
|
|
106
|
+
def broadcast(
|
|
107
|
+
self, *, capacity: Literal["unbounded"], replay: int | None = None
|
|
108
|
+
) -> Effect[Stream[A_co, E_co], Never, R_co | Scope]: ...
|
|
109
|
+
@overload
|
|
110
|
+
def broadcast(
|
|
111
|
+
self, *, capacity: int, strategy: Strategy = "suspend", replay: int | None = None
|
|
112
|
+
) -> Effect[Stream[A_co, E_co], Never, R_co | Scope]: ...
|
|
113
|
+
def broadcast(
|
|
114
|
+
self, *, capacity: Capacity, strategy: Strategy = "suspend", replay: int | None = None
|
|
115
|
+
) -> Effect[Stream[A_co, E_co], Never, R_co | Scope]:
|
|
116
|
+
"""Run the stream on a fiber in the current ``Scope``, publishing its
|
|
117
|
+
chunks to a pubsub of ``capacity`` chunks; each run of the returned
|
|
118
|
+
stream reads what is published from then on (and the last
|
|
119
|
+
``replay`` chunks), then the end or failure."""
|
|
120
|
+
from pyfect.stream import _fanout
|
|
121
|
+
|
|
122
|
+
return _fanout.broadcast(self, capacity, strategy, replay)
|
|
123
|
+
|
|
124
|
+
@overload
|
|
125
|
+
def broadcast_n(
|
|
126
|
+
self, n: int, *, capacity: Literal["unbounded"], replay: int | None = None
|
|
127
|
+
) -> Effect[tuple[Stream[A_co, E_co], ...], Never, R_co | Scope]: ...
|
|
128
|
+
@overload
|
|
129
|
+
def broadcast_n(
|
|
130
|
+
self,
|
|
131
|
+
n: int,
|
|
132
|
+
*,
|
|
133
|
+
capacity: int,
|
|
134
|
+
strategy: Strategy = "suspend",
|
|
135
|
+
replay: int | None = None,
|
|
136
|
+
) -> Effect[tuple[Stream[A_co, E_co], ...], Never, R_co | Scope]: ...
|
|
137
|
+
def broadcast_n(
|
|
138
|
+
self,
|
|
139
|
+
n: int,
|
|
140
|
+
*,
|
|
141
|
+
capacity: Capacity,
|
|
142
|
+
strategy: Strategy = "suspend",
|
|
143
|
+
replay: int | None = None,
|
|
144
|
+
) -> Effect[tuple[Stream[A_co, E_co], ...], Never, R_co | Scope]:
|
|
145
|
+
"""``n`` streams (none below 1) each reading every chunk. They
|
|
146
|
+
subscribe now, so none misses the start; with ``"suspend"`` the
|
|
147
|
+
upstream stays at most ``capacity`` chunks ahead of the slowest. A
|
|
148
|
+
stream that stops unsubscribes."""
|
|
149
|
+
from pyfect.stream import _fanout
|
|
150
|
+
|
|
151
|
+
return _fanout.broadcast_n(self, n, capacity, strategy, replay)
|
|
152
|
+
|
|
153
|
+
@overload
|
|
154
|
+
def share(
|
|
155
|
+
self,
|
|
156
|
+
*,
|
|
157
|
+
capacity: Literal["unbounded"],
|
|
158
|
+
replay: int | None = None,
|
|
159
|
+
idle_time_to_live: Duration | None = None,
|
|
160
|
+
) -> Effect[Stream[A_co, E_co], Never, R_co | Scope]: ...
|
|
161
|
+
@overload
|
|
162
|
+
def share(
|
|
163
|
+
self,
|
|
164
|
+
*,
|
|
165
|
+
capacity: int,
|
|
166
|
+
strategy: Strategy = "suspend",
|
|
167
|
+
replay: int | None = None,
|
|
168
|
+
idle_time_to_live: Duration | None = None,
|
|
169
|
+
) -> Effect[Stream[A_co, E_co], Never, R_co | Scope]: ...
|
|
170
|
+
def share(
|
|
171
|
+
self,
|
|
172
|
+
*,
|
|
173
|
+
capacity: Capacity,
|
|
174
|
+
strategy: Strategy = "suspend",
|
|
175
|
+
replay: int | None = None,
|
|
176
|
+
idle_time_to_live: Duration | None = None,
|
|
177
|
+
) -> Effect[Stream[A_co, E_co], Never, R_co | Scope]:
|
|
178
|
+
"""A stream that ``broadcast``s this one when its first reader
|
|
179
|
+
starts and stops it when the last one stops (or ``idle_time_to_live``
|
|
180
|
+
after, so a later reader continues where it left off)."""
|
|
181
|
+
from pyfect.stream import _fanout
|
|
182
|
+
|
|
183
|
+
return _fanout.share(self, capacity, strategy, replay, idle_time_to_live)
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"""``Stream`` methods that keep some items: filtering, taking, dropping and
|
|
2
|
+
dropping repeats.
|
|
3
|
+
|
|
4
|
+
Counts are ``int``s; a count below zero counts as zero. Predicates take
|
|
5
|
+
the item only (``enumerate`` the stream with ``zip_with_index`` for its
|
|
6
|
+
position). A filter is a function returning ``Ok(value)`` to keep
|
|
7
|
+
``value`` or ``Err(...)`` to drop the item (Effect's ``Filter``).
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from collections.abc import Callable
|
|
13
|
+
from typing import TYPE_CHECKING, Never, TypeIs, overload
|
|
14
|
+
|
|
15
|
+
from pyfect._equal import equals
|
|
16
|
+
from pyfect.result import Ok, Result
|
|
17
|
+
from pyfect.stream._base import A_co, E_co, R_co, StreamBase
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from pyfect._core import Effect
|
|
21
|
+
from pyfect.stream._stream import Stream
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class FilterMethods(StreamBase[A_co, E_co, R_co]):
|
|
25
|
+
__slots__ = ()
|
|
26
|
+
|
|
27
|
+
# --- filtering ------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
@overload
|
|
30
|
+
def filter[B](self, predicate: Callable[[A_co], TypeIs[B]]) -> Stream[B, E_co, R_co]: ...
|
|
31
|
+
@overload
|
|
32
|
+
def filter(self, predicate: Callable[[A_co], bool]) -> Stream[A_co, E_co, R_co]: ...
|
|
33
|
+
def filter(self, predicate: Callable[[A_co], bool]) -> Stream[object, E_co, R_co]:
|
|
34
|
+
"""Keep the items that pass ``predicate``."""
|
|
35
|
+
from pyfect.stream._stream import Stream
|
|
36
|
+
|
|
37
|
+
return Stream(self._channel.filter_array(predicate))
|
|
38
|
+
|
|
39
|
+
def filter_map[B](self, f: Callable[[A_co], Result[B, object]]) -> Stream[B, E_co, R_co]:
|
|
40
|
+
"""Write ``value`` for each item ``f`` maps to ``Ok(value)``; drop
|
|
41
|
+
the items it maps to ``Err``."""
|
|
42
|
+
from pyfect.stream import _taking
|
|
43
|
+
|
|
44
|
+
return _taking.filter_map(self, f)
|
|
45
|
+
|
|
46
|
+
def filter_effect[E2 = Never, R2 = Never](
|
|
47
|
+
self, predicate: Callable[[A_co], Effect[bool, E2, R2]]
|
|
48
|
+
) -> Stream[A_co, E_co | E2, R_co | R2]:
|
|
49
|
+
"""Keep the items whose ``predicate`` succeeds with ``True``."""
|
|
50
|
+
from pyfect.stream._stream import Stream
|
|
51
|
+
|
|
52
|
+
return Stream(self._channel.filter_array_effect(predicate))
|
|
53
|
+
|
|
54
|
+
def filter_map_effect[B, E2 = Never, R2 = Never](
|
|
55
|
+
self, f: Callable[[A_co], Effect[Result[B, object], E2, R2]]
|
|
56
|
+
) -> Stream[B, E_co | E2, R_co | R2]:
|
|
57
|
+
"""``filter_map`` with an effectful ``f``."""
|
|
58
|
+
from pyfect.stream import _taking
|
|
59
|
+
|
|
60
|
+
return _taking.filter_map_effect(self, f)
|
|
61
|
+
|
|
62
|
+
# --- taking ---------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
def take(self, n: int) -> Stream[A_co, E_co, R_co]:
|
|
65
|
+
"""The first ``n`` items; then end without pulling again."""
|
|
66
|
+
from pyfect.stream import _taking
|
|
67
|
+
|
|
68
|
+
return _taking.take(self, n)
|
|
69
|
+
|
|
70
|
+
def take_right(self, n: int) -> Stream[A_co, E_co, R_co]:
|
|
71
|
+
"""The last ``n`` items, written when the stream ends."""
|
|
72
|
+
from pyfect.stream import _taking
|
|
73
|
+
|
|
74
|
+
return _taking.take_right(self, n)
|
|
75
|
+
|
|
76
|
+
def take_until(
|
|
77
|
+
self, predicate: Callable[[A_co], bool], *, exclude_last: bool = False
|
|
78
|
+
) -> Stream[A_co, E_co, R_co]:
|
|
79
|
+
"""Items up to and including the first that passes ``predicate``
|
|
80
|
+
(excluding it with ``exclude_last``); then end."""
|
|
81
|
+
from pyfect.stream import _taking
|
|
82
|
+
|
|
83
|
+
return _taking.take_until(self, predicate, exclude_last)
|
|
84
|
+
|
|
85
|
+
def take_until_effect[E2 = Never, R2 = Never](
|
|
86
|
+
self, predicate: Callable[[A_co], Effect[bool, E2, R2]], *, exclude_last: bool = False
|
|
87
|
+
) -> Stream[A_co, E_co | E2, R_co | R2]:
|
|
88
|
+
"""``take_until`` with an effectful ``predicate``."""
|
|
89
|
+
from pyfect.stream import _taking
|
|
90
|
+
|
|
91
|
+
return _taking.take_until_effect(self, predicate, exclude_last)
|
|
92
|
+
|
|
93
|
+
@overload
|
|
94
|
+
def take_while[B](self, predicate: Callable[[A_co], TypeIs[B]]) -> Stream[B, E_co, R_co]: ...
|
|
95
|
+
@overload
|
|
96
|
+
def take_while(self, predicate: Callable[[A_co], bool]) -> Stream[A_co, E_co, R_co]: ...
|
|
97
|
+
def take_while(self, predicate: Callable[[A_co], bool]) -> Stream[object, E_co, R_co]:
|
|
98
|
+
"""Items while they pass ``predicate``; end at the first that fails."""
|
|
99
|
+
from pyfect.stream import _taking
|
|
100
|
+
|
|
101
|
+
return _taking.take_while(self, predicate)
|
|
102
|
+
|
|
103
|
+
def take_while_filter[B](self, f: Callable[[A_co], Result[B, object]]) -> Stream[B, E_co, R_co]:
|
|
104
|
+
"""Write ``value`` while ``f`` maps items to ``Ok(value)``; end at the
|
|
105
|
+
first ``Err``."""
|
|
106
|
+
from pyfect.stream import _taking
|
|
107
|
+
|
|
108
|
+
return _taking.take_while_filter(self, f)
|
|
109
|
+
|
|
110
|
+
def take_while_effect[E2 = Never, R2 = Never](
|
|
111
|
+
self, predicate: Callable[[A_co], Effect[bool, E2, R2]]
|
|
112
|
+
) -> Stream[A_co, E_co | E2, R_co | R2]:
|
|
113
|
+
"""``take_while`` with an effectful ``predicate``."""
|
|
114
|
+
from pyfect.stream import _taking
|
|
115
|
+
|
|
116
|
+
return _taking.take_until_effect(self, lambda a: predicate(a).map(_not), True)
|
|
117
|
+
|
|
118
|
+
def limit_bytes[E, R](
|
|
119
|
+
self: FilterMethods[bytes, E, R],
|
|
120
|
+
limit: int,
|
|
121
|
+
on_limit_reached: Callable[[], Stream[bytes, E, R]],
|
|
122
|
+
) -> Stream[bytes, E, R]:
|
|
123
|
+
"""Byte strings while their total length stays within ``limit``;
|
|
124
|
+
the first one that would cross it is dropped and the stream goes on
|
|
125
|
+
with ``on_limit_reached()`` instead."""
|
|
126
|
+
from pyfect.stream import _taking
|
|
127
|
+
|
|
128
|
+
return _taking.limit_bytes(self, limit, on_limit_reached)
|
|
129
|
+
|
|
130
|
+
# --- dropping -------------------------------------------------------------
|
|
131
|
+
|
|
132
|
+
def drop(self, n: int) -> Stream[A_co, E_co, R_co]:
|
|
133
|
+
"""All but the first ``n`` items."""
|
|
134
|
+
from pyfect.stream import _taking
|
|
135
|
+
|
|
136
|
+
return _taking.drop(self, n)
|
|
137
|
+
|
|
138
|
+
def drop_right(self, n: int) -> Stream[A_co, E_co, R_co]:
|
|
139
|
+
"""All but the last ``n`` items (each written once ``n`` later ones
|
|
140
|
+
have come)."""
|
|
141
|
+
from pyfect.stream import _taking
|
|
142
|
+
|
|
143
|
+
return _taking.drop_right(self, n)
|
|
144
|
+
|
|
145
|
+
def drop_while(self, predicate: Callable[[A_co], bool]) -> Stream[A_co, E_co, R_co]:
|
|
146
|
+
"""Drop items while they pass ``predicate``; write the rest."""
|
|
147
|
+
from pyfect.stream import _taking
|
|
148
|
+
|
|
149
|
+
return _taking.drop_while(self, predicate)
|
|
150
|
+
|
|
151
|
+
def drop_while_filter(
|
|
152
|
+
self, f: Callable[[A_co], Result[object, object]]
|
|
153
|
+
) -> Stream[A_co, E_co, R_co]:
|
|
154
|
+
"""Drop items while ``f`` maps them to ``Ok``; write the rest."""
|
|
155
|
+
from pyfect.stream import _taking
|
|
156
|
+
|
|
157
|
+
return _taking.drop_while(self, lambda a: isinstance(f(a), Ok))
|
|
158
|
+
|
|
159
|
+
def drop_while_effect[E2 = Never, R2 = Never](
|
|
160
|
+
self, predicate: Callable[[A_co], Effect[bool, E2, R2]]
|
|
161
|
+
) -> Stream[A_co, E_co | E2, R_co | R2]:
|
|
162
|
+
"""``drop_while`` with an effectful ``predicate``."""
|
|
163
|
+
from pyfect.stream import _taking
|
|
164
|
+
|
|
165
|
+
return _taking.drop_while_effect(self, predicate)
|
|
166
|
+
|
|
167
|
+
def drop_until(self, predicate: Callable[[A_co], bool]) -> Stream[A_co, E_co, R_co]:
|
|
168
|
+
"""Drop items up to and including the first that passes
|
|
169
|
+
``predicate``."""
|
|
170
|
+
return self.drop_while(lambda a: not predicate(a)).drop(1)
|
|
171
|
+
|
|
172
|
+
def drop_until_effect[E2 = Never, R2 = Never](
|
|
173
|
+
self, predicate: Callable[[A_co], Effect[bool, E2, R2]]
|
|
174
|
+
) -> Stream[A_co, E_co | E2, R_co | R2]:
|
|
175
|
+
"""``drop_until`` with an effectful ``predicate``."""
|
|
176
|
+
return self.drop_while_effect(lambda a: predicate(a).map(_not)).drop(1)
|
|
177
|
+
|
|
178
|
+
# --- repeats --------------------------------------------------------------
|
|
179
|
+
|
|
180
|
+
def changes(self) -> Stream[A_co, E_co, R_co]:
|
|
181
|
+
"""Drop each item ``Equal.equals`` calls equal to the one written
|
|
182
|
+
before it (``True`` is not ``1``, NaN is NaN)."""
|
|
183
|
+
from pyfect.stream import _taking
|
|
184
|
+
|
|
185
|
+
return _taking.changes_with(self, equals)
|
|
186
|
+
|
|
187
|
+
def changes_with(self, f: Callable[[A_co, A_co], bool]) -> Stream[A_co, E_co, R_co]:
|
|
188
|
+
"""Drop each item ``f(item, last_written)`` calls the same."""
|
|
189
|
+
from pyfect.stream import _taking
|
|
190
|
+
|
|
191
|
+
return _taking.changes_with(self, f)
|
|
192
|
+
|
|
193
|
+
def changes_with_effect[E2 = Never, R2 = Never](
|
|
194
|
+
self, f: Callable[[A_co, A_co], Effect[bool, E2, R2]]
|
|
195
|
+
) -> Stream[A_co, E_co | E2, R_co | R2]:
|
|
196
|
+
"""``changes_with`` with an effectful ``f``."""
|
|
197
|
+
from pyfect.stream import _taking
|
|
198
|
+
|
|
199
|
+
return _taking.changes_with_effect(self, f)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _not(value: bool) -> bool:
|
|
203
|
+
return not value
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"""The work behind ``Stream.group_by``, ``group_by_key`` and
|
|
2
|
+
``group_adjacent_by``.
|
|
3
|
+
|
|
4
|
+
``group_by`` and ``group_by_key`` run the upstream on a fiber in the
|
|
5
|
+
stream's scope. Each new key gets a queue of ``buffer_size`` (an ``RcMap``
|
|
6
|
+
entry, ended when the entry is released) and the outer stream writes
|
|
7
|
+
``(key, group)`` once, where ``group`` reads that queue and shuts it down
|
|
8
|
+
when it stops, so a group that stops early never blocks the others.
|
|
9
|
+
"""
|
|
10
|
+
# pyright: reportPrivateUsage=false
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import math
|
|
15
|
+
from collections.abc import Callable, Generator, Hashable
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
from pyfect import channel
|
|
19
|
+
from pyfect._core import Effect, _FlatMap, _Gen, _Succeed, _Suspend, _Sync
|
|
20
|
+
from pyfect.channel._base import end_with
|
|
21
|
+
from pyfect.duration import Duration, to_seconds
|
|
22
|
+
from pyfect.effect import provide_service
|
|
23
|
+
from pyfect.errors import Done
|
|
24
|
+
from pyfect.pull import catch_done
|
|
25
|
+
from pyfect.queue import Queue
|
|
26
|
+
from pyfect.rc_map import RcMap
|
|
27
|
+
from pyfect.scope import CloseableScope, Scope, acquire_release, fork_in, scoped
|
|
28
|
+
from pyfect.stream._base import AnyStream
|
|
29
|
+
from pyfect.stream._stream import Stream, transform_pull, transform_pull_bracket
|
|
30
|
+
|
|
31
|
+
type AnyEffect = Effect[Any, Any, Any]
|
|
32
|
+
type Chunk = tuple[Any, ...]
|
|
33
|
+
type AnyStream_ = Stream[Any, Any, Any]
|
|
34
|
+
type Groups = RcMap[Any, Queue[Any, Done], Any]
|
|
35
|
+
type OfferChunk = Callable[[Chunk, Groups, dict[Any, Queue[Any, Done]]], AnyEffect]
|
|
36
|
+
|
|
37
|
+
_ENDED: AnyEffect = end_with(None)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def from_queue_shutdown_on_end(queue: Queue[Any, Any]) -> AnyStream_:
|
|
41
|
+
"""A stream taking everything waiting in ``queue`` at each pull; it
|
|
42
|
+
shuts the queue down when it stops."""
|
|
43
|
+
|
|
44
|
+
def transform(_upstream: object, scope: CloseableScope) -> AnyEffect:
|
|
45
|
+
take = queue.take_all().map(tuple)
|
|
46
|
+
return scope.add_finalizer(lambda _: queue.shutdown()).as_(take)
|
|
47
|
+
|
|
48
|
+
built: channel.Channel[Any, Any, Any, Any, Any, Any, Any] = channel.from_transform(transform)
|
|
49
|
+
return Stream(built)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _queue_for(key: Any, groups: Groups, open_queues: dict[Any, Queue[Any, Done]]) -> AnyEffect:
|
|
53
|
+
queue = open_queues.get(key)
|
|
54
|
+
found = _Succeed(queue) if queue is not None else scoped(groups.get(key))
|
|
55
|
+
return found.tap(lambda _: groups.touch(key))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _group_by(
|
|
59
|
+
self: AnyStream,
|
|
60
|
+
offer_chunk: OfferChunk,
|
|
61
|
+
buffer_size: int,
|
|
62
|
+
idle_time_to_live: Duration | None,
|
|
63
|
+
) -> AnyStream_:
|
|
64
|
+
ttl = math.inf if idle_time_to_live is None else to_seconds(idle_time_to_live)
|
|
65
|
+
|
|
66
|
+
def build(pull: AnyEffect, scope: CloseableScope, forked: CloseableScope) -> AnyEffect:
|
|
67
|
+
def body() -> Generator[AnyEffect, Any, AnyEffect]:
|
|
68
|
+
out: Queue[Any, Any] = Queue(None)
|
|
69
|
+
yield scope.add_finalizer(lambda _: out.shutdown())
|
|
70
|
+
open_queues: dict[Any, Queue[Any, Done]] = {}
|
|
71
|
+
|
|
72
|
+
def lookup(key: Any) -> AnyEffect:
|
|
73
|
+
def opened(queue: Queue[Any, Done]) -> AnyEffect:
|
|
74
|
+
open_queues[key] = queue
|
|
75
|
+
return out.offer((key, from_queue_shutdown_on_end(queue)))
|
|
76
|
+
|
|
77
|
+
def release(queue: Queue[Any, Done], _: object) -> AnyEffect:
|
|
78
|
+
open_queues.pop(key, None)
|
|
79
|
+
return queue.end()
|
|
80
|
+
|
|
81
|
+
made: Effect[Queue[Any, Done]] = _Sync(lambda: Queue(buffer_size))
|
|
82
|
+
return acquire_release(made.tap(opened), release)
|
|
83
|
+
|
|
84
|
+
make_groups = RcMap.make(lookup, idle_time_to_live=ttl)
|
|
85
|
+
groups: Groups = yield make_groups.pipe(provide_service(Scope, forked))
|
|
86
|
+
run = _FlatMap(pull, lambda chunk: offer_chunk(chunk, groups, open_queues)).forever(
|
|
87
|
+
disable_yield=True
|
|
88
|
+
)
|
|
89
|
+
yield fork_in(run.catch_cause(out.fail_cause), scope)
|
|
90
|
+
return out.take_all().map(tuple)
|
|
91
|
+
|
|
92
|
+
return _Gen(body)
|
|
93
|
+
|
|
94
|
+
return transform_pull_bracket(self, build)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def group_by(
|
|
98
|
+
self: AnyStream,
|
|
99
|
+
f: Callable[[Any], Effect[tuple[Hashable, Any], Any, Any]],
|
|
100
|
+
buffer_size: int,
|
|
101
|
+
idle_time_to_live: Duration | None,
|
|
102
|
+
) -> AnyStream_:
|
|
103
|
+
def offer_chunk(
|
|
104
|
+
chunk: Chunk, groups: Groups, open_queues: dict[Any, Queue[Any, Done]]
|
|
105
|
+
) -> AnyEffect:
|
|
106
|
+
def body() -> Generator[AnyEffect, Any]:
|
|
107
|
+
for item in chunk:
|
|
108
|
+
key, value = yield f(item)
|
|
109
|
+
queue = yield _queue_for(key, groups, open_queues)
|
|
110
|
+
yield queue.offer(value)
|
|
111
|
+
|
|
112
|
+
return _Gen(body)
|
|
113
|
+
|
|
114
|
+
return _group_by(self, offer_chunk, buffer_size, idle_time_to_live)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def group_by_key(
|
|
118
|
+
self: AnyStream,
|
|
119
|
+
f: Callable[[Any], Hashable],
|
|
120
|
+
buffer_size: int,
|
|
121
|
+
idle_time_to_live: Duration | None,
|
|
122
|
+
) -> AnyStream_:
|
|
123
|
+
def offer_chunk(
|
|
124
|
+
chunk: Chunk, groups: Groups, open_queues: dict[Any, Queue[Any, Done]]
|
|
125
|
+
) -> AnyEffect:
|
|
126
|
+
batch: dict[Any, list[Any]] = {}
|
|
127
|
+
for item in chunk:
|
|
128
|
+
batch.setdefault(f(item), []).append(item)
|
|
129
|
+
|
|
130
|
+
def body() -> Generator[AnyEffect, Any]:
|
|
131
|
+
for key, values in batch.items():
|
|
132
|
+
queue = yield _queue_for(key, groups, open_queues)
|
|
133
|
+
yield queue.offer_all(values)
|
|
134
|
+
|
|
135
|
+
return _Gen(body)
|
|
136
|
+
|
|
137
|
+
return _group_by(self, offer_chunk, buffer_size, idle_time_to_live)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def group_adjacent_by(self: AnyStream, f: Callable[[Any], object]) -> AnyStream_:
|
|
141
|
+
def build(pull: AnyEffect, _scope: CloseableScope) -> AnyEffect:
|
|
142
|
+
key: object = None
|
|
143
|
+
group: list[Any] = []
|
|
144
|
+
done = False
|
|
145
|
+
|
|
146
|
+
def split(chunk: Chunk) -> AnyEffect:
|
|
147
|
+
nonlocal key, group
|
|
148
|
+
ready: list[tuple[object, Chunk]] = []
|
|
149
|
+
for item in chunk:
|
|
150
|
+
item_key = f(item)
|
|
151
|
+
if group and item_key != key:
|
|
152
|
+
ready.append((key, tuple(group)))
|
|
153
|
+
group = []
|
|
154
|
+
if not group:
|
|
155
|
+
key = item_key
|
|
156
|
+
group.append(item)
|
|
157
|
+
return _Succeed(tuple(ready)) if ready else loop
|
|
158
|
+
|
|
159
|
+
def flush(_: None) -> AnyEffect:
|
|
160
|
+
nonlocal done, group
|
|
161
|
+
done = True
|
|
162
|
+
last, group = group, []
|
|
163
|
+
return _Succeed(((key, tuple(last)),)) if last else _ENDED
|
|
164
|
+
|
|
165
|
+
loop: AnyEffect = _FlatMap(pull, split)
|
|
166
|
+
return _Succeed(catch_done(_Suspend(lambda: _ENDED if done else loop), flush))
|
|
167
|
+
|
|
168
|
+
return transform_pull(self, build)
|
pyfect/stream/_many.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Functions combining any number of streams: ``merge_all``,
|
|
2
|
+
``zip_latest_all`` and ``race_all``. Each uses one shared error and
|
|
3
|
+
service type for all its streams."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from collections.abc import Iterable
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Never, overload
|
|
9
|
+
|
|
10
|
+
from pyfect.stream._base import StreamBase, require_stream, require_streams
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pyfect._concurrency import Concurrency
|
|
14
|
+
from pyfect.stream._stream import Stream
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def merge_all[A, EE = Never, RR = Never](
|
|
18
|
+
streams: Iterable[StreamBase[A, EE, RR]], *, concurrency: Concurrency, buffer_size: int = 16
|
|
19
|
+
) -> Stream[A, EE, RR]:
|
|
20
|
+
"""Run ``streams``, up to ``concurrency`` at once, writing their items
|
|
21
|
+
as they come (at most ``buffer_size`` waiting)."""
|
|
22
|
+
from pyfect.stream._constructors import from_iterable
|
|
23
|
+
|
|
24
|
+
parts = list(streams)
|
|
25
|
+
for part in parts:
|
|
26
|
+
require_stream(part, "streams")
|
|
27
|
+
return from_iterable(parts).flatten(concurrency=concurrency, buffer_size=buffer_size)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@overload
|
|
31
|
+
def zip_latest_all() -> Stream[Never]: ...
|
|
32
|
+
@overload
|
|
33
|
+
def zip_latest_all[A1, EE = Never, RR = Never](
|
|
34
|
+
s1: StreamBase[A1, EE, RR], /
|
|
35
|
+
) -> Stream[tuple[A1], EE, RR]: ...
|
|
36
|
+
@overload
|
|
37
|
+
def zip_latest_all[A1, A2, EE = Never, RR = Never](
|
|
38
|
+
s1: StreamBase[A1, EE, RR], s2: StreamBase[A2, EE, RR], /
|
|
39
|
+
) -> Stream[tuple[A1, A2], EE, RR]: ...
|
|
40
|
+
@overload
|
|
41
|
+
def zip_latest_all[A1, A2, A3, EE = Never, RR = Never](
|
|
42
|
+
s1: StreamBase[A1, EE, RR], s2: StreamBase[A2, EE, RR], s3: StreamBase[A3, EE, RR], /
|
|
43
|
+
) -> Stream[tuple[A1, A2, A3], EE, RR]: ...
|
|
44
|
+
@overload
|
|
45
|
+
def zip_latest_all[A, EE = Never, RR = Never](
|
|
46
|
+
*streams: StreamBase[A, EE, RR],
|
|
47
|
+
) -> Stream[tuple[A, ...], EE, RR]: ...
|
|
48
|
+
def zip_latest_all(*streams: StreamBase[Any, Any, Any]) -> Stream[Any, Any, Any]:
|
|
49
|
+
"""Once every stream has written, write a tuple of each one's latest
|
|
50
|
+
item whenever any writes; end when any ends (at once if one ends
|
|
51
|
+
without writing)."""
|
|
52
|
+
from pyfect.stream import _constructors, _zipping
|
|
53
|
+
|
|
54
|
+
require_streams(streams, "streams")
|
|
55
|
+
if not streams:
|
|
56
|
+
return _constructors.empty
|
|
57
|
+
return _zipping.zip_latest_all(*streams)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def race_all[A, EE = Never, RR = Never](*streams: StreamBase[A, EE, RR]) -> Stream[A, EE, RR]:
|
|
61
|
+
"""The stream that writes first; the others are interrupted."""
|
|
62
|
+
from pyfect.stream import _zipping
|
|
63
|
+
|
|
64
|
+
require_streams(streams, "streams")
|
|
65
|
+
return _zipping.race_all(*streams)
|