diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b300e68..558946d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -37,6 +37,8 @@ jobs: # - windows-latest steps: - uses: actions/checkout@v4 + with: + submodules: true - uses: astral-sh/setup-uv@v3 - uses: Swatinem/rust-cache@v2 - name: Install Python version diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..403b869 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "_obstore"] + path = _obstore + url = https://github.com/developmentseed/obstore diff --git a/CHANGELOG.md b/CHANGELOG.md index 0078a71..e4b1b3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Added + +- `rustac.store` ([#127](https://github.com/stac-utils/rustac-py/pull/127)) + ## [0.7.2] - 2025-05-05 ### Fixed diff --git a/Cargo.lock b/Cargo.lock index f05bcd5..c67c65c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,17 +30,17 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "const-random", - "getrandom 0.2.16", + "getrandom 0.3.3", "once_cell", "serde", "version_check", - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -203,7 +203,7 @@ version = "55.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cebfe926794fbc1f49ddd0cdaf898956ca9f6e79541efce62dabccfd81380472" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "arrow-buffer", "arrow-data", "arrow-schema", @@ -334,7 +334,7 @@ version = "55.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa5f5a93c75f46ef48e4001535e7b6c922eeb0aa20b73cf58d09e13d057490d8" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "arrow-array", "arrow-buffer", "arrow-data", @@ -469,9 +469,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -674,9 +674,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.21" +version = "1.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" +checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" dependencies = [ "jobserver", "libc", @@ -1424,9 +1424,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "js-sys", @@ -1496,7 +1496,7 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", ] [[package]] @@ -1645,7 +1645,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", + "webpki-roots 0.26.11", ] [[package]] @@ -1738,21 +1738,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -1761,31 +1762,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -1793,67 +1774,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -1873,9 +1841,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -1953,9 +1921,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd" +checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -1968,9 +1936,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300" +checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48" dependencies = [ "proc-macro2", "quote", @@ -1998,7 +1966,7 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "libc", ] @@ -2030,7 +1998,7 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "161c33c3ec738cfea3288c5c53dfcdb32fd4fc2954de86ea06f71b5a1a40bfcd" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "base64", "bytecount", "email_address", @@ -2054,7 +2022,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1b46a0365a611fbf1d2143104dcf910aada96fafd295bab16c60b802bf6fa1d" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "base64", "bytecount", "email_address", @@ -2168,9 +2136,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25169bd5913a4b437588a7e3d127cd6e90127b60e0ffbd834a38f1599e016b8" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" @@ -2206,9 +2174,9 @@ checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" @@ -2226,6 +2194,12 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "lz4_flex" version = "0.11.3" @@ -2567,7 +2541,7 @@ version = "55.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd31a8290ac5b19f09ad77ee7a1e6a541f1be7674ad410547d5f1eef6eef4a9c" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "arrow-array", "arrow-buffer", "arrow-cast", @@ -2671,7 +2645,7 @@ dependencies = [ [[package]] name = "pgstac" version = "0.3.0" -source = "git+https://github.com/stac-utils/rustac?branch=main#c8f20c3202e4e8c37e81d7c47644a272719d863b" +source = "git+https://github.com/stac-utils/rustac?branch=main#20b2823bb1feda50806f3ff112c3a7acbb6f570e" dependencies = [ "serde", "serde_json", @@ -2797,6 +2771,15 @@ dependencies = [ "serde_json", ] +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -2809,7 +2792,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.25", + "zerocopy", ] [[package]] @@ -2959,6 +2942,28 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "pyo3-object_store" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d86e64cc8cb37a7950eadeee4a80c7d8467c3871baf176996af917fa6cda36" +dependencies = [ + "async-trait", + "bytes", + "chrono", + "futures", + "humantime", + "itertools 0.14.0", + "object_store", + "percent-encoding", + "pyo3", + "pyo3-async-runtimes", + "serde", + "thiserror 1.0.69", + "tokio", + "url", +] + [[package]] name = "pythonize" version = "0.24.0" @@ -2981,9 +2986,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.7" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" dependencies = [ "bytes", "cfg_aliases", @@ -3001,12 +3006,13 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.11" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbafbbdbb0f638fe3f35f3c56739f77a8a1d070cb25603226c83339b391472b" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" dependencies = [ "bytes", - "getrandom 0.3.2", + "getrandom 0.3.3", + "lru-slab", "rand 0.9.1", "ring", "rustc-hash", @@ -3110,7 +3116,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", ] [[package]] @@ -3174,7 +3180,7 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40a64b3a635fad9000648b4d8a59c8710c523ab61a23d392a7d91d47683f5adc" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "fluent-uri", "once_cell", "parking_lot", @@ -3188,7 +3194,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8eff4fa778b5c2a57e85c5f2fe3a709c52f0e60d23146e2151cbef5893f420e" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "fluent-uri", "once_cell", "parking_lot", @@ -3293,7 +3299,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots", + "webpki-roots 0.26.11", "windows-registry", ] @@ -3376,7 +3382,7 @@ dependencies = [ [[package]] name = "rustac" version = "0.5.3" -source = "git+https://github.com/stac-utils/rustac?branch=main#c8f20c3202e4e8c37e81d7c47644a272719d863b" +source = "git+https://github.com/stac-utils/rustac?branch=main#20b2823bb1feda50806f3ff112c3a7acbb6f570e" dependencies = [ "anyhow", "axum", @@ -3404,6 +3410,7 @@ dependencies = [ "pyo3-arrow", "pyo3-async-runtimes", "pyo3-log", + "pyo3-object_store", "pythonize", "rustac", "serde", @@ -3452,9 +3459,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.26" +version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ "once_cell", "ring", @@ -3487,18 +3494,19 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ "web-time", + "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.1" +version = "0.103.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +checksum = "7149975849f1abb3832b246010ef62ccc80d3a76169517ada7188252b9cfb437" dependencies = [ "ring", "rustls-pki-types", @@ -3779,7 +3787,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "stac" version = "0.12.0" -source = "git+https://github.com/stac-utils/rustac?branch=main#c8f20c3202e4e8c37e81d7c47644a272719d863b" +source = "git+https://github.com/stac-utils/rustac?branch=main#20b2823bb1feda50806f3ff112c3a7acbb6f570e" dependencies = [ "arrow-array", "arrow-cast", @@ -3814,7 +3822,7 @@ dependencies = [ [[package]] name = "stac-api" version = "0.7.1" -source = "git+https://github.com/stac-utils/rustac?branch=main#c8f20c3202e4e8c37e81d7c47644a272719d863b" +source = "git+https://github.com/stac-utils/rustac?branch=main#20b2823bb1feda50806f3ff112c3a7acbb6f570e" dependencies = [ "async-stream", "chrono", @@ -3839,7 +3847,7 @@ dependencies = [ [[package]] name = "stac-derive" version = "0.2.0" -source = "git+https://github.com/stac-utils/rustac?branch=main#c8f20c3202e4e8c37e81d7c47644a272719d863b" +source = "git+https://github.com/stac-utils/rustac?branch=main#20b2823bb1feda50806f3ff112c3a7acbb6f570e" dependencies = [ "quote", "syn 2.0.101", @@ -3848,7 +3856,7 @@ dependencies = [ [[package]] name = "stac-duckdb" version = "0.1.1" -source = "git+https://github.com/stac-utils/rustac?branch=main#c8f20c3202e4e8c37e81d7c47644a272719d863b" +source = "git+https://github.com/stac-utils/rustac?branch=main#20b2823bb1feda50806f3ff112c3a7acbb6f570e" dependencies = [ "arrow-array", "chrono", @@ -3867,7 +3875,7 @@ dependencies = [ [[package]] name = "stac-server" version = "0.3.4" -source = "git+https://github.com/stac-utils/rustac?branch=main#c8f20c3202e4e8c37e81d7c47644a272719d863b" +source = "git+https://github.com/stac-utils/rustac?branch=main#20b2823bb1feda50806f3ff112c3a7acbb6f570e" dependencies = [ "axum", "bb8", @@ -4110,9 +4118,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -4156,9 +4164,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.44.2" +version = "1.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" dependencies = [ "backtrace", "bytes", @@ -4499,12 +4507,6 @@ dependencies = [ "serde", ] -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -4704,9 +4706,18 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.10" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37493cadf42a2a939ed404698ded7fb378bf301b5011f973361779a3a74f8c93" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.0", +] + +[[package]] +name = "webpki-roots" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" dependencies = [ "rustls-pki-types", ] @@ -4980,9 +4991,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] @@ -5044,17 +5055,11 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wyz" @@ -5089,9 +5094,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -5101,9 +5106,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", @@ -5111,33 +5116,13 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive 0.7.35", -] - [[package]] name = "zerocopy" version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "zerocopy-derive 0.8.25", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", + "zerocopy-derive", ] [[package]] @@ -5192,11 +5177,22 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -5205,9 +5201,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index c7af62f..42df05e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ thiserror = "2.0.12" tokio = { version = "1.44.0", features = ["rt-multi-thread"] } pyo3-log = "0.12.1" tracing = "0.1.41" +pyo3-object_store = "0.2.0" [build-dependencies] cargo-lock = "10" diff --git a/_obstore b/_obstore new file mode 160000 index 0000000..aaa8d6a --- /dev/null +++ b/_obstore @@ -0,0 +1 @@ +Subproject commit aaa8d6a0de646b532dc74a81f4adbd8ecf9de026 diff --git a/docs/api/store/aws.md b/docs/api/store/aws.md new file mode 100644 index 0000000..ffd48b5 --- /dev/null +++ b/docs/api/store/aws.md @@ -0,0 +1,8 @@ +# AWS S3 + +::: rustac.store.S3Store +::: rustac.store.S3Config + options: + show_if_no_docstring: true +::: rustac.store.S3Credential +::: rustac.store.S3CredentialProvider diff --git a/docs/api/store/azure.md b/docs/api/store/azure.md new file mode 100644 index 0000000..548c506 --- /dev/null +++ b/docs/api/store/azure.md @@ -0,0 +1,11 @@ +# Microsoft Azure + +::: rustac.store.AzureStore +::: rustac.store.AzureAccessKey +::: rustac.store.AzureConfig + options: + show_if_no_docstring: true +::: rustac.store.AzureSASToken +::: rustac.store.AzureBearerToken +::: rustac.store.AzureCredential +::: rustac.store.AzureCredentialProvider diff --git a/docs/api/store/config.md b/docs/api/store/config.md new file mode 100644 index 0000000..04584e9 --- /dev/null +++ b/docs/api/store/config.md @@ -0,0 +1,5 @@ +# Configuration + +::: rustac.store.ClientConfig +::: rustac.store.BackoffConfig +::: rustac.store.RetryConfig diff --git a/docs/api/store/gcs.md b/docs/api/store/gcs.md new file mode 100644 index 0000000..4db5cf0 --- /dev/null +++ b/docs/api/store/gcs.md @@ -0,0 +1,8 @@ +# Google Cloud Storage + +::: rustac.store.GCSStore +::: rustac.store.GCSConfig + options: + show_if_no_docstring: true +::: rustac.store.GCSCredential +::: rustac.store.GCSCredentialProvider diff --git a/docs/api/store/http.md b/docs/api/store/http.md new file mode 100644 index 0000000..42e0667 --- /dev/null +++ b/docs/api/store/http.md @@ -0,0 +1,3 @@ +# HTTP + +::: rustac.store.HTTPStore diff --git a/docs/api/store/index.md b/docs/api/store/index.md new file mode 100644 index 0000000..f5eb62d --- /dev/null +++ b/docs/api/store/index.md @@ -0,0 +1,4 @@ +# ObjectStore + +::: rustac.store.from_url +::: rustac.store.ObjectStore diff --git a/docs/api/store/local.md b/docs/api/store/local.md new file mode 100644 index 0000000..7a901c4 --- /dev/null +++ b/docs/api/store/local.md @@ -0,0 +1,3 @@ +# Local + +::: rustac.store.LocalStore diff --git a/docs/api/store/memory.md b/docs/api/store/memory.md new file mode 100644 index 0000000..fac0183 --- /dev/null +++ b/docs/api/store/memory.md @@ -0,0 +1,3 @@ +# Memory + +::: rustac.store.MemoryStore diff --git a/mkdocs.yml b/mkdocs.yml index 00d4450..cf54840 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -26,6 +26,15 @@ nav: - read: api/read.md - search: api/search.md - stac: api/stac.md + - store: + - api/store/index.md + - api/store/aws.md + - api/store/azure.md + - api/store/config.md + - api/store/gcs.md + - api/store/http.md + - api/store/local.md + - api/store/memory.md - version: api/version.md - walk: api/walk.md - write: api/write.md @@ -57,6 +66,7 @@ plugins: inventories: - https://kylebarron.dev/arro3/latest/objects.inv - https://geopandas.org/en/stable/objects.inv + - https://developmentseed.org/obstore/latest/objects.inv - search - social: cards_layout_options: diff --git a/pyproject.toml b/pyproject.toml index 0959b9f..635e168 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,9 +43,14 @@ ignore_missing_imports = true [tool.pytest.ini_options] asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "function" +testpaths = ["tests"] [tool.ruff] -exclude = ["python/rustac/__init__.py", "docs/examples/example_*.py"] +exclude = [ + "python/rustac/__init__.py", + "docs/examples/example_*.py", + "_obstore", +] [dependency-groups] dev = [ @@ -63,6 +68,7 @@ dev = [ docs = [ "arro3-core>=0.4.5", "contextily>=1.6.2", + "griffe>=1.6.0", "humanize>=4.12.1", "ipykernel>=6.29.5", "jinja2>=3.1.4", diff --git a/python/rustac/__init__.py b/python/rustac/__init__.py index da5e16d..b39667b 100644 --- a/python/rustac/__init__.py +++ b/python/rustac/__init__.py @@ -2,6 +2,7 @@ from .rustac import * from typing import TypedDict, Required, Any, Literal +from . import store class Catalog(TypedDict, total=False): diff --git a/python/rustac/rustac.pyi b/python/rustac/rustac.pyi index 258766b..5241d35 100644 --- a/python/rustac/rustac.pyi +++ b/python/rustac/rustac.pyi @@ -6,6 +6,7 @@ from typing import Any, AsyncIterator, Literal, Optional, Tuple import arro3.core from rustac import Catalog, Collection, Item, ItemCollection +from rustac.store import ObjectStore class RustacError(Exception): """A package-specific exception.""" @@ -210,7 +211,7 @@ async def read( href: str, *, format: str | None = None, - options: list[tuple[str, str]] | None = None, + store: ObjectStore | None = None, set_self_link: bool = True, ) -> dict[str, Any]: """ @@ -220,8 +221,7 @@ async def read( href: The href to write to format: The input format. If not provided, will be inferred from the href's extension. - options: Options for configuring an - object store, e.g. your AWS credentials. + store: An optional [ObjectStore][] set_self_link: If True, set the `self` link to the value of `href`. Returns: @@ -424,7 +424,7 @@ async def write( value: dict[str, Any] | list[dict[str, Any]], *, format: str | None = None, - options: list[tuple[str, str]] | None = None, + store: ObjectStore | None = None, ) -> dict[str, str] | None: """ Writes STAC to a href. @@ -435,8 +435,7 @@ async def write( can be a STAC dictionary or a list of items. format: The output format to write. If not provided, will be inferred from the href's extension. - options: Options for configuring an - object store, e.g. your AWS credentials. + store: The object store to use for writing. Returns: The result of putting data into an object store, e.g. the e_tag and the diff --git a/python/rustac/store b/python/rustac/store new file mode 120000 index 0000000..e177177 --- /dev/null +++ b/python/rustac/store @@ -0,0 +1 @@ +../../_obstore/obstore/python/obstore/store \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index f7d36ff..4b73d1e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,6 +41,9 @@ fn rustac(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(walk::walk, m)?)?; m.add_function(wrap_pyfunction!(write::write, m)?)?; + pyo3_object_store::register_store_module(py, m, "rustac", "store")?; + pyo3_object_store::register_exceptions_module(py, m, "rustac", "exceptions")?; + Ok(()) } diff --git a/src/read.rs b/src/read.rs index 9e20da2..48b127d 100644 --- a/src/read.rs +++ b/src/read.rs @@ -1,31 +1,37 @@ use crate::{Error, Json}; use pyo3::{Bound, PyResult, Python, pyfunction, types::PyAny}; +use pyo3_object_store::AnyObjectStore; use stac::{Format, Link, Links, SelfHref, Value}; #[pyfunction] -#[pyo3(signature = (href, *, format=None, options=None, set_self_link=true))] +#[pyo3(signature = (href, *, format=None, store=None, set_self_link=true))] pub fn read( py: Python<'_>, href: String, format: Option, - options: Option>, + store: Option, set_self_link: bool, ) -> PyResult> { let format = format .and_then(|f| f.parse::().ok()) .or_else(|| Format::infer_from_href(&href)) .unwrap_or_default(); - let options = options.unwrap_or_default(); pyo3_async_runtimes::tokio::future_into_py(py, async move { - let mut value = format - .get_opts::(href, options) - .await - .map_err(Error::from)?; + let mut value: Value = if let Some(store) = store { + format + .get_store(store.into_dyn(), href.as_str()) + .await + .map_err(Error::from)? + } else { + format + .get_opts(href.as_str(), [] as [(&str, &str); 0]) + .await + .map_err(Error::from)? + }; if set_self_link { - if let Some(href) = value.self_href().cloned() { - value.set_link(Link::self_(href)); - } + value.set_link(Link::self_(href.clone())); } + *value.self_href_mut() = Some(href.into()); Ok(Json(value)) }) } diff --git a/src/write.rs b/src/write.rs index 33bbab6..dc63f30 100644 --- a/src/write.rs +++ b/src/write.rs @@ -1,16 +1,17 @@ use crate::{Error, Json, Result}; use pyo3::{Bound, PyAny, PyResult, Python, pyfunction}; +use pyo3_object_store::AnyObjectStore; use serde_json::Value; use stac::{Format, Item, ItemCollection}; #[pyfunction] -#[pyo3(signature = (href, value, *, format=None, options=None))] +#[pyo3(signature = (href, value, *, format=None, store=None))] pub fn write<'py>( py: Python<'py>, href: String, value: Bound<'_, PyAny>, format: Option, - options: Option>, + store: Option, ) -> PyResult> { let value: Value = pythonize::depythonize(&value)?; let value = if let Value::Array(array) = value { @@ -27,10 +28,18 @@ pub fn write<'py>( .and_then(|f| f.parse::().ok()) .or_else(|| Format::infer_from_href(&href)) .unwrap_or_default(); - let put_result = format - .put_opts(href, value, options.unwrap_or_default()) - .await - .map_err(Error::from)?; + let put_result = if let Some(store) = store { + format + .put_store(store.into_dyn(), href, value) + .await + .map(Some) + .map_err(Error::from)? + } else { + format + .put_opts(href, value, [] as [(&str, &str); 0]) + .await + .map_err(Error::from)? + }; if let Some(put_result) = put_result { let put_result = serde_json::json!({ "e_tag": put_result.e_tag, diff --git a/tests/test_read.py b/tests/test_read.py index 789066b..4deb316 100644 --- a/tests/test_read.py +++ b/tests/test_read.py @@ -3,6 +3,7 @@ import rustac from pystac import Item +from rustac.store import LocalStore async def test_read(examples: Path) -> None: @@ -27,3 +28,8 @@ async def test_read_proj_geometry( await rustac.write(path, maxar_items) items = await rustac.read(path) assert len(items["features"]) == 2 + + +async def test_read_store(examples: Path) -> None: + store = LocalStore(prefix=str(examples)) + await rustac.read("simple-item.json", store=store) diff --git a/tests/test_write.py b/tests/test_write.py index 465cc06..91a5837 100644 --- a/tests/test_write.py +++ b/tests/test_write.py @@ -4,6 +4,7 @@ import pyarrow.parquet import rustac import stac_geoparquet +from rustac.store import LocalStore async def test_write(item: dict[str, Any], tmp_path: Path) -> None: @@ -19,3 +20,10 @@ async def test_write_compressed(item: dict[str, Any], tmp_path: Path) -> None: await rustac.write(path, [item]) metadata = pyarrow.parquet.read_metadata(path) assert metadata.row_group(0).column(0).compression == "SNAPPY" + + +async def test_write_store(item: dict[str, Any], tmp_path: Path) -> None: + store = LocalStore(prefix=tmp_path) + await rustac.write("item.json", item, store=store) + read_item = await rustac.read("item.json", store=store) + assert item["id"] == read_item["id"] diff --git a/uv.lock b/uv.lock index 8bdfb97..6124b86 100644 --- a/uv.lock +++ b/uv.lock @@ -558,14 +558,14 @@ wheels = [ [[package]] name = "griffe" -version = "1.5.7" +version = "1.7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/59/80/13b6456bfbf8bc854875e58d3a3bad297ee19ebdd693ce62a10fab007e7a/griffe-1.5.7.tar.gz", hash = "sha256:465238c86deaf1137761f700fb343edd8ffc846d72f6de43c3c345ccdfbebe92", size = 391503, upload-time = "2025-02-11T13:38:11.867Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/3e/5aa9a61f7c3c47b0b52a1d930302992229d191bf4bc76447b324b731510a/griffe-1.7.3.tar.gz", hash = "sha256:52ee893c6a3a968b639ace8015bec9d36594961e156e23315c8e8e51401fa50b", size = 395137, upload-time = "2025-04-23T11:29:09.147Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/67/b43330ed76f96be098c165338d47ccb952964ed77ba1d075247fbdf05c04/griffe-1.5.7-py3-none-any.whl", hash = "sha256:4af8ec834b64de954d447c7b6672426bb145e71605c74a4e22d510cc79fe7d8b", size = 128294, upload-time = "2025-02-11T13:38:09.319Z" }, + { url = "https://files.pythonhosted.org/packages/58/c6/5c20af38c2a57c15d87f7f38bee77d63c1d2a3689f74fefaf35915dd12b2/griffe-1.7.3-py3-none-any.whl", hash = "sha256:c6b3ee30c2f0f17f30bcdef5068d6ab7a2a4f1b8bf1a3e74b56fffd21e1c5f75", size = 129303, upload-time = "2025-04-23T11:29:07.145Z" }, ] [[package]] @@ -2052,6 +2052,7 @@ dev = [ docs = [ { name = "arro3-core" }, { name = "contextily" }, + { name = "griffe" }, { name = "humanize" }, { name = "ipykernel" }, { name = "jinja2" }, @@ -2083,6 +2084,7 @@ dev = [ docs = [ { name = "arro3-core", specifier = ">=0.4.5" }, { name = "contextily", specifier = ">=1.6.2" }, + { name = "griffe", specifier = ">=1.6.0" }, { name = "humanize", specifier = ">=4.12.1" }, { name = "ipykernel", specifier = ">=6.29.5" }, { name = "jinja2", specifier = ">=3.1.4" },