sqlspec 0.36.0__cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.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.
- ac8f31065839703b4e70__mypyc.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/__init__.py +140 -0
- sqlspec/__main__.py +12 -0
- sqlspec/__metadata__.py +14 -0
- sqlspec/_serialization.py +315 -0
- sqlspec/_typing.py +700 -0
- sqlspec/adapters/__init__.py +0 -0
- sqlspec/adapters/adbc/__init__.py +5 -0
- sqlspec/adapters/adbc/_typing.py +82 -0
- sqlspec/adapters/adbc/adk/__init__.py +5 -0
- sqlspec/adapters/adbc/adk/store.py +1273 -0
- sqlspec/adapters/adbc/config.py +295 -0
- sqlspec/adapters/adbc/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/adbc/core.py +735 -0
- sqlspec/adapters/adbc/data_dictionary.py +334 -0
- sqlspec/adapters/adbc/driver.py +529 -0
- sqlspec/adapters/adbc/events/__init__.py +5 -0
- sqlspec/adapters/adbc/events/store.py +285 -0
- sqlspec/adapters/adbc/litestar/__init__.py +5 -0
- sqlspec/adapters/adbc/litestar/store.py +502 -0
- sqlspec/adapters/adbc/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/adbc/type_converter.py +140 -0
- sqlspec/adapters/aiosqlite/__init__.py +25 -0
- sqlspec/adapters/aiosqlite/_typing.py +82 -0
- sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/adk/store.py +818 -0
- sqlspec/adapters/aiosqlite/config.py +334 -0
- sqlspec/adapters/aiosqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/aiosqlite/core.py +315 -0
- sqlspec/adapters/aiosqlite/data_dictionary.py +208 -0
- sqlspec/adapters/aiosqlite/driver.py +313 -0
- sqlspec/adapters/aiosqlite/events/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/events/store.py +20 -0
- sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/litestar/store.py +279 -0
- sqlspec/adapters/aiosqlite/pool.py +533 -0
- sqlspec/adapters/asyncmy/__init__.py +21 -0
- sqlspec/adapters/asyncmy/_typing.py +87 -0
- sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
- sqlspec/adapters/asyncmy/adk/store.py +703 -0
- sqlspec/adapters/asyncmy/config.py +302 -0
- sqlspec/adapters/asyncmy/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/asyncmy/core.py +360 -0
- sqlspec/adapters/asyncmy/data_dictionary.py +124 -0
- sqlspec/adapters/asyncmy/driver.py +383 -0
- sqlspec/adapters/asyncmy/events/__init__.py +5 -0
- sqlspec/adapters/asyncmy/events/store.py +104 -0
- sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncmy/litestar/store.py +296 -0
- sqlspec/adapters/asyncpg/__init__.py +19 -0
- sqlspec/adapters/asyncpg/_typing.py +88 -0
- sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
- sqlspec/adapters/asyncpg/adk/store.py +748 -0
- sqlspec/adapters/asyncpg/config.py +569 -0
- sqlspec/adapters/asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/asyncpg/core.py +367 -0
- sqlspec/adapters/asyncpg/data_dictionary.py +162 -0
- sqlspec/adapters/asyncpg/driver.py +487 -0
- sqlspec/adapters/asyncpg/events/__init__.py +6 -0
- sqlspec/adapters/asyncpg/events/backend.py +286 -0
- sqlspec/adapters/asyncpg/events/store.py +40 -0
- sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncpg/litestar/store.py +251 -0
- sqlspec/adapters/bigquery/__init__.py +14 -0
- sqlspec/adapters/bigquery/_typing.py +86 -0
- sqlspec/adapters/bigquery/adk/__init__.py +5 -0
- sqlspec/adapters/bigquery/adk/store.py +827 -0
- sqlspec/adapters/bigquery/config.py +353 -0
- sqlspec/adapters/bigquery/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/bigquery/core.py +715 -0
- sqlspec/adapters/bigquery/data_dictionary.py +128 -0
- sqlspec/adapters/bigquery/driver.py +548 -0
- sqlspec/adapters/bigquery/events/__init__.py +5 -0
- sqlspec/adapters/bigquery/events/store.py +139 -0
- sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
- sqlspec/adapters/bigquery/litestar/store.py +325 -0
- sqlspec/adapters/bigquery/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/bigquery/type_converter.py +107 -0
- sqlspec/adapters/cockroach_asyncpg/__init__.py +24 -0
- sqlspec/adapters/cockroach_asyncpg/_typing.py +72 -0
- sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/adk/store.py +410 -0
- sqlspec/adapters/cockroach_asyncpg/config.py +238 -0
- sqlspec/adapters/cockroach_asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
- sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +107 -0
- sqlspec/adapters/cockroach_asyncpg/driver.py +144 -0
- sqlspec/adapters/cockroach_asyncpg/events/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/events/store.py +20 -0
- sqlspec/adapters/cockroach_asyncpg/litestar/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/litestar/store.py +142 -0
- sqlspec/adapters/cockroach_psycopg/__init__.py +38 -0
- sqlspec/adapters/cockroach_psycopg/_typing.py +129 -0
- sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
- sqlspec/adapters/cockroach_psycopg/adk/store.py +868 -0
- sqlspec/adapters/cockroach_psycopg/config.py +484 -0
- sqlspec/adapters/cockroach_psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/cockroach_psycopg/core.py +63 -0
- sqlspec/adapters/cockroach_psycopg/data_dictionary.py +215 -0
- sqlspec/adapters/cockroach_psycopg/driver.py +284 -0
- sqlspec/adapters/cockroach_psycopg/events/__init__.py +6 -0
- sqlspec/adapters/cockroach_psycopg/events/store.py +34 -0
- sqlspec/adapters/cockroach_psycopg/litestar/__init__.py +3 -0
- sqlspec/adapters/cockroach_psycopg/litestar/store.py +325 -0
- sqlspec/adapters/duckdb/__init__.py +25 -0
- sqlspec/adapters/duckdb/_typing.py +81 -0
- sqlspec/adapters/duckdb/adk/__init__.py +14 -0
- sqlspec/adapters/duckdb/adk/store.py +850 -0
- sqlspec/adapters/duckdb/config.py +463 -0
- sqlspec/adapters/duckdb/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/duckdb/core.py +257 -0
- sqlspec/adapters/duckdb/data_dictionary.py +140 -0
- sqlspec/adapters/duckdb/driver.py +430 -0
- sqlspec/adapters/duckdb/events/__init__.py +5 -0
- sqlspec/adapters/duckdb/events/store.py +57 -0
- sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
- sqlspec/adapters/duckdb/litestar/store.py +330 -0
- sqlspec/adapters/duckdb/pool.py +293 -0
- sqlspec/adapters/duckdb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/duckdb/type_converter.py +118 -0
- sqlspec/adapters/mock/__init__.py +72 -0
- sqlspec/adapters/mock/_typing.py +147 -0
- sqlspec/adapters/mock/config.py +483 -0
- sqlspec/adapters/mock/core.py +319 -0
- sqlspec/adapters/mock/data_dictionary.py +366 -0
- sqlspec/adapters/mock/driver.py +721 -0
- sqlspec/adapters/mysqlconnector/__init__.py +36 -0
- sqlspec/adapters/mysqlconnector/_typing.py +141 -0
- sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
- sqlspec/adapters/mysqlconnector/adk/store.py +1060 -0
- sqlspec/adapters/mysqlconnector/config.py +394 -0
- sqlspec/adapters/mysqlconnector/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/mysqlconnector/core.py +303 -0
- sqlspec/adapters/mysqlconnector/data_dictionary.py +235 -0
- sqlspec/adapters/mysqlconnector/driver.py +483 -0
- sqlspec/adapters/mysqlconnector/events/__init__.py +8 -0
- sqlspec/adapters/mysqlconnector/events/store.py +98 -0
- sqlspec/adapters/mysqlconnector/litestar/__init__.py +5 -0
- sqlspec/adapters/mysqlconnector/litestar/store.py +426 -0
- sqlspec/adapters/oracledb/__init__.py +60 -0
- sqlspec/adapters/oracledb/_numpy_handlers.py +141 -0
- sqlspec/adapters/oracledb/_typing.py +182 -0
- sqlspec/adapters/oracledb/_uuid_handlers.py +166 -0
- sqlspec/adapters/oracledb/adk/__init__.py +10 -0
- sqlspec/adapters/oracledb/adk/store.py +2369 -0
- sqlspec/adapters/oracledb/config.py +550 -0
- sqlspec/adapters/oracledb/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/oracledb/core.py +543 -0
- sqlspec/adapters/oracledb/data_dictionary.py +536 -0
- sqlspec/adapters/oracledb/driver.py +1229 -0
- sqlspec/adapters/oracledb/events/__init__.py +16 -0
- sqlspec/adapters/oracledb/events/backend.py +347 -0
- sqlspec/adapters/oracledb/events/store.py +420 -0
- sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
- sqlspec/adapters/oracledb/litestar/store.py +781 -0
- sqlspec/adapters/oracledb/migrations.py +535 -0
- sqlspec/adapters/oracledb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/oracledb/type_converter.py +211 -0
- sqlspec/adapters/psqlpy/__init__.py +17 -0
- sqlspec/adapters/psqlpy/_typing.py +79 -0
- sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
- sqlspec/adapters/psqlpy/adk/store.py +766 -0
- sqlspec/adapters/psqlpy/config.py +304 -0
- sqlspec/adapters/psqlpy/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psqlpy/core.py +480 -0
- sqlspec/adapters/psqlpy/data_dictionary.py +126 -0
- sqlspec/adapters/psqlpy/driver.py +438 -0
- sqlspec/adapters/psqlpy/events/__init__.py +6 -0
- sqlspec/adapters/psqlpy/events/backend.py +310 -0
- sqlspec/adapters/psqlpy/events/store.py +20 -0
- sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
- sqlspec/adapters/psqlpy/litestar/store.py +270 -0
- sqlspec/adapters/psqlpy/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psqlpy/type_converter.py +113 -0
- sqlspec/adapters/psycopg/__init__.py +32 -0
- sqlspec/adapters/psycopg/_typing.py +164 -0
- sqlspec/adapters/psycopg/adk/__init__.py +10 -0
- sqlspec/adapters/psycopg/adk/store.py +1387 -0
- sqlspec/adapters/psycopg/config.py +576 -0
- sqlspec/adapters/psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psycopg/core.py +450 -0
- sqlspec/adapters/psycopg/data_dictionary.py +289 -0
- sqlspec/adapters/psycopg/driver.py +975 -0
- sqlspec/adapters/psycopg/events/__init__.py +20 -0
- sqlspec/adapters/psycopg/events/backend.py +458 -0
- sqlspec/adapters/psycopg/events/store.py +42 -0
- sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
- sqlspec/adapters/psycopg/litestar/store.py +552 -0
- sqlspec/adapters/psycopg/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psycopg/type_converter.py +93 -0
- sqlspec/adapters/pymysql/__init__.py +21 -0
- sqlspec/adapters/pymysql/_typing.py +71 -0
- sqlspec/adapters/pymysql/adk/__init__.py +5 -0
- sqlspec/adapters/pymysql/adk/store.py +540 -0
- sqlspec/adapters/pymysql/config.py +195 -0
- sqlspec/adapters/pymysql/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/pymysql/core.py +299 -0
- sqlspec/adapters/pymysql/data_dictionary.py +122 -0
- sqlspec/adapters/pymysql/driver.py +259 -0
- sqlspec/adapters/pymysql/events/__init__.py +5 -0
- sqlspec/adapters/pymysql/events/store.py +50 -0
- sqlspec/adapters/pymysql/litestar/__init__.py +5 -0
- sqlspec/adapters/pymysql/litestar/store.py +232 -0
- sqlspec/adapters/pymysql/pool.py +137 -0
- sqlspec/adapters/spanner/__init__.py +40 -0
- sqlspec/adapters/spanner/_typing.py +86 -0
- sqlspec/adapters/spanner/adk/__init__.py +5 -0
- sqlspec/adapters/spanner/adk/store.py +732 -0
- sqlspec/adapters/spanner/config.py +352 -0
- sqlspec/adapters/spanner/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/spanner/core.py +188 -0
- sqlspec/adapters/spanner/data_dictionary.py +120 -0
- sqlspec/adapters/spanner/dialect/__init__.py +6 -0
- sqlspec/adapters/spanner/dialect/_spangres.py +57 -0
- sqlspec/adapters/spanner/dialect/_spanner.py +130 -0
- sqlspec/adapters/spanner/driver.py +373 -0
- sqlspec/adapters/spanner/events/__init__.py +5 -0
- sqlspec/adapters/spanner/events/store.py +187 -0
- sqlspec/adapters/spanner/litestar/__init__.py +5 -0
- sqlspec/adapters/spanner/litestar/store.py +291 -0
- sqlspec/adapters/spanner/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/spanner/type_converter.py +331 -0
- sqlspec/adapters/sqlite/__init__.py +19 -0
- sqlspec/adapters/sqlite/_typing.py +80 -0
- sqlspec/adapters/sqlite/adk/__init__.py +5 -0
- sqlspec/adapters/sqlite/adk/store.py +958 -0
- sqlspec/adapters/sqlite/config.py +280 -0
- sqlspec/adapters/sqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/sqlite/core.py +312 -0
- sqlspec/adapters/sqlite/data_dictionary.py +202 -0
- sqlspec/adapters/sqlite/driver.py +359 -0
- sqlspec/adapters/sqlite/events/__init__.py +5 -0
- sqlspec/adapters/sqlite/events/store.py +20 -0
- sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/sqlite/litestar/store.py +316 -0
- sqlspec/adapters/sqlite/pool.py +198 -0
- sqlspec/adapters/sqlite/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/sqlite/type_converter.py +114 -0
- sqlspec/base.py +747 -0
- sqlspec/builder/__init__.py +179 -0
- sqlspec/builder/_base.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_base.py +1022 -0
- sqlspec/builder/_column.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_column.py +521 -0
- sqlspec/builder/_ddl.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_ddl.py +1642 -0
- sqlspec/builder/_delete.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_delete.py +95 -0
- sqlspec/builder/_dml.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_dml.py +365 -0
- sqlspec/builder/_explain.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_explain.py +579 -0
- sqlspec/builder/_expression_wrappers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_expression_wrappers.py +46 -0
- sqlspec/builder/_factory.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_factory.py +1697 -0
- sqlspec/builder/_insert.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_insert.py +328 -0
- sqlspec/builder/_join.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_join.py +499 -0
- sqlspec/builder/_merge.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_merge.py +821 -0
- sqlspec/builder/_parsing_utils.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_parsing_utils.py +297 -0
- sqlspec/builder/_select.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_select.py +1660 -0
- sqlspec/builder/_temporal.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_temporal.py +139 -0
- sqlspec/builder/_update.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_update.py +173 -0
- sqlspec/builder/_vector_expressions.py +267 -0
- sqlspec/cli.py +911 -0
- sqlspec/config.py +1755 -0
- sqlspec/core/__init__.py +374 -0
- sqlspec/core/_correlation.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/_correlation.py +176 -0
- sqlspec/core/cache.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/cache.py +1069 -0
- sqlspec/core/compiler.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/compiler.py +954 -0
- sqlspec/core/explain.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/explain.py +275 -0
- sqlspec/core/filters.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/filters.py +952 -0
- sqlspec/core/hashing.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/hashing.py +262 -0
- sqlspec/core/metrics.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/metrics.py +83 -0
- sqlspec/core/parameters/__init__.py +71 -0
- sqlspec/core/parameters/_alignment.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_alignment.py +270 -0
- sqlspec/core/parameters/_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_converter.py +543 -0
- sqlspec/core/parameters/_processor.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_processor.py +505 -0
- sqlspec/core/parameters/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_registry.py +206 -0
- sqlspec/core/parameters/_transformers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_transformers.py +292 -0
- sqlspec/core/parameters/_types.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_types.py +499 -0
- sqlspec/core/parameters/_validator.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_validator.py +180 -0
- sqlspec/core/pipeline.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/pipeline.py +319 -0
- sqlspec/core/query_modifiers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/query_modifiers.py +437 -0
- sqlspec/core/result/__init__.py +23 -0
- sqlspec/core/result/_base.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/result/_base.py +1121 -0
- sqlspec/core/result/_io.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/result/_io.py +28 -0
- sqlspec/core/splitter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/splitter.py +966 -0
- sqlspec/core/stack.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/stack.py +163 -0
- sqlspec/core/statement.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/statement.py +1503 -0
- sqlspec/core/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/type_converter.py +339 -0
- sqlspec/data_dictionary/__init__.py +22 -0
- sqlspec/data_dictionary/_loader.py +123 -0
- sqlspec/data_dictionary/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/_registry.py +74 -0
- sqlspec/data_dictionary/_types.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/_types.py +121 -0
- sqlspec/data_dictionary/dialects/__init__.py +21 -0
- sqlspec/data_dictionary/dialects/bigquery.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/bigquery.py +49 -0
- sqlspec/data_dictionary/dialects/cockroachdb.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/cockroachdb.py +43 -0
- sqlspec/data_dictionary/dialects/duckdb.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/duckdb.py +47 -0
- sqlspec/data_dictionary/dialects/mysql.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/mysql.py +42 -0
- sqlspec/data_dictionary/dialects/oracle.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/oracle.py +34 -0
- sqlspec/data_dictionary/dialects/postgres.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/postgres.py +46 -0
- sqlspec/data_dictionary/dialects/spanner.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/spanner.py +37 -0
- sqlspec/data_dictionary/dialects/sqlite.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/sqlite.py +42 -0
- sqlspec/data_dictionary/sql/.gitkeep +0 -0
- sqlspec/data_dictionary/sql/bigquery/columns.sql +23 -0
- sqlspec/data_dictionary/sql/bigquery/foreign_keys.sql +34 -0
- sqlspec/data_dictionary/sql/bigquery/indexes.sql +19 -0
- sqlspec/data_dictionary/sql/bigquery/tables.sql +33 -0
- sqlspec/data_dictionary/sql/bigquery/version.sql +3 -0
- sqlspec/data_dictionary/sql/cockroachdb/columns.sql +34 -0
- sqlspec/data_dictionary/sql/cockroachdb/foreign_keys.sql +40 -0
- sqlspec/data_dictionary/sql/cockroachdb/indexes.sql +32 -0
- sqlspec/data_dictionary/sql/cockroachdb/tables.sql +44 -0
- sqlspec/data_dictionary/sql/cockroachdb/version.sql +3 -0
- sqlspec/data_dictionary/sql/duckdb/columns.sql +23 -0
- sqlspec/data_dictionary/sql/duckdb/foreign_keys.sql +36 -0
- sqlspec/data_dictionary/sql/duckdb/indexes.sql +19 -0
- sqlspec/data_dictionary/sql/duckdb/tables.sql +38 -0
- sqlspec/data_dictionary/sql/duckdb/version.sql +3 -0
- sqlspec/data_dictionary/sql/mysql/columns.sql +23 -0
- sqlspec/data_dictionary/sql/mysql/foreign_keys.sql +28 -0
- sqlspec/data_dictionary/sql/mysql/indexes.sql +26 -0
- sqlspec/data_dictionary/sql/mysql/tables.sql +33 -0
- sqlspec/data_dictionary/sql/mysql/version.sql +3 -0
- sqlspec/data_dictionary/sql/oracle/columns.sql +23 -0
- sqlspec/data_dictionary/sql/oracle/foreign_keys.sql +48 -0
- sqlspec/data_dictionary/sql/oracle/indexes.sql +44 -0
- sqlspec/data_dictionary/sql/oracle/tables.sql +25 -0
- sqlspec/data_dictionary/sql/oracle/version.sql +20 -0
- sqlspec/data_dictionary/sql/postgres/columns.sql +34 -0
- sqlspec/data_dictionary/sql/postgres/foreign_keys.sql +40 -0
- sqlspec/data_dictionary/sql/postgres/indexes.sql +56 -0
- sqlspec/data_dictionary/sql/postgres/tables.sql +44 -0
- sqlspec/data_dictionary/sql/postgres/version.sql +3 -0
- sqlspec/data_dictionary/sql/spanner/columns.sql +23 -0
- sqlspec/data_dictionary/sql/spanner/foreign_keys.sql +70 -0
- sqlspec/data_dictionary/sql/spanner/indexes.sql +30 -0
- sqlspec/data_dictionary/sql/spanner/tables.sql +9 -0
- sqlspec/data_dictionary/sql/spanner/version.sql +3 -0
- sqlspec/data_dictionary/sql/sqlite/columns.sql +23 -0
- sqlspec/data_dictionary/sql/sqlite/foreign_keys.sql +22 -0
- sqlspec/data_dictionary/sql/sqlite/indexes.sql +7 -0
- sqlspec/data_dictionary/sql/sqlite/tables.sql +28 -0
- sqlspec/data_dictionary/sql/sqlite/version.sql +3 -0
- sqlspec/driver/__init__.py +32 -0
- sqlspec/driver/_async.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_async.py +1737 -0
- sqlspec/driver/_common.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_common.py +1478 -0
- sqlspec/driver/_sql_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_sql_helpers.py +148 -0
- sqlspec/driver/_storage_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_storage_helpers.py +144 -0
- sqlspec/driver/_sync.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_sync.py +1710 -0
- sqlspec/exceptions.py +338 -0
- sqlspec/extensions/__init__.py +0 -0
- sqlspec/extensions/adk/__init__.py +70 -0
- sqlspec/extensions/adk/_types.py +51 -0
- sqlspec/extensions/adk/converters.py +172 -0
- sqlspec/extensions/adk/memory/__init__.py +69 -0
- sqlspec/extensions/adk/memory/_types.py +30 -0
- sqlspec/extensions/adk/memory/converters.py +149 -0
- sqlspec/extensions/adk/memory/service.py +217 -0
- sqlspec/extensions/adk/memory/store.py +569 -0
- sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +246 -0
- sqlspec/extensions/adk/migrations/__init__.py +0 -0
- sqlspec/extensions/adk/service.py +225 -0
- sqlspec/extensions/adk/store.py +567 -0
- sqlspec/extensions/events/__init__.py +51 -0
- sqlspec/extensions/events/_channel.py +703 -0
- sqlspec/extensions/events/_hints.py +45 -0
- sqlspec/extensions/events/_models.py +23 -0
- sqlspec/extensions/events/_payload.py +69 -0
- sqlspec/extensions/events/_protocols.py +134 -0
- sqlspec/extensions/events/_queue.py +461 -0
- sqlspec/extensions/events/_store.py +209 -0
- sqlspec/extensions/events/migrations/0001_create_event_queue.py +59 -0
- sqlspec/extensions/events/migrations/__init__.py +3 -0
- sqlspec/extensions/fastapi/__init__.py +19 -0
- sqlspec/extensions/fastapi/extension.py +351 -0
- sqlspec/extensions/fastapi/providers.py +607 -0
- sqlspec/extensions/flask/__init__.py +37 -0
- sqlspec/extensions/flask/_state.py +76 -0
- sqlspec/extensions/flask/_utils.py +71 -0
- sqlspec/extensions/flask/extension.py +519 -0
- sqlspec/extensions/litestar/__init__.py +28 -0
- sqlspec/extensions/litestar/_utils.py +52 -0
- sqlspec/extensions/litestar/channels.py +165 -0
- sqlspec/extensions/litestar/cli.py +102 -0
- sqlspec/extensions/litestar/config.py +90 -0
- sqlspec/extensions/litestar/handlers.py +316 -0
- sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
- sqlspec/extensions/litestar/migrations/__init__.py +3 -0
- sqlspec/extensions/litestar/plugin.py +671 -0
- sqlspec/extensions/litestar/providers.py +526 -0
- sqlspec/extensions/litestar/store.py +296 -0
- sqlspec/extensions/otel/__init__.py +58 -0
- sqlspec/extensions/prometheus/__init__.py +113 -0
- sqlspec/extensions/starlette/__init__.py +19 -0
- sqlspec/extensions/starlette/_state.py +30 -0
- sqlspec/extensions/starlette/_utils.py +96 -0
- sqlspec/extensions/starlette/extension.py +346 -0
- sqlspec/extensions/starlette/middleware.py +235 -0
- sqlspec/loader.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/loader.py +702 -0
- sqlspec/migrations/__init__.py +36 -0
- sqlspec/migrations/base.py +731 -0
- sqlspec/migrations/commands.py +1232 -0
- sqlspec/migrations/context.py +157 -0
- sqlspec/migrations/fix.py +204 -0
- sqlspec/migrations/loaders.py +443 -0
- sqlspec/migrations/runner.py +1172 -0
- sqlspec/migrations/templates.py +234 -0
- sqlspec/migrations/tracker.py +611 -0
- sqlspec/migrations/utils.py +256 -0
- sqlspec/migrations/validation.py +207 -0
- sqlspec/migrations/version.py +446 -0
- sqlspec/observability/__init__.py +55 -0
- sqlspec/observability/_common.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_common.py +77 -0
- sqlspec/observability/_config.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_config.py +348 -0
- sqlspec/observability/_diagnostics.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_diagnostics.py +74 -0
- sqlspec/observability/_dispatcher.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_dispatcher.py +152 -0
- sqlspec/observability/_formatters/__init__.py +13 -0
- sqlspec/observability/_formatters/_aws.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_aws.py +102 -0
- sqlspec/observability/_formatters/_azure.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_azure.py +96 -0
- sqlspec/observability/_formatters/_base.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_base.py +57 -0
- sqlspec/observability/_formatters/_gcp.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_gcp.py +131 -0
- sqlspec/observability/_formatting.py +58 -0
- sqlspec/observability/_observer.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_observer.py +357 -0
- sqlspec/observability/_runtime.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_runtime.py +420 -0
- sqlspec/observability/_sampling.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_sampling.py +188 -0
- sqlspec/observability/_spans.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_spans.py +161 -0
- sqlspec/protocols.py +916 -0
- sqlspec/py.typed +0 -0
- sqlspec/storage/__init__.py +48 -0
- sqlspec/storage/_utils.py +104 -0
- sqlspec/storage/backends/__init__.py +1 -0
- sqlspec/storage/backends/base.py +253 -0
- sqlspec/storage/backends/fsspec.py +529 -0
- sqlspec/storage/backends/local.py +441 -0
- sqlspec/storage/backends/obstore.py +916 -0
- sqlspec/storage/errors.py +104 -0
- sqlspec/storage/pipeline.py +582 -0
- sqlspec/storage/registry.py +301 -0
- sqlspec/typing.py +395 -0
- sqlspec/utils/__init__.py +7 -0
- sqlspec/utils/arrow_helpers.py +318 -0
- sqlspec/utils/config_tools.py +332 -0
- sqlspec/utils/correlation.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/correlation.py +134 -0
- sqlspec/utils/deprecation.py +190 -0
- sqlspec/utils/fixtures.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/fixtures.py +258 -0
- sqlspec/utils/logging.py +222 -0
- sqlspec/utils/module_loader.py +306 -0
- sqlspec/utils/portal.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/portal.py +375 -0
- sqlspec/utils/schema.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/schema.py +485 -0
- sqlspec/utils/serializers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/serializers.py +408 -0
- sqlspec/utils/singleton.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/singleton.py +41 -0
- sqlspec/utils/sync_tools.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/sync_tools.py +311 -0
- sqlspec/utils/text.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/text.py +108 -0
- sqlspec/utils/type_converters.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/type_converters.py +128 -0
- sqlspec/utils/type_guards.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/type_guards.py +1360 -0
- sqlspec/utils/uuids.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/uuids.py +225 -0
- sqlspec-0.36.0.dist-info/METADATA +205 -0
- sqlspec-0.36.0.dist-info/RECORD +531 -0
- sqlspec-0.36.0.dist-info/WHEEL +7 -0
- sqlspec-0.36.0.dist-info/entry_points.txt +2 -0
- sqlspec-0.36.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Storage error normalization helpers."""
|
|
2
|
+
|
|
3
|
+
import errno
|
|
4
|
+
import logging
|
|
5
|
+
from typing import TYPE_CHECKING, TypeVar
|
|
6
|
+
|
|
7
|
+
from sqlspec.exceptions import FileNotFoundInStorageError, StorageOperationFailedError
|
|
8
|
+
from sqlspec.utils.logging import get_logger, log_with_context
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from collections.abc import Awaitable, Callable, Mapping
|
|
12
|
+
|
|
13
|
+
__all__ = ("StorageError", "execute_async_storage_operation", "execute_sync_storage_operation", "raise_storage_error")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
logger = get_logger(__name__)
|
|
17
|
+
|
|
18
|
+
T = TypeVar("T")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
_NOT_FOUND_NAMES = {"NotFoundError", "ObjectNotFound", "NoSuchKey", "NoSuchBucket", "NoSuchFile"}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class StorageError:
|
|
25
|
+
"""Normalized view of a storage backend exception."""
|
|
26
|
+
|
|
27
|
+
__slots__ = ("backend", "message", "operation", "original", "path", "retryable")
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self, message: str, backend: str, operation: str, path: str | None, retryable: bool, original: Exception
|
|
31
|
+
) -> None:
|
|
32
|
+
self.message = message
|
|
33
|
+
self.backend = backend
|
|
34
|
+
self.operation = operation
|
|
35
|
+
self.path = path
|
|
36
|
+
self.retryable = retryable
|
|
37
|
+
self.original = original
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _is_missing_error(error: Exception) -> bool:
|
|
41
|
+
if isinstance(error, FileNotFoundError):
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
if isinstance(error, OSError) and error.errno in {errno.ENOENT, errno.ENOTDIR}:
|
|
45
|
+
return True
|
|
46
|
+
|
|
47
|
+
name = error.__class__.__name__
|
|
48
|
+
return name in _NOT_FOUND_NAMES
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _is_retryable(error: Exception) -> bool:
|
|
52
|
+
if isinstance(error, (ConnectionError, TimeoutError)):
|
|
53
|
+
return True
|
|
54
|
+
|
|
55
|
+
name = error.__class__.__name__
|
|
56
|
+
return bool("Timeout" in name or "Temporary" in name)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _normalize_storage_error(error: Exception, *, backend: str, operation: str, path: str | None) -> "StorageError":
|
|
60
|
+
message = f"{backend} {operation} failed"
|
|
61
|
+
if path:
|
|
62
|
+
message = f"{message} for {path}"
|
|
63
|
+
|
|
64
|
+
return StorageError(
|
|
65
|
+
message=message, backend=backend, operation=operation, path=path, retryable=_is_retryable(error), original=error
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def raise_storage_error(error: Exception, *, backend: str, operation: str, path: str | None) -> None:
|
|
70
|
+
is_missing = _is_missing_error(error)
|
|
71
|
+
normalized = _normalize_storage_error(error, backend=backend, operation=operation, path=path)
|
|
72
|
+
|
|
73
|
+
log_extra: Mapping[str, str | bool | None] = {
|
|
74
|
+
"backend_type": backend,
|
|
75
|
+
"operation": operation,
|
|
76
|
+
"path": path,
|
|
77
|
+
"exception_type": error.__class__.__name__,
|
|
78
|
+
"retryable": normalized.retryable,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if is_missing:
|
|
82
|
+
log_with_context(logger, logging.INFO, "storage.object.missing", **log_extra)
|
|
83
|
+
raise FileNotFoundInStorageError(normalized.message) from error
|
|
84
|
+
|
|
85
|
+
log_with_context(logger, logging.WARNING, "storage.operation.failed", **log_extra)
|
|
86
|
+
raise StorageOperationFailedError(normalized.message) from error
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def execute_sync_storage_operation(func: "Callable[[], T]", *, backend: str, operation: str, path: str | None) -> T:
|
|
90
|
+
try:
|
|
91
|
+
return func()
|
|
92
|
+
except Exception as error:
|
|
93
|
+
raise_storage_error(error, backend=backend, operation=operation, path=path)
|
|
94
|
+
raise
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
async def execute_async_storage_operation(
|
|
98
|
+
func: "Callable[[], Awaitable[T]]", *, backend: str, operation: str, path: str | None
|
|
99
|
+
) -> T:
|
|
100
|
+
try:
|
|
101
|
+
return await func()
|
|
102
|
+
except Exception as error:
|
|
103
|
+
raise_storage_error(error, backend=backend, operation=operation, path=path)
|
|
104
|
+
raise
|
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
"""Storage pipeline scaffolding for driver-aware storage bridge."""
|
|
2
|
+
|
|
3
|
+
from collections import deque
|
|
4
|
+
from functools import partial
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from time import perf_counter, time
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Literal, NamedTuple, TypeAlias, cast
|
|
8
|
+
from uuid import uuid4
|
|
9
|
+
|
|
10
|
+
from mypy_extensions import mypyc_attr
|
|
11
|
+
from typing_extensions import NotRequired, TypedDict
|
|
12
|
+
|
|
13
|
+
from sqlspec.exceptions import ImproperConfigurationError
|
|
14
|
+
from sqlspec.storage._utils import import_pyarrow, import_pyarrow_parquet
|
|
15
|
+
from sqlspec.storage.errors import execute_async_storage_operation, execute_sync_storage_operation
|
|
16
|
+
from sqlspec.storage.registry import StorageRegistry, storage_registry
|
|
17
|
+
from sqlspec.utils.serializers import from_json, get_serializer_metrics, serialize_collection, to_json
|
|
18
|
+
from sqlspec.utils.sync_tools import async_
|
|
19
|
+
from sqlspec.utils.type_guards import supports_async_delete, supports_async_read_bytes, supports_async_write_bytes
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from collections.abc import AsyncIterator, Iterator
|
|
23
|
+
|
|
24
|
+
from sqlspec.protocols import ObjectStoreProtocol
|
|
25
|
+
from sqlspec.typing import ArrowTable
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
__all__ = (
|
|
29
|
+
"AsyncStoragePipeline",
|
|
30
|
+
"PartitionStrategyConfig",
|
|
31
|
+
"StagedArtifact",
|
|
32
|
+
"StorageBridgeJob",
|
|
33
|
+
"StorageCapabilities",
|
|
34
|
+
"StorageDestination",
|
|
35
|
+
"StorageDiagnostics",
|
|
36
|
+
"StorageFormat",
|
|
37
|
+
"StorageLoadRequest",
|
|
38
|
+
"StorageTelemetry",
|
|
39
|
+
"SyncStoragePipeline",
|
|
40
|
+
"create_storage_bridge_job",
|
|
41
|
+
"get_recent_storage_events",
|
|
42
|
+
"get_storage_bridge_diagnostics",
|
|
43
|
+
"get_storage_bridge_metrics",
|
|
44
|
+
"record_storage_diagnostic_event",
|
|
45
|
+
"reset_storage_bridge_events",
|
|
46
|
+
"reset_storage_bridge_metrics",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
StorageFormat = Literal["jsonl", "json", "parquet", "arrow-ipc"]
|
|
50
|
+
StorageDestination: TypeAlias = str | Path
|
|
51
|
+
StorageDiagnostics: TypeAlias = dict[str, float]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class StorageCapabilities(TypedDict):
|
|
55
|
+
"""Runtime-evaluated driver storage capabilities."""
|
|
56
|
+
|
|
57
|
+
arrow_export_enabled: bool
|
|
58
|
+
arrow_import_enabled: bool
|
|
59
|
+
parquet_export_enabled: bool
|
|
60
|
+
parquet_import_enabled: bool
|
|
61
|
+
requires_staging_for_load: bool
|
|
62
|
+
staging_protocols: "list[str]"
|
|
63
|
+
partition_strategies: "list[str]"
|
|
64
|
+
default_storage_profile: NotRequired[str | None]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class PartitionStrategyConfig(TypedDict, total=False):
|
|
68
|
+
"""Configuration for partition fan-out strategies."""
|
|
69
|
+
|
|
70
|
+
kind: str
|
|
71
|
+
partitions: int
|
|
72
|
+
rows_per_chunk: int
|
|
73
|
+
manifest_path: str
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class StorageLoadRequest(TypedDict):
|
|
77
|
+
"""Request describing a staging allocation."""
|
|
78
|
+
|
|
79
|
+
partition_id: str
|
|
80
|
+
destination_uri: str
|
|
81
|
+
ttl_seconds: int
|
|
82
|
+
correlation_id: str
|
|
83
|
+
source_uri: NotRequired[str]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class StagedArtifact(TypedDict):
|
|
87
|
+
"""Metadata describing a staged artifact managed by the pipeline."""
|
|
88
|
+
|
|
89
|
+
partition_id: str
|
|
90
|
+
uri: str
|
|
91
|
+
cleanup_token: str
|
|
92
|
+
ttl_seconds: int
|
|
93
|
+
expires_at: float
|
|
94
|
+
correlation_id: str
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class StorageTelemetry(TypedDict, total=False):
|
|
98
|
+
"""Telemetry payload for storage bridge operations."""
|
|
99
|
+
|
|
100
|
+
destination: str
|
|
101
|
+
bytes_processed: int
|
|
102
|
+
rows_processed: int
|
|
103
|
+
partitions_created: int
|
|
104
|
+
duration_s: float
|
|
105
|
+
format: str
|
|
106
|
+
extra: "dict[str, object]"
|
|
107
|
+
backend: str
|
|
108
|
+
correlation_id: str
|
|
109
|
+
config: str
|
|
110
|
+
bind_key: str
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class StorageBridgeJob(NamedTuple):
|
|
114
|
+
"""Handle representing a storage bridge operation."""
|
|
115
|
+
|
|
116
|
+
job_id: str
|
|
117
|
+
status: str
|
|
118
|
+
telemetry: StorageTelemetry
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class _StorageBridgeMetrics:
|
|
122
|
+
__slots__ = ("bytes_written", "partitions_created")
|
|
123
|
+
|
|
124
|
+
def __init__(self) -> None:
|
|
125
|
+
self.bytes_written = 0
|
|
126
|
+
self.partitions_created = 0
|
|
127
|
+
|
|
128
|
+
def record_bytes(self, count: int) -> None:
|
|
129
|
+
self.bytes_written += max(count, 0)
|
|
130
|
+
|
|
131
|
+
def record_partitions(self, count: int) -> None:
|
|
132
|
+
self.partitions_created += max(count, 0)
|
|
133
|
+
|
|
134
|
+
def snapshot(self) -> "dict[str, int]":
|
|
135
|
+
return {
|
|
136
|
+
"storage_bridge.bytes_written": self.bytes_written,
|
|
137
|
+
"storage_bridge.partitions_created": self.partitions_created,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
def reset(self) -> None:
|
|
141
|
+
self.bytes_written = 0
|
|
142
|
+
self.partitions_created = 0
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
_METRICS = _StorageBridgeMetrics()
|
|
146
|
+
_RECENT_STORAGE_EVENTS: "deque[StorageTelemetry]" = deque(maxlen=25)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def get_storage_bridge_metrics() -> "dict[str, int]":
|
|
150
|
+
"""Return aggregated storage bridge metrics."""
|
|
151
|
+
|
|
152
|
+
return _METRICS.snapshot()
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def reset_storage_bridge_metrics() -> None:
|
|
156
|
+
"""Reset aggregated storage bridge metrics."""
|
|
157
|
+
|
|
158
|
+
_METRICS.reset()
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def record_storage_diagnostic_event(telemetry: StorageTelemetry) -> None:
|
|
162
|
+
"""Record telemetry for inclusion in diagnostics snapshots."""
|
|
163
|
+
|
|
164
|
+
_RECENT_STORAGE_EVENTS.append(cast("StorageTelemetry", dict(telemetry)))
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def get_recent_storage_events() -> "list[StorageTelemetry]":
|
|
168
|
+
"""Return recent storage telemetry events (most recent first)."""
|
|
169
|
+
|
|
170
|
+
return [cast("StorageTelemetry", dict(entry)) for entry in _RECENT_STORAGE_EVENTS]
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def reset_storage_bridge_events() -> None:
|
|
174
|
+
"""Clear recorded storage telemetry events."""
|
|
175
|
+
|
|
176
|
+
_RECENT_STORAGE_EVENTS.clear()
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def create_storage_bridge_job(status: str, telemetry: StorageTelemetry) -> StorageBridgeJob:
|
|
180
|
+
"""Create a storage bridge job handle with a unique identifier."""
|
|
181
|
+
|
|
182
|
+
job = StorageBridgeJob(job_id=str(uuid4()), status=status, telemetry=telemetry)
|
|
183
|
+
record_storage_diagnostic_event(job.telemetry)
|
|
184
|
+
return job
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def get_storage_bridge_diagnostics() -> "StorageDiagnostics":
|
|
188
|
+
"""Return aggregated storage bridge + serializer cache metrics."""
|
|
189
|
+
|
|
190
|
+
diagnostics: dict[str, float] = {key: float(value) for key, value in get_storage_bridge_metrics().items()}
|
|
191
|
+
serializer_metrics = get_serializer_metrics()
|
|
192
|
+
for key, value in serializer_metrics.items():
|
|
193
|
+
diagnostics[f"serializer.{key}"] = float(value)
|
|
194
|
+
return diagnostics
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _encode_row_payload(rows: "list[Any]", format_hint: StorageFormat) -> bytes:
|
|
198
|
+
if format_hint == "json":
|
|
199
|
+
data = to_json(rows, as_bytes=True)
|
|
200
|
+
if isinstance(data, bytes):
|
|
201
|
+
return data
|
|
202
|
+
return data.encode()
|
|
203
|
+
buffer = bytearray()
|
|
204
|
+
for row in rows:
|
|
205
|
+
buffer.extend(to_json(row, as_bytes=True))
|
|
206
|
+
buffer.extend(b"\n")
|
|
207
|
+
return bytes(buffer)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _encode_arrow_payload(table: "ArrowTable", format_choice: StorageFormat, *, compression: str | None) -> bytes:
|
|
211
|
+
pa = import_pyarrow()
|
|
212
|
+
sink = pa.BufferOutputStream()
|
|
213
|
+
if format_choice == "arrow-ipc":
|
|
214
|
+
writer = pa.ipc.new_file(sink, table.schema)
|
|
215
|
+
writer.write_table(table)
|
|
216
|
+
writer.close()
|
|
217
|
+
else:
|
|
218
|
+
pq = import_pyarrow_parquet()
|
|
219
|
+
pq.write_table(table, sink, compression=compression)
|
|
220
|
+
buffer = sink.getvalue()
|
|
221
|
+
result_bytes: bytes = buffer.to_pybytes()
|
|
222
|
+
return result_bytes
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _delete_backend_sync(backend: "ObjectStoreProtocol", path: str, *, backend_name: str) -> None:
|
|
226
|
+
execute_sync_storage_operation(partial(backend.delete, path), backend=backend_name, operation="delete", path=path)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _write_backend_sync(backend: "ObjectStoreProtocol", path: str, payload: bytes, *, backend_name: str) -> None:
|
|
230
|
+
execute_sync_storage_operation(
|
|
231
|
+
partial(backend.write_bytes, path, payload), backend=backend_name, operation="write_bytes", path=path
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _read_backend_sync(backend: "ObjectStoreProtocol", path: str, *, backend_name: str) -> bytes:
|
|
236
|
+
return execute_sync_storage_operation(
|
|
237
|
+
partial(backend.read_bytes, path), backend=backend_name, operation="read_bytes", path=path
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _decode_arrow_payload(payload: bytes, format_choice: StorageFormat) -> "ArrowTable":
|
|
242
|
+
pa = import_pyarrow()
|
|
243
|
+
if format_choice == "parquet":
|
|
244
|
+
pq = import_pyarrow_parquet()
|
|
245
|
+
return cast("ArrowTable", pq.read_table(pa.BufferReader(payload)))
|
|
246
|
+
if format_choice == "arrow-ipc":
|
|
247
|
+
reader = pa.ipc.open_file(pa.BufferReader(payload))
|
|
248
|
+
return cast("ArrowTable", reader.read_all())
|
|
249
|
+
text_payload = payload.decode()
|
|
250
|
+
if format_choice == "json":
|
|
251
|
+
data = from_json(text_payload)
|
|
252
|
+
rows = data if isinstance(data, list) else [data]
|
|
253
|
+
return cast("ArrowTable", pa.Table.from_pylist(rows))
|
|
254
|
+
if format_choice == "jsonl":
|
|
255
|
+
rows = [from_json(line) for line in text_payload.splitlines() if line.strip()]
|
|
256
|
+
return cast("ArrowTable", pa.Table.from_pylist(rows))
|
|
257
|
+
msg = f"Unsupported storage format for Arrow decoding: {format_choice}"
|
|
258
|
+
raise ValueError(msg)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _resolve_alias_destination(
|
|
262
|
+
registry: StorageRegistry, destination: str, backend_options: "dict[str, Any]"
|
|
263
|
+
) -> "tuple[ObjectStoreProtocol, str] | None":
|
|
264
|
+
if not destination.startswith("alias://"):
|
|
265
|
+
return None
|
|
266
|
+
payload = destination.removeprefix("alias://")
|
|
267
|
+
alias_name, _, relative_path = payload.partition("/")
|
|
268
|
+
alias = alias_name.strip()
|
|
269
|
+
if not alias:
|
|
270
|
+
msg = "Alias destinations must include a registry alias before the path component"
|
|
271
|
+
raise ImproperConfigurationError(msg)
|
|
272
|
+
path_segment = relative_path.strip()
|
|
273
|
+
if not path_segment:
|
|
274
|
+
msg = "Alias destinations must include an object path after the alias name"
|
|
275
|
+
raise ImproperConfigurationError(msg)
|
|
276
|
+
backend = registry.get(alias, **backend_options)
|
|
277
|
+
return backend, path_segment.lstrip("/")
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def _normalize_path_for_backend(destination: str) -> str:
|
|
281
|
+
if destination.startswith("file://"):
|
|
282
|
+
return destination.removeprefix("file://")
|
|
283
|
+
if "://" in destination:
|
|
284
|
+
_, remainder = destination.split("://", 1)
|
|
285
|
+
return remainder.lstrip("/")
|
|
286
|
+
return destination
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def _resolve_storage_backend(
|
|
290
|
+
registry: StorageRegistry, destination: StorageDestination, backend_options: "dict[str, Any] | None"
|
|
291
|
+
) -> "tuple[ObjectStoreProtocol, str]":
|
|
292
|
+
destination_str = destination.as_posix() if isinstance(destination, Path) else str(destination)
|
|
293
|
+
options = backend_options or {}
|
|
294
|
+
alias_resolution = _resolve_alias_destination(registry, destination_str, options)
|
|
295
|
+
if alias_resolution is not None:
|
|
296
|
+
return alias_resolution
|
|
297
|
+
backend = registry.get(destination_str, **options)
|
|
298
|
+
normalized_path = _normalize_path_for_backend(destination_str)
|
|
299
|
+
return backend, normalized_path
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
@mypyc_attr(allow_interpreted_subclasses=True)
|
|
303
|
+
class SyncStoragePipeline:
|
|
304
|
+
"""Pipeline coordinating storage registry operations and telemetry."""
|
|
305
|
+
|
|
306
|
+
__slots__ = ("registry",)
|
|
307
|
+
|
|
308
|
+
def __init__(self, *, registry: StorageRegistry | None = None) -> None:
|
|
309
|
+
self.registry = registry or storage_registry
|
|
310
|
+
|
|
311
|
+
def _resolve_backend(
|
|
312
|
+
self, destination: StorageDestination, backend_options: "dict[str, Any] | None"
|
|
313
|
+
) -> "tuple[ObjectStoreProtocol, str]":
|
|
314
|
+
"""Resolve storage backend and normalized path for a destination."""
|
|
315
|
+
return _resolve_storage_backend(self.registry, destination, backend_options)
|
|
316
|
+
|
|
317
|
+
def write_rows(
|
|
318
|
+
self,
|
|
319
|
+
rows: "list[dict[str, Any]]",
|
|
320
|
+
destination: StorageDestination,
|
|
321
|
+
*,
|
|
322
|
+
format_hint: StorageFormat | None = None,
|
|
323
|
+
storage_options: "dict[str, Any] | None" = None,
|
|
324
|
+
) -> StorageTelemetry:
|
|
325
|
+
"""Write dictionary rows to storage using cached serializers."""
|
|
326
|
+
|
|
327
|
+
serialized = serialize_collection(rows)
|
|
328
|
+
format_choice = format_hint or "jsonl"
|
|
329
|
+
payload = _encode_row_payload(serialized, format_choice)
|
|
330
|
+
return self._write_bytes(
|
|
331
|
+
payload,
|
|
332
|
+
destination,
|
|
333
|
+
rows=len(serialized),
|
|
334
|
+
format_label=format_choice,
|
|
335
|
+
storage_options=storage_options or {},
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
def write_arrow(
|
|
339
|
+
self,
|
|
340
|
+
table: "ArrowTable",
|
|
341
|
+
destination: StorageDestination,
|
|
342
|
+
*,
|
|
343
|
+
format_hint: StorageFormat | None = None,
|
|
344
|
+
storage_options: "dict[str, Any] | None" = None,
|
|
345
|
+
compression: str | None = None,
|
|
346
|
+
) -> StorageTelemetry:
|
|
347
|
+
"""Write an Arrow table to storage using zero-copy buffers."""
|
|
348
|
+
|
|
349
|
+
format_choice = format_hint or "parquet"
|
|
350
|
+
payload = _encode_arrow_payload(table, format_choice, compression=compression)
|
|
351
|
+
return self._write_bytes(
|
|
352
|
+
payload,
|
|
353
|
+
destination,
|
|
354
|
+
rows=int(table.num_rows),
|
|
355
|
+
format_label=format_choice,
|
|
356
|
+
storage_options=storage_options or {},
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
def read_arrow(
|
|
360
|
+
self, source: StorageDestination, *, file_format: StorageFormat, storage_options: "dict[str, Any] | None" = None
|
|
361
|
+
) -> "tuple[ArrowTable, StorageTelemetry]":
|
|
362
|
+
"""Read an artifact from storage and decode it into an Arrow table."""
|
|
363
|
+
|
|
364
|
+
backend, path = self._resolve_backend(source, storage_options)
|
|
365
|
+
backend_name = backend.backend_type
|
|
366
|
+
payload = _read_backend_sync(backend, path, backend_name=backend_name)
|
|
367
|
+
table = _decode_arrow_payload(payload, file_format)
|
|
368
|
+
rows_processed = int(table.num_rows)
|
|
369
|
+
telemetry: StorageTelemetry = {
|
|
370
|
+
"destination": path,
|
|
371
|
+
"bytes_processed": len(payload),
|
|
372
|
+
"rows_processed": rows_processed,
|
|
373
|
+
"format": file_format,
|
|
374
|
+
"backend": backend_name,
|
|
375
|
+
}
|
|
376
|
+
return table, telemetry
|
|
377
|
+
|
|
378
|
+
def stream_read(
|
|
379
|
+
self,
|
|
380
|
+
source: StorageDestination,
|
|
381
|
+
*,
|
|
382
|
+
chunk_size: int | None = None,
|
|
383
|
+
storage_options: "dict[str, Any] | None" = None,
|
|
384
|
+
) -> "Iterator[bytes]":
|
|
385
|
+
"""Stream bytes from an artifact."""
|
|
386
|
+
backend, path = self._resolve_backend(source, storage_options)
|
|
387
|
+
return backend.stream_read(path, chunk_size=chunk_size)
|
|
388
|
+
|
|
389
|
+
def allocate_staging_artifacts(self, requests: "list[StorageLoadRequest]") -> "list[StagedArtifact]":
|
|
390
|
+
"""Allocate staging metadata for upcoming loads."""
|
|
391
|
+
|
|
392
|
+
artifacts: list[StagedArtifact] = []
|
|
393
|
+
now = time()
|
|
394
|
+
|
|
395
|
+
for request in requests:
|
|
396
|
+
ttl = max(request["ttl_seconds"], 0)
|
|
397
|
+
cleanup_token = f"{request['correlation_id']}::{request['partition_id']}"
|
|
398
|
+
artifacts.append({
|
|
399
|
+
"partition_id": request["partition_id"],
|
|
400
|
+
"uri": request["destination_uri"],
|
|
401
|
+
"cleanup_token": cleanup_token,
|
|
402
|
+
"ttl_seconds": ttl,
|
|
403
|
+
"expires_at": now + ttl if ttl else now,
|
|
404
|
+
"correlation_id": request["correlation_id"],
|
|
405
|
+
})
|
|
406
|
+
if artifacts:
|
|
407
|
+
_METRICS.record_partitions(len(artifacts))
|
|
408
|
+
return artifacts
|
|
409
|
+
|
|
410
|
+
def cleanup_staging_artifacts(self, artifacts: "list[StagedArtifact]", *, ignore_errors: bool = True) -> None:
|
|
411
|
+
"""Delete staged artifacts best-effort."""
|
|
412
|
+
|
|
413
|
+
for artifact in artifacts:
|
|
414
|
+
backend, path = self._resolve_backend(artifact["uri"], None)
|
|
415
|
+
try:
|
|
416
|
+
_delete_backend_sync(backend, path, backend_name=backend.backend_type)
|
|
417
|
+
except Exception:
|
|
418
|
+
if not ignore_errors:
|
|
419
|
+
raise
|
|
420
|
+
|
|
421
|
+
def _write_bytes(
|
|
422
|
+
self,
|
|
423
|
+
payload: bytes,
|
|
424
|
+
destination: StorageDestination,
|
|
425
|
+
*,
|
|
426
|
+
rows: int,
|
|
427
|
+
format_label: str,
|
|
428
|
+
storage_options: "dict[str, Any]",
|
|
429
|
+
) -> StorageTelemetry:
|
|
430
|
+
backend, path = self._resolve_backend(destination, storage_options)
|
|
431
|
+
backend_name = backend.backend_type
|
|
432
|
+
start = perf_counter()
|
|
433
|
+
_write_backend_sync(backend, path, payload, backend_name=backend_name)
|
|
434
|
+
elapsed = perf_counter() - start
|
|
435
|
+
bytes_written = len(payload)
|
|
436
|
+
_METRICS.record_bytes(bytes_written)
|
|
437
|
+
telemetry: StorageTelemetry = {
|
|
438
|
+
"destination": path,
|
|
439
|
+
"bytes_processed": bytes_written,
|
|
440
|
+
"rows_processed": rows,
|
|
441
|
+
"duration_s": elapsed,
|
|
442
|
+
"format": format_label,
|
|
443
|
+
"backend": backend_name,
|
|
444
|
+
}
|
|
445
|
+
return telemetry
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
@mypyc_attr(allow_interpreted_subclasses=True)
|
|
449
|
+
class AsyncStoragePipeline:
|
|
450
|
+
"""Async variant of the storage pipeline leveraging async-capable backends when available."""
|
|
451
|
+
|
|
452
|
+
__slots__ = ("registry",)
|
|
453
|
+
|
|
454
|
+
def __init__(self, *, registry: StorageRegistry | None = None) -> None:
|
|
455
|
+
self.registry = registry or storage_registry
|
|
456
|
+
|
|
457
|
+
async def write_rows(
|
|
458
|
+
self,
|
|
459
|
+
rows: "list[dict[str, Any]]",
|
|
460
|
+
destination: StorageDestination,
|
|
461
|
+
*,
|
|
462
|
+
format_hint: StorageFormat | None = None,
|
|
463
|
+
storage_options: "dict[str, Any] | None" = None,
|
|
464
|
+
) -> StorageTelemetry:
|
|
465
|
+
serialized = serialize_collection(rows)
|
|
466
|
+
format_choice = format_hint or "jsonl"
|
|
467
|
+
payload = _encode_row_payload(serialized, format_choice)
|
|
468
|
+
return await self._write_bytes_async(
|
|
469
|
+
payload,
|
|
470
|
+
destination,
|
|
471
|
+
rows=len(serialized),
|
|
472
|
+
format_label=format_choice,
|
|
473
|
+
storage_options=storage_options or {},
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
async def write_arrow(
|
|
477
|
+
self,
|
|
478
|
+
table: "ArrowTable",
|
|
479
|
+
destination: StorageDestination,
|
|
480
|
+
*,
|
|
481
|
+
format_hint: StorageFormat | None = None,
|
|
482
|
+
storage_options: "dict[str, Any] | None" = None,
|
|
483
|
+
compression: str | None = None,
|
|
484
|
+
) -> StorageTelemetry:
|
|
485
|
+
format_choice = format_hint or "parquet"
|
|
486
|
+
payload = _encode_arrow_payload(table, format_choice, compression=compression)
|
|
487
|
+
return await self._write_bytes_async(
|
|
488
|
+
payload,
|
|
489
|
+
destination,
|
|
490
|
+
rows=int(table.num_rows),
|
|
491
|
+
format_label=format_choice,
|
|
492
|
+
storage_options=storage_options or {},
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
async def cleanup_staging_artifacts(self, artifacts: "list[StagedArtifact]", *, ignore_errors: bool = True) -> None:
|
|
496
|
+
for artifact in artifacts:
|
|
497
|
+
backend, path = _resolve_storage_backend(self.registry, artifact["uri"], None)
|
|
498
|
+
backend_name = backend.backend_type
|
|
499
|
+
if supports_async_delete(backend):
|
|
500
|
+
try:
|
|
501
|
+
await execute_async_storage_operation(
|
|
502
|
+
partial(backend.delete_async, path), backend=backend_name, operation="delete", path=path
|
|
503
|
+
)
|
|
504
|
+
except Exception:
|
|
505
|
+
if not ignore_errors:
|
|
506
|
+
raise
|
|
507
|
+
continue
|
|
508
|
+
|
|
509
|
+
try:
|
|
510
|
+
await async_(_delete_backend_sync)(backend=backend, path=path, backend_name=backend_name)
|
|
511
|
+
except Exception:
|
|
512
|
+
if not ignore_errors:
|
|
513
|
+
raise
|
|
514
|
+
|
|
515
|
+
async def _write_bytes_async(
|
|
516
|
+
self,
|
|
517
|
+
payload: bytes,
|
|
518
|
+
destination: StorageDestination,
|
|
519
|
+
*,
|
|
520
|
+
rows: int,
|
|
521
|
+
format_label: str,
|
|
522
|
+
storage_options: "dict[str, Any]",
|
|
523
|
+
) -> StorageTelemetry:
|
|
524
|
+
backend, path = _resolve_storage_backend(self.registry, destination, storage_options)
|
|
525
|
+
backend_name = backend.backend_type
|
|
526
|
+
start = perf_counter()
|
|
527
|
+
if supports_async_write_bytes(backend):
|
|
528
|
+
await execute_async_storage_operation(
|
|
529
|
+
partial(backend.write_bytes_async, path, payload),
|
|
530
|
+
backend=backend_name,
|
|
531
|
+
operation="write_bytes",
|
|
532
|
+
path=path,
|
|
533
|
+
)
|
|
534
|
+
else:
|
|
535
|
+
await async_(_write_backend_sync)(backend=backend, path=path, payload=payload, backend_name=backend_name)
|
|
536
|
+
|
|
537
|
+
elapsed = perf_counter() - start
|
|
538
|
+
bytes_written = len(payload)
|
|
539
|
+
_METRICS.record_bytes(bytes_written)
|
|
540
|
+
telemetry: StorageTelemetry = {
|
|
541
|
+
"destination": path,
|
|
542
|
+
"bytes_processed": bytes_written,
|
|
543
|
+
"rows_processed": rows,
|
|
544
|
+
"duration_s": elapsed,
|
|
545
|
+
"format": format_label,
|
|
546
|
+
"backend": backend_name,
|
|
547
|
+
}
|
|
548
|
+
return telemetry
|
|
549
|
+
|
|
550
|
+
async def read_arrow_async(
|
|
551
|
+
self, source: StorageDestination, *, file_format: StorageFormat, storage_options: "dict[str, Any] | None" = None
|
|
552
|
+
) -> "tuple[ArrowTable, StorageTelemetry]":
|
|
553
|
+
backend, path = _resolve_storage_backend(self.registry, source, storage_options)
|
|
554
|
+
backend_name = backend.backend_type
|
|
555
|
+
if supports_async_read_bytes(backend):
|
|
556
|
+
payload = await execute_async_storage_operation(
|
|
557
|
+
partial(backend.read_bytes_async, path), backend=backend_name, operation="read_bytes", path=path
|
|
558
|
+
)
|
|
559
|
+
else:
|
|
560
|
+
payload = await async_(_read_backend_sync)(backend=backend, path=path, backend_name=backend_name)
|
|
561
|
+
|
|
562
|
+
table = _decode_arrow_payload(payload, file_format)
|
|
563
|
+
rows_processed = int(table.num_rows)
|
|
564
|
+
telemetry: StorageTelemetry = {
|
|
565
|
+
"destination": path,
|
|
566
|
+
"bytes_processed": len(payload),
|
|
567
|
+
"rows_processed": rows_processed,
|
|
568
|
+
"format": file_format,
|
|
569
|
+
"backend": backend_name,
|
|
570
|
+
}
|
|
571
|
+
return table, telemetry
|
|
572
|
+
|
|
573
|
+
async def stream_read_async(
|
|
574
|
+
self,
|
|
575
|
+
source: StorageDestination,
|
|
576
|
+
*,
|
|
577
|
+
chunk_size: int | None = None,
|
|
578
|
+
storage_options: "dict[str, Any] | None" = None,
|
|
579
|
+
) -> "AsyncIterator[bytes]":
|
|
580
|
+
"""Stream bytes from an artifact asynchronously."""
|
|
581
|
+
backend, path = _resolve_storage_backend(self.registry, source, storage_options)
|
|
582
|
+
return await backend.stream_read_async(path, chunk_size=chunk_size)
|