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,57 @@
|
|
|
1
|
+
"""``Effect`` methods for logging: annotations, spans and extra loggers."""
|
|
2
|
+
# pyright: reportPrivateUsage=false
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from collections.abc import Mapping
|
|
7
|
+
from typing import TYPE_CHECKING, Any, overload
|
|
8
|
+
|
|
9
|
+
from pyfect import _core
|
|
10
|
+
from pyfect._effect_base import A_co, E_co, EffectBase, R_co, as_effect
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pyfect._core import Effect
|
|
14
|
+
from pyfect._fiber import Fiber
|
|
15
|
+
from pyfect.logger import Logger
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class LoggingMethods(EffectBase[A_co, E_co, R_co]):
|
|
19
|
+
__slots__ = ()
|
|
20
|
+
|
|
21
|
+
@overload
|
|
22
|
+
def annotate_logs(self, key: str, value: object, /) -> Effect[A_co, E_co, R_co]: ...
|
|
23
|
+
@overload
|
|
24
|
+
def annotate_logs(self, values: Mapping[str, object], /) -> Effect[A_co, E_co, R_co]: ...
|
|
25
|
+
def annotate_logs(
|
|
26
|
+
self, key_or_values: str | Mapping[str, object], value: object = None, /
|
|
27
|
+
) -> Effect[A_co, E_co, R_co]:
|
|
28
|
+
"""Run with these annotations added to every log."""
|
|
29
|
+
from pyfect.logger import CurrentLogAnnotations
|
|
30
|
+
|
|
31
|
+
added = {key_or_values: value} if isinstance(key_or_values, str) else dict(key_or_values)
|
|
32
|
+
return as_effect(self).update_service(
|
|
33
|
+
CurrentLogAnnotations, lambda annotations: {**annotations, **added}
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def with_log_span(self, label: str) -> Effect[A_co, E_co, R_co]:
|
|
37
|
+
"""Run inside a log span: logs show ``label=<elapsed>ms``, timed by
|
|
38
|
+
the ``Clock`` from when this effect starts."""
|
|
39
|
+
from pyfect.clock import Clock, now_millis_unsafe
|
|
40
|
+
from pyfect.logger import CurrentLogSpans, LogSpan
|
|
41
|
+
|
|
42
|
+
inner = as_effect(self)
|
|
43
|
+
|
|
44
|
+
def body(fiber: Fiber[Any, Any]) -> Effect[A_co, E_co, R_co]:
|
|
45
|
+
span = LogSpan(label, now_millis_unsafe(fiber.get_ref(Clock)))
|
|
46
|
+
return inner.update_service(CurrentLogSpans, lambda spans: (span, *spans))
|
|
47
|
+
|
|
48
|
+
return _core._WithFiber(body)
|
|
49
|
+
|
|
50
|
+
def with_logger(self, logger: Logger[object]) -> Effect[A_co, E_co, R_co]:
|
|
51
|
+
"""Run with ``logger`` added to the current loggers."""
|
|
52
|
+
from pyfect.logger import CurrentLoggers
|
|
53
|
+
|
|
54
|
+
return as_effect(self).update_service(
|
|
55
|
+
CurrentLoggers,
|
|
56
|
+
lambda loggers: loggers if any(lg is logger for lg in loggers) else (*loggers, logger),
|
|
57
|
+
)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""``Effect`` methods for metrics: update a metric with how an effect
|
|
2
|
+
ended, what it succeeded or failed with, or how long it took."""
|
|
3
|
+
# pyright: reportPrivateUsage=false
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
from typing import TYPE_CHECKING, Any, overload
|
|
9
|
+
|
|
10
|
+
from pyfect import _core
|
|
11
|
+
from pyfect._effect_base import A_co, E_co, EffectBase, R_co, as_effect
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from pyfect._core import Effect
|
|
15
|
+
from pyfect._fiber import Fiber
|
|
16
|
+
from pyfect.duration import Seconds
|
|
17
|
+
from pyfect.exit import Exit
|
|
18
|
+
from pyfect.metric import Metric
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class MetricMethods(EffectBase[A_co, E_co, R_co]):
|
|
22
|
+
__slots__ = ()
|
|
23
|
+
|
|
24
|
+
@overload
|
|
25
|
+
def track(self, metric: Metric[Exit[A_co, E_co], object], /) -> Effect[A_co, E_co, R_co]: ...
|
|
26
|
+
@overload
|
|
27
|
+
def track[I](
|
|
28
|
+
self, metric: Metric[I, object], f: Callable[[Exit[A_co, E_co]], I], /
|
|
29
|
+
) -> Effect[A_co, E_co, R_co]: ...
|
|
30
|
+
def track(
|
|
31
|
+
self, metric: Metric[Any, object], f: Callable[[Any], Any] | None = None, /
|
|
32
|
+
) -> Effect[A_co, E_co, R_co]:
|
|
33
|
+
"""Update ``metric`` with this effect's exit (or ``f(exit)``)
|
|
34
|
+
however it ends."""
|
|
35
|
+
return as_effect(self).on_exit(lambda ex: metric.update(ex if f is None else f(ex)))
|
|
36
|
+
|
|
37
|
+
@overload
|
|
38
|
+
def track_successes(self, metric: Metric[A_co, object], /) -> Effect[A_co, E_co, R_co]: ...
|
|
39
|
+
@overload
|
|
40
|
+
def track_successes[I](
|
|
41
|
+
self, metric: Metric[I, object], f: Callable[[A_co], I], /
|
|
42
|
+
) -> Effect[A_co, E_co, R_co]: ...
|
|
43
|
+
def track_successes(
|
|
44
|
+
self, metric: Metric[Any, object], f: Callable[[Any], Any] | None = None, /
|
|
45
|
+
) -> Effect[A_co, E_co, R_co]:
|
|
46
|
+
"""Update ``metric`` with each value (or ``f(value)``)."""
|
|
47
|
+
return as_effect(self).tap(lambda a: metric.update(a if f is None else f(a)))
|
|
48
|
+
|
|
49
|
+
@overload
|
|
50
|
+
def track_errors(self, metric: Metric[E_co, object], /) -> Effect[A_co, E_co, R_co]: ...
|
|
51
|
+
@overload
|
|
52
|
+
def track_errors[I](
|
|
53
|
+
self, metric: Metric[I, object], f: Callable[[E_co], I], /
|
|
54
|
+
) -> Effect[A_co, E_co, R_co]: ...
|
|
55
|
+
def track_errors(
|
|
56
|
+
self, metric: Metric[Any, object], f: Callable[[Any], Any] | None = None, /
|
|
57
|
+
) -> Effect[A_co, E_co, R_co]:
|
|
58
|
+
"""Update ``metric`` with each typed error (or ``f(error)``)."""
|
|
59
|
+
return as_effect(self).tap_error(lambda e: metric.update(e if f is None else f(e)))
|
|
60
|
+
|
|
61
|
+
@overload
|
|
62
|
+
def track_defects(
|
|
63
|
+
self, metric: Metric[BaseException, object], /
|
|
64
|
+
) -> Effect[A_co, E_co, R_co]: ...
|
|
65
|
+
@overload
|
|
66
|
+
def track_defects[I](
|
|
67
|
+
self, metric: Metric[I, object], f: Callable[[object], I], /
|
|
68
|
+
) -> Effect[A_co, E_co, R_co]: ...
|
|
69
|
+
def track_defects(
|
|
70
|
+
self, metric: Metric[Any, object], f: Callable[[Any], Any] | None = None, /
|
|
71
|
+
) -> Effect[A_co, E_co, R_co]:
|
|
72
|
+
"""Update ``metric`` with each defect (or ``f(defect)``)."""
|
|
73
|
+
return as_effect(self).tap_defect(lambda d: metric.update(d if f is None else f(d)))
|
|
74
|
+
|
|
75
|
+
@overload
|
|
76
|
+
def track_duration(self, metric: Metric[Seconds, object], /) -> Effect[A_co, E_co, R_co]: ...
|
|
77
|
+
@overload
|
|
78
|
+
def track_duration[I](
|
|
79
|
+
self, metric: Metric[I, object], f: Callable[[Seconds], I], /
|
|
80
|
+
) -> Effect[A_co, E_co, R_co]: ...
|
|
81
|
+
def track_duration(
|
|
82
|
+
self, metric: Metric[Any, object], f: Callable[[Any], Any] | None = None, /
|
|
83
|
+
) -> Effect[A_co, E_co, R_co]:
|
|
84
|
+
"""Update ``metric`` with how long this effect took (or
|
|
85
|
+
``f(duration)``), measured on the ``Clock``'s monotonic time
|
|
86
|
+
however it ends."""
|
|
87
|
+
from pyfect.clock import Clock
|
|
88
|
+
from pyfect.duration import Seconds
|
|
89
|
+
|
|
90
|
+
inner = as_effect(self)
|
|
91
|
+
|
|
92
|
+
def body(fiber: Fiber[Any, Any]) -> Effect[A_co, E_co, R_co]:
|
|
93
|
+
clock = fiber.get_ref(Clock)
|
|
94
|
+
start = clock.monotonic_nanos_unsafe()
|
|
95
|
+
|
|
96
|
+
def record(_: object) -> Effect[None]:
|
|
97
|
+
elapsed = Seconds((clock.monotonic_nanos_unsafe() - start) / 1_000_000_000)
|
|
98
|
+
return metric.update(elapsed if f is None else f(elapsed))
|
|
99
|
+
|
|
100
|
+
return inner.on_exit(record)
|
|
101
|
+
|
|
102
|
+
return _core._WithFiber(body)
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""``Effect`` methods for resource safety: finalizers and interruptibility.
|
|
2
|
+
|
|
3
|
+
Every user callback runs through ``_call_user``, so a raise becomes a
|
|
4
|
+
defect inside the surrounding finalizer or region.
|
|
5
|
+
"""
|
|
6
|
+
# pyright: reportPrivateUsage=false
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from collections.abc import Callable
|
|
11
|
+
from typing import TYPE_CHECKING, Any, Never
|
|
12
|
+
|
|
13
|
+
from pyfect import _core
|
|
14
|
+
from pyfect._effect_args import require_effect
|
|
15
|
+
from pyfect._effect_base import A_co, E_co, EffectBase, R_co, Step, as_effect
|
|
16
|
+
from pyfect.cause import Cause, merge
|
|
17
|
+
from pyfect.exit import Exit, Failure, Success
|
|
18
|
+
from pyfect.result import Ok, Result
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from pyfect._core import Effect
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ResourceMethods(EffectBase[A_co, E_co, R_co]):
|
|
25
|
+
__slots__ = ()
|
|
26
|
+
|
|
27
|
+
def on_exit[R2 = Never](
|
|
28
|
+
self, f: Callable[[Exit[A_co, E_co]], Effect[object, Never, R2]]
|
|
29
|
+
) -> Effect[A_co, E_co, R_co | R2]:
|
|
30
|
+
"""Run ``f`` after this effect however it ends. ``f`` runs
|
|
31
|
+
uninterruptibly; if it fails, its cause is added to the result."""
|
|
32
|
+
return _on_exit(as_effect(self), f)
|
|
33
|
+
|
|
34
|
+
def on_exit_primitive[E2 = Never, R2 = Never](
|
|
35
|
+
self,
|
|
36
|
+
f: Callable[[Exit[A_co, E_co]], Effect[object, E2, R2] | None],
|
|
37
|
+
interruptible: bool = False,
|
|
38
|
+
) -> Effect[A_co, E_co | E2, R_co | R2]:
|
|
39
|
+
"""``on_exit`` whose ``f`` may return ``None``, and may fail, as
|
|
40
|
+
Effect's building block for it. With ``interruptible`` the finalizer
|
|
41
|
+
stays as interruptible as the fiber is: ``f`` is still called, but an
|
|
42
|
+
interrupted fiber does not run the effect it returns."""
|
|
43
|
+
|
|
44
|
+
def run(ex: Exit[A_co, E_co]) -> Effect[object, E2, R2]:
|
|
45
|
+
after = f(ex)
|
|
46
|
+
return _core._Succeed(None) if after is None else after
|
|
47
|
+
|
|
48
|
+
effect = as_effect(self)
|
|
49
|
+
if not interruptible:
|
|
50
|
+
return _on_exit(effect, run)
|
|
51
|
+
|
|
52
|
+
def finish(ex: Exit[A_co, E_co]) -> Step:
|
|
53
|
+
return _run_finalizer(run(ex), ex)
|
|
54
|
+
|
|
55
|
+
return _core._MatchCause(effect, lambda c: finish(Failure(c)), lambda a: finish(Success(a)))
|
|
56
|
+
|
|
57
|
+
def ensuring[R2 = Never](
|
|
58
|
+
self, finalizer: Effect[object, Never, R2]
|
|
59
|
+
) -> Effect[A_co, E_co, R_co | R2]:
|
|
60
|
+
require_effect(finalizer, "finalizer")
|
|
61
|
+
return self.on_exit(lambda _: finalizer)
|
|
62
|
+
|
|
63
|
+
def on_error[R2 = Never](
|
|
64
|
+
self, f: Callable[[Cause[E_co]], Effect[object, Never, R2]]
|
|
65
|
+
) -> Effect[A_co, E_co, R_co | R2]:
|
|
66
|
+
def handle(ex: Exit[A_co, E_co]) -> Effect[object, Never, R2]:
|
|
67
|
+
return f(ex.cause) if isinstance(ex, Failure) else _core._Succeed(None)
|
|
68
|
+
|
|
69
|
+
return self.on_exit(handle)
|
|
70
|
+
|
|
71
|
+
def on_error_if[E2 = Never, R2 = Never](
|
|
72
|
+
self,
|
|
73
|
+
predicate: Callable[[Cause[E_co]], bool],
|
|
74
|
+
f: Callable[[Cause[E_co]], Effect[object, E2, R2]],
|
|
75
|
+
) -> Effect[A_co, E_co | E2, R_co | R2]:
|
|
76
|
+
"""``on_error`` for the causes ``predicate`` accepts. If ``f``
|
|
77
|
+
fails, its cause is added to the result."""
|
|
78
|
+
|
|
79
|
+
def handle(ex: Exit[A_co, E_co]) -> Effect[object, E2, R2]:
|
|
80
|
+
if isinstance(ex, Failure) and predicate(ex.cause):
|
|
81
|
+
return f(ex.cause)
|
|
82
|
+
return _core._Succeed(None)
|
|
83
|
+
|
|
84
|
+
return _on_exit(as_effect(self), handle)
|
|
85
|
+
|
|
86
|
+
def on_error_filter[B, E2 = Never, R2 = Never](
|
|
87
|
+
self,
|
|
88
|
+
filter: Callable[[Cause[E_co]], Result[B, object]],
|
|
89
|
+
f: Callable[[B, Cause[E_co]], Effect[object, E2, R2]],
|
|
90
|
+
) -> Effect[A_co, E_co | E2, R_co | R2]:
|
|
91
|
+
"""``on_error`` for the causes ``filter`` passes (``Ok(value)``):
|
|
92
|
+
run ``f(value, cause)``."""
|
|
93
|
+
|
|
94
|
+
def handle(ex: Exit[A_co, E_co]) -> Effect[object, E2, R2]:
|
|
95
|
+
if isinstance(ex, Failure):
|
|
96
|
+
passed = filter(ex.cause)
|
|
97
|
+
if isinstance(passed, Ok):
|
|
98
|
+
return f(passed.value, ex.cause)
|
|
99
|
+
return _core._Succeed(None)
|
|
100
|
+
|
|
101
|
+
return _on_exit(as_effect(self), handle)
|
|
102
|
+
|
|
103
|
+
def on_exit_if[E2 = Never, R2 = Never](
|
|
104
|
+
self,
|
|
105
|
+
predicate: Callable[[Exit[A_co, E_co]], bool],
|
|
106
|
+
f: Callable[[Exit[A_co, E_co]], Effect[object, E2, R2]],
|
|
107
|
+
) -> Effect[A_co, E_co | E2, R_co | R2]:
|
|
108
|
+
"""``on_exit`` for the exits ``predicate`` accepts. If ``f`` fails,
|
|
109
|
+
its cause is added to the result."""
|
|
110
|
+
|
|
111
|
+
def handle(ex: Exit[A_co, E_co]) -> Effect[object, E2, R2]:
|
|
112
|
+
return f(ex) if predicate(ex) else _core._Succeed(None)
|
|
113
|
+
|
|
114
|
+
return _on_exit(as_effect(self), handle)
|
|
115
|
+
|
|
116
|
+
def on_exit_filter[B, E2 = Never, R2 = Never](
|
|
117
|
+
self,
|
|
118
|
+
filter: Callable[[Exit[A_co, E_co]], Result[B, object]],
|
|
119
|
+
f: Callable[[B, Exit[A_co, E_co]], Effect[object, E2, R2]],
|
|
120
|
+
) -> Effect[A_co, E_co | E2, R_co | R2]:
|
|
121
|
+
"""``on_exit`` for the exits ``filter`` passes (``Ok(value)``): run
|
|
122
|
+
``f(value, exit)``."""
|
|
123
|
+
|
|
124
|
+
def handle(ex: Exit[A_co, E_co]) -> Effect[object, E2, R2]:
|
|
125
|
+
passed = filter(ex)
|
|
126
|
+
return f(passed.value, ex) if isinstance(passed, Ok) else _core._Succeed(None)
|
|
127
|
+
|
|
128
|
+
return _on_exit(as_effect(self), handle)
|
|
129
|
+
|
|
130
|
+
def on_interrupt[R2 = Never](
|
|
131
|
+
self, finalizer: Effect[object, Never, R2]
|
|
132
|
+
) -> Effect[A_co, E_co, R_co | R2]:
|
|
133
|
+
require_effect(finalizer, "finalizer")
|
|
134
|
+
|
|
135
|
+
def handle(ex: Exit[A_co, E_co]) -> Effect[object, Never, R2]:
|
|
136
|
+
if isinstance(ex, Failure) and ex.cause.has_interrupts:
|
|
137
|
+
return finalizer
|
|
138
|
+
return _core._Succeed(None)
|
|
139
|
+
|
|
140
|
+
return self.on_exit(handle)
|
|
141
|
+
|
|
142
|
+
def uninterruptible(self) -> Effect[A_co, E_co, R_co]:
|
|
143
|
+
return _core._SetInterruptible(as_effect(self), False)
|
|
144
|
+
|
|
145
|
+
def interruptible(self) -> Effect[A_co, E_co, R_co]:
|
|
146
|
+
return _core._SetInterruptible(as_effect(self), True)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _on_exit[A, E, R, E2, R2](
|
|
150
|
+
eff: Effect[A, E, R], f: Callable[[Exit[A, E]], Effect[object, E2, R2]]
|
|
151
|
+
) -> Effect[A, E | E2, R | R2]:
|
|
152
|
+
"""Run ``f(exit)`` uninterruptibly after ``eff``; a failure of ``f``
|
|
153
|
+
adds its cause to the result."""
|
|
154
|
+
return _core.uninterruptible_mask(
|
|
155
|
+
lambda restore: _core._MatchCause(
|
|
156
|
+
restore(eff),
|
|
157
|
+
lambda c: _run_finalizer(_call_user(f, Failure(c)), Failure(c)),
|
|
158
|
+
lambda a: _run_finalizer(_call_user(f, Success(a)), Success(a)),
|
|
159
|
+
)
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _call_user[*Ts, A, E, R](f: Callable[[*Ts], Effect[A, E, R]], *args: *Ts) -> Effect[A, E, R]:
|
|
164
|
+
"""Call user code when the effect runs, not when it is built. A raise
|
|
165
|
+
then becomes a defect at that point of the program, inside whatever
|
|
166
|
+
finalizer or region surrounds it. Resource and finalizer combinators
|
|
167
|
+
call every user callback through this."""
|
|
168
|
+
return _core._Suspend(lambda: f(*args))
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _run_finalizer(finalizer: Effect[object, Any, Any], ex: Exit[Any, Any]) -> Step:
|
|
172
|
+
"""Run ``finalizer``, then end with ``ex``. A failing finalizer adds
|
|
173
|
+
its cause to the result."""
|
|
174
|
+
|
|
175
|
+
def after_failure(fin_cause: Cause[Any]) -> Effect[Any, Any, Any]:
|
|
176
|
+
base = ex.cause if isinstance(ex, Failure) else Cause(())
|
|
177
|
+
return _core._FailCause(merge(base, fin_cause))
|
|
178
|
+
|
|
179
|
+
return _core._MatchCause(finalizer, after_failure, lambda _: _core._FromExit(ex))
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""``Effect`` methods for services."""
|
|
2
|
+
# pyright: reportPrivateUsage=false
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
from pyfect import _core
|
|
10
|
+
from pyfect._effect_base import A_co, E_co, EffectBase, R_co, as_effect
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pyfect._core import Effect
|
|
14
|
+
from pyfect.context import TagLike
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ServiceMethods(EffectBase[A_co, E_co, R_co]):
|
|
18
|
+
__slots__ = ()
|
|
19
|
+
|
|
20
|
+
def update_service[S, T](
|
|
21
|
+
self, tag: TagLike[S, T], f: Callable[[S], S]
|
|
22
|
+
) -> Effect[A_co, E_co, R_co | T]:
|
|
23
|
+
"""Run with ``f`` applied to the service of ``tag``, which this
|
|
24
|
+
effect then needs."""
|
|
25
|
+
return _core._Locally(as_effect(self), lambda ctx: ctx.add(tag, f(ctx.get_unsafe(tag))))
|
pyfect/_effect_timing.py
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""``Effect`` methods over time: delaying, timing, caching and schedules.
|
|
2
|
+
The work lives in ``pyfect.clock``, ``pyfect._cached`` and
|
|
3
|
+
``pyfect.schedule``; these are the method spellings."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Never, TypeIs, overload
|
|
9
|
+
|
|
10
|
+
from pyfect._effect_base import A_co, E_co, EffectBase, R_co, as_effect
|
|
11
|
+
from pyfect.duration import Duration
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from pyfect._core import Effect
|
|
15
|
+
from pyfect.exit import Exit
|
|
16
|
+
from pyfect.schedule import Metadata, Schedule, SetInputType
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TimingMethods(EffectBase[A_co, E_co, R_co]):
|
|
20
|
+
__slots__ = ()
|
|
21
|
+
|
|
22
|
+
def delay(self, duration: Duration) -> Effect[A_co, E_co, R_co]:
|
|
23
|
+
from pyfect.clock import sleep
|
|
24
|
+
|
|
25
|
+
return sleep(duration).and_then(as_effect(self))
|
|
26
|
+
|
|
27
|
+
def timed(self) -> Effect[tuple[float, A_co], E_co, R_co]:
|
|
28
|
+
"""Pair the value with how long it took, in seconds."""
|
|
29
|
+
from pyfect.clock import timed
|
|
30
|
+
|
|
31
|
+
return timed(as_effect(self))
|
|
32
|
+
|
|
33
|
+
def cached(self) -> Effect[Effect[A_co, E_co, R_co]]:
|
|
34
|
+
"""An effect that runs this one on first use and then replays its
|
|
35
|
+
exit. Concurrent callers share one run; an interrupted run is not
|
|
36
|
+
cached (see ``cached_invalidate_with_ttl``)."""
|
|
37
|
+
from pyfect._cached import cached
|
|
38
|
+
|
|
39
|
+
return cached(as_effect(self))
|
|
40
|
+
|
|
41
|
+
def cached_with_ttl(
|
|
42
|
+
self, time_to_live: Duration | Callable[[Exit[A_co, E_co]], Duration]
|
|
43
|
+
) -> Effect[Effect[A_co, E_co, R_co]]:
|
|
44
|
+
"""``cached``, but each exit is replayed only for ``time_to_live``
|
|
45
|
+
(or ``time_to_live(exit)``) after it was produced."""
|
|
46
|
+
from pyfect._cached import cached_invalidate_with_ttl
|
|
47
|
+
|
|
48
|
+
return cached_invalidate_with_ttl(as_effect(self), time_to_live).map(lambda pair: pair[0])
|
|
49
|
+
|
|
50
|
+
def cached_invalidate_with_ttl(
|
|
51
|
+
self, time_to_live: Duration | Callable[[Exit[A_co, E_co]], Duration]
|
|
52
|
+
) -> Effect[tuple[Effect[A_co, E_co, R_co], Effect[None]]]:
|
|
53
|
+
"""``cached_with_ttl`` plus an effect that drops the cached exit.
|
|
54
|
+
|
|
55
|
+
Callers already waiting on a run keep waiting on it; later callers
|
|
56
|
+
start a fresh run. A run is interrupted once every caller waiting on
|
|
57
|
+
it has gone, and an interrupted run is never cached."""
|
|
58
|
+
from pyfect._cached import cached_invalidate_with_ttl
|
|
59
|
+
|
|
60
|
+
return cached_invalidate_with_ttl(as_effect(self), time_to_live)
|
|
61
|
+
|
|
62
|
+
@overload
|
|
63
|
+
def retry[EE = Never, RR = Never](
|
|
64
|
+
self, policy: Schedule[object, E_co, EE, RR], /
|
|
65
|
+
) -> Effect[A_co, E_co | EE, R_co | RR]: ...
|
|
66
|
+
@overload
|
|
67
|
+
def retry[A, E, R, EE = Never, RR = Never](
|
|
68
|
+
self: TimingMethods[A, E, R],
|
|
69
|
+
builder: Callable[[SetInputType[E]], Schedule[object, E, EE, RR]],
|
|
70
|
+
/,
|
|
71
|
+
) -> Effect[A, E | EE, R | RR]: ...
|
|
72
|
+
@overload
|
|
73
|
+
def retry[E2](self, /, *, until: Callable[[E_co], TypeIs[E2]]) -> Effect[A_co, E2, R_co]: ...
|
|
74
|
+
@overload
|
|
75
|
+
def retry[EE = Never, RR = Never](
|
|
76
|
+
self,
|
|
77
|
+
/,
|
|
78
|
+
*,
|
|
79
|
+
schedule: Schedule[object, E_co, EE, RR] | None = None,
|
|
80
|
+
times: int | None = None,
|
|
81
|
+
while_: Callable[[E_co], bool | Effect[bool, EE, RR]] | None = None,
|
|
82
|
+
until: Callable[[E_co], bool | Effect[bool, EE, RR]] | None = None,
|
|
83
|
+
) -> Effect[A_co, E_co | EE, R_co | RR]: ...
|
|
84
|
+
def retry(
|
|
85
|
+
self,
|
|
86
|
+
policy: Schedule[Any, Any, Any, Any] | Callable[[Any], Any] | None = None,
|
|
87
|
+
/,
|
|
88
|
+
*,
|
|
89
|
+
schedule: Schedule[Any, Any, Any, Any] | None = None,
|
|
90
|
+
times: int | None = None,
|
|
91
|
+
while_: Callable[[Any], Any] | None = None,
|
|
92
|
+
until: Callable[[Any], Any] | None = None,
|
|
93
|
+
) -> Effect[Any, Any, Any]:
|
|
94
|
+
"""Retry on typed failure while ``policy`` recurs; then fail with the
|
|
95
|
+
last error. Defects and interruptions are not retried.
|
|
96
|
+
|
|
97
|
+
``policy`` is a schedule, or a function from ``SetInputType`` to
|
|
98
|
+
one, so the schedule's metadata sees this effect's error type::
|
|
99
|
+
|
|
100
|
+
eff.retry(lambda typed: typed(schedule.recurs(3)).while_(lambda m: m.input.retryable))
|
|
101
|
+
|
|
102
|
+
Instead of a policy, the keywords build one: retry at most
|
|
103
|
+
``times`` times, only while ``while_(error)`` holds, until
|
|
104
|
+
``until(error)`` holds, on ``schedule``'s delays. Predicates may
|
|
105
|
+
return a bool or an effect of one; with a ``TypeIs`` predicate as
|
|
106
|
+
``until`` and no other keyword, the error narrows (``while_`` can
|
|
107
|
+
stop on any error, so with it nothing narrows)."""
|
|
108
|
+
from pyfect.schedule._drive import resolve_policy, retry
|
|
109
|
+
|
|
110
|
+
policy = resolve_policy(policy, schedule, times, while_, until)
|
|
111
|
+
return retry(as_effect(self), policy)
|
|
112
|
+
|
|
113
|
+
def retry_or_else[B, A2, EE = Never, RR = Never](
|
|
114
|
+
self,
|
|
115
|
+
policy: Schedule[B, E_co, EE, RR],
|
|
116
|
+
or_else: Callable[[E_co, B], Effect[A2, EE, RR]],
|
|
117
|
+
) -> Effect[A_co | A2, EE, R_co | RR]:
|
|
118
|
+
"""``retry``, handing the last error and the policy's final output
|
|
119
|
+
to ``or_else`` once the policy stops."""
|
|
120
|
+
from pyfect.schedule._drive import retry_or_else
|
|
121
|
+
|
|
122
|
+
return retry_or_else(as_effect(self), policy, or_else)
|
|
123
|
+
|
|
124
|
+
@overload
|
|
125
|
+
def repeat[B, EE = Never, RR = Never](
|
|
126
|
+
self, schedule: Schedule[B, A_co, EE, RR], /
|
|
127
|
+
) -> Effect[B, E_co | EE, R_co | RR]: ...
|
|
128
|
+
@overload
|
|
129
|
+
def repeat[A, E, R, B, EE = Never, RR = Never](
|
|
130
|
+
self: TimingMethods[A, E, R],
|
|
131
|
+
builder: Callable[[SetInputType[A]], Schedule[B, A, EE, RR]],
|
|
132
|
+
/,
|
|
133
|
+
) -> Effect[B, E | EE, R | RR]: ...
|
|
134
|
+
@overload
|
|
135
|
+
def repeat[B](self, /, *, until: Callable[[A_co], TypeIs[B]]) -> Effect[B, E_co, R_co]: ...
|
|
136
|
+
@overload
|
|
137
|
+
def repeat[EE = Never, RR = Never](
|
|
138
|
+
self,
|
|
139
|
+
/,
|
|
140
|
+
*,
|
|
141
|
+
schedule: Schedule[object, A_co, EE, RR] | None = None,
|
|
142
|
+
times: int | None = None,
|
|
143
|
+
while_: Callable[[A_co], bool | Effect[bool, EE, RR]] | None = None,
|
|
144
|
+
until: Callable[[A_co], bool | Effect[bool, EE, RR]] | None = None,
|
|
145
|
+
) -> Effect[A_co, E_co | EE, R_co | RR]: ...
|
|
146
|
+
def repeat(
|
|
147
|
+
self,
|
|
148
|
+
policy: Schedule[Any, Any, Any, Any] | Callable[[Any], Any] | None = None,
|
|
149
|
+
/,
|
|
150
|
+
*,
|
|
151
|
+
schedule: Schedule[Any, Any, Any, Any] | None = None,
|
|
152
|
+
times: int | None = None,
|
|
153
|
+
while_: Callable[[Any], Any] | None = None,
|
|
154
|
+
until: Callable[[Any], Any] | None = None,
|
|
155
|
+
) -> Effect[Any, Any, Any]:
|
|
156
|
+
"""Repeat after each success while the schedule recurs. Succeeds
|
|
157
|
+
with the schedule's final output. The schedule may also be given
|
|
158
|
+
as a function from ``SetInputType`` to one (see ``retry``).
|
|
159
|
+
|
|
160
|
+
Instead of a schedule, the keywords build one: repeat at most
|
|
161
|
+
``times`` times, only while ``while_(value)`` holds, until
|
|
162
|
+
``until(value)`` holds, on ``schedule``'s delays. That form
|
|
163
|
+
succeeds with the last value, narrowed by a ``TypeIs`` predicate
|
|
164
|
+
as ``until`` when it is the only keyword. Predicates may
|
|
165
|
+
return a bool or an effect of one."""
|
|
166
|
+
from pyfect.schedule._drive import repeat, resolve_policy
|
|
167
|
+
|
|
168
|
+
policy = resolve_policy(policy, schedule, times, while_, until)
|
|
169
|
+
return repeat(as_effect(self), policy)
|
|
170
|
+
|
|
171
|
+
def repeat_or_else[B, B2, E2, EE = Never, RR = Never](
|
|
172
|
+
self,
|
|
173
|
+
schedule: Schedule[B, A_co, EE, RR],
|
|
174
|
+
or_else: Callable[[E_co | EE, Metadata[B, A_co] | None], Effect[B2, E2, RR]],
|
|
175
|
+
) -> Effect[B | B2, E2, R_co | RR]:
|
|
176
|
+
"""``repeat``, handing a typed failure (of this effect or of the
|
|
177
|
+
schedule) and the last step's metadata (``None`` before the first)
|
|
178
|
+
to ``or_else``."""
|
|
179
|
+
from pyfect.schedule._drive import repeat_or_else
|
|
180
|
+
|
|
181
|
+
return repeat_or_else(as_effect(self), schedule, or_else)
|
|
182
|
+
|
|
183
|
+
def schedule[B, EE = Never, RR = Never](
|
|
184
|
+
self, schedule: Schedule[B, A_co | None, EE, RR]
|
|
185
|
+
) -> Effect[B, E_co | EE, R_co | RR]:
|
|
186
|
+
"""Run after each recurrence of ``schedule`` (first after its first
|
|
187
|
+
delay), stepping it with ``None`` and then each result. Succeeds
|
|
188
|
+
with the schedule's final output."""
|
|
189
|
+
from pyfect.schedule._drive import scheduled
|
|
190
|
+
|
|
191
|
+
return scheduled(as_effect(self), schedule)
|
|
192
|
+
|
|
193
|
+
def schedule_from[A, B, EE = Never, RR = Never](
|
|
194
|
+
self: TimingMethods[A, E_co, R_co], initial: A, schedule: Schedule[B, A, EE, RR]
|
|
195
|
+
) -> Effect[B, E_co | EE, R_co | RR]:
|
|
196
|
+
"""``schedule``, stepping first with ``initial``."""
|
|
197
|
+
from pyfect.schedule._drive import schedule_from
|
|
198
|
+
|
|
199
|
+
return schedule_from(as_effect(self), initial, schedule)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""``Effect`` methods for tracing: spans around an effect, and what the
|
|
2
|
+
spans made inside it carry."""
|
|
3
|
+
# pyright: reportPrivateUsage=false
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from collections.abc import Mapping
|
|
8
|
+
from typing import TYPE_CHECKING, Unpack, overload
|
|
9
|
+
|
|
10
|
+
from pyfect._effect_base import A_co, E_co, EffectBase, R_co, as_effect
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pyfect._core import Effect
|
|
14
|
+
from pyfect._stack_frame import CaptureStackTrace
|
|
15
|
+
from pyfect.scope import Scope
|
|
16
|
+
from pyfect.tracer import AnySpan, TracedSpanOptions, Tracer
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TracingMethods(EffectBase[A_co, E_co, R_co]):
|
|
20
|
+
__slots__ = ()
|
|
21
|
+
|
|
22
|
+
def with_span(
|
|
23
|
+
self, name: str, **options: Unpack[TracedSpanOptions]
|
|
24
|
+
) -> Effect[A_co, E_co, R_co]:
|
|
25
|
+
"""Run inside a new span, the parent of the spans made inside. It
|
|
26
|
+
ends with this effect's exit. Failures inside record the span's
|
|
27
|
+
stack frame: this call site unless ``capture_stack_trace`` says
|
|
28
|
+
otherwise."""
|
|
29
|
+
from pyfect._stack_frame import stack_of
|
|
30
|
+
from pyfect.tracer._spans import in_span_frame, span_using
|
|
31
|
+
|
|
32
|
+
eff = as_effect(self)
|
|
33
|
+
stack = stack_of(options.get("capture_stack_trace", True), 1)
|
|
34
|
+
return span_using(name, lambda span: in_span_frame(eff, span, stack), options)
|
|
35
|
+
|
|
36
|
+
def with_span_scoped(
|
|
37
|
+
self, name: str, **options: Unpack[TracedSpanOptions]
|
|
38
|
+
) -> Effect[A_co, E_co, R_co | Scope]:
|
|
39
|
+
"""Run inside a new span that ends when the current scope closes."""
|
|
40
|
+
from pyfect._stack_frame import stack_of
|
|
41
|
+
from pyfect.tracer._spans import in_span_frame, span_scoped
|
|
42
|
+
|
|
43
|
+
eff = as_effect(self)
|
|
44
|
+
stack = stack_of(options.get("capture_stack_trace", True), 1)
|
|
45
|
+
return span_scoped(name, options).flat_map(lambda span: in_span_frame(eff, span, stack))
|
|
46
|
+
|
|
47
|
+
def with_parent_span(
|
|
48
|
+
self, span: AnySpan, *, capture_stack_trace: CaptureStackTrace = True
|
|
49
|
+
) -> Effect[A_co, E_co, R_co]:
|
|
50
|
+
"""Run with ``span`` as the parent of the spans made inside, and,
|
|
51
|
+
unless it is external, inside its stack frame."""
|
|
52
|
+
from pyfect._stack_frame import stack_of
|
|
53
|
+
from pyfect.tracer._spans import in_span_frame
|
|
54
|
+
|
|
55
|
+
return in_span_frame(as_effect(self), span, stack_of(capture_stack_trace, 1))
|
|
56
|
+
|
|
57
|
+
@overload
|
|
58
|
+
def annotate_spans(self, key: str, value: object, /) -> Effect[A_co, E_co, R_co]: ...
|
|
59
|
+
@overload
|
|
60
|
+
def annotate_spans(self, values: Mapping[str, object], /) -> Effect[A_co, E_co, R_co]: ...
|
|
61
|
+
def annotate_spans(
|
|
62
|
+
self, key_or_values: str | Mapping[str, object], value: object = None, /
|
|
63
|
+
) -> Effect[A_co, E_co, R_co]:
|
|
64
|
+
"""Run with these attributes set on every span made inside."""
|
|
65
|
+
from pyfect.tracer._refs import TracerSpanAnnotations
|
|
66
|
+
|
|
67
|
+
added = {key_or_values: value} if isinstance(key_or_values, str) else dict(key_or_values)
|
|
68
|
+
return as_effect(self).update_service(
|
|
69
|
+
TracerSpanAnnotations, lambda annotations: {**annotations, **added}
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def link_spans(
|
|
73
|
+
self, *spans: AnySpan, attributes: Mapping[str, object] | None = None
|
|
74
|
+
) -> Effect[A_co, E_co, R_co]:
|
|
75
|
+
"""Run with links to ``spans`` added to every span made inside."""
|
|
76
|
+
from pyfect.tracer._model import SpanLink
|
|
77
|
+
from pyfect.tracer._refs import TracerSpanLinks
|
|
78
|
+
|
|
79
|
+
shared: Mapping[str, object] = {} if attributes is None else attributes
|
|
80
|
+
links = tuple(SpanLink(span, shared) for span in spans)
|
|
81
|
+
return as_effect(self).update_service(TracerSpanLinks, lambda current: (*current, *links))
|
|
82
|
+
|
|
83
|
+
def with_tracer(self, tracer: Tracer) -> Effect[A_co, E_co, R_co]:
|
|
84
|
+
"""Run with spans made by ``tracer``."""
|
|
85
|
+
from pyfect._tracer_ref import CurrentTracer
|
|
86
|
+
|
|
87
|
+
return as_effect(self).update_service(CurrentTracer, lambda _: tracer)
|
|
88
|
+
|
|
89
|
+
def with_tracer_enabled(self, enabled: bool) -> Effect[A_co, E_co, R_co]:
|
|
90
|
+
"""Run with tracing on or off: off, every span is a no-op span."""
|
|
91
|
+
from pyfect.tracer._refs import TracerEnabled
|
|
92
|
+
|
|
93
|
+
return as_effect(self).update_service(TracerEnabled, lambda _: enabled)
|
|
94
|
+
|
|
95
|
+
def with_tracer_timing(self, enabled: bool) -> Effect[A_co, E_co, R_co]:
|
|
96
|
+
"""Run with span timing on or off: off, spans start and end at 0."""
|
|
97
|
+
from pyfect.tracer._refs import TracerTimingEnabled
|
|
98
|
+
|
|
99
|
+
return as_effect(self).update_service(TracerTimingEnabled, lambda _: enabled)
|