tigrbl-atoms 0.4.5.dev4__tar.gz → 0.4.5.dev8__tar.gz
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.
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/PKG-INFO +19 -8
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/README.md +16 -5
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/pyproject.toml +5 -3
- tigrbl_atoms-0.4.5.dev8/tigrbl_atoms/_opview_helpers.py +377 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/err/rollback.py +3 -1
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/framing/__init__.py +12 -0
- tigrbl_atoms-0.4.5.dev8/tigrbl_atoms/atoms/framing/websocket_jsonrpc.py +59 -0
- tigrbl_atoms-0.4.5.dev8/tigrbl_atoms/atoms/framing/webtransport_records.py +64 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/response/error_to_transport.py +5 -2
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/storage/to_stored.py +5 -2
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/_oltp_context.py +56 -97
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/commit_tx.py +3 -1
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_bulk_delete.py +1 -2
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_clear.py +3 -1
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_persistence.py +2 -3
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_publish.py +1 -1
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_replace.py +2 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_subscribe.py +1 -1
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_update.py +2 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/transport/__init__.py +2 -1
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/transport/asgi_channel.py +79 -26
- tigrbl_atoms-0.4.5.dev8/tigrbl_atoms/atoms/transport/sink_bind.py +65 -0
- tigrbl_atoms-0.4.5.dev8/tigrbl_atoms/atoms/transport/websocket.py +112 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/wire/build_in.py +8 -22
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/wire/validate_in.py +60 -68
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/runtime_channel.py +20 -1
- tigrbl_atoms-0.4.5.dev4/tigrbl_atoms/_opview_helpers.py +0 -190
- tigrbl_atoms-0.4.5.dev4/tigrbl_atoms/atoms/transport/sink_bind.py +0 -37
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/LICENSE +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/NOTICE +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/_ctx.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/_request.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/algebra.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/_temp.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/_scheduler.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/_types.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/abort_group.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/admit.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/await_seal.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/cleanup.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/commit.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/dedupe.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/error_project.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/execute.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/precommit_validate.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/prepare_execute.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/reject_admission.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/result_slots.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/scheduler.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/seal_check.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/batch/tx_begin.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/dep/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/dep/_param_resolver.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/dep/extra.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/dep/security.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/dispatch/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/dispatch/binding_match.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/dispatch/binding_parse.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/dispatch/input_normalize.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/dispatch/op_resolve.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/egress/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/egress/asgi_send.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/egress/envelope_apply.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/egress/headers_apply.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/egress/http_finalize.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/egress/out_dump.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/egress/result_normalize.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/egress/to_transport_response.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/emit/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/emit/paired_post.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/emit/paired_pre.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/emit/readtime_alias.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/err/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/err/classify.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/err/ctx_build.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/err/transport_shape.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/fanout/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/fanout/emit_many.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/fanout/shape.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/framing/app_frame.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/framing/codec.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/hot/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/hot/slots.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/ingress/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/ingress/ctx_init.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/ingress/input_prepare.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/ingress/transport_extract.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/intent/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/intent/build.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/intent/final_group_key.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/intent/prekey.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/out/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/out/masking.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/refresh/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/refresh/demand.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/resolve/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/resolve/assemble.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/resolve/paired_gen.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/response/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/response/headers_from_payload.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/response/negotiate.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/response/negotiation.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/response/render.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/response/renderer.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/response/template.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/response/templates.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/schema/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/schema/collect_in.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/schema/collect_out.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/storage/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/_db.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_aggregate.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_append_chunk.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_bulk_create.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_bulk_merge.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_bulk_replace.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_bulk_update.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_checkpoint.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_close_session.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_close_stream.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_count.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_create.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_custom.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_delete.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_download.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_exists.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_group_by.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_list.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_merge.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_noop.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_open_bidi_stream.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_open_unidi_stream.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_read.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_send_datagram.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_tail.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_upload.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/handler_well_known.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/phase_db.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/sys/start_tx.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/transport/completion_fence.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/transport/unit_capture.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/transport/websocket_unary.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/wire/__init__.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/wire/build_out.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/atoms/wire/dump.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/client_session_coverage.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/events.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/packed_inputs.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/phases.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/protocol_runtime.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/protocol_scope.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/runtime_callbacks.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/runtime_loop_regions.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/runtime_resume.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/runtime_transactions.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/stages.py +0 -0
- {tigrbl_atoms-0.4.5.dev4 → tigrbl_atoms-0.4.5.dev8}/tigrbl_atoms/types.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tigrbl-atoms
|
|
3
|
-
Version: 0.4.5.
|
|
3
|
+
Version: 0.4.5.dev8
|
|
4
4
|
Summary: Runtime atom package for Tigrbl stages, phases, typed contexts, event anchors, protocol execution, and composable pipeline algebra.
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -232,7 +232,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
232
232
|
Classifier: Typing :: Typed
|
|
233
233
|
Requires-Dist: jinja2 (>=3.1)
|
|
234
234
|
Requires-Dist: sqlalchemy (>=2.0)
|
|
235
|
-
Requires-Dist: tigrbl-core
|
|
235
|
+
Requires-Dist: tigrbl-core (>=0.4.5.dev6)
|
|
236
236
|
Requires-Dist: tigrbl-ops-olap
|
|
237
237
|
Requires-Dist: tigrbl-ops-oltp
|
|
238
238
|
Requires-Dist: tigrbl-ops-realtime
|
|
@@ -243,7 +243,7 @@ Project-URL: Discord, https://discord.gg/K4YTAPapjR
|
|
|
243
243
|
Project-URL: Homepage, https://github.com/tigrbl/tigrbl
|
|
244
244
|
Project-URL: Issues, https://github.com/tigrbl/tigrbl/issues
|
|
245
245
|
Project-URL: Organization, https://github.com/tigrbl
|
|
246
|
-
Project-URL: Repository, https://github.com/tigrbl/tigrbl/tree/master/pkgs/
|
|
246
|
+
Project-URL: Repository, https://github.com/tigrbl/tigrbl/tree/master/pkgs/40_atoms/tigrbl_atoms
|
|
247
247
|
Description-Content-Type: text/markdown
|
|
248
248
|
|
|
249
249
|
<div align="center">
|
|
@@ -253,7 +253,7 @@ Description-Content-Type: text/markdown
|
|
|
253
253
|
<a href="https://pypi.org/project/tigrbl-atoms/"><img src="https://img.shields.io/pypi/v/tigrbl-atoms?label=PyPI" alt="PyPI version for tigrbl-atoms"/></a>
|
|
254
254
|
<a href="https://pypi.org/project/tigrbl-atoms/"><img src="https://static.pepy.tech/badge/tigrbl-atoms" alt="Downloads for tigrbl-atoms"/></a>
|
|
255
255
|
<a href="https://discord.gg/K4YTAPapjR"><img src="https://img.shields.io/badge/Discord-Join%20chat-5865F2?logo=discord&logoColor=white" alt="Discord community for tigrbl-atoms"/></a>
|
|
256
|
-
<a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/
|
|
256
|
+
<a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/40_atoms/tigrbl_atoms/README.md"><img src="https://hits.sh/github.com/tigrbl/tigrbl/blob/master/pkgs/40_atoms/tigrbl_atoms/README.md.svg?label=hits" alt="Repository hits for tigrbl-atoms README"/></a>
|
|
257
257
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-525252" alt="Apache 2.0 license"/></a>
|
|
258
258
|
<a href="pyproject.toml"><img src="https://img.shields.io/badge/python-3.10%2C%203.11%2C%203.12%2C%203.13%2C%203.14-3776ab" alt="Python versions 3.10 | 3.11 | 3.12 | 3.13 | 3.14 for tigrbl-atoms"/></a>
|
|
259
259
|
<a href="https://github.com/tigrbl/tigrbl/blob/master/docs/README.md"><img src="https://img.shields.io/badge/workspace-core-1f6feb" alt="Workspace group for tigrbl-atoms"/></a>
|
|
@@ -277,12 +277,23 @@ Framework maintainers, extension authors, and advanced users composing Tigrbl fr
|
|
|
277
277
|
|
|
278
278
|
## Where does tigrbl-atoms fit?
|
|
279
279
|
|
|
280
|
-
`tigrbl-atoms` lives at `pkgs/
|
|
280
|
+
`tigrbl-atoms` lives at `pkgs/40_atoms/tigrbl_atoms` and serves a focused layer in the split Tigrbl framework.
|
|
281
281
|
|
|
282
282
|
## How does tigrbl-atoms work?
|
|
283
283
|
|
|
284
284
|
It owns a narrow layer in the split workspace and is consumed by higher-level packages through explicit dependencies.
|
|
285
285
|
|
|
286
|
+
Inbound materialization belongs to `wire.validate_in`, which uses the core schema
|
|
287
|
+
materializer and declared field types (or mapped storage types when no field type
|
|
288
|
+
is declared). Member identifiers are selector inputs even when the primary key
|
|
289
|
+
is not writable. Route selectors take precedence over payload identifiers and
|
|
290
|
+
invalid selectors raise 422 before persistence. Persistence atoms consume the
|
|
291
|
+
validated payload and path carriers, including bulk values; CRUD helpers do not
|
|
292
|
+
repeat type coercion. Selector operations currently use the full atom pipeline
|
|
293
|
+
because the compiled scalar input shortcut does not implement route alias and
|
|
294
|
+
selector precedence validation. CRUD operations retain their existing flush-only
|
|
295
|
+
transaction contract; the caller owns commit or rollback.
|
|
296
|
+
|
|
286
297
|
|
|
287
298
|
## Install
|
|
288
299
|
|
|
@@ -299,7 +310,7 @@ pip install tigrbl-atoms
|
|
|
299
310
|
| Surface | Value |
|
|
300
311
|
|---|---|
|
|
301
312
|
| PyPI package | [`tigrbl-atoms`](https://pypi.org/project/tigrbl-atoms/) |
|
|
302
|
-
| Repository path | [`pkgs/
|
|
313
|
+
| Repository path | [`pkgs/40_atoms/tigrbl_atoms`](https://github.com/tigrbl/tigrbl/tree/master/pkgs/40_atoms/tigrbl_atoms) |
|
|
303
314
|
| Python import root | `tigrbl_atoms` |
|
|
304
315
|
| Console scripts | none declared |
|
|
305
316
|
| Entry points | none declared |
|
|
@@ -466,7 +477,7 @@ Choose `tigrbl-atoms` when the quick-answer table matches your use case. Choose
|
|
|
466
477
|
|
|
467
478
|
- Community: [Discord](https://discord.gg/K4YTAPapjR).
|
|
468
479
|
- Issues: [GitHub Issues](https://github.com/tigrbl/tigrbl/issues).
|
|
469
|
-
- Repository: [pkgs/
|
|
480
|
+
- Repository: [pkgs/40_atoms/tigrbl_atoms](https://github.com/tigrbl/tigrbl/tree/master/pkgs/40_atoms/tigrbl_atoms).
|
|
470
481
|
|
|
471
482
|
## Package-local Boundary
|
|
472
483
|
|
|
@@ -477,7 +488,7 @@ This file is a package-local distribution entry point. This README is the packag
|
|
|
477
488
|
- Package status: governed package in the `tigrbl/tigrbl` workspace.
|
|
478
489
|
- Governance source: [SSOT registry](https://github.com/tigrbl/tigrbl/blob/master/.ssot/registry.json).
|
|
479
490
|
- Release evidence: [publish workflow](https://github.com/tigrbl/tigrbl/actions/workflows/publish.yml) validates package builds, tests, GitHub release assets, and PyPI publication for managed packages.
|
|
480
|
-
- Local certification guard: `pkgs/
|
|
491
|
+
- Local certification guard: `pkgs/97_tests/tigrbl_tests/tests/unit/test_package_badges_and_notices.py` verifies every package README keeps the Discord badge, Apache 2.0 badge, explicit Python-version badge, `LICENSE`, and `NOTICE`.
|
|
481
492
|
- Scope note: this README documents the package boundary. Runtime feature support remains governed by `.ssot/` entities and the conformance docs linked below.
|
|
482
493
|
|
|
483
494
|
## License
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<a href="https://pypi.org/project/tigrbl-atoms/"><img src="https://img.shields.io/pypi/v/tigrbl-atoms?label=PyPI" alt="PyPI version for tigrbl-atoms"/></a>
|
|
6
6
|
<a href="https://pypi.org/project/tigrbl-atoms/"><img src="https://static.pepy.tech/badge/tigrbl-atoms" alt="Downloads for tigrbl-atoms"/></a>
|
|
7
7
|
<a href="https://discord.gg/K4YTAPapjR"><img src="https://img.shields.io/badge/Discord-Join%20chat-5865F2?logo=discord&logoColor=white" alt="Discord community for tigrbl-atoms"/></a>
|
|
8
|
-
<a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/
|
|
8
|
+
<a href="https://github.com/tigrbl/tigrbl/blob/master/pkgs/40_atoms/tigrbl_atoms/README.md"><img src="https://hits.sh/github.com/tigrbl/tigrbl/blob/master/pkgs/40_atoms/tigrbl_atoms/README.md.svg?label=hits" alt="Repository hits for tigrbl-atoms README"/></a>
|
|
9
9
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-525252" alt="Apache 2.0 license"/></a>
|
|
10
10
|
<a href="pyproject.toml"><img src="https://img.shields.io/badge/python-3.10%2C%203.11%2C%203.12%2C%203.13%2C%203.14-3776ab" alt="Python versions 3.10 | 3.11 | 3.12 | 3.13 | 3.14 for tigrbl-atoms"/></a>
|
|
11
11
|
<a href="https://github.com/tigrbl/tigrbl/blob/master/docs/README.md"><img src="https://img.shields.io/badge/workspace-core-1f6feb" alt="Workspace group for tigrbl-atoms"/></a>
|
|
@@ -29,12 +29,23 @@ Framework maintainers, extension authors, and advanced users composing Tigrbl fr
|
|
|
29
29
|
|
|
30
30
|
## Where does tigrbl-atoms fit?
|
|
31
31
|
|
|
32
|
-
`tigrbl-atoms` lives at `pkgs/
|
|
32
|
+
`tigrbl-atoms` lives at `pkgs/40_atoms/tigrbl_atoms` and serves a focused layer in the split Tigrbl framework.
|
|
33
33
|
|
|
34
34
|
## How does tigrbl-atoms work?
|
|
35
35
|
|
|
36
36
|
It owns a narrow layer in the split workspace and is consumed by higher-level packages through explicit dependencies.
|
|
37
37
|
|
|
38
|
+
Inbound materialization belongs to `wire.validate_in`, which uses the core schema
|
|
39
|
+
materializer and declared field types (or mapped storage types when no field type
|
|
40
|
+
is declared). Member identifiers are selector inputs even when the primary key
|
|
41
|
+
is not writable. Route selectors take precedence over payload identifiers and
|
|
42
|
+
invalid selectors raise 422 before persistence. Persistence atoms consume the
|
|
43
|
+
validated payload and path carriers, including bulk values; CRUD helpers do not
|
|
44
|
+
repeat type coercion. Selector operations currently use the full atom pipeline
|
|
45
|
+
because the compiled scalar input shortcut does not implement route alias and
|
|
46
|
+
selector precedence validation. CRUD operations retain their existing flush-only
|
|
47
|
+
transaction contract; the caller owns commit or rollback.
|
|
48
|
+
|
|
38
49
|
|
|
39
50
|
## Install
|
|
40
51
|
|
|
@@ -51,7 +62,7 @@ pip install tigrbl-atoms
|
|
|
51
62
|
| Surface | Value |
|
|
52
63
|
|---|---|
|
|
53
64
|
| PyPI package | [`tigrbl-atoms`](https://pypi.org/project/tigrbl-atoms/) |
|
|
54
|
-
| Repository path | [`pkgs/
|
|
65
|
+
| Repository path | [`pkgs/40_atoms/tigrbl_atoms`](https://github.com/tigrbl/tigrbl/tree/master/pkgs/40_atoms/tigrbl_atoms) |
|
|
55
66
|
| Python import root | `tigrbl_atoms` |
|
|
56
67
|
| Console scripts | none declared |
|
|
57
68
|
| Entry points | none declared |
|
|
@@ -218,7 +229,7 @@ Choose `tigrbl-atoms` when the quick-answer table matches your use case. Choose
|
|
|
218
229
|
|
|
219
230
|
- Community: [Discord](https://discord.gg/K4YTAPapjR).
|
|
220
231
|
- Issues: [GitHub Issues](https://github.com/tigrbl/tigrbl/issues).
|
|
221
|
-
- Repository: [pkgs/
|
|
232
|
+
- Repository: [pkgs/40_atoms/tigrbl_atoms](https://github.com/tigrbl/tigrbl/tree/master/pkgs/40_atoms/tigrbl_atoms).
|
|
222
233
|
|
|
223
234
|
## Package-local Boundary
|
|
224
235
|
|
|
@@ -229,7 +240,7 @@ This file is a package-local distribution entry point. This README is the packag
|
|
|
229
240
|
- Package status: governed package in the `tigrbl/tigrbl` workspace.
|
|
230
241
|
- Governance source: [SSOT registry](https://github.com/tigrbl/tigrbl/blob/master/.ssot/registry.json).
|
|
231
242
|
- Release evidence: [publish workflow](https://github.com/tigrbl/tigrbl/actions/workflows/publish.yml) validates package builds, tests, GitHub release assets, and PyPI publication for managed packages.
|
|
232
|
-
- Local certification guard: `pkgs/
|
|
243
|
+
- Local certification guard: `pkgs/97_tests/tigrbl_tests/tests/unit/test_package_badges_and_notices.py` verifies every package README keeps the Discord badge, Apache 2.0 badge, explicit Python-version badge, `LICENSE`, and `NOTICE`.
|
|
233
244
|
- Scope note: this README documents the package boundary. Runtime feature support remains governed by `.ssot/` entities and the conformance docs linked below.
|
|
234
245
|
|
|
235
246
|
## License
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tigrbl-atoms"
|
|
3
|
-
version = "0.4.5.
|
|
3
|
+
version = "0.4.5.dev8"
|
|
4
4
|
description = "Runtime atom package for Tigrbl stages, phases, typed contexts, event anchors, protocol execution, and composable pipeline algebra."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { file = "LICENSE" }
|
|
@@ -55,7 +55,7 @@ dependencies = [
|
|
|
55
55
|
"tigrbl-ops-olap",
|
|
56
56
|
"tigrbl-ops-realtime",
|
|
57
57
|
"tigrbl-ops-webtransport",
|
|
58
|
-
"tigrbl-core",
|
|
58
|
+
"tigrbl-core>=0.4.5.dev6",
|
|
59
59
|
"tigrbl-typing",
|
|
60
60
|
"jinja2>=3.1",
|
|
61
61
|
"sqlalchemy>=2.0",
|
|
@@ -67,10 +67,11 @@ dependencies = [
|
|
|
67
67
|
Organization = "https://github.com/tigrbl"
|
|
68
68
|
Discord = "https://discord.gg/K4YTAPapjR"
|
|
69
69
|
Homepage = "https://github.com/tigrbl/tigrbl"
|
|
70
|
-
Repository = "https://github.com/tigrbl/tigrbl/tree/master/pkgs/
|
|
70
|
+
Repository = "https://github.com/tigrbl/tigrbl/tree/master/pkgs/40_atoms/tigrbl_atoms"
|
|
71
71
|
Issues = "https://github.com/tigrbl/tigrbl/issues"
|
|
72
72
|
|
|
73
73
|
[tool.uv.sources]
|
|
74
|
+
"tigrbl-kernel" = { workspace = true }
|
|
74
75
|
"tigrbl-ops-oltp" = { workspace = true }
|
|
75
76
|
"tigrbl-ops-olap" = { workspace = true }
|
|
76
77
|
"tigrbl-ops-realtime" = { workspace = true }
|
|
@@ -90,6 +91,7 @@ packages = [
|
|
|
90
91
|
|
|
91
92
|
[dependency-groups]
|
|
92
93
|
dev = [
|
|
94
|
+
"tigrbl-kernel",
|
|
93
95
|
"pytest>=8.0",
|
|
94
96
|
"pytest-asyncio>=0.24.0",
|
|
95
97
|
"pytest-timeout>=2.3.1",
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from tigrbl_core.schema.builder.helpers import (
|
|
7
|
+
_spec_python_type,
|
|
8
|
+
_input_selector_entries,
|
|
9
|
+
_input_filter_entries,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
_READ_ONLY_TARGETS = frozenset(
|
|
13
|
+
{
|
|
14
|
+
"read",
|
|
15
|
+
"list",
|
|
16
|
+
"count",
|
|
17
|
+
"exists",
|
|
18
|
+
"aggregate",
|
|
19
|
+
"group_by",
|
|
20
|
+
"subscribe",
|
|
21
|
+
"tail",
|
|
22
|
+
"download",
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
_NON_PERSISTING_TARGETS = frozenset(
|
|
26
|
+
{"delete", "clear", "bulk_delete", "close_stream", "close_session"}
|
|
27
|
+
)
|
|
28
|
+
_CREATE_LIKE_TARGETS = frozenset({"create", "bulk_create"})
|
|
29
|
+
_UPDATE_LIKE_TARGETS = frozenset({"update", "merge", "bulk_update", "bulk_merge"})
|
|
30
|
+
_REPLACE_LIKE_TARGETS = frozenset({"replace", "bulk_replace"})
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _storage_requires_input(storage: Any, op: str) -> bool:
|
|
34
|
+
if storage is None or op == "update":
|
|
35
|
+
return False
|
|
36
|
+
if bool(getattr(storage, "primary_key", False)):
|
|
37
|
+
if op in {"replace", "delete"}:
|
|
38
|
+
return True
|
|
39
|
+
auto = getattr(storage, "autoincrement", False)
|
|
40
|
+
if auto not in (False, None) or getattr(storage, "identity", None) is not None:
|
|
41
|
+
return False
|
|
42
|
+
has_default = (
|
|
43
|
+
getattr(storage, "default", None) is not None
|
|
44
|
+
or getattr(storage, "server_default", None) is not None
|
|
45
|
+
or callable(getattr(storage, "default_factory", None))
|
|
46
|
+
)
|
|
47
|
+
return not bool(getattr(storage, "nullable", True)) and not has_default
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _storage_has_server_default(spec: Any, storage: Any) -> bool:
|
|
51
|
+
return bool(
|
|
52
|
+
getattr(storage, "default", None) is not None
|
|
53
|
+
or getattr(storage, "server_default", None) is not None
|
|
54
|
+
or callable(getattr(storage, "default_factory", None))
|
|
55
|
+
or callable(getattr(spec, "default_factory", None))
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _supports_stored_shape(op: str) -> bool:
|
|
60
|
+
lowered = str(op or "").lower()
|
|
61
|
+
return lowered not in _READ_ONLY_TARGETS and lowered not in _NON_PERSISTING_TARGETS
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _is_input_enabled(io: Any, op: str) -> bool:
|
|
65
|
+
return op in set(getattr(io, "in_verbs", ()) or ())
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _is_paired_enabled(io: Any, op: str) -> bool:
|
|
69
|
+
cfg = getattr(io, "_paired", None)
|
|
70
|
+
if cfg is None:
|
|
71
|
+
return False
|
|
72
|
+
return op in set(getattr(cfg, "verbs", ()) or ())
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _include_in_stored_schema(spec: Any, io: Any, storage: Any, op: str) -> bool:
|
|
76
|
+
lowered = str(op or "").lower()
|
|
77
|
+
if storage is None or not _supports_stored_shape(lowered):
|
|
78
|
+
return False
|
|
79
|
+
if _is_input_enabled(io, op) or _is_paired_enabled(io, op):
|
|
80
|
+
return True
|
|
81
|
+
if lowered in _CREATE_LIKE_TARGETS or lowered in _UPDATE_LIKE_TARGETS:
|
|
82
|
+
return True
|
|
83
|
+
if lowered in _REPLACE_LIKE_TARGETS:
|
|
84
|
+
return True
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _stored_required(spec: Any, storage: Any, op: str, *, derived: bool) -> bool:
|
|
89
|
+
lowered = str(op or "").lower()
|
|
90
|
+
if lowered in _UPDATE_LIKE_TARGETS:
|
|
91
|
+
return False
|
|
92
|
+
if lowered in _READ_ONLY_TARGETS or lowered in _NON_PERSISTING_TARGETS:
|
|
93
|
+
return False
|
|
94
|
+
if derived:
|
|
95
|
+
return True
|
|
96
|
+
return not bool(
|
|
97
|
+
getattr(storage, "nullable", True)
|
|
98
|
+
) and not _storage_has_server_default(
|
|
99
|
+
spec,
|
|
100
|
+
storage,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _ensure_temp(ctx: Any) -> dict[str, Any]:
|
|
105
|
+
tmp = getattr(ctx, "temp", None)
|
|
106
|
+
if not isinstance(tmp, dict):
|
|
107
|
+
tmp = {}
|
|
108
|
+
setattr(ctx, "temp", tmp)
|
|
109
|
+
return tmp
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _ensure_ov(ctx: Any):
|
|
113
|
+
ov = getattr(ctx, "opview", None)
|
|
114
|
+
if ov is None:
|
|
115
|
+
raise RuntimeError("ctx_missing:opview")
|
|
116
|
+
return ov
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _normalize_schema_from_specs(ctx: Any) -> None:
|
|
120
|
+
specs = getattr(ctx, "specs", None)
|
|
121
|
+
op = getattr(ctx, "op", None)
|
|
122
|
+
if not isinstance(specs, Mapping) or not isinstance(op, str) or not op:
|
|
123
|
+
raise RuntimeError("ctx_missing:opview")
|
|
124
|
+
|
|
125
|
+
in_fields: list[str] = []
|
|
126
|
+
out_fields: list[str] = []
|
|
127
|
+
stored_fields: list[str] = []
|
|
128
|
+
by_field_in: dict[str, dict[str, Any]] = {}
|
|
129
|
+
by_field_out: dict[str, dict[str, Any]] = {}
|
|
130
|
+
by_field_stored: dict[str, dict[str, Any]] = {}
|
|
131
|
+
required_from_client: list[str] = []
|
|
132
|
+
|
|
133
|
+
for field_name, spec in specs.items():
|
|
134
|
+
if not isinstance(field_name, str):
|
|
135
|
+
continue
|
|
136
|
+
io = getattr(spec, "io", None)
|
|
137
|
+
fs = getattr(spec, "field", None)
|
|
138
|
+
storage = getattr(spec, "storage", None)
|
|
139
|
+
|
|
140
|
+
in_verbs = set(getattr(io, "in_verbs", ()) or ())
|
|
141
|
+
out_verbs = set(getattr(io, "out_verbs", ()) or ())
|
|
142
|
+
|
|
143
|
+
if op in in_verbs:
|
|
144
|
+
in_fields.append(field_name)
|
|
145
|
+
in_meta: dict[str, Any] = {"in_enabled": True}
|
|
146
|
+
if storage is None:
|
|
147
|
+
in_meta["virtual"] = True
|
|
148
|
+
py_type = _spec_python_type(spec)
|
|
149
|
+
if py_type is not None and py_type is not Any:
|
|
150
|
+
in_meta["py_type"] = py_type
|
|
151
|
+
constraints = getattr(fs, "constraints", {}) or {}
|
|
152
|
+
if isinstance(constraints, Mapping):
|
|
153
|
+
max_length = constraints.get("max_length")
|
|
154
|
+
if isinstance(max_length, int) and max_length > 0:
|
|
155
|
+
in_meta["max_length"] = max_length
|
|
156
|
+
|
|
157
|
+
default_factory = getattr(spec, "default_factory", None)
|
|
158
|
+
if callable(default_factory):
|
|
159
|
+
in_meta["default_factory"] = default_factory
|
|
160
|
+
|
|
161
|
+
alias_in = getattr(io, "alias_in", None)
|
|
162
|
+
if alias_in:
|
|
163
|
+
in_meta["alias_in"] = alias_in
|
|
164
|
+
|
|
165
|
+
header_in = getattr(io, "header_in", None)
|
|
166
|
+
if header_in:
|
|
167
|
+
in_meta["header_in"] = header_in
|
|
168
|
+
in_meta["header_required_in"] = bool(
|
|
169
|
+
getattr(io, "header_required_in", False)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
in_meta["required"] = bool(
|
|
173
|
+
(fs and op in getattr(fs, "required_in", ()))
|
|
174
|
+
or _storage_requires_input(storage, op)
|
|
175
|
+
)
|
|
176
|
+
in_meta["nullable"] = (
|
|
177
|
+
True if storage is None else bool(getattr(storage, "nullable", True))
|
|
178
|
+
)
|
|
179
|
+
in_meta["coerce"] = True
|
|
180
|
+
by_field_in[field_name] = in_meta
|
|
181
|
+
|
|
182
|
+
if op in out_verbs:
|
|
183
|
+
out_fields.append(field_name)
|
|
184
|
+
out_meta: dict[str, Any] = {}
|
|
185
|
+
|
|
186
|
+
alias_out = getattr(io, "alias_out", None)
|
|
187
|
+
if alias_out:
|
|
188
|
+
out_meta["alias_out"] = alias_out
|
|
189
|
+
if storage is None:
|
|
190
|
+
out_meta["virtual"] = True
|
|
191
|
+
|
|
192
|
+
py_type = getattr(getattr(fs, "py_type", None), "__name__", None)
|
|
193
|
+
if py_type:
|
|
194
|
+
out_meta["py_type"] = py_type
|
|
195
|
+
by_field_out[field_name] = out_meta
|
|
196
|
+
|
|
197
|
+
if _include_in_stored_schema(spec, io, storage, op):
|
|
198
|
+
stored_fields.append(field_name)
|
|
199
|
+
input_enabled = _is_input_enabled(io, op)
|
|
200
|
+
paired_enabled = _is_paired_enabled(io, op)
|
|
201
|
+
server_default = _storage_has_server_default(spec, storage)
|
|
202
|
+
py_type = getattr(fs, "py_type", None) if fs is not None else None
|
|
203
|
+
if py_type is not None and py_type is not Any:
|
|
204
|
+
resolved_py_type = py_type
|
|
205
|
+
else:
|
|
206
|
+
storage_type = getattr(storage, "type_", None)
|
|
207
|
+
resolved_py_type = (
|
|
208
|
+
Any
|
|
209
|
+
if storage_type is None
|
|
210
|
+
else getattr(storage_type, "python_type", Any)
|
|
211
|
+
)
|
|
212
|
+
stored_meta: dict[str, Any] = {
|
|
213
|
+
"nullable": bool(getattr(storage, "nullable", True)),
|
|
214
|
+
"from_client": input_enabled,
|
|
215
|
+
"required_from_client": bool(
|
|
216
|
+
input_enabled and _storage_requires_input(storage, op)
|
|
217
|
+
),
|
|
218
|
+
"server_default": server_default,
|
|
219
|
+
}
|
|
220
|
+
if resolved_py_type is not Any:
|
|
221
|
+
stored_meta["py_type"] = resolved_py_type
|
|
222
|
+
constraints = getattr(fs, "constraints", {}) or {}
|
|
223
|
+
if isinstance(constraints, Mapping):
|
|
224
|
+
max_length = constraints.get("max_length")
|
|
225
|
+
if isinstance(max_length, int) and max_length > 0:
|
|
226
|
+
stored_meta["max_length"] = max_length
|
|
227
|
+
derived = paired_enabled or callable(
|
|
228
|
+
getattr(getattr(storage, "transform", None), "to_stored", None)
|
|
229
|
+
)
|
|
230
|
+
stored_meta["derived"] = derived
|
|
231
|
+
stored_meta["required"] = _stored_required(
|
|
232
|
+
spec,
|
|
233
|
+
storage,
|
|
234
|
+
op,
|
|
235
|
+
derived=derived,
|
|
236
|
+
)
|
|
237
|
+
if stored_meta["required_from_client"]:
|
|
238
|
+
required_from_client.append(field_name)
|
|
239
|
+
by_field_stored[field_name] = stored_meta
|
|
240
|
+
|
|
241
|
+
target = str(getattr(ctx, "target", None) or op)
|
|
242
|
+
for name, meta in {
|
|
243
|
+
**_input_filter_entries(specs, target),
|
|
244
|
+
**_input_selector_entries(specs, target),
|
|
245
|
+
}.items():
|
|
246
|
+
if name not in by_field_in:
|
|
247
|
+
in_fields.append(name)
|
|
248
|
+
by_field_in[name] = meta
|
|
249
|
+
elif meta.get("selector"):
|
|
250
|
+
by_field_in[name] = {**meta, **by_field_in[name], "selector": True}
|
|
251
|
+
|
|
252
|
+
in_fields_sorted = tuple(sorted(in_fields))
|
|
253
|
+
out_fields_sorted = tuple(sorted(out_fields))
|
|
254
|
+
stored_fields_sorted = tuple(sorted(stored_fields))
|
|
255
|
+
|
|
256
|
+
setattr(
|
|
257
|
+
ctx,
|
|
258
|
+
"schema_in",
|
|
259
|
+
{
|
|
260
|
+
"fields": in_fields_sorted,
|
|
261
|
+
"by_field": {f: by_field_in.get(f, {}) for f in in_fields_sorted},
|
|
262
|
+
"required": tuple(
|
|
263
|
+
f for f in in_fields_sorted if by_field_in.get(f, {}).get("required")
|
|
264
|
+
),
|
|
265
|
+
},
|
|
266
|
+
)
|
|
267
|
+
setattr(
|
|
268
|
+
ctx,
|
|
269
|
+
"schema_out",
|
|
270
|
+
{
|
|
271
|
+
"fields": out_fields_sorted,
|
|
272
|
+
"by_field": {f: by_field_out.get(f, {}) for f in out_fields_sorted},
|
|
273
|
+
"expose": out_fields_sorted,
|
|
274
|
+
},
|
|
275
|
+
)
|
|
276
|
+
setattr(
|
|
277
|
+
ctx,
|
|
278
|
+
"schema_stored",
|
|
279
|
+
{
|
|
280
|
+
"fields": stored_fields_sorted,
|
|
281
|
+
"by_field": {f: by_field_stored.get(f, {}) for f in stored_fields_sorted},
|
|
282
|
+
"required_from_client": tuple(sorted(required_from_client)),
|
|
283
|
+
"required": tuple(
|
|
284
|
+
f
|
|
285
|
+
for f in stored_fields_sorted
|
|
286
|
+
if by_field_stored.get(f, {}).get("required")
|
|
287
|
+
),
|
|
288
|
+
},
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def _ensure_schema_in(ctx: Any) -> Mapping[str, Any]:
|
|
293
|
+
temp = _ensure_temp(ctx)
|
|
294
|
+
cached = temp.get("schema_in")
|
|
295
|
+
if isinstance(cached, Mapping):
|
|
296
|
+
return cached
|
|
297
|
+
|
|
298
|
+
schema_in = getattr(ctx, "schema_in", None)
|
|
299
|
+
if isinstance(schema_in, Mapping):
|
|
300
|
+
temp["schema_in"] = schema_in
|
|
301
|
+
return schema_in
|
|
302
|
+
|
|
303
|
+
try:
|
|
304
|
+
ov = _ensure_ov(ctx)
|
|
305
|
+
bf = ov.schema_in.by_field
|
|
306
|
+
req = tuple(n for n, e in bf.items() if e.get("required"))
|
|
307
|
+
temp["schema_in"] = {
|
|
308
|
+
"fields": ov.schema_in.fields,
|
|
309
|
+
"by_field": bf,
|
|
310
|
+
"required": req,
|
|
311
|
+
}
|
|
312
|
+
except RuntimeError as exc:
|
|
313
|
+
if str(exc) != "ctx_missing:opview":
|
|
314
|
+
raise
|
|
315
|
+
_normalize_schema_from_specs(ctx)
|
|
316
|
+
temp["schema_in"] = getattr(ctx, "schema_in")
|
|
317
|
+
return temp["schema_in"]
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def _ensure_schema_out(ctx: Any) -> Mapping[str, Any]:
|
|
321
|
+
temp = _ensure_temp(ctx)
|
|
322
|
+
cached = temp.get("schema_out")
|
|
323
|
+
if isinstance(cached, Mapping):
|
|
324
|
+
return cached
|
|
325
|
+
|
|
326
|
+
schema_out = getattr(ctx, "schema_out", None)
|
|
327
|
+
if isinstance(schema_out, Mapping):
|
|
328
|
+
temp["schema_out"] = schema_out
|
|
329
|
+
return schema_out
|
|
330
|
+
|
|
331
|
+
try:
|
|
332
|
+
ov = _ensure_ov(ctx)
|
|
333
|
+
temp["schema_out"] = {
|
|
334
|
+
"fields": ov.schema_out.fields,
|
|
335
|
+
"by_field": ov.schema_out.by_field,
|
|
336
|
+
"expose": ov.schema_out.expose,
|
|
337
|
+
}
|
|
338
|
+
except RuntimeError as exc:
|
|
339
|
+
if str(exc) != "ctx_missing:opview":
|
|
340
|
+
raise
|
|
341
|
+
_normalize_schema_from_specs(ctx)
|
|
342
|
+
temp["schema_out"] = getattr(ctx, "schema_out")
|
|
343
|
+
return temp["schema_out"]
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def _ensure_schema_stored(ctx: Any) -> Mapping[str, Any]:
|
|
347
|
+
temp = _ensure_temp(ctx)
|
|
348
|
+
cached = temp.get("schema_stored")
|
|
349
|
+
if isinstance(cached, Mapping):
|
|
350
|
+
return cached
|
|
351
|
+
|
|
352
|
+
schema_stored = getattr(ctx, "schema_stored", None)
|
|
353
|
+
if isinstance(schema_stored, Mapping):
|
|
354
|
+
temp["schema_stored"] = schema_stored
|
|
355
|
+
return schema_stored
|
|
356
|
+
|
|
357
|
+
try:
|
|
358
|
+
ov = _ensure_ov(ctx)
|
|
359
|
+
stored = getattr(ov, "schema_stored", None)
|
|
360
|
+
if stored is None:
|
|
361
|
+
raise RuntimeError("ctx_missing:opview")
|
|
362
|
+
temp["schema_stored"] = {
|
|
363
|
+
"fields": stored.fields,
|
|
364
|
+
"by_field": stored.by_field,
|
|
365
|
+
"required_from_client": getattr(stored, "required_from_client", ()),
|
|
366
|
+
"required": tuple(
|
|
367
|
+
field
|
|
368
|
+
for field, meta in getattr(stored, "by_field", {}).items()
|
|
369
|
+
if meta.get("required")
|
|
370
|
+
),
|
|
371
|
+
}
|
|
372
|
+
except RuntimeError as exc:
|
|
373
|
+
if str(exc) != "ctx_missing:opview":
|
|
374
|
+
raise
|
|
375
|
+
_normalize_schema_from_specs(ctx)
|
|
376
|
+
temp["schema_stored"] = getattr(ctx, "schema_stored")
|
|
377
|
+
return temp["schema_stored"]
|
|
@@ -37,7 +37,9 @@ async def run(obj: object | None, ctx: Any) -> None:
|
|
|
37
37
|
if isinstance(temp, dict):
|
|
38
38
|
release = temp.pop("__sys_db_release__", None)
|
|
39
39
|
if callable(release):
|
|
40
|
-
release()
|
|
40
|
+
rv = release()
|
|
41
|
+
if hasattr(rv, "__await__"):
|
|
42
|
+
await rv
|
|
41
43
|
|
|
42
44
|
|
|
43
45
|
__all__ = ["ANCHOR", "run"]
|
|
@@ -20,22 +20,34 @@ from .codec import (
|
|
|
20
20
|
get_frame_codec,
|
|
21
21
|
supported_frame_codecs,
|
|
22
22
|
)
|
|
23
|
+
from . import websocket_jsonrpc as websocket_jsonrpc
|
|
24
|
+
from .webtransport_records import (
|
|
25
|
+
DEFAULT_MAX_RECORD_BYTES,
|
|
26
|
+
WebTransportRecordDecoder,
|
|
27
|
+
decode_jsonrpc_records,
|
|
28
|
+
encode_jsonrpc_record,
|
|
29
|
+
)
|
|
23
30
|
|
|
24
31
|
__all__ = [
|
|
25
32
|
"DEFAULT_MAX_PAYLOAD_SIZE",
|
|
33
|
+
"DEFAULT_MAX_RECORD_BYTES",
|
|
26
34
|
"FRAME_CODECS",
|
|
27
35
|
"HEADER_SIZE",
|
|
28
36
|
"RESERVED_FLAG_MASK",
|
|
29
37
|
"SUPPORTED_VERSION",
|
|
30
38
|
"FrameCodec",
|
|
31
39
|
"FrameStreamDecoder",
|
|
40
|
+
"WebTransportRecordDecoder",
|
|
32
41
|
"decode_app_frame",
|
|
33
42
|
"decode_app_frames",
|
|
34
43
|
"decode_frame",
|
|
44
|
+
"decode_jsonrpc_records",
|
|
35
45
|
"decode_webtransport_inner_frame",
|
|
36
46
|
"encode_app_frame",
|
|
37
47
|
"encode_frame",
|
|
48
|
+
"encode_jsonrpc_record",
|
|
38
49
|
"encode_webtransport_inner_frame",
|
|
39
50
|
"get_frame_codec",
|
|
40
51
|
"supported_frame_codecs",
|
|
52
|
+
"websocket_jsonrpc",
|
|
41
53
|
]
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .codec import decode_frame, encode_frame
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _ctx_get(ctx: Any, key: str, default: Any = None) -> Any:
|
|
9
|
+
getter = getattr(ctx, "get", None)
|
|
10
|
+
if callable(getter):
|
|
11
|
+
try:
|
|
12
|
+
return getter(key, default)
|
|
13
|
+
except Exception:
|
|
14
|
+
pass
|
|
15
|
+
return getattr(ctx, key, default)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _ctx_set(ctx: Any, key: str, value: Any) -> None:
|
|
19
|
+
try:
|
|
20
|
+
ctx[key] = value
|
|
21
|
+
return
|
|
22
|
+
except Exception:
|
|
23
|
+
pass
|
|
24
|
+
setattr(ctx, key, value)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _temp(ctx: Any) -> dict[str, Any]:
|
|
28
|
+
temp = _ctx_get(ctx, "temp")
|
|
29
|
+
if not isinstance(temp, dict):
|
|
30
|
+
temp = {}
|
|
31
|
+
_ctx_set(ctx, "temp", temp)
|
|
32
|
+
return temp
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _ws_state(ctx: Any) -> dict[str, Any]:
|
|
36
|
+
return _temp(ctx).setdefault("websocket", {})
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
async def decode(ctx: Any) -> Any:
|
|
40
|
+
state = _ws_state(ctx)
|
|
41
|
+
payload = decode_frame("websocket.jsonrpc", state.get("message"))
|
|
42
|
+
state["decoded"] = payload
|
|
43
|
+
return payload
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
async def encode(ctx: Any) -> Any:
|
|
47
|
+
state = _ws_state(ctx)
|
|
48
|
+
outbound = encode_frame("websocket.jsonrpc", state.get("response"))
|
|
49
|
+
state["outbound"] = outbound
|
|
50
|
+
return outbound
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
setattr(decode, "__tigrbl_atom_name__", "framing.decode")
|
|
54
|
+
setattr(decode, "__tigrbl_label", "atom:framing.decode")
|
|
55
|
+
setattr(encode, "__tigrbl_atom_name__", "framing.encode")
|
|
56
|
+
setattr(encode, "__tigrbl_label", "atom:framing.encode")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
__all__ = ["decode", "encode"]
|