diff --git a/.gitignore b/.gitignore index 0fa04a75..573aacb2 100644 --- a/.gitignore +++ b/.gitignore @@ -218,3 +218,4 @@ uv.lock # VCS versioning src/eopf_geozarr/_version.py analysis/.edh_token +docs/superpowers/ diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e1a24428..31ed71b1 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.10.1" + ".": "0.10.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 20c5c3be..7319ccb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.10.2 (2026-07-17) + +## What's Changed +* ci(deps): bump the actions group with 3 updates by @dependabot[bot] in https://github.com/EOPF-Explorer/data-model/pull/185 +* bump zarr conventions; migrate type checking to pyright by @d-v-b in https://github.com/EOPF-Explorer/data-model/pull/199 +* fix(conversion): concurrent-safe source opening (native-chunk-aligned reads + atomic CacheStore) for data-pipeline#339 by @lhoupert in https://github.com/EOPF-Explorer/data-model/pull/220 + + +**Full Changelog**: https://github.com/EOPF-Explorer/data-model/compare/v0.10.1...v0.10.2 + ## 0.10.1 (2026-06-09) ## What's Changed diff --git a/README.md b/README.md index 44f3f6ea..a5fe0d14 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,6 @@ dt_geozarr = create_geozarr_dataset( output_path="s3://my-bucket/geozarr-data/output.zarr", spatial_chunk=4096, min_dimension=256, - tile_width=256, max_retries=3 ) ``` @@ -207,7 +206,6 @@ dt_geozarr = create_geozarr_dataset( output_path="path/to/output/geozarr.zarr", spatial_chunk=4096, min_dimension=256, - tile_width=256, max_retries=3 ) ``` @@ -227,7 +225,6 @@ Create a GeoZarr-spec 0.4 compliant dataset from EOPF data. - `output_path` (str): Output path for the Zarr store - `spatial_chunk` (int, default=4096): Spatial chunk size for encoding - `min_dimension` (int, default=256): Minimum dimension for overview levels -- `tile_width` (int, default=256): Tile width for TMS compatibility - `max_retries` (int, default=3): Maximum number of retries for network operations **Returns:** @@ -283,6 +280,71 @@ Check if a variable is a grid_mapping variable by looking for references to it. Validate that a specific band exists and is complete in the dataset. +## Supported Products + +### Sentinel-2 MSI + +Sentinel-2 MSI (MultiSpectral Instrument) L1C and L2A products are detected +automatically by `eopf-geozarr convert` and routed to the optimized multiscale +layout (`convert-s2-optimized`). The three native resolution groups (10 m, 20 m, +60 m) are reused as-is and coarser overviews (120 m, 360 m, 720 m) are computed +via /2 downsampling. + +### Sentinel-3 OLCI L1 EFR + +Sentinel-3 OLCI (Ocean and Land Colour Instrument) Level-1 EFR (Full Resolution) +products are detected automatically by `eopf-geozarr convert` and routed to the +dedicated OLCI converter. Unlike Sentinel-2, OLCI data starts out on **native +swath geometry**: measurements are stored on a per-pixel 2-D lat/lon grid. The +exporter warps this curvilinear swath once onto a regular grid (default +`EPSG:4326`) so that the output is a standard GeoZarr raster. + +#### Auto-detection + +```bash +eopf-geozarr convert S3A_OL_1_EFR.zarr output.zarr +``` + +#### Dedicated command + +```bash +eopf-geozarr convert-s3-olci-optimized S3A_OL_1_EFR.zarr output.zarr \ + --spatial-chunk 1024 \ + --min-dimension 256 \ + --compression-level 3 +``` + +Key flags: + +- `--spatial-chunk` — target spatial chunk size in pixels (default: 1024) +- `--compression-level` — Blosc/zstd compression level 1–9 (default: 3) +- `--min-dimension` — stop generating /2 overview levels once either spatial + dimension would drop below this value (default: 256) +- `--enable-sharding` — accepted but not yet wired into encoding (follow-up task) +- `--keep-scale-offset` — accepted but not yet wired into encoding (follow-up task) +- `--target-crs` — target CRS for the reprojected output grid (default: `EPSG:4326`) + +#### What is converted + +- **`/measurements/r0`**: all 21 OLCI radiance bands warped once from the + native swath onto a regular grid (default `EPSG:4326`, ~300 m preserved), + with 1-D `y`/`x` coordinates, a `spatial_ref` variable, and `grid_mapping` + on every band; the parent `measurements/` group carries the GeoZarr + `multiscales`, `spatial:`, and `proj:` convention metadata. +- **Overview subgroups** (`r2`, `r4`, …): /2 fill-aware block-averaged copies + stored as sibling Zarr groups next to `r0`, each with its own CRS metadata. +- **`/conditions` and `/quality`**: copied through unmodified. + +> **Note:** per-scan-line `time_stamp` is not representable on a regular grid +> and is dropped from the converted measurements (it remains in the source +> product). + +> **Note:** OLCI support is initial/measurements-focused (v1). Tie-point grid +> groups (`conditions/geometry`, `meteorology`, `instrument`) are copied through but +> not converted to GeoZarr convention. Encoding wiring for `--enable-sharding`, +> `--spatial-chunk`, `--compression-level`, and `--keep-scale-offset` is accepted +> but scheduled as a follow-up task. + ## Architecture The library is organized into the following modules: diff --git a/docs/converter.md b/docs/converter.md index 898c251a..8c44b59d 100644 --- a/docs/converter.md +++ b/docs/converter.md @@ -177,6 +177,68 @@ dt_optimized = convert_s2_optimized( The result is a space-efficient multiscale pyramid: `/measurements/reflectance/{r10m, r20m, r60m, r120m, r360m, r720m}` where the native resolutions are preserved as-is and only the coarser levels are computed. +## Sentinel-3 OLCI L1 EFR Conversion + +Sentinel-3 OLCI (Ocean and Land Colour Instrument) Level-1 EFR (Full Resolution) +products are supported. OLCI measurements start out on **native swath geometry**: +a per-pixel 2-D lat/lon grid. The converter reprojects (warps) the swath measurements +once onto a regular grid (default `EPSG:4326`) using the swath geolocation arrays, +then generates /2 fill-aware block-averaged overview subgroups for multi-resolution +access. + +### Auto-detection + +The generic `convert` command detects OLCI products automatically: + +```bash +eopf-geozarr convert S3A_OL_1_EFR.zarr output.zarr +``` + +### Dedicated command + +A dedicated command offers fine-grained control: + +```bash +eopf-geozarr convert-s3-olci-optimized S3A_OL_1_EFR.zarr output.zarr \ + --spatial-chunk 1024 \ + --min-dimension 256 \ + --compression-level 3 +``` + +| Flag | Default | Description | +|------|---------|-------------| +| `--spatial-chunk` | 1024 | Target spatial chunk size in pixels | +| `--compression-level` | 3 | Blosc/zstd compression level (1–9) | +| `--min-dimension` | 256 | Minimum spatial dimension for overview levels | +| `--enable-sharding` | off | Accepted but not yet wired into encoding (follow-up task) | +| `--keep-scale-offset` | off | Accepted but not yet wired into encoding (follow-up task) | +| `--target-crs` | EPSG:4326 | Target CRS for the reprojected output grid | + +### Output layout + +``` +output.zarr/ +├── measurements/ # Carries multiscales + spatial: + proj: convention metadata +│ ├── r0/ # Warped native-resolution OLCI bands (oa01_radiance … oa21_radiance) +│ │ # with 1-D y/x coordinates and spatial_ref +│ ├── r2/ # 1/2-resolution overview +│ ├── r4/ # 1/4-resolution overview +│ └── ... +├── conditions/ # Copied through unmodified (tie-point geometry, meteorology) +└── quality/ # Copied through unmodified (quality flags) +``` + +Each measurement group carries GeoZarr `spatial:` and `proj:` convention metadata, +with 1-D `y`/`x` dimension coordinates and a `spatial_ref` variable referenced by +`grid_mapping` on every band. Per-scan-line `time_stamp` is dropped, since it has +no representation on a regular grid. + +> **Note:** OLCI support is initial/measurements-focused (v1). Tie-point grid +> groups in `conditions/geometry`, `meteorology`, and `instrument` are copied +> through but not converted to GeoZarr convention. Encoding wiring for +> `--enable-sharding`, `--spatial-chunk`, `--compression-level`, and +> `--keep-scale-offset` is accepted but scheduled as a follow-up task. + ## Error Handling The converter includes robust error handling and retry logic for network operations, ensuring reliable processing even in challenging environments. diff --git a/docs/notebooks/sentinel3_olci_geozarr.ipynb b/docs/notebooks/sentinel3_olci_geozarr.ipynb new file mode 100644 index 00000000..36ad101d --- /dev/null +++ b/docs/notebooks/sentinel3_olci_geozarr.ipynb @@ -0,0 +1,735 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2888da1e", + "metadata": {}, + "source": [ + "# Sentinel-3 OLCI L1 EFR → GeoZarr\n", + "\n", + "This notebook demonstrates the Sentinel-3 OLCI exporter in `eopf-geozarr`:\n", + "\n", + "1. **Open** an EOPF Zarr Sentinel-3 OLCI L1 EFR product.\n", + "2. **Detect** that it is an OLCI product.\n", + "3. **Convert** it to a GeoZarr-compliant, multiscale Zarr store.\n", + "4. **Visualize** the multiscale pyramid by splitting one field of view into\n", + " four quadrants, each rendered from a *different* overview level.\n", + "\n", + "OLCI is delivered as a **curvilinear swath** (per-pixel 2-D latitude/longitude,\n", + "no projected CRS). The exporter warps the swath once onto a regular grid\n", + "(default `EPSG:4326`) using the dense per-pixel geolocation, then builds\n", + "overviews by fill-aware 2×2 block averaging of the radiance bands. Every\n", + "pyramid level declares its CRS (`spatial_ref`/`grid_mapping` plus `proj:`\n", + "convention attrs), so generic GeoZarr readers can tile it directly.\n", + "\n", + "> Requires the `notebooks` dependency group:\n", + "> `uv sync --group notebooks` (jupyter, matplotlib, nbformat)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "96531b64", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-28T06:42:29.715144Z", + "iopub.status.busy": "2026-07-28T06:42:29.715055Z", + "iopub.status.idle": "2026-07-28T06:42:31.808045Z", + "shell.execute_reply": "2026-07-28T06:42:31.807326Z" + } + }, + "outputs": [], + "source": [ + "import pathlib\n", + "import tempfile\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import rioxarray # noqa: F401\n", + "import xarray as xr\n", + "import zarr\n", + "\n", + "from eopf_geozarr.s3_olci_optimization.olci_converter import (\n", + " convert_olci_optimized,\n", + " is_sentinel3_olci_dataset,\n", + ")\n", + "from eopf_geozarr.conversion.geozarr import get_zarr_group" + ] + }, + { + "cell_type": "markdown", + "id": "cb881df9", + "metadata": {}, + "source": [ + "## 1. Open an EOPF OLCI product\n", + "\n", + "We open a real Sentinel-3 OLCI L1 EFR product from the EOPF sample store on\n", + "EODC. If the store is unreachable (offline / CI), we fall back to the small\n", + "structure-only test fixture shipped with the repository so the notebook still\n", + "runs end to end.\n", + "\n", + "EOPF radiance is stored as scaled `uint16`; we open with `mask_and_scale=False`\n", + "so the raw integers and their `scale_factor` / `_FillValue` are preserved for a\n", + "faithful conversion (the converter expects un-decoded input)." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "baf81f90", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-28T06:42:31.810203Z", + "iopub.status.busy": "2026-07-28T06:42:31.809957Z", + "iopub.status.idle": "2026-07-28T06:42:32.915643Z", + "shell.execute_reply": "2026-07-28T06:42:32.914869Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Opened remote EODC OLCI product.\n", + "Top-level groups: ['/', '/conditions', '/conditions/geometry', '/conditions/image', '/conditions/instrument', '/conditions/meteorology', '/conditions/orphans', '/measurements', '/measurements/orphans', '/quality', '/quality/orphans']\n" + ] + } + ], + "source": [ + "# A real OLCI L1 EFR product on the EODC EOPF sample store (use an _NT_,\n", + "# fully-consolidated product — _NR_ near-real-time copies may lack metadata).\n", + "EODC_OLCI_URL = (\n", + " \"https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202511-s03olcefr-eu/\"\n", + " \"01/products/cpm_v262/\"\n", + " \"S3A_OL_1_EFR____20251101T073957_20251101T074257_20251102T084255_\"\n", + " \"0179_132_149_2160_PS1_O_NT_004.zarr\"\n", + ")\n", + "\n", + "\n", + "def open_olci_input() -> xr.DataTree:\n", + " \"\"\"Open the remote OLCI product; fall back to the repo test fixture offline.\"\"\"\n", + " try:\n", + " dt = xr.open_datatree(\n", + " EODC_OLCI_URL, engine=\"zarr\", chunks={}, mask_and_scale=False\n", + " )\n", + " print(\"Opened remote EODC OLCI product.\")\n", + " return dt\n", + " except Exception as exc: # noqa: BLE001 - notebook offline fallback\n", + " print(f\"Remote open failed ({type(exc).__name__}); using bundled fixture.\")\n", + " from tests.conftest import create_group_from_json\n", + "\n", + " fixture = pathlib.Path(\n", + " \"tests/_test_data/s3_examples/\"\n", + " \"S3A_OL_1_EFR____20251101T073957_20251101T074257_20251102T084255_\"\n", + " \"0179_132_149_2160_PS1_O_NT_004.json\"\n", + " )\n", + " store = create_group_from_json(fixture, pathlib.Path(tempfile.mkdtemp()))\n", + "\n", + " # The JSON fixture materializes arrays as zeros; zero lat/lon is a\n", + " # degenerate geolocation the warp rejects. Seed a plausible grid\n", + " # (whole-degree spacing survives this fixture's raw int32 storage).\n", + " import zarr as _zarr\n", + "\n", + " fixture_group = _zarr.open_group(str(store), mode=\"a\")\n", + " fixture_meas = fixture_group[\"measurements\"]\n", + " assert isinstance(fixture_meas, _zarr.Group)\n", + " lat_arr = fixture_meas[\"latitude\"]\n", + " assert isinstance(lat_arr, _zarr.Array)\n", + " ny, nx = lat_arr.shape\n", + " lat_1d = np.linspace(45.0, 45.0 + 1.0 * (ny - 1), ny)\n", + " lon_1d = np.linspace(10.0, 10.0 + 1.0 * (nx - 1), nx)\n", + " lat_arr[:] = np.repeat(lat_1d[:, None], nx, axis=1)\n", + " lon_arr = fixture_meas[\"longitude\"]\n", + " assert isinstance(lon_arr, _zarr.Array)\n", + " lon_arr[:] = np.repeat(lon_1d[None, :], ny, axis=0)\n", + "\n", + " return xr.open_datatree(store, engine=\"zarr\", mask_and_scale=False)\n", + "\n", + "\n", + "dt_input = open_olci_input()\n", + "print(\"Top-level groups:\", sorted(dt_input.groups))" + ] + }, + { + "cell_type": "markdown", + "id": "fd59eb10", + "metadata": {}, + "source": [ + "### Inspect the measurements group\n", + "\n", + "OLCI L1 EFR carries 21 radiance bands (`oa01_radiance` … `oa21_radiance`) on a\n", + "single full-resolution grid, geolocated by per-pixel 2-D `latitude` /\n", + "`longitude` coordinate arrays." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "3bab9194", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-28T06:42:32.917397Z", + "iopub.status.busy": "2026-07-28T06:42:32.917242Z", + "iopub.status.idle": "2026-07-28T06:42:32.921736Z", + "shell.execute_reply": "2026-07-28T06:42:32.921001Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "21 radiance bands; e.g. ['oa01_radiance', 'oa02_radiance', 'oa03_radiance'] … oa21_radiance\n", + "oa01_radiance: (4090, 4865) uint16 | dims ('rows', 'columns')\n", + "scale_factor: 0.013946459628641605 | _FillValue: 65535\n", + "geolocation coords: ['latitude', 'longitude', 'altitude']\n" + ] + } + ], + "source": [ + "meas = dt_input[\"/measurements\"].to_dataset()\n", + "bands = [v for v in meas.data_vars if str(v).endswith(\"_radiance\")]\n", + "print(f\"{len(bands)} radiance bands; e.g. {bands[:3]} … {bands[-1]}\")\n", + "oa = meas[\"oa01_radiance\"]\n", + "print(\"oa01_radiance:\", oa.shape, oa.dtype, \"| dims\", oa.dims)\n", + "print(\"scale_factor:\", oa.attrs.get(\"scale_factor\"), \"| _FillValue:\", oa.attrs.get(\"_FillValue\"))\n", + "print(\"geolocation coords:\", [c for c in (\"latitude\", \"longitude\", \"altitude\") if c in meas])" + ] + }, + { + "cell_type": "markdown", + "id": "90b511c0", + "metadata": {}, + "source": [ + "## 2. Detect the product type\n", + "\n", + "Detection is structural: a product is OLCI iff it validates against the OLCI\n", + "data model and its measurements group contains the radiance bands." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "35c20e40", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-28T06:42:32.923263Z", + "iopub.status.busy": "2026-07-28T06:42:32.923119Z", + "iopub.status.idle": "2026-07-28T06:42:33.001243Z", + "shell.execute_reply": "2026-07-28T06:42:33.000704Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "is_sentinel3_olci_dataset: True\n" + ] + } + ], + "source": [ + "group = get_zarr_group(dt_input)\n", + "print(\"is_sentinel3_olci_dataset:\", is_sentinel3_olci_dataset(group))" + ] + }, + { + "cell_type": "markdown", + "id": "f2497b10", + "metadata": {}, + "source": [ + "## 3. Convert to GeoZarr\n", + "\n", + "`convert_olci_optimized` first warps the swath onto a regular EPSG:4326 grid\n", + "using the per-pixel geolocation, then writes the `r0` base level plus `/2`\n", + "block-averaged overview siblings (`r2`, `r4`, …) down to `min_dimension`,\n", + "and declares them with the GeoZarr `multiscales` convention. `conditions`\n", + "and `quality` are copied through unchanged.\n", + "\n", + "We use a small `min_dimension` here so even the small sample yields several\n", + "overview levels to visualize." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "781d44e8", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-28T06:42:33.002683Z", + "iopub.status.busy": "2026-07-28T06:42:33.002577Z", + "iopub.status.idle": "2026-07-28T06:48:56.873720Z", + "shell.execute_reply": "2026-07-28T06:48:56.873157Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:42:46\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mReprojecting OLCI swath \u001b[0m \u001b[36mdst_shape\u001b[0m=\u001b[35m(4371, 6773)\u001b[0m \u001b[36msrc_shape\u001b[0m=\u001b[35m(4090, 4865)\u001b[0m \u001b[36mtarget_crs\u001b[0m=\u001b[35mEPSG:4326\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:08\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mDropping swath-bound variable with no grid home\u001b[0m \u001b[36mvariable\u001b[0m=\u001b[35mtime_stamp\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:09\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mWriting native-resolution measurements\u001b[0m \u001b[36mshape\u001b[0m=\u001b[35m{'y': 4371, 'x': 6773}\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:11\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mGenerating overview levels \u001b[0m \u001b[36mn_levels\u001b[0m=\u001b[35m10\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:31\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mWriting overview \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mmeasurements/r2\u001b[0m \u001b[36mshape\u001b[0m=\u001b[35m{'y': 2185, 'x': 3386}\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:36\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mWriting overview \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mmeasurements/r4\u001b[0m \u001b[36mshape\u001b[0m=\u001b[35m{'y': 1092, 'x': 1693}\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:37\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mWriting overview \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mmeasurements/r8\u001b[0m \u001b[36mshape\u001b[0m=\u001b[35m{'y': 546, 'x': 846}\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:38\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mWriting overview \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mmeasurements/r16\u001b[0m \u001b[36mshape\u001b[0m=\u001b[35m{'y': 273, 'x': 423}\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:38\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mWriting overview \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mmeasurements/r32\u001b[0m \u001b[36mshape\u001b[0m=\u001b[35m{'y': 136, 'x': 211}\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:38\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mWriting overview \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mmeasurements/r64\u001b[0m \u001b[36mshape\u001b[0m=\u001b[35m{'y': 68, 'x': 105}\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:38\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mWriting overview \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mmeasurements/r128\u001b[0m \u001b[36mshape\u001b[0m=\u001b[35m{'y': 34, 'x': 52}\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:39\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mWriting overview \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mmeasurements/r256\u001b[0m \u001b[36mshape\u001b[0m=\u001b[35m{'y': 17, 'x': 26}\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:39\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mWriting overview \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mmeasurements/r512\u001b[0m \u001b[36mshape\u001b[0m=\u001b[35m{'y': 8, 'x': 13}\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:39\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mWriting overview \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mmeasurements/r1024\u001b[0m \u001b[36mshape\u001b[0m=\u001b[35m{'y': 4, 'x': 6}\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:39\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mCopying ancillary group \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mconditions\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:39\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mCopying ancillary subgroup \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mconditions/geometry\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:40\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mCopying ancillary subgroup \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mconditions/image\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:43\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mCopying ancillary subgroup \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mconditions/instrument\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:43\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mCopying ancillary subgroup \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mconditions/meteorology\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:45\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mCopying ancillary subgroup \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mconditions/orphans\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:45\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mCopying ancillary group \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mquality\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:45\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mCopying ancillary subgroup \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mquality\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:54\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mCopying ancillary subgroup \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mquality/orphans\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:55\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mCopying measurements subgroup \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mmeasurements/orphans\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2m2026-07-28 08:48:55\u001b[0m [\u001b[32m\u001b[1minfo \u001b[0m] \u001b[1mCopying ancillary subgroup \u001b[0m \u001b[36mgroup\u001b[0m=\u001b[35mmeasurements/orphans\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Pyramid levels (native + overviews): ['r0', 'r2', 'r4', 'r8', 'r16', 'r32', 'r64', 'r128', 'r256', 'r512', 'r1024']\n", + "CRS: EPSG:4326\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_3687551/683526426.py:13: RuntimeWarning: Failed to open Zarr store with consolidated metadata, but successfully read with non-consolidated metadata. This is typically much slower for opening a dataset. To silence this warning, consider:\n", + "1. Consolidating metadata in this existing store with zarr.consolidate_metadata().\n", + "2. Explicitly setting consolidated=False, to avoid trying to read consolidate metadata, or\n", + "3. Explicitly setting consolidated=True, to raise an error in this case instead of falling back to try reading non-consolidated metadata.\n", + " \"CRS:\", xr.open_dataset(output_path, engine=\"zarr\", group=\"measurements/r0\").rio.crs\n" + ] + } + ], + "source": [ + "output_path = str(pathlib.Path(tempfile.mkdtemp()) / \"olci_geozarr.zarr\")\n", + "convert_olci_optimized(dt_input, output_path=output_path, min_dimension=4)\n", + "\n", + "store = zarr.open_group(output_path, mode=\"r\")\n", + "# Pyramid levels are the rN subgroups under measurements (exclude e.g. orphans):\n", + "# r0 is native resolution, r2/r4/… are the overviews.\n", + "levels = sorted(\n", + " (k for k in store[\"measurements\"].group_keys() if k.startswith(\"r\")),\n", + " key=lambda k: int(k[1:]),\n", + ")\n", + "print(\"Pyramid levels (native + overviews):\", levels)\n", + "print(\n", + " \"CRS:\", xr.open_dataset(output_path, engine=\"zarr\", group=\"measurements/r0\").rio.crs\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "1c5310cc", + "metadata": {}, + "source": [ + "### Load one band at every pyramid level\n", + "\n", + "Level `r0` is the native resolution; `r2`, `r4`, … are successively coarser\n", + "block-averaged overviews. We read with\n", + "default decoding so the stored `uint16` radiance is scaled to physical units\n", + "for display." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "3f654e2e", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-28T06:48:56.875690Z", + "iopub.status.busy": "2026-07-28T06:48:56.875581Z", + "iopub.status.idle": "2026-07-28T06:48:57.124716Z", + "shell.execute_reply": "2026-07-28T06:48:57.123792Z" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_3687551/3670716255.py:5: RuntimeWarning: Failed to open Zarr store with consolidated metadata, but successfully read with non-consolidated metadata. This is typically much slower for opening a dataset. To silence this warning, consider:\n", + "1. Consolidating metadata in this existing store with zarr.consolidate_metadata().\n", + "2. Explicitly setting consolidated=False, to avoid trying to read consolidate metadata, or\n", + "3. Explicitly setting consolidated=True, to raise an error in this case instead of falling back to try reading non-consolidated metadata.\n", + " ds = xr.open_dataset(output_path, engine=\"zarr\", group=f\"measurements/{level}\")\n", + "/tmp/ipykernel_3687551/3670716255.py:5: RuntimeWarning: Failed to open Zarr store with consolidated metadata, but successfully read with non-consolidated metadata. This is typically much slower for opening a dataset. To silence this warning, consider:\n", + "1. Consolidating metadata in this existing store with zarr.consolidate_metadata().\n", + "2. Explicitly setting consolidated=False, to avoid trying to read consolidate metadata, or\n", + "3. Explicitly setting consolidated=True, to raise an error in this case instead of falling back to try reading non-consolidated metadata.\n", + " ds = xr.open_dataset(output_path, engine=\"zarr\", group=f\"measurements/{level}\")\n", + "/tmp/ipykernel_3687551/3670716255.py:5: RuntimeWarning: Failed to open Zarr store with consolidated metadata, but successfully read with non-consolidated metadata. This is typically much slower for opening a dataset. To silence this warning, consider:\n", + "1. Consolidating metadata in this existing store with zarr.consolidate_metadata().\n", + "2. Explicitly setting consolidated=False, to avoid trying to read consolidate metadata, or\n", + "3. Explicitly setting consolidated=True, to raise an error in this case instead of falling back to try reading non-consolidated metadata.\n", + " ds = xr.open_dataset(output_path, engine=\"zarr\", group=f\"measurements/{level}\")\n", + "/tmp/ipykernel_3687551/3670716255.py:5: RuntimeWarning: Failed to open Zarr store with consolidated metadata, but successfully read with non-consolidated metadata. This is typically much slower for opening a dataset. To silence this warning, consider:\n", + "1. Consolidating metadata in this existing store with zarr.consolidate_metadata().\n", + "2. Explicitly setting consolidated=False, to avoid trying to read consolidate metadata, or\n", + "3. Explicitly setting consolidated=True, to raise an error in this case instead of falling back to try reading non-consolidated metadata.\n", + " ds = xr.open_dataset(output_path, engine=\"zarr\", group=f\"measurements/{level}\")\n", + "/tmp/ipykernel_3687551/3670716255.py:5: RuntimeWarning: Failed to open Zarr store with consolidated metadata, but successfully read with non-consolidated metadata. This is typically much slower for opening a dataset. To silence this warning, consider:\n", + "1. Consolidating metadata in this existing store with zarr.consolidate_metadata().\n", + "2. Explicitly setting consolidated=False, to avoid trying to read consolidate metadata, or\n", + "3. Explicitly setting consolidated=True, to raise an error in this case instead of falling back to try reading non-consolidated metadata.\n", + " ds = xr.open_dataset(output_path, engine=\"zarr\", group=f\"measurements/{level}\")\n", + "/tmp/ipykernel_3687551/3670716255.py:5: RuntimeWarning: Failed to open Zarr store with consolidated metadata, but successfully read with non-consolidated metadata. This is typically much slower for opening a dataset. To silence this warning, consider:\n", + "1. Consolidating metadata in this existing store with zarr.consolidate_metadata().\n", + "2. Explicitly setting consolidated=False, to avoid trying to read consolidate metadata, or\n", + "3. Explicitly setting consolidated=True, to raise an error in this case instead of falling back to try reading non-consolidated metadata.\n", + " ds = xr.open_dataset(output_path, engine=\"zarr\", group=f\"measurements/{level}\")\n", + "/tmp/ipykernel_3687551/3670716255.py:5: RuntimeWarning: Failed to open Zarr store with consolidated metadata, but successfully read with non-consolidated metadata. This is typically much slower for opening a dataset. To silence this warning, consider:\n", + "1. Consolidating metadata in this existing store with zarr.consolidate_metadata().\n", + "2. Explicitly setting consolidated=False, to avoid trying to read consolidate metadata, or\n", + "3. Explicitly setting consolidated=True, to raise an error in this case instead of falling back to try reading non-consolidated metadata.\n", + " ds = xr.open_dataset(output_path, engine=\"zarr\", group=f\"measurements/{level}\")\n", + "/tmp/ipykernel_3687551/3670716255.py:5: RuntimeWarning: Failed to open Zarr store with consolidated metadata, but successfully read with non-consolidated metadata. This is typically much slower for opening a dataset. To silence this warning, consider:\n", + "1. Consolidating metadata in this existing store with zarr.consolidate_metadata().\n", + "2. Explicitly setting consolidated=False, to avoid trying to read consolidate metadata, or\n", + "3. Explicitly setting consolidated=True, to raise an error in this case instead of falling back to try reading non-consolidated metadata.\n", + " ds = xr.open_dataset(output_path, engine=\"zarr\", group=f\"measurements/{level}\")\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_3687551/3670716255.py:5: RuntimeWarning: Failed to open Zarr store with consolidated metadata, but successfully read with non-consolidated metadata. This is typically much slower for opening a dataset. To silence this warning, consider:\n", + "1. Consolidating metadata in this existing store with zarr.consolidate_metadata().\n", + "2. Explicitly setting consolidated=False, to avoid trying to read consolidate metadata, or\n", + "3. Explicitly setting consolidated=True, to raise an error in this case instead of falling back to try reading non-consolidated metadata.\n", + " ds = xr.open_dataset(output_path, engine=\"zarr\", group=f\"measurements/{level}\")\n", + "/tmp/ipykernel_3687551/3670716255.py:5: RuntimeWarning: Failed to open Zarr store with consolidated metadata, but successfully read with non-consolidated metadata. This is typically much slower for opening a dataset. To silence this warning, consider:\n", + "1. Consolidating metadata in this existing store with zarr.consolidate_metadata().\n", + "2. Explicitly setting consolidated=False, to avoid trying to read consolidate metadata, or\n", + "3. Explicitly setting consolidated=True, to raise an error in this case instead of falling back to try reading non-consolidated metadata.\n", + " ds = xr.open_dataset(output_path, engine=\"zarr\", group=f\"measurements/{level}\")\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " r0: shape (4371, 6773)\n", + " r2: shape (2185, 3386)\n", + " r4: shape (1092, 1693)\n", + " r8: shape (546, 846)\n", + " r16: shape (273, 423)\n", + " r32: shape (136, 211)\n", + " r64: shape (68, 105)\n", + "r128: shape (34, 52)\n", + "r256: shape (17, 26)\n", + "r512: shape (8, 13)\n", + "r1024: shape (4, 6)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_3687551/3670716255.py:5: RuntimeWarning: Failed to open Zarr store with consolidated metadata, but successfully read with non-consolidated metadata. This is typically much slower for opening a dataset. To silence this warning, consider:\n", + "1. Consolidating metadata in this existing store with zarr.consolidate_metadata().\n", + "2. Explicitly setting consolidated=False, to avoid trying to read consolidate metadata, or\n", + "3. Explicitly setting consolidated=True, to raise an error in this case instead of falling back to try reading non-consolidated metadata.\n", + " ds = xr.open_dataset(output_path, engine=\"zarr\", group=f\"measurements/{level}\")\n" + ] + } + ], + "source": [ + "BAND = \"oa08_radiance\" # ~665 nm (red); good visual contrast\n", + "\n", + "\n", + "def read_level(level: str) -> xr.DataArray:\n", + " ds = xr.open_dataset(output_path, engine=\"zarr\", group=f\"measurements/{level}\")\n", + " return ds[BAND]\n", + "\n", + "\n", + "level_arrays = {lvl: read_level(lvl) for lvl in levels}\n", + "for lvl, arr in level_arrays.items():\n", + " print(f\"{lvl:>4}: shape {tuple(arr.shape)}\")" + ] + }, + { + "cell_type": "markdown", + "id": "95da72f9", + "metadata": {}, + "source": [ + "## 4. Multiscale quadrant visualization\n", + "\n", + "To show the pyramid in a single field of view, we split the native-resolution\n", + "image into four quadrants and fill each quadrant with data from a **different**\n", + "overview level. Each level's array is nearest-neighbour upsampled back to the\n", + "native quadrant size, so coarser levels render as visibly blockier — the\n", + "resolution drop is the point.\n", + "\n", + "Top-left = native, top-right = `r2`, bottom-left = `r4`, bottom-right = the\n", + "next coarser level available (clamped to the coarsest if fewer exist)." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "b40965eb", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-28T06:48:57.126653Z", + "iopub.status.busy": "2026-07-28T06:48:57.126456Z", + "iopub.status.idle": "2026-07-28T06:49:03.348857Z", + "shell.execute_reply": "2026-07-28T06:49:03.348179Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAqoAAAIrCAYAAAAnabsXAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlcelbwAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs/XmcZFV9/48/zzn33tq6q7une/YZQDZBFiUiLoiIEEDibpL54IrGSIwmxjU/o8EYkyAalWCMxg/40bigEQnGn4oR45IIAoIIKIogMCwDs/dWy13O+f7xPvdWNzNADzjDDHOej8cwTPWtW7duVXW97vu83q+3cs45AoFAIBAIBAKB3Qz9aB9AIBAIBAKBQCCwPYJQDQQCgUAgEAjslgShGggEAoFAIBDYLQlCNRAIBAKBQCCwWxKEaiAQCAQCgUBgtyQI1UAgEAgEAoHAbkkQqoFAIBAIBAKB3ZLo0T6AQCAQCAQCgT2BXq9Hmqa75LGSJKFer++Sx9qdCUI1EAgEAoFA4CHo9Xo8bt8h7l1f7JLHW7ZsGbfddtteL1aDUA0EAoFAIBB4CNI05d71BXdcsx/t4Z3rnJyatuz75NtJ0zQI1Uf7AAKBQCAQCAT2FIaGFUPDaqc+hmXn7n9PIgjVQCAQCAQCgT0Y5xyXXHIJ3/nOd5idneXII4/kta99LWNjY9U25513Hv/93/89734HHngg//iP/zjvtuuvv57zzz+f9evX86QnPYk3velNDA0N7ZLnsT2CUA0EAoFAIBBYIIWzFG7nP8aO8LKXvQytNSeccAJaa84//3w+/vGP85Of/IRFixYBcO2117J161b+4i/+orrfXCELcPnll/Oc5zyH17zmNfzu7/4u//Iv/8JFF13E5ZdfTpIkj/h5PRyUc24nn+5AIBAIBAKBPZupqSlGRkZY/6t9d4lHdcnj72BycpJ2u/2Q22/cuJGJiYnq35OTk4yNjfGlL32JP/zDPwTgjDPOIM9zPv/5zz/gfo477jiWLVvGV77yFQDWr1/P6tWr+cQnPsFrX/vaR/isHh4hRzUQCAQCgUBggVjcLvmzI8wVqQA333wzzjn233//ebdfe+21nH766bzxjW/k3//93+f9bHp6mh/96Ee89KUvrW5bsmQJxx9/PN/61rd28Cz99ghCNRAIBAKBQGA3ZGpqat6ffr//gNteeeWVvOhFL+KEE07ghS98IV/+8pc5+uijq5/Hccwzn/lMTjvtNFasWMGf/umf8gd/8AfVz2+//Xacc6xevXreflevXs1tt932239yCyR4VAOBQCAQCAQWiMWyYw7Sh/cYwDai8b3vfS9/8zd/s9377LPPPpxxxhls2LCBT3/605xzzjmcdNJJlUf1H//xHxkZGam2P/nkkznmmGO49NJLOfXUUysR3Gw25+13aGiIXq/323pqO0wQqoFAIBAIBAK7IXfeeec8j2qtVnvAbZcvX86LXvQiAF7xilew//7788///M+cddZZAPNEKsBTnvIUli9fzk9+8hNOPfXU6udbtmyZt92mTZu2abralYSl/0AgEAgEAoEFUji3S/4AtNvteX8eTKjOpdFosGrVKu68884H3MZay/T0NFEkNcv999+f4eFhfvazn83b7rrrruPII498mGfrkROEaiAQCAQCgcAeyvT09DaNUf/zP//Dz372M44//ngAOp0OX/ziF+dt8/73v59Op8Pzn/98AIwxnH766XzqU59iamoKgG9961v8/Oc/5xWveMUueCbbJyz9BwKBQCAQCOyh1Go1vvnNb/KXf/mXHHTQQWzevJlf/epXvOMd7+DlL385II1U3/nOd/irv/orDjroIO644w6mpqb4whe+wGGHHVbt65xzzuG0007j4IMP5qCDDuKaa67h7//+73n605/+aD29kKMaCAQCgUAg8FCUOap3/HLFLslR3feQexacowpw3333ccMNNzA8PMwhhxyyjSd17jbj4+MccsghNBqNbbZxznHNNdewYcMGjjzySFauXPmIn88jIQjVQCAQCAQCgYdgdxeqj1XC0n8gEAgEAoHAArE4ih0M5H84jxEQQjNVIBAIBAKBQGC3JFRUA4FAIBAIBBbIwxlx+nAeIyCEimogEAgEAoFAYLckVFQDgUAgEAgEFsjcQP6d+RgBIVRUA4FAIBAIBAK7JaGiGggEAoFAILBArP+zsx8jIISKaiAQCAQCgUBgtyRUVAOBQCAQCAQWSLELclR39v73JEJFNRAIBAKBQCCwWxIqqoFAIBAIBAILpHDyZ2c/RkAIFdVAIBAIBAKBwG5JqKgGAoFAIBAILJDQ9b9rCRXVQCAQCAQCgcBuSaioBgKBQCAQCCwQi6JA7fTHCAihohoIBAKBQCAQ2C0JFdVAIBAIBAKB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+0N9Bq+99lpuvvlmnvvc5zIyMrLdffd6PS655BIe97jH8dSnPnWHjvlHP/oRz3/+83n84x/Pvvvui7U2CNWdzJ133snpp5/OhRde+JBCbnZ2ltNPP52zzz77QYXqjuxzZ7M7HUvg4XH/aKntMTQ0xNDQ0CPeZlcRhOoexi9/+Uve+MY3cvnll/P0pz+ddrvNddddR6/X4/3vfz9//Md/PG/7v/zLv2RmZuYhReWtt97KW97yFi699FKOOuooVq5cyb333stVV13Fs5/9bD7wgQ9UZuqF7nNn8I53vIPzzjuP448/nm63yzXXXMNHPvIR/uRP/mTedr/85S959atfzU033cSxxx5Lmqb8z//8D6eccgr/7//9v0e1g3EhPP/5z+eQQw55tA9jr+Ev//IvufXWW7f7nj7wwAPnCdWFfgbLL/1zzz2XN7/5zdt93IsuuohXvvKVfPazn91hofre976XQw45hMsvv3yH7hd4+IyOjrJmzRr23XffR/tQAo8iBYqCndv1v7P3vycRhOoexM9//nOOPfZYDj/8cH7zm9+wfPlyAJxzfOQjH+HMM89k7dq1vP/979+h/f7iF7/gmc98JgcffDC//OUv2X///auf3X777bz+9a/nsssue1S7/gA+9rGP8eEPf5hvfetb1eSMj33sY/zpn/4pBx98MM95znOqbU8//XTuuusubrrppkpkXHXVVRx77LG85S1v4XOf+9yj8hwWysc+9rFH+xD2OpYuXcqXvvSlB91mRz6Dv/d7v8fy5cu54IILHlConn/++YyMjPAHf/AHO3y8N9100zz/WWDns2rVqod8jwQCgd8uQajuQbz61a8miiK+9rWvMT4+Xt2ulOJtb3sbv/71r/n7v/97XvCCF1Rj0xa6X2MM3/jGN+btF2C//fbjm9/8Jtdff/3DOmbnHD/72c+47bbbGB4e5qlPfSrDw8PztrnsssvYuHEjIGPgFi9ezFOe8pR5HhvnHB/84Ad59rOfPW+82xvf+EY++MEPcs4551RCNc9zrrvuOl760pfOq4Qdc8wxHHzwwfzkJz/Z4edx8cUXs88++3D00Udz++2387Of/YwDDjiAww8/fEHHX5JlGZdffjlTU1McffTRldC5P9vzqC70cbZ3rEuXLuWpT30qSm3/Kn3t2rXccMMNJEnC7/zO72zzPgC47bbbuPHGG1FKcfTRR2+zxPSLX/yC66+/nhNOOGEbu8j2WMh74+E8l4c6zkfCjn4GzzjjDM4++2yuuuoqjjnmmHn7uuWWW/jhD3/IG97wBhqNxoKP4Te/+Q1XXXUVW7du5Y477qiE0/Of/3xarRYgloIrr7ySTZs2sXLlSo4++uh5toS1a9dy+eWXc+qpp86zzqRpysUXX8xRRx1VNU9s3LiRyy67jGc961msWLGCn/zkJ9x2222cdNJJjI2NbXN8c7dfvnw5P/7xj1m/fj1HHnkkj3vc46rtNm/ezH/9139x9NFHc+CBB26zn0suuYTx8XGOO+64Bz2GVqvFxRdfXN2vVqux33778aQnPWnee+T+x1Wen6c+9anzVliuvPJK1q1bx1Oe8pRtLB8P5uHcvHkzV1xxBUmScNxxxz3wC7gDWGv56U9/ytq1axkZGeFpT3ta9Xkvz99TnvIUDjjggAc9fwvZ34NRflbXrl3L+Pg4Rx555Daf1b0J6zTW7dzQpJ29/z0KF9gjuPLKKx3g3vrWtz7gNr/61a8c4F772tdWtz3xiU90BxxwwEPu9+1vf/uCj+Wh9lny61//2h111FFudHTUnXLKKe7QQw91Q0ND7uMf//i87d7znve4NWvWuDVr1rgXvvCFbv/993ftdtt99atfrba56aabHODe9773bfM4L3/5y12SJC5N0+q2I444wh122GEuz/Pqtq1bt7p2u+1e9rKXLfi5loyMjLgzzzzTvetd73JPetKT3LHHHuv+5m/+ZsHH75xzN954o9t///3dxMSEe+5zn+sOPfRQd/7557tjjz3WHXvssfO23Xfffd3LX/7yHT5Pc4/1b//2b93v/M7vuJNPPtk1Gg33rGc9y3W73Xnbrl+/3j3/+c93tVrNPe1pT3Mnn3yyW7VqlfvABz5QbbNhwwb3vOc9zzUaDXf88ce7448/3tXrdfeOd7zDWWur7d7//vc7wH3nO995yPO50PfGjjyXhR7n9ljIe/rhfAZvvfVWp5Ryr3/967fZ9i//8i8d4H76058+6OPen//+7/92a9ascXEcu/333796T6xfv94559xFF13kJiYm3H777eee+9znuiVLlrgDDjjAXXXVVdU+Lrzwwu0+9oYNGxzgPvShD1W3/c///I8D3Oc//3l38sknu2c961nugAMOcFdfffV2j2/u9s95znPcCSec4I455hintXZvfetbq9ciTVO3dOlS98IXvnCbfVx77bUOcOeee+5DHsPU1FR1DtasWeNOPvlkNzo66g499FB32223bXNcX/jCF9zJJ5/sTjzxRHf44Ye7drvtfvCDH7jNmze7E0880T3nOc9xRx55pKvVau6iiy6ad1w33HCDA9yFF1447/bPfOYzrtlsuoMPPtideuqp7ogjjqge7+yzz37Q1/OB9nnFFVe4gw46yC1dutSddtpp7vDDD3fj4+Pukksucc451+v13KJFi9wf/MEfbLPPG2+8cd75W8j+HuhY7rjjDnfYYYe5ZcuWuec973nu+OOPd6tXr3b/8i//8qDP67HI5OSkfA9deZI75+en7tQ/77vyJAe4ycnJR/tpP+oEobqHcO655zpgm1+c92d8fNwdeuih1b8f6gt4ofudy0K+1NM0dQcffLA7+OCD3d13313d/q53vcsB7utf//oD3tda6972tre5drtdffl+/etfd4D7f//v/22z/V/91V85wN1yyy3Vbddff7074ogj3EknneT+9V//1X3sYx9zT3ziE90JJ5zg1q1bt+DnWjIyMuL233//eV/gcx/voY6/3++7Aw44wD3xiU90GzdudM45VxSFe/3rX+9WrVq1IKG6kMcpj/Wggw5y//RP/1TdVn5pfuxjH5t3/6c+9alu5cqV7oYbbqhu7/V67ktf+lK1zTOe8Qy3evVq9+tf/7ra5oc//KGLosj98z//c3XbxRdf7NasWTNvX9tjR94bO/JcFnqc2+OJT3yiW7p0qbvwwgvn/Zkruh/uZ/A5z3mOa7fbbnZ2trotyzK3fPly9+QnP/lB9/VgjIyMuD/6oz+ad9tPf/pTF8exe8UrXuGyLHPOyZfrscce6yYmJqr33sMRqkcccUQlTjudjrvnnnu2e1xzt7/mmmuq2z/72c86wH3yk5+sbnv3u9/tjDFu7dq18/bxute9ziVJUh3vjh7D1NSUe/KTn+xOOumkbY7rqKOOqt6jRVG4U0891R100EHuta99rfvZz37mnJP30/Oe9zy3atWqeRfA2xNy11xzjTPGuD/90z+tRPi9997rTjvttIctVG+77TbXbrfdC1/4wnnvm3e/+92uVqu5X/7yl8455/78z//cJUniNmzYMG+fb3nLW+adv4Xub3vH8opXvMIdcMABrtPpzDu///7v//6gz+ux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csopp/DLX/6S++67b17DySN9nB1hZGSEiy66iBe/+MUcc8wxnH766bTbbS6//HImJyf52te+xsjICJdccgkvfvGLefKTn8z/+T//hyVLlnDbbbfx7W9/myc/+cnVl9/FF1/MX//1X/Od73znQXNUF/re2NHnstDjfCQ83M8gyBLta1/7WgA++tGPPuBjvOc97+G66657WM0qp59+OpdeeilveMMbuOGGGzj88MP5/ve/zxe/+EXOOeecyoc5MTHBG9/4Rj760Y+ilGL//ffnG9/4Bs9//vPnNeY8EtasWcMpp5zC7//+79PpdDjvvPM46KCDtjuQ5IwzzuDd734311xzDSeddNIOXUi++c1v5stf/jKnnXYaL3vZy7jzzjv5z//8T970pjdx9tln/1aey4Pxspe9jIsvvphXvepVXHPNNRxwwAF84xvf4DnPec7DPpennHIK55xzDm9+85v5/ve/z/HHH08cx/zyl7/ka1/7Gh/+8Id58YtfXG3/ute9js985jOcc845nHTSSdtMztrR/c3lT/7kT7DWcvzxx7N69WrWrl3Leeedx2mnncYTn/jEh/X8AoEdIQjVPYw3velNvPSlL+WrX/0qN9xwQzVn/NJLL91uyPSpp57K7bffvk11EaR7+QUveAEAr3nNa3jRi17EJZdcwjXXXMMvfvELli1bxutf//qqWjV3n3OrFw/Ey1/+co4++mi++MUvcvnllzM8PMy//du/8eIXv7gSio1GgyuvvJJPfepTXH/99YyPj3P++eezdOlS/vd//3deZ/34+DhXX301n/nMZ/jJT35CFEV89KMfZc2aNdsIzz//8z/nec97Hl/+8pe59tprieOYV77ylbzyla98WONTX/rSl263OWJHjv91r3sdRx55JF/84hf58Y9/zNOf/nQ++MEP8nd/93fb7Pf+I1R35HEe6FiPO+64bYLBTzjhBH7961/z+c9/nhtuuIFWq8Wpp546r+r1zGc+k1tuuYUvfelL/PSnP62W5z/xiU/ME9mHHXYYa9asWVDA/kLeGzv6XBZ6nNtjoe9p2PHPYMmaNWv4zne+g3OOV77ylQ+43dq1a3nWs571kMfx0pe+dJshAiBV+pe//OV885vf5Ic//CGrV6/mJz/5CU9+8pPnbfehD32IJz3pSXzve9+j0+nwnve8h0MPPZTvfve78957ixcv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sGABN998M7Nnzx6TMc3EU089xbe+9S02bdrEUUcdxQ033MBxxx3XMCYMQ77yla/ws5/9jHw+z1VXXcXFF188JmOaiTAM+fa3v81DDz1EtVpl2bJl3HDDDYwfP75h3KOPPso999xDV1cXJ510En/1V39FS0vLmIxpRnbv3s1NN93EpEmT+NrXvtbwWE9PD3fddRdPP/0006ZN413vehdLly4dkzHNxHXXXcf+/fsbll1xxRVce+21Dcvuv/9+vv/97xMEARdffDHXXHMNSqkxGdNMRFHEfffdx4MPPojv+7z97W/n3HPPbRizbt06/vEf/5Ft27Zx3HHH8dd//ddMnTp1TMYIwpFApv4PQV9fH6eeeiq/+tWvWL16NX19fZx88sk8/fTTR3rXRpX77ruPFStWUKvV+PGPf8zWrVuHjNm6dSsnnXQSmzZt4o1vfCNr167l5JNPZteuXaM+ppn4yle+wvXXX8+ECRO4/PLLKRQKLFmyhJ/+9KcN497+9rfzqU99ivPPP5+FCxdy6aWX8pWvfGVMxjQTl112GQ899BBnn3025513Ht/5zndYvnx53I8b4Cc/+QlnnHEG48aNY+XKlXzrW9/iggsuIAzDUR/TjERRxNvf/naeeeYZHnrooYbHSqUSZ5xxBj/+8Y9ZvXo1QRCwfPlyHn/88VEf02z89Kc/ZeHChdx0003xz/LlyxvGfPKTn+S6665j2bJlnHHGGfzN3/wN733ve8dkTDMRhiGrM1LI8AAAHMdJREFUV6/mIx/5CMuXL+eiiy7izjvvbPjcee655zjppJPo7OzkjW98I4899hjLly+nu7t71McICbQ+PD+CQQsH5ZOf/KSePHmyLhQK8bKzzz5bX3rppUdup8aA3bt361qtprXWOpvN6q985StDxrzzne/US5Ys0WEYaq21rlaresGCBfqv//qvR31MM7Fnz54hyy677DJ97rnnxn8/9thjGtC/+c1v4mV///d/rydOnKgrlcqojmk2Ojs7G/7euXOnBvQPfvCDeNnSpUv1O97xjvjvbdu2ad/39be+9a1RH9OM3HHHHXrVqlX6tttu00cffXTDY3fffbdua2vTvb298bKVK1fq888/f9THNBuzZs3SX//61w/4eFdXl85ms/rLX/5yvOx73/ue9jxPb9iwYVTHNBt33XWXbm1t1Vu2bGlY3tPTE///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YSzufvrTnx624pnnn3+eL3zhC/HUsueZj6bhIpkAl156KZs2bYqn9VtbW8nn87FIq1QqcdTScajzdiBWrlzJ5MmT+chHPoLWGq01H/rQh5gyZUpcrHXfffc1nCtX5NXS0nLQx2bPnt0QUXVR5+nTp4/I43by5Mns3bs3dhHYuHFjnIPsWL16NdOnT+fd7353HC3dsGED3/nOd4as78477+T666/n/PPP5+mnn46XB0HAz372M970pjcdcp8EQRBGExGqgvAy5O677+b0009n8eLFLFiwgNmzZzfkHH7uc59j+vTpzJo1i3nz5nH55Zfz2c9+ljPOOOOA6/zgBz9IKpVi9uzZzJs3j4997GOcddZZh+NwmDVrFuvWrWPKlCkce+yxzJgxgzlz5vA3f/M3w46fO3cuq1evji2a0uk0X/ziF3nf+97HMcccw9SpU0mlUnGE0nGo8zYc+Xyeb3/72/znf/4n06ZNY+rUqfzoRz/iO9/5Dvl8HjDT+5/61KeYMGECxx13HGeccQa33347r3/96w/62IF4//vfz/ve9z5OOOGEIc4FSVauXMnq1atZvHgxCxcu5HWvex1nn332kP1/4IEHeP7555k8eTLz589n5cqVzJ8/f9h1fuYzn+G6667jvPPOi8Xqj370I/L5/JD8XkF4NSKG/4cXqfoXhJcxvb297N69m/nz55NOp4c8vmfPHrq6upg7d24sqhxbtmzB8zzmzJkTL9Nas23bNvL5PFOmTImjeq4Sf9OmTWQyGWbNmhU/Z8OGDbS0tDBjxox42bp162hvb2fatGkHfN7OnTspl8sNgqlarbJ582amTJly0GlqMHZaZ555JmvXrmXixImAySfdunUr06ZNY+LEiTzzzDPMnj2b8ePHj+i8DbefyXOzYcMGlFLMnz+/wRrL0dPTw759+5gzZw65XG7Ejw1Hb28v27dvRynF4sWLefLJJznmmGOGzTd1r/P8+fMJgoB169Zx4oknDtnHHTt2UKvVmDt3bsPy4db99NNP09bWxrx58zjllFP4wAc+wJVXXnnI/RaEVyqu6v/8Ez54WKr+H3rmMyOu+v/nf/5n/vu//7th2YIFCxocTgDWrl3L17/+dfbu3cuyZct417veNeS7odkQoSoIwsuWdevWMXXq1CGRU2H0qNVqPPvss3HuryC8WomF6vF/e3iE6prPjlio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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def to_native_grid(arr: xr.DataArray, ny: int, nx: int) -> np.ndarray:\n", + " \"\"\"Nearest-neighbour upsample a (rows, columns) array to (ny, nx).\"\"\"\n", + " a = np.asarray(arr.values, dtype=float)\n", + " row_idx = (np.arange(ny) * a.shape[0] // ny).clip(0, a.shape[0] - 1)\n", + " col_idx = (np.arange(nx) * a.shape[1] // nx).clip(0, a.shape[1] - 1)\n", + " return a[np.ix_(row_idx, col_idx)]\n", + "\n", + "\n", + "native = level_arrays[\"r0\"]\n", + "ny, nx = native.shape\n", + "hy, hx = ny // 2, nx // 2\n", + "\n", + "# Choose four levels (native + up to three coarser), clamped to what exists.\n", + "chosen = [levels[min(i, len(levels) - 1)] for i in range(4)]\n", + "\n", + "# Build a single canvas: each quadrant upsampled from its chosen level.\n", + "canvas = np.empty((ny, nx), dtype=float)\n", + "quadrants = {\n", + " (slice(0, hy), slice(0, hx)): chosen[0], # top-left\n", + " (slice(0, hy), slice(hx, nx)): chosen[1], # top-right\n", + " (slice(hy, ny), slice(0, hx)): chosen[2], # bottom-left\n", + " (slice(hy, ny), slice(hx, nx)): chosen[3], # bottom-right\n", + "}\n", + "for (rsl, csl), lvl in quadrants.items():\n", + " full = to_native_grid(level_arrays[lvl], ny, nx)\n", + " canvas[rsl, csl] = full[rsl, csl]\n", + "\n", + "fig, ax = plt.subplots(figsize=(7, 7))\n", + "im = ax.imshow(canvas, cmap=\"viridis\")\n", + "ax.axhline(hy - 0.5, color=\"white\", lw=1)\n", + "ax.axvline(hx - 0.5, color=\"white\", lw=1)\n", + "labels = {\n", + " (hx / 2, hy / 2): chosen[0],\n", + " (hx + hx / 2, hy / 2): chosen[1],\n", + " (hx / 2, hy + hy / 2): chosen[2],\n", + " (hx + hx / 2, hy + hy / 2): chosen[3],\n", + "}\n", + "for (x, y), lvl in labels.items():\n", + " res = 1 if lvl == \".\" else int(lvl[1:])\n", + " name = \"native (r1)\" if lvl == \".\" else lvl\n", + " ax.text(\n", + " x, y, f\"{name}\\n1/{res} res\", color=\"white\", ha=\"center\", va=\"center\",\n", + " fontweight=\"bold\", bbox={\"facecolor\": \"black\", \"alpha\": 0.4, \"pad\": 3},\n", + " )\n", + "ax.set_title(f\"OLCI {BAND}: one FOV, four pyramid levels\")\n", + "ax.set_xlabel(\"columns (across-track)\")\n", + "ax.set_ylabel(\"rows (along-track)\")\n", + "fig.colorbar(im, ax=ax, shrink=0.8, label=\"radiance (scaled)\")\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "b4beef58", + "metadata": {}, + "source": [ + "Each quadrant covers the same ground area but is drawn from a coarser level as\n", + "you move down/right — the blockier quadrants are the lower-resolution overviews\n", + "from the multiscale pyramid, all produced by the single conversion above." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pyproject.toml b/pyproject.toml index bd22dce3..57598ca1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "eopf-geozarr" -version = "0.10.1" +version = "0.10.2" description = "GeoZarr compliant data model for EOPF datasets" readme = "README.md" license = { text = "Apache-2.0" } @@ -29,7 +29,9 @@ requires-python = ">=3.12" dependencies = [ "pydantic-zarr>=0.8.0", "pydantic>=2.12", - "zarr[cast-value-rs]>=3.2.0", + # <3.3.0: open_source_datatree uses zarr's experimental CacheStore, whose + # location/API may change between minor releases; bump deliberately. + "zarr[cast-value-rs]>=3.2.0,<3.3.0", "xarray>=2025.7.1", "dask[array,distributed]>=2026.1.0", "numpy>=2.3.1", @@ -71,6 +73,12 @@ docs = [ "pymdown-extensions>=10.0", "mike>=2.1.3", ] +notebooks = [ + "cartopy>=0.23", + "jupyter>=1.0.0", + "matplotlib>=3.8.0", + "nbformat>=5.9.0", +] [project.urls] Homepage = "https://github.com/developmentseed/eopf-geozarr" @@ -204,7 +212,8 @@ constraint-dependencies = [ "urllib3>=2.7.0", "requests>=2.33.0", "cryptography>=46.0.6", - "tornado>=6.5.5", + "tornado>=6.5.7", + "msgpack>=1.2.1", "filelock>=3.20.3", "virtualenv>=20.36.1", "black>=26.3.1", diff --git a/src/eopf_geozarr/cli.py b/src/eopf_geozarr/cli.py index 805c9237..f6f42ee0 100755 --- a/src/eopf_geozarr/cli.py +++ b/src/eopf_geozarr/cli.py @@ -15,6 +15,10 @@ import xarray as xr from eopf_geozarr.s2_optimization.s2_converter import convert_s2_optimized, is_sentinel2_dataset +from eopf_geozarr.s3_olci_optimization.olci_converter import ( + convert_olci_optimized, + is_sentinel3_olci_dataset, +) from . import create_geozarr_dataset from .conversion.fs_utils import ( @@ -24,12 +28,17 @@ validate_s3_access, ) from .conversion.geozarr import get_zarr_group +from .conversion.open_source import open_source_datatree if TYPE_CHECKING: from dask.distributed import Client log = structlog.get_logger() +# Default for convert's --spatial-chunk; shared between the parser definition +# and the OLCI auto-detect path's ignored-options check. +CONVERT_SPATIAL_CHUNK_DEFAULT = 4096 + # Suppress xarray FutureWarning about timedelta decoding warnings.filterwarnings("ignore", message=".*", category=FutureWarning) @@ -100,6 +109,24 @@ def _is_sentinel2_input(dt: xr.DataTree) -> bool: return False +def _is_sentinel3_olci_input(dt: xr.DataTree) -> bool: + """Best-effort Sentinel-3 OLCI detection that never breaks the generic path. + + ``is_sentinel3_olci_dataset`` validates structurally against a Zarr v2 model + and can raise on unrelated inputs; any failure simply means "not a recognised + OLCI product", so fall back to the generic converter. + + Detection is intentionally conservative (strict structural validation), so + near-miss OLCI products fall through to the generic path; the explicit + ``convert-s3-olci-optimized`` subcommand bypasses detection entirely. + """ + try: + return is_sentinel3_olci_dataset(get_zarr_group(dt)) + except Exception as exc: + log.debug("Sentinel-3 OLCI detection skipped", error=str(exc)) + return False + + def convert_command(args: argparse.Namespace) -> None: """ Convert EOPF dataset to GeoZarr compliant format. @@ -184,14 +211,14 @@ def convert_command(args: argparse.Namespace) -> None: # Convert to GeoZarr compliant format log.info("Converting to GeoZarr compliant format...") - if _is_sentinel2_input(dt): + if _is_sentinel2_input(dt) and not getattr(args, "no_s2_optimized", False): # Sentinel-2 inputs use the optimized flat multiscale layout # (sibling r{N}m levels), shared with `convert-s2-optimized`. The # generic per-group options below do not apply to that layout. log.info( "Detected Sentinel-2 input; using optimized flat multiscale layout " "(per-group options such as --groups/--crs-groups/--gcp-group/--min-dimension " - "do not apply)" + "do not apply; pass --no-s2-optimized to force the generic path)" ) dt_geozarr = convert_s2_optimized( dt_input=dt, @@ -203,6 +230,51 @@ def convert_command(args: argparse.Namespace) -> None: keep_scale_offset=False, max_retries=args.max_retries, ) + # Opt-out flag first: skip the structural OLCI detection (a full + # model validation of the store) when the user already declined it. + elif not getattr(args, "no_s3_olci_optimized", False) and _is_sentinel3_olci_input(dt): + log.info( + "Detected Sentinel-3 OLCI product; using OLCI converter " + "(pass --no-s3-olci-optimized to force the generic path)" + ) + # convert_olci_optimized requires raw (non-mask-scaled) input: + # radiance must stay packed uint16 with CF scale_factor/add_offset + # and _FillValue in .attrs (see _clear_encoding / reduce_swath). + # The tree above was opened with CF decoding on for detection and + # the generic path, so close it and re-open raw, matching + # convert_s3_olci_optimized_command. + dt.close() + dt_raw = open_source_datatree( + str(input_path), + storage_options=storage_options, + mask_and_scale=False, + ) + # Only forward options the OLCI converter actually applies; + # enable_sharding / spatial_chunk are accepted by + # convert_olci_optimized but not yet wired into the encoding + # (forwarding them would trigger its ignored-options warning on + # every run, since convert's defaults differ). Re-add them here + # once the converter wires them through — and don't drop a user's + # explicit setting silently in the meantime. + ignored_cli_options = [ + name + for name, is_non_default in ( + ("--spatial-chunk", args.spatial_chunk != CONVERT_SPATIAL_CHUNK_DEFAULT), + ("--enable-sharding", args.enable_sharding), + ) + if is_non_default + ] + if ignored_cli_options: + log.warning( + "Options not yet applied by the OLCI converter and " + "ignored on the auto-detect path", + ignored_options=ignored_cli_options, + ) + dt_geozarr = convert_olci_optimized( + dt_raw, + output_path=output_path, + min_dimension=args.min_dimension, + ) else: dt_geozarr = create_geozarr_dataset( dt_input=dt, @@ -1074,7 +1146,22 @@ def create_parser() -> argparse.ArgumentParser: # Convert command convert_parser = subparsers.add_parser( - "convert", help="Convert EOPF dataset to GeoZarr compliant format" + "convert", + help="Convert EOPF dataset to GeoZarr compliant format", + description=( + "Convert EOPF dataset to GeoZarr compliant format. Sentinel-2 inputs are " + "auto-detected and converted with the optimized flat multiscale layout " + "(equivalent to convert-s2-optimized with keep_scale_offset disabled); for " + "those inputs the per-group options --groups, --crs-groups, --gcp-group and " + "--min-dimension do not apply. Sentinel-3 OLCI inputs are likewise " + "auto-detected and converted with the OLCI swath converter (equivalent to " + "convert-s3-olci-optimized), which honors --min-dimension but not the " + "per-group options; OLCI detection is intentionally strict, so near-miss " + "products fall back to the generic path — use convert-s3-olci-optimized " + "to convert them explicitly. Pass --no-s2-optimized / " + "--no-s3-olci-optimized to force the generic conversion path, which " + "honors all options." + ), ) convert_parser.add_argument( "input_path", type=str, help="Path to input EOPF dataset (Zarr format)" @@ -1089,19 +1176,22 @@ def create_parser() -> argparse.ArgumentParser: type=str, nargs="+", default=["/measurements/r10m", "/measurements/r20m", "/measurements/r60m"], - help="Groups to convert (default: Sentinel-2 resolution groups)", + help="Groups to convert (ignored for auto-detected Sentinel-2 inputs)", ) convert_parser.add_argument( "--spatial-chunk", type=int, - default=4096, + default=CONVERT_SPATIAL_CHUNK_DEFAULT, help="Spatial chunk size for encoding (default: 4096)", ) convert_parser.add_argument( "--min-dimension", type=int, default=256, - help="Minimum dimension for overview levels (default: 256)", + help=( + "Minimum dimension for overview levels (default: 256; ignored for " + "auto-detected Sentinel-2 inputs)" + ), ) convert_parser.add_argument( "--max-retries", @@ -1113,12 +1203,19 @@ def create_parser() -> argparse.ArgumentParser: "--crs-groups", type=str, nargs="*", - help="Groups that need CRS information added on best-effort basis (e.g., /conditions/geometry)", + help=( + "Groups that need CRS information added on best-effort basis " + "(e.g., /conditions/geometry; ignored for auto-detected Sentinel-2 inputs)" + ), ) convert_parser.add_argument( "--gcp-group", type=str, - help="Groups where Ground Control Points (GCPs) are located (e.g., /conditions/gcp) (Sentinel-1)", + help=( + "Groups where Ground Control Points (GCPs) are located " + "(e.g., /conditions/gcp) (Sentinel-1; ignored for auto-detected " + "Sentinel-2 inputs)" + ), ) convert_parser.add_argument("--verbose", action="store_true", help="Enable verbose output") convert_parser.add_argument( @@ -1131,6 +1228,22 @@ def create_parser() -> argparse.ArgumentParser: action="store_true", help="Enable zarr sharding for spatial dimensions of each variable", ) + convert_parser.add_argument( + "--no-s2-optimized", + action="store_true", + help=( + "Disable Sentinel-2 auto-detection and use the generic conversion path, " + "honoring --groups/--crs-groups/--gcp-group/--min-dimension" + ), + ) + convert_parser.add_argument( + "--no-s3-olci-optimized", + action="store_true", + help=( + "Disable Sentinel-3 OLCI auto-detection and use the generic conversion " + "path, honoring --groups/--crs-groups/--gcp-group" + ), + ) convert_parser.set_defaults(func=convert_command) # Info command @@ -1154,6 +1267,7 @@ def create_parser() -> argparse.ArgumentParser: # Add S2 optimization commands add_s2_optimization_commands(subparsers) + add_s3_olci_optimization_commands(subparsers) return parser @@ -1216,10 +1330,7 @@ def convert_s2_optimized_command(args: argparse.Namespace) -> None: try: # Load input dataset log.info("Loading Sentinel-2 dataset from", input_path=args.input_path) - storage_options = get_storage_options(str(args.input_path)) - dt_input = xr.open_datatree( - str(args.input_path), engine="zarr", chunks="auto", storage_options=storage_options - ) + dt_input = open_source_datatree(str(args.input_path)) # Convert convert_s2_optimized( @@ -1247,6 +1358,72 @@ def convert_s2_optimized_command(args: argparse.Namespace) -> None: log.warning("Error closing dask cluster", error=str(e)) +def add_s3_olci_optimization_commands(subparsers: argparse._SubParsersAction) -> None: + """Add S3 OLCI optimization commands to CLI parser.""" + p = subparsers.add_parser( + "convert-s3-olci-optimized", + help="Convert a Sentinel-3 OLCI L1 EFR dataset to optimized GeoZarr", + ) + p.add_argument("input_path", type=str, help="Path to input OLCI dataset (Zarr)") + p.add_argument("output_path", type=str, help="Path for output optimized dataset") + p.add_argument( + "--spatial-chunk", + type=int, + default=1024, + help="Spatial chunk size (not yet applied; reserved for a follow-up)", + ) + p.add_argument( + "--enable-sharding", + action="store_true", + help="Enable Zarr v3 sharding (not yet applied; reserved for a follow-up)", + ) + p.add_argument( + "--compression-level", + type=int, + default=3, + choices=range(1, 10), + help="Compression level 1-9 (default: 3; not yet applied; reserved for a follow-up)", + ) + p.add_argument( + "--min-dimension", + type=int, + default=256, + help="Minimum overview dimension (default: 256)", + ) + p.add_argument( + "--keep-scale-offset", + action="store_true", + help=( + "Preserve scale-offset encoding instead of decoding to float " + "(not yet applied; output is currently always raw integer)" + ), + ) + p.add_argument( + "--target-crs", + type=str, + default="EPSG:4326", + help="Target CRS for the reprojected output grid (default: EPSG:4326)", + ) + p.add_argument("--verbose", action="store_true", help="Enable verbose output") + p.set_defaults(func=convert_s3_olci_optimized_command) + + +def convert_s3_olci_optimized_command(args: argparse.Namespace) -> None: + """Execute S3 OLCI optimized conversion command.""" + dt_input = open_source_datatree(str(args.input_path), mask_and_scale=False) + convert_olci_optimized( + dt_input, + output_path=args.output_path, + enable_sharding=args.enable_sharding, + spatial_chunk=args.spatial_chunk, + compression_level=args.compression_level, + min_dimension=args.min_dimension, + keep_scale_offset=args.keep_scale_offset, + target_crs=args.target_crs, + ) + log.info("S3 OLCI optimization completed", output_path=args.output_path) + + def main() -> None: """Execute main entry point for the CLI.""" parser = create_parser() diff --git a/src/eopf_geozarr/conversion/__init__.py b/src/eopf_geozarr/conversion/__init__.py index 1a0e448a..1a292070 100644 --- a/src/eopf_geozarr/conversion/__init__.py +++ b/src/eopf_geozarr/conversion/__init__.py @@ -17,6 +17,7 @@ iterative_copy, setup_datatree_metadata_geozarr_spec_compliant, ) +from .open_source import open_source_datatree from .utils import ( calculate_aligned_chunk_size, downsample_2d_array, @@ -36,6 +37,7 @@ "is_s3_path", "iterative_copy", "open_s3_zarr_group", + "open_source_datatree", "parse_s3_path", "s3_path_exists", "setup_datatree_metadata_geozarr_spec_compliant", diff --git a/src/eopf_geozarr/conversion/geozarr.py b/src/eopf_geozarr/conversion/geozarr.py index 8f9c68f4..3d7a6bdc 100644 --- a/src/eopf_geozarr/conversion/geozarr.py +++ b/src/eopf_geozarr/conversion/geozarr.py @@ -507,14 +507,11 @@ def write_geozarr_group( if not success: raise RuntimeError(f"Failed to write all bands for {group_name}") - # Create GeoZarr-spec compliant multiscales - if _is_sentinel1(dt_input): - assert gcp_group is not None, "GCP group required for processing Sentinel-1" - ds_gcp: xr.Dataset | None = dt_input[gcp_group].to_dataset() - # For Sentinel-1, ds_gcp is set to None since data is now reprojected and doesn't need GCP handling - ds_gcp = None - else: - ds_gcp = None + # Create GeoZarr-spec compliant multiscales. GCPs are not needed here: + # Sentinel-1 data was already reprojected upstream (see + # setup_datatree_metadata_geozarr_spec_compliant), so multiscales are + # created without GCP handling. + ds_gcp: xr.Dataset | None = None try: log.info("Creating GeoZarr-spec compliant multiscales", group_name=group_name) @@ -528,7 +525,10 @@ def write_geozarr_group( enable_sharding=enable_sharding, ) except Exception as e: - log.warning( + # Deliberately continue with the remaining groups, but surface the + # failure loudly (with traceback): the output store is missing its + # multiscales metadata for this group. + log.exception( "Failed to create GeoZarr-spec compliant multiscales", group_name=group_name, error=str(e), diff --git a/src/eopf_geozarr/conversion/open_source.py b/src/eopf_geozarr/conversion/open_source.py new file mode 100644 index 00000000..d43d9530 --- /dev/null +++ b/src/eopf_geozarr/conversion/open_source.py @@ -0,0 +1,101 @@ +"""Open source EOPF zarr stores with dask chunks aligned to native chunks. + +With ``chunks="auto"``, dask may split one on-disk zarr chunk into several +read tasks that each fetch and decompress the same object key — multiplying +egress and racing on shared cache files (EOPF-Explorer/data-pipeline#339). +``open_source_datatree`` opens with ``chunks={}`` (the store's native chunk +grid), so each zarr chunk is read by exactly one dask task; downstream +conversion code rechunks to its own output encoding anyway. Note that one +task then materializes one whole native chunk (~241 MB raw for cpm_v270 +aot/wvp) — under tight memory budgets, lower dask task concurrency rather +than sub-splitting stored chunks. +""" + +import hashlib +from pathlib import Path +from typing import Any + +import xarray as xr + +from .fs_utils import S3FsOptions, get_storage_options + + +def open_source_datatree( + path: str, + *, + storage_options: S3FsOptions | dict[str, Any] | None = None, + cache_dir: str | None = None, + engine: str = "zarr", + mask_and_scale: bool = True, +) -> xr.DataTree: + """Open a source datatree with dask chunks matching the native zarr chunks. + + Parameters + ---------- + path : str + Source store URL (local path, s3://, or https://). + storage_options : dict, optional + fsspec storage options. Defaults to ``get_storage_options(path)`` + (S3 credentials/endpoint for s3:// paths, None otherwise). + cache_dir : str, optional + Local directory for an on-disk read cache of source objects, backed + by zarr's ``CacheStore`` over a ``LocalStore``. LocalStore writes are + atomic (temp file + rename), so a concurrent read never sees a + partially downloaded object. Entries are namespaced per source URL + (CacheStore keys entries by relative zarr key, so different sources + sharing a directory would otherwise collide) and never expire; use an + ephemeral directory. + engine : str + xarray backend engine, default ``"zarr"``. + mask_and_scale : bool + Forwarded to ``xr.open_datatree``. Pass ``False`` to keep variables + packed (e.g. uint16 with CF scale_factor/add_offset in ``.attrs``) + instead of CF-decoding to floats, as the OLCI converter requires. + + Returns + ------- + xr.DataTree + Datatree whose dask arrays are chunked exactly on the store's native + chunk grid: each on-disk zarr chunk is read by exactly one dask task. + """ + if storage_options is None: + storage_options = get_storage_options(path) + if cache_dir is None: + return xr.open_datatree( + path, + engine=engine, + chunks={}, + storage_options=storage_options, + mask_and_scale=mask_and_scale, + ) + # Imported lazily: CacheStore is zarr's experimental API, so a relocation + # in a future zarr release must not break importing this package. + try: + from zarr.experimental.cache_store import CacheStore + except ImportError as exc: + raise ImportError( + "cache_dir requires zarr.experimental.cache_store.CacheStore " + "(present in zarr 3.2.x). Your zarr version no longer provides " + "it; pin zarr accordingly or open without cache_dir." + ) from exc + from zarr.storage import FsspecStore, LocalStore + + source = FsspecStore.from_url( + path, + storage_options=dict(storage_options) if storage_options else None, + read_only=True, + ) + # CacheStore keys entries by relative zarr key ("aot/0.0" is the same key + # for every S2 product), so namespace the cache per source URL. Trailing + # slashes are stripped so equivalent URLs share a namespace. + cache_key = hashlib.sha256(path.rstrip("/").encode()).hexdigest()[:16] + source_cache = Path(cache_dir) / cache_key + cached = CacheStore(source, cache_store=LocalStore(source_cache)) + # xarray's open_datatree accepts a zarr store at runtime, but its stub does + # not list Store among the accepted input types. + return xr.open_datatree( + cached, # pyright: ignore[reportArgumentType] + engine=engine, + chunks={}, + mask_and_scale=mask_and_scale, + ) diff --git a/src/eopf_geozarr/conversion/sentinel1_reprojection.py b/src/eopf_geozarr/conversion/sentinel1_reprojection.py index 7681e931..17b8f8e0 100644 --- a/src/eopf_geozarr/conversion/sentinel1_reprojection.py +++ b/src/eopf_geozarr/conversion/sentinel1_reprojection.py @@ -281,6 +281,14 @@ def _reproject_data_variable( # Set nodata using rioxarray if not NaN if not np.isnan(nodata_value): reprojected_var = reprojected_var.rio.write_nodata(nodata_value) + # Also record the fill value in the encoding: downstream attribute + # sanitization (setup_datatree_metadata_geozarr_spec_compliant) strips + # `_FillValue` from attrs and only re-adds it for float variables, and + # `explicit_fill_value` reads the encoding — without this, integer + # nodata would be lost from the output metadata. + reprojected_var.encoding["_FillValue"] = ( + np.asarray(nodata_value).astype(reprojected_var.dtype).item() + ) return reprojected_var diff --git a/src/eopf_geozarr/conversion/utils.py b/src/eopf_geozarr/conversion/utils.py index ff5e8d2c..32810807 100644 --- a/src/eopf_geozarr/conversion/utils.py +++ b/src/eopf_geozarr/conversion/utils.py @@ -112,7 +112,17 @@ def sanitize_array_attrs( ) -> dict[str, Any]: """Return a copy of *attrs* with source-only and misleading keys removed. - - ``_eopf_attrs`` is always removed. + - ``_eopf_attrs`` and ``_FillValue`` are always removed. ``_FillValue`` + belongs in the variable's *encoding* (where the zarr-level fill value is + carried), not in its attributes; callers that need a CF ``_FillValue`` + attribute (e.g. the NaN workaround for xarray issue #11345) must re-add + it after sanitizing. + + .. warning:: The Sentinel-3 OLCI converter has its own deliberately + divergent sanitizer + (``s3_olci_optimization.olci_converter._sanitize_olci_array_attrs_keep_fill``) + that **preserves** ``_FillValue`` for raw (non-mask-scaled) input. + Edits to the strip-list here do not apply there, and vice versa. - For decoded float measurement arrays (*is_decoded_float=True*), also removes raw-encoding leftovers ``dtype``, ``fill_value``, ``valid_min``, ``valid_max`` and rewrites diff --git a/src/eopf_geozarr/data_api/s3_olci.py b/src/eopf_geozarr/data_api/s3_olci.py new file mode 100644 index 00000000..7b55f8f0 --- /dev/null +++ b/src/eopf_geozarr/data_api/s3_olci.py @@ -0,0 +1,94 @@ +"""Pydantic-zarr model for the Sentinel-3 OLCI L1 EFR EOPF Zarr structure. + +Mirrors data_api/s2.py: GroupSpec + closed TypedDict members. Used for +structural product detection (an EOPF product is OLCI iff it validates here). +""" + +from __future__ import annotations + +from collections.abc import Mapping # noqa: TC003 + +from pydantic import BaseModel +from typing_extensions import TypedDict + +from eopf_geozarr.data_api.geozarr.common import DatasetAttrs +from eopf_geozarr.pyz.v2 import ArraySpec, GroupSpec + + +class Sentinel3OlciRootAttrs(BaseModel): + """Root-level attributes for an OLCI DataTree (not validated in detail).""" + + other_metadata: dict[str, object] + stac_discovery: dict[str, object] + + +class Sentinel3OlciMeasurementsMembers(TypedDict, closed=True, total=False): + """Members of the OLCI measurements group. + + The 21 radiance bands and the per-pixel geolocation coordinate arrays are + required in practice but typed optional so partial/variant products still + validate; the converter checks for the bands it needs. + """ + + latitude: ArraySpec[object] + longitude: ArraySpec[object] + altitude: ArraySpec[object] + time_stamp: ArraySpec[object] + orphans: GroupSpec[Mapping[str, object], Mapping[str, ArraySpec[object]]] + oa01_radiance: ArraySpec[object] + oa02_radiance: ArraySpec[object] + oa03_radiance: ArraySpec[object] + oa04_radiance: ArraySpec[object] + oa05_radiance: ArraySpec[object] + oa06_radiance: ArraySpec[object] + oa07_radiance: ArraySpec[object] + oa08_radiance: ArraySpec[object] + oa09_radiance: ArraySpec[object] + oa10_radiance: ArraySpec[object] + oa11_radiance: ArraySpec[object] + oa12_radiance: ArraySpec[object] + oa13_radiance: ArraySpec[object] + oa14_radiance: ArraySpec[object] + oa15_radiance: ArraySpec[object] + oa16_radiance: ArraySpec[object] + oa17_radiance: ArraySpec[object] + oa18_radiance: ArraySpec[object] + oa19_radiance: ArraySpec[object] + oa20_radiance: ArraySpec[object] + oa21_radiance: ArraySpec[object] + + +class Sentinel3OlciMeasurementsGroup(GroupSpec[DatasetAttrs, Sentinel3OlciMeasurementsMembers]): + """OLCI measurements group: 21 radiance bands + 2-D geolocation.""" + + +class Sentinel3OlciRootMembers(TypedDict, closed=True, total=False): + """Members of the OLCI root group.""" + + measurements: Sentinel3OlciMeasurementsGroup + quality: GroupSpec[ + Mapping[str, object], + Mapping[ + str, + GroupSpec[Mapping[str, object], Mapping[str, ArraySpec[object]]] | ArraySpec[object], + ], + ] + conditions: GroupSpec[ + Mapping[str, object], + Mapping[ + str, + GroupSpec[Mapping[str, object], Mapping[str, ArraySpec[object]]] | ArraySpec[object], + ], + ] + + +class Sentinel3OlciRoot(GroupSpec[Sentinel3OlciRootAttrs, Sentinel3OlciRootMembers]): + """Complete Sentinel-3 OLCI L1 EFR EOPF Zarr hierarchy.""" + + @property + def measurements(self) -> Sentinel3OlciMeasurementsGroup: + """Get the measurements group.""" + group = self.members.get("measurements") + if group is None: + raise KeyError("measurements") + return group diff --git a/src/eopf_geozarr/s2_optimization/s2_multiscale.py b/src/eopf_geozarr/s2_optimization/s2_multiscale.py index 35a06520..a79a9832 100644 --- a/src/eopf_geozarr/s2_optimization/s2_multiscale.py +++ b/src/eopf_geozarr/s2_optimization/s2_multiscale.py @@ -483,6 +483,11 @@ def create_measurements_encoding( # Forward-propagate the existing encoding, minus keys that should be omitted keep_keys = XARRAY_ENCODING_KEYS - {"compressors", "shards", "chunks"} + # Whether to inject a CF _FillValue attribute for xarray issue #11345. + # The injection itself happens after sanitize_array_attrs below, which + # would otherwise strip it. + inject_nan_fillvalue = False + if experimental_scale_offset_codec and not keep_scale_offset: # Push CF scale-offset into the zarr codec pipeline instead of # decoding to float. The data stays as packed integers on disk, @@ -524,8 +529,7 @@ def create_measurements_encoding( # on the source variable. keep_keys = keep_keys - CF_SCALE_OFFSET_KEYS - {"_FillValue", "filters"} var_encoding["fill_value"] = "NaN" - # Inject CF _FillValue attribute for xarray issue #11345 - var_data.attrs["_FillValue"] = np.nan + inject_nan_fillvalue = True elif not keep_scale_offset: # When stripping scale/offset, also strip _FillValue since the original # _FillValue is in raw integer units and meaningless for decoded float data. @@ -536,8 +540,7 @@ def create_measurements_encoding( # to set the zarr-level fill value, distinct from "_FillValue" which # controls CF-convention attribute masking. var_encoding["fill_value"] = "NaN" - # Inject CF _FillValue attribute for xarray issue #11345 - var_data.attrs["_FillValue"] = np.nan + inject_nan_fillvalue = True for key in keep_keys: if key in var_data.encoding: @@ -554,6 +557,9 @@ def create_measurements_encoding( # otherwise leak into the output). is_float = np.issubdtype(var_data.dtype, np.floating) var_data.attrs = utils.sanitize_array_attrs(var_data.attrs, is_decoded_float=is_float) + if inject_nan_fillvalue: + # Inject CF _FillValue attribute for xarray issue #11345 + var_data.attrs["_FillValue"] = np.nan encoding[str(var_name)] = var_encoding # Add coordinate encoding and sanitize coord attrs (e.g. drop diff --git a/src/eopf_geozarr/s3_olci_optimization/__init__.py b/src/eopf_geozarr/s3_olci_optimization/__init__.py new file mode 100644 index 00000000..6850218b --- /dev/null +++ b/src/eopf_geozarr/s3_olci_optimization/__init__.py @@ -0,0 +1 @@ +"""Sentinel-3 OLCI L1 EFR optimization (GeoZarr export).""" diff --git a/src/eopf_geozarr/s3_olci_optimization/olci_band_mapping.py b/src/eopf_geozarr/s3_olci_optimization/olci_band_mapping.py new file mode 100644 index 00000000..db0cc35e --- /dev/null +++ b/src/eopf_geozarr/s3_olci_optimization/olci_band_mapping.py @@ -0,0 +1,51 @@ +"""Band definitions for Sentinel-3 OLCI L1 EFR. + +OLCI has 21 radiance bands (Oa01..Oa21), all delivered at the same full +resolution (~300 m) on a single swath grid. +""" + +from dataclasses import dataclass + +RADIANCE_DTYPE = "uint16" + +# Band index -> central wavelength in nm (OLCI Oa01..Oa21). +_WAVELENGTHS_NM: tuple[float, ...] = ( + 400.0, + 412.5, + 442.5, + 490.0, + 510.0, + 560.0, + 620.0, + 665.0, + 673.75, + 681.25, + 708.75, + 753.75, + 761.25, + 764.375, + 767.5, + 778.75, + 865.0, + 885.0, + 900.0, + 940.0, + 1020.0, +) + +OLCI_BANDS: tuple[str, ...] = tuple(f"oa{i:02d}_radiance" for i in range(1, 22)) + + +@dataclass(frozen=True) +class OlciBandInfo: + """Spectral characterization of a single OLCI radiance band.""" + + name: str + data_type: str + wavelength_center: float # nanometers + + +OLCI_BAND_INFO: dict[str, OlciBandInfo] = { + name: OlciBandInfo(name=name, data_type=RADIANCE_DTYPE, wavelength_center=wl) + for name, wl in zip(OLCI_BANDS, _WAVELENGTHS_NM, strict=True) +} diff --git a/src/eopf_geozarr/s3_olci_optimization/olci_converter.py b/src/eopf_geozarr/s3_olci_optimization/olci_converter.py new file mode 100644 index 00000000..dfc70108 --- /dev/null +++ b/src/eopf_geozarr/s3_olci_optimization/olci_converter.py @@ -0,0 +1,418 @@ +"""Top-level Sentinel-3 OLCI L1 EFR -> GeoZarr conversion.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, cast + +import rioxarray # noqa: F401 +import structlog +import xarray as xr +import zarr +from rasterio.crs import CRS + +from eopf_geozarr.conversion.utils import build_convention_attrs +from eopf_geozarr.data_api.s3_olci import Sentinel3OlciRoot +from eopf_geozarr.s3_olci_optimization.olci_band_mapping import OLCI_BANDS +from eopf_geozarr.s3_olci_optimization.olci_multiscale import ( + grid_spatial_attrs, + reduce_swath, +) +from eopf_geozarr.s3_olci_optimization.olci_reproject import GRID_DIMS, reproject_olci + +if TYPE_CHECKING: + from zarr.core.common import JSON + from zarr_cm import LayoutObject, MultiscalesAttrs, Transform + +log = structlog.get_logger() + + +def _sanitize_olci_array_attrs_keep_fill(attrs: dict[str, object]) -> dict[str, object]: + """Return a copy of *attrs* with stale source-only keys removed. + + Strips ``_eopf_attrs``, ``dtype``, ``valid_min``, and ``valid_max`` (source + provenance and raw-integer-domain metadata that is misleading in GeoZarr + output). Unlike the shared :func:`~eopf_geozarr.conversion.utils.sanitize_array_attrs`, + this helper intentionally **preserves** ``_FillValue`` because OLCI input is + opened with ``mask_and_scale=False`` (raw uint16) and downstream code (e.g. + ``reduce_swath``) needs ``_FillValue`` in ``.attrs`` to identify fill pixels + without CF decoding. + + CF keys ``scale_factor``, ``add_offset``, ``units``, ``standard_name``, + ``coordinates``, and ``long_name`` are always preserved. + """ + _strip = frozenset(("_eopf_attrs", "dtype", "valid_min", "valid_max")) + return {k: v for k, v in attrs.items() if k not in _strip} + + +def is_sentinel3_olci_dataset(group: zarr.Group) -> bool: + """Return True if *group* is a Sentinel-3 OLCI L1 EFR product. + + Detection is structural: the group must validate against + ``Sentinel3OlciRoot`` and its ``measurements`` group must contain the + first OLCI radiance band. + + Detection is intentionally conservative: ``Sentinel3OlciRoot`` uses a + closed member set and requires the standard EOPF root attrs, so a + product with extra top-level groups or missing root metadata fails + validation and is treated as "not OLCI" (falling through to the generic + converter in the CLI). Users with such near-miss products should use the + explicit ``convert-s3-olci-optimized`` subcommand, which skips detection. + """ + from eopf_geozarr.pyz.v2 import GroupSpec + + try: + model = Sentinel3OlciRoot.model_validate(GroupSpec.from_zarr(group).model_dump()) + except Exception as e: + # Classify, never raise: from_zarr/model_dump can fail with types + # other than ValidationError on malformed or unexpected stores, and + # any failure simply means "not a recognised OLCI product". + log.debug("Not an OLCI dataset", error=str(e)) + return False + try: + return OLCI_BANDS[0] in model.measurements.members + except KeyError: + return False + + +def _overview_levels(rows: int, cols: int, min_dimension: int) -> int: + """Return the number of /2 decimations before min(rows, cols) drops below min_dimension. + + A level is generated only when the *post*-decimation minimum spatial + dimension is at least *min_dimension*. For example, a 512x480 dataset + with min_dimension=256 yields zero levels because 480//2=240 < 256, while + a 1024x1024 dataset with min_dimension=256 yields two levels (512x512, + then 256x256). + """ + levels = 0 + r, c = rows, cols + while min(r, c) // 2 >= min_dimension: + r, c = r // 2, c // 2 + levels += 1 + return levels + + +def _clear_encoding(ds: xr.Dataset) -> xr.Dataset: + """Return *ds* with all inherited source encoding cleared. + + When the input DataTree was opened from a Zarr v2 store, xarray carries + ``numcodecs.Blosc`` compressors (and potentially scale-offset filters) in + each variable's ``.encoding``. Passing that encoding to + ``Dataset.to_zarr(zarr_format=3)`` raises:: + + TypeError: Expected a BytesBytesCodec. Got + + because numcodecs codecs are not valid Zarr v3 BytesBytesCodecs. Clearing + the encoding lets the Zarr v3 writer choose its own default codecs. + + This converter expects raw (non-mask-scaled) input: the caller must open + the source DataTree with ``mask_and_scale=False`` so that CF + ``scale_factor``/``add_offset`` stay in ``.attrs`` and integer fill pixels + are identified via ``attrs["_FillValue"]``. Only Zarr v2 *codec* encoding + (e.g. ``numcodecs.Blosc`` compressors) is stripped here — CF metadata is + untouched. + """ + ds = ds.copy() + ds.encoding = {} + for var in list(ds.data_vars) + list(ds.coords): + ds[var].encoding.clear() + return ds + + +def _sanitize_data_vars(ds: xr.Dataset) -> xr.Dataset: + """Return *ds* with stale source attrs stripped from all data variables. + + Applies :func:`_sanitize_olci_array_attrs_keep_fill` to every data variable in *ds*. + Coordinate variable attrs are left intact. + + This removes ``_eopf_attrs``, ``dtype``, ``valid_min``, and ``valid_max`` + (source-only / misleading) while preserving CF attrs + (``scale_factor``, ``add_offset``, ``_FillValue``, ``units``, + ``standard_name``, ``coordinates``). + + Note: ``xr.DataArray.assign_attrs`` *merges* (update semantics), so we + copy the DataArray and replace ``.attrs`` in-place to ensure stale keys + are actually removed rather than retained from the old dict. + """ + new_vars: dict[str, xr.DataArray] = {} + for name in ds.data_vars: + var = ds[name] + new_var = var.copy(data=var.data) + new_var.attrs = _sanitize_olci_array_attrs_keep_fill(dict(var.attrs)) + new_vars[str(name)] = new_var + return ds.assign(new_vars) + + +def _copy_subtree(node: xr.DataTree, output_path: str, *, root_group: str) -> None: + """Write every Dataset in *node*'s subtree to the Zarr store at *output_path*. + + Each path is mapped relative to the node's own path: the node root becomes + *root_group*, and child nodes are placed at ``root_group/``. + + ``DataTree.to_zarr`` does not yet support a ``group`` keyword for + specifying a root offset, so we write each leaf's :py:meth:`~xarray.DataTree.to_dataset` + using ``xr.Dataset.to_zarr`` instead. + """ + node_path = node.path # e.g. "/conditions" + for child in node.subtree: + ds = child.to_dataset() + if not ds.data_vars and not ds.coords: + continue + # Strip any inherited Zarr v2 encoding before writing to a v3 store. + ds = _clear_encoding(ds) + # Build the group path: strip the ancestor prefix and prepend root_group. + relative = child.path[len(node_path) :] # "" for root, "/sub" for children + group_path = root_group + relative + log.info("Copying ancillary subgroup", group=group_path) + ds.to_zarr( + output_path, + group=group_path, + mode="a", + consolidated=False, + zarr_format=3, + ) + + +def convert_olci_optimized( + dt_input: xr.DataTree, + *, + output_path: str, + enable_sharding: bool = False, + spatial_chunk: int = 1024, + compression_level: int = 3, + min_dimension: int = 256, + keep_scale_offset: bool = False, + target_crs: str = "EPSG:4326", +) -> xr.DataTree: + """Convert an EOPF OLCI L1 EFR DataTree to a GeoZarr multiscale store. + + Warps the swath once to a regular *target_crs* grid, writes it to + ``measurements/r0``, then /2-reduced overview siblings (``r2``, ``r4``, + …) down to *min_dimension*; the ``measurements`` group carries the + GeoZarr convention metadata tying the levels together. Any + ``conditions`` or ``quality`` groups present in *dt_input* are copied + through unchanged, along with any child subgroups of ``measurements`` + (e.g. ``orphans``). Every level (``r0``, ``r2``, …) carries its own + ``spatial_ref``/``grid_mapping`` plus zarr-cm spatial/geo-proj convention + attrs; the source product's per-scan-line ``time_stamp`` is dropped here + (it has no home on the regular grid) but survives in the source product. + + Parameters + ---------- + dt_input: + Input OLCI L1 EFR DataTree (must contain a ``/measurements`` node). + output_path: + Filesystem path for the output Zarr v3 store. + enable_sharding: + Enable Zarr v3 sharding on measurement arrays. + Not yet wired into encoding for this minimal pass; accepted as a + typed parameter for forward-compatibility (follow-up task). + spatial_chunk: + Target spatial chunk size (pixels per side). + Not yet wired into encoding for this minimal pass; accepted as a + typed parameter for forward-compatibility (follow-up task). + compression_level: + Blosc/zstd compression level. + Not yet wired into encoding for this minimal pass; accepted as a + typed parameter for forward-compatibility (follow-up task). + min_dimension: + Stop generating overview levels once either spatial dimension would + drop below this value after /2 decimation. + keep_scale_offset: + When ``True``, preserve CF ``scale_factor``/``add_offset`` in the + output encoding rather than decoding to float32. + Not yet wired into encoding for this minimal pass; accepted as a + typed parameter for forward-compatibility (follow-up task). + target_crs: + Target CRS for the output grid; the swath is warped once at native + resolution before the pyramid builds. + + Returns + ------- + xr.DataTree + The opened output DataTree (lazy; backed by the written Zarr store). + Opened with ``mask_and_scale=False``, mirroring the raw store and the + converter's input: radiance is packed ``uint16`` with its CF + ``scale_factor``/``_FillValue`` attrs intact, not decoded floats. + Native-resolution arrays live at ``measurements/r0`` with overview + levels (``r2``, ``r4``, …) as sibling groups, all on a regular grid + with 1-D ``y``/``x`` coordinates and a declared CRS; ``measurements`` + itself holds only the multiscales/spatial convention metadata, so the + whole store opens cleanly with ``xr.open_datatree``. + + Notes + ----- + Parameters ``enable_sharding``, ``spatial_chunk``, ``compression_level``, + and ``keep_scale_offset`` are accepted but not yet applied to the on-disk + encoding. Wiring them through the existing ``conversion`` helpers + (``create_measurements_encoding``, sharding codec, etc.) is left for a + follow-up task so as not to block the integration test. A warning is + logged when a non-default value is passed for any of them, so callers + aren't silently handed default-encoded output. + """ + unwired: dict[str, tuple[object, object]] = { + "enable_sharding": (enable_sharding, False), + "spatial_chunk": (spatial_chunk, 1024), + "compression_level": (compression_level, 3), + "keep_scale_offset": (keep_scale_offset, False), + } + ignored = [name for name, (value, default) in unwired.items() if value != default] + if ignored: + log.warning( + "Options not yet applied by the OLCI converter; output uses default encoding", + ignored_options=ignored, + ) + + measurements = dt_input["/measurements"].to_dataset() + # Structural detection does not constrain dimension names, but the whole + # swath pipeline (reduce_swath, decimate_swath, SWATH_DIMS) assumes + # rows/columns; fail with a clear error instead of a bare KeyError below. + missing_dims = [d for d in ("rows", "columns") if d not in measurements.sizes] + if missing_dims: + raise ValueError( + "OLCI converter requires swath dimensions ('rows', 'columns') on the " + f"measurements group; missing {missing_dims}. Use the generic convert " + "path for products with different dimension names." + ) + # Strip any inherited Zarr v2 encoding (e.g. numcodecs.Blosc compressors) + # so the v3 writer can choose its own default codecs without raising a + # "Expected a BytesBytesCodec" error. The caller is expected to have opened + # the source with mask_and_scale=False, so CF attrs (scale_factor, + # add_offset, _FillValue) live in .attrs and are preserved here. + measurements = _clear_encoding(measurements) + # Sanitize radiance variable attrs: strip source-only / misleading attrs + # (_eopf_attrs, dtype, valid_min, valid_max) while keeping CF scale/offset + # and _FillValue so that downstream readers and reduce_swath can work + # correctly with raw integer data. + measurements = _sanitize_data_vars(measurements) + + # Warp the curvilinear swath onto a regular target_crs grid (1-D y/x + # coords, spatial_ref + grid_mapping on every variable) at (approximately) + # native resolution. Everything downstream — the pyramid, spatial attrs, + # and CRS metadata — operates on this gridded dataset. + measurements = reproject_olci(measurements, target_crs=target_crs) + # rioxarray's write_crs records grid_mapping in both .attrs (explicitly, + # above) and .encoding; xarray's to_zarr refuses to serialize a variable + # whose attrs and encoding disagree on an encoding-owned key, so clear the + # inherited encoding once more after the warp. + measurements = _clear_encoding(measurements) + + # Truncate any pre-existing store first: the writes below are per-group + # (mode="w" scoped to measurements/r0, mode="a" for overviews/ancillary), + # so a prior run with more overview levels or extra ancillary groups would + # otherwise leave stale sibling groups behind, and the returned DataTree + # (built by re-scanning the store) would surface them. + zarr.open_group(output_path, mode="w", zarr_format=3) + + # The native-resolution arrays go in a named child group (r0) alongside the + # overview groups (r2, r4, …) rather than directly in ``measurements``. + # If the parent held the full-res coordinates itself, every overview child + # would inherit them over the shared y/x dims at mismatched sizes and + # ``xr.open_datatree`` (and any generic GeoZarr reader) would reject the + # store with an alignment error. + log.info("Writing native-resolution measurements", shape=dict(measurements.sizes)) + measurements.to_zarr( + output_path, + group="measurements/r0", + mode="w", + consolidated=False, + zarr_format=3, + ) + + # Write /2 reduced overview subgroups: r2, r4, r8, … + rows = measurements.sizes["y"] + cols = measurements.sizes["x"] + n_levels = _overview_levels(rows, cols, min_dimension) + log.info("Generating overview levels", n_levels=n_levels) + + level_datasets: dict[str, xr.Dataset] = {"r0": measurements} + current = measurements + for level in range(1, n_levels + 1): + current = reduce_swath(current, factor=2, dims=GRID_DIMS) + current = _clear_encoding(current) + # Attrs already sanitized at native level and passed through by + # reduce_swath; no second sanitize pass needed. + group_name = f"r{2**level}" + level_datasets[group_name] = current + log.info("Writing overview", group=f"measurements/{group_name}", shape=dict(current.sizes)) + current.to_zarr( + output_path, + group=f"measurements/{group_name}", + mode="a", + consolidated=False, + zarr_format=3, + ) + + # Build and attach GeoZarr convention metadata (spatial + multiscales CMO) + # to the measurements group attrs. + layout: list[LayoutObject] = [{"asset": "r0"}] + for lvl in range(1, n_levels + 1): + transform: Transform = {"scale": [2.0, 2.0], "translation": [0.0, 0.0]} + lo: LayoutObject = { + "asset": f"r{2**lvl}", + "derived_from": f"r{2 ** (lvl - 1)}" if lvl > 1 else "r0", + "transform": transform, + "resampling_method": "average", + } + layout.append(lo) + + # zarr_cm's proj convention wants a CRSLike (to_epsg/to_wkt) object, not a + # bare string, so resolve target_crs once here. + crs_obj = CRS.from_string(target_crs) + + root_rw = zarr.open_group(output_path, mode="a") + base_transform = measurements.rio.transform(recalc=True) + base_spatial = grid_spatial_attrs( + base_transform, (measurements.sizes["y"], measurements.sizes["x"]) + ) + for group_name, level_ds in level_datasets.items(): + level_transform = level_ds.rio.transform(recalc=True) + level_conv = build_convention_attrs( + spatial=grid_spatial_attrs(level_transform, (level_ds.sizes["y"], level_ds.sizes["x"])), + crs=crs_obj, + ) + root_rw[f"measurements/{group_name}"].attrs.update(cast("dict[str, JSON]", level_conv)) + + if n_levels > 0: + ms: MultiscalesAttrs = {"layout": layout, "resampling_method": "average"} + conv = build_convention_attrs(multiscales=ms, spatial=base_spatial, crs=crs_obj) + else: + conv = build_convention_attrs(spatial=base_spatial, crs=crs_obj) + + root_rw["measurements"].attrs.update(cast("dict[str, JSON]", conv)) + + # Copy conditions/quality through unchanged (if present). + # DataTree.to_zarr does not support a root ``group`` argument, so we + # iterate the subtree and write each leaf Dataset individually. + for grp in ("conditions", "quality"): + try: + node_item = dt_input[f"/{grp}"] + except KeyError: + continue + if not isinstance(node_item, xr.DataTree): + continue + log.info("Copying ancillary group", group=grp) + _copy_subtree(node_item, output_path, root_group=grp) + + # Copy any child subgroups of measurements (e.g. orphans) through unchanged. + try: + meas_node = dt_input["/measurements"] + except KeyError: + meas_node = None + if isinstance(meas_node, xr.DataTree): + for child in meas_node.children.values(): + log.info("Copying measurements subgroup", group=f"measurements/{child.name}") + _copy_subtree(child, output_path, root_group=f"measurements/{child.name}") + + # The r0 named-sibling layout keeps every parent group free of arrays, so + # the whole store — overview levels and nested ancillary groups included — + # opens directly as a DataTree. mask_and_scale=False so the returned tree + # mirrors the raw store (packed uint16 + CF attrs), matching how the + # converter opened its input, rather than handing callers CF-decoded + # floats. + return xr.open_datatree( + output_path, + engine="zarr", + chunks={}, + consolidated=False, + mask_and_scale=False, + ) diff --git a/src/eopf_geozarr/s3_olci_optimization/olci_multiscale.py b/src/eopf_geozarr/s3_olci_optimization/olci_multiscale.py new file mode 100644 index 00000000..425bd044 --- /dev/null +++ b/src/eopf_geozarr/s3_olci_optimization/olci_multiscale.py @@ -0,0 +1,286 @@ +"""Multiscale (overview) generation for OLCI data. + +Both reduction strategies operate over a configurable pair of spatial +dimensions (default the raw-swath ``(rows, columns)``; the converter's +reprojected pyramid uses ``(y, x)``): + +* :func:`decimate_swath` — pure stride-based decimation; every 2-D spatial + variable is subsampled ``[::factor, ::factor]``. Intended for cases where + preserving pixel identity matters. + +* :func:`reduce_swath` — radiance bands and altitude are fill-aware + block-averaged (mean of ``factor x factor`` blocks); other spatial + variables (including 1-D dimension coordinates) are stride-decimated; + non-spatial variables pass through unchanged. Intended for producing + GeoZarr multiscale overview groups. + +:func:`grid_spatial_attrs` emits the zarr-cm spatial-convention attrs for a +regular grid level with an affine transform. +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import numpy as np +import rasterio.transform +import structlog +import xarray as xr + +from eopf_geozarr.s3_olci_optimization.olci_band_mapping import OLCI_BANDS + +if TYPE_CHECKING: + from affine import Affine + from zarr_cm import SpatialAttrs + +log = structlog.get_logger() + +SWATH_DIMS = ("rows", "columns") + + +def decimate_swath( + ds: xr.Dataset, factor: int = 2, *, dims: tuple[str, str] = SWATH_DIMS +) -> xr.Dataset: + """Return *ds* with every array spanning the *dims* spatial dimensions (default ``(rows, columns)``) subsampled by *factor*. + + Both data variables and coordinate variables that span exactly the swath + dims are decimated ``[::factor, ::factor]``; everything else is passed + through unchanged. Attributes and encoding are preserved by xarray's isel. + """ + if factor < 1: + raise ValueError(f"factor must be >= 1, got {factor}") + if factor == 1: + return ds + indexers = {dim: slice(None, None, factor) for dim in dims if dim in ds.sizes} + if not indexers: + return ds + return ds.isel(indexers) + + +def _fill_value_of(var: xr.DataArray) -> int | float | None: + """Declared ``_FillValue`` from attrs or encoding, or None.""" + fill = var.attrs.get("_FillValue") + if fill is None: + fill = var.encoding.get("_FillValue") + return fill + + +def reduce_swath( + ds: xr.Dataset, factor: int = 2, *, dims: tuple[str, str] = SWATH_DIMS +) -> xr.Dataset: + """Return *ds* with radiance and altitude block-averaged, other spatial variables decimated. + + Overviews are an unweighted index-block mean that ASSUMES locally-uniform + pixel spacing; intended for visualization, not quantitative analysis at + reduced resolution. + + Parameters spanning the *dims* spatial dimensions (default ``(rows, columns)``) + are processed; other variables pass through unchanged. + + Radiance variables (those named in :data:`OLCI_BANDS`) are averaged over + ``factor x factor`` pixel blocks with fill-value awareness: fill pixels + are masked before averaging so a single fill pixel does not contaminate + the entire block. Blocks where ALL pixels are fill are set back to the + fill value in the output. + + Altitude (identified by ``standard_name`` falling back to variable name) + is fill-aware block-averaged exactly like radiance, so the elevation of + an overview cell describes the same pixel block its radiance was averaged + over; being linear, its mean commutes with CF packing and runs on raw + values. Remaining 2-D spatial variables and 1-D dimension coordinates + are decimated by trimmed stride; variables that do not span the *dims* + spatial dimensions are passed through unchanged. + + Parameters + ---------- + ds: + Input dataset. May contain any mix of radiance bands, 2-D coordinate + arrays, and other variables. + factor: + Spatial reduction factor. Must be >= 1. Factor 1 returns *ds* + unchanged. + + Returns + ------- + xr.Dataset + Reduced dataset with the same variables but smaller (rows, columns) + dimensions. + + Raises + ------ + ValueError + If *factor* < 1. + """ + if factor < 1: + raise ValueError(f"factor must be >= 1, got {factor}") + if factor == 1: + return ds + + olci_band_set: frozenset[str] = frozenset(OLCI_BANDS) + result_vars: dict[str, xr.DataArray] = {} + result_coords: dict[str, xr.DataArray] = {} + + coord_names: frozenset[str] = frozenset(str(k) for k in ds.coords) + + # Pre-compute the trimmed length for each swath dimension so that both the + # coarsen path (radiance) and the isel stride path (coordinates) produce + # exactly floor(N / factor) output elements. coarsen(boundary="trim") + # already truncates to a multiple of factor; we match it by stopping the + # stride at the same trimmed limit: slice(0, n_trim, factor). + # + # Without this, an odd-length dimension N yields: + # coarsen → floor(N / factor) e.g. 4865 → 2432 + # isel[::factor] → ceil(N / factor) e.g. 4865 → 2433 + # producing a store where coordinate arrays are longer than the data they + # describe, which makes xr.open_dataset raise a conflicting-sizes error. + dim_trim: dict[str, int] = { + dim: (ds.sizes[dim] // factor) * factor for dim in dims if dim in ds.sizes + } + + all_names: list[str] = [str(k) for k in ds.data_vars] + [str(k) for k in ds.coords] + for name in all_names: + var: xr.DataArray = ds[name] if name in ds.data_vars else ds.coords[name] + # Order-insensitive: a variant product storing a band transposed as + # (columns, rows) must still get fill-aware averaging, not silently + # fall through to stride decimation. Normalize to *dims* order below. + var_dims = tuple(str(d) for d in var.dims) + is_swath_2d: bool = len(var_dims) == 2 and set(var_dims) == set(dims) + # Altitude gets the same fill-aware block mean as radiance so the + # elevation of an overview cell describes the same pixel block its + # radiance was averaged over (a stride sample would sit ~half a block + # away). It is a linear quantity, and a mean commutes with affine CF + # packing, so averaging raw packed values is exact. + is_altitude: bool = str(var.attrs.get("standard_name") or name) == "altitude" + + if (name in olci_band_set or is_altitude) and is_swath_2d: + if var_dims != dims: + log.info("Transposing band to canonical spatial dim order", band=name) + var = var.transpose(*dims) + # Fill-aware block averaging for radiance bands. + fill_value: int | float | None = _fill_value_of(var) + orig_dtype = var.dtype + + float_var = var.astype("float64") + if fill_value is not None: + if np.isnan(float(fill_value)): + # NaN sentinel (float sources): equality comparison would + # be a no-op (NaN != NaN is always True); mask explicitly. + float_var = float_var.where(float_var.notnull()) + else: + float_var = float_var.where(float_var != float(fill_value)) + + # coarsen().mean() is available at runtime; pyright stubs don't expose .mean() + # on DataArrayCoarsen, so we suppress the type-check on the reduction call. + coarsened = float_var.coarsen({dims[0]: factor, dims[1]: factor}, boundary="trim") + # skipna=True explicitly: the fill-aware promise (one fill pixel + # must not contaminate its block) depends on it, so don't rely on + # the version-dependent default. + averaged: xr.DataArray = coarsened.mean(skipna=True) # type: ignore[attr-defined,assignment] + # Materialize once: with dask-backed input, the isnull()/where()/ + # .values accesses below would otherwise each re-evaluate the + # coarsen+mask graph — the heaviest compute in the converter. + averaged = averaged.compute() + + if fill_value is not None: + valid_mask = ~averaged.isnull().values + fill_da = xr.where(averaged.isnull(), float(fill_value), averaged) + result_arr = fill_da.values + else: + valid_mask = None + result_arr = averaged.values + # Round only when packing back into an integer dtype; float + # radiance (e.g. a CF-decoded source) must not be quantized. + if np.issubdtype(orig_dtype, np.integer): + unrounded = result_arr + result_arr = np.round(result_arr) + if fill_value is not None and valid_mask is not None: + # A valid block whose mean rounds to the fill sentinel + # would be recoded as fill in the overview; nudge it one + # step back into the valid domain, on the side of the + # sentinel the unrounded mean came from (fill may sit at + # either end of the dtype range). + collision = valid_mask & (result_arr == float(fill_value)) + if collision.any(): + # Nudge candidates, clamped to the dtype range: when + # the sentinel sits at a dtype bound (e.g. 0 for an + # unsigned dtype), both sides resolve to the one + # in-range neighbour instead of wrapping around. + info = np.iinfo(orig_dtype) + down = float(fill_value) - 1 + up = float(fill_value) + 1 + if down < float(info.min): + down = up + if up > float(info.max): + up = down + nudged = np.where(unrounded <= float(fill_value), down, up) + result_arr = np.where(collision, nudged, result_arr) + result_val = result_arr.astype(orig_dtype) + + out_var = xr.DataArray(result_val, dims=averaged.dims, attrs=var.attrs) + + if name in ds.data_vars: + result_vars[name] = out_var + else: + result_coords[name] = out_var + + elif is_swath_2d: + # Coordinate or non-radiance 2-D swath variable: decimate. + # Use slice(0, n_trim, factor) rather than slice(None, None, factor) + # so that an odd-length dimension N yields floor(N / factor) elements, + # matching the output length of coarsen(boundary="trim").mean(). + indexers: dict[str, slice] = { + dim: slice(0, dim_trim[dim], factor) for dim in dims if dim in dim_trim + } + decimated = var.isel(indexers) + if name in coord_names: + result_coords[name] = decimated + else: + result_vars[name] = decimated + + elif any(dim in (str(d) for d in var.dims) for dim in dims): + # 1-D (or higher) variable sharing a swath dim but not 2-D swath: + # decimate along whichever swath dims it carries. + var_dims = {str(d) for d in var.dims} + idx: dict[str, slice] = { + dim: slice(0, dim_trim[dim], factor) + for dim in dims + if dim in var_dims and dim in dim_trim + } + decimated = var.isel(idx) + if name in coord_names: + result_coords[name] = decimated + else: + result_vars[name] = decimated + + else: + # Non-swath variable: pass through unchanged. + if name in coord_names: + result_coords[name] = var + else: + result_vars[name] = var + + return xr.Dataset(result_vars, coords=result_coords) + + +def grid_spatial_attrs(transform: Affine, shape: tuple[int, int]) -> SpatialAttrs: + """Spatial-convention data for a regular grid with an affine *transform*. + + *shape* is ``(height, width)``. Emits ``spatial:dimensions`` ``["y","x"]``, + pixel registration, the bounding box, and the 6-element row-major affine + transform. + """ + height, width = shape + left, bottom, right, top = rasterio.transform.array_bounds(height, width, transform) + return { + "spatial:dimensions": ["y", "x"], + "spatial:registration": "pixel", + "spatial:bbox": [float(left), float(bottom), float(right), float(top)], + "spatial:transform": [ + float(transform.a), + float(transform.b), + float(transform.c), + float(transform.d), + float(transform.e), + float(transform.f), + ], + } diff --git a/src/eopf_geozarr/s3_olci_optimization/olci_reproject.py b/src/eopf_geozarr/s3_olci_optimization/olci_reproject.py new file mode 100644 index 00000000..3d088700 --- /dev/null +++ b/src/eopf_geozarr/s3_olci_optimization/olci_reproject.py @@ -0,0 +1,181 @@ +"""Reprojection of OLCI swath measurements to a regular grid. + +OLCI L1 EFR is a curvilinear swath geolocated by dense per-pixel 2-D +latitude/longitude arrays. Generic GeoZarr readers (titiler, rioxarray) +require a regular grid with an affine transform and a declared CRS, so the +converter warps the swath once at native resolution using rasterio's +geolocation-array support (``src_geoloc_array``, rasterio >= 1.4). +""" + +from __future__ import annotations + +import numpy as np +import rioxarray # noqa: F401 # enables the .rio accessor +import structlog +import xarray as xr +from pyproj import CRS as ProjCRS +from rasterio.crs import CRS +from rasterio.warp import Resampling, calculate_default_transform, reproject + +log = structlog.get_logger() + +#: CRS of the OLCI geolocation arrays (per-pixel lat/lon in degrees). +GEOLOC_CRS = "EPSG:4326" + +#: Dimension names of the reprojected regular grid. +GRID_DIMS: tuple[str, str] = ("y", "x") + +_SWATH_DIMS = ("rows", "columns") + + +def _nodata_for(var: xr.DataArray) -> float: + """Warp nodata for *var*: its ``_FillValue`` if present, else a dtype default. + + Integer variables without a fill value get the dtype maximum (matching the + OLCI convention of 65535 for uint16 radiances); floats get NaN. + """ + fill = var.attrs.get("_FillValue") + if fill is None: + fill = var.encoding.get("_FillValue") + if fill is not None: + return float(fill) + if np.issubdtype(var.dtype, np.integer): + return float(np.iinfo(var.dtype).max) + return float("nan") + + +def _grid_coord_attrs(target_crs: str) -> tuple[dict[str, str], dict[str, str]]: + """CF attrs for the 1-D (y, x) dimension coordinates in *target_crs*.""" + if ProjCRS.from_user_input(target_crs).is_geographic: + y_attrs = {"standard_name": "latitude", "units": "degrees_north", "axis": "Y"} + x_attrs = {"standard_name": "longitude", "units": "degrees_east", "axis": "X"} + else: + y_attrs = {"standard_name": "projection_y_coordinate", "units": "m", "axis": "Y"} + x_attrs = {"standard_name": "projection_x_coordinate", "units": "m", "axis": "X"} + return y_attrs, x_attrs + + +def reproject_olci( + ds: xr.Dataset, + *, + target_crs: str = "EPSG:4326", + resampling: Resampling = Resampling.bilinear, +) -> xr.Dataset: + """Warp an OLCI swath dataset onto a regular *target_crs* grid. + + Every numeric variable spanning exactly ``(rows, columns)`` — radiance + bands and the 2-D ``altitude`` coordinate alike — is warped onto a common + grid sized by :func:`rasterio.warp.calculate_default_transform` from the + dense per-pixel geolocation (~native resolution preserved). The + ``latitude``/``longitude`` geolocation arrays are consumed by the warp and + replaced by 1-D ``y``/``x`` dimension coordinates. Variables that carry a + swath dim but cannot live on the grid (e.g. per-scan-line ``time_stamp``) + are dropped; variables without swath dims pass through unchanged. + + Off-swath cells are set to each warped variable's ``_FillValue`` (dtype + max for integer variables without one, NaN for float variables without + one), and ``_FillValue`` is recorded in the output attrs of every warped + variable — including NaN for float variables — so downstream fill-aware + averaging keeps working. Passthrough variables that carry no swath dim + are not warped and carry no such guarantee. + + Raises + ------ + ValueError + If the 2-D ``latitude``/``longitude`` coordinates are missing, or if + the geolocation spans a zero-area (degenerate) extent. + """ + for required in ("latitude", "longitude"): + if required not in ds.coords: + raise ValueError(f"cannot reproject OLCI swath: missing 2-D coordinate {required!r}") + lat = ds.coords["latitude"] + lon = ds.coords["longitude"] + if tuple(str(d) for d in lat.dims) != _SWATH_DIMS or lat.dims != lon.dims: + raise ValueError("latitude/longitude must be 2-D over (rows, columns)") + lat_vals = np.asarray(lat.values, dtype="float64") + lon_vals = np.asarray(lon.values, dtype="float64") + if lat_vals.max() == lat_vals.min() or lon_vals.max() == lon_vals.min(): + raise ValueError("degenerate geolocation extent: latitude/longitude span zero area") + + src_height, src_width = lat_vals.shape + geoloc = np.stack([lon_vals, lat_vals]) # (2, H, W): x first, then y + transform, width, height = calculate_default_transform( + src_crs=CRS.from_string(GEOLOC_CRS), + dst_crs=CRS.from_string(target_crs), + width=src_width, + height=src_height, + src_geoloc_array=geoloc, + ) + assert width is not None + assert height is not None + log.info( + "Reprojecting OLCI swath", + target_crs=target_crs, + src_shape=(src_height, src_width), + dst_shape=(height, width), + ) + + result_vars: dict[str, xr.DataArray] = {} + passthrough_coords: dict[str, xr.DataArray] = {} + all_names = [str(k) for k in ds.data_vars] + [ + str(k) for k in ds.coords if str(k) not in ("latitude", "longitude") + ] + for name in all_names: + var = ds[name] if name in ds.data_vars else ds.coords[name] + var_dims = tuple(str(d) for d in var.dims) + if var_dims == _SWATH_DIMS and np.issubdtype(var.dtype, np.number): + nodata = _nodata_for(var) + src_nodata = ( + nodata + if ( + var.attrs.get("_FillValue") is not None + or var.encoding.get("_FillValue") is not None + ) + else None + ) + dest = np.full((height, width), nodata, dtype=var.dtype) + reproject( + source=np.ascontiguousarray(var.values), + destination=dest, + src_crs=CRS.from_string(GEOLOC_CRS), + src_geoloc_array=geoloc, + src_nodata=src_nodata, + dst_crs=CRS.from_string(target_crs), + dst_transform=transform, + dst_nodata=nodata, + resampling=resampling, + ) + out_attrs = dict(var.attrs) + if np.issubdtype(var.dtype, np.integer): + out_attrs["_FillValue"] = int(nodata) + else: + out_attrs["_FillValue"] = float(nodata) # NaN included + out_attrs.pop("coordinates", None) # swath geolocation is gone + result_vars[name] = xr.DataArray(dest, dims=GRID_DIMS, attrs=out_attrs) + elif any(d in var_dims for d in _SWATH_DIMS): + log.info("Dropping swath-bound variable with no grid home", variable=name) + elif name in ds.coords: + passthrough_coords[name] = var + else: + result_vars[name] = var + + xs = transform.c + transform.a * (np.arange(width) + 0.5) + ys = transform.f + transform.e * (np.arange(height) + 0.5) + y_attrs, x_attrs = _grid_coord_attrs(target_crs) + out = xr.Dataset( + result_vars, + coords={ + "y": ("y", ys, y_attrs), + "x": ("x", xs, x_attrs), + **passthrough_coords, + }, + attrs=dict(ds.attrs), + ) + out = out.rio.write_crs(target_crs) + if not isinstance(out, xr.Dataset): + raise TypeError(f"expected an xarray.Dataset after write_crs, got {type(out).__name__}") + # rioxarray records grid_mapping in encoding; pin it in attrs so it is + # guaranteed to reach the zarr store. + for name in out.data_vars: + out[name].attrs["grid_mapping"] = "spatial_ref" + return out diff --git a/tests/_test_data/optimized_olci_examples/S3A_OL_1_EFR____20251101T073957_20251101T074257_20251102T084255_0179_132_149_2160_PS1_O_NT_004.json b/tests/_test_data/optimized_olci_examples/S3A_OL_1_EFR____20251101T073957_20251101T074257_20251102T084255_0179_132_149_2160_PS1_O_NT_004.json new file mode 100644 index 00000000..78d96999 --- /dev/null +++ b/tests/_test_data/optimized_olci_examples/S3A_OL_1_EFR____20251101T073957_20251101T074257_20251102T084255_0179_132_149_2160_PS1_O_NT_004.json @@ -0,0 +1,10864 @@ +{ + "attributes": {}, + "members": { + "conditions": { + "attributes": {}, + "members": { + "geometry": { + "attributes": {}, + "members": { + "latitude": { + "attributes": { + "dimensions": [ + "rows", + "columns" + ], + "dtype": " return out_dir +@pytest.fixture(params=s3_example_json_paths, ids=get_stem) +def s3_olci_group_example(request: pytest.FixtureRequest, tmp_path: pathlib.Path) -> pathlib.Path: + """Path to a Zarr group with the layout of a Sentinel-3 OLCI product.""" + return create_group_from_json(request.param, tmp_path) + + @pytest.fixture(params=s1_example_json_paths, ids=get_stem) def s1_group_example(request: pytest.FixtureRequest, tmp_path: pathlib.Path) -> pathlib.Path: """ diff --git a/tests/test_cli_convert_routing.py b/tests/test_cli_convert_routing.py new file mode 100644 index 00000000..bfabd624 --- /dev/null +++ b/tests/test_cli_convert_routing.py @@ -0,0 +1,193 @@ +""" +In-process tests for the convert command's Sentinel-2 auto-detection and routing. + +The e2e tests in test_cli_e2e.py drive the CLI through subprocesses; these tests +call ``convert_command`` directly (with the converters stubbed out) so the +routing logic itself is exercised in-process. +""" + +import argparse +from pathlib import Path +from typing import Any + +import numpy as np +import pytest +import xarray as xr + +from eopf_geozarr import cli + + +def _convert_args(input_path: str, output_path: str, **overrides: Any) -> argparse.Namespace: + """Build a Namespace mirroring the convert subcommand's defaults.""" + ns = argparse.Namespace( + input_path=input_path, + output_path=output_path, + groups=["/measurements/reflectance/r10m"], + spatial_chunk=4096, + min_dimension=256, + max_retries=3, + crs_groups=None, + gcp_group=None, + verbose=False, + dask_cluster=False, + enable_sharding=False, + no_s2_optimized=False, + no_s3_olci_optimized=False, + ) + for key, value in overrides.items(): + setattr(ns, key, value) + return ns + + +@pytest.fixture +def plain_zarr_input(tmp_path: Path) -> Path: + """A minimal non-Sentinel-2 zarr store.""" + path = tmp_path / "plain_input.zarr" + ds = xr.Dataset( + {"temperature": (["y", "x"], np.zeros((4, 4)))}, + coords={"x": ("x", np.arange(4.0)), "y": ("y", np.arange(4.0))}, + ) + ds.to_zarr(path, zarr_format=3) + return path + + +def test_is_sentinel2_input_true(s2_group_example: Path) -> None: + """A real Sentinel-2 layout is detected.""" + dt = xr.open_datatree(str(s2_group_example), engine="zarr") + assert cli._is_sentinel2_input(dt) is True + + +def test_is_sentinel2_input_false(plain_zarr_input: Path) -> None: + """A plain zarr store is not detected as Sentinel-2 (and never raises).""" + dt = xr.open_datatree(str(plain_zarr_input), engine="zarr") + assert cli._is_sentinel2_input(dt) is False + + +def test_is_sentinel2_input_swallow_errors() -> None: + """Detection failures (e.g. in-memory datatree with no store) mean 'not S2'.""" + dt = xr.DataTree(xr.Dataset({"a": (["y", "x"], np.zeros((2, 2)))})) + assert cli._is_sentinel2_input(dt) is False + + +@pytest.fixture +def converter_spy(monkeypatch: pytest.MonkeyPatch) -> dict[str, dict[str, Any]]: + """Stub out both converters, recording which one convert_command dispatches to.""" + calls: dict[str, dict[str, Any]] = {} + + def fake_s2(**kwargs: Any) -> xr.DataTree: + calls["s2_optimized"] = kwargs + return xr.DataTree() + + def fake_generic(**kwargs: Any) -> xr.DataTree: + calls["generic"] = kwargs + return xr.DataTree() + + def fake_olci(dt_input: xr.DataTree, **kwargs: Any) -> xr.DataTree: + calls["olci"] = {"dt_input": dt_input, **kwargs} + return xr.DataTree() + + monkeypatch.setattr(cli, "convert_s2_optimized", fake_s2) + monkeypatch.setattr(cli, "create_geozarr_dataset", fake_generic) + monkeypatch.setattr(cli, "convert_olci_optimized", fake_olci) + return calls + + +def test_convert_command_routes_s2_to_optimized( + s2_group_example: Path, + tmp_path: Path, + converter_spy: dict[str, dict[str, Any]], +) -> None: + """Sentinel-2 inputs are auto-routed to the optimized converter.""" + args = _convert_args(str(s2_group_example), str(tmp_path / "out.zarr")) + cli.convert_command(args) + + assert "s2_optimized" in calls_or_fail(converter_spy) + assert "generic" not in converter_spy + assert converter_spy["s2_optimized"]["keep_scale_offset"] is False + + +def test_convert_command_no_s2_optimized_forces_generic( + s2_group_example: Path, + tmp_path: Path, + converter_spy: dict[str, dict[str, Any]], +) -> None: + """--no-s2-optimized sends Sentinel-2 inputs down the generic path.""" + args = _convert_args( + str(s2_group_example), + str(tmp_path / "out.zarr"), + no_s2_optimized=True, + crs_groups=["/conditions/geometry"], + ) + cli.convert_command(args) + + assert "generic" in calls_or_fail(converter_spy) + assert "s2_optimized" not in converter_spy + assert converter_spy["generic"]["crs_groups"] == ["/conditions/geometry"] + + +def test_convert_command_routes_olci_with_raw_input( + s3_olci_group_example: Path, + tmp_path: Path, + converter_spy: dict[str, dict[str, Any]], +) -> None: + """Sentinel-3 OLCI inputs are auto-routed to the OLCI converter with raw input. + + convert_olci_optimized requires the source opened with + ``mask_and_scale=False``: radiance must arrive packed (uint16 with CF + scale_factor/add_offset in .attrs), not CF-decoded to float. + """ + args = _convert_args(str(s3_olci_group_example), str(tmp_path / "out.zarr"), min_dimension=128) + cli.convert_command(args) + + assert "olci" in calls_or_fail(converter_spy) + assert "s2_optimized" not in converter_spy + assert "generic" not in converter_spy + assert converter_spy["olci"]["min_dimension"] == 128 + + dt_received = converter_spy["olci"]["dt_input"] + radiance = next( + var + for name, var in dt_received["/measurements"].data_vars.items() + if str(name).endswith("_radiance") + ) + assert not np.issubdtype(radiance.dtype, np.floating), ( + "OLCI converter received CF-decoded (mask_and_scale) input; expected raw packed radiance" + ) + assert "scale_factor" in radiance.attrs + + +def test_convert_command_no_s3_olci_optimized_forces_generic( + s3_olci_group_example: Path, + tmp_path: Path, + converter_spy: dict[str, dict[str, Any]], +) -> None: + """--no-s3-olci-optimized sends Sentinel-3 OLCI inputs down the generic path.""" + args = _convert_args( + str(s3_olci_group_example), + str(tmp_path / "out.zarr"), + no_s3_olci_optimized=True, + ) + cli.convert_command(args) + + assert "generic" in calls_or_fail(converter_spy) + assert "olci" not in converter_spy + + +def test_convert_command_routes_non_s2_to_generic( + plain_zarr_input: Path, + tmp_path: Path, + converter_spy: dict[str, dict[str, Any]], +) -> None: + """Non-Sentinel-2 inputs use the generic converter.""" + args = _convert_args(str(plain_zarr_input), str(tmp_path / "out.zarr"), groups=["/"]) + cli.convert_command(args) + + assert "generic" in calls_or_fail(converter_spy) + assert "s2_optimized" not in converter_spy + + +def calls_or_fail(calls: dict[str, dict[str, Any]]) -> dict[str, dict[str, Any]]: + """Fail loudly if convert_command dispatched to neither converter.""" + if not calls: + pytest.fail("convert_command did not call any converter (it likely errored early)") + return calls diff --git a/tests/test_cli_e2e.py b/tests/test_cli_e2e.py index b91ce2b9..8b27b3f6 100644 --- a/tests/test_cli_e2e.py +++ b/tests/test_cli_e2e.py @@ -211,7 +211,9 @@ def test_cli_convert_with_crs_groups(s2_group_example: Path, tmp_path: Path) -> Test CLI conversion with --crs-groups option using real Sentinel-2 data. This test verifies that the --crs-groups option works correctly and - processes the specified groups for CRS enhancement. + processes the specified groups for CRS enhancement. It passes + --no-s2-optimized so the Sentinel-2 input goes through the generic + conversion path (the auto-detected optimized path ignores --crs-groups). """ # Dataset from the notebook @@ -242,6 +244,7 @@ def test_cli_convert_with_crs_groups(s2_group_example: Path, tmp_path: Path) -> "256", "--max-retries", "3", + "--no-s2-optimized", "--verbose", ] diff --git a/tests/test_data_api/test_s1.py b/tests/test_data_api/test_s1.py index 5e7ce77d..ed0c3a29 100644 --- a/tests/test_data_api/test_s1.py +++ b/tests/test_data_api/test_s1.py @@ -10,7 +10,14 @@ from the markdown files in docs/models/sentinel1.md """ -from eopf_geozarr.data_api.s1 import Sentinel1Root +import inspect +from typing import Any + +import pytest + +import eopf_geozarr.data_api.s1 as s1_module +from eopf_geozarr.data_api.s1 import Sentinel1PolarizationGroup, Sentinel1Root +from eopf_geozarr.pyz.v2 import GroupSpec def test_sentinel1_roundtrip(s1_json_example: dict[str, object]) -> None: @@ -19,3 +26,62 @@ def test_sentinel1_roundtrip(s1_json_example: dict[str, object]) -> None: dumped = model1.model_dump() model2 = Sentinel1Root.model_validate(dumped) assert model1.model_dump() == model2.model_dump() + + +def _member_accessor_cases() -> list[Any]: + """Collect every generated member-accessor property on the S1 group models. + + The S1 group classes define uniform properties of the shape + ``self.members.get(key)`` + ``raise KeyError(key)`` when absent; identify + them by their source so unrelated properties are not swept in. + """ + cases: list[Any] = [] + for cls_name, cls in inspect.getmembers(s1_module, inspect.isclass): + if cls.__module__ != s1_module.__name__ or not issubclass(cls, GroupSpec): + continue + for prop_name, prop in vars(cls).items(): + if ( + isinstance(prop, property) + and prop.fget is not None + and "raise KeyError" in inspect.getsource(prop.fget) + ): + cases.append(pytest.param(cls, prop_name, id=f"{cls_name}.{prop_name}")) + return cases + + +@pytest.mark.parametrize(("cls", "prop_name"), _member_accessor_cases()) +def test_member_accessor(cls: type[GroupSpec[Any, Any]], prop_name: str) -> None: + """Member accessors return the member when present and raise KeyError when absent.""" + empty = cls.model_construct(members={}) + with pytest.raises(KeyError) as excinfo: + getattr(empty, prop_name) + member_key = excinfo.value.args[0] + + sentinel = object() + populated = cls.model_construct(members={member_key: sentinel}) + assert getattr(populated, prop_name) is sentinel + + +def test_polarization_group_helpers(s1_json_example: dict[str, object]) -> None: + """The root model's polarization lookups find the VH and VV groups.""" + model = Sentinel1Root.model_validate(s1_json_example) + + pols = model.get_polarization_groups() + assert pols + assert all(isinstance(group, Sentinel1PolarizationGroup) for group in pols.values()) + + vh = model.get_vh_group() + assert vh is not None + assert any("VH" in name for name in pols) + + vv = model.get_vv_group() + assert vv is not None + assert any("VV" in name for name in pols) + + +def test_polarization_group_helpers_empty() -> None: + """The polarization lookups return None / empty on a root with no members.""" + empty = Sentinel1Root.model_construct(members={}) + assert empty.get_polarization_groups() == {} + assert empty.get_vh_group() is None + assert empty.get_vv_group() is None diff --git a/tests/test_data_api/test_s3_olci.py b/tests/test_data_api/test_s3_olci.py new file mode 100644 index 00000000..0625ec84 --- /dev/null +++ b/tests/test_data_api/test_s3_olci.py @@ -0,0 +1,132 @@ +"""Tests for the Sentinel-3 OLCI data-api model.""" + +import pytest +from pydantic import ValidationError + +from eopf_geozarr.data_api.s3_olci import Sentinel3OlciRoot +from eopf_geozarr.pyz.v2 import ArraySpec, GroupSpec # noqa: F401 + + +def _olci_arr() -> dict[str, object]: + """Return a minimal v2 ArraySpec-shaped dict for a 2-D uint16 array.""" + return ArraySpec( + shape=(4, 5), + chunks=(4, 5), + dtype=" None: + """A dict with 21 radiance bands + geolocation validates as Sentinel3OlciRoot.""" + radiance = {f"oa{i:02d}_radiance": _olci_arr() for i in range(1, 22)} + coords = {c: _olci_arr() for c in ("latitude", "longitude", "altitude")} + root = { + "zarr_format": 2, + "attributes": {"other_metadata": {}, "stac_discovery": {}}, + "members": { + "measurements": { + "zarr_format": 2, + "attributes": {}, + "members": {**radiance, **coords}, + }, + }, + } + model = Sentinel3OlciRoot.model_validate(root) + assert "oa01_radiance" in model.measurements.members + + +def test_rejects_non_olci_product() -> None: + """A dict with an unexpected key in measurements is rejected by closed=True.""" + not_olci = { + "zarr_format": 2, + "attributes": {"other_metadata": {}, "stac_discovery": {}}, + "members": { + "measurements": { + "zarr_format": 2, + "attributes": {}, + "members": { + "reflectance": { + "zarr_format": 2, + "attributes": {}, + "members": {}, + } + }, + } + }, + } + with pytest.raises(ValidationError): + Sentinel3OlciRoot.model_validate(not_olci) + + +def test_detector_accepts_olci_zarr(tmp_path: object) -> None: + import pathlib + + import zarr + + from eopf_geozarr.s3_olci_optimization.olci_converter import ( + is_sentinel3_olci_dataset, + ) + + # build a minimal OLCI zarr v2 store from the model dict used above + radiance = {f"oa{i:02d}_radiance": _olci_arr() for i in range(1, 22)} + coords = {c: _olci_arr() for c in ("latitude", "longitude", "altitude")} + root_dict = { + "zarr_format": 2, + "attributes": {"other_metadata": {}, "stac_discovery": {}}, + "members": { + "measurements": { + "zarr_format": 2, + "attributes": {}, + "members": {**radiance, **coords}, + } + }, + } + assert isinstance(tmp_path, pathlib.Path) + out = tmp_path / "olci.zarr" + Sentinel3OlciRoot.model_validate(root_dict).to_zarr(out, path="") # type: ignore[arg-type] + group = zarr.open_group(str(out), mode="r") + assert is_sentinel3_olci_dataset(group) is True + + +def test_detector_rejects_s2_zarr(s2_group_example: object) -> None: + import pathlib + + import zarr + + from eopf_geozarr.s3_olci_optimization.olci_converter import ( + is_sentinel3_olci_dataset, + ) + + assert isinstance(s2_group_example, pathlib.Path) + group = zarr.open_group(str(s2_group_example), mode="r") + assert is_sentinel3_olci_dataset(group) is False + + +def test_real_olci_product_is_detected(s3_olci_group_example: object) -> None: + import pathlib + + import zarr + + from eopf_geozarr.s3_olci_optimization.olci_converter import ( + is_sentinel3_olci_dataset, + ) + + assert isinstance(s3_olci_group_example, pathlib.Path) + group = zarr.open_group(str(s3_olci_group_example), mode="r") + assert is_sentinel3_olci_dataset(group) is True + + +def test_real_olci_product_validates_model(s3_olci_group_example: object) -> None: + import pathlib + + import zarr + + from eopf_geozarr.data_api.s3_olci import Sentinel3OlciRoot + from eopf_geozarr.pyz.v2 import GroupSpec as PyzGroupSpec + + assert isinstance(s3_olci_group_example, pathlib.Path) + group = zarr.open_group(str(s3_olci_group_example), mode="r") + model = Sentinel3OlciRoot.model_validate(PyzGroupSpec.from_zarr(group).model_dump()) + assert "oa01_radiance" in model.measurements.members diff --git a/tests/test_data_api/test_v2.py b/tests/test_data_api/test_v2.py index 78bdc161..dd4c6941 100644 --- a/tests/test_data_api/test_v2.py +++ b/tests/test_data_api/test_v2.py @@ -8,8 +8,10 @@ from pydantic import ValidationError from pydantic_zarr.v2 import GroupSpec +from eopf_geozarr.data_api.geozarr.common import DatasetAttrs from eopf_geozarr.data_api.geozarr.v2 import ( DataArray, + Dataset, check_valid_coordinates, ) @@ -72,3 +74,30 @@ def test_invalid_coordinates( msg = "Dimension .* for array 'base' has a shape mismatch:" with pytest.raises(ValueError, match=msg): check_valid_coordinates(cast("GroupLike", group)) + + +class TestDataset: + @staticmethod + def _members() -> dict[str, DataArray]: + base_array = DataArray.from_array( + np.zeros((4, 4), dtype="uint8"), dimension_names=["y", "x"] + ) + coords_arrays = { + name: DataArray.from_array(np.arange(4), dimension_names=(name,)) for name in ("y", "x") + } + return {"band": base_array, **coords_arrays} + + def test_valid(self) -> None: + """A dataset with consistent coordinates and no grid mapping validates.""" + ds = Dataset(attributes=DatasetAttrs(), members=self._members()) + assert isinstance(ds, Dataset) + + def test_missing_grid_mapping_variable(self) -> None: + """A member declaring a grid_mapping that is not in the dataset fails validation.""" + members = self._members() + band = members["band"] + members["band"] = band.model_copy( + update={"attributes": band.attributes.model_copy(update={"grid_mapping": "nope"})} + ) + with pytest.raises(ValidationError, match="Grid mapping variable 'nope'"): + Dataset(attributes=DatasetAttrs(), members=members) diff --git a/tests/test_data_api/test_v3.py b/tests/test_data_api/test_v3.py index c2a16fa4..51c85419 100644 --- a/tests/test_data_api/test_v3.py +++ b/tests/test_data_api/test_v3.py @@ -4,11 +4,14 @@ import numpy as np import pytest import zarr +from pydantic import ValidationError from pydantic_zarr.core import tuplify_json from pydantic_zarr.v3 import ArraySpec, GroupSpec +from eopf_geozarr.data_api.geozarr.common import DatasetAttrs from eopf_geozarr.data_api.geozarr.v3 import ( DataArray, + Dataset, MultiscaleGroup, check_valid_coordinates, ) @@ -94,3 +97,30 @@ def test_multiscale_attrs_round_trip(s2_geozarr_group_example: zarr.Group) -> No assert tuplify_json(MultiscaleGroup(**model_json).model_dump()) == tuplify_json( model_json ) + + +class TestDataset: + @staticmethod + def _members() -> dict[str, DataArray]: + base_array = DataArray.from_array( + np.zeros((4, 4), dtype="uint8"), dimension_names=["y", "x"] + ) + coords_arrays = { + name: DataArray.from_array(np.arange(4), dimension_names=(name,)) for name in ("y", "x") + } + return {"band": base_array, **coords_arrays} + + def test_valid(self) -> None: + """A dataset with consistent coordinates and no grid mapping validates.""" + ds = Dataset(attributes=DatasetAttrs(), members=self._members()) + assert isinstance(ds, Dataset) + + def test_missing_grid_mapping_variable(self) -> None: + """A member declaring a grid_mapping that is not in the dataset fails validation.""" + members = self._members() + band = members["band"] + members["band"] = band.model_copy( + update={"attributes": band.attributes.model_copy(update={"grid_mapping": "nope"})} + ) + with pytest.raises(ValidationError, match="Grid mapping variable 'nope'"): + Dataset(attributes=DatasetAttrs(), members=members) diff --git a/tests/test_geozarr_output_contract.py b/tests/test_geozarr_output_contract.py new file mode 100644 index 00000000..f968c938 --- /dev/null +++ b/tests/test_geozarr_output_contract.py @@ -0,0 +1,157 @@ +"""Cross-product output contract. + +Reprojection to a regular grid with a declared CRS is a hard requirement for +every converted product (see +docs/superpowers/specs/2026-07-27-s3-olci-reprojection-design.md). One +parametrized test walks each converter's output and asserts the contract at +every multiscale level. Products whose converter has not yet migrated off the +legacy nested layout carry an xfail on the whole-store DataTree check so the +requirement stays on record. + +Per-level CRS detection requires opening each level with +``decode_coords="all"`` (the generic converter's own read path uses the same +flag, see geozarr.py) so the CF `grid_mapping`/`spatial_ref` reference gets +promoted into a coordinate; the default `xr.open_dataset` decode never does +this. Separately, S1/S2 overview sub-groups (r2, r4, ...) still lack the +zarr-cm proj:/spatial: convention attrs that OLCI stamps on every level — a +real design-consistency gap, but not one that defeats CRS detection here, so +it is tracked outside this test rather than xfailed. +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING +from unittest.mock import patch + +import numpy as np +import pytest +import rioxarray # noqa: F401 +import xarray as xr +import zarr +from pyproj import CRS as ProjCRS + +from eopf_geozarr.conversion import create_geozarr_dataset +from eopf_geozarr.s3_olci_optimization.olci_converter import convert_olci_optimized + +from .test_integration_sentinel1 import MockSentinel1L1GRDBuilder +from .test_integration_sentinel2 import build_sample_sentinel2_datatree +from .test_olci_integration import build_synthetic_olci + +if TYPE_CHECKING: + import pathlib + from collections.abc import Callable + + +def _convert_olci(tmp: pathlib.Path) -> pathlib.Path: + out = tmp / "olci.zarr" + convert_olci_optimized( + build_synthetic_olci(rows=256, cols=256), output_path=str(out), min_dimension=64 + ) + return out + + +def _convert_s1(tmp: pathlib.Path) -> pathlib.Path: + out = tmp / "s1.zarr" + dt = MockSentinel1L1GRDBuilder("20170508T164830_0025_A094_8604_01B54C").build() + with patch("eopf_geozarr.conversion.geozarr.print"): + create_geozarr_dataset( + dt, + groups=["measurements"], + output_path=str(out), + gcp_group="conditions/gcp", + ) + return out + + +def _convert_s2(tmp: pathlib.Path) -> pathlib.Path: + out = tmp / "s2.zarr" + with patch("eopf_geozarr.conversion.geozarr.print"): + create_geozarr_dataset( + build_sample_sentinel2_datatree(), + groups=["/measurements/reflectance/r10m"], + output_path=str(out), + ) + return out + + +PRODUCT_CONVERTERS: dict[str, Callable[[pathlib.Path], pathlib.Path]] = { + "olci": _convert_olci, + "s1": _convert_s1, + "s2": _convert_s2, +} + +#: Converters that still write the legacy layout (native at group root with +#: asset "."), which xr.open_datatree rejects. The xfail keeps the hard +#: requirement on record until the generic converter migrates (cf. PR #212). +DATATREE_XFAIL: dict[str, str] = { + "s1": "generic converter still writes asset='.' nested overview layout", + "s2": "generic converter still writes asset='.' nested overview layout", +} + + +@pytest.fixture(scope="module", params=sorted(PRODUCT_CONVERTERS), ids=str) +def converted_store( + request: pytest.FixtureRequest, tmp_path_factory: pytest.TempPathFactory +) -> tuple[pathlib.Path, str]: + name = str(request.param) + store = PRODUCT_CONVERTERS[name](tmp_path_factory.mktemp(name)) + return store, name + + +def _multiscale_level_paths(store: pathlib.Path) -> list[str]: + """Every pyramid-level group path, discovered via multiscales layout attrs.""" + root = zarr.open_group(str(store), mode="r") + found: list[str] = [] + + def walk(group: zarr.Group, path: str) -> None: + attrs = dict(group.attrs) + multiscales = attrs.get("multiscales") + if isinstance(multiscales, dict): + layout = multiscales.get("layout") + assert isinstance(layout, list) + for entry in layout: + assert isinstance(entry, dict) + asset = entry["asset"] + assert isinstance(asset, str) + found.append(path if asset == "." else f"{path}/{asset}" if path else asset) + for key in group.group_keys(): + child = group[key] + assert isinstance(child, zarr.Group) + walk(child, f"{path}/{key}" if path else key) + + walk(root, "") + return found + + +def test_every_level_is_regular_grid_with_crs( + converted_store: tuple[pathlib.Path, str], +) -> None: + """Hard requirement: each pyramid level is a regular grid with a real CRS.""" + store, name = converted_store + levels = _multiscale_level_paths(store) + assert levels, f"{name}: no multiscale groups found in {store}" + for level in levels: + ds = xr.open_dataset( + str(store), group=level, engine="zarr", consolidated=False, decode_coords="all" + ) + crs = ds.rio.crs + assert crs is not None, f"{name}:{level}: no CRS declared" + # CRS round-trips through pyproj + ProjCRS.from_user_input(crs.to_wkt()) + for dim in ("y", "x"): + assert dim in ds.sizes, f"{name}:{level}: missing spatial dim {dim}" + coord = ds[dim] + assert coord.ndim == 1, f"{name}:{level}: {dim} coordinate is not 1-D" + steps = np.diff(coord.values) + assert np.allclose(steps, steps[0]), ( + f"{name}:{level}: {dim} coordinate spacing is not regular" + ) + ds.close() + + +def test_store_opens_as_datatree(converted_store: tuple[pathlib.Path, str]) -> None: + """Hard requirement: the whole store opens with xr.open_datatree.""" + store, name = converted_store + if name in DATATREE_XFAIL: + pytest.xfail(DATATREE_XFAIL[name]) + xr.open_datatree(str(store), engine="zarr", consolidated=False, chunks={}) diff --git a/tests/test_integration_sentinel2.py b/tests/test_integration_sentinel2.py index 91b6b7bc..96cf50ba 100644 --- a/tests/test_integration_sentinel2.py +++ b/tests/test_integration_sentinel2.py @@ -27,10 +27,8 @@ ) -@pytest.fixture -def sample_sentinel2_datatree() -> xr.DataTree: - """ - Create a sample Sentinel-2 EOPF DataTree structure for testing. +def build_sample_sentinel2_datatree() -> xr.DataTree: + """Build the sample Sentinel-2 EOPF DataTree (importable, non-fixture form). This mimics the structure from the notebook: - Multiple resolution groups (r10m, r20m, r60m) @@ -221,6 +219,12 @@ def sample_sentinel2_datatree() -> xr.DataTree: return dt +@pytest.fixture +def sample_sentinel2_datatree() -> xr.DataTree: + """Create a sample Sentinel-2 EOPF DataTree structure for testing.""" + return build_sample_sentinel2_datatree() + + @pytest.fixture def temp_output_dir() -> Generator[str, None, None]: """Create a temporary directory for test outputs.""" diff --git a/tests/test_olci_band_mapping.py b/tests/test_olci_band_mapping.py new file mode 100644 index 00000000..8fca56c7 --- /dev/null +++ b/tests/test_olci_band_mapping.py @@ -0,0 +1,25 @@ +from eopf_geozarr.s3_olci_optimization.olci_band_mapping import ( + OLCI_BAND_INFO, + OLCI_BANDS, + RADIANCE_DTYPE, + OlciBandInfo, +) + + +def test_there_are_21_olci_bands() -> None: + assert len(OLCI_BANDS) == 21 + assert OLCI_BANDS[0] == "oa01_radiance" + assert OLCI_BANDS[-1] == "oa21_radiance" + + +def test_every_band_has_info() -> None: + assert set(OLCI_BAND_INFO) == set(OLCI_BANDS) + for name, info in OLCI_BAND_INFO.items(): + assert isinstance(info, OlciBandInfo) + assert info.name == name + assert info.data_type == RADIANCE_DTYPE + assert info.wavelength_center > 0 + + +def test_first_band_wavelength() -> None: + assert OLCI_BAND_INFO["oa01_radiance"].wavelength_center == 400.0 diff --git a/tests/test_olci_integration.py b/tests/test_olci_integration.py new file mode 100644 index 00000000..c40ab17f --- /dev/null +++ b/tests/test_olci_integration.py @@ -0,0 +1,526 @@ +"""Integration tests for convert_olci_optimized.""" + +from __future__ import annotations + +import json +import subprocess +import sys +from pathlib import Path +from typing import TYPE_CHECKING + +import numpy as np +import rioxarray # noqa: F401 +import xarray as xr +import zarr +from pydantic_zarr.core import tuplify_json +from pydantic_zarr.v3 import GroupSpec + +from eopf_geozarr.s3_olci_optimization.olci_converter import ( + _sanitize_olci_array_attrs_keep_fill, +) + +if TYPE_CHECKING: + import pathlib + +from eopf_geozarr.s3_olci_optimization.olci_converter import convert_olci_optimized + + +def build_synthetic_olci(rows: int = 512, cols: int = 480) -> xr.DataTree: + """Minimal synthetic OLCI L1 EFR datatree (measurements only). + + Geolocation is an axis-aligned ~300 m grid (0.003 deg spacing) so the + dataset is genuinely warpable to a regular lat/lon grid. + """ + rng = np.random.default_rng(0) + lat_1d = np.linspace(45.0, 45.0 + 0.003 * (rows - 1), rows) + lon_1d = np.linspace(10.0, 10.0 + 0.003 * (cols - 1), cols) + lat = np.repeat(lat_1d[:, None], cols, axis=1) + lon = np.repeat(lon_1d[None, :], rows, axis=0) + alt = np.zeros((rows, cols), dtype="int16") + data: dict[str, xr.DataArray] = {} + for i in range(1, 22): + name = f"oa{i:02d}_radiance" + arr = xr.DataArray( + rng.integers(0, 6000, (rows, cols)).astype("uint16"), + dims=("rows", "columns"), + attrs={ + "scale_factor": 0.0139, + "add_offset": 0.0, + "standard_name": "toa_upwelling_spectral_radiance", + "coordinates": "latitude longitude altitude", + }, + ) + data[name] = arr + ds = xr.Dataset( + data, + coords={ + "latitude": (("rows", "columns"), lat, {"standard_name": "latitude"}), + "longitude": (("rows", "columns"), lon, {"standard_name": "longitude"}), + "altitude": (("rows", "columns"), alt, {"standard_name": "altitude"}), + }, + ) + return xr.DataTree.from_dict({"/measurements": ds}) + + +def test_convert_olci_writes_measurements(tmp_path: object) -> None: + """Native-resolution measurements group must contain all 21 radiance bands.""" + import zarr + + dt = build_synthetic_olci() + out = str(tmp_path / "olci_geozarr.zarr") # type: ignore[operator] + convert_olci_optimized(dt, output_path=out) + + g = zarr.open_group(out, mode="r") + # native measurements present + assert "measurements" in g + # all 21 bands at native res, in the r0 base-level group + meas = g["measurements"] + assert isinstance(meas, zarr.Group) + r0 = meas["r0"] + assert isinstance(r0, zarr.Group) + for i in range(1, 22): + assert f"oa{i:02d}_radiance" in r0 + + +def test_convert_olci_creates_overviews(tmp_path: object) -> None: + """Overview subgroups must only be written when BOTH post-decimation dims >= min_dimension. + + Case 1 — 512x480 with min_dimension=256: + 480//2 = 240 < 256, so the guard fires immediately → zero overview levels. + + Case 2 — 1024x1024 with min_dimension=256: + the warped grid stays close to 1024x1024, yielding exactly two + overview levels; each halves the previous and the deepest would drop + below min_dimension if halved again. + """ + import zarr + + # --- Case 1: 512x480, min_dimension=256 → zero overview levels --- + dt1 = build_synthetic_olci(rows=512, cols=480) + out1 = str(tmp_path / "olci_case1.zarr") # type: ignore[operator] + convert_olci_optimized(dt1, output_path=out1, min_dimension=256) + + g1 = zarr.open_group(out1, mode="r") + meas1 = g1["measurements"] + assert isinstance(meas1, zarr.Group) + subgroups1 = sorted(meas1.group_keys()) + assert subgroups1 == ["r0"], ( + f"Expected only the r0 base level for 512x480 at min_dimension=256, got {subgroups1}" + ) + + # --- Case 2: 1024x1024, min_dimension=256 → exactly two valid levels --- + dt2 = build_synthetic_olci(rows=1024, cols=1024) + out2 = str(tmp_path / "olci_case2.zarr") # type: ignore[operator] + convert_olci_optimized(dt2, output_path=out2, min_dimension=256) + + g2 = zarr.open_group(out2, mode="r") + meas2 = g2["measurements"] + assert isinstance(meas2, zarr.Group) + subgroups2 = sorted(meas2.group_keys()) + assert subgroups2 == ["r0", "r2", "r4"], ( + f"Expected r0 + exactly 2 overview levels for 1024x1024 at min_dimension=256, " + f"got {subgroups2}" + ) + + # Every level must have BOTH spatial dims >= min_dimension, and each + # overview must be exactly half the previous level (floor division). + r0_2 = meas2["r0"] + assert isinstance(r0_2, zarr.Group) + band0 = r0_2["oa01_radiance"] + assert isinstance(band0, zarr.Array) + prev_shape = band0.shape + for sg_name in [k for k in subgroups2 if k != "r0"]: + sg = meas2[sg_name] + assert isinstance(sg, zarr.Group) + band = sg["oa01_radiance"] + assert isinstance(band, zarr.Array) + assert band.shape[0] == prev_shape[0] // 2 + assert band.shape[1] == prev_shape[1] // 2 + assert band.shape[0] >= 256 + assert band.shape[1] >= 256 + prev_shape = band.shape + + # The deepest level would violate min_dimension if halved again. + assert prev_shape[0] // 2 < 256 or prev_shape[1] // 2 < 256 + + +def test_convert_olci_returns_datatree(tmp_path: object) -> None: + """convert_olci_optimized must return an xr.DataTree backed by the output store.""" + dt = build_synthetic_olci(rows=256, cols=256) + out = str(tmp_path / "olci_geozarr.zarr") # type: ignore[operator] + result = convert_olci_optimized(dt, output_path=out, min_dimension=256) + assert isinstance(result, xr.DataTree) + assert "/measurements" in result.groups + + +def test_convert_olci_output_opens_as_datatree(tmp_path: object) -> None: + """Acceptance: the exported store is a regular grid with CRS at every level. + + xr.open_datatree must open the whole store; measurements/r0 holds the + warped native-resolution grid with 1-D y/x coordinates and a declared + CRS, overview siblings halve it, and the multiscales layout references + the base level by name. + """ + dt = build_synthetic_olci(rows=1024, cols=1024) + out = str(tmp_path / "olci_geozarr.zarr") # type: ignore[operator] + result = convert_olci_optimized(dt, output_path=out, min_dimension=256) + + opened = xr.open_datatree(out, engine="zarr", consolidated=False, chunks={}) + + r0 = opened["/measurements/r0"].to_dataset() + assert set(r0.sizes) == {"y", "x"} + for i in range(1, 22): + assert f"oa{i:02d}_radiance" in r0 + # CRS declared at every level, 1-D regular coordinates + for level in ("r0", "r2", "r4"): + ds = opened[f"/measurements/{level}"].to_dataset() + assert ds.rio.crs is not None, f"{level}: no CRS" + assert ds.rio.crs.to_epsg() == 4326 + for dim in ("y", "x"): + coord = ds[dim] + assert coord.ndim == 1 + steps = np.diff(coord.values) + assert np.allclose(steps, steps[0]) + band = ds["oa01_radiance"] + assert band.attrs["grid_mapping"] == "spatial_ref" + # halving structure relative to observed r0 + r2 = opened["/measurements/r2"].to_dataset() + assert r2.sizes["y"] == r0.sizes["y"] // 2 + assert r2.sizes["x"] == r0.sizes["x"] // 2 + + # measurements itself holds only convention metadata + meas = opened["/measurements"].to_dataset() + assert len(meas.data_vars) == 0 + + meas_attrs = dict(zarr.open_group(out, mode="r")["measurements"].attrs) + multiscales = meas_attrs["multiscales"] + assert isinstance(multiscales, dict) + layout = multiscales["layout"] + assert isinstance(layout, list) + assert layout[0] == {"asset": "r0"} + # per-level geo-proj convention present + meas_group = zarr.open_group(out, mode="r")["measurements"] + assert isinstance(meas_group, zarr.Group) + r0_group = meas_group["r0"] + assert isinstance(r0_group, zarr.Group) + r0_attrs = dict(r0_group.attrs) + assert "proj:code" in r0_attrs + + assert "/measurements/r0" in result.groups + assert "/measurements/r2" in result.groups + + +def test_convert_olci_conditions_quality_passthrough(tmp_path: object) -> None: + """conditions and quality groups, when present, are copied through unchanged.""" + import zarr + + # Build a tree with conditions and quality groups + rng = np.random.default_rng(1) + rows, cols = 128, 128 + lat_1d = np.linspace(45.0, 45.0 + 0.003 * (rows - 1), rows) + lon_1d = np.linspace(10.0, 10.0 + 0.003 * (cols - 1), cols) + lat = np.repeat(lat_1d[:, None], cols, axis=1) + lon = np.repeat(lon_1d[None, :], rows, axis=0) + alt = np.zeros((rows, cols), dtype="int16") + + meas_data: dict[str, xr.DataArray] = { + "oa01_radiance": xr.DataArray( + rng.integers(0, 6000, (rows, cols)).astype("uint16"), + dims=("rows", "columns"), + ) + } + meas_ds = xr.Dataset( + meas_data, + coords={ + "latitude": (("rows", "columns"), lat), + "longitude": (("rows", "columns"), lon), + "altitude": (("rows", "columns"), alt), + }, + ) + cond_ds = xr.Dataset( + { + "wind_speed": xr.DataArray( + rng.random((rows, cols)).astype("float32"), dims=("rows", "columns") + ) + } + ) + quality_ds = xr.Dataset( + { + "flags": xr.DataArray( + rng.integers(0, 255, (rows, cols)).astype("uint8"), dims=("rows", "columns") + ) + } + ) + # Build a measurements/orphans sub-dataset to verify child subgroup copy. + orphans_ds = xr.Dataset( + { + "removed_count": xr.DataArray( + rng.integers(0, 10, (rows,)).astype("int32"), dims=("rows",) + ) + } + ) + dt = xr.DataTree.from_dict( + { + "/measurements": meas_ds, + "/measurements/orphans": orphans_ds, + "/conditions": cond_ds, + "/quality": quality_ds, + } + ) + + out = str(tmp_path / "olci_geozarr.zarr") # type: ignore[operator] + convert_olci_optimized(dt, output_path=out, min_dimension=64) + + g = zarr.open_group(out, mode="r") + assert "conditions" in g + assert "quality" in g + # measurements/orphans subgroup must have been copied through. + assert "orphans" in g["measurements"] + + +def test_cli_convert_s3_olci_optimized(tmp_path: pathlib.Path) -> None: + """convert-s3-olci-optimized subcommand must write a GeoZarr measurements group.""" + import zarr + + # materialise a synthetic OLCI product to a zarr v2 store on disk + dt = build_synthetic_olci(rows=300, cols=300) + src = tmp_path / "olci_src.zarr" + dt.to_zarr(src, mode="w", consolidated=False) + out = tmp_path / "olci_out.zarr" + result = subprocess.run( + [ + sys.executable, + "-m", + "eopf_geozarr", + "convert-s3-olci-optimized", + str(src), + str(out), + "--spatial-chunk", + "256", + ], + capture_output=True, + text=True, + timeout=300, + ) + assert result.returncode == 0, result.stdout + result.stderr + g = zarr.open_group(str(out), mode="r") + assert "measurements" in g + + +def _assert_radiance_dtype_and_attrs( + group: zarr.Group, band_name: str, *, level_label: str +) -> None: + """Assert that *band_name* in *group* is uint16 with scale_factor and no stale attrs. + + This is a regression guard: the converter must preserve raw integer storage + and CF scale/offset, and must strip source-only attrs (_eopf_attrs, dtype, + valid_min, valid_max). + """ + band = group[band_name] + assert isinstance(band, zarr.Array), f"{level_label}/{band_name} is not a zarr.Array" + assert band.dtype == np.dtype("uint16"), ( + f"{level_label}/{band_name}: expected uint16, got {band.dtype}" + ) + attrs = dict(band.attrs) + assert "scale_factor" in attrs, ( + f"{level_label}/{band_name}: scale_factor missing from attrs (got {list(attrs)})" + ) + for stale_key in ("_eopf_attrs", "dtype", "valid_min", "valid_max"): + assert stale_key not in attrs, ( + f"{level_label}/{band_name}: stale attr '{stale_key}' present in output attrs" + ) + + +def test_olci_conversion_matches_snapshot( + s3_olci_group_example: pathlib.Path, + tmp_path: pathlib.Path, +) -> None: + """Snapshot test: converted OLCI structure must match committed golden file. + + The fixture is a Zarr v2 store representing a real OLCI L1 EFR product. + We open the whole DataTree so that conditions, quality, and + measurements/orphans subgroups are included in the conversion. + The fixture uses the real product's dimension names: tie-point grids reuse + 'columns' (at size 4) while measurement grids also use 'columns' (at size 16); + orphan arrays use removed_pixels=4. + + ``min_dimension=8`` is used so that the 16x16 measurements grid generates + one overview level (r2 at 8x8). + + To (re)generate the snapshot, uncomment the regeneration block below, + run the test once, then re-comment before committing. + """ + # The JSON fixture materializes arrays as zeros; zero lat/lon is a + # degenerate geolocation the warp rejects. Seed a plausible grid. + # + # NOTE: the fixture's latitude/longitude arrays are stored raw as int32 + # with a CF scale_factor of 1e-6 (real degrees = raw * scale_factor), and + # this test opens the datatree with mask_and_scale=False, so xarray hands + # reproject_olci the *raw* int32 values unscaled. A ~300 m (0.003 deg) + # spacing collapses to a single truncated integer across this fixture's + # small 16-row/16-col grid, which is degenerate. Use whole-degree spacing + # instead so each row/column truncates to a distinct raw value. + fixture_group = zarr.open_group(str(s3_olci_group_example), mode="a") + fixture_meas = fixture_group["measurements"] + assert isinstance(fixture_meas, zarr.Group) + lat_arr = fixture_meas["latitude"] + assert isinstance(lat_arr, zarr.Array) + ny, nx = lat_arr.shape + lat_1d = np.linspace(45.0, 45.0 + 1.0 * (ny - 1), ny) + lon_1d = np.linspace(10.0, 10.0 + 1.0 * (nx - 1), nx) + lat_arr[:] = np.repeat(lat_1d[:, None], nx, axis=1) + lon_arr = fixture_meas["longitude"] + assert isinstance(lon_arr, zarr.Array) + lon_arr[:] = np.repeat(lon_1d[None, :], ny, axis=0) + + dt_in = xr.open_datatree( + str(s3_olci_group_example), + engine="zarr", + consolidated=False, + chunks={}, + mask_and_scale=False, + ) + out = str(tmp_path / "out.zarr") + convert_olci_optimized(dt_in, output_path=out, min_dimension=8) + + observed_group = zarr.open_group(out, use_consolidated=False) + observed_structure_json = GroupSpec.from_zarr(observed_group).model_dump() + + expected_path = Path("tests/_test_data/optimized_olci_examples") / ( + s3_olci_group_example.stem + ".json" + ) + + # Uncomment this block to (re)generate the snapshot from the observed structure. + # expected_path.parent.mkdir(parents=True, exist_ok=True) + # expected_path.write_text(json.dumps(observed_structure_json, indent=2, sort_keys=True)) + + observed_structure = GroupSpec(**tuplify_json(observed_structure_json)) + observed_structure_flat = observed_structure.to_flat() + expected_structure_json = tuplify_json(json.loads(expected_path.read_text())) + expected_structure = GroupSpec(**expected_structure_json) + expected_structure_flat = expected_structure.to_flat() + + o_keys = set(observed_structure_flat.keys()) + e_keys = set(expected_structure_flat.keys()) + assert o_keys == e_keys + assert [k for k in o_keys if observed_structure_flat[k] != expected_structure_flat[k]] == [] + + # Dtype/attrs regression guard: radiance must be stored as uint16 with + # scale_factor preserved and stale source attrs absent. + meas_g = observed_group["measurements"] + assert isinstance(meas_g, zarr.Group) + r0_g = meas_g["r0"] + assert isinstance(r0_g, zarr.Group) + _assert_radiance_dtype_and_attrs(r0_g, "oa01_radiance", level_label="r0") + if "r2" in meas_g: + r2_g = meas_g["r2"] + assert isinstance(r2_g, zarr.Group) + _assert_radiance_dtype_and_attrs(r2_g, "oa01_radiance", level_label="r2") + + +def test_convert_olci_odd_dims_overview_no_conflicting_sizes(tmp_path: object) -> None: + """Overview groups written from an odd-dimensioned swath must open without errors. + + Regression test for the off-by-one bug in reduce_swath where coordinate + decimation via [::factor] produced ceil(N/factor) elements while + coarsen(boundary="trim") produced floor(N/factor) for the radiance data. + On an odd-column real OLCI product (4865 cols) this caused xr.open_dataset + to raise ``ValueError: conflicting sizes for dimension 'columns'``. + + We use rows=10, cols=9 (odd cols) with min_dimension=4. Once warped to a + regular grid the exact base size need not match the swath input, so this + asserts coord/data length agreement and floor-halving structure at every + level rather than a specific (5, 4) shape. + """ + dt = build_synthetic_olci(rows=10, cols=9) + out = str(tmp_path / "odd_olci.zarr") # type: ignore[operator] + convert_olci_optimized(dt, output_path=out, min_dimension=4) + + # Determine which overview groups were written. + import zarr as _zarr + + g = _zarr.open_group(out, mode="r") + meas = g["measurements"] + assert isinstance(meas, _zarr.Group) + level_keys = sorted(meas.group_keys()) + assert level_keys[0] == "r0" + + # Open each level (base + overviews); this must NOT raise a + # conflicting-sizes error, and each level must floor-halve the previous. + prev_shape: tuple[int, ...] | None = None + for lvl in level_keys: + ds = xr.open_dataset(out, engine="zarr", group=f"measurements/{lvl}", consolidated=False) + rad_shape = ds["oa01_radiance"].shape + assert rad_shape == (ds["y"].size, ds["x"].size), ( + f"measurements/{lvl}: data shape {rad_shape} != coord sizes " + f"(y={ds['y'].size}, x={ds['x'].size})" + ) + if prev_shape is not None: + assert rad_shape[0] == prev_shape[0] // 2 + assert rad_shape[1] == prev_shape[1] // 2 + prev_shape = rad_shape + ds.close() + + +def test_sanitize_olci_array_attrs_strips_stale_keeps_fill_value() -> None: + """_sanitize_olci_array_attrs_keep_fill must strip stale source attrs and preserve _FillValue. + + Unlike the shared sanitize_array_attrs (which always strips _FillValue), + the OLCI-local helper must preserve _FillValue so that downstream readers + and reduce_swath can identify fill pixels on raw uint16 data opened with + mask_and_scale=False. + """ + attrs: dict[str, object] = { + "_eopf_attrs": {"source": "some blob"}, + "dtype": "uint16", + "valid_min": 0, + "valid_max": 65534, + "scale_factor": 0.0139, + "add_offset": 0.0, + "_FillValue": 65535, + "units": "W m-2 sr-1 um-1", + "standard_name": "toa_upwelling_spectral_radiance", + "coordinates": "latitude longitude altitude", + } + result = _sanitize_olci_array_attrs_keep_fill(attrs) + # Stale source-only attrs must be removed. + assert "_eopf_attrs" not in result, "_eopf_attrs must be stripped" + assert "dtype" not in result, "dtype must be stripped" + assert "valid_min" not in result, "valid_min must be stripped" + assert "valid_max" not in result, "valid_max must be stripped" + # CF and fill attrs must be preserved. + assert result.get("scale_factor") == 0.0139, "scale_factor must be preserved" + assert result.get("add_offset") == 0.0, "add_offset must be preserved" + assert result.get("_FillValue") == 65535, "_FillValue must be preserved for OLCI raw uint16" + assert result.get("units") == "W m-2 sr-1 um-1", "units must be preserved" + assert result.get("standard_name") == "toa_upwelling_spectral_radiance" + assert result.get("coordinates") == "latitude longitude altitude" + + +def test_convert_olci_rerun_removes_stale_overview_groups(tmp_path: object) -> None: + """Re-running against an existing output path must not leave stale groups. + + The first run (small min_dimension) produces more overview levels than the + second; without up-front store truncation the extra r{N} groups from run + one would survive run two. + """ + import zarr + + out = str(tmp_path / "olci_geozarr.zarr") # type: ignore[operator] + convert_olci_optimized( + build_synthetic_olci(rows=256, cols=256), output_path=out, min_dimension=64 + ) + root = zarr.open_group(out, mode="r") + meas = root["measurements"] + assert isinstance(meas, zarr.Group) + levels_first = {k for k in meas.group_keys() if k.startswith("r")} + assert "r4" in levels_first + + convert_olci_optimized( + build_synthetic_olci(rows=256, cols=256), output_path=out, min_dimension=128 + ) + root = zarr.open_group(out, mode="r") + meas = root["measurements"] + assert isinstance(meas, zarr.Group) + levels_second = {k for k in meas.group_keys() if k.startswith("r")} + assert levels_second == {"r0", "r2"}, f"stale overview groups survived re-run: {levels_second}" diff --git a/tests/test_olci_multiscale.py b/tests/test_olci_multiscale.py new file mode 100644 index 00000000..88a8db44 --- /dev/null +++ b/tests/test_olci_multiscale.py @@ -0,0 +1,437 @@ +"""Tests for olci_multiscale: decimate_swath, reduce_swath, grid_spatial_attrs.""" + +from __future__ import annotations + +import numpy as np +import pytest +import rasterio.transform +import xarray as xr + +from eopf_geozarr.s3_olci_optimization.olci_multiscale import ( + decimate_swath, + grid_spatial_attrs, + reduce_swath, +) + + +def _geodesic_center(lat_deg: np.ndarray, lon_deg: np.ndarray) -> tuple[float, float]: + """Reference spherical centroid of a set of lat/lon positions, in degrees.""" + lat = np.deg2rad(np.asarray(lat_deg, dtype="float64")) + lon = np.deg2rad(np.asarray(lon_deg, dtype="float64")) + x = float((np.cos(lat) * np.cos(lon)).mean()) + y = float((np.cos(lat) * np.sin(lon)).mean()) + z = float(np.sin(lat).mean()) + return ( + float(np.rad2deg(np.arctan2(z, np.hypot(x, y)))), + float(np.rad2deg(np.arctan2(y, x))), + ) + + +def _swath(rows: int = 8, cols: int = 6) -> xr.Dataset: + """Minimal synthetic swath dataset with one radiance band and two coords.""" + rad = xr.DataArray( + np.arange(rows * cols, dtype="uint16").reshape(rows, cols), + dims=("rows", "columns"), + attrs={ + "scale_factor": 0.5, + "units": "mW.m-2.sr-1.nm-1", + "_FillValue": 65535, + }, + ) + lat = xr.DataArray( + np.linspace(0, 1, rows * cols).reshape(rows, cols), + dims=("rows", "columns"), + attrs={"standard_name": "latitude"}, + ) + lon = xr.DataArray( + np.linspace(10, 11, rows * cols).reshape(rows, cols), + dims=("rows", "columns"), + attrs={"standard_name": "longitude"}, + ) + return xr.Dataset( + {"oa01_radiance": rad}, + coords={"latitude": lat, "longitude": lon}, + ) + + +# --------------------------------------------------------------------------- +# decimate_swath tests +# --------------------------------------------------------------------------- + + +def test_decimate_halves_each_axis() -> None: + out = decimate_swath(_swath(8, 6), factor=2) + assert out["oa01_radiance"].shape == (4, 3) + assert out["latitude"].shape == (4, 3) + assert out["longitude"].shape == (4, 3) + + +def test_decimate_takes_every_other_pixel() -> None: + ds = _swath(8, 6) + out = decimate_swath(ds, factor=2) + # top-left pixel is preserved exactly (no averaging) + assert int(out["oa01_radiance"].values[0, 0]) == 0 + assert float(out["latitude"].values[0, 0]) == 0.0 + # interior pixel: stride-2 decimation means out[1, 1] comes from original [2, 2] + assert int(out["oa01_radiance"].values[1, 1]) == int(ds["oa01_radiance"].values[2, 2]) + + +def test_decimate_preserves_attrs() -> None: + out = decimate_swath(_swath(8, 6), factor=2) + assert out["oa01_radiance"].attrs["scale_factor"] == 0.5 + assert out["latitude"].attrs["standard_name"] == "latitude" + + +def test_decimate_factor_1_returns_unchanged() -> None: + ds = _swath(8, 6) + out = decimate_swath(ds, factor=1) + assert out["oa01_radiance"].shape == (8, 6) + + +def test_decimate_invalid_factor_raises() -> None: + with pytest.raises(ValueError, match="factor must be >= 1"): + decimate_swath(_swath(), factor=0) + + +# --------------------------------------------------------------------------- +# reduce_swath tests +# --------------------------------------------------------------------------- + + +def test_reduce_swath_halves_each_axis() -> None: + """reduce_swath must produce output with halved spatial dims.""" + out = reduce_swath(_swath(8, 6), factor=2) + assert out["oa01_radiance"].shape == (4, 3) + assert out["latitude"].shape == (4, 3) + assert out["longitude"].shape == (4, 3) + + +def test_reduce_swath_radiance_is_averaged_not_decimated() -> None: + """Radiance must be block-averaged; top-left output != top-left input (unless accident).""" + rng = np.random.default_rng(42) + rad_data = rng.integers(100, 200, (8, 6)).astype("uint16") + rad = xr.DataArray( + rad_data, + dims=("rows", "columns"), + attrs={"_FillValue": 65535}, + ) + ds = xr.Dataset({"oa01_radiance": rad}) + out = reduce_swath(ds, factor=2) + # block [0:2, 0:2] averages to a value; verify it's a rounded mean + expected_block = int(np.round(rad_data[0:2, 0:2].astype("float64").mean())) + assert int(out["oa01_radiance"].values[0, 0]) == expected_block + + +def test_reduce_swath_altitude_is_block_averaged() -> None: + """Altitude gets the fill-aware block mean, not stride decimation. + + A stride sample would locate the overview cell's altitude ~half a block + away from the geodesic-centroid lat/lon describing the same cell. + """ + fill = -32768 + alt = xr.DataArray( + np.array([[100, 200], [300, fill]], dtype="int16"), + dims=("rows", "columns"), + attrs={"standard_name": "altitude", "_FillValue": fill}, + ) + lat = xr.DataArray( + np.zeros((2, 2)), dims=("rows", "columns"), attrs={"standard_name": "latitude"} + ) + lon = xr.DataArray( + np.zeros((2, 2)), dims=("rows", "columns"), attrs={"standard_name": "longitude"} + ) + ds = xr.Dataset(coords={"latitude": lat, "longitude": lon, "altitude": alt}) + out = reduce_swath(ds, factor=2) + # Mean of the three valid pixels (fill excluded), not alt[0, 0] == 100. + assert int(out["altitude"].values[0, 0]) == 200 + assert out["altitude"].dtype == np.dtype("int16") + assert out["altitude"].attrs["standard_name"] == "altitude" + + +def test_reduce_swath_fill_value_preserved_in_all_fill_block() -> None: + """A block where all pixels are fill must produce fill output, not 65535.0 average.""" + fill = 65535 + rad_data = np.ones((4, 4), dtype="uint16") * fill + # put some non-fill values only in lower-right block + rad_data[2:4, 2:4] = 100 + rad = xr.DataArray( + rad_data, + dims=("rows", "columns"), + attrs={"_FillValue": fill}, + ) + ds = xr.Dataset({"oa01_radiance": rad}) + out = reduce_swath(ds, factor=2) + # top-left block: all fill -> output must be fill + assert int(out["oa01_radiance"].values[0, 0]) == fill + # bottom-right block: all 100 -> output must be 100 + assert int(out["oa01_radiance"].values[1, 1]) == 100 + + +def test_reduce_swath_preserves_attrs() -> None: + """reduce_swath must carry over variable attributes.""" + out = reduce_swath(_swath(8, 6), factor=2) + assert out["oa01_radiance"].attrs["scale_factor"] == 0.5 + assert out["latitude"].attrs["standard_name"] == "latitude" + + +def test_reduce_swath_factor_1_returns_unchanged() -> None: + ds = _swath(8, 6) + out = reduce_swath(ds, factor=1) + assert out["oa01_radiance"].shape == (8, 6) + + +def test_reduce_swath_invalid_factor_raises() -> None: + with pytest.raises(ValueError, match="factor must be >= 1"): + reduce_swath(_swath(), factor=0) + + +def test_reduce_swath_non_swath_var_passthrough() -> None: + """Variables that don't span (rows, columns) must pass through unchanged.""" + ds = _swath(8, 6) + scalar = xr.DataArray(42.0, attrs={"info": "scalar"}) + ds = ds.assign({"extra": scalar}) + out = reduce_swath(ds, factor=2) + assert "extra" in out + assert float(out["extra"].values) == 42.0 + + +# --------------------------------------------------------------------------- +# odd-dimension regression tests (real OLCI: 4865 columns is odd) +# --------------------------------------------------------------------------- + + +def _swath_odd(rows: int = 7, cols: int = 5) -> xr.Dataset: + """Synthetic swath with ODD spatial dimensions. + + Matches the real-world scenario where OLCI products have 4865 columns + (odd). Before the fix, reduce_swath on an odd-sized dimension produced + coordinate arrays one element longer than the corresponding radiance data + (ceil vs floor of N/factor), causing xr.open_dataset to raise a + conflicting-sizes error. + """ + fill = 65535 + rad = xr.DataArray( + np.arange(rows * cols, dtype="uint16").reshape(rows, cols), + dims=("rows", "columns"), + attrs={ + "scale_factor": 0.5, + "units": "mW.m-2.sr-1.nm-1", + "_FillValue": fill, + }, + ) + lat = xr.DataArray( + np.linspace(0, 1, rows * cols).reshape(rows, cols), + dims=("rows", "columns"), + attrs={"standard_name": "latitude"}, + ) + lon = xr.DataArray( + np.linspace(10, 11, rows * cols).reshape(rows, cols), + dims=("rows", "columns"), + attrs={"standard_name": "longitude"}, + ) + return xr.Dataset( + {"oa01_radiance": rad}, + coords={"latitude": lat, "longitude": lon}, + ) + + +def test_reduce_swath_odd_dims_consistent_shape() -> None: + """reduce_swath must produce identical shapes for radiance AND coordinates on odd dims. + + Regression test for the off-by-one bug where coordinate decimation via + [::factor] yields ceil(N/factor) but coarsen(boundary="trim") yields + floor(N/factor). For rows=7, cols=5, factor=2 the expected output shape + is (floor(7/2), floor(5/2)) = (3, 2). + """ + ds = _swath_odd(rows=7, cols=5) + out = reduce_swath(ds, factor=2) + + expected_rows = 7 // 2 # 3 + expected_cols = 5 // 2 # 2 + + assert out["oa01_radiance"].shape == (expected_rows, expected_cols), ( + f"radiance shape {out['oa01_radiance'].shape} != ({expected_rows}, {expected_cols})" + ) + assert out["latitude"].shape == (expected_rows, expected_cols), ( + f"latitude shape {out['latitude'].shape} != ({expected_rows}, {expected_cols})" + ) + assert out["longitude"].shape == (expected_rows, expected_cols), ( + f"longitude shape {out['longitude'].shape} != ({expected_rows}, {expected_cols})" + ) + + +def test_reduce_swath_odd_dims_radiance_is_block_averaged() -> None: + """Radiance values must be block-averaged (not decimated) on odd-dim inputs.""" + rng = np.random.default_rng(7) + rows, cols = 7, 5 + rad_data = rng.integers(100, 200, (rows, cols)).astype("uint16") + rad = xr.DataArray( + rad_data, + dims=("rows", "columns"), + attrs={"_FillValue": 65535}, + ) + ds = xr.Dataset({"oa01_radiance": rad}) + out = reduce_swath(ds, factor=2) + # The top-left output pixel must be the rounded mean of the 2x2 input block. + expected = int(np.round(rad_data[0:2, 0:2].astype("float64").mean())) + assert int(out["oa01_radiance"].values[0, 0]) == expected + + +def test_reduce_swath_odd_simulates_real_olci_columns() -> None: + """Simulate the real-world OLCI case: 4090x4865 (odd cols) -> both 2432 cols. + + Uses smaller proxy dimensions that are proportionally odd to avoid + heavy memory use: rows=10, cols=9 with factor=2 must yield (5, 4) for + both radiance and coordinates. This specifically guards floor vs ceil + on the cols dimension (9 // 2 = 4, not 5). + """ + ds = _swath_odd(rows=10, cols=9) + out = reduce_swath(ds, factor=2) + expected = (10 // 2, 9 // 2) # (5, 4) + assert out["oa01_radiance"].shape == expected, ( + f"radiance shape {out['oa01_radiance'].shape} != {expected}" + ) + assert out["latitude"].shape == expected, ( + f"latitude shape {out['latitude'].shape} != {expected}" + ) + assert out["longitude"].shape == expected, ( + f"longitude shape {out['longitude'].shape} != {expected}" + ) + + +# --------------------------------------------------------------------------- +# grid dims tests (for Task 4: reprojected pyramid) +# --------------------------------------------------------------------------- + + +def test_reduce_swath_on_grid_dims() -> None: + """reduce_swath(dims=("y","x")) block-averages bands and strides 1-D coords. + + After reprojection the pyramid dims are (y, x): bands average fill-aware, + the 1-D dimension coordinates decimate by trimmed stride, and non-spatial + variables (spatial_ref) pass through unchanged. + """ + ny, nx = 6, 5 # odd x exercises the coarsen-trim alignment + band = np.arange(ny * nx, dtype="uint16").reshape(ny, nx) + ds = xr.Dataset( + {"oa01_radiance": (("y", "x"), band, {"_FillValue": 65535})}, + coords={ + "y": ("y", np.linspace(46.0, 45.0, ny)), + "x": ("x", np.linspace(10.0, 11.0, nx)), + "spatial_ref": ((), 0, {"crs_wkt": "stub"}), + }, + ) + out = reduce_swath(ds, factor=2, dims=("y", "x")) + assert dict(out.sizes) == {"y": 3, "x": 2} + # block mean of the top-left 2x2 block, rounded + expected00 = round((band[0, 0] + band[0, 1] + band[1, 0] + band[1, 1]) / 4) + assert int(out["oa01_radiance"].values[0, 0]) == expected00 + # 1-D coords: trimmed stride, lengths match the data + assert out["y"].size == 3 + assert out["x"].size == 2 + np.testing.assert_allclose(out["x"].values, ds["x"].values[0:4:2]) + # scalar passthrough survives + assert "spatial_ref" in out.coords + assert out["spatial_ref"].attrs["crs_wkt"] == "stub" + + +# --------------------------------------------------------------------------- +# grid_spatial_attrs tests +# --------------------------------------------------------------------------- + + +def test_grid_spatial_attrs() -> None: + """grid_spatial_attrs derives dimensions, bbox, and 6-element transform.""" + transform = rasterio.transform.from_origin(10.0, 46.0, 0.01, 0.01) + attrs = grid_spatial_attrs(transform, (100, 200)) + assert attrs["spatial:dimensions"] == ["y", "x"] + assert attrs["spatial:registration"] == "pixel" # type: ignore[index] + assert attrs["spatial:transform"] == [ # type: ignore[index] + 0.01, + 0.0, + 10.0, + 0.0, + -0.01, + 46.0, + ] + # bbox is [xmin, ymin, xmax, ymax] from array_bounds + assert attrs["spatial:bbox"] == [10.0, 45.0, 12.0, 46.0] # type: ignore[index] + + +def test_reduce_fill_collision_nudged_not_recoded_as_fill() -> None: + """A valid block whose mean rounds to the fill sentinel must not become fill. + + Uses a sentinel interior to the data range (a bound sentinel such as 0 or + 65535 cannot be reached by a mean of valid values that all sit on one side + of it): values [999, 1001, 999, 1001] average exactly to _FillValue=1000 + and must be nudged to the neighboring in-range value instead. + """ + rows, cols = 2, 2 + rad = xr.DataArray( + np.array([[999, 1001], [999, 1001]], dtype="uint16"), + dims=("rows", "columns"), + attrs={"_FillValue": 1000}, + ) + lat = xr.DataArray(np.zeros((rows, cols)), dims=("rows", "columns")) + lon = xr.DataArray(np.zeros((rows, cols)), dims=("rows", "columns")) + ds = xr.Dataset({"oa01_radiance": rad}, coords={"latitude": lat, "longitude": lon}) + + out = reduce_swath(ds, factor=2) + value = int(out["oa01_radiance"].values[0, 0]) + assert value != 1000, "valid block was recoded as fill" + assert value == 999 # unrounded mean == sentinel → nudged one step down + + +def test_reduce_all_fill_block_stays_fill() -> None: + """An all-fill block keeps the sentinel value in the overview.""" + rad = xr.DataArray( + np.full((2, 2), 1000, dtype="uint16"), + dims=("rows", "columns"), + attrs={"_FillValue": 1000}, + ) + lat = xr.DataArray(np.zeros((2, 2)), dims=("rows", "columns")) + lon = xr.DataArray(np.zeros((2, 2)), dims=("rows", "columns")) + ds = xr.Dataset({"oa01_radiance": rad}, coords={"latitude": lat, "longitude": lon}) + + out = reduce_swath(ds, factor=2) + assert int(out["oa01_radiance"].values[0, 0]) == 1000 + + +def test_reduce_partially_filled_block_averages_valid_pixels_only() -> None: + """A block mixing fill and valid pixels averages only the valid pixels. + + Block [[100, 200], [300, fill]] with _FillValue=65535 must average the + three valid pixels (200), not collapse to fill or include the sentinel. + """ + rad = xr.DataArray( + np.array([[100, 200], [300, 65535]], dtype="uint16"), + dims=("rows", "columns"), + attrs={"_FillValue": 65535}, + ) + lat = xr.DataArray(np.zeros((2, 2)), dims=("rows", "columns")) + lon = xr.DataArray(np.zeros((2, 2)), dims=("rows", "columns")) + ds = xr.Dataset({"oa01_radiance": rad}, coords={"latitude": lat, "longitude": lon}) + + out = reduce_swath(ds, factor=2) + assert int(out["oa01_radiance"].values[0, 0]) == 200 + + +def test_reduce_transposed_band_still_block_averaged() -> None: + """A radiance band stored as (columns, rows) is averaged, not decimated. + + Swath detection is order-insensitive: the transposed band is normalized to + (rows, columns) and fill-aware block-averaged. Stride decimation would + keep the block's origin value (10) instead of the block mean (25). + """ + rad = xr.DataArray( + np.array([[10, 20], [30, 40]], dtype="uint16"), + dims=("columns", "rows"), + attrs={"_FillValue": 65535}, + ) + lat = xr.DataArray(np.zeros((2, 2)), dims=("rows", "columns")) + lon = xr.DataArray(np.zeros((2, 2)), dims=("rows", "columns")) + ds = xr.Dataset({"oa01_radiance": rad}, coords={"latitude": lat, "longitude": lon}) + + out = reduce_swath(ds, factor=2) + assert tuple(out["oa01_radiance"].dims) == ("rows", "columns") + assert int(out["oa01_radiance"].values[0, 0]) == 25 diff --git a/tests/test_olci_reproject.py b/tests/test_olci_reproject.py new file mode 100644 index 00000000..33aa30fd --- /dev/null +++ b/tests/test_olci_reproject.py @@ -0,0 +1,148 @@ +"""Tests for OLCI swath -> regular grid reprojection.""" + +from __future__ import annotations + +import numpy as np +import pytest +import xarray as xr + +from eopf_geozarr.s3_olci_optimization.olci_reproject import reproject_olci + +FILL = 65535 + + +def build_rotated_swath(rows: int = 64, cols: int = 60, angle_deg: float = 30.0) -> xr.Dataset: + """Synthetic OLCI-like swath: regular grid rotated by *angle_deg* in lon/lat. + + Rotation matters: it makes the dst bounding-box corners fall outside the + swath, exercising real geolocation warping and off-swath fill. + """ + rr, cc = np.meshgrid( + np.arange(rows, dtype="float64"), np.arange(cols, dtype="float64"), indexing="ij" + ) + theta = np.deg2rad(angle_deg) + lon = 10.0 + 0.01 * (cc * np.cos(theta) - rr * np.sin(theta)) + lat = 45.0 + 0.01 * (cc * np.sin(theta) + rr * np.cos(theta)) + + band = (100.0 * rr + cc).astype("uint16") + band[:4, :4] = FILL # a filled block inside the swath + da = xr.DataArray( + band, + dims=("rows", "columns"), + attrs={"scale_factor": 0.0139, "add_offset": 0.0, "_FillValue": FILL}, + ) + # float32 band with no pre-existing _FillValue: nodata defaults to NaN. + solar_flux = xr.DataArray( + (rr + cc).astype("float32"), + dims=("rows", "columns"), + ) + time_stamp = xr.DataArray(np.arange(rows).astype("datetime64[ns]"), dims=("rows",)) + return xr.Dataset( + {"oa01_radiance": da, "solar_flux_proxy": solar_flux}, + coords={ + "latitude": (("rows", "columns"), lat), + "longitude": (("rows", "columns"), lon), + "altitude": (("rows", "columns"), np.full((rows, cols), 7, dtype="int16")), + "time_stamp": time_stamp, + }, + ) + + +def test_reproject_olci_produces_regular_grid_with_crs() -> None: + """One behavior test: grid shape, CRS, dtype, attrs, fill, and dropped vars.""" + ds = build_rotated_swath() + out = reproject_olci(ds) + + # Regular 1-D coordinate grid over (y, x) + assert set(out.sizes) == {"y", "x"} + for dim in ("y", "x"): + coord = out[dim] + assert coord.ndim == 1 + steps = np.diff(coord.values) + assert np.allclose(steps, steps[0]) + # y descends (north-up grid) + assert out["y"].values[0] > out["y"].values[-1] + + # CRS declared in both idioms + assert out.rio.crs is not None + assert out.rio.crs.to_epsg() == 4326 + assert "spatial_ref" in out.coords or "spatial_ref" in out.variables + assert out["oa01_radiance"].attrs["grid_mapping"] == "spatial_ref" + + # dtype and CF scaling preserved; fill recorded + band = out["oa01_radiance"] + assert band.dtype == np.dtype("uint16") + assert band.attrs["scale_factor"] == 0.0139 + assert int(band.attrs["_FillValue"]) == FILL + + # Off-swath cells (bbox corners of a rotated swath) are fill + vals = band.values + assert vals[0, 0] == FILL + assert vals[-1, -1] == FILL + # …and real data survived the warp + valid = vals[vals != FILL] + assert valid.size > 0 + assert valid.max() <= (100.0 * 64 + 60) + + # altitude warped onto the grid; per-scan-line time_stamp dropped + assert "altitude" in out.data_vars + assert out["altitude"].dims == ("y", "x") + assert "time_stamp" not in out.variables + + # float variable with no pre-existing _FillValue: nodata is NaN, but it + # is still recorded, and off-swath corners are NaN. + flux = out["solar_flux_proxy"] + assert np.isnan(flux.attrs["_FillValue"]) + flux_vals = flux.values + assert np.isnan(flux_vals[0, 0]) + assert np.isnan(flux_vals[-1, -1]) + + +def test_reproject_olci_missing_geolocation_raises() -> None: + ds = build_rotated_swath().drop_vars("latitude") + with pytest.raises(ValueError, match="latitude"): + reproject_olci(ds) + + +def test_reproject_olci_wrong_geolocation_dims_raises() -> None: + ds = build_rotated_swath() + ds = ds.assign_coords(latitude=("rows", np.linspace(45, 46, 64))) + with pytest.raises(ValueError, match="2-D"): + reproject_olci(ds) + + +def test_reproject_olci_degenerate_extent_raises() -> None: + ds = build_rotated_swath() + ds = ds.assign_coords( + latitude=(("rows", "columns"), np.full((64, 60), 45.0)), + longitude=(("rows", "columns"), np.full((64, 60), 10.0)), + ) + with pytest.raises(ValueError, match="degenerate"): + reproject_olci(ds) + + +def test_reproject_olci_projected_target_crs() -> None: + """Warping to a projected target CRS yields a metric grid with matching coord attrs. + + Exercises the non-geographic branch end-to-end: the CLI-advertised + --target-crs flag must produce a regular grid in the requested CRS, with + projection_x/y_coordinate standard names and metre units on the 1-D coords. + """ + ds = build_rotated_swath() + out = reproject_olci(ds, target_crs="EPSG:3857") + + assert out.rio.crs is not None + assert out.rio.crs.to_epsg() == 3857 + for dim, std_name in ( + ("y", "projection_y_coordinate"), + ("x", "projection_x_coordinate"), + ): + coord = out[dim] + assert coord.ndim == 1 + steps = np.diff(coord.values) + assert np.allclose(steps, steps[0]) + assert coord.attrs["standard_name"] == std_name + assert coord.attrs["units"] == "m" + band = out["oa01_radiance"] + assert band.dtype == np.dtype("uint16") + assert band.attrs["grid_mapping"] == "spatial_ref" diff --git a/tests/test_open_source.py b/tests/test_open_source.py new file mode 100644 index 00000000..66a674c2 --- /dev/null +++ b/tests/test_open_source.py @@ -0,0 +1,162 @@ +"""Tests for open_source_datatree: native-chunk-aligned reads and the +per-source cache (EOPF-Explorer/data-pipeline#339).""" + +import os +import threading +from collections.abc import Iterator +from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer + +import numcodecs +import numpy as np +import pytest +import zarr + +from eopf_geozarr.conversion.open_source import open_source_datatree + + +def _build_source_store(store_path: str, seed: int = 42) -> str: + """Write a zarr v2 store mimicking a cpm_v270 source group. + + - ``aot``: ONE whole-array chunk (the pathological v270 layout) + - ``b02``: regular 32x32 tiles + + ``seed`` varies the values so two stores can share a key layout but differ + in content. + """ + group = zarr.open_group(store_path, mode="w", zarr_format=2) + rng = np.random.default_rng(seed) + + aot = group.create_array( + "aot", + shape=(128, 128), + chunks=(128, 128), + dtype="f8", + compressors=numcodecs.Blosc(cname="lz4", clevel=5, shuffle=1), + ) + aot[:] = rng.random((128, 128)) + aot.attrs["_ARRAY_DIMENSIONS"] = ["y", "x"] + + b02 = group.create_array( + "b02", + shape=(128, 128), + chunks=(32, 32), + dtype="f8", + compressors=numcodecs.Blosc(cname="lz4", clevel=5, shuffle=1), + ) + b02[:] = rng.random((128, 128)) + b02.attrs["_ARRAY_DIMENSIONS"] = ["y", "x"] + + zarr.consolidate_metadata(group.store) + return store_path + + +@pytest.fixture +def source_store(tmp_path) -> str: + return _build_source_store(str(tmp_path / "source.zarr")) + + +def test_single_chunk_array_is_one_dask_task(source_store) -> None: + dt = open_source_datatree(source_store) + assert dt["aot"].data.chunks == ((128,), (128,)) + + +def test_tiled_array_chunks_match_native_grid(source_store) -> None: + dt = open_source_datatree(source_store) + assert dt["aot"].data.chunks == ((128,), (128,)) + assert dt["b02"].data.chunks == ((32,) * 4, (32,) * 4) + + +def test_values_roundtrip(source_store) -> None: + dt = open_source_datatree(source_store) + aot_expected = np.asarray(zarr.open_array(source_store, mode="r", path="aot")[:]) + np.testing.assert_array_equal(dt["aot"].values, aot_expected) + + +def test_explicit_storage_options_are_forwarded_to_xarray(monkeypatch) -> None: + captured: dict[str, object] = {} + + def fake_open_datatree(path: object, **kwargs: object) -> None: + captured.update(kwargs) + raise InterruptedError("stop before any I/O") + + monkeypatch.setattr("xarray.open_datatree", fake_open_datatree) + sentinel = {"endpoint_url": "https://example.invalid"} + with pytest.raises(InterruptedError): + open_source_datatree("/some/store.zarr", storage_options=sentinel) + assert captured["storage_options"] == sentinel + assert captured["chunks"] == {} + + +def test_mask_and_scale_is_forwarded_to_xarray(monkeypatch) -> None: + captured: dict[str, object] = {} + + def fake_open_datatree(path: object, **kwargs: object) -> None: + captured.update(kwargs) + raise InterruptedError("stop before any I/O") + + monkeypatch.setattr("xarray.open_datatree", fake_open_datatree) + with pytest.raises(InterruptedError): + open_source_datatree("/some/store.zarr", storage_options={}) + assert captured["mask_and_scale"] is True + + with pytest.raises(InterruptedError): + open_source_datatree("/some/store.zarr", storage_options={}, mask_and_scale=False) + assert captured["mask_and_scale"] is False + + +@pytest.fixture +def http_source(source_store) -> Iterator[str]: + """Serve the source store over local HTTP (mimics the EODC https source).""" + root = os.path.dirname(source_store) + name = os.path.basename(source_store) + + class Handler(SimpleHTTPRequestHandler): + def __init__(self, *args: object, **kwargs: object) -> None: + super().__init__(*args, directory=root, **kwargs) # type: ignore[arg-type] + + def log_message(self, format: str, *args: object) -> None: + pass + + server = ThreadingHTTPServer(("127.0.0.1", 0), Handler) + threading.Thread(target=server.serve_forever, daemon=True).start() + yield f"http://127.0.0.1:{server.server_address[1]}/{name}" + server.shutdown() + + +def test_cache_dir_reads_correct_data_over_http(http_source, source_store, tmp_path) -> None: + """cache_dir reads return correct data and populate the cache, with no + leftover temp files. Atomicity of the cache writes themselves is zarr + LocalStore's contract (temp file + rename).""" + cache_dir = str(tmp_path / "source-cache") + dt = open_source_datatree(http_source, cache_dir=cache_dir) + + aot_expected = np.asarray(zarr.open_array(source_store, mode="r", path="aot")[:]) + np.testing.assert_array_equal(dt["aot"].values, aot_expected) + assert dt["aot"].data.chunks == ((128,), (128,)) # native alignment preserved + + cached_files = [f for _, _, fs in os.walk(cache_dir) for f in fs] + assert cached_files, "cache directory should be populated after reads" + assert not [f for f in cached_files if f.endswith(".partial")] + + +def test_two_sources_can_share_one_cache_dir(tmp_path) -> None: + """A shared cache_dir must never let one source serve another's bytes. + + CacheStore keys entries by zarr key ("aot/0.0" is identical for every S2 + product), so open_source_datatree namespaces the cache per source URL. + """ + first = _build_source_store(str(tmp_path / "first.zarr"), seed=1) + second = _build_source_store(str(tmp_path / "second.zarr"), seed=2) + shared_cache = str(tmp_path / "shared-cache") + + dt_first = open_source_datatree(first, cache_dir=shared_cache) + np.testing.assert_array_equal( + dt_first["aot"].values, + np.asarray(zarr.open_array(first, mode="r", path="aot")[:]), + ) + + dt_second = open_source_datatree(second, cache_dir=shared_cache) + np.testing.assert_array_equal( + dt_second["aot"].values, + np.asarray(zarr.open_array(second, mode="r", path="aot")[:]), + ) diff --git a/uv.lock b/uv.lock index 88d9e183..6a1eaacc 100644 --- a/uv.lock +++ b/uv.lock @@ -18,9 +18,10 @@ constraints = [ { name = "black", specifier = ">=26.3.1" }, { name = "cryptography", specifier = ">=46.0.6" }, { name = "filelock", specifier = ">=3.20.3" }, + { name = "msgpack", specifier = ">=1.2.1" }, { name = "pygments", specifier = ">=2.20.0" }, { name = "requests", specifier = ">=2.33.0" }, - { name = "tornado", specifier = ">=6.5.5" }, + { name = "tornado", specifier = ">=6.5.7" }, { name = "urllib3", specifier = ">=2.7.0" }, { name = "virtualenv", specifier = ">=20.36.1" }, ] @@ -214,6 +215,89 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" }, ] +[[package]] +name = "appnope" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, +] + +[[package]] +name = "argon2-cffi" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argon2-cffi-bindings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657, upload-time = "2025-06-03T06:55:30.804Z" }, +] + +[[package]] +name = "argon2-cffi-bindings" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441, upload-time = "2025-07-30T10:02:05.147Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/97/3c0a35f46e52108d4707c44b95cfe2afcafc50800b5450c197454569b776/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:3d3f05610594151994ca9ccb3c771115bdb4daef161976a266f0dd8aa9996b8f", size = 54393, upload-time = "2025-07-30T10:01:40.97Z" }, + { url = "https://files.pythonhosted.org/packages/9d/f4/98bbd6ee89febd4f212696f13c03ca302b8552e7dbf9c8efa11ea4a388c3/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8b8efee945193e667a396cbc7b4fb7d357297d6234d30a489905d96caabde56b", size = 29328, upload-time = "2025-07-30T10:01:41.916Z" }, + { url = "https://files.pythonhosted.org/packages/43/24/90a01c0ef12ac91a6be05969f29944643bc1e5e461155ae6559befa8f00b/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3c6702abc36bf3ccba3f802b799505def420a1b7039862014a65db3205967f5a", size = 31269, upload-time = "2025-07-30T10:01:42.716Z" }, + { url = "https://files.pythonhosted.org/packages/d4/d3/942aa10782b2697eee7af5e12eeff5ebb325ccfb86dd8abda54174e377e4/argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1c70058c6ab1e352304ac7e3b52554daadacd8d453c1752e547c76e9c99ac44", size = 86558, upload-time = "2025-07-30T10:01:43.943Z" }, + { url = "https://files.pythonhosted.org/packages/0d/82/b484f702fec5536e71836fc2dbc8c5267b3f6e78d2d539b4eaa6f0db8bf8/argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2fd3bfbff3c5d74fef31a722f729bf93500910db650c925c2d6ef879a7e51cb", size = 92364, upload-time = "2025-07-30T10:01:44.887Z" }, + { url = "https://files.pythonhosted.org/packages/c9/c1/a606ff83b3f1735f3759ad0f2cd9e038a0ad11a3de3b6c673aa41c24bb7b/argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4f9665de60b1b0e99bcd6be4f17d90339698ce954cfd8d9cf4f91c995165a92", size = 85637, upload-time = "2025-07-30T10:01:46.225Z" }, + { url = "https://files.pythonhosted.org/packages/44/b4/678503f12aceb0262f84fa201f6027ed77d71c5019ae03b399b97caa2f19/argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ba92837e4a9aa6a508c8d2d7883ed5a8f6c308c89a4790e1e447a220deb79a85", size = 91934, upload-time = "2025-07-30T10:01:47.203Z" }, + { url = "https://files.pythonhosted.org/packages/f0/c7/f36bd08ef9bd9f0a9cff9428406651f5937ce27b6c5b07b92d41f91ae541/argon2_cffi_bindings-25.1.0-cp314-cp314t-win32.whl", hash = "sha256:84a461d4d84ae1295871329b346a97f68eade8c53b6ed9a7ca2d7467f3c8ff6f", size = 28158, upload-time = "2025-07-30T10:01:48.341Z" }, + { url = "https://files.pythonhosted.org/packages/b3/80/0106a7448abb24a2c467bf7d527fe5413b7fdfa4ad6d6a96a43a62ef3988/argon2_cffi_bindings-25.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b55aec3565b65f56455eebc9b9f34130440404f27fe21c3b375bf1ea4d8fbae6", size = 32597, upload-time = "2025-07-30T10:01:49.112Z" }, + { url = "https://files.pythonhosted.org/packages/05/b8/d663c9caea07e9180b2cb662772865230715cbd573ba3b5e81793d580316/argon2_cffi_bindings-25.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:87c33a52407e4c41f3b70a9c2d3f6056d88b10dad7695be708c5021673f55623", size = 28231, upload-time = "2025-07-30T10:01:49.92Z" }, + { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121, upload-time = "2025-07-30T10:01:50.815Z" }, + { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177, upload-time = "2025-07-30T10:01:51.681Z" }, + { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090, upload-time = "2025-07-30T10:01:53.184Z" }, + { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246, upload-time = "2025-07-30T10:01:54.145Z" }, + { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126, upload-time = "2025-07-30T10:01:55.074Z" }, + { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343, upload-time = "2025-07-30T10:01:56.007Z" }, + { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777, upload-time = "2025-07-30T10:01:56.943Z" }, + { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180, upload-time = "2025-07-30T10:01:57.759Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715, upload-time = "2025-07-30T10:01:58.56Z" }, + { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149, upload-time = "2025-07-30T10:01:59.329Z" }, +] + +[[package]] +name = "arrow" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" }, +] + +[[package]] +name = "asttokens" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, +] + +[[package]] +name = "async-lru" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/1f/989ecfef8e64109a489fff357450cb73fa73a865a92bd8c272170a6922c2/async_lru-2.3.0.tar.gz", hash = "sha256:89bdb258a0140d7313cf8f4031d816a042202faa61d0ab310a0a538baa1c24b6", size = 16332, upload-time = "2026-03-19T01:04:32.413Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/e2/c2e3abf398f80732e58b03be77bde9022550d221dd8781bf586bd4d97cc1/async_lru-2.3.0-py3-none-any.whl", hash = "sha256:eea27b01841909316f2cc739807acea1c623df2be8c5cfad7583286397bb8315", size = 8403, upload-time = "2026-03-19T01:04:30.883Z" }, +] + [[package]] name = "attrs" version = "26.1.0" @@ -260,6 +344,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/05/a4/a26d5b25671d27e03afb5401a0be5899d94ff8fab6a698b1ac5be3ec29ef/bandit-1.9.4-py3-none-any.whl", hash = "sha256:f89ffa663767f5a0585ea075f01020207e966a9c0f2b9ef56a57c7963a3f6f8e", size = 134741, upload-time = "2026-02-25T06:44:13.694Z" }, ] +[[package]] +name = "beautifulsoup4" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/65/318323f98dbee45d42dff61d8f047181bc6f2268a9068cfad035a46be5af/beautifulsoup4-4.15.0.tar.gz", hash = "sha256:288e3ca7d54b06f2ac191970bc275c1939cb46d450b255bf6718b04aa37ab4f7", size = 632571, upload-time = "2026-06-07T16:44:20.453Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/c6/92fcd42f1ba33e1184263f25bfabf3d27c383410470f169e4b8163bf9c17/beautifulsoup4-4.15.0-py3-none-any.whl", hash = "sha256:d6f88de62e1d4e38ecb1077eb9724cd0eff29d2a08ca16a401e9b9e93f117cf9", size = 109924, upload-time = "2026-06-07T16:44:21.566Z" }, +] + [[package]] name = "black" version = "26.3.1" @@ -292,6 +389,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8e/0d/52d98722666d6fc6c3dd4c76df339501d6efd40e0ff95e6186a7b7f0befd/black-26.3.1-py3-none-any.whl", hash = "sha256:2bd5aa94fc267d38bb21a70d7410a89f1a1d318841855f698746f8e7f51acd1b", size = 207542, upload-time = "2026-03-12T03:36:01.668Z" }, ] +[[package]] +name = "bleach" +version = "6.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/3c/e12ac860709702bd5ebeb9b56a4fe334f1001246ee1b8f2b7ee28912df7d/bleach-6.4.0.tar.gz", hash = "sha256:4202482733d85cedd04e59fcb2f89f4e4c7c385a78d3c3c23c30446843a37452", size = 204857, upload-time = "2026-06-05T13:01:13.734Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/9d/40b6267367182187139a4000b82a3b287d84d745bccd808e75d916920e9d/bleach-6.4.0-py3-none-any.whl", hash = "sha256:4b6b6a54fff2e69a3dde9d21cc6301220bee3c3cb792187d11403fd795031081", size = 165109, upload-time = "2026-06-05T13:01:12.504Z" }, +] + +[package.optional-dependencies] +css = [ + { name = "tinycss2" }, +] + [[package]] name = "boto3" version = "1.43.0" @@ -329,6 +443,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/87/42/e09974bc74ea2791f985dff3d7f06065d11abcc31da6c46fc5f83046516e/cachetools-7.1.0-py3-none-any.whl", hash = "sha256:05afd1d309309e7c8971db462b4cf516d93fa8c9aea1b906e26e61b4399d0d82", size = 16748, upload-time = "2026-05-01T21:20:02.879Z" }, ] +[[package]] +name = "cartopy" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pyproj" }, + { name = "pyshp" }, + { name = "shapely" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3c/3f/ec3dee34237b696a486d566a6d3ae6550ae821836e0412bafdcbbec2cfd2/cartopy-0.25.0.tar.gz", hash = "sha256:55f1a390e5f3f075b221c7d91fb10258ad978db786c7930eba06eb45d28753fe", size = 10767728, upload-time = "2025-08-01T12:44:16.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/35/b19901cbe7f1b118dccbb9e655cda7d01a31ee1ecd67e5d2d8afe119f6d3/cartopy-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:060a7b835c0c4222c1067b6ffb2f9c18458abaa35b6624573a3aa37ecf55f4bf", size = 11006900, upload-time = "2025-08-01T12:43:57.708Z" }, + { url = "https://files.pythonhosted.org/packages/4b/4f/09e824f86be09152ec0f1fa1fe69affbd34eac7a13b545e2e08b9b6bc8ff/cartopy-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:57717cb603aecff03ecfee1bc153bb4022c054fcd51a4214a1bb53e5a6f74465", size = 10994813, upload-time = "2025-08-01T12:44:00.069Z" }, + { url = "https://files.pythonhosted.org/packages/b9/30/7465b650110514fc5c9c3b59935264c35ab56f876322de34efa55367ee4e/cartopy-0.25.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:53c256351433155ef51dde976557212f4e230b8cca4e5d0d9b9a2737ad92959d", size = 11799069, upload-time = "2025-08-01T12:44:02.287Z" }, + { url = "https://files.pythonhosted.org/packages/1d/52/3a57ecb4598c33ee06b512d3686e46b3983e65abd6ec94c5262d01930ed9/cartopy-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:efedb82f38409b72becdfee02231126952816d33a68b1c584bd2136713036bfb", size = 10983127, upload-time = "2025-08-01T12:44:04.441Z" }, + { url = "https://files.pythonhosted.org/packages/8e/b9/0773ff8f1c755b8a362029e6910db87064d27ca021b060c48ce511ec98b7/cartopy-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a6fcd2df8039293096f957fc9c76e969b1a9715d12ab8cee1a6bdae0c6773b8b", size = 11007728, upload-time = "2025-08-01T12:44:06.64Z" }, + { url = "https://files.pythonhosted.org/packages/34/a6/75738630b7f64bca7afc6bc5de08ddf0c61f13563f2a1abf642373d1095e/cartopy-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e4def451617e6957169447fe6ecdad0f63ef2d2007e7d451dd7b9656ada57382", size = 10996613, upload-time = "2025-08-01T12:44:08.822Z" }, + { url = "https://files.pythonhosted.org/packages/19/0d/669d4bbeb36b87ba504409d85c68ec297e6f434ea6525424f8aa5f14abac/cartopy-0.25.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c388824cb13e4fa9c2901dc4fbb2dbe9547acd2f4a6a3440983d4e6c6973ae3", size = 11829044, upload-time = "2025-08-01T12:44:11.402Z" }, + { url = "https://files.pythonhosted.org/packages/01/ff/b46e2120abd99b2ff3d376dc91ed58ae8f0a052d57c242c9b140497573dd/cartopy-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:60bad14c072d16e3c96967638cd66eb5a62cf24bc70087bcbfc6b30a3872ed26", size = 10987060, upload-time = "2025-08-01T12:44:14.222Z" }, +] + [[package]] name = "cast-value-rs" version = "0.4.0" @@ -417,6 +555,63 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f4/2f/2d4f04e27c2481fd697522340df04f3a278dfe9a1f13292b2f9e39b98a44/cf_xarray-0.11.1-py3-none-any.whl", hash = "sha256:b55c77af7bc5c0768a65ab6eafef89646e5cbf003a12ec37513983565e25f888", size = 79377, upload-time = "2026-05-12T20:58:51.016Z" }, ] +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + [[package]] name = "cfgv" version = "3.5.0" @@ -564,6 +759,81 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "comm" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" }, + { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" }, + { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" }, + { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" }, + { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" }, + { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" }, + { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" }, + { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" }, + { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" }, + { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" }, + { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" }, + { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" }, + { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" }, + { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" }, + { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" }, + { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" }, + { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" }, + { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" }, + { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" }, + { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" }, + { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" }, + { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" }, + { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" }, + { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" }, + { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" }, + { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" }, + { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" }, + { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" }, + { url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" }, + { url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" }, + { url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871, upload-time = "2025-07-26T12:02:20.418Z" }, + { url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264, upload-time = "2025-07-26T12:02:21.916Z" }, + { url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819, upload-time = "2025-07-26T12:02:23.759Z" }, + { url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650, upload-time = "2025-07-26T12:02:26.181Z" }, + { url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833, upload-time = "2025-07-26T12:02:28.782Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692, upload-time = "2025-07-26T12:02:30.128Z" }, + { url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424, upload-time = "2025-07-26T12:02:31.395Z" }, + { url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300, upload-time = "2025-07-26T12:02:32.956Z" }, + { url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769, upload-time = "2025-07-26T12:02:34.2Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892, upload-time = "2025-07-26T12:02:35.807Z" }, + { url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748, upload-time = "2025-07-26T12:02:37.193Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554, upload-time = "2025-07-26T12:02:38.894Z" }, + { url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118, upload-time = "2025-07-26T12:02:40.642Z" }, + { url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555, upload-time = "2025-07-26T12:02:42.25Z" }, + { url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295, upload-time = "2025-07-26T12:02:44.668Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027, upload-time = "2025-07-26T12:02:47.09Z" }, + { url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428, upload-time = "2025-07-26T12:02:48.691Z" }, + { url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331, upload-time = "2025-07-26T12:02:50.137Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831, upload-time = "2025-07-26T12:02:51.449Z" }, +] + [[package]] name = "coverage" version = "7.13.5" @@ -716,6 +986,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ce/c6/c71e82e041c95ffe6a92ac707785500aa2a515a4339c2c7dd67e3c449249/cramjam-2.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:028400d699442d40dbda02f74158c73d05cb76587a12490d0bfedd958fd49188", size = 1713108, upload-time = "2025-07-27T21:24:10.147Z" }, ] +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + [[package]] name = "dask" version = "2026.3.0" @@ -742,6 +1021,45 @@ distributed = [ { name = "distributed" }, ] +[[package]] +name = "debugpy" +version = "1.8.21" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/aa/12037145b7a56eaa5b29b41872f7a21b538e807e13f32c4d3c46e59be084/debugpy-1.8.21.tar.gz", hash = "sha256:a3c53278e84c94e11bd87c53970ec391d1a67396c8b22609fcac576520e611a6", size = 1697577, upload-time = "2026-06-01T19:30:35.156Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/df/bf625547431a9cadc9f4cbfeda38866e2b17f6aed147b625377e87834449/debugpy-1.8.21-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:9f96713896f39c3dff0ee841f47320c3f2983d33c341e009361bb0ebc79adc4e", size = 2483609, upload-time = "2026-06-01T19:30:50.794Z" }, + { url = "https://files.pythonhosted.org/packages/bf/09/59324b903599031ff9faaec1758292409f6561a0ec2492fe4b703327705a/debugpy-1.8.21-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:c193d474f0a211191f2b4449d2d06157c689013035bd952f3b617e0ef422b176", size = 3968900, upload-time = "2026-06-01T19:30:52.341Z" }, + { url = "https://files.pythonhosted.org/packages/14/cd/27f65b805d7fe005c44e1a36b9183ecdfbcdbf9d3e721a5115d461ecc7ee/debugpy-1.8.21-cp312-cp312-win32.whl", hash = "sha256:4743373c1cac7f9e74a1b9915bf1dbe0e900eca657ffb170ae07ac8363205ae9", size = 5336340, upload-time = "2026-06-01T19:30:54.047Z" }, + { url = "https://files.pythonhosted.org/packages/77/1d/c84e30c0c674184948b66f076ab271c01d940618a2824c23cd035a27bc20/debugpy-1.8.21-cp312-cp312-win_amd64.whl", hash = "sha256:bd7ba9dd3daa7c2f942c6ca8d4695a16bf9ac16b63615261c7982bc74f7ed20c", size = 5374751, upload-time = "2026-06-01T19:30:55.891Z" }, + { url = "https://files.pythonhosted.org/packages/77/6b/d817e1f8cc77aa055d37fba092e0febfdff40fe652d8d53d4cd7a86ad98d/debugpy-1.8.21-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:13678151fc401e2d68c9880b91e28714f797d40422994572b24560ef80910a88", size = 2477398, upload-time = "2026-06-01T19:30:57.644Z" }, + { url = "https://files.pythonhosted.org/packages/48/57/412421516afc3055fa577516f00beec3d663f9b0ab330639547ae6c57720/debugpy-1.8.21-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:ecbd158386c31ffe71d46f72d44d56e66331ab9b16cad649156d514368f23ab2", size = 3962096, upload-time = "2026-06-01T19:30:59.235Z" }, + { url = "https://files.pythonhosted.org/packages/c1/62/2c616337cf6ba7b07ebbc97f02c6c945a8e2f76b365e33ee809c32ee36d1/debugpy-1.8.21-cp313-cp313-win32.whl", hash = "sha256:2c2ae706dec41d99a9ca1f7ebc987a83e65578363be6f6b3ac9067504917fae1", size = 5336288, upload-time = "2026-06-01T19:31:00.79Z" }, + { url = "https://files.pythonhosted.org/packages/f8/99/9175103392f84c4b1bf7622888cdc68da07f0ff7d9e581266428f6776033/debugpy-1.8.21-cp313-cp313-win_amd64.whl", hash = "sha256:aa648733047443eb1d07682c4ef287d36a54507b643ffdf38b09a3ef002c72a0", size = 5376567, upload-time = "2026-06-01T19:31:02.56Z" }, + { url = "https://files.pythonhosted.org/packages/ce/3d/f4bbb323a548bfab2af3d6b4ffd9bf22636e55956a1285d317a1de643aad/debugpy-1.8.21-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:9bb2a685287a2ac9b181cde89edcec64845cb51de7faaa75badb9a698bc24782", size = 2477209, upload-time = "2026-06-01T19:31:04.157Z" }, + { url = "https://files.pythonhosted.org/packages/8c/2d/6e7ec524984a1702777868de49a4c53202bddac2a432a76a093469587750/debugpy-1.8.21-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:3d6922439bf33fd38a3e2c447869ebc7b97da5cd3d329ff1ef9bc06c4903437e", size = 3927115, upload-time = "2026-06-01T19:31:05.863Z" }, + { url = "https://files.pythonhosted.org/packages/97/47/d1aa6d64005a98a9144647d99306b419396f9ad7bf1d73c119e17a81fb4d/debugpy-1.8.21-cp314-cp314-win32.whl", hash = "sha256:15d4963bd5ffa48f0da0947fd06757fa7621945048a14ad7705431566d3c0e7c", size = 5336724, upload-time = "2026-06-01T19:31:07.711Z" }, + { url = "https://files.pythonhosted.org/packages/5f/67/b905b90d163af11878c1af8abafa4a25206335e112e284e413454543a6da/debugpy-1.8.21-cp314-cp314-win_amd64.whl", hash = "sha256:fe0744a12353406de0ae8ccff0d0a4a666f00801a3db8fd04e7a5f761cd520e8", size = 5373803, upload-time = "2026-06-01T19:31:09.469Z" }, + { url = "https://files.pythonhosted.org/packages/95/51/67e7cf11a53e40694f720457d5b3a1cdaaa3d5a9a633e482f225456b93ff/debugpy-1.8.21-py2.py3-none-any.whl", hash = "sha256:b1e37d333663c8851516a47364ef473da127f9caebe4417e6df6f5825a7e9a92", size = 5352888, upload-time = "2026-06-01T19:31:25.186Z" }, +] + +[[package]] +name = "decorator" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/60/8b/32f9823da46cde7df2087faa08cd98d01b908f8dcab982cdba9c84e85355/decorator-5.3.1.tar.gz", hash = "sha256:4cbcdd55a6efadb9dbea26b858f4fb3264567b52d69ca0d25b721b553f60ea82", size = 58084, upload-time = "2026-05-18T06:03:28.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/7f/798705f5296a58ca505d600456748d1be48078eac8a7050d8a98bc9edb89/decorator-5.3.1-py3-none-any.whl", hash = "sha256:f47fe6fdbd2edd623ecfe36875d37aba411624e2670dd395dddae1358689bb3c", size = 10365, upload-time = "2026-05-18T06:03:26.517Z" }, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, +] + [[package]] name = "distlib" version = "0.4.0" @@ -791,7 +1109,7 @@ wheels = [ [[package]] name = "eopf-geozarr" -version = "0.10.1" +version = "0.10.2" source = { editable = "." } dependencies = [ { name = "aiohttp" }, @@ -829,6 +1147,12 @@ downstream-titiler = [ { name = "httpx" }, { name = "titiler-xarray" }, ] +notebooks = [ + { name = "cartopy" }, + { name = "jupyter" }, + { name = "matplotlib" }, + { name = "nbformat" }, +] test = [ { name = "jsondiff" }, { name = "pytest" }, @@ -853,8 +1177,8 @@ requires-dist = [ { name = "structlog", specifier = ">=25.5.0" }, { name = "typing-extensions", specifier = ">=4.15.0" }, { name = "xarray", specifier = ">=2025.7.1" }, - { name = "zarr", extras = ["cast-value-rs"], specifier = ">=3.2.0" }, - { name = "zarr-cm", git = "https://github.com/zarr-conventions/zarr-cm.git?rev=main" }, + { name = "zarr", extras = ["cast-value-rs"], specifier = ">=3.2.0,<3.3.0" }, + { name = "zarr-cm", specifier = ">=0.4.1" }, ] [package.metadata.requires-dev] @@ -875,6 +1199,12 @@ downstream-titiler = [ { name = "httpx", specifier = ">=0.27.0" }, { name = "titiler-xarray", specifier = ">=2.0.0" }, ] +notebooks = [ + { name = "cartopy", specifier = ">=0.23" }, + { name = "jupyter", specifier = ">=1.0.0" }, + { name = "matplotlib", specifier = ">=3.8.0" }, + { name = "nbformat", specifier = ">=5.9.0" }, +] test = [ { name = "jsondiff", specifier = ">=2.0.0" }, { name = "jsondiff", specifier = ">=2.2.1" }, @@ -894,6 +1224,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" }, ] +[[package]] +name = "executing" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, +] + [[package]] name = "fastapi" version = "0.136.1" @@ -910,6 +1249,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5a/ff/2e4eca3ade2c22fe1dea7043b8ee9dabe47753349eb1b56a202de8af6349/fastapi-0.136.1-py3-none-any.whl", hash = "sha256:a6e9d7eeada96c93a4d69cb03836b44fa34e2854accb7244a1ece36cd4781c3f", size = 117683, upload-time = "2026-04-23T16:49:42.437Z" }, ] +[[package]] +name = "fastjsonschema" +version = "2.21.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130, upload-time = "2025-08-14T18:49:36.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024, upload-time = "2025-08-14T18:49:34.776Z" }, +] + [[package]] name = "filelock" version = "3.29.0" @@ -919,6 +1267,56 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812, upload-time = "2026-04-19T15:39:08.752Z" }, ] +[[package]] +name = "fonttools" +version = "4.63.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/84/69/c97f2c18e0db87d2c7b15da1974dace76ae938f1cfa22e2727a648b7ed43/fonttools-4.63.0.tar.gz", hash = "sha256:caeb583deeb5168e694b65cda8b4ee62abedfa66cf88488734466f2366b9c4e0", size = 3597189, upload-time = "2026-05-14T12:04:30.958Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/ef/b3c6b9b5be2f82416d73fe2ed2e96e2793cd80e7510bd6a17ca79cdd88ec/fonttools-4.63.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:37dd23e621e3b0aef1baa70a303b80aaf38449632cfc8fd2a55fb285bbccfc02", size = 2881131, upload-time = "2026-05-14T12:03:13.386Z" }, + { url = "https://files.pythonhosted.org/packages/44/a0/c815bea63117fa63e4e1c01f8a1110d2112fa003f838e6467094ec2432ce/fonttools-4.63.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a9faff9e0c1f76f9fd55899d2ce785832efebab37eb8ae13995853aef178bef0", size = 2426704, upload-time = "2026-05-14T12:03:15.801Z" }, + { url = "https://files.pythonhosted.org/packages/44/04/0b91d8e916e92ad1fac9e4624760baf0fd5ff2ead614c2f68fb21373f03f/fonttools-4.63.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef3048ef05dbb552b89817713d9cac912e00d0fde4a3105c00d29e52e10c89af", size = 5044298, upload-time = "2026-05-14T12:03:18.085Z" }, + { url = "https://files.pythonhosted.org/packages/77/c7/2342da9830e3e9d4870305ca5d2091d2a83284f2953079b7bdd3b5e029d8/fonttools-4.63.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58dc6bb86a78d782f00f9190ca02c119cf5bbe2807536e361e18d42019f877d8", size = 4999800, upload-time = "2026-05-14T12:03:20.161Z" }, + { url = "https://files.pythonhosted.org/packages/e6/6d/67fe16c48d7ce050979b33f47e0d28a318f02da030602e944c34f7a16ef3/fonttools-4.63.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee08ebfa58f6e1aeff5697ab9582105bb620008c1caafb681e4c557e7483027b", size = 4982666, upload-time = "2026-05-14T12:03:22.87Z" }, + { url = "https://files.pythonhosted.org/packages/f2/00/3bbab338c07c71fa56269953845e92c951a61457bbbb0f1022551ea266d9/fonttools-4.63.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:27fdc65af8da6f88b9c6121c47a464cbe359fcfff7ff6fc2d37a1f395d755b78", size = 5133598, upload-time = "2026-05-14T12:03:25.168Z" }, + { url = "https://files.pythonhosted.org/packages/62/f2/aa27c7f98db5b064883dadcc5283947e81e034de42e22a33675878d98b54/fonttools-4.63.0-cp312-cp312-win32.whl", hash = "sha256:af2fd1664d00a397d75f806985ddb36282091c2131a73a6485c23b4a34722263", size = 2292575, upload-time = "2026-05-14T12:03:27.496Z" }, + { url = "https://files.pythonhosted.org/packages/87/36/cccb9bc2a6ab63d1b2980374f0dca72ce95ae267c9b4cfe77455bb70d0d4/fonttools-4.63.0-cp312-cp312-win_amd64.whl", hash = "sha256:59ac449f8cca9b4ffa08d2e7bbadad87ce710d69d1eda5c3c1ce579baa987272", size = 2343211, upload-time = "2026-05-14T12:03:30.057Z" }, + { url = "https://files.pythonhosted.org/packages/0f/8d/d8fec3dcde2963f8c908fb315e5ff2cd0ac34f82394bbbf73a2aa5145ce3/fonttools-4.63.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cd7e9857e5e63738b9d9fd707bc1f59c8b09e5177726d23664db393c59bb08bd", size = 2876062, upload-time = "2026-05-14T12:03:32.554Z" }, + { url = "https://files.pythonhosted.org/packages/ef/71/d935dc54e4ff121bfdd11e08702db63a7e6f25af21d8a3d7b7212df53641/fonttools-4.63.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c2a2a42198b696a6f48fad91709afb55176e66a5e566131219dba372fb7f8c59", size = 2424594, upload-time = "2026-05-14T12:03:34.86Z" }, + { url = "https://files.pythonhosted.org/packages/8e/40/e76320afa1df918e146155ef239b1719ee266092e96f5423bfd075affba1/fonttools-4.63.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e874792a8212b44583ea02189d9e693906b2f78b261f372f95d6c563210ac1d", size = 5024840, upload-time = "2026-05-14T12:03:36.745Z" }, + { url = "https://files.pythonhosted.org/packages/ce/36/0b805d8c485f872f65a509cbe3b58a5d0d17bee855333b54a150c79d3061/fonttools-4.63.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22135da48a348785c5e2d5d2d9d6bec5ed44adacbaeb9db12d9493bf6c6bfa68", size = 4975801, upload-time = "2026-05-14T12:03:38.833Z" }, + { url = "https://files.pythonhosted.org/packages/c8/26/2cee03d0aa083ab022da5c07aff9ed3f689da1defb81ad6917c9627896da/fonttools-4.63.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ccf41f2efdf56994d22d73bef4ced1052161958169428d06ba9724ea9e9a64be", size = 4965009, upload-time = "2026-05-14T12:03:41.494Z" }, + { url = "https://files.pythonhosted.org/packages/7e/48/cc4b66d9058c0d0982c833fad10127c4b0e9324606aafa41382295ca4102/fonttools-4.63.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9ced0bd02ac751dd6319b0da88aaef24414e3b0dbc32bb4f24944821a3741a27", size = 5105892, upload-time = "2026-05-14T12:03:43.525Z" }, + { url = "https://files.pythonhosted.org/packages/d8/1f/a98a30a814b9ddef3a2e706025f90b9e0bc94890e6cb15254bc86547d11a/fonttools-4.63.0-cp313-cp313-win32.whl", hash = "sha256:85be818f5506e8a7753153def2c9550178f0ecae6a47b5e0e8dbb23f7cc90380", size = 2291313, upload-time = "2026-05-14T12:03:45.594Z" }, + { url = "https://files.pythonhosted.org/packages/92/46/5177b01f3b4abfdd4409f31cca4ab279c9343a26efbe9ec78c97fc612e02/fonttools-4.63.0-cp313-cp313-win_amd64.whl", hash = "sha256:ba04cb5891d4c0c21b6da95eda8d7b090021508a294fff33464fc7d241e0856b", size = 2342299, upload-time = "2026-05-14T12:03:47.414Z" }, + { url = "https://files.pythonhosted.org/packages/27/d2/23d25e3f247b328be58d04a4c9f894178a0d1eda7d42867cfb388adaf416/fonttools-4.63.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fd1e3094f42d806d3d7c79162fc59e5910fcbe3a7360c385b8da969bc4493745", size = 2875338, upload-time = "2026-05-14T12:03:50.052Z" }, + { url = "https://files.pythonhosted.org/packages/cd/58/7dfa0c761cb3b2964e2a84c4dc986c926a87de0cb9fb60d5b28ded3f2914/fonttools-4.63.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6e528da43bc3791085f8cb6141b1d13e459226790240340fcbb4625649238b03", size = 2422661, upload-time = "2026-05-14T12:03:52.154Z" }, + { url = "https://files.pythonhosted.org/packages/dd/87/64cfa18a7a1621d17b7f4502b2b0ed8a135a90c3db51ea590ee99043e76b/fonttools-4.63.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b2248c5decb223562f7902ff6325077a073f608ee8e33e88ad88db734eb9f49", size = 5010526, upload-time = "2026-05-14T12:03:54.647Z" }, + { url = "https://files.pythonhosted.org/packages/36/e1/a8933a72c45a87177fbde2696e0d0755c8c9062f8c077a961c6215fa27b1/fonttools-4.63.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:308f957cdeaf8abe4e5f2f124902ef405448af92c90f80e302a3b771c2e6116b", size = 4923946, upload-time = "2026-05-14T12:03:56.984Z" }, + { url = "https://files.pythonhosted.org/packages/27/60/872e6e233b8c5e8b41413796ff18b7fe479661bd40147e071b450dfad7a1/fonttools-4.63.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bf00f21eb5fb721dbaf73d1e9da6d02a1af7768f2ebcf9798be98beab8ba90f6", size = 4962489, upload-time = "2026-05-14T12:03:59.443Z" }, + { url = "https://files.pythonhosted.org/packages/30/c4/83c24f2ec38b90cfda84bf4b1a1f49df80e84a1db4e7ac6e0d41bf23bc39/fonttools-4.63.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c1aaa4b9c75798400ac043ce04d74e7830376c85095a5a6ed7cba2f17a266bf4", size = 5071870, upload-time = "2026-05-14T12:04:02.122Z" }, + { url = "https://files.pythonhosted.org/packages/de/40/3ae22b60ff1d41ce0bd044b31238cdc72cef99f28b976f1e128ebd618c9b/fonttools-4.63.0-cp314-cp314-win32.whl", hash = "sha256:22693918177bd9ceabec4736d338045f357769416fc6b0b2508eefef75b08616", size = 2295026, upload-time = "2026-05-14T12:04:04.47Z" }, + { url = "https://files.pythonhosted.org/packages/c3/d4/98078064ccc76b45cb0f6c002452011e93c4bd26f6850344f0951cc1fe89/fonttools-4.63.0-cp314-cp314-win_amd64.whl", hash = "sha256:7d782fac32985914c351556f68ac0855391572bcd87de50e05970d3cd4c96fc5", size = 2347454, upload-time = "2026-05-14T12:04:06.752Z" }, + { url = "https://files.pythonhosted.org/packages/49/4e/652d1580c5f4e39f7d103b0c793e4773129ad633dce4addd0cf4dfebde02/fonttools-4.63.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:6db5140a60a5d731d21ec076745b40a310607731b0a565b50776393188649001", size = 2958152, upload-time = "2026-05-14T12:04:08.706Z" }, + { url = "https://files.pythonhosted.org/packages/0e/55/ad864c9a9b219f552eb46b32cd7906c466e5a578ba0c3abfcc0fe7413eb6/fonttools-4.63.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7d76edbff9014094dbf03bd2d074709dfa6ec7aba13d838c937a2b33d2d6a86e", size = 2460809, upload-time = "2026-05-14T12:04:10.783Z" }, + { url = "https://files.pythonhosted.org/packages/ea/2b/0aa8db70f18cf52e49b4ed5ecec68547f981160bf5ded3b5aed6faa0a6f9/fonttools-4.63.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0eac00b9118c3c2f87d272e45341871c5b3066baa3c86897fa634a7c3fb59096", size = 5148649, upload-time = "2026-05-14T12:04:12.747Z" }, + { url = "https://files.pythonhosted.org/packages/7f/63/18e4369c25043096f1048e0c9915951adc4f842bd81c6b18155824d6fa99/fonttools-4.63.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:51394295f1a51de8b5f30bdb1e1b9a4231536c7064ef5c6e211eec19fa36036f", size = 4932147, upload-time = "2026-05-14T12:04:14.806Z" }, + { url = "https://files.pythonhosted.org/packages/a1/3f/67f3eac2ffd8a98446c5022f8ed3864eac878a5ff7af8df4c8286dba16cc/fonttools-4.63.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9e12f105d2b6342c559c298afb674006bb2893afc7102dcf8a1b55b0486b4e40", size = 5027237, upload-time = "2026-05-14T12:04:17.675Z" }, + { url = "https://files.pythonhosted.org/packages/1a/ba/4e6214cb38a7b04779e97bb7636de9a5c7f20af7018d03dee0b64c08510a/fonttools-4.63.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:796f27556dbe094c4824f75ca85267e4df776c79036c8441469a4df37038c196", size = 5053933, upload-time = "2026-05-14T12:04:20.818Z" }, + { url = "https://files.pythonhosted.org/packages/34/3b/214dcc19ee31d3d38fb5ad2755c11ef0514e5dc300bbaf41c0b69f393799/fonttools-4.63.0-cp314-cp314t-win32.whl", hash = "sha256:948428a275741f0b64b113c955425a953314f4b9ab9997f73a72c83e68e569c8", size = 2359326, upload-time = "2026-05-14T12:04:24.22Z" }, + { url = "https://files.pythonhosted.org/packages/dd/1e/3ff1a9b523058c2eeb6a9d50f5574e2a738200d0d94107d5bc4105e8da3f/fonttools-4.63.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6d4741eb179121cab9eea4cb2393d24492373a260d7945006358c08cfbf45419", size = 2425829, upload-time = "2026-05-14T12:04:26.829Z" }, + { url = "https://files.pythonhosted.org/packages/2c/47/c99d5268f354002ce80f8d029cd9d7d872969da1de8b93d32de4dc56d6f4/fonttools-4.63.0-py3-none-any.whl", hash = "sha256:445af2eab030a16b9171ea8bdda7ebf7d96bda2df88ee182a464252f6e05e20d", size = 1164562, upload-time = "2026-05-14T12:04:29.092Z" }, +] + +[[package]] +name = "fqdn" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015, upload-time = "2021-03-11T07:16:29.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" }, +] + [[package]] name = "frozenlist" version = "1.8.0" @@ -1128,6 +1526,104 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] +[[package]] +name = "ipykernel" +version = "7.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "appnope", marker = "sys_platform == 'darwin'" }, + { name = "comm" }, + { name = "debugpy" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "matplotlib-inline" }, + { name = "nest-asyncio2" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/c4/e4a38f579de4225a561305666f7541cdabb30075def2aa1ac17bd73c1fb5/ipykernel-7.3.0.tar.gz", hash = "sha256:9acaaaf97d16355166e4085afe9d225bfbdf2b7ef520f9df3be8f2b248275e09", size = 184899, upload-time = "2026-06-10T08:41:25.481Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/02/77b271f5dc58bfbc0b577c877b2365d1ffea2afe66a80c13f2312820348c/ipykernel-7.3.0-py3-none-any.whl", hash = "sha256:897eb64da762549ef610698fca5e9675195ec6ac8ec7f19d81ce1ca20c876057", size = 120583, upload-time = "2026-06-10T08:41:23.648Z" }, +] + +[[package]] +name = "ipython" +version = "9.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "ipython-pygments-lexers" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "psutil", marker = "sys_platform != 'cygwin' and sys_platform != 'emscripten'" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/53/59/165d3b4d75cc34add3122c4417ecb229085140ac573103c223cd01dde96f/ipython-9.15.0.tar.gz", hash = "sha256:da2819ce2aa83135257df830660b1176d986c3d2876db24df01974fa955b2756", size = 4442580, upload-time = "2026-06-26T11:03:35.913Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/3a/948263ca3b9d65bb2b1b0c521b3a49fad5d59ada58724bd87d2bd5ff3f36/ipython-9.15.0-py3-none-any.whl", hash = "sha256:515ad9c3cdf0c932a5a9f6245419e8aba706b7bd03c3e1d3a1c83d9351d6aa6e", size = 630895, upload-time = "2026-06-26T11:03:33.809Z" }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, +] + +[[package]] +name = "ipywidgets" +version = "8.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "comm" }, + { name = "ipython" }, + { name = "jupyterlab-widgets" }, + { name = "traitlets" }, + { name = "widgetsnbextension" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739, upload-time = "2025-11-01T21:18:12.393Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808, upload-time = "2025-11-01T21:18:10.956Z" }, +] + +[[package]] +name = "isoduration" +version = "20.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "arrow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" }, +] + +[[package]] +name = "jedi" +version = "0.20.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/b7/a3635f6a2d7cf5b5dd98064fc1d5fbbafcb25477bcea204a3a92145d158b/jedi-0.20.0.tar.gz", hash = "sha256:c3f4ccbd276696f4b19c54618d4fb18f9fc24b0aef02acf704b23f487daa1011", size = 3119416, upload-time = "2026-05-01T23:38:47.814Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/93/242e2eab5fe682ffcb8b0084bde703a41d51e17ee0f3a31ff0d9d813620a/jedi-0.20.0-py2.py3-none-any.whl", hash = "sha256:7bdd9c2634f56713299976f4cbd59cb3fa92165cc5e05ea811fb253480728b67", size = 4884812, upload-time = "2026-05-01T23:38:43.919Z" }, +] + [[package]] name = "jinja2" version = "3.1.6" @@ -1141,24 +1637,389 @@ wheels = [ ] [[package]] -name = "jmespath" -version = "1.1.0" +name = "jmespath" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377, upload-time = "2026-01-22T16:35:26.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" }, +] + +[[package]] +name = "json5" +version = "0.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/7d/05c46a96a78147ae3bf99c2f4169ce144a70220b8d6fcd56f6ec368b8ce9/json5-0.15.0.tar.gz", hash = "sha256:7424d1f1eb1d56da6e3d70643f53619862b4ce81440bdb8ecfd6f875e5ba4a71", size = 53278, upload-time = "2026-06-19T20:08:27.716Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/be/59527c99478aade6bb33a68d72e6e18dd4e6ff6eacfc7d01bdb15bc76912/json5-0.15.0-py3-none-any.whl", hash = "sha256:56636a30c0e8a4665fe2179c0212f32eae3796dea89ea6f649b9436ecdb39618", size = 36570, upload-time = "2026-06-19T20:08:26.748Z" }, +] + +[[package]] +name = "jsondiff" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/35/48/841137f1843fa215ea284834d1514b8e9e20962bda63a636c7417e02f8fb/jsondiff-2.2.1.tar.gz", hash = "sha256:658d162c8a86ba86de26303cd86a7b37e1b2c1ec98b569a60e2ca6180545f7fe", size = 26649, upload-time = "2024-08-29T04:09:06.201Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/94/a8066f84d62ab666d61ef97deba1a33126e3e5c0c0da2c458ada17053ed6/jsondiff-2.2.1-py3-none-any.whl", hash = "sha256:b1f0f7e2421881848b1d556d541ac01a91680cfcc14f51a9b62cdf4da0e56722", size = 13440, upload-time = "2024-08-29T04:09:04.955Z" }, +] + +[[package]] +name = "jsonpointer" +version = "3.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/c7/af399a2e7a67fd18d63c40c5e62d3af4e67b836a2107468b6a5ea24c4304/jsonpointer-3.1.1.tar.gz", hash = "sha256:0b801c7db33a904024f6004d526dcc53bbb8a4a0f4e32bfd10beadf60adf1900", size = 9068, upload-time = "2026-03-23T22:32:32.458Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl", hash = "sha256:8ff8b95779d071ba472cf5bc913028df06031797532f08a7d5b602d8b2a488ca", size = 7659, upload-time = "2026-03-23T22:32:31.568Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.26.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, +] + +[package.optional-dependencies] +format-nongpl = [ + { name = "fqdn" }, + { name = "idna" }, + { name = "isoduration" }, + { name = "jsonpointer" }, + { name = "rfc3339-validator" }, + { name = "rfc3986-validator" }, + { name = "rfc3987-syntax" }, + { name = "uri-template" }, + { name = "webcolors" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "jupyter" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ipykernel" }, + { name = "ipywidgets" }, + { name = "jupyter-console" }, + { name = "jupyterlab" }, + { name = "nbconvert" }, + { name = "notebook" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959, upload-time = "2024-08-30T07:15:48.299Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657, upload-time = "2024-08-30T07:15:47.045Z" }, +] + +[[package]] +name = "jupyter-builder" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-core" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/45/d0df8b43c10a61529c0f4a8af5e19ebe108f0c3af8f57e0fc358969907af/jupyter_builder-1.0.2.tar.gz", hash = "sha256:6155d78a5325010532a6419ffcba89eac643fd1aa56ea83115e661924d6f6aab", size = 968638, upload-time = "2026-06-12T02:33:25.767Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/b6/c418e0b3256f67c04933566b80bfce947350682db92c4b786a8653db32d6/jupyter_builder-1.0.2-py3-none-any.whl", hash = "sha256:b024f65d36e1d530542db597b00dd513261aa59842e0d0fbbb1015a9f1935e9c", size = 910789, upload-time = "2026-06-12T02:33:23.317Z" }, +] + +[[package]] +name = "jupyter-client" +version = "8.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-core" }, + { name = "python-dateutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/dc/5512503b088997c2250b8bf18258fba9d9ce5ead641183700960d3c9d342/jupyter_client-8.9.1.tar.gz", hash = "sha256:a58f730dd9e728ba16ba1d62ebccf7ffe1ebbdbce4e95cfae941b7321ae1f4fa", size = 359256, upload-time = "2026-06-09T13:15:01.033Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/6f/56d39bf385c5c27988aebaf0c18a2a17e960575740100973511018bd904e/jupyter_client-8.9.1-py3-none-any.whl", hash = "sha256:0b7a295bc46e8751e9adae84781f726c851c1d911bd793edc4a3bde942e3da81", size = 109828, upload-time = "2026-06-09T13:14:58.835Z" }, +] + +[[package]] +name = "jupyter-console" +version = "6.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ipykernel" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "pyzmq" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363, upload-time = "2023-03-06T14:13:31.02Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510, upload-time = "2023-03-06T14:13:28.229Z" }, +] + +[[package]] +name = "jupyter-core" +version = "5.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "platformdirs" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032, upload-time = "2025-10-16T19:19:16.783Z" }, +] + +[[package]] +name = "jupyter-events" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonschema", extra = ["format-nongpl"] }, + { name = "packaging" }, + { name = "python-json-logger" }, + { name = "pyyaml" }, + { name = "referencing" }, + { name = "rfc3339-validator" }, + { name = "rfc3986-validator" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/18/f8/475c4241b2b75af0deaae453ed003c6c851766dbc44d332d8baf245dc931/jupyter_events-0.12.1.tar.gz", hash = "sha256:faff25f77218335752f35f23c5fe6e4a392a7bd99a5939ccb9b8fbf594636cf3", size = 62854, upload-time = "2026-04-20T23:17:50.66Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/6c/6fcde0c8f616ed360ffd3587f7db9e225a7e62b583a04494d2f069cf64ea/jupyter_events-0.12.1-py3-none-any.whl", hash = "sha256:c366585253f537a627da52fa7ca7410c5b5301fe893f511e7b077c2d93ec8bcf", size = 19512, upload-time = "2026-04-20T23:17:48.927Z" }, +] + +[[package]] +name = "jupyter-lsp" +version = "2.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-server" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/36/ff/1e4a61f5170a9a1d978f3ac3872449de6c01fc71eaf89657824c878b1549/jupyter_lsp-2.3.1.tar.gz", hash = "sha256:fdf8a4aa7d85813976d6e29e95e6a2c8f752701f926f2715305249a3829805a6", size = 55677, upload-time = "2026-04-02T08:10:06.749Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/23/e8/9d61dcbd1dce8ef418f06befd4ac084b4720429c26b0b1222bc218685eff/jupyter_lsp-2.3.1-py3-none-any.whl", hash = "sha256:71b954d834e85ff3096400554f2eefaf7fe37053036f9a782b0f7c5e42dadb81", size = 77513, upload-time = "2026-04-02T08:10:01.753Z" }, +] + +[[package]] +name = "jupyter-server" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "argon2-cffi" }, + { name = "jinja2" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "jupyter-events" }, + { name = "jupyter-server-terminals" }, + { name = "nbconvert" }, + { name = "nbformat" }, + { name = "packaging" }, + { name = "prometheus-client" }, + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "pyzmq" }, + { name = "send2trash" }, + { name = "terminado" }, + { name = "tornado" }, + { name = "traitlets" }, + { name = "websocket-client" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6b/dc/db3a582633170186f8c8b31298d7eb26ad0eb031a1f53476c258b64eed05/jupyter_server-2.20.0.tar.gz", hash = "sha256:b5778ba337d8015a3dc2b80803ecdd5ac18d3797fddf61a50ea5fb472b4ebe14", size = 756523, upload-time = "2026-06-17T12:09:09.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/71/8c002223e873a870f5c41dc69b0a7c922301123e4a31d5d01ecb700aef77/jupyter_server-2.20.0-py3-none-any.whl", hash = "sha256:c3b67c93c471e947c18b5026f04f21614218adb706df8f48227d3ee8e0a7cdcc", size = 393143, upload-time = "2026-06-17T12:09:07.234Z" }, +] + +[[package]] +name = "jupyter-server-terminals" +version = "0.5.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "terminado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/a7/bcd0a9b0cbba88986fe944aaaf91bfda603e5a50bda8ed15123f381a3b2f/jupyter_server_terminals-0.5.4.tar.gz", hash = "sha256:bbda128ed41d0be9020349f9f1f2a4ab9952a73ed5f5ac9f1419794761fb87f5", size = 31770, upload-time = "2026-01-14T16:53:20.213Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl", hash = "sha256:55be353fc74a80bc7f3b20e6be50a55a61cd525626f578dcb66a5708e2007d14", size = 13704, upload-time = "2026-01-14T16:53:18.738Z" }, +] + +[[package]] +name = "jupyterlab" +version = "4.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "async-lru" }, + { name = "httpx" }, + { name = "ipykernel" }, + { name = "jinja2" }, + { name = "jupyter-builder" }, + { name = "jupyter-core" }, + { name = "jupyter-lsp" }, + { name = "jupyter-server" }, + { name = "jupyterlab-server" }, + { name = "notebook-shim" }, + { name = "packaging" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/2a/d6af53bfd45a43a5bfe7e40ba47ee7a8921a807daf4bb708e3a295bbb54d/jupyterlab-4.6.1.tar.gz", hash = "sha256:75315982ed28427edaa62bb85eadb5105e4043a757643c910efd787fe6ed0837", size = 28179125, upload-time = "2026-06-29T12:48:45.402Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/81/90ac6cc31d248e83a0d1eab343a5e6e68bc783d3f74fbe61640f42a61da4/jupyterlab-4.6.1-py3-none-any.whl", hash = "sha256:85a58546c831f3dce6cf919468c26874c9065e99c42279fb4abb8e1b552a98bb", size = 17164660, upload-time = "2026-06-29T12:48:41.21Z" }, +] + +[[package]] +name = "jupyterlab-pygments" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, +] + +[[package]] +name = "jupyterlab-server" +version = "2.28.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "jinja2" }, + { name = "json5" }, + { name = "jsonschema" }, + { name = "jupyter-server" }, + { name = "packaging" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996, upload-time = "2025-10-22T13:59:18.37Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830, upload-time = "2025-10-22T13:59:16.767Z" }, +] + +[[package]] +name = "jupyterlab-widgets" +version = "3.0.16" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377, upload-time = "2026-01-22T16:35:26.279Z" } +sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423, upload-time = "2025-11-01T21:11:29.724Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" }, + { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926, upload-time = "2025-11-01T21:11:28.008Z" }, ] [[package]] -name = "jsondiff" -version = "2.2.1" +name = "kiwisolver" +version = "1.5.0" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyyaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/35/48/841137f1843fa215ea284834d1514b8e9e20962bda63a636c7417e02f8fb/jsondiff-2.2.1.tar.gz", hash = "sha256:658d162c8a86ba86de26303cd86a7b37e1b2c1ec98b569a60e2ca6180545f7fe", size = 26649, upload-time = "2024-08-29T04:09:06.201Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/b2/818b74ebea34dabe6d0c51cb1c572e046730e64844da6ed646d5298c40ce/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9", size = 123158, upload-time = "2026-03-09T13:13:23.127Z" }, + { url = "https://files.pythonhosted.org/packages/bf/d9/405320f8077e8e1c5c4bd6adc45e1e6edf6d727b6da7f2e2533cf58bff71/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588", size = 66388, upload-time = "2026-03-09T13:13:24.765Z" }, + { url = "https://files.pythonhosted.org/packages/99/9f/795fedf35634f746151ca8839d05681ceb6287fbed6cc1c9bf235f7887c2/kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819", size = 64068, upload-time = "2026-03-09T13:13:25.878Z" }, + { url = "https://files.pythonhosted.org/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f", size = 1477934, upload-time = "2026-03-09T13:13:27.166Z" }, + { url = "https://files.pythonhosted.org/packages/c8/2f/cebfcdb60fd6a9b0f6b47a9337198bcbad6fbe15e68189b7011fd914911f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf", size = 1278537, upload-time = "2026-03-09T13:13:28.707Z" }, + { url = "https://files.pythonhosted.org/packages/f2/0d/9b782923aada3fafb1d6b84e13121954515c669b18af0c26e7d21f579855/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d", size = 1296685, upload-time = "2026-03-09T13:13:30.528Z" }, + { url = "https://files.pythonhosted.org/packages/27/70/83241b6634b04fe44e892688d5208332bde130f38e610c0418f9ede47ded/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083", size = 1346024, upload-time = "2026-03-09T13:13:32.818Z" }, + { url = "https://files.pythonhosted.org/packages/e4/db/30ed226fb271ae1a6431fc0fe0edffb2efe23cadb01e798caeb9f2ceae8f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6", size = 987241, upload-time = "2026-03-09T13:13:34.435Z" }, + { url = "https://files.pythonhosted.org/packages/ec/bd/c314595208e4c9587652d50959ead9e461995389664e490f4dce7ff0f782/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1", size = 2227742, upload-time = "2026-03-09T13:13:36.4Z" }, + { url = "https://files.pythonhosted.org/packages/c1/43/0499cec932d935229b5543d073c2b87c9c22846aab48881e9d8d6e742a2d/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0", size = 2323966, upload-time = "2026-03-09T13:13:38.204Z" }, + { url = "https://files.pythonhosted.org/packages/3d/6f/79b0d760907965acfd9d61826a3d41f8f093c538f55cd2633d3f0db269f6/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15", size = 1977417, upload-time = "2026-03-09T13:13:39.966Z" }, + { url = "https://files.pythonhosted.org/packages/ab/31/01d0537c41cb75a551a438c3c7a80d0c60d60b81f694dac83dd436aec0d0/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314", size = 2491238, upload-time = "2026-03-09T13:13:41.698Z" }, + { url = "https://files.pythonhosted.org/packages/e4/34/8aefdd0be9cfd00a44509251ba864f5caf2991e36772e61c408007e7f417/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9", size = 2294947, upload-time = "2026-03-09T13:13:43.343Z" }, + { url = "https://files.pythonhosted.org/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384", size = 73569, upload-time = "2026-03-09T13:13:45.792Z" }, + { url = "https://files.pythonhosted.org/packages/28/26/192b26196e2316e2bd29deef67e37cdf9870d9af8e085e521afff0fed526/kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7", size = 64997, upload-time = "2026-03-09T13:13:46.878Z" }, + { url = "https://files.pythonhosted.org/packages/9d/69/024d6711d5ba575aa65d5538042e99964104e97fa153a9f10bc369182bc2/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:fd40bb9cd0891c4c3cb1ddf83f8bbfa15731a248fdc8162669405451e2724b09", size = 123166, upload-time = "2026-03-09T13:13:48.032Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/adbb40df306f587054a348831220812b9b1d787aff714cfbc8556e38fccd/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0e1403fd7c26d77c1f03e096dc58a5c726503fa0db0456678b8668f76f521e3", size = 66395, upload-time = "2026-03-09T13:13:49.365Z" }, + { url = "https://files.pythonhosted.org/packages/a8/3a/d0a972b34e1c63e2409413104216cd1caa02c5a37cb668d1687d466c1c45/kiwisolver-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dda366d548e89a90d88a86c692377d18d8bd64b39c1fb2b92cb31370e2896bbd", size = 64065, upload-time = "2026-03-09T13:13:50.562Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0a/7b98e1e119878a27ba8618ca1e18b14f992ff1eda40f47bccccf4de44121/kiwisolver-1.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:332b4f0145c30b5f5ad9374881133e5aa64320428a57c2c2b61e9d891a51c2f3", size = 1477903, upload-time = "2026-03-09T13:13:52.084Z" }, + { url = "https://files.pythonhosted.org/packages/18/d8/55638d89ffd27799d5cc3d8aa28e12f4ce7a64d67b285114dbedc8ea4136/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c50b89ffd3e1a911c69a1dd3de7173c0cd10b130f56222e57898683841e4f96", size = 1278751, upload-time = "2026-03-09T13:13:54.673Z" }, + { url = "https://files.pythonhosted.org/packages/b8/97/b4c8d0d18421ecceba20ad8701358453b88e32414e6f6950b5a4bad54e65/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4db576bb8c3ef9365f8b40fe0f671644de6736ae2c27a2c62d7d8a1b4329f099", size = 1296793, upload-time = "2026-03-09T13:13:56.287Z" }, + { url = "https://files.pythonhosted.org/packages/c4/10/f862f94b6389d8957448ec9df59450b81bec4abb318805375c401a1e6892/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0b85aad90cea8ac6797a53b5d5f2e967334fa4d1149f031c4537569972596cb8", size = 1346041, upload-time = "2026-03-09T13:13:58.269Z" }, + { url = "https://files.pythonhosted.org/packages/a3/6a/f1650af35821eaf09de398ec0bc2aefc8f211f0cda50204c9f1673741ba9/kiwisolver-1.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:d36ca54cb4c6c4686f7cbb7b817f66f5911c12ddb519450bbe86707155028f87", size = 987292, upload-time = "2026-03-09T13:13:59.871Z" }, + { url = "https://files.pythonhosted.org/packages/de/19/d7fb82984b9238115fe629c915007be608ebd23dc8629703d917dbfaffd4/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:38f4a703656f493b0ad185211ccfca7f0386120f022066b018eb5296d8613e23", size = 2227865, upload-time = "2026-03-09T13:14:01.401Z" }, + { url = "https://files.pythonhosted.org/packages/7f/b9/46b7f386589fd222dac9e9de9c956ce5bcefe2ee73b4e79891381dda8654/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ac2360e93cb41be81121755c6462cff3beaa9967188c866e5fce5cf13170859", size = 2324369, upload-time = "2026-03-09T13:14:02.972Z" }, + { url = "https://files.pythonhosted.org/packages/92/8b/95e237cf3d9c642960153c769ddcbe278f182c8affb20cecc1cc983e7cc5/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c95cab08d1965db3d84a121f1c7ce7479bdd4072c9b3dafd8fecce48a2e6b902", size = 1977989, upload-time = "2026-03-09T13:14:04.503Z" }, + { url = "https://files.pythonhosted.org/packages/1b/95/980c9df53501892784997820136c01f62bc1865e31b82b9560f980c0e649/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc20894c3d21194d8041a28b65622d5b86db786da6e3cfe73f0c762951a61167", size = 2491645, upload-time = "2026-03-09T13:14:06.106Z" }, + { url = "https://files.pythonhosted.org/packages/cb/32/900647fd0840abebe1561792c6b31e6a7c0e278fc3973d30572a965ca14c/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a32f72973f0f950c1920475d5c5ea3d971b81b6f0ec53b8d0a956cc965f22e0", size = 2295237, upload-time = "2026-03-09T13:14:08.891Z" }, + { url = "https://files.pythonhosted.org/packages/be/8a/be60e3bbcf513cc5a50f4a3e88e1dcecebb79c1ad607a7222877becaa101/kiwisolver-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bf3acf1419fa93064a4c2189ac0b58e3be7872bf6ee6177b0d4c63dc4cea276", size = 73573, upload-time = "2026-03-09T13:14:12.327Z" }, + { url = "https://files.pythonhosted.org/packages/4d/d2/64be2e429eb4fca7f7e1c52a91b12663aeaf25de3895e5cca0f47ef2a8d0/kiwisolver-1.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa8eb9ecdb7efb0b226acec134e0d709e87a909fa4971a54c0c4f6e88635484c", size = 64998, upload-time = "2026-03-09T13:14:13.469Z" }, + { url = "https://files.pythonhosted.org/packages/b0/69/ce68dd0c85755ae2de490bf015b62f2cea5f6b14ff00a463f9d0774449ff/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db485b3847d182b908b483b2ed133c66d88d49cacf98fd278fadafe11b4478d1", size = 125700, upload-time = "2026-03-09T13:14:14.636Z" }, + { url = "https://files.pythonhosted.org/packages/74/aa/937aac021cf9d4349990d47eb319309a51355ed1dbdc9c077cdc9224cb11/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:be12f931839a3bdfe28b584db0e640a65a8bcbc24560ae3fdb025a449b3d754e", size = 67537, upload-time = "2026-03-09T13:14:15.808Z" }, + { url = "https://files.pythonhosted.org/packages/ee/20/3a87fbece2c40ad0f6f0aefa93542559159c5f99831d596050e8afae7a9f/kiwisolver-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:16b85d37c2cbb3253226d26e64663f755d88a03439a9c47df6246b35defbdfb7", size = 65514, upload-time = "2026-03-09T13:14:18.035Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7f/f943879cda9007c45e1f7dba216d705c3a18d6b35830e488b6c6a4e7cdf0/kiwisolver-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4432b835675f0ea7414aab3d37d119f7226d24869b7a829caeab49ebda407b0c", size = 1584848, upload-time = "2026-03-09T13:14:19.745Z" }, + { url = "https://files.pythonhosted.org/packages/37/f8/4d4f85cc1870c127c88d950913370dd76138482161cd07eabbc450deff01/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b0feb50971481a2cc44d94e88bdb02cdd497618252ae226b8eb1201b957e368", size = 1391542, upload-time = "2026-03-09T13:14:21.54Z" }, + { url = "https://files.pythonhosted.org/packages/04/0b/65dd2916c84d252b244bd405303220f729e7c17c9d7d33dca6feeff9ffc4/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56fa888f10d0f367155e76ce849fa1166fc9730d13bd2d65a2aa13b6f5424489", size = 1404447, upload-time = "2026-03-09T13:14:23.205Z" }, + { url = "https://files.pythonhosted.org/packages/39/5c/2606a373247babce9b1d056c03a04b65f3cf5290a8eac5d7bdead0a17e21/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:940dda65d5e764406b9fb92761cbf462e4e63f712ab60ed98f70552e496f3bf1", size = 1455918, upload-time = "2026-03-09T13:14:24.74Z" }, + { url = "https://files.pythonhosted.org/packages/d5/d1/c6078b5756670658e9192a2ef11e939c92918833d2745f85cd14a6004bdf/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:89fc958c702ee9a745e4700378f5d23fddbc46ff89e8fdbf5395c24d5c1452a3", size = 1072856, upload-time = "2026-03-09T13:14:26.597Z" }, + { url = "https://files.pythonhosted.org/packages/cb/c8/7def6ddf16eb2b3741d8b172bdaa9af882b03c78e9b0772975408801fa63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9027d773c4ff81487181a925945743413f6069634d0b122d0b37684ccf4f1e18", size = 2333580, upload-time = "2026-03-09T13:14:28.237Z" }, + { url = "https://files.pythonhosted.org/packages/9e/87/2ac1fce0eb1e616fcd3c35caa23e665e9b1948bb984f4764790924594128/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5b233ea3e165e43e35dba1d2b8ecc21cf070b45b65ae17dd2747d2713d942021", size = 2423018, upload-time = "2026-03-09T13:14:30.018Z" }, + { url = "https://files.pythonhosted.org/packages/67/13/c6700ccc6cc218716bfcda4935e4b2997039869b4ad8a94f364c5a3b8e63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ce9bf03dad3b46408c08649c6fbd6ca28a9fce0eb32fdfffa6775a13103b5310", size = 2062804, upload-time = "2026-03-09T13:14:32.888Z" }, + { url = "https://files.pythonhosted.org/packages/1b/bd/877056304626943ff0f1f44c08f584300c199b887cb3176cd7e34f1515f1/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:fc4d3f1fb9ca0ae9f97b095963bc6326f1dbfd3779d6679a1e016b9baaa153d3", size = 2597482, upload-time = "2026-03-09T13:14:34.971Z" }, + { url = "https://files.pythonhosted.org/packages/75/19/c60626c47bf0f8ac5dcf72c6c98e266d714f2fbbfd50cf6dab5ede3aaa50/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f443b4825c50a51ee68585522ab4a1d1257fac65896f282b4c6763337ac9f5d2", size = 2394328, upload-time = "2026-03-09T13:14:36.816Z" }, + { url = "https://files.pythonhosted.org/packages/47/84/6a6d5e5bb8273756c27b7d810d47f7ef2f1f9b9fd23c9ee9a3f8c75c9cef/kiwisolver-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:893ff3a711d1b515ba9da14ee090519bad4610ed1962fbe298a434e8c5f8db53", size = 68410, upload-time = "2026-03-09T13:14:38.695Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/060f45052f2a01ad5762c8fdecd6d7a752b43400dc29ff75cd47225a40fd/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8df31fe574b8b3993cc61764f40941111b25c2d9fea13d3ce24a49907cd2d615", size = 123231, upload-time = "2026-03-09T13:14:41.323Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a7/78da680eadd06ff35edef6ef68a1ad273bad3e2a0936c9a885103230aece/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1d49a49ac4cbfb7c1375301cd1ec90169dfeae55ff84710d782260ce77a75a02", size = 66489, upload-time = "2026-03-09T13:14:42.534Z" }, + { url = "https://files.pythonhosted.org/packages/49/b2/97980f3ad4fae37dd7fe31626e2bf75fbf8bdf5d303950ec1fab39a12da8/kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0cbe94b69b819209a62cb27bdfa5dc2a8977d8de2f89dfd97ba4f53ed3af754e", size = 64063, upload-time = "2026-03-09T13:14:44.759Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f9/b06c934a6aa8bc91f566bd2a214fd04c30506c2d9e2b6b171953216a65b6/kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:80aa065ffd378ff784822a6d7c3212f2d5f5e9c3589614b5c228b311fd3063ac", size = 1475913, upload-time = "2026-03-09T13:14:46.247Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f0/f768ae564a710135630672981231320bc403cf9152b5596ec5289de0f106/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e7f886f47ab881692f278ae901039a234e4025a68e6dfab514263a0b1c4ae05", size = 1282782, upload-time = "2026-03-09T13:14:48.458Z" }, + { url = "https://files.pythonhosted.org/packages/e2/9f/1de7aad00697325f05238a5f2eafbd487fb637cc27a558b5367a5f37fb7f/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5060731cc3ed12ca3a8b57acd4aeca5bbc2f49216dd0bec1650a1acd89486bcd", size = 1300815, upload-time = "2026-03-09T13:14:50.721Z" }, + { url = "https://files.pythonhosted.org/packages/5a/c2/297f25141d2e468e0ce7f7a7b92e0cf8918143a0cbd3422c1ad627e85a06/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a4aa69609f40fce3cbc3f87b2061f042eee32f94b8f11db707b66a26461591a", size = 1347925, upload-time = "2026-03-09T13:14:52.304Z" }, + { url = "https://files.pythonhosted.org/packages/b9/d3/f4c73a02eb41520c47610207b21afa8cdd18fdbf64ffd94674ae21c4812d/kiwisolver-1.5.0-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:d168fda2dbff7b9b5f38e693182d792a938c31db4dac3a80a4888de603c99554", size = 991322, upload-time = "2026-03-09T13:14:54.637Z" }, + { url = "https://files.pythonhosted.org/packages/7b/46/d3f2efef7732fcda98d22bf4ad5d3d71d545167a852ca710a494f4c15343/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:413b820229730d358efd838ecbab79902fe97094565fdc80ddb6b0a18c18a581", size = 2232857, upload-time = "2026-03-09T13:14:56.471Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ec/2d9756bf2b6d26ae4349b8d3662fb3993f16d80c1f971c179ce862b9dbae/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5124d1ea754509b09e53738ec185584cc609aae4a3b510aaf4ed6aa047ef9303", size = 2329376, upload-time = "2026-03-09T13:14:58.072Z" }, + { url = "https://files.pythonhosted.org/packages/8f/9f/876a0a0f2260f1bde92e002b3019a5fabc35e0939c7d945e0fa66185eb20/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e4415a8db000bf49a6dd1c478bf70062eaacff0f462b92b0ba68791a905861f9", size = 1982549, upload-time = "2026-03-09T13:14:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/6c/4f/ba3624dfac23a64d54ac4179832860cb537c1b0af06024936e82ca4154a0/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d618fd27420381a4f6044faa71f46d8bfd911bd077c555f7138ed88729bfbe79", size = 2494680, upload-time = "2026-03-09T13:15:01.364Z" }, + { url = "https://files.pythonhosted.org/packages/39/b7/97716b190ab98911b20d10bf92eca469121ec483b8ce0edd314f51bc85af/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5092eb5b1172947f57d6ea7d89b2f29650414e4293c47707eb499ec07a0ac796", size = 2297905, upload-time = "2026-03-09T13:15:03.925Z" }, + { url = "https://files.pythonhosted.org/packages/a3/36/4e551e8aa55c9188bca9abb5096805edbf7431072b76e2298e34fd3a3008/kiwisolver-1.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:d76e2d8c75051d58177e762164d2e9ab92886534e3a12e795f103524f221dd8e", size = 75086, upload-time = "2026-03-09T13:15:07.775Z" }, + { url = "https://files.pythonhosted.org/packages/70/15/9b90f7df0e31a003c71649cf66ef61c3c1b862f48c81007fa2383c8bd8d7/kiwisolver-1.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:fa6248cd194edff41d7ea9425ced8ca3a6f838bfb295f6f1d6e6bb694a8518df", size = 66577, upload-time = "2026-03-09T13:15:09.139Z" }, + { url = "https://files.pythonhosted.org/packages/17/01/7dc8c5443ff42b38e72731643ed7cf1ed9bf01691ae5cdca98501999ed83/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d1ffeb80b5676463d7a7d56acbe8e37a20ce725570e09549fe738e02ca6b7e1e", size = 125794, upload-time = "2026-03-09T13:15:10.525Z" }, + { url = "https://files.pythonhosted.org/packages/46/8a/b4ebe46ebaac6a303417fab10c2e165c557ddaff558f9699d302b256bc53/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc4d8e252f532ab46a1de9349e2d27b91fce46736a9eedaa37beaca66f574ed4", size = 67646, upload-time = "2026-03-09T13:15:12.016Z" }, + { url = "https://files.pythonhosted.org/packages/60/35/10a844afc5f19d6f567359bf4789e26661755a2f36200d5d1ed8ad0126e5/kiwisolver-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6783e069732715ad0c3ce96dbf21dbc2235ab0593f2baf6338101f70371f4028", size = 65511, upload-time = "2026-03-09T13:15:13.311Z" }, + { url = "https://files.pythonhosted.org/packages/f8/8a/685b297052dd041dcebce8e8787b58923b6e78acc6115a0dc9189011c44b/kiwisolver-1.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e7c4c09a490dc4d4a7f8cbee56c606a320f9dc28cf92a7157a39d1ce7676a657", size = 1584858, upload-time = "2026-03-09T13:15:15.103Z" }, + { url = "https://files.pythonhosted.org/packages/9e/80/04865e3d4638ac5bddec28908916df4a3075b8c6cc101786a96803188b96/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a075bd7bd19c70cf67c8badfa36cf7c5d8de3c9ddb8420c51e10d9c50e94920", size = 1392539, upload-time = "2026-03-09T13:15:16.661Z" }, + { url = "https://files.pythonhosted.org/packages/ba/01/77a19cacc0893fa13fafa46d1bba06fb4dc2360b3292baf4b56d8e067b24/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bdd3e53429ff02aa319ba59dfe4ceeec345bf46cf180ec2cf6fd5b942e7975e9", size = 1405310, upload-time = "2026-03-09T13:15:18.229Z" }, + { url = "https://files.pythonhosted.org/packages/53/39/bcaf5d0cca50e604cfa9b4e3ae1d64b50ca1ae5b754122396084599ef903/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cdcb35dc9d807259c981a85531048ede628eabcffb3239adf3d17463518992d", size = 1456244, upload-time = "2026-03-09T13:15:20.444Z" }, + { url = "https://files.pythonhosted.org/packages/d0/7a/72c187abc6975f6978c3e39b7cf67aeb8b3c0a8f9790aa7fd412855e9e1f/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:70d593af6a6ca332d1df73d519fddb5148edb15cd90d5f0155e3746a6d4fcc65", size = 1073154, upload-time = "2026-03-09T13:15:22.039Z" }, + { url = "https://files.pythonhosted.org/packages/c7/ca/cf5b25783ebbd59143b4371ed0c8428a278abe68d6d0104b01865b1bbd0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:377815a8616074cabbf3f53354e1d040c35815a134e01d7614b7692e4bf8acfa", size = 2334377, upload-time = "2026-03-09T13:15:23.741Z" }, + { url = "https://files.pythonhosted.org/packages/4a/e5/b1f492adc516796e88751282276745340e2a72dcd0d36cf7173e0daf3210/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0255a027391d52944eae1dbb5d4cc5903f57092f3674e8e544cdd2622826b3f0", size = 2425288, upload-time = "2026-03-09T13:15:25.789Z" }, + { url = "https://files.pythonhosted.org/packages/e6/e5/9b21fbe91a61b8f409d74a26498706e97a48008bfcd1864373d32a6ba31c/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:012b1eb16e28718fa782b5e61dc6f2da1f0792ca73bd05d54de6cb9561665fc9", size = 2063158, upload-time = "2026-03-09T13:15:27.63Z" }, + { url = "https://files.pythonhosted.org/packages/b1/02/83f47986138310f95ea95531f851b2a62227c11cbc3e690ae1374fe49f0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e3aafb33aed7479377e5e9a82e9d4bf87063741fc99fc7ae48b0f16e32bdd6f", size = 2597260, upload-time = "2026-03-09T13:15:29.421Z" }, + { url = "https://files.pythonhosted.org/packages/07/18/43a5f24608d8c313dd189cf838c8e68d75b115567c6279de7796197cfb6a/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7a116ae737f0000343218c4edf5bd45893bfeaff0993c0b215d7124c9f77646", size = 2394403, upload-time = "2026-03-09T13:15:31.517Z" }, + { url = "https://files.pythonhosted.org/packages/3b/b5/98222136d839b8afabcaa943b09bd05888c2d36355b7e448550211d1fca4/kiwisolver-1.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1dd9b0b119a350976a6d781e7278ec7aca0b201e1a9e2d23d9804afecb6ca681", size = 79687, upload-time = "2026-03-09T13:15:33.204Z" }, + { url = "https://files.pythonhosted.org/packages/99/a2/ca7dc962848040befed12732dff6acae7fb3c4f6fc4272b3f6c9a30b8713/kiwisolver-1.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:58f812017cd2985c21fbffb4864d59174d4903dd66fa23815e74bbc7a0e2dd57", size = 70032, upload-time = "2026-03-09T13:15:34.411Z" }, + { url = "https://files.pythonhosted.org/packages/1c/fa/2910df836372d8761bb6eff7d8bdcb1613b5c2e03f260efe7abe34d388a7/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797", size = 130262, upload-time = "2026-03-09T13:15:35.629Z" }, + { url = "https://files.pythonhosted.org/packages/0f/41/c5f71f9f00aabcc71fee8b7475e3f64747282580c2fe748961ba29b18385/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203", size = 138036, upload-time = "2026-03-09T13:15:36.894Z" }, + { url = "https://files.pythonhosted.org/packages/fa/06/7399a607f434119c6e1fdc8ec89a8d51ccccadf3341dee4ead6bd14caaf5/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7", size = 194295, upload-time = "2026-03-09T13:15:38.22Z" }, + { url = "https://files.pythonhosted.org/packages/b5/91/53255615acd2a1eaca307ede3c90eb550bae9c94581f8c00081b6b1c8f44/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57", size = 75987, upload-time = "2026-03-09T13:15:39.65Z" }, +] + +[[package]] +name = "lark" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732, upload-time = "2025-10-27T18:25:56.653Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/63/94/a8066f84d62ab666d61ef97deba1a33126e3e5c0c0da2c458ada17053ed6/jsondiff-2.2.1-py3-none-any.whl", hash = "sha256:b1f0f7e2421881848b1d556d541ac01a91680cfcc14f51a9b62cdf4da0e56722", size = 13440, upload-time = "2024-08-29T04:09:04.955Z" }, + { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151, upload-time = "2025-10-27T18:25:54.882Z" }, ] [[package]] @@ -1254,6 +2115,72 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, ] +[[package]] +name = "matplotlib" +version = "3.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1f/24/080c99d223d158d3a8902769269ab6da5b50f7a0e6e072513907e02b7a6c/matplotlib-3.11.0.tar.gz", hash = "sha256:68c0c7be01b30dcca3638934f7f591df73401235cbdbf0d1ab1c71e7db7f8b57", size = 33251176, upload-time = "2026-06-12T02:29:15.508Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/17/f5276b496c61477a6c4fc5e7401f4bfe1c2e5ef7c6cd67896f2ade3809cb/matplotlib-3.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:06b5872e9cf11adc8f589ded3ce11bc3e1061ad498259664fabc1f6615beb918", size = 9449976, upload-time = "2026-06-12T02:27:50.989Z" }, + { url = "https://files.pythonhosted.org/packages/82/34/bdd77418adb2178a1d59f044bd67bfebb115896e91b840b8a197eb3f4f4e/matplotlib-3.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0515d495124be3124340e59f164d901ed4484e2246a5b74cfa483cac3b80bd97", size = 9279307, upload-time = "2026-06-12T02:27:53.247Z" }, + { url = "https://files.pythonhosted.org/packages/94/95/7f522393c88313336b20d70fc849555757b2e5febc22b83b3a3f0fd4bce9/matplotlib-3.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be5f93a1d21981bfb802ded0d77a0caa92d4342a47d45754fac77e314a506344", size = 10031353, upload-time = "2026-06-12T02:27:55.215Z" }, + { url = "https://files.pythonhosted.org/packages/87/ce/8f25a0e3186aefd61913e7467d1b999465bcd0d0c03ac695c1b26ca559b7/matplotlib-3.11.0-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41635d7909d19e52e924a521dde6d8f670b0f53ab1d0e8c331fa831554f681d1", size = 10839232, upload-time = "2026-06-12T02:27:57.746Z" }, + { url = "https://files.pythonhosted.org/packages/85/c2/db15da2bbdf9e3ca66df7db8e2c33a1dfed67be24a24d2c878efaaff01d6/matplotlib-3.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:94f5000f67ca9faa300863ea17f8bce9175cb67b88bec4bc7780502d53dd7c9e", size = 10923899, upload-time = "2026-06-12T02:28:00.223Z" }, + { url = "https://files.pythonhosted.org/packages/e5/2f/a58a4443a4d052a4ea77557478336aefc26c7981f6408d37adba763aa758/matplotlib-3.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:ac6f1ef39f3d0f9e2463303013094992cdbe0f85f43bc54155bc472b2042768e", size = 9329528, upload-time = "2026-06-12T02:28:02.27Z" }, + { url = "https://files.pythonhosted.org/packages/61/0f/4b669589d47733b97ab9df4b58d6fc1e68acb5ea42a928dc7cbdd6bf5871/matplotlib-3.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:9dd11fb612ce7bc60b1de5b4fc87ff959d22317b5de42aabf392f66f97af22eb", size = 9003413, upload-time = "2026-06-12T02:28:04.49Z" }, + { url = "https://files.pythonhosted.org/packages/55/41/aa47f156b061d14c98b906f76c428507397708ec63ff94f410ae1752b426/matplotlib-3.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce3b839b34ae1f430b4616893a2945a2999debaa7e94e7e29a2a8bbf286f7b5", size = 9450532, upload-time = "2026-06-12T02:28:06.769Z" }, + { url = "https://files.pythonhosted.org/packages/8c/4f/5a9eb0375e81413953febf8af7b012a6b6357f53438a15c4f5ad86c6bbb5/matplotlib-3.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:373db8f91214e8ccaf35ac833cc1dd59dd961e148bbd55dd027141591dde1313", size = 9279760, upload-time = "2026-06-12T02:28:09.152Z" }, + { url = "https://files.pythonhosted.org/packages/a4/c0/1117d53077e3ac3152503a84e9cf7a5c239576805ee71276e80c2aaa7471/matplotlib-3.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be152b7570324dc8d01574cc9474dd2d803237acf528bcbb5b211fa347461a09", size = 10031623, upload-time = "2026-06-12T02:28:11.26Z" }, + { url = "https://files.pythonhosted.org/packages/92/7e/e937138daffad65b71bf831a377809dcbc830fb4f31a31e067dc1faa2575/matplotlib-3.11.0-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:126f256df600652d7e4b394cf3164ff75210a00038f287c95a012a6f58d0e83f", size = 10839372, upload-time = "2026-06-12T02:28:14.102Z" }, + { url = "https://files.pythonhosted.org/packages/1d/c2/438ecc197ffb8023b6b9922915542f2172f5fd45b76703b0b4fc47322243/matplotlib-3.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:03acfeddf87b0dddb11b081ef7740ad445a3ca8bcb6b8e3011b08f2cf802b75c", size = 10924099, upload-time = "2026-06-12T02:28:16.383Z" }, + { url = "https://files.pythonhosted.org/packages/40/2e/395883da416f378b3ed2c9f3e843ac477eae1ce731b671b79adaa6f0bacd/matplotlib-3.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:ab3722f04f3ff34c23b5012c5873d2894174e06c3822fcdac3610965a5ac7d06", size = 9329727, upload-time = "2026-06-12T02:28:18.581Z" }, + { url = "https://files.pythonhosted.org/packages/61/82/2c388956abf8bf392dfb5b8917c502f1082df6a941b781ab8c8e5ba2474b/matplotlib-3.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:c945824670fb8915b4ac879e5e61f3c58e0913022f70a0de4c082b17372f8771", size = 9003506, upload-time = "2026-06-12T02:28:20.474Z" }, + { url = "https://files.pythonhosted.org/packages/c8/c1/34454baa44da7975ada82e9aea37105ec47059514dc967d3be14426ba8dc/matplotlib-3.11.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3489c3dc487669b4a980bc3068f87856de7a1564248d3f6c629efb2a58b03f24", size = 9499838, upload-time = "2026-06-12T02:28:22.713Z" }, + { url = "https://files.pythonhosted.org/packages/b1/c3/98fe79a398cf232219f090163a7fa7e6766e9f2e0ad26df54d6f8934d8ee/matplotlib-3.11.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6a98f5476ce784a50ce09998f4ae1e6a9f25043cef8a480c98949902eda74620", size = 9332298, upload-time = "2026-06-12T02:28:24.796Z" }, + { url = "https://files.pythonhosted.org/packages/95/e4/b4b7c33151e74e5c802f3cde1ba807ebfc38401e329b44e215a5888dd76d/matplotlib-3.11.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:565af866fd63e4bd3f987d580afe27c44c2552a3b3305f4ecbb85133601ea6f3", size = 10045491, upload-time = "2026-06-12T02:28:27.141Z" }, + { url = "https://files.pythonhosted.org/packages/71/28/394548efd68354110c1a1be11fe6b6e559e06d1a23da35908a0e316c55a9/matplotlib-3.11.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e6b3e64dea5062c570f04358e2711859f3531b459f29516274fbad889079e4f3", size = 10857059, upload-time = "2026-06-12T02:28:29.222Z" }, + { url = "https://files.pythonhosted.org/packages/c8/44/e7922e6e2a4d63bdfbc9dc4a53e3850ab438d46cf42e6779bb15ec92c948/matplotlib-3.11.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:942b37c5db1899610bd1543ce8e13e4ecff9a4633e7f63bb6aa9205d2644ebd1", size = 10939576, upload-time = "2026-06-12T02:28:31.66Z" }, + { url = "https://files.pythonhosted.org/packages/3d/be/b1ca96003a441d619b727fee21d671fdff7a5ce2f1bb797b2521aa2f679a/matplotlib-3.11.0-cp313-cp313t-win_amd64.whl", hash = "sha256:c08e649a6313e1291e713623b97a38e5bb4aa580b2a100a94a3309bc6b9c8eb3", size = 9379519, upload-time = "2026-06-12T02:28:33.888Z" }, + { url = "https://files.pythonhosted.org/packages/e3/72/4bf3b91821c34596dd6a7bdac5836d94f744144c8208939ef49d8ec43f7e/matplotlib-3.11.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2746cd2c113742ff6ce37a864c5ac5fd7aa644568f445e66166e457ac78e40e0", size = 9055456, upload-time = "2026-06-12T02:28:35.878Z" }, + { url = "https://files.pythonhosted.org/packages/57/52/a94102ac99eb78e2fe9b826674f9ef9ee23327110ea6ab4776c1b4eb6209/matplotlib-3.11.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3338e3e3de128cf50d0d2fb92a122815daf9c755bd882a474343c05f8fd7ec79", size = 9452137, upload-time = "2026-06-12T02:28:37.93Z" }, + { url = "https://files.pythonhosted.org/packages/7c/03/b8cdb625a21f710dfa11bbca1f48fb4057d2c0286975f8b415bf80942c99/matplotlib-3.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:25c2e5455efd8d99f41fb79871a31feb7d301569642e332ec58d72cfe9282bc3", size = 9281514, upload-time = "2026-06-12T02:28:40.028Z" }, + { url = "https://files.pythonhosted.org/packages/b7/2d/4e1240ea82ee197dfb3851e71f71c87eeeb975f1753b56a0588e4e80739a/matplotlib-3.11.0-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9695457a467ff86d23f35037a43deb6f1134dd6d3e2ac8ce1e2087cff09ffb9", size = 10843005, upload-time = "2026-06-12T02:28:42.39Z" }, + { url = "https://files.pythonhosted.org/packages/29/dc/6377ecfaa5fef79430f74a1a16638b4e2aa30d4692bae2c19f9d76fe3b01/matplotlib-3.11.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:19c16c61dea63b3582918503e6b294193961261d9daa806d4ae2151f1ad05430", size = 11127459, upload-time = "2026-06-12T02:28:44.483Z" }, + { url = "https://files.pythonhosted.org/packages/6f/41/795c405aa7560443a3b01309424cde4a1113b85c90b8a63417444a749617/matplotlib-3.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2d72ea8b7924f3cb955e61518d21e43b3df1e6c8a793b480a0c1214f185d30ba", size = 10925160, upload-time = "2026-06-12T02:28:46.564Z" }, + { url = "https://files.pythonhosted.org/packages/1a/f7/3a9e6389a7cfaeff76c56e40c2dabcb13110e21e82f837228c834ebe748c/matplotlib-3.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:1c02da0a629dfa9debf52725ea06866b74c1fb70a895bae05e4493d34074f9f2", size = 9485186, upload-time = "2026-06-12T02:28:49.344Z" }, + { url = "https://files.pythonhosted.org/packages/8b/c0/396478ee7cf2091d182db8b4a8695f6a37f1ddb978989cf9dbb84cd5c123/matplotlib-3.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:aa55d73b3117d4b07f959cd9eb6f69b375d8df3414139c479388e551aa5d999d", size = 9160349, upload-time = "2026-06-12T02:28:51.382Z" }, + { url = "https://files.pythonhosted.org/packages/c5/6f/1c3bd51bb2b34eaacdcf3c3d859dbb357f952fc8020c617dc118ad7c9e38/matplotlib-3.11.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a9d8c6e7cd2f0ddf11d8d92e520dd1d9d2abb0cf6ac8831e338666c81e905847", size = 9500921, upload-time = "2026-06-12T02:28:53.443Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/4d861d0121840cb1a3fd4a10deb211efd6fccd481ed23e553f31f4f4da4a/matplotlib-3.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:be050fcf32f729eda99f7f75a80bf67612ce16ab9ac1c23a387dcaede95cb70e", size = 9332190, upload-time = "2026-06-12T02:28:55.623Z" }, + { url = "https://files.pythonhosted.org/packages/4b/cb/22f6bc35711a0b5639a784e74e653e77c86210bd4304449dd399a482f74e/matplotlib-3.11.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dfabef0230d0697aa0d717385194dd41162e00207a68bf4abf94c2bf4c27dca0", size = 10854181, upload-time = "2026-06-12T02:28:57.856Z" }, + { url = "https://files.pythonhosted.org/packages/3f/7e/9a9eaca731a2939589da520f0ebe8fd8753d0f51fca98c7d20af6dbe261a/matplotlib-3.11.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1644db30e759199443493ac5e5caec24fdb775a8f6123021f85ba47c4133c3cb", size = 11137715, upload-time = "2026-06-12T02:29:00.555Z" }, + { url = "https://files.pythonhosted.org/packages/ef/f9/9b030b6088354acb0296871bb624b25befc1c42509d3c6cd17420c83a5b8/matplotlib-3.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:15b0d160079cb10699a0e98b5989c70677b2df7cacdc62af67c30f2facec46d9", size = 10939427, upload-time = "2026-06-12T02:29:02.527Z" }, + { url = "https://files.pythonhosted.org/packages/59/94/6b273eaee4ee250863567d100865da61a5c1527fa67f527b7ed22e0dd29c/matplotlib-3.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:446307e6b04b57b1f1239e228a1ec2af0d589a1008cebc3dfa3f5441d095cfb6", size = 9535809, upload-time = "2026-06-12T02:29:04.994Z" }, + { url = "https://files.pythonhosted.org/packages/60/95/1d36bddf2b7e2692c1540e78a6e5bc88bc1496b137e3e35a611f91b65ac3/matplotlib-3.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:652fb5696271d4c50f196d22a5ff4f8e4444c74f847423570d7dc0aa2bbd0159", size = 9209226, upload-time = "2026-06-12T02:29:07.033Z" }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bd/c0/9f7c9a46090390368a4d7bcb76bb87a4a36c421e4c0792cdb53486ffac7a/matplotlib_inline-0.2.2.tar.gz", hash = "sha256:72f3fe8fce36b70d4a5b612f899090cd0401deddc4ea90e1572b9f4bfb058c79", size = 8150, upload-time = "2026-05-08T17:33:33.49Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/09/5b161152e2d90f7b87f781c2e1267494aef9c32498df793f73ad0a0a494a/matplotlib_inline-0.2.2-py3-none-any.whl", hash = "sha256:3c821cf1c209f59fb2d2d64abbf5b23b67bcb2210d663f9918dd851c6da1fcf6", size = 9534, upload-time = "2026-05-08T17:33:32.055Z" }, +] + [[package]] name = "mdurl" version = "0.1.2" @@ -1289,6 +2216,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/76/8e/56ccb09c7232a55403a7637caa21922f3b65901a37f5e8bdb405d0de0946/mike-2.2.0-py3-none-any.whl", hash = "sha256:e1f4981c1152eec7c2490a3401142292cc47d686194188416db2648fdfe1d040", size = 34026, upload-time = "2026-04-14T04:59:02.602Z" }, ] +[[package]] +name = "mistune" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/04/5f/007786743f962224423753b78f7d7acb0f2ade46d1604f2e0fa2bedf9020/mistune-3.3.2.tar.gz", hash = "sha256:e12ee4f1e74336e91aa1141e35f913b337c40bdf7c0cc49f21fb853a27e8b62f", size = 111284, upload-time = "2026-06-23T00:29:28.568Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/43/894c2cbbcbdf53b57d1257a249811abe2ee9ab7ef76af301b40f1c054533/mistune-3.3.2-py3-none-any.whl", hash = "sha256:a678a56387d487db7368ede4647cb2ba1deff22ce61f92343e4ebe0ddfce4f2d", size = 61554, upload-time = "2026-06-23T00:29:27.088Z" }, +] + [[package]] name = "mkdocs" version = "1.6.1" @@ -1375,46 +2311,54 @@ wheels = [ [[package]] name = "msgpack" -version = "1.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ad/bd/8b0d01c756203fbab65d265859749860682ccd2a59594609aeec3a144efa/msgpack-1.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:70a0dff9d1f8da25179ffcf880e10cf1aad55fdb63cd59c9a49a1b82290062aa", size = 81939, upload-time = "2025-10-08T09:15:01.472Z" }, - { url = "https://files.pythonhosted.org/packages/34/68/ba4f155f793a74c1483d4bdef136e1023f7bcba557f0db4ef3db3c665cf1/msgpack-1.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:446abdd8b94b55c800ac34b102dffd2f6aa0ce643c55dfc017ad89347db3dbdb", size = 85064, upload-time = "2025-10-08T09:15:03.764Z" }, - { url = "https://files.pythonhosted.org/packages/f2/60/a064b0345fc36c4c3d2c743c82d9100c40388d77f0b48b2f04d6041dbec1/msgpack-1.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c63eea553c69ab05b6747901b97d620bb2a690633c77f23feb0c6a947a8a7b8f", size = 417131, upload-time = "2025-10-08T09:15:05.136Z" }, - { url = "https://files.pythonhosted.org/packages/65/92/a5100f7185a800a5d29f8d14041f61475b9de465ffcc0f3b9fba606e4505/msgpack-1.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:372839311ccf6bdaf39b00b61288e0557916c3729529b301c52c2d88842add42", size = 427556, upload-time = "2025-10-08T09:15:06.837Z" }, - { url = "https://files.pythonhosted.org/packages/f5/87/ffe21d1bf7d9991354ad93949286f643b2bb6ddbeab66373922b44c3b8cc/msgpack-1.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2929af52106ca73fcb28576218476ffbb531a036c2adbcf54a3664de124303e9", size = 404920, upload-time = "2025-10-08T09:15:08.179Z" }, - { url = "https://files.pythonhosted.org/packages/ff/41/8543ed2b8604f7c0d89ce066f42007faac1eaa7d79a81555f206a5cdb889/msgpack-1.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be52a8fc79e45b0364210eef5234a7cf8d330836d0a64dfbb878efa903d84620", size = 415013, upload-time = "2025-10-08T09:15:09.83Z" }, - { url = "https://files.pythonhosted.org/packages/41/0d/2ddfaa8b7e1cee6c490d46cb0a39742b19e2481600a7a0e96537e9c22f43/msgpack-1.1.2-cp312-cp312-win32.whl", hash = "sha256:1fff3d825d7859ac888b0fbda39a42d59193543920eda9d9bea44d958a878029", size = 65096, upload-time = "2025-10-08T09:15:11.11Z" }, - { url = "https://files.pythonhosted.org/packages/8c/ec/d431eb7941fb55a31dd6ca3404d41fbb52d99172df2e7707754488390910/msgpack-1.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1de460f0403172cff81169a30b9a92b260cb809c4cb7e2fc79ae8d0510c78b6b", size = 72708, upload-time = "2025-10-08T09:15:12.554Z" }, - { url = "https://files.pythonhosted.org/packages/c5/31/5b1a1f70eb0e87d1678e9624908f86317787b536060641d6798e3cf70ace/msgpack-1.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:be5980f3ee0e6bd44f3a9e9dea01054f175b50c3e6cdb692bc9424c0bbb8bf69", size = 64119, upload-time = "2025-10-08T09:15:13.589Z" }, - { url = "https://files.pythonhosted.org/packages/6b/31/b46518ecc604d7edf3a4f94cb3bf021fc62aa301f0cb849936968164ef23/msgpack-1.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4efd7b5979ccb539c221a4c4e16aac1a533efc97f3b759bb5a5ac9f6d10383bf", size = 81212, upload-time = "2025-10-08T09:15:14.552Z" }, - { url = "https://files.pythonhosted.org/packages/92/dc/c385f38f2c2433333345a82926c6bfa5ecfff3ef787201614317b58dd8be/msgpack-1.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42eefe2c3e2af97ed470eec850facbe1b5ad1d6eacdbadc42ec98e7dcf68b4b7", size = 84315, upload-time = "2025-10-08T09:15:15.543Z" }, - { url = "https://files.pythonhosted.org/packages/d3/68/93180dce57f684a61a88a45ed13047558ded2be46f03acb8dec6d7c513af/msgpack-1.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1fdf7d83102bf09e7ce3357de96c59b627395352a4024f6e2458501f158bf999", size = 412721, upload-time = "2025-10-08T09:15:16.567Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ba/459f18c16f2b3fc1a1ca871f72f07d70c07bf768ad0a507a698b8052ac58/msgpack-1.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fac4be746328f90caa3cd4bc67e6fe36ca2bf61d5c6eb6d895b6527e3f05071e", size = 424657, upload-time = "2025-10-08T09:15:17.825Z" }, - { url = "https://files.pythonhosted.org/packages/38/f8/4398c46863b093252fe67368b44edc6c13b17f4e6b0e4929dbf0bdb13f23/msgpack-1.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fffee09044073e69f2bad787071aeec727183e7580443dfeb8556cbf1978d162", size = 402668, upload-time = "2025-10-08T09:15:19.003Z" }, - { url = "https://files.pythonhosted.org/packages/28/ce/698c1eff75626e4124b4d78e21cca0b4cc90043afb80a507626ea354ab52/msgpack-1.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5928604de9b032bc17f5099496417f113c45bc6bc21b5c6920caf34b3c428794", size = 419040, upload-time = "2025-10-08T09:15:20.183Z" }, - { url = "https://files.pythonhosted.org/packages/67/32/f3cd1667028424fa7001d82e10ee35386eea1408b93d399b09fb0aa7875f/msgpack-1.1.2-cp313-cp313-win32.whl", hash = "sha256:a7787d353595c7c7e145e2331abf8b7ff1e6673a6b974ded96e6d4ec09f00c8c", size = 65037, upload-time = "2025-10-08T09:15:21.416Z" }, - { url = "https://files.pythonhosted.org/packages/74/07/1ed8277f8653c40ebc65985180b007879f6a836c525b3885dcc6448ae6cb/msgpack-1.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:a465f0dceb8e13a487e54c07d04ae3ba131c7c5b95e2612596eafde1dccf64a9", size = 72631, upload-time = "2025-10-08T09:15:22.431Z" }, - { url = "https://files.pythonhosted.org/packages/e5/db/0314e4e2db56ebcf450f277904ffd84a7988b9e5da8d0d61ab2d057df2b6/msgpack-1.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:e69b39f8c0aa5ec24b57737ebee40be647035158f14ed4b40e6f150077e21a84", size = 64118, upload-time = "2025-10-08T09:15:23.402Z" }, - { url = "https://files.pythonhosted.org/packages/22/71/201105712d0a2ff07b7873ed3c220292fb2ea5120603c00c4b634bcdafb3/msgpack-1.1.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e23ce8d5f7aa6ea6d2a2b326b4ba46c985dbb204523759984430db7114f8aa00", size = 81127, upload-time = "2025-10-08T09:15:24.408Z" }, - { url = "https://files.pythonhosted.org/packages/1b/9f/38ff9e57a2eade7bf9dfee5eae17f39fc0e998658050279cbb14d97d36d9/msgpack-1.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c15b7d74c939ebe620dd8e559384be806204d73b4f9356320632d783d1f7939", size = 84981, upload-time = "2025-10-08T09:15:25.812Z" }, - { url = "https://files.pythonhosted.org/packages/8e/a9/3536e385167b88c2cc8f4424c49e28d49a6fc35206d4a8060f136e71f94c/msgpack-1.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99e2cb7b9031568a2a5c73aa077180f93dd2e95b4f8d3b8e14a73ae94a9e667e", size = 411885, upload-time = "2025-10-08T09:15:27.22Z" }, - { url = "https://files.pythonhosted.org/packages/2f/40/dc34d1a8d5f1e51fc64640b62b191684da52ca469da9cd74e84936ffa4a6/msgpack-1.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:180759d89a057eab503cf62eeec0aa61c4ea1200dee709f3a8e9397dbb3b6931", size = 419658, upload-time = "2025-10-08T09:15:28.4Z" }, - { url = "https://files.pythonhosted.org/packages/3b/ef/2b92e286366500a09a67e03496ee8b8ba00562797a52f3c117aa2b29514b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:04fb995247a6e83830b62f0b07bf36540c213f6eac8e851166d8d86d83cbd014", size = 403290, upload-time = "2025-10-08T09:15:29.764Z" }, - { url = "https://files.pythonhosted.org/packages/78/90/e0ea7990abea5764e4655b8177aa7c63cdfa89945b6e7641055800f6c16b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8e22ab046fa7ede9e36eeb4cfad44d46450f37bb05d5ec482b02868f451c95e2", size = 415234, upload-time = "2025-10-08T09:15:31.022Z" }, - { url = "https://files.pythonhosted.org/packages/72/4e/9390aed5db983a2310818cd7d3ec0aecad45e1f7007e0cda79c79507bb0d/msgpack-1.1.2-cp314-cp314-win32.whl", hash = "sha256:80a0ff7d4abf5fecb995fcf235d4064b9a9a8a40a3ab80999e6ac1e30b702717", size = 66391, upload-time = "2025-10-08T09:15:32.265Z" }, - { url = "https://files.pythonhosted.org/packages/6e/f1/abd09c2ae91228c5f3998dbd7f41353def9eac64253de3c8105efa2082f7/msgpack-1.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:9ade919fac6a3e7260b7f64cea89df6bec59104987cbea34d34a2fa15d74310b", size = 73787, upload-time = "2025-10-08T09:15:33.219Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b0/9d9f667ab48b16ad4115c1935d94023b82b3198064cb84a123e97f7466c1/msgpack-1.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:59415c6076b1e30e563eb732e23b994a61c159cec44deaf584e5cc1dd662f2af", size = 66453, upload-time = "2025-10-08T09:15:34.225Z" }, - { url = "https://files.pythonhosted.org/packages/16/67/93f80545eb1792b61a217fa7f06d5e5cb9e0055bed867f43e2b8e012e137/msgpack-1.1.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:897c478140877e5307760b0ea66e0932738879e7aa68144d9b78ea4c8302a84a", size = 85264, upload-time = "2025-10-08T09:15:35.61Z" }, - { url = "https://files.pythonhosted.org/packages/87/1c/33c8a24959cf193966ef11a6f6a2995a65eb066bd681fd085afd519a57ce/msgpack-1.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a668204fa43e6d02f89dbe79a30b0d67238d9ec4c5bd8a940fc3a004a47b721b", size = 89076, upload-time = "2025-10-08T09:15:36.619Z" }, - { url = "https://files.pythonhosted.org/packages/fc/6b/62e85ff7193663fbea5c0254ef32f0c77134b4059f8da89b958beb7696f3/msgpack-1.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5559d03930d3aa0f3aacb4c42c776af1a2ace2611871c84a75afe436695e6245", size = 435242, upload-time = "2025-10-08T09:15:37.647Z" }, - { url = "https://files.pythonhosted.org/packages/c1/47/5c74ecb4cc277cf09f64e913947871682ffa82b3b93c8dad68083112f412/msgpack-1.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70c5a7a9fea7f036b716191c29047374c10721c389c21e9ffafad04df8c52c90", size = 432509, upload-time = "2025-10-08T09:15:38.794Z" }, - { url = "https://files.pythonhosted.org/packages/24/a4/e98ccdb56dc4e98c929a3f150de1799831c0a800583cde9fa022fa90602d/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f2cb069d8b981abc72b41aea1c580ce92d57c673ec61af4c500153a626cb9e20", size = 415957, upload-time = "2025-10-08T09:15:40.238Z" }, - { url = "https://files.pythonhosted.org/packages/da/28/6951f7fb67bc0a4e184a6b38ab71a92d9ba58080b27a77d3e2fb0be5998f/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d62ce1f483f355f61adb5433ebfd8868c5f078d1a52d042b0a998682b4fa8c27", size = 422910, upload-time = "2025-10-08T09:15:41.505Z" }, - { url = "https://files.pythonhosted.org/packages/f0/03/42106dcded51f0a0b5284d3ce30a671e7bd3f7318d122b2ead66ad289fed/msgpack-1.1.2-cp314-cp314t-win32.whl", hash = "sha256:1d1418482b1ee984625d88aa9585db570180c286d942da463533b238b98b812b", size = 75197, upload-time = "2025-10-08T09:15:42.954Z" }, - { url = "https://files.pythonhosted.org/packages/15/86/d0071e94987f8db59d4eeb386ddc64d0bb9b10820a8d82bcd3e53eeb2da6/msgpack-1.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5a46bf7e831d09470ad92dff02b8b1ac92175ca36b087f904a0519857c6be3ff", size = 85772, upload-time = "2025-10-08T09:15:43.954Z" }, - { url = "https://files.pythonhosted.org/packages/81/f2/08ace4142eb281c12701fc3b93a10795e4d4dc7f753911d836675050f886/msgpack-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d99ef64f349d5ec3293688e91486c5fdb925ed03807f64d98d205d2713c60b46", size = 70868, upload-time = "2025-10-08T09:15:44.959Z" }, +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/31/f9/c0a1c127f9049db9155afc316952ea571720dd01833ff5e4d7e8e6352dbb/msgpack-1.2.1.tar.gz", hash = "sha256:04c721c2c7448767e9e3f2520a475663d8ee0f09c31890f6d2bd70fd636a9647", size = 183960, upload-time = "2026-06-18T16:13:52.594Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/dd/9e8cbd8f5582ca4b590336f2b91ee5662f6a6ca562b565abaf696a0f81ff/msgpack-1.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2ef59c659f289eddf8aa6623823f19fa2f40a4029266889eac7a2505dd210c35", size = 83531, upload-time = "2026-06-18T16:12:58.249Z" }, + { url = "https://files.pythonhosted.org/packages/50/2e/ebdb85a8da151397a2790363676b7ed7c125924fe618e4c6d8befb0cc62c/msgpack-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d3567748a5107cb40cdf66a275430c2f87c07777698f4bfd25c35f44d533258c", size = 82657, upload-time = "2026-06-18T16:12:59.396Z" }, + { url = "https://files.pythonhosted.org/packages/26/aa/753ad8b007b464e1d8aa0c8e650b9c5f4f725e658fc5ac8a7635c55b7f6e/msgpack-1.2.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60926b75d00c8e816ef98f3034f484a8bc64242d66839cef4cf7e503142316a0", size = 410634, upload-time = "2026-06-18T16:13:00.383Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fd/6adabd4f6d5e686f97dd02ce7fce3fe4cf672cbac36b8f67ff4040e8ad8b/msgpack-1.2.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:020e881a764b20d8d7ca1a54fc01b8175519d108e3c3f194fddc200bda95951a", size = 419989, upload-time = "2026-06-18T16:13:01.776Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cc/85039b7b0eb168aaad7383a23c97e291a11f08351cb45a606ce865e4e3f1/msgpack-1.2.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4202c74688ca06591f78cb18988228bd4cca2cc75d57b60008372892d2f1e6e6", size = 377544, upload-time = "2026-06-18T16:13:03.637Z" }, + { url = "https://files.pythonhosted.org/packages/ed/bf/35963899493b32030c85fc513b723ae66144ac70c11ebc52e889e16e3d99/msgpack-1.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8b267ce94efb76fbd1b3373511420074ee3187f0f7811bf394531de13294735a", size = 400842, upload-time = "2026-06-18T16:13:05.012Z" }, + { url = "https://files.pythonhosted.org/packages/a6/df/8e2ac970c8f99264cd9997d1c73df5466bc19da3301d7dc5500862a9b089/msgpack-1.2.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f1d0f8f98ade9634e01fb704a408f9336c0a8f1117b369f5db83dc7551d8b1", size = 374108, upload-time = "2026-06-18T16:13:06.232Z" }, + { url = "https://files.pythonhosted.org/packages/17/dd/fa8bd265110dfa51c20cb529f9e6d240a16fafe7e645004c6af2d01353ba/msgpack-1.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f02cf17a6ca1abe29b5f980644f7551f94d71f2011509b26d8625ce038f0df64", size = 414939, upload-time = "2026-06-18T16:13:07.478Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b9/8377a5ad8953fc0437c70cc98d9ae29f27fe5ac5109fbec0812085865735/msgpack-1.2.1-cp312-cp312-win32.whl", hash = "sha256:0c0d9802354507bcba62af19c17918e3eb437cc25e6f50657d511b5856a77aac", size = 64504, upload-time = "2026-06-18T16:13:08.822Z" }, + { url = "https://files.pythonhosted.org/packages/57/7f/ce1e377df7e62461fefd9eb23bfb93a4a523f40a517b377b8f844d836828/msgpack-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:5c24aa15d5963051e1a5c62b12c50cd705992502b5ec1f3bece6046f33c9fc24", size = 71421, upload-time = "2026-06-18T16:13:09.828Z" }, + { url = "https://files.pythonhosted.org/packages/8f/32/ebfe84c9929f08f188d56c7a2fd913406a9ddad76a634697c1c43b8112e6/msgpack-1.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:4227224aaec8f7fbcbfbd4272319347b2bb4030366502600f8c45588c5187b07", size = 64775, upload-time = "2026-06-18T16:13:11.056Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ac/dcddcab6f6c20ecb387ca5e980371cdb3f87ff69aeca388be97eebc4c074/msgpack-1.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a70e3cf2804a300d921bb0940426e35f4e489a23adfb77a808892241db0a064", size = 83151, upload-time = "2026-06-18T16:13:12.173Z" }, + { url = "https://files.pythonhosted.org/packages/64/71/fbcfa83a1d6a9c6091942d1cfd070962244664b87427a9a49a6897b1b219/msgpack-1.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:491cc39455ca765fad51fb451bf2915eb2cf41192ab5801ce8d67c1d614fe056", size = 82351, upload-time = "2026-06-18T16:13:13.194Z" }, + { url = "https://files.pythonhosted.org/packages/e3/10/ddf7b06db879e8792d13934ddda09ff20bd2a583fd84c9b59aae9b0e650b/msgpack-1.2.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f310233ef7fb9c14e201c93639fe5f5260b005f56f0b29048e999c30935596cc", size = 407518, upload-time = "2026-06-18T16:13:14.233Z" }, + { url = "https://files.pythonhosted.org/packages/79/d3/36a46a8ed992b781acbc05928bd5bee3c810cb0c3563bf81a7b0c04a1a76/msgpack-1.2.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:787c9bebb5833e8f6fc8abca3c0597683d8d87f56a8842b6b89c75a5f3176e2d", size = 416405, upload-time = "2026-06-18T16:13:15.435Z" }, + { url = "https://files.pythonhosted.org/packages/f9/84/e8e9598b557c0ba6ddae901a73780a4c75ac667dddf59414b1e56a42fb34/msgpack-1.2.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dc871b997a9370d855b7394465f2f350e847a5b806dd38dcc9c989e7d87da155", size = 376257, upload-time = "2026-06-18T16:13:17.022Z" }, + { url = "https://files.pythonhosted.org/packages/40/16/738fe6d875ad7e2a9429c165322a4ec088f4f273cdfae63d96a89c467961/msgpack-1.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:85f57e960d877f2977f6430896191b04a21f8901b3b4baf2e4604329f4db5402", size = 397469, upload-time = "2026-06-18T16:13:18.287Z" }, + { url = "https://files.pythonhosted.org/packages/ca/be/6d5952df75a7f24f35833af764c3a6860780364cb3a0030beb8099e1b2b4/msgpack-1.2.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:1233ee2dd0cefba127583de50ea654677277047d238303521db35def3d7b2e7c", size = 372802, upload-time = "2026-06-18T16:13:19.685Z" }, + { url = "https://files.pythonhosted.org/packages/e1/39/e2ef7dbf0473bcb8dc7c50bf782a892d67414877b63e47fc88eb189ef5e6/msgpack-1.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e3dc2feb0876209d9c38aa56cb1de169bd6c4348f1aa48271f241226590993e6", size = 411273, upload-time = "2026-06-18T16:13:21.028Z" }, + { url = "https://files.pythonhosted.org/packages/ef/c5/133f4512a56e983a93445c836c9d94d88f3bc2e0980ff4b9e577bd8416ce/msgpack-1.2.1-cp313-cp313-win32.whl", hash = "sha256:6d09badf350af2be9d189184e04e64cf54ad93569ab3d96fca58bd3e84aad707", size = 64471, upload-time = "2026-06-18T16:13:22.293Z" }, + { url = "https://files.pythonhosted.org/packages/e2/98/577e10b055096a7dd40732358cabaf7180a20c79ed1dcdbb618e4b9deac7/msgpack-1.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:33f14fba63278b714efe6ad07e50ea5f03d91537aa6a1c5f1ceca4cf44013ca9", size = 71274, upload-time = "2026-06-18T16:13:23.455Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ee/0c0048e7cfbef23c6a94791b8959ab28155232e7956de8a305b5ff588f05/msgpack-1.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:afc5febcd4c99effbc02b528e49d6fd0760b2b7d48c05239e345a5fa6e743d9a", size = 64795, upload-time = "2026-06-18T16:13:24.687Z" }, + { url = "https://files.pythonhosted.org/packages/77/58/cce442852c6b9e1639c7c8ac8fd9143121cb32dab0f308df4d1426a8eb9c/msgpack-1.2.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:05f340e47e7e47d2da8db9b53e1bb1d294369e9ef45a747441309f6650b8351d", size = 83610, upload-time = "2026-06-18T16:13:25.724Z" }, + { url = "https://files.pythonhosted.org/packages/60/5c/15b4c7a0182f75ffa90751958ba36a9c01cafee367d49a3edc10ed140b01/msgpack-1.2.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:810b916696c86ef0deb3b74588480224df4c1b071136c34183e4a2a4284d7ac7", size = 83138, upload-time = "2026-06-18T16:13:26.781Z" }, + { url = "https://files.pythonhosted.org/packages/b8/a6/99e58722feaffc5f2fbcc0c8c0d1451ab9f84097f7af87291b46af2390f4/msgpack-1.2.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ca0dacff965c47afdc3749a8469d7302a8f801d6a28758d55120d75e66ce6889", size = 406090, upload-time = "2026-06-18T16:13:28.072Z" }, + { url = "https://files.pythonhosted.org/packages/19/03/8c63e8cf52958534ef688625965ab04c269a6cadd8caef16758b380a821a/msgpack-1.2.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e2bf9280bceb5efca998435904b5d3e9fdbcc11d90dc9df30aec7973252b720", size = 412106, upload-time = "2026-06-18T16:13:29.427Z" }, + { url = "https://files.pythonhosted.org/packages/63/d2/155d9e71b40e41fd934bc0c48b9b2770f22263e1ac20aad8e29fdca7be3f/msgpack-1.2.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6c4be5d1c02a42b066ca6ddb71adf36432868fdcdb6ee87e634e86e0674190", size = 374851, upload-time = "2026-06-18T16:13:30.631Z" }, + { url = "https://files.pythonhosted.org/packages/98/48/deaf2326262a8d5ea3295ce9649912ecd3f551ba7ec8e33c665d2ba583f3/msgpack-1.2.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec0e675d59150a6269ddc9139087c722292664a37d071a849c05c473350f1f2d", size = 396168, upload-time = "2026-06-18T16:13:31.977Z" }, + { url = "https://files.pythonhosted.org/packages/10/2a/b4410f906c2ec0008f1608d3ab5143afc3ad3f4e6da0fed3ea2231d0bef4/msgpack-1.2.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:dd3bfe82d53edfe4b7fc9a7ec9761e23a7a5b1dac22264505af428253c29ed24", size = 371959, upload-time = "2026-06-18T16:13:33.282Z" }, + { url = "https://files.pythonhosted.org/packages/59/86/1edc67270099a528fa2093ea60fe191233cd238e4bd30cfacf7db79fc959/msgpack-1.2.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5ad5467fc3f68b5468e06c5f788d712e9f8ffc8b0cd1bcb160c105c1ee92dae7", size = 408457, upload-time = "2026-06-18T16:13:34.567Z" }, + { url = "https://files.pythonhosted.org/packages/82/90/8b630fef07d8c5ab457b71ff2c217910c83d333c7a68472c186e87cc504a/msgpack-1.2.1-cp314-cp314-win32.whl", hash = "sha256:98b58bdb89c46190e4609bb36abe17c6d4105ad13f9c5f8f6f64d320f8ced3fb", size = 65942, upload-time = "2026-06-18T16:13:36.056Z" }, + { url = "https://files.pythonhosted.org/packages/16/f1/467b81e98b24dd3885d7b1857728797b4ffc76a7a7483af4fb321a07de3c/msgpack-1.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:74847557e28ce71bd3c438a447ca90e4b507e997ddbdef8a12a7b283b86c156b", size = 72627, upload-time = "2026-06-18T16:13:37.079Z" }, + { url = "https://files.pythonhosted.org/packages/a7/1d/5d8c4c89985feb6acefb82a09e501c60392261856d2408d20bfe4f0360b1/msgpack-1.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:b50b727bd652bdc37d950336c848ef20ec54a4cafc38dce19b1cd86ad625d0f7", size = 66908, upload-time = "2026-06-18T16:13:38.23Z" }, + { url = "https://files.pythonhosted.org/packages/1b/02/ad2afb678b4de94496cd432b581759b756a92c1192d8c767edd6b132efdc/msgpack-1.2.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8d00f177ca88a77c1cf848d204a38f249751650b601cb6532acc68805d8a8273", size = 86000, upload-time = "2026-06-18T16:13:39.44Z" }, + { url = "https://files.pythonhosted.org/packages/54/74/0b797484013128837f3b1cbb6cea019277c4de4e377dc512b4d9a0f92940/msgpack-1.2.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5bb9c386f0a329c035ddbab4b72d1028bf9627add8dda41070288563d57ed1b1", size = 86544, upload-time = "2026-06-18T16:13:40.447Z" }, + { url = "https://files.pythonhosted.org/packages/a9/b4/b774d7eb95561739907fec675582f83203cf41c597a418c2589b4bfb8e9d/msgpack-1.2.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:20466cca18c49c7292a8984bc15d65857b171e7264bdcb5f96baf8be238791fc", size = 427661, upload-time = "2026-06-18T16:13:41.574Z" }, + { url = "https://files.pythonhosted.org/packages/b2/f9/3243191dc9937e00756c8bc1b0272fed8f23758e43df2a3b46f533e5090f/msgpack-1.2.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:196300e7e5d6e74d50f1607ab9c06c4a1484c383cd22defd727902591f7e8dde", size = 426375, upload-time = "2026-06-18T16:13:42.936Z" }, + { url = "https://files.pythonhosted.org/packages/23/c7/1693111db9944ba4ad4b67a1e788400d78a0b6af7a6523dc7e4e58f8274b/msgpack-1.2.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575957e79cd51903a4e8495a242442949641e08f1efd5197b43bebd3ea7682b4", size = 380495, upload-time = "2026-06-18T16:13:44.306Z" }, + { url = "https://files.pythonhosted.org/packages/3e/2b/92f86956a0c13e8662f7e2ad630c4eb4db07497b967589bd5245e018b2c1/msgpack-1.2.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8c2ed1e48cc0f460bf3c7780e7137ff21a4e18433451916f2442c1b21036cd7d", size = 410897, upload-time = "2026-06-18T16:13:45.629Z" }, + { url = "https://files.pythonhosted.org/packages/da/ea/1479f72d200313a76fc2f823a79d1e07ed052ab7b8a0280640aa7b95de42/msgpack-1.2.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5f6277e5f783c36786a145e0247fc189a03f35f84b251646e53592d2bc12b355", size = 378519, upload-time = "2026-06-18T16:13:46.998Z" }, + { url = "https://files.pythonhosted.org/packages/f5/4d/fa006060ffa1011d32bfae826fe766fe73e02982183601633b7121058ab3/msgpack-1.2.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f9389552ecf4784886345ead0647e4edc96bee37cbab05b75540f542f766c48c", size = 419815, upload-time = "2026-06-18T16:13:48.205Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/aab6c946570496b78e67804721f3d5e2d62a93081b9b37df77764ef56347/msgpack-1.2.1-cp314-cp314t-win32.whl", hash = "sha256:c1c79a604a2969a868a78b6ebd27a887e00c624f14f66b3038e0590cb23332d1", size = 70914, upload-time = "2026-06-18T16:13:49.385Z" }, + { url = "https://files.pythonhosted.org/packages/13/0a/e608956488a2af014cfe6e3d665e090b8ee42aa14b07f8f95b8880d66b09/msgpack-1.2.1-cp314-cp314t-win_amd64.whl", hash = "sha256:f12038a35fabd52e56a3547bab42401af49a45caa6dd00b34c44de235bc93ee2", size = 77999, upload-time = "2026-06-18T16:13:50.467Z" }, + { url = "https://files.pythonhosted.org/packages/d2/8a/27e2e57055176e366a46b85d02d68e7a5bcfbdd8474c9706375d965f24d3/msgpack-1.2.1-cp314-cp314t-win_arm64.whl", hash = "sha256:0adcf06ffde0777c0e1a9b771a2b1c4226ba1bbf748c8efcc02fcdeca3299107", size = 71160, upload-time = "2026-06-18T16:13:51.498Z" }, ] [[package]] @@ -1525,6 +2469,70 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, ] +[[package]] +name = "nbclient" +version = "0.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "nbformat" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/a5/b3bae4b590c0cbcada2c63a34f7580024e834a8ba213e949a2f906705787/nbclient-0.11.0.tar.gz", hash = "sha256:04a134a5b087f2c5887f228aca155db50169b8cd9334dee6942c8e927e56081a", size = 62535, upload-time = "2026-06-05T07:52:41.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/c9/94d73e5a01c5b926c3fa2496e97d7a8dc28ed5a77c0b2ed712f1a62e6694/nbclient-0.11.0-py3-none-any.whl", hash = "sha256:ef7fa0d59d6e1d41103933d8a445a18d5de860ca6b613b87b8574accdb3c2895", size = 25288, upload-time = "2026-06-05T07:52:40.115Z" }, +] + +[[package]] +name = "nbconvert" +version = "7.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "bleach", extra = ["css"] }, + { name = "defusedxml" }, + { name = "jinja2" }, + { name = "jupyter-core" }, + { name = "jupyterlab-pygments" }, + { name = "markupsafe" }, + { name = "mistune" }, + { name = "nbclient" }, + { name = "nbformat" }, + { name = "packaging" }, + { name = "pandocfilters" }, + { name = "pygments" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/01/b1/708e53fe2e429c103c6e6e159106bcf0357ac41aa4c28772bd8402339051/nbconvert-7.17.1.tar.gz", hash = "sha256:34d0d0a7e73ce3cbab6c5aae8f4f468797280b01fd8bd2ca746da8569eddd7d2", size = 865311, upload-time = "2026-04-08T00:44:14.914Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/f8/bb0a9d5f46819c821dc1f004aa2cc29b1d91453297dbf5ff20470f00f193/nbconvert-7.17.1-py3-none-any.whl", hash = "sha256:aa85c087b435e7bf1ffd03319f658e285f2b89eccab33bc1ba7025495ab3e7c8", size = 261927, upload-time = "2026-04-08T00:44:12.845Z" }, +] + +[[package]] +name = "nbformat" +version = "5.10.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fastjsonschema" }, + { name = "jsonschema" }, + { name = "jupyter-core" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, +] + +[[package]] +name = "nest-asyncio2" +version = "1.7.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b4/73/731debf26e27e0a0323d7bda270dc2f634b398e38f040a09da1f4351d0aa/nest_asyncio2-1.7.2.tar.gz", hash = "sha256:1921d70b92cc4612c374928d081552efb59b83d91b2b789d935c665fa01729a8", size = 14743, upload-time = "2026-02-13T00:34:04.386Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/3c/3179b85b0e1c3659f0369940200cd6d0fa900e6cefcc7ea0bc6dd0e29ffb/nest_asyncio2-1.7.2-py3-none-any.whl", hash = "sha256:f5dfa702f3f81f6a03857e9a19e2ba578c0946a4ad417b4c50a24d7ba641fe01", size = 7843, upload-time = "2026-02-13T00:34:02.691Z" }, +] + [[package]] name = "nodeenv" version = "1.10.0" @@ -1534,6 +2542,35 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, ] +[[package]] +name = "notebook" +version = "7.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-builder" }, + { name = "jupyter-server" }, + { name = "jupyterlab" }, + { name = "jupyterlab-server" }, + { name = "notebook-shim" }, + { name = "tornado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0d/44/d5c65783f490298473bb1c05722e05ee2256231389559c2c5ae0a3e5d975/notebook-7.6.0.tar.gz", hash = "sha256:ea13e79e601bf273074895fdfb17dd3f2da916d3c045e0b9c47d18b16ab62481", size = 5497344, upload-time = "2026-06-18T16:18:55.202Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/d1/e617c40db57ff40e75f43a7d4d1c305e3a54c053ab5cb0534a6c314664f9/notebook-7.6.0-py3-none-any.whl", hash = "sha256:98aa2811b54ac191321d5dfce12ca700f8a511a33a26e4de2fa106a357c43d6a", size = 5544575, upload-time = "2026-06-18T16:18:52.551Z" }, +] + +[[package]] +name = "notebook-shim" +version = "0.2.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-server" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167, upload-time = "2024-02-14T23:35:18.353Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307, upload-time = "2024-02-14T23:35:16.286Z" }, +] + [[package]] name = "numcodecs" version = "0.16.5" @@ -1793,6 +2830,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/2b/f8434233fab2bd66a02ec014febe4e5adced20e2693e0e90a07d118ed30e/pandas-3.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:5371b72c2d4d415d08765f32d689217a43227484e81b2305b52076e328f6f482", size = 9455341, upload-time = "2026-03-31T06:48:28.418Z" }, ] +[[package]] +name = "pandocfilters" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, +] + +[[package]] +name = "parso" +version = "0.8.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/4b/90c937815137d43ce71ba043cd3566221e9df6b9c805f24b5d138c9d40a7/parso-0.8.7.tar.gz", hash = "sha256:eaaac4c9fdd5e9e8852dc778d2d7405897ec510f2a298071453e5e3a07914bb1", size = 401824, upload-time = "2026-05-01T23:13:02.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/5d/8268b644392ee874ee82a635cd0df1773de230bde356c38de28e298392cc/parso-0.8.7-py2.py3-none-any.whl", hash = "sha256:a8926eb2a1b915486941fdbd31e86a4baf88fe8c210f25f2f35ecec5b574ca1c", size = 107025, upload-time = "2026-05-01T23:12:58.867Z" }, +] + [[package]] name = "partd" version = "1.4.2" @@ -1815,6 +2870,89 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, ] +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, +] + +[[package]] +name = "pillow" +version = "12.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/3d/bb7fca845737cf9d7dbde16ed1843984665ff2e0a518f5db43e77ec540b9/pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce", size = 47025035, upload-time = "2026-07-01T11:56:38.965Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/bf/fb3ebff8ddcb76aac5a01389251bbbb9519922a9b520d8247c1ca864a25d/pillow-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965", size = 5345969, upload-time = "2026-07-01T11:54:06.397Z" }, + { url = "https://files.pythonhosted.org/packages/d8/66/9a386a92561f402389a4fc70c18838bf6d35eb5eb5c6850b4b2dc64f5048/pillow-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7", size = 4780323, upload-time = "2026-07-01T11:54:09.351Z" }, + { url = "https://files.pythonhosted.org/packages/25/27/ac8f99618ffd3dde21db0f4d4b1d2ab00c0880595bfd17df103f7f39fd0c/pillow-12.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9", size = 6266838, upload-time = "2026-07-01T11:54:11.71Z" }, + { url = "https://files.pythonhosted.org/packages/84/21/a35af28dcc61f37ed850a2d64c65c701321dfbf25085e469d5559360cbbf/pillow-12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91", size = 6940830, upload-time = "2026-07-01T11:54:13.732Z" }, + { url = "https://files.pythonhosted.org/packages/eb/51/8b08617af3ad95e33ce6d7dd2c99ed6c8298f7fb131636303956be022e25/pillow-12.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c", size = 6344383, upload-time = "2026-07-01T11:54:15.756Z" }, + { url = "https://files.pythonhosted.org/packages/1d/72/cf78ac9780bb93c28328f408973845a309d4d145041665f734572ced1b52/pillow-12.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df", size = 7052934, upload-time = "2026-07-01T11:54:17.721Z" }, + { url = "https://files.pythonhosted.org/packages/20/20/25e0f4dc178a6bc0696793720055519a0de89e7661dae886992decbd2f81/pillow-12.3.0-cp312-cp312-win32.whl", hash = "sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f", size = 6472684, upload-time = "2026-07-01T11:54:19.839Z" }, + { url = "https://files.pythonhosted.org/packages/45/89/da2f7971a317f83d807fdd4065c0af40208e59e692cc43d315a71a0e96d1/pillow-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09", size = 7227137, upload-time = "2026-07-01T11:54:22.025Z" }, + { url = "https://files.pythonhosted.org/packages/de/47/4845a0a6c0dbf1db8456bd9fc791f13c5ced7ced20606d08a0aacfd25b49/pillow-12.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510", size = 2568267, upload-time = "2026-07-01T11:54:24.051Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ac/31fb64e1e7efb5a4b50cd3d92049ba89ac6e4d8d3bb6a74e15048ca3353e/pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:21900ce7ba264168cd50defae43cd75d25c833ad4ad6e73ffc5596d12e25ac89", size = 4161684, upload-time = "2026-07-01T11:54:25.934Z" }, + { url = "https://files.pythonhosted.org/packages/87/b4/9805e23d2b4d77842b468513841fda254ee42f0289d25088340e4ff46e2d/pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:4e8c2a84d977f50b9daed6eeaf3baef67d00d5d74d932288f02cb94518ee3ace", size = 4255487, upload-time = "2026-07-01T11:54:27.935Z" }, + { url = "https://files.pythonhosted.org/packages/df/39/ecf519435a200c693fe053a6ee4d835b41cf963a4dfc2551c4e637cb2a71/pillow-12.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:ae26d61dfa7a47befdc7572b521024e8745f3d809bd95ca9505a7bba9ef849ec", size = 3696433, upload-time = "2026-07-01T11:54:29.813Z" }, + { url = "https://files.pythonhosted.org/packages/42/92/2fc3ffad878ae8dd5469ec1bc8eb83b71f48e13efdf68f02709003982a32/pillow-12.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a743ff716f746fc19a9557f60dab1600d4613255f8a7aeb3cdde4db7eb15a66", size = 5345889, upload-time = "2026-07-01T11:54:31.97Z" }, + { url = "https://files.pythonhosted.org/packages/10/76/8803c13605b763d33d156c4678fc77f8443389c0c51c8aef707bb02015f4/pillow-12.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d69141514cc30b774ceea5e3ed3a6635c8d8a96edf664689b890f4089111fb35", size = 4780109, upload-time = "2026-07-01T11:54:34.026Z" }, + { url = "https://files.pythonhosted.org/packages/1f/01/e18aff37cb0b4aac47ac90f016d347a49aca667ef97f190b06ac2aabc928/pillow-12.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7401aebd7f581d7f83a439d87d474999317ee099218e5ad25d125290990ba65", size = 6263736, upload-time = "2026-07-01T11:54:36.131Z" }, + { url = "https://files.pythonhosted.org/packages/f7/62/de5bdd77d935331f4f802edc11e4d82950f642caad6cb2f949837b8560e2/pillow-12.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0847a763afefb695bc912d7c131e7e0632d4edc1d8698f58ddabec8e46b8b6d3", size = 6937129, upload-time = "2026-07-01T11:54:38.216Z" }, + { url = "https://files.pythonhosted.org/packages/70/4d/105627a13300c5e0df1d174230b32fd1273062c96f7745fd552b945d1e1d/pillow-12.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:571b9fcb07b97ef3a492028fb3d2dc0993ca23a06138b0315286566d29ef718a", size = 6339562, upload-time = "2026-07-01T11:54:40.354Z" }, + { url = "https://files.pythonhosted.org/packages/6b/1d/f13de01a553988ab895ba1c722e06cf3144d4f57656fd5b81b6d881f1179/pillow-12.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:756c768d0c9c2955feb7a56c37ea24aea2e369f8d36a88da270b6a9f19e62b5e", size = 7049439, upload-time = "2026-07-01T11:54:42.489Z" }, + { url = "https://files.pythonhosted.org/packages/c9/f9/066794cca041b969964f779ee5fa66a9498bbf34248ac39c5d7954e4198f/pillow-12.3.0-cp313-cp313-win32.whl", hash = "sha256:a876864214e136f0eb367788dbd7df045f4806801518e2cfe9e13229cfe06d8f", size = 6473287, upload-time = "2026-07-01T11:54:44.9Z" }, + { url = "https://files.pythonhosted.org/packages/a6/9b/7a58e61d62be561da3a356fe2384d4059a6345fc130e23ef1c36a5b81d24/pillow-12.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1cca606cd25738df4ed873d5ad46bbdb3d83b5cbca291f6b4ff13a4df6b0bbe8", size = 7239691, upload-time = "2026-07-01T11:54:47.141Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b0/c4ed4f0ef8f8fa5ee8351537db6650bb8189f7e118842978dd6589065692/pillow-12.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:b629de27fda84b42cde7edef0d85f13b958b47f6e9bbcbba9b673c562a89bd8b", size = 2568185, upload-time = "2026-07-01T11:54:49.137Z" }, + { url = "https://files.pythonhosted.org/packages/dc/01/001f65b68192f0228cc1dbbc8d2530ab5d58b61037ba0587f946fea607cd/pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:9cf95fe4d0f84c82d282745d9bb08ad9f926efa00be4697e767b814ce40d4330", size = 4161736, upload-time = "2026-07-01T11:54:51.156Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d2/0219746d0fd16fc8a84498e79452375be3797d3ce4044596ce565164b84f/pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:8728f216dcdb6e6d555cf971cb34076139ad74b31fc2c14da4fafc741c5f6217", size = 4255435, upload-time = "2026-07-01T11:54:53.414Z" }, + { url = "https://files.pythonhosted.org/packages/c8/02/8d0bc62ef0302318c46ff2a512822d2610e81c7aa46c9b3abe6cbaca5ad0/pillow-12.3.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:a45650e8ce7fafffd731db8550230db6b0d306d181a90b67d3e6bca2f1990930", size = 3696262, upload-time = "2026-07-01T11:54:55.739Z" }, + { url = "https://files.pythonhosted.org/packages/85/e2/73c77d218410b14f5f2d565e8a998d5317b7b9c75368d29985139f7a46f0/pillow-12.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ba54cfebe86920a559a7c4d6b9050791c20513650a1952ebe3368c7dc70306f8", size = 5350344, upload-time = "2026-07-01T11:54:57.657Z" }, + { url = "https://files.pythonhosted.org/packages/c7/da/32c752228ae345f489e3a42499d817b6c3996da7e8a3bc7a04fc806b243b/pillow-12.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e158cb00350dc278f3b91551101aa7d12415a66ebf2c91d8d5ac14e56ddd3ad0", size = 4780131, upload-time = "2026-07-01T11:54:59.713Z" }, + { url = "https://files.pythonhosted.org/packages/b1/9d/8b2c807dbef61a5197c047afe99823787eb66f63daf9fb2432f91d6f0462/pillow-12.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9aeb04d6aef139de265b29683e119b638208f88cf73cdd1658aa07221165321", size = 6263757, upload-time = "2026-07-01T11:55:01.778Z" }, + { url = "https://files.pythonhosted.org/packages/5c/44/c85361f65dbe00eea8576ee467c768d25129989efb76e94f205e9ca9bb46/pillow-12.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:251bf95b67017e27b13d82f5b326234ca62d70f9cf4c2b9032de2358a3b12c7b", size = 6936962, upload-time = "2026-07-01T11:55:03.93Z" }, + { url = "https://files.pythonhosted.org/packages/18/7e/e483414b35800b86b6f08dbbc7803fb5cd52c4d6f897f47d53ea2c7e6f65/pillow-12.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fe3cca2e4e8a592be0f269a1ca4835c25199d9f3ce815c8491048f785b0a0198", size = 6339171, upload-time = "2026-07-01T11:55:05.989Z" }, + { url = "https://files.pythonhosted.org/packages/f0/f4/68c491844841ede6bed70189546b3ee9731cf9f2cbad396faff5e1ccba45/pillow-12.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:23aceaa007d6172b02c277f0cd359c79492bbb14f7072b4ede9fbcaf20648130", size = 7048116, upload-time = "2026-07-01T11:55:08.131Z" }, + { url = "https://files.pythonhosted.org/packages/a3/34/77f3f793fed8efc7d243f21b33c5a3f0d1c97ee70346d3db855587e155ff/pillow-12.3.0-cp314-cp314-win32.whl", hash = "sha256:af8d94b0db561cf68b88a267c5c44b49e134f525d0dc2cb7ed413a66bc23559a", size = 6467209, upload-time = "2026-07-01T11:55:10.408Z" }, + { url = "https://files.pythonhosted.org/packages/f1/e0/492879f69d94f91f60fc8cd05ba03650e9520afebb2fb7aa12777d7c7f38/pillow-12.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:fdafc9cce40277e0f7a0feabce0ee50dd2fa1800f3b38015e51296b5e814048d", size = 7237707, upload-time = "2026-07-01T11:55:12.745Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ac/6b11f2875f1c2ac040d84e1bbf9cf22a88038f901ca1037898b280b38365/pillow-12.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:e91206ee562682b51b98ef4b26a6ef48fd84e15fd4c4bc5ec768eb641d206838", size = 2565995, upload-time = "2026-07-01T11:55:14.736Z" }, + { url = "https://files.pythonhosted.org/packages/52/69/c2208e56af9bfc1913afb24020297a691eb1d4ef688474c8a04913f65e04/pillow-12.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:164b31cd1a0490ab6efae01aa5df49da7061be0af1b30e035b6e9a1bfe34ee6e", size = 5352503, upload-time = "2026-07-01T11:55:17.076Z" }, + { url = "https://files.pythonhosted.org/packages/07/70/e5686d753e898a45d778ff1718dba8516ead6ab6b95d85fc8c4b70650cf2/pillow-12.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5afb51d599ea772b8365ae807ae557f18bccfe46ab261fd1c2a9ed700fc6eb17", size = 4782956, upload-time = "2026-07-01T11:55:19.448Z" }, + { url = "https://files.pythonhosted.org/packages/d5/37/25c6692f06927ee973ff18c8d9ee98ad0b4d84ee67a09610c2dd1447958e/pillow-12.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3edce1d53195db527e0191f84b71d02022de0540bf43a16ed734ed7537b07385", size = 6322855, upload-time = "2026-07-01T11:55:21.613Z" }, + { url = "https://files.pythonhosted.org/packages/cc/91/420637fcb8f1bc11029e403b4538e6694744428d8246118e45719f944556/pillow-12.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf16ba1b4d0b6b7c8e534936632270cf70eb00dbe09005bc345b2677b726855c", size = 6989642, upload-time = "2026-07-01T11:55:24.006Z" }, + { url = "https://files.pythonhosted.org/packages/10/08/b94d7811281ccf0d143a1cf768d1c49e1e54af63e7b708ab2ee3eb87face/pillow-12.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:24870b09b224f7ae3c39ed07d10e819d06f8720bc551847b1d623832b5b0e28d", size = 6391281, upload-time = "2026-07-01T11:55:26.252Z" }, + { url = "https://files.pythonhosted.org/packages/d2/87/24233f785f55474dc02ce3e739c5528a77e3a862e9333d1dd7a25cc31f70/pillow-12.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:30f2aa603c41533cc25c05acd0da21636e84a315768feb631c937177db558931", size = 7096716, upload-time = "2026-07-01T11:55:28.318Z" }, + { url = "https://files.pythonhosted.org/packages/23/26/fcb2f6e37175b04f53570b59937867e2b80ee1685e744023153028fc14f9/pillow-12.3.0-cp314-cp314t-win32.whl", hash = "sha256:4b0a7fe987b14c31ebda6083f74f22b561fd3739bc0ac51e019622e3d72668c7", size = 6474125, upload-time = "2026-07-01T11:55:30.956Z" }, + { url = "https://files.pythonhosted.org/packages/90/de/3634abee5f1c9e13c56787b7d5517b0ba8d6de51700b95578cf338349c9f/pillow-12.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:962864dc93511324d51ddbb5b9f8731bf71675b93ca612a07441896f4688fb8c", size = 7242939, upload-time = "2026-07-01T11:55:34.044Z" }, + { url = "https://files.pythonhosted.org/packages/ce/2a/fd13f8eb24de5714a6eb444a3d67e2842c6c576e159a43793adf23051351/pillow-12.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0740a512dc522224c77d9aa5a8d70d8b7d73fb91f2c21125d8d025d3b8990e45", size = 2567506, upload-time = "2026-07-01T11:55:35.988Z" }, + { url = "https://files.pythonhosted.org/packages/5d/dc/8fdce34ec725a33c81c6ba122b904d6b9024e50ea9ac7bede62fab54506c/pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0feb2e9d6ad6c9e3c06effe9d00f3f1e618a6643273576b016f591e9315a7139", size = 4162063, upload-time = "2026-07-01T11:55:37.941Z" }, + { url = "https://files.pythonhosted.org/packages/76/66/2044b9a63d3b84ff048228dfcb7cd9bf0df983e8470971bf7d4c57b693de/pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:9e881fca225083806662a5c43d627d215f258ff43c890f831966c7d7ba9c7402", size = 4255549, upload-time = "2026-07-01T11:55:40.022Z" }, + { url = "https://files.pythonhosted.org/packages/52/7e/1f67e6f4ece6b582ee4b539decbcc9f848dc245a93ed8cd7338bafef72f1/pillow-12.3.0-cp315-cp315-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:4998562bf62a445225f22e07c896bb04b35b1b1f2eb6d760584c9c51d7a5f78c", size = 3696331, upload-time = "2026-07-01T11:55:41.98Z" }, + { url = "https://files.pythonhosted.org/packages/12/40/d306fc2c8e4d45d7f175c77edca7063be7b86fe7fe6e68f4353bf71d808c/pillow-12.3.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:dc624f6bc473dacdf7ef7eb8678d0d08edf15cd94fad6ae5c7d6cc67a4e4902f", size = 5350370, upload-time = "2026-07-01T11:55:44.028Z" }, + { url = "https://files.pythonhosted.org/packages/dd/44/668fb1437e8ce420f62d6106eb66e44a5971602a4d794615bdf79315d82d/pillow-12.3.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:71d6097b330eea8fd15097780c8e89cb1a8ce7838669f48c5bacd6f663dd4701", size = 4780147, upload-time = "2026-07-01T11:55:46.073Z" }, + { url = "https://files.pythonhosted.org/packages/0c/08/93fa2e70e30a2d81547e481b6ee2bb9522117221fb1e0ce4b5df70967677/pillow-12.3.0-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:28ce87c5ab450a9dd970b52e5aca5fe63ed432d18a2eaddd1979a00a1ba24ace", size = 6273659, upload-time = "2026-07-01T11:55:48.264Z" }, + { url = "https://files.pythonhosted.org/packages/f8/6d/043e96ff814fc31a33077e4cba86082167db520c93632afdf2042febbb0c/pillow-12.3.0-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b02afb9b97f65fbca5f31db6a2a3ba21aa93030225f150fa3f249717e938fb4", size = 6947439, upload-time = "2026-07-01T11:55:50.503Z" }, + { url = "https://files.pythonhosted.org/packages/af/92/ba71d2ee2ac0edf3fa33bd9d5ee9ee080da70b1766f3ca3934f9938ddac9/pillow-12.3.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:1182d52bc2d5e5d7d0949503aa7e36d12f42205dc287e4883f407b1988820d39", size = 6353577, upload-time = "2026-07-01T11:55:52.697Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ce/e63064e2122923ff687c8ad792d0d736a7b3920a56a46982e81a7fdd25d6/pillow-12.3.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e795b7eb908249c4e43c7c99fac7c2c75dab0c43566e37db472a355f63693d71", size = 7060394, upload-time = "2026-07-01T11:55:55.149Z" }, + { url = "https://files.pythonhosted.org/packages/54/76/a09cc3ccc8d773a7283d34c38bec1708f9e3cc932093cbc4c5e71ac4060b/pillow-12.3.0-cp315-cp315-win32.whl", hash = "sha256:57b3d78c95ba9059768b10e28b813002261d3f3dfc55cc48b0c988f625175827", size = 6467375, upload-time = "2026-07-01T11:55:57.769Z" }, + { url = "https://files.pythonhosted.org/packages/3e/03/1846c49ba3b1d5550392a4bbd06d6fb4578e1cd91a803198b5c90f5f7d53/pillow-12.3.0-cp315-cp315-win_amd64.whl", hash = "sha256:fa4ecea169a355be7a3ade2c783e2ed12f0e40d2c5621cda8b3297faf7fbb9f5", size = 7237048, upload-time = "2026-07-01T11:55:59.975Z" }, + { url = "https://files.pythonhosted.org/packages/fb/bb/89f35dcc79610423f9f195504d7def7f0d1416a711541b42867e25fe3412/pillow-12.3.0-cp315-cp315-win_arm64.whl", hash = "sha256:877c3f311ff35410f690861c4409e7ccbf0cd2f878e50628a28e5a0bb689e658", size = 2566006, upload-time = "2026-07-01T11:56:02.143Z" }, + { url = "https://files.pythonhosted.org/packages/30/88/707027ba09942dfa2c28759b5c222d769290a41c6d20ea60ec250801941f/pillow-12.3.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:e9871b1ffbfa9656b60aeee92ed5136a5742696006fa322b29ea3d8da0ecc9cf", size = 5352509, upload-time = "2026-07-01T11:56:04.2Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6d/00352fa25332c2569cd387851f568cc5a4b75a9adbfb37ac4fbce4c02eec/pillow-12.3.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:53aa02d20d10c3d814d536aa4e5ac9b84ca0ff5a88377963b085ad6822f93e64", size = 4783167, upload-time = "2026-07-01T11:56:06.631Z" }, + { url = "https://files.pythonhosted.org/packages/13/4f/9e049dfa21af7c22427275720e2490267ba8138120add5c4c574deb69782/pillow-12.3.0-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:446c34dcc4324b084a53b705127dc15717b22c5e140ae0a3c38349d4efec071e", size = 6329237, upload-time = "2026-07-01T11:56:08.868Z" }, + { url = "https://files.pythonhosted.org/packages/36/16/cf6eeaae8d0fce8dd390a33437cf68c5d5bd73834a2bc6e2f14efda0ab45/pillow-12.3.0-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf1845d02ad822a369a49f2bb9345b1614744267682e7a03527dc3bf6eea1777", size = 6997047, upload-time = "2026-07-01T11:56:11.379Z" }, + { url = "https://files.pythonhosted.org/packages/1e/69/dbf769bdd55f48bf5733cac28edc6364ffaa072ec9ba336266e4fe66be55/pillow-12.3.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:186941b6aef820ad110fb01fb06eb925374dc3a21b17e37ec9a53b250c6fe2d1", size = 6400440, upload-time = "2026-07-01T11:56:13.908Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e1/ffc9cfc2eea0d178da8018e18e959301ad9d6bc9f3edb7181e748a474b97/pillow-12.3.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:f13c32a3abd6079a66d9526e18dad9b6d280384d49d7c54040cd57b6424041d9", size = 7105895, upload-time = "2026-07-01T11:56:16.575Z" }, + { url = "https://files.pythonhosted.org/packages/18/f0/a5595c1e8c3ae44b9828cb2f0fa8155e5095ef04d6327b8f61cf44a3df85/pillow-12.3.0-cp315-cp315t-win32.whl", hash = "sha256:1657923d2d45afb66526e5b933e5b3052e6bdea196c90d3abb2424e18c77dae8", size = 6474384, upload-time = "2026-07-01T11:56:18.855Z" }, + { url = "https://files.pythonhosted.org/packages/e4/04/62bcd9f844984c5938d3b05264a61d797a29d3e0812341a8204af70bbdee/pillow-12.3.0-cp315-cp315t-win_amd64.whl", hash = "sha256:8cd2f7bdda092d99c9fc2fb7391354f306d01443d22785d0cbfafa2e2c8bb418", size = 7243537, upload-time = "2026-07-01T11:56:21.214Z" }, + { url = "https://files.pythonhosted.org/packages/3d/68/1f3066acedf37673694a7141381d8f811ae97f30d34413d236abe7d489f1/pillow-12.3.0-cp315-cp315t-win_arm64.whl", hash = "sha256:06ff022112bc9cbf83b60f8e028d94ad87b60621706487e65f673de61610ab59", size = 2567491, upload-time = "2026-07-01T11:56:23.506Z" }, +] + [[package]] name = "platformdirs" version = "4.9.6" @@ -1849,6 +2987,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/80/6e/4b28b62ecb6aae56769c34a8ff1d661473ec1e9519e2d5f8b2c150086b26/pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b", size = 226472, upload-time = "2026-04-21T20:31:40.092Z" }, ] +[[package]] +name = "prometheus-client" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/fb/d9aa83ffe43ce1f19e557c0971d04b90561b0cfd50762aafb01968285553/prometheus_client-0.25.0.tar.gz", hash = "sha256:5e373b75c31afb3c86f1a52fa1ad470c9aace18082d39ec0d2f918d11cc9ba28", size = 86035, upload-time = "2026-04-09T19:53:42.359Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/9b/d4b1e644385499c8346fa9b622a3f030dce14cd6ef8a1871c221a17a67e7/prometheus_client-0.25.0-py3-none-any.whl", hash = "sha256:d5aec89e349a6ec230805d0df882f3807f74fd6c1a2fa86864e3c2279059fed1", size = 64154, upload-time = "2026-04-09T19:53:41.324Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, +] + [[package]] name = "propcache" version = "0.4.1" @@ -1961,6 +3120,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, ] +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + [[package]] name = "pydantic" version = "2.13.4" @@ -2179,6 +3365,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/33/288b5868fa00846dacf249633719d747893e54aebd196b9968ac1878a5d3/pyright-1.1.410-py3-none-any.whl", hash = "sha256:5e961bed37cacf96b3f7cd7b1da39b350a9239aa2e69138d0e88f728cfaf296c", size = 6082448, upload-time = "2026-06-01T17:35:46.387Z" }, ] +[[package]] +name = "pyshp" +version = "3.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/58/8d9461f328b2878a4b1632db4189a68c77e0c87689830a7834f204302704/pyshp-3.1.4.tar.gz", hash = "sha256:0663762be72c67684c890decd888fb8e849e01a85ee6ef0346214b7329270453", size = 2225442, upload-time = "2026-06-29T16:55:14.621Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/40/f1c777c07866b9de9420627c79bd22141268256d78afb890feabc4a85d70/pyshp-3.1.4-py3-none-any.whl", hash = "sha256:5bdd39c8fe02a47fe8de9c3355c5efaa312ff5c7fc6b8156592df738246f6167", size = 73189, upload-time = "2026-06-29T16:55:13.226Z" }, +] + [[package]] name = "pystac" version = "1.14.3" @@ -2294,6 +3489,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, ] +[[package]] +name = "python-json-logger" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/ff/3cc9165fd44106973cd7ac9facb674a65ed853494592541d339bdc9a30eb/python_json_logger-4.1.0.tar.gz", hash = "sha256:b396b9e3ed782b09ff9d6e4f1683d46c83ad0d35d2e407c09a9ebbf038f88195", size = 17573, upload-time = "2026-03-29T04:39:56.805Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/be/0631a861af4d1c875f096c07d34e9a63639560a717130e7a87cbc82b7e3f/python_json_logger-4.1.0-py3-none-any.whl", hash = "sha256:132994765cf75bf44554be9aa49b06ef2345d23661a96720262716438141b6b2", size = 15021, upload-time = "2026-03-29T04:39:55.266Z" }, +] + [[package]] name = "pytokens" version = "0.4.1" @@ -2323,6 +3527,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" }, ] +[[package]] +name = "pywinpty" +version = "3.0.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/ef/2d27f30c59a67be7025b2d7858c8c2d282b74d66544b2384730b82de74fd/pywinpty-3.0.5.tar.gz", hash = "sha256:61db0db063de9865adbea66db294628f8577f608d9764a4c7d3384eeacc4e81b", size = 16223484, upload-time = "2026-06-11T00:11:58.93Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/34/942cc95ca4e26489875aa8a95192766247a687379ec29543eebe73ec945f/pywinpty-3.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:d62946adf14b15b54c0b8d785f93fe18b04da23f4ad59e2e8c4612646e9abd23", size = 2090915, upload-time = "2026-06-10T23:43:14.98Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/5b9053004844139ea8bd86209c57ade12b134b2782f383a095784c8531ec/pywinpty-3.0.5-cp312-cp312-win_arm64.whl", hash = "sha256:e9391c05fbfa7a992a97e831fc6849887b4014a614192e3d984a7ca59592b376", size = 815934, upload-time = "2026-06-10T23:41:42.384Z" }, + { url = "https://files.pythonhosted.org/packages/b9/f4/2a464b9893cceb3b3f416356e94fdc3e1bca9476993927e4e6d99fe95382/pywinpty-3.0.5-cp313-cp313-win_amd64.whl", hash = "sha256:48db1b0ad9d0a1b81dcaaa7163a99a7808deaceb0c1b2344716dc1fc090c3c4c", size = 2090471, upload-time = "2026-06-10T23:42:11.071Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2c/a138491a0afbdb50eb79395577bd326d4b0fbde7209417d1a8087ff2493a/pywinpty-3.0.5-cp313-cp313-win_arm64.whl", hash = "sha256:2c6008fb2d3774b48693b2fcb7f2cc317ade9dc581289a964ffeeaf81307c9b5", size = 815518, upload-time = "2026-06-10T23:42:02.363Z" }, + { url = "https://files.pythonhosted.org/packages/6f/15/54400049a380582acd1282665c70fcf11e0bd3713679aca78e24c3aae738/pywinpty-3.0.5-cp313-cp313t-win_amd64.whl", hash = "sha256:22ce1b780d89821cc52daf6eac0708af22d93d000ce9c7c07e37489db8594598", size = 2089920, upload-time = "2026-06-10T23:44:13.395Z" }, + { url = "https://files.pythonhosted.org/packages/94/0c/6f24f3c0799f502259b24bdf841a99ad2b0d59df5c2525b4e2a286d14be2/pywinpty-3.0.5-cp313-cp313t-win_arm64.whl", hash = "sha256:9c2919a81bc5cfb09b86fc5a002112b2de95ca4304a07413cbeeb746a1307a5c", size = 814520, upload-time = "2026-06-10T23:43:28.588Z" }, + { url = "https://files.pythonhosted.org/packages/e9/23/f3cd1b1e5fc56517f54452c49f92049e7dd9ffc8a63de22a495581f50d04/pywinpty-3.0.5-cp314-cp314-win_amd64.whl", hash = "sha256:03bb3c16d691d9242267201830bcd0e64a9b663170e9042bc84b210da9de15ac", size = 2090663, upload-time = "2026-06-10T23:43:59.845Z" }, + { url = "https://files.pythonhosted.org/packages/9d/dd/96d6cbfc6d9ddab5c1c2f92c26545ae8997446a2ba7ee2024cd43c81f49b/pywinpty-3.0.5-cp314-cp314-win_arm64.whl", hash = "sha256:89c5c6ef08997a3b4b277b214a35fe15cab4dd6d119f0140aa71df5b1168fdbc", size = 815700, upload-time = "2026-06-10T23:40:50.001Z" }, + { url = "https://files.pythonhosted.org/packages/30/36/d98087bce0acaa4cce7f196103cfa7be3f63ce65f52473bb3e38784ae5d9/pywinpty-3.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:7b566165e0c5fdd6abe167a5ac8b954be6a843eb55a85946576d6bc1dea03d6d", size = 2090093, upload-time = "2026-06-10T23:40:58.933Z" }, + { url = "https://files.pythonhosted.org/packages/57/fd/fe2b0db922ba052ce3976a08f3fc05d0c05047c8b4ebb6102e832b8ef563/pywinpty-3.0.5-cp314-cp314t-win_arm64.whl", hash = "sha256:24366280a8aa677323da87bec729cb3ea3b35367386cece0978bdc6e4695c690", size = 814517, upload-time = "2026-06-10T23:42:34.946Z" }, +] + [[package]] name = "pyyaml" version = "6.0.3" @@ -2381,6 +3603,49 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, ] +[[package]] +name = "pyzmq" +version = "27.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, + { url = "https://files.pythonhosted.org/packages/60/cb/84a13459c51da6cec1b7b1dc1a47e6db6da50b77ad7fd9c145842750a011/pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5", size = 1122436, upload-time = "2025-09-08T23:08:20.801Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b6/94414759a69a26c3dd674570a81813c46a078767d931a6c70ad29fc585cb/pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6", size = 1156301, upload-time = "2025-09-08T23:08:22.47Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ad/15906493fd40c316377fd8a8f6b1f93104f97a752667763c9b9c1b71d42d/pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7", size = 1341197, upload-time = "2025-09-08T23:08:24.286Z" }, + { url = "https://files.pythonhosted.org/packages/14/1d/d343f3ce13db53a54cb8946594e567410b2125394dafcc0268d8dda027e0/pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05", size = 897275, upload-time = "2025-09-08T23:08:26.063Z" }, + { url = "https://files.pythonhosted.org/packages/69/2d/d83dd6d7ca929a2fc67d2c3005415cdf322af7751d773524809f9e585129/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9", size = 660469, upload-time = "2025-09-08T23:08:27.623Z" }, + { url = "https://files.pythonhosted.org/packages/3e/cd/9822a7af117f4bc0f1952dbe9ef8358eb50a24928efd5edf54210b850259/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128", size = 847961, upload-time = "2025-09-08T23:08:29.672Z" }, + { url = "https://files.pythonhosted.org/packages/9a/12/f003e824a19ed73be15542f172fd0ec4ad0b60cf37436652c93b9df7c585/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39", size = 1650282, upload-time = "2025-09-08T23:08:31.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4a/e82d788ed58e9a23995cee70dbc20c9aded3d13a92d30d57ec2291f1e8a3/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97", size = 2024468, upload-time = "2025-09-08T23:08:33.543Z" }, + { url = "https://files.pythonhosted.org/packages/d9/94/2da0a60841f757481e402b34bf4c8bf57fa54a5466b965de791b1e6f747d/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db", size = 1885394, upload-time = "2025-09-08T23:08:35.51Z" }, + { url = "https://files.pythonhosted.org/packages/4f/6f/55c10e2e49ad52d080dc24e37adb215e5b0d64990b57598abc2e3f01725b/pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", size = 574964, upload-time = "2025-09-08T23:08:37.178Z" }, + { url = "https://files.pythonhosted.org/packages/87/4d/2534970ba63dd7c522d8ca80fb92777f362c0f321900667c615e2067cb29/pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", size = 641029, upload-time = "2025-09-08T23:08:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541, upload-time = "2025-09-08T23:08:42.668Z" }, + { url = "https://files.pythonhosted.org/packages/87/45/19efbb3000956e82d0331bafca5d9ac19ea2857722fa2caacefb6042f39d/pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a", size = 1341197, upload-time = "2025-09-08T23:08:44.973Z" }, + { url = "https://files.pythonhosted.org/packages/48/43/d72ccdbf0d73d1343936296665826350cb1e825f92f2db9db3e61c2162a2/pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea", size = 897175, upload-time = "2025-09-08T23:08:46.601Z" }, + { url = "https://files.pythonhosted.org/packages/2f/2e/a483f73a10b65a9ef0161e817321d39a770b2acf8bcf3004a28d90d14a94/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96", size = 660427, upload-time = "2025-09-08T23:08:48.187Z" }, + { url = "https://files.pythonhosted.org/packages/f5/d2/5f36552c2d3e5685abe60dfa56f91169f7a2d99bbaf67c5271022ab40863/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d", size = 847929, upload-time = "2025-09-08T23:08:49.76Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2a/404b331f2b7bf3198e9945f75c4c521f0c6a3a23b51f7a4a401b94a13833/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146", size = 1650193, upload-time = "2025-09-08T23:08:51.7Z" }, + { url = "https://files.pythonhosted.org/packages/1c/0b/f4107e33f62a5acf60e3ded67ed33d79b4ce18de432625ce2fc5093d6388/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd", size = 2024388, upload-time = "2025-09-08T23:08:53.393Z" }, + { url = "https://files.pythonhosted.org/packages/0d/01/add31fe76512642fd6e40e3a3bd21f4b47e242c8ba33efb6809e37076d9b/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a", size = 1885316, upload-time = "2025-09-08T23:08:55.702Z" }, + { url = "https://files.pythonhosted.org/packages/c4/59/a5f38970f9bf07cee96128de79590bb354917914a9be11272cfc7ff26af0/pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92", size = 587472, upload-time = "2025-09-08T23:08:58.18Z" }, + { url = "https://files.pythonhosted.org/packages/70/d8/78b1bad170f93fcf5e3536e70e8fadac55030002275c9a29e8f5719185de/pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0", size = 661401, upload-time = "2025-09-08T23:08:59.802Z" }, + { url = "https://files.pythonhosted.org/packages/81/d6/4bfbb40c9a0b42fc53c7cf442f6385db70b40f74a783130c5d0a5aa62228/pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7", size = 575170, upload-time = "2025-09-08T23:09:01.418Z" }, +] + [[package]] name = "rasterio" version = "1.5.0" @@ -2428,6 +3693,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6e/d1/8b017856e63ccaff3cbd0e82490dbb01363a42f3a462a41b1d8a391e1443/rasterio-1.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:f4b9c2c3b5f10469eb9588f105086e68f0279e62cc9095c4edd245e3f9b88c8a", size = 29418321, upload-time = "2026-01-05T16:06:44.758Z" }, ] +[[package]] +name = "referencing" +version = "0.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, +] + [[package]] name = "requests" version = "2.33.1" @@ -2443,6 +3722,39 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947, upload-time = "2026-03-30T16:09:13.83Z" }, ] +[[package]] +name = "rfc3339-validator" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, +] + +[[package]] +name = "rfc3986-validator" +version = "0.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760, upload-time = "2019-10-28T16:00:19.144Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242, upload-time = "2019-10-28T16:00:13.976Z" }, +] + +[[package]] +name = "rfc3987-syntax" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lark" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239, upload-time = "2025-07-18T01:05:05.015Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046, upload-time = "2025-07-18T01:05:03.843Z" }, +] + [[package]] name = "rich" version = "15.0.0" @@ -2494,6 +3806,102 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3f/dd/0b2c68495331ba36af783139baaa94693ef310d484d458c11dfa1357287d/rioxarray-0.22.0-py3-none-any.whl", hash = "sha256:db0aa55cd36a95060968f2e6574107829def29d43a563560b90bc642d0bd6a3b", size = 72018, upload-time = "2026-03-06T17:10:58.965Z" }, ] +[[package]] +name = "rpds-py" +version = "2026.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/2a/9618a122aeb2a169a28b03889a2995fe297588964333d4a7d67bdf46e147/rpds_py-2026.6.3.tar.gz", hash = "sha256:1cebd1337c242e4ec2293e541f712b2da849b29f48f0c293684b71c0632625d4", size = 64051, upload-time = "2026-06-30T07:17:53.009Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/be/2e8974163072e7bab7df1a5acd54c4498e75e35d6d18b864d3a9d5dadc92/rpds_py-2026.6.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a0811d33247c3d6128a3001d763f2aa056bb3425204335400ac54f89eec3a0d0", size = 343691, upload-time = "2026-06-30T07:15:14.96Z" }, + { url = "https://files.pythonhosted.org/packages/a4/73/319dfa745dd668efe89309141ded489126461fcecd2b8f3a3cda185129b6/rpds_py-2026.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:538949e262e46caa31ac01bdb3c1e8f642622922cacbabbae6a8445d9dc33eaf", size = 338542, upload-time = "2026-06-30T07:15:16.267Z" }, + { url = "https://files.pythonhosted.org/packages/21/63/4239893be1c4d09b709b1a8f6be4188f0870084ff547f46606b8a75f1b03/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55927d532399c2c646100ff7feb48eaa940ad70f42cd68e1328f3ded9f81ca24", size = 368180, upload-time = "2026-06-30T07:15:17.62Z" }, + { url = "https://files.pythonhosted.org/packages/1c/ca/9c5de382225234ceb37b1844ebdb140db12b2a278bb9efe2fcd19f6c82ce/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f56f1695bc5c0871cbc33dc0130fcf503aab0c57dcc5a6700a4f49eba4f2652e", size = 375067, upload-time = "2026-06-30T07:15:18.952Z" }, + { url = "https://files.pythonhosted.org/packages/87/dc/863f69d1bf04ade34b7fe0d59b9fdf6f0135fe2d7cbca74f1d665589559d/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:270b293dae9058fc9fcedab50f13cebf46fb8ed1d1d54e0521a9da5d6b211975", size = 490509, upload-time = "2026-06-30T07:15:20.434Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ef/eac16a12048b45ec7c7fa94f2be3438a5f26bf9cc8580b18a1cfd609b7f6/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:127565fead0a10943b282957bd5447804ff3160ad79f2ad2635e6d249e380680", size = 382754, upload-time = "2026-06-30T07:15:21.831Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/d2f3f532616be4d06c316ef119683e832bd3d41e112bf3a88f4151c95b17/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecabd69db66de867690f9797f2f8fa27ba501bbc24540cbdbdc649cd15888ba6", size = 366189, upload-time = "2026-06-30T07:15:23.371Z" }, + { url = "https://files.pythonhosted.org/packages/e3/29/41a7b0e98a4b44cd676ab7598419623373eb43b20be68c084935c1a8cf88/rpds_py-2026.6.3-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:58eadac9cd119677b60e1cf8ac4052f35949d71b8a9e5556efccbe82533cf22a", size = 377750, upload-time = "2026-06-30T07:15:24.659Z" }, + { url = "https://files.pythonhosted.org/packages/2e/05/ecda0bec46f9a1565090bcdc941d023f6a25aff85fda28f89f8d19878152/rpds_py-2026.6.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7491ee23305ac3eb59e492b6945881f5cd77a6f731061a3f25b77fd40f9e99a4", size = 395576, upload-time = "2026-06-30T07:15:25.987Z" }, + { url = "https://files.pythonhosted.org/packages/68/a8/6ed52f03ee6cb854ce78785cc9a9a672eb880e83fd7224d471f667d151f1/rpds_py-2026.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2c99f7e8ccb3dd6e3e4bfeac657a7b208c9bac8075f4b078c02d7404c34107fa", size = 543807, upload-time = "2026-06-30T07:15:27.356Z" }, + { url = "https://files.pythonhosted.org/packages/8f/d6/156c0d3eea27ba09b92562ba2364ba124c0a061b199e17eac637cd25a5e2/rpds_py-2026.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:62698275682bf121181861295c9181e789030a2d516071f5b8f3c23c170cd0fc", size = 611187, upload-time = "2026-06-30T07:15:28.931Z" }, + { url = "https://files.pythonhosted.org/packages/f1/31/774212ed989c62f7f310220089f9b0a3fb8f40f5443d1727abd5d9f52bc9/rpds_py-2026.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a214c993455f99a89aaeadc9b21241900037adc9d97203e374d75513c5911822", size = 573030, upload-time = "2026-06-30T07:15:30.553Z" }, + { url = "https://files.pythonhosted.org/packages/c9/50/22f73127a41f1ce4f87fe39aadfb9a126345801c274aa93ae88456249327/rpds_py-2026.6.3-cp312-cp312-win32.whl", hash = "sha256:501f9f04a588d6a09179368c57071301445191767c64e4b52a6aa9871f1ef5ed", size = 202185, upload-time = "2026-06-30T07:15:32.027Z" }, + { url = "https://files.pythonhosted.org/packages/04/3a/f0ee4d4dde9d3b69dedf1b5f74e7a40017046d55052d173e418c6a94f960/rpds_py-2026.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:2c958bf94822e9290a40aaf2a822d4bc5c88099093e3948ad6c571eca9272e5f", size = 220394, upload-time = "2026-06-30T07:15:33.359Z" }, + { url = "https://files.pythonhosted.org/packages/f3/83/3382fe37f809b59f02aac04dbc4e765b480b46ee0227ed516e3bdc4d3dfc/rpds_py-2026.6.3-cp312-cp312-win_arm64.whl", hash = "sha256:22bffe6042b9bcb0822bcd1955ec00e245daf17b4344e4ed8e9551b976b63e96", size = 215753, upload-time = "2026-06-30T07:15:34.778Z" }, + { url = "https://files.pythonhosted.org/packages/a4/9e/b818ee580026ec578138e961027a68820c40afeb1ec8f6819b54fb99e196/rpds_py-2026.6.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3cfe765c1da0072636ca06628261e0ea05688e160d5c8a03e0217c3854037223", size = 343012, upload-time = "2026-06-30T07:15:36.005Z" }, + { url = "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f4d78253f6996be4901669ad25319f842f740eccf4d58e3c7f3dd39e6dde1d8f", size = 338203, upload-time = "2026-06-30T07:15:37.462Z" }, + { url = "https://files.pythonhosted.org/packages/9e/9b/069aa329940f8207615e091f5eedbbd40e1e15eac68a0790fd05ccdf796c/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54f45a148e28767bf343d33a684693c70e451c6f4c0e9904709a723fafbdfc1f", size = 367984, upload-time = "2026-06-30T07:15:39.008Z" }, + { url = "https://files.pythonhosted.org/packages/14/db/34c203e4becff3703e4d3bc121842c00b8689197f398161203a880052f4e/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:842e7b070435622248c7a2c44ae53fa1440e073cc3023bc919fed570884097a7", size = 374815, upload-time = "2026-06-30T07:15:40.253Z" }, + { url = "https://files.pythonhosted.org/packages/ee/7d/8071067d2cc453d916ad836e828c943f575e8a44612537759002a1e07381/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8020133a74bd81b4572dd8e4be028a6b1ebcd70e6726edc3918008c08bee6ee6", size = 490545, upload-time = "2026-06-30T07:15:41.729Z" }, + { url = "https://files.pythonhosted.org/packages/a3/42/da06c5aa8f0484ff07f270787434204d9f4535e2f8c3b51ed402267e63c3/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cdc7e35386f3847df728fbcb5e887e2d79c19e2fa1eba9e51b6621d23e3243af", size = 382828, upload-time = "2026-06-30T07:15:43.327Z" }, + { url = "https://files.pythonhosted.org/packages/57/d7/fe978efc2ae50abe48eb7464668ea99f53c010c60aeebb7b35ad27f23661/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acac386b453c2516111b50985d60ce46e7fadb5ea71ae7b25f4c946935bf27cf", size = 365678, upload-time = "2026-06-30T07:15:44.992Z" }, + { url = "https://files.pythonhosted.org/packages/69/9d/1d8922e1990b2a6eb532b6ff53d3e73d2b3bbffc84116c75826bee73dfc6/rpds_py-2026.6.3-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:425560c6fa0415f27261727bb20bd097568485e5eb0c121f1949417d1c516885", size = 377811, upload-time = "2026-06-30T07:15:46.523Z" }, + { url = "https://files.pythonhosted.org/packages/b1/3d/198dceafb4fb034a6a47347e1b0735d34e0bd4a50be4e898d408ee66cb14/rpds_py-2026.6.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a550fb4950a06dde3beb4721f5ad4b25bf4513784665b0a8522c792e2bd822a4", size = 395382, upload-time = "2026-06-30T07:15:47.955Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f1/13968e49655d40b6b19d8b9140296bbc6f1d86b3f0f6c346cf9f1adddf4b/rpds_py-2026.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f4bca01b63096f606e095734dd56e74e175f94cfbf24ff3d63281cec61f7bb7", size = 543832, upload-time = "2026-06-30T07:15:49.33Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ab/289bcb1b90bd3e40a2900c561fa0e2087345ecbb094f0b870f2345142b7c/rpds_py-2026.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ccffae9a092a00deb7efd545fe5e2c33c33b88e7c054337e9a74c179347d0b7d", size = 611011, upload-time = "2026-06-30T07:15:50.847Z" }, + { url = "https://files.pythonhosted.org/packages/1e/16/5043105e679436ccfbc8e5e0dd2d663ed18a8b8113515fd06a5e5d77c83e/rpds_py-2026.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1cf01971c4f2c5553b772a542e4aaf191789cd331bc2cd4ff0e6e65ba49e1e97", size = 572431, upload-time = "2026-06-30T07:15:52.394Z" }, + { url = "https://files.pythonhosted.org/packages/85/ed/adab103321c0a6565d5ae1c2998349bc3ee175b82ccc5ae8fc04cc413075/rpds_py-2026.6.3-cp313-cp313-win32.whl", hash = "sha256:8c3d1e9c15b9d51ca0391e13da1a25a0a4df3c58a37c9dc368e0736cf7f69df0", size = 201710, upload-time = "2026-06-30T07:15:53.894Z" }, + { url = "https://files.pythonhosted.org/packages/7b/ed/a03b09668e74e5dabbf2e211f6468e1820c0552f7b0500082da31841bf7b/rpds_py-2026.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:9250a9a0a6fd4648b3f868da8d91a4c52b5811a62df58e753d50ae4454a36f80", size = 219454, upload-time = "2026-06-30T07:15:55.25Z" }, + { url = "https://files.pythonhosted.org/packages/27/17/b8642c12930b71bc2b25831f6708ccf0f75abcd11883932ec9ce54ba3a78/rpds_py-2026.6.3-cp313-cp313-win_arm64.whl", hash = "sha256:900a67df3fd1660b035a4761c4ce73c382ea6b35f90f9863c36c6fd8bf8b09bb", size = 215063, upload-time = "2026-06-30T07:15:56.573Z" }, + { url = "https://files.pythonhosted.org/packages/b6/36/7fbe9dcdaf857fb3f63c2a2284b62492d95f5e8334e947e5fb6e7f68c9be/rpds_py-2026.6.3-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:931908d9fc855d8f74783377822be318edb6dcb19e47169dc038f9a1bf60b06e", size = 344510, upload-time = "2026-06-30T07:15:57.921Z" }, + { url = "https://files.pythonhosted.org/packages/ba/54/f785cc3d3f60839ca57a5af4927a9f347b07b2799c373fc20f7949f87c7e/rpds_py-2026.6.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d7469697dce35be237db177d42e2a2ee26e6dcc5fc052078a6fefabd288c6edd", size = 339495, upload-time = "2026-06-30T07:15:59.238Z" }, + { url = "https://files.pythonhosted.org/packages/63/ef/d4cdaf309e6b095b43597103cf8c0b951d6cca2acce68c474f75ec12e0c7/rpds_py-2026.6.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcfbcf66006befb9fd2aeaa9e01feaf881b4dc330a02ba07d2322b1c11be7b5d", size = 369454, upload-time = "2026-06-30T07:16:01.021Z" }, + { url = "https://files.pythonhosted.org/packages/96/4a/9559a68b7ee15db09d7981212e8c2e219d2a1d6d4faa0391d813c3496a36/rpds_py-2026.6.3-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:847927daf4cffbd4e90e42bc890069897101edd015f956cb8721b3473372edda", size = 374583, upload-time = "2026-06-30T07:16:02.287Z" }, + { url = "https://files.pythonhosted.org/packages/ef/75/8964aa7d2c6e8ac43eba8eb6e6b0fdda1f46d39f2fc3e6aa9f2cb17f485d/rpds_py-2026.6.3-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aca6c1ef08a82bfe327cc156da694660f599923e2e6665b6d81c9c2d0ac9ffc8", size = 492919, upload-time = "2026-06-30T07:16:03.723Z" }, + { url = "https://files.pythonhosted.org/packages/8f/97/6908094ac804115e65aedfd90f1b5fee4eebebd3f6c4cfc5419939267565/rpds_py-2026.6.3-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ae50181a047c871561212bb97f7932a2d45fb53e947bd9b57ebad85b529cbc53", size = 383725, upload-time = "2026-06-30T07:16:05.305Z" }, + { url = "https://files.pythonhosted.org/packages/d1/9c/0d1fdc2e7aba23e290d603bc494e97bd205bae262ce33c6b32a69768ed5e/rpds_py-2026.6.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc319e5a1de4b6913aac94bf6a2f9e847371e0a140a43dd4991db1a09bc2d504", size = 367255, upload-time = "2026-06-30T07:16:07.086Z" }, + { url = "https://files.pythonhosted.org/packages/c4/fe/f0209ca4a9ed074bc8acb44dfd0e81c3122e94c9689f5645b7973a866719/rpds_py-2026.6.3-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:e4316bf32babbed84e691e352faf967ce2f0f024174a8643c37c94a1080374fc", size = 379060, upload-time = "2026-06-30T07:16:08.525Z" }, + { url = "https://files.pythonhosted.org/packages/c6/8d/f1cc54c616b9d8897de8738aac148d20afca93f68187475fe194d09a71b9/rpds_py-2026.6.3-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8c6e5a2f750cc71c3e3b11d71661f21d6f9bc6cebc6564b1466417a1ec03ec77", size = 395960, upload-time = "2026-06-30T07:16:09.989Z" }, + { url = "https://files.pythonhosted.org/packages/fb/04/aafff00f73aeca2945f734f1d483c64ab8f472d0864ab02377fd8e89c3b2/rpds_py-2026.6.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4470ce197d4090875cf6affbf1f853338387428df97c4fb7b7106317b8214698", size = 545356, upload-time = "2026-06-30T07:16:11.816Z" }, + { url = "https://files.pythonhosted.org/packages/fd/cc/e229663b9e4ddac5a4acbe9085dd80a71af2a5d356b8b39d6bff233f24b0/rpds_py-2026.6.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ea964164cc9afa72d4d9b23cc28dafae93693c0a53e0b42acbff15b22c3f9ddd", size = 612319, upload-time = "2026-06-30T07:16:13.586Z" }, + { url = "https://files.pythonhosted.org/packages/e3/7a/8a0e6d3e6cd066af108b71b43122c3fe158dd9eb86acac626593a2582eb1/rpds_py-2026.6.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:639c8929aa0afe81be836b04de888460d6bed38b9c54cfc18da8f6bfabf5af5d", size = 573508, upload-time = "2026-06-30T07:16:15.23Z" }, + { url = "https://files.pythonhosted.org/packages/87/03/2a69ab618a789cf6cf85c86bb844c62d090e700ab1a2aa676b3741b6c516/rpds_py-2026.6.3-cp314-cp314-win32.whl", hash = "sha256:882076c00c0a608b131187055ddc5ae29f2e7eaf870d6168980420d58528a5c8", size = 202504, upload-time = "2026-06-30T07:16:16.893Z" }, + { url = "https://files.pythonhosted.org/packages/85/62/a3892ba945f4e24c78f352e5de3c7620d8479f73f211406a97263d13c7d2/rpds_py-2026.6.3-cp314-cp314-win_amd64.whl", hash = "sha256:0be972be84cfcaf46c8c6edf690ca0f154ac17babf1f6a955a51579b34ad2dc5", size = 220380, upload-time = "2026-06-30T07:16:18.108Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e7/c2bd44dc831931815ad11ebb5f430b5a0a4d3caa9de837107876c30c3432/rpds_py-2026.6.3-cp314-cp314-win_arm64.whl", hash = "sha256:2a9c6f195058cb45335e8cc3802745c603d716eb96bc9625950c1aac71c0c703", size = 215976, upload-time = "2026-06-30T07:16:19.654Z" }, + { url = "https://files.pythonhosted.org/packages/79/9c/fff7b74bce9a091ec9a012a03f9ff5f69364eaf9451060dfc4486da2ffdd/rpds_py-2026.6.3-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:f90938e92afda60266da758ee7d363447f7f0138c9559f9e1811629580582d90", size = 346840, upload-time = "2026-06-30T07:16:21.268Z" }, + { url = "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ec829541c45bca16e61c7ae50c20501f213605beb75d1aba91a6ee37fbbb56a4", size = 340282, upload-time = "2026-06-30T07:16:22.875Z" }, + { url = "https://files.pythonhosted.org/packages/87/3c/7a9081c7c9e645b39efe19e4ffbeccd80add246327cd9b888aecffd72317/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afd70d95892096cdb26f15a00c45907b17817577aa8d1c76b2dcc2788391f9e9", size = 370403, upload-time = "2026-06-30T07:16:24.415Z" }, + { url = "https://files.pythonhosted.org/packages/f7/69/af47021eb7dad6ff3396cb001c08f0f3c4d06c20253f75be6421a59fe6b7/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:29dfa0533a5d4c94d4dfa1b694fcb56c9c63aad8330ffdd816fd225d0a7a162f", size = 376055, upload-time = "2026-06-30T07:16:26.111Z" }, + { url = "https://files.pythonhosted.org/packages/81/fc/a3bcf517084396a6dd258c592567a3c011ba4557f2fde23dceaf26e74f2e/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:af05d726809bff6b141be124d4c7ce998f9c9c7f30edb1f46c07aa103d540b41", size = 494419, upload-time = "2026-06-30T07:16:27.596Z" }, + { url = "https://files.pythonhosted.org/packages/c9/eb/13d529d1788135425c7bf207f8463458ca5d92e43f3f701365b83e9dffc1/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9826217f048f620d9a712672818bf231442c1b35d96b227a07eabd11b4bb6945", size = 384848, upload-time = "2026-06-30T07:16:29.183Z" }, + { url = "https://files.pythonhosted.org/packages/8e/f4/b7ac49f30013aba8f7b9566b1dd07e81de95e708c1374b7bacc5b9bc5c9c/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:536bceea4fa4acf7e1c61da2b5786304367c816c8895be71b8f537c480b0ea1f", size = 371369, upload-time = "2026-06-30T07:16:30.912Z" }, + { url = "https://files.pythonhosted.org/packages/31/86/6260bafa622f788b07ddec0e52d810305c8b9b0b8c27f58a2ab04bf62b4f/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:bc0011654b91cc4fb2ae701bec0a0ba1e552c0714247fa7af6c59e0ccfa3a4e1", size = 379673, upload-time = "2026-06-30T07:16:32.486Z" }, + { url = "https://files.pythonhosted.org/packages/19/c3/03f1ee79a047b48daeca157c89a18509cde22b6b951d642b9b0af1be660a/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:539d75de9e0d536c84ff18dfeb805398e58227001ce09231a26a08b9aed1ee0e", size = 397500, upload-time = "2026-06-30T07:16:34.471Z" }, + { url = "https://files.pythonhosted.org/packages/f0/95/8ed0cd8c377dca12aea498f119fe639fc474d1461545c39d2b5872eb1c0f/rpds_py-2026.6.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:166cf54d9f44fc6ceb53c7860258dde44a81406646de79f8ed3234fca3b6e538", size = 545978, upload-time = "2026-06-30T07:16:36.45Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f2/0eb57f0eaa83f8fc152a7e03de968ab77e1f00732bebc892b190c6eebde7/rpds_py-2026.6.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:d34c20167764fbcf927194d532dd7e0c56772f0a5f943fa5ef9e9afbba8fb9db", size = 613350, upload-time = "2026-06-30T07:16:38.213Z" }, + { url = "https://files.pythonhosted.org/packages/5b/de/e0674bdbc3ef7634989b3f854c3f34bc1f587d36e5bfdc5c378d57034619/rpds_py-2026.6.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ea7bb13b7c9a29791f87a0387ba7d3ad3a6d783d827e4d3f27b40a0ff44495e2", size = 576486, upload-time = "2026-06-30T07:16:39.797Z" }, + { url = "https://files.pythonhosted.org/packages/f2/f6/21101359743cd136ada781e8210a85769578422ba460672eea0e29739200/rpds_py-2026.6.3-cp314-cp314t-win32.whl", hash = "sha256:6de4744d05bd1aa1be4ed7ea1189e3979196808008113bbbf899a460966b925e", size = 201068, upload-time = "2026-06-30T07:16:41.316Z" }, + { url = "https://files.pythonhosted.org/packages/a6/b2/9574d4d44f7760c2aa32d92a0a4f41698e33f5b204a0bf5c9758f52c79d5/rpds_py-2026.6.3-cp314-cp314t-win_amd64.whl", hash = "sha256:c7b9a2f8f4d8e90af72571d3d495deebdd7e3c75451f5b41719aee166e940fc2", size = 220600, upload-time = "2026-06-30T07:16:43.091Z" }, + { url = "https://files.pythonhosted.org/packages/08/ae/f23a2697e6ee6340a578b0f136be6483657bef0c6f9497b752bb5c0964bb/rpds_py-2026.6.3-cp315-cp315-macosx_10_12_x86_64.whl", hash = "sha256:e059c5dde6452b44424bd1834557556c226b57781dee1227af23518459722b13", size = 344726, upload-time = "2026-06-30T07:16:44.5Z" }, + { url = "https://files.pythonhosted.org/packages/c3/63/e7b3a1a5358dd32c930a1062d8e15b67fd6e8922e81df9e91706d66ee5c8/rpds_py-2026.6.3-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:2f7c26fbc5acd2522b95d4177fe4710ffd8e9b20529e703ffbf8db4d93903f05", size = 339587, upload-time = "2026-06-30T07:16:46.255Z" }, + { url = "https://files.pythonhosted.org/packages/ec/64/10a85681916ca55fffb91b0a211f84e34297c109243484dd6394660a8a7c/rpds_py-2026.6.3-cp315-cp315-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3086b538543802f84c843911242db20447de00d8752dd0efc936dbcf02218ba", size = 369585, upload-time = "2026-06-30T07:16:48.101Z" }, + { url = "https://files.pythonhosted.org/packages/76/c2/baf95c7c38823e12ba34407c5f5767a89e5cf2233895e56f608167ae9493/rpds_py-2026.6.3-cp315-cp315-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f2e5c5ee828d42cb11760761c0af6507927bec42d0ad5458f97c9203b054617", size = 375479, upload-time = "2026-06-30T07:16:49.93Z" }, + { url = "https://files.pythonhosted.org/packages/6a/94/0aad06c72d65101e11d33528d438cda99a39ce0da99466e156158f2541d3/rpds_py-2026.6.3-cp315-cp315-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed0c1e5d10cdc7135537988c74a0188da68e2f3c30813ba3744ab1e42e0480f9", size = 492418, upload-time = "2026-06-30T07:16:51.641Z" }, + { url = "https://files.pythonhosted.org/packages/b5/17/de3f5a479a1f056535d7489819639d8cd591ea6281d700390b43b1abd745/rpds_py-2026.6.3-cp315-cp315-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c2642a7603ec0b16ed77da4555db3b4b472341904873788327c0b0d7b95f1bb", size = 384123, upload-time = "2026-06-30T07:16:53.622Z" }, + { url = "https://files.pythonhosted.org/packages/46/7d/bf09bd1b145bb2671c03e1e6d1ab8651858d90d8c7dfeadd85a37a934fd8/rpds_py-2026.6.3-cp315-cp315-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e4320744c1ffdd95a603def63344bfab2d33edeab301c5007e7de9f9f5b3885", size = 367351, upload-time = "2026-06-30T07:16:55.241Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ea/1bb734f314b8be319149ddee80b18bd41372bdcfbdf88d28131c0cd37719/rpds_py-2026.6.3-cp315-cp315-manylinux_2_31_riscv64.whl", hash = "sha256:a9f4645593036b81bbdb36b9c8e0ea0d1c3fee968c4d59db0344c14087ef143a", size = 378827, upload-time = "2026-06-30T07:16:56.841Z" }, + { url = "https://files.pythonhosted.org/packages/4b/93/d9611e5b25e26df9a3649813ed66193ace9347a7c7fc4ab7cf70e94851c0/rpds_py-2026.6.3-cp315-cp315-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e55d236be29255554da47abe5c577637db7c24a02b8b46f0ca9524c855801868", size = 395966, upload-time = "2026-06-30T07:16:58.557Z" }, + { url = "https://files.pythonhosted.org/packages/c3/cb/99d77e16e5534ae1d90629bbe419ba6ee170833a6a85e3aa1cc41726fbbc/rpds_py-2026.6.3-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:24e9c5386e16669b674a69c156c8eeefcb578f3b3397b713b08e6d60f3c7b187", size = 545680, upload-time = "2026-06-30T07:17:00.164Z" }, + { url = "https://files.pythonhosted.org/packages/59/15/11a29755f790cef7a2f755e8e14f4f0c33f39489e1893a632a2eee59672b/rpds_py-2026.6.3-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:c60924535c75f1566b6eb75b5c31a48a43fef04fa2d0d201acbad8a9969c6107", size = 611853, upload-time = "2026-06-30T07:17:01.962Z" }, + { url = "https://files.pythonhosted.org/packages/68/86/0c27547e21644da938fb530f7e1a8148dd24d02db07e7a5f2567a17ce710/rpds_py-2026.6.3-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:38a2fea2787428f811719ceb9114cb78964a3138838320c29ac39526c79c16ba", size = 573715, upload-time = "2026-06-30T07:17:03.693Z" }, + { url = "https://files.pythonhosted.org/packages/29/71/4d8fcf700931815594bce892255bbd973b94efaf0fc1932b0590df18d886/rpds_py-2026.6.3-cp315-cp315-win32.whl", hash = "sha256:d483fe17f01ad64b7bf7cc38fcefff1ca9fb83f8c2b2542b68f97ffe0611b369", size = 202864, upload-time = "2026-06-30T07:17:05.746Z" }, + { url = "https://files.pythonhosted.org/packages/eb/62/b577562de0edbb55b2be85ce5fd09c33e386b9b13eee09833af4240fd5c4/rpds_py-2026.6.3-cp315-cp315-win_amd64.whl", hash = "sha256:67e3a721ffc5d8d2210d3671872298c4a84e4b8035cfe42ffd7cde35d772b146", size = 220430, upload-time = "2026-06-30T07:17:07.471Z" }, + { url = "https://files.pythonhosted.org/packages/c8/95/d6d0b2509825141eef60669a5739eec88dbc6a48053d6c92993a5704defe/rpds_py-2026.6.3-cp315-cp315-win_arm64.whl", hash = "sha256:6e84adbcf4bf841aed8116a8264b9f50b4cb3e7bd89b516122e616ac56ca269e", size = 215877, upload-time = "2026-06-30T07:17:09.008Z" }, + { url = "https://files.pythonhosted.org/packages/b7/bf/f3ea278f0afd615c1d0f19cb69043a41526e2bb600c2b536eb192218eb27/rpds_py-2026.6.3-cp315-cp315t-macosx_10_12_x86_64.whl", hash = "sha256:ae6dd8f10bd17aad820876d24caec9efdafd80a318d16c0a48edb5e136902c6b", size = 346933, upload-time = "2026-06-30T07:17:10.762Z" }, + { url = "https://files.pythonhosted.org/packages/9d/29/9907bdf1c5346763cf10b7f6852aad86652168c259def904cbe0082c5864/rpds_py-2026.6.3-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:bdbd97738551fca3917c1bd7188bec1920bb520104f28e7e1007f9ceb17b7690", size = 340274, upload-time = "2026-06-30T07:17:12.266Z" }, + { url = "https://files.pythonhosted.org/packages/6f/2c/8e03767b5778ef25cebf74a7a91a2c3806f8eced4c92cb7406bbe060756d/rpds_py-2026.6.3-cp315-cp315t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b95977e7211527ab0ba576e286d023389fbeeb32a6b7b771665d333c60e5342", size = 370763, upload-time = "2026-06-30T07:17:14.107Z" }, + { url = "https://files.pythonhosted.org/packages/2e/e1/df2a7e1ba2efd796af26194250b8d42c821b46592311595162af9ef0528d/rpds_py-2026.6.3-cp315-cp315t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d15fde0e6fb0d88a60d221204873743e5d9f0b7d29165e62cd86d0413ad74ba6", size = 376467, upload-time = "2026-06-30T07:17:15.76Z" }, + { url = "https://files.pythonhosted.org/packages/6b/de/8a0814d1946af29cb068fb259aa8622f856df1d0bab58429448726b537f5/rpds_py-2026.6.3-cp315-cp315t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a136d453475ac0fcbda502ef1e6504bd28d6d904700915d278deeab0d00fe140", size = 496689, upload-time = "2026-06-30T07:17:17.308Z" }, + { url = "https://files.pythonhosted.org/packages/df/f3/f19e0c852ba13694f5a79f3b719331051573cb5693feacf8a88ffffc3a71/rpds_py-2026.6.3-cp315-cp315t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f826877d462181e5eb1c26a0026b8d0cab05d99844ecb6d8bf3627a2ca0c0442", size = 385340, upload-time = "2026-06-30T07:17:18.928Z" }, + { url = "https://files.pythonhosted.org/packages/e2/ae/7ec3a9d2d4351f99e37bcb06b6b6f954512646bfdbf9742e1de727865daf/rpds_py-2026.6.3-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79486287de1730dbaff3dbd124d0ca4d2ef7f9d29bf2544f1f93c09b5bcbbd12", size = 372179, upload-time = "2026-06-30T07:17:20.539Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ac/9cee911dff2aaa9a5a8354f6610bf2e6a616de9197c5fff4f54f82585f1e/rpds_py-2026.6.3-cp315-cp315t-manylinux_2_31_riscv64.whl", hash = "sha256:808345f53cb952433ca2816f1604ff3515608a81784954f38d4452acfe8e61d5", size = 379993, upload-time = "2026-06-30T07:17:22.212Z" }, + { url = "https://files.pythonhosted.org/packages/83/6b/7c2a07ba88d1e9a936612f7a5d067467ed03d971d5a06f7d309dff044a7e/rpds_py-2026.6.3-cp315-cp315t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1967debc37f64f2c4dc90a7f563aec558b471966e12adcac4e1c4240496b6ebf", size = 398909, upload-time = "2026-06-30T07:17:23.66Z" }, + { url = "https://files.pythonhosted.org/packages/97/0b/776ffcb66783637b0031f6d58d6fb55913c8b5abf00aeecd46bf933fb477/rpds_py-2026.6.3-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:f0840b5b17057f7fd918b76183a4b5a0635f43e14eb2ce60dce1d4ee4707ea00", size = 546584, upload-time = "2026-06-30T07:17:25.264Z" }, + { url = "https://files.pythonhosted.org/packages/55/33/ba3bc04d7092bd553c9b2b195624992d2cc4f3de1f380b7b93cbee67bd79/rpds_py-2026.6.3-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:faa679d19a6696fd54259ad321251ad77a13e70e03dd834daa762a44fb6196ef", size = 614357, upload-time = "2026-06-30T07:17:26.888Z" }, + { url = "https://files.pythonhosted.org/packages/8b/71/14edf065f04630b1a8472f7653cad03f6c478bcf95ea0e6aed55451e33ea/rpds_py-2026.6.3-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:23a439f31ccbeff1574e24889128821d1f7917470e830cf6544dced1c662262a", size = 576533, upload-time = "2026-06-30T07:17:28.546Z" }, + { url = "https://files.pythonhosted.org/packages/ba/76/65002b08596c389105720a8c0d22298b8dc25a4baf89b2ce431343c8b1de/rpds_py-2026.6.3-cp315-cp315t-win32.whl", hash = "sha256:913ca42ccad3f8cc6e292b587ae8ae49c8c823e5dce51a736252fc7c7cdfa577", size = 201204, upload-time = "2026-06-30T07:17:30.193Z" }, + { url = "https://files.pythonhosted.org/packages/8c/97/d855d6b3c322d1f27e26f5241c42016b56cf01377ea8ed348285f54652f0/rpds_py-2026.6.3-cp315-cp315t-win_amd64.whl", hash = "sha256:ae3d4fe8c0b9213624fdce7279d70e3b148b682ca20719ebd193a23ebfa47324", size = 220719, upload-time = "2026-06-30T07:17:31.788Z" }, +] + [[package]] name = "ruff" version = "0.15.12" @@ -2545,6 +3953,66 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/87/72/c6c32d2b657fa3dad1de340254e14390b1e334ce38268b7ad51abda3c8c2/s3transfer-0.17.0-py3-none-any.whl", hash = "sha256:ce3801712acf4ad3e89fb9990df97b4972e93f4b3b0004d214be5bce12814c20", size = 86811, upload-time = "2026-04-29T22:07:34.966Z" }, ] +[[package]] +name = "send2trash" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/f0/184b4b5f8d00f2a92cf96eec8967a3d550b52cf94362dad1100df9e48d57/send2trash-2.1.0.tar.gz", hash = "sha256:1c72b39f09457db3c05ce1d19158c2cbef4c32b8bedd02c155e49282b7ea7459", size = 17255, upload-time = "2026-01-14T06:27:36.056Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/78/504fdd027da3b84ff1aecd9f6957e65f35134534ccc6da8628eb71e76d3f/send2trash-2.1.0-py3-none-any.whl", hash = "sha256:0da2f112e6d6bb22de6aa6daa7e144831a4febf2a87261451c4ad849fe9a873c", size = 17610, upload-time = "2026-01-14T06:27:35.218Z" }, +] + +[[package]] +name = "shapely" +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4d/bc/0989043118a27cccb4e906a46b7565ce36ca7b57f5a18b78f4f1b0f72d9d/shapely-2.1.2.tar.gz", hash = "sha256:2ed4ecb28320a433db18a5bf029986aa8afcfd740745e78847e330d5d94922a9", size = 315489, upload-time = "2025-09-24T13:51:41.432Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/c0/f3b6453cf2dfa99adc0ba6675f9aaff9e526d2224cbd7ff9c1a879238693/shapely-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fe2533caae6a91a543dec62e8360fe86ffcdc42a7c55f9dfd0128a977a896b94", size = 1833550, upload-time = "2025-09-24T13:50:30.019Z" }, + { url = "https://files.pythonhosted.org/packages/86/07/59dee0bc4b913b7ab59ab1086225baca5b8f19865e6101db9ebb7243e132/shapely-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ba4d1333cc0bc94381d6d4308d2e4e008e0bd128bdcff5573199742ee3634359", size = 1643556, upload-time = "2025-09-24T13:50:32.291Z" }, + { url = "https://files.pythonhosted.org/packages/26/29/a5397e75b435b9895cd53e165083faed5d12fd9626eadec15a83a2411f0f/shapely-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0bd308103340030feef6c111d3eb98d50dc13feea33affc8a6f9fa549e9458a3", size = 2988308, upload-time = "2025-09-24T13:50:33.862Z" }, + { url = "https://files.pythonhosted.org/packages/b9/37/e781683abac55dde9771e086b790e554811a71ed0b2b8a1e789b7430dd44/shapely-2.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1e7d4d7ad262a48bb44277ca12c7c78cb1b0f56b32c10734ec9a1d30c0b0c54b", size = 3099844, upload-time = "2025-09-24T13:50:35.459Z" }, + { url = "https://files.pythonhosted.org/packages/d8/f3/9876b64d4a5a321b9dc482c92bb6f061f2fa42131cba643c699f39317cb9/shapely-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e9eddfe513096a71896441a7c37db72da0687b34752c4e193577a145c71736fc", size = 3988842, upload-time = "2025-09-24T13:50:37.478Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a0/704c7292f7014c7e74ec84eddb7b109e1fbae74a16deae9c1504b1d15565/shapely-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:980c777c612514c0cf99bc8a9de6d286f5e186dcaf9091252fcd444e5638193d", size = 4152714, upload-time = "2025-09-24T13:50:39.9Z" }, + { url = "https://files.pythonhosted.org/packages/53/46/319c9dc788884ad0785242543cdffac0e6530e4d0deb6c4862bc4143dcf3/shapely-2.1.2-cp312-cp312-win32.whl", hash = "sha256:9111274b88e4d7b54a95218e243282709b330ef52b7b86bc6aaf4f805306f454", size = 1542745, upload-time = "2025-09-24T13:50:41.414Z" }, + { url = "https://files.pythonhosted.org/packages/ec/bf/cb6c1c505cb31e818e900b9312d514f381fbfa5c4363edfce0fcc4f8c1a4/shapely-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:743044b4cfb34f9a67205cee9279feaf60ba7d02e69febc2afc609047cb49179", size = 1722861, upload-time = "2025-09-24T13:50:43.35Z" }, + { url = "https://files.pythonhosted.org/packages/c3/90/98ef257c23c46425dc4d1d31005ad7c8d649fe423a38b917db02c30f1f5a/shapely-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b510dda1a3672d6879beb319bc7c5fd302c6c354584690973c838f46ec3e0fa8", size = 1832644, upload-time = "2025-09-24T13:50:44.886Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ab/0bee5a830d209adcd3a01f2d4b70e587cdd9fd7380d5198c064091005af8/shapely-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8cff473e81017594d20ec55d86b54bc635544897e13a7cfc12e36909c5309a2a", size = 1642887, upload-time = "2025-09-24T13:50:46.735Z" }, + { url = "https://files.pythonhosted.org/packages/2d/5e/7d7f54ba960c13302584c73704d8c4d15404a51024631adb60b126a4ae88/shapely-2.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe7b77dc63d707c09726b7908f575fc04ff1d1ad0f3fb92aec212396bc6cfe5e", size = 2970931, upload-time = "2025-09-24T13:50:48.374Z" }, + { url = "https://files.pythonhosted.org/packages/f2/a2/83fc37e2a58090e3d2ff79175a95493c664bcd0b653dd75cb9134645a4e5/shapely-2.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7ed1a5bbfb386ee8332713bf7508bc24e32d24b74fc9a7b9f8529a55db9f4ee6", size = 3082855, upload-time = "2025-09-24T13:50:50.037Z" }, + { url = "https://files.pythonhosted.org/packages/44/2b/578faf235a5b09f16b5f02833c53822294d7f21b242f8e2d0cf03fb64321/shapely-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a84e0582858d841d54355246ddfcbd1fce3179f185da7470f41ce39d001ee1af", size = 3979960, upload-time = "2025-09-24T13:50:51.74Z" }, + { url = "https://files.pythonhosted.org/packages/4d/04/167f096386120f692cc4ca02f75a17b961858997a95e67a3cb6a7bbd6b53/shapely-2.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dc3487447a43d42adcdf52d7ac73804f2312cbfa5d433a7d2c506dcab0033dfd", size = 4142851, upload-time = "2025-09-24T13:50:53.49Z" }, + { url = "https://files.pythonhosted.org/packages/48/74/fb402c5a6235d1c65a97348b48cdedb75fb19eca2b1d66d04969fc1c6091/shapely-2.1.2-cp313-cp313-win32.whl", hash = "sha256:9c3a3c648aedc9f99c09263b39f2d8252f199cb3ac154fadc173283d7d111350", size = 1541890, upload-time = "2025-09-24T13:50:55.337Z" }, + { url = "https://files.pythonhosted.org/packages/41/47/3647fe7ad990af60ad98b889657a976042c9988c2807cf322a9d6685f462/shapely-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:ca2591bff6645c216695bdf1614fca9c82ea1144d4a7591a466fef64f28f0715", size = 1722151, upload-time = "2025-09-24T13:50:57.153Z" }, + { url = "https://files.pythonhosted.org/packages/3c/49/63953754faa51ffe7d8189bfbe9ca34def29f8c0e34c67cbe2a2795f269d/shapely-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2d93d23bdd2ed9dc157b46bc2f19b7da143ca8714464249bef6771c679d5ff40", size = 1834130, upload-time = "2025-09-24T13:50:58.49Z" }, + { url = "https://files.pythonhosted.org/packages/7f/ee/dce001c1984052970ff60eb4727164892fb2d08052c575042a47f5a9e88f/shapely-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:01d0d304b25634d60bd7cf291828119ab55a3bab87dc4af1e44b07fb225f188b", size = 1642802, upload-time = "2025-09-24T13:50:59.871Z" }, + { url = "https://files.pythonhosted.org/packages/da/e7/fc4e9a19929522877fa602f705706b96e78376afb7fad09cad5b9af1553c/shapely-2.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8d8382dd120d64b03698b7298b89611a6ea6f55ada9d39942838b79c9bc89801", size = 3018460, upload-time = "2025-09-24T13:51:02.08Z" }, + { url = "https://files.pythonhosted.org/packages/a1/18/7519a25db21847b525696883ddc8e6a0ecaa36159ea88e0fef11466384d0/shapely-2.1.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:19efa3611eef966e776183e338b2d7ea43569ae99ab34f8d17c2c054d3205cc0", size = 3095223, upload-time = "2025-09-24T13:51:04.472Z" }, + { url = "https://files.pythonhosted.org/packages/48/de/b59a620b1f3a129c3fecc2737104a0a7e04e79335bd3b0a1f1609744cf17/shapely-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:346ec0c1a0fcd32f57f00e4134d1200e14bf3f5ae12af87ba83ca275c502498c", size = 4030760, upload-time = "2025-09-24T13:51:06.455Z" }, + { url = "https://files.pythonhosted.org/packages/96/b3/c6655ee7232b417562bae192ae0d3ceaadb1cc0ffc2088a2ddf415456cc2/shapely-2.1.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6305993a35989391bd3476ee538a5c9a845861462327efe00dd11a5c8c709a99", size = 4170078, upload-time = "2025-09-24T13:51:08.584Z" }, + { url = "https://files.pythonhosted.org/packages/a0/8e/605c76808d73503c9333af8f6cbe7e1354d2d238bda5f88eea36bfe0f42a/shapely-2.1.2-cp313-cp313t-win32.whl", hash = "sha256:c8876673449f3401f278c86eb33224c5764582f72b653a415d0e6672fde887bf", size = 1559178, upload-time = "2025-09-24T13:51:10.73Z" }, + { url = "https://files.pythonhosted.org/packages/36/f7/d317eb232352a1f1444d11002d477e54514a4a6045536d49d0c59783c0da/shapely-2.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:4a44bc62a10d84c11a7a3d7c1c4fe857f7477c3506e24c9062da0db0ae0c449c", size = 1739756, upload-time = "2025-09-24T13:51:12.105Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c4/3ce4c2d9b6aabd27d26ec988f08cb877ba9e6e96086eff81bfea93e688c7/shapely-2.1.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:9a522f460d28e2bf4e12396240a5fc1518788b2fcd73535166d748399ef0c223", size = 1831290, upload-time = "2025-09-24T13:51:13.56Z" }, + { url = "https://files.pythonhosted.org/packages/17/b9/f6ab8918fc15429f79cb04afa9f9913546212d7fb5e5196132a2af46676b/shapely-2.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1ff629e00818033b8d71139565527ced7d776c269a49bd78c9df84e8f852190c", size = 1641463, upload-time = "2025-09-24T13:51:14.972Z" }, + { url = "https://files.pythonhosted.org/packages/a5/57/91d59ae525ca641e7ac5551c04c9503aee6f29b92b392f31790fcb1a4358/shapely-2.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f67b34271dedc3c653eba4e3d7111aa421d5be9b4c4c7d38d30907f796cb30df", size = 2970145, upload-time = "2025-09-24T13:51:16.961Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cb/4948be52ee1da6927831ab59e10d4c29baa2a714f599f1f0d1bc747f5777/shapely-2.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:21952dc00df38a2c28375659b07a3979d22641aeb104751e769c3ee825aadecf", size = 3073806, upload-time = "2025-09-24T13:51:18.712Z" }, + { url = "https://files.pythonhosted.org/packages/03/83/f768a54af775eb41ef2e7bec8a0a0dbe7d2431c3e78c0a8bdba7ab17e446/shapely-2.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1f2f33f486777456586948e333a56ae21f35ae273be99255a191f5c1fa302eb4", size = 3980803, upload-time = "2025-09-24T13:51:20.37Z" }, + { url = "https://files.pythonhosted.org/packages/9f/cb/559c7c195807c91c79d38a1f6901384a2878a76fbdf3f1048893a9b7534d/shapely-2.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cf831a13e0d5a7eb519e96f58ec26e049b1fad411fc6fc23b162a7ce04d9cffc", size = 4133301, upload-time = "2025-09-24T13:51:21.887Z" }, + { url = "https://files.pythonhosted.org/packages/80/cd/60d5ae203241c53ef3abd2ef27c6800e21afd6c94e39db5315ea0cbafb4a/shapely-2.1.2-cp314-cp314-win32.whl", hash = "sha256:61edcd8d0d17dd99075d320a1dd39c0cb9616f7572f10ef91b4b5b00c4aeb566", size = 1583247, upload-time = "2025-09-24T13:51:23.401Z" }, + { url = "https://files.pythonhosted.org/packages/74/d4/135684f342e909330e50d31d441ace06bf83c7dc0777e11043f99167b123/shapely-2.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:a444e7afccdb0999e203b976adb37ea633725333e5b119ad40b1ca291ecf311c", size = 1773019, upload-time = "2025-09-24T13:51:24.873Z" }, + { url = "https://files.pythonhosted.org/packages/a3/05/a44f3f9f695fa3ada22786dc9da33c933da1cbc4bfe876fe3a100bafe263/shapely-2.1.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:5ebe3f84c6112ad3d4632b1fd2290665aa75d4cef5f6c5d77c4c95b324527c6a", size = 1834137, upload-time = "2025-09-24T13:51:26.665Z" }, + { url = "https://files.pythonhosted.org/packages/52/7e/4d57db45bf314573427b0a70dfca15d912d108e6023f623947fa69f39b72/shapely-2.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5860eb9f00a1d49ebb14e881f5caf6c2cf472c7fd38bd7f253bbd34f934eb076", size = 1642884, upload-time = "2025-09-24T13:51:28.029Z" }, + { url = "https://files.pythonhosted.org/packages/5a/27/4e29c0a55d6d14ad7422bf86995d7ff3f54af0eba59617eb95caf84b9680/shapely-2.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b705c99c76695702656327b819c9660768ec33f5ce01fa32b2af62b56ba400a1", size = 3018320, upload-time = "2025-09-24T13:51:29.903Z" }, + { url = "https://files.pythonhosted.org/packages/9f/bb/992e6a3c463f4d29d4cd6ab8963b75b1b1040199edbd72beada4af46bde5/shapely-2.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a1fd0ea855b2cf7c9cddaf25543e914dd75af9de08785f20ca3085f2c9ca60b0", size = 3094931, upload-time = "2025-09-24T13:51:32.699Z" }, + { url = "https://files.pythonhosted.org/packages/9c/16/82e65e21070e473f0ed6451224ed9fa0be85033d17e0c6e7213a12f59d12/shapely-2.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:df90e2db118c3671a0754f38e36802db75fe0920d211a27481daf50a711fdf26", size = 4030406, upload-time = "2025-09-24T13:51:34.189Z" }, + { url = "https://files.pythonhosted.org/packages/7c/75/c24ed871c576d7e2b64b04b1fe3d075157f6eb54e59670d3f5ffb36e25c7/shapely-2.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:361b6d45030b4ac64ddd0a26046906c8202eb60d0f9f53085f5179f1d23021a0", size = 4169511, upload-time = "2025-09-24T13:51:36.297Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f7/b3d1d6d18ebf55236eec1c681ce5e665742aab3c0b7b232720a7d43df7b6/shapely-2.1.2-cp314-cp314t-win32.whl", hash = "sha256:b54df60f1fbdecc8ebc2c5b11870461a6417b3d617f555e5033f1505d36e5735", size = 1602607, upload-time = "2025-09-24T13:51:37.757Z" }, + { url = "https://files.pythonhosted.org/packages/9a/f6/f09272a71976dfc138129b8faf435d064a811ae2f708cb147dccdf7aacdb/shapely-2.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:0036ac886e0923417932c2e6369b6c52e38e0ff5d9120b90eef5cd9a5fc5cae9", size = 1796682, upload-time = "2025-09-24T13:51:39.233Z" }, +] + [[package]] name = "simplejson" version = "4.1.1" @@ -2616,6 +4084,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, ] +[[package]] +name = "soupsieve" +version = "2.8.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/2c/0a5f6f8ee0d5589e48c7640213ed5175d52cf540a06725b628cc1a45d6ce/soupsieve-2.8.4.tar.gz", hash = "sha256:e121fd02e975c695e4e9e8774a5ee35d74714b59307868dcc5319ad2d9e3328e", size = 121110, upload-time = "2026-05-24T13:55:57.154Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5e/f5/0c41cb68dcae6b7de4fac4188a3a9589e21fb31df21ea3a2e888db95e6c9/soupsieve-2.8.4-py3-none-any.whl", hash = "sha256:e7e6b0769c8f51ed59acab6e994b00621096cfb1c640a7509295987388fbaf65", size = 37304, upload-time = "2026-05-24T13:55:55.406Z" }, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, +] + [[package]] name = "starlette" version = "1.0.0" @@ -2669,6 +4160,32 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/be/5d2d47b1fb58943194fb59dcf222f7c4e35122ec0ffe8c36e18b5d728f0b/tblib-3.2.2-py3-none-any.whl", hash = "sha256:26bdccf339bcce6a88b2b5432c988b266ebbe63a4e593f6b578b1d2e723d2b76", size = 12893, upload-time = "2025-11-12T12:21:14.407Z" }, ] +[[package]] +name = "terminado" +version = "0.18.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess", marker = "os_name != 'nt'" }, + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "tornado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701, upload-time = "2024-03-12T14:34:39.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, +] + +[[package]] +name = "tinycss2" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/ae/2ca4913e5c0f09781d75482874c3a95db9105462a92ddd303c7d285d3df2/tinycss2-1.5.1.tar.gz", hash = "sha256:d339d2b616ba90ccce58da8495a78f46e55d4d25f9fd71dfd526f07e7d53f957", size = 88195, upload-time = "2025-11-23T10:29:10.082Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/45/c7b5c3168458db837e8ceab06dc77824e18202679d0463f0e8f002143a97/tinycss2-1.5.1-py3-none-any.whl", hash = "sha256:3415ba0f5839c062696996998176c4a3751d18b7edaaeeb658c9ce21ec150661", size = 28404, upload-time = "2025-11-23T10:29:08.676Z" }, +] + [[package]] name = "titiler-core" version = "2.0.2" @@ -2718,19 +4235,28 @@ wheels = [ [[package]] name = "tornado" -version = "6.5.5" +version = "6.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/64/24/95ec527ad67b76d59299e5465b3935d05e4294b7e0290a3924b7487df30b/tornado-6.5.7.tar.gz", hash = "sha256:66c513a76cda70d53907bc27cf1447557699c2e95aa48ba27a442ff61c3ddfc2", size = 519252, upload-time = "2026-06-08T17:34:51.232Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/dc/c7043cab6fed8ae159fc1923ce829ada35c4dbd797d408a43858ffaf9639/tornado-6.5.7-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:148b2eb15c2c765a50796172c1e499649b35f30d2e3c3d3e15913cfa56bfb163", size = 448543, upload-time = "2026-06-08T17:34:38.052Z" }, + { url = "https://files.pythonhosted.org/packages/92/4f/090b1431e5a43df696feceffc268c5383cc079ecb5f08ce58f917109aafe/tornado-6.5.7-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9da38de27f1da3b78a966f0dae12b5a1ea9afe72ca805d84ff06508272ddf100", size = 446707, upload-time = "2026-06-08T17:34:39.594Z" }, + { url = "https://files.pythonhosted.org/packages/37/d8/ef374952fd5da67d4463122c2b8e5a96536ec10b4b339254c6dcde81d01c/tornado-6.5.7-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8d759e71906ee783f8867b93bf26a265743da4c1e2f4a018464c1ba019862972", size = 449774, upload-time = "2026-06-08T17:34:41.204Z" }, + { url = "https://files.pythonhosted.org/packages/35/37/d434c73f4c6e014b745b9b37085f34f40c022f007efff3d7fe65991899f3/tornado-6.5.7-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a46347a18f23fb92b396beebe0fb78f61dda0cc302445202c16203d8a18848b", size = 450745, upload-time = "2026-06-08T17:34:42.531Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2b/56b9aff361d7f1ab728a805ec7d7ea835f8807afa9f5cc690ea0e630efb9/tornado-6.5.7-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7778b30bef919231265e91c69963ce0f49a1e9c07ac900bbe75b19ce2575ba92", size = 450578, upload-time = "2026-06-08T17:34:43.787Z" }, + { url = "https://files.pythonhosted.org/packages/02/30/a7444fb23aa76860a14198fab96ac79f1866b0a6e19e26c4381b0938e50f/tornado-6.5.7-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e726f0c75da7726eec023aa62751ff8878bd2737e34fbdd33b1ae5897d2200f5", size = 449985, upload-time = "2026-06-08T17:34:45.326Z" }, + { url = "https://files.pythonhosted.org/packages/5c/42/5f0e56c01e8d9d36f4e23f367b85ae6cae0c1ecddd5e6977d8388ad27488/tornado-6.5.7-cp39-abi3-win32.whl", hash = "sha256:f8de3bf12d3efdd0cbe7c8887868198f8a91415e3f29fcf258d9b8eb7b1d9ae4", size = 451047, upload-time = "2026-06-08T17:34:46.784Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a4/b393076ffb21b469eec5b328a0534cf03a3b90bfc6b1f09507cdd075d938/tornado-6.5.7-cp39-abi3-win_amd64.whl", hash = "sha256:de942f843533a039ef9fa3d9c88c7cd8a7c94553fb5ad0154270989b3d99a2c4", size = 451485, upload-time = "2026-06-08T17:34:48.248Z" }, + { url = "https://files.pythonhosted.org/packages/71/2e/7b1c769803121b809112cf9a00681c472eae1d80e32d7ec0e0bd61d0d0e1/tornado-6.5.7-cp39-abi3-win_arm64.whl", hash = "sha256:ff934fce95643af5f11efdae618eaa73d469dc588641e5c8d19295a0c65c4796", size = 450506, upload-time = "2026-06-08T17:34:49.702Z" }, +] + +[[package]] +name = "traitlets" +version = "5.15.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/f1/3173dfa4a18db4a9b03e5d55325559dab51ee653763bb8745a75af491286/tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9", size = 516006, upload-time = "2026-03-10T21:31:02.067Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/a9/a2584b8313b89f94869ddb3c4074617a691de1812a614d2d50e32ca5a7a6/traitlets-5.15.1.tar.gz", hash = "sha256:7b1c07854fe25acb39e009bae49f11b79ff6cbb2f27999104e9110e7a6b53722", size = 163344, upload-time = "2026-06-03T12:26:06.181Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/59/8c/77f5097695f4dd8255ecbd08b2a1ed8ba8b953d337804dd7080f199e12bf/tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa", size = 445983, upload-time = "2026-03-10T21:30:44.28Z" }, - { url = "https://files.pythonhosted.org/packages/ab/5e/7625b76cd10f98f1516c36ce0346de62061156352353ef2da44e5c21523c/tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521", size = 444246, upload-time = "2026-03-10T21:30:46.571Z" }, - { url = "https://files.pythonhosted.org/packages/b2/04/7b5705d5b3c0fab088f434f9c83edac1573830ca49ccf29fb83bf7178eec/tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5", size = 447229, upload-time = "2026-03-10T21:30:48.273Z" }, - { url = "https://files.pythonhosted.org/packages/34/01/74e034a30ef59afb4097ef8659515e96a39d910b712a89af76f5e4e1f93c/tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07", size = 448192, upload-time = "2026-03-10T21:30:51.22Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/fe9e02c5a96429fce1a1d15a517f5d8444f9c412e0bb9eadfbe3b0fc55bf/tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e", size = 448039, upload-time = "2026-03-10T21:30:53.52Z" }, - { url = "https://files.pythonhosted.org/packages/82/9e/656ee4cec0398b1d18d0f1eb6372c41c6b889722641d84948351ae19556d/tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca", size = 447445, upload-time = "2026-03-10T21:30:55.541Z" }, - { url = "https://files.pythonhosted.org/packages/5a/76/4921c00511f88af86a33de770d64141170f1cfd9c00311aea689949e274e/tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7", size = 448582, upload-time = "2026-03-10T21:30:57.142Z" }, - { url = "https://files.pythonhosted.org/packages/2c/23/f6c6112a04d28eed765e374435fb1a9198f73e1ec4b4024184f21faeb1ad/tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b", size = 448990, upload-time = "2026-03-10T21:30:58.857Z" }, - { url = "https://files.pythonhosted.org/packages/b7/c8/876602cbc96469911f0939f703453c1157b0c826ecb05bdd32e023397d4e/tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6", size = 448016, upload-time = "2026-03-10T21:31:00.43Z" }, + { url = "https://files.pythonhosted.org/packages/96/8d/1080ee4c231f361b6ce4470d556c8c435b67c7e0753aaa641497ee92f88b/traitlets-5.15.1-py3-none-any.whl", hash = "sha256:770a53705f84b81ac107e83a1b3328ff2dae16094d8fc3cfc004e4b22dfd8e92", size = 85858, upload-time = "2026-06-03T12:26:04.395Z" }, ] [[package]] @@ -2763,6 +4289,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" }, ] +[[package]] +name = "uri-template" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678, upload-time = "2023-06-21T01:49:05.374Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140, upload-time = "2023-06-21T01:49:03.467Z" }, +] + [[package]] name = "urllib3" version = "2.7.0" @@ -2820,6 +4355,51 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, ] +[[package]] +name = "wcwidth" +version = "0.8.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/34/74/c6428f875774288bec1396f5bfcbc2d925700a4dad61727fd5f2b12f249d/wcwidth-0.8.2.tar.gz", hash = "sha256:91fbef97204b96a3d4d421609b80340b760cf33e26da123ff243d76b1fda8dda", size = 1466253, upload-time = "2026-06-29T18:11:11.601Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl", hash = "sha256:d63947694a0539a1d51e01eda7caf800c291020e6cdd7e28ad7b14dd33ad4f85", size = 323166, upload-time = "2026-06-29T18:11:09.888Z" }, +] + +[[package]] +name = "webcolors" +version = "25.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491, upload-time = "2025-10-31T07:51:03.977Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905, upload-time = "2025-10-31T07:51:01.778Z" }, +] + +[[package]] +name = "webencodings" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, +] + +[[package]] +name = "websocket-client" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, +] + +[[package]] +name = "widgetsnbextension" +version = "4.0.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402, upload-time = "2025-11-01T21:15:55.178Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503, upload-time = "2025-11-01T21:15:53.565Z" }, +] + [[package]] name = "wrapt" version = "2.1.2" @@ -3026,11 +4606,15 @@ cast-value-rs = [ [[package]] name = "zarr-cm" -version = "0.4.1.dev13+ge94a3ee8d" -source = { git = "https://github.com/zarr-conventions/zarr-cm.git?rev=main#e94a3ee8db52689883753f5b928f8331c3d01b15" } +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/f9/c6/51d38cafa07bdf725c77a67719647eea43255f925fda062b40799bbb361d/zarr_cm-0.4.1.tar.gz", hash = "sha256:693d24ca2b8e3a7230e1ed448c2c57f98833b81e5899607b6cb4a7ac31f94002", size = 50839, upload-time = "2026-06-21T19:20:36.277Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/14/3de8976647909b2f6764b8d0c9add0a961667ef4ab46f3f99e12d7a522fa/zarr_cm-0.4.1-py3-none-any.whl", hash = "sha256:2c7f36383af2e6f75eb274a797a13154fd5c5827390de7c79294dfeb9f0543ee", size = 33005, upload-time = "2026-06-21T19:20:35.05Z" }, +] [[package]] name = "zict"