diff --git a/.gemini/GEMINI.md b/.gemini/GEMINI.md index e18d7aa..d3a177a 100644 --- a/.gemini/GEMINI.md +++ b/.gemini/GEMINI.md @@ -1 +1 @@ -You must strictly adhere to the project rules defined in `docs/agents/agent_instructions.md`. Read this file before making any significant architectural, geospatial data processing changes, or general code modifications. Use `read_file` to load `docs/agents/agent_istructions.md`. +You must strictly adhere to the project rules defined in [docs/agents/agent_instructions.md](../docs/agents/agent_instructions.md). Read this file before making any significant architectural, geospatial data processing changes, or general code modifications. Use `read_file` to load [docs/agents/agent_instructions.md](../docs/agents/agent_instructions.md). diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 442bd20..e98e227 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1 +1 @@ -You must strictly adhere to the project rules defined in `docs/agents/agent_instructions.md`. Read this file before making any significant architectural, geospatial data processing changes, or general code modifications. +You must strictly adhere to the project rules defined in [docs/agents/agent_instructions.md](../docs/agents/agent_instructions.md). Read this file before making any significant architectural, geospatial data processing changes, or general code modifications. diff --git a/.gitignore b/.gitignore index ea96e5d..a3ef330 100644 --- a/.gitignore +++ b/.gitignore @@ -183,3 +183,4 @@ data/* scripts/config.sh Makefile.private configs/geospatial_tools_ini.yaml +**/settings.local.json diff --git a/.markdown-link-check.json b/.markdown-link-check.json index 20015c2..e9d400a 100644 --- a/.markdown-link-check.json +++ b/.markdown-link-check.json @@ -3,21 +3,6 @@ { "pattern": "http://localhost" }, - { - "pattern": "tps://github.com/RolnickLab/best-practices-documentation/tree" - }, - { - "pattern": "tps://github.com/RolnickLab/best-practices-documentation/issues" - }, - { - "pattern": "tps://github.com/RolnickLab/best-practices-documentation/pulls" - }, - { - "pattern": "https://github.com/RolnickLab/best-practices-documentation/wiki" - }, - { - "pattern": "https://github.com/RolnickLab/best-practices-documentation/wiki/DRAC-%E2%80%90-Compute-Canada" - }, { "pattern": "https://github.com/RolnickLab/lab-advanced-template" }, @@ -35,6 +20,9 @@ }, { "pattern": "https://www.earthdata.nasa.gov/" + }, + { + "pattern": "https://earthexplorer.usgs.gov" } ] } \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 442bd20..5940d49 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1 +1 @@ -You must strictly adhere to the project rules defined in `docs/agents/agent_instructions.md`. Read this file before making any significant architectural, geospatial data processing changes, or general code modifications. +You must strictly adhere to the project rules defined in [docs/agents/agent_instructions.md](docs/agents/agent_instructions.md). Read this file before making any significant architectural, geospatial data processing changes, or general code modifications. diff --git a/docs/agents/README.md b/docs/agents/README.md index faa09ad..cd94e6a 100644 --- a/docs/agents/README.md +++ b/docs/agents/README.md @@ -14,20 +14,13 @@ Yes, these instructions are more prescriptive than *current* best practices, but The `instructions/` folder contains specific skill files that guide the agent's behavior for particular tasks. Here is a summary of each skill, its purpose, and when to use it: -| Skill | Description | When to Use & Why | -| ------------------------ | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -| `analytics.md` | Extracts truth from experimental data with statistical rigor. | Use for Exploratory Data Analysis (EDA) and visualization to ensure reproducibility and prevent misleading claims. | -| `formal_planning.md` | Enforces a structured planning protocol via a Formal Design Document. | Use when explicitly asked for a plan, architecture, or proposal to map out scope, trade-offs, and steps before coding. | -| `infrastructure.md` | Manages reproducible and resilient environments/pipelines as code. | Use for containerization (Docker), HPC/SLURM cluster setup, or CI/CD tasks to ensure fault tolerance and exact dependency pinning. | -| `KNOWLEDGE.md` | A centralized repository for project-specific tribal knowledge. | Use to document or consult specific findings, library quirks, or architectural decisions to avoid repeating past mistakes. | -| `ml.md` | Builds state-of-the-art, reproducible, and reliable machine learning pipelines. | Use for ML model training, evaluation, and experiment management to guarantee strict data isolation and deterministic execution. | -| `orchestrator.md` | Focuses on horizontal integration and strategic decomposition of goals. | Use for multi-component tasks to define explicit contracts between modules and ensure end-to-end flows work correctly. | -| `plan_to_tasks.md` | Decomposes high-level plans into modular, atomic, and verifiable tasks. | Use when transitioning from planning to execution to ensure each step has clear context, acceptance criteria, and testing protocols. | -| `python.md` | Elevates Python scripts into robust, maintainable, and type-safe software. | Use for all Python development and QA to enforce strict typing, SOLID principles, vectorization, and automated workflows. | -| `root_cause_analysis.md` | Systematically diagnoses and permanently fixes software failures. | Use when presented with a bug, traceback, or unexpected result to isolate the failure (MRE) and target the actual root cause. | -| `security.md` | Identifies vulnerabilities, enforces defense-in-depth, and ensures data privacy. | Use for tasks involving authentication, untrusted input, or infrastructure to prevent injection attacks and hardcoded secrets. | -| `specdrivendev.md` | Implements lightweight Spec-Driven Development to define contracts first. | Use when starting a new feature to define data structures, signatures, and docstrings before writing logic, preventing LLM hallucinations. | -| `systemdesign.md` | Designs systems that are maintainable, evolvable, and robust. | Use for architectural decisions to enforce separation of concerns, configuration-first design, and proper dependency injection. | +| Skill | Description | When to Use & Why | +| ------------------------ | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | +| `planning.md` | Combined Planning, Specification (SDD), and Task Decomposition Protocol. | Use for any multi-step implementation to map out scope, define technical contracts (SDD), and break down work into atomic tasks. | +| `software-dev.md` | Unified Software Development, ML, Analytics & Infrastructure Protocol. | Use for Python development, system design, ML/geospatial processing, data analysis, and infrastructure/environment management. | +| `review.md` | Harsh Security & Architecture Review Protocol. | Use to identify vulnerabilities (tokens, paths, SSL) and tear apart implementations for performance bottlenecks and architectural rot. | +| `root_cause_analysis.md` | Systematically diagnoses and permanently fixes software failures. | Use when presented with a bug, traceback, or unexpected result to isolate the failure (MRE) and target the actual root cause. | +| `KNOWLEDGE.md` | A centralized repository for project-specific tribal knowledge. | Use to document or consult specific findings, library quirks, or architectural decisions to avoid repeating past mistakes. | ## How to use them @@ -36,16 +29,36 @@ This template comes with CLAUDE.md and GEMINI.md files that essentially point to In practice... it's not always the case. It is probably better to manually feed the instructions directly to the agent/tool as context in your prompt just to make sure: ```text -Using @docs/agents/agent_instructions.md, @docs/agents/instructions/python.md, and @docs/agents/instructions/systemdesign.md and @docs/agents/instructions/formal_planning.md, create a plan for a new class that will ... +Using @docs/agents/agent_instructions.md, @docs/agents/instructions/software-dev.md, and @docs/agents/instructions/planning.md, create a plan for a new class that will ... ``` -When using models with smaller context windows, it will also be important to clear the context once in a while to ensure better results. +It's usually a good thing to clear/compress the context once in a while to ensure better results. -For example: +### Workflow example -- Create plan - - Manually revise plan document -- Clear context -- Ask agent to implement first step of the plan -- Clear context -- Repeat +First, define **what** you want to do, **how** and **why**. Go in as much detail as you can. Let's call this your *preliminary design document*. + +You can also do this step through a chat interface with an LLM so you can brainstorm, ask questions, investigate starting points, development directions and library/tool selections. + +Once you have your *preliminary design document*, you are ready to start using your agent. + +- Activate `@docs/agents/instructions/planning.md` + - **Create PLAN** + - Ask agent to create a plan based on your *preliminary design document* + - Manually revise plan document + - **Create SPEC** + - Ask agent to create a specification based on the plan + - Manually revise the specification document + - **Create TASKS** + - Ask agent to create tasks based on the plan and specification created + - Manually revise the tasks + - **_CLEAR CONTEXT_** +- Activate `@docs/agents/instructions/code_review.md` + - Ask the agent to review your planning documents + - **_CLEAR CONTEXT_** +- Activate `@docs/agents/instructions/software_dev.md` + - Ask agent to implement first task of the plan + - Manual review + - Commit work to git + - **_COMPRESS CONTEXT_** + - Repeat for subsequent tasks diff --git a/docs/agents/agent_instructions.md b/docs/agents/agent_instructions.md index d77264e..de80b72 100644 --- a/docs/agents/agent_instructions.md +++ b/docs/agents/agent_instructions.md @@ -1,73 +1,100 @@ -# Agent Instructions: Educational ML Research Architect +# Core agent instructions for all agents -\ -Your mission is twofold: +## Mission -1. Help build robust, reproducible, and well-designed systems for machine learning and geospatial science. - \ +1. **Systems Orchestration:** Build robust, reproducible systems for ML and geospatial science. Focus on horizontal integration and end-to-end verification. - -- **Environment:** This project is a **Laboratory**, not a strict production environment. We value experimentation, speed, and learning. -- **Outcome:** We aim for **Advanced Proofs of Concepts (POCs)** and **Prototypes** that are clean, documented, and easy for others to understand and take over. Remember: "Nothing is more permanent than a temporary solution." -- **Project level instructions:** These are your mandatory, project-level instructions. You need to consider these instructions for every task. - +## Context -## 1. Core Mandate & Skills +- **Environment:** This project is a **Laboratory**, not a strict production environment. Value experimentation, speed, and learning. +- **Outcome:** Aim for **Advanced Proofs of Concepts (POCs)** and **Prototypes** that are clean, documented, and easy to transfer. "Nothing is more permanent than a temporary solution." +- **Project level instructions:** Mandatory project-level instructions. Consider these for every task. -- **Proactive Context Gathering:** Do not ask the user for information you can find yourself. Use your available search and file-reading tools (e.g., `grep_search` / `grep` / `file_search`, `glob` / `find`, `read_file` / `read_file_content` / `cat`) to understand existing data loaders, models, config patterns, and project standards (linting, testing frameworks). -- **Fail Gracefully & Teach Debugging:** When things break, do not just provide the fixed code. Explain *how* you found the bug, *why* it occurred, and *how* the user can diagnose similar issues in the future. -- **Keep it Simple:** Favor boring, simple, and readable code over overly clever, complex abstractions. The code must be understandable by a researcher who may not be a senior software engineer. -- **Intellectual Honesty:** Prioritize technical truth over agreement. Critically evaluate and challenge all requests, tasks, and assumptions. Propose superior alternatives with a clear explanation of technical trade-offs (e.g., performance, complexity, maintainability) and rationale. +## Communication Style: Caveman Lite -## 2. Operational Workflow +Maintain a terse, high-signal, and professional communication style. Retain full technical accuracy while eliminating all conversational fluff. -- **Establish Baseline:** Identify the current state of the application. -- **Focused Execution:** Prioritize short, high-intent sessions with narrow, actionable objectives (e.g., "Implement the `RasterLoader` class and add unit tests") over broad, open-ended requests. -- **Durable Artifacts:** Establish explicit checkpoints between lifecycle phases. Persist research findings to files and commit interface contracts or architecture decisions (ADRs) after planning to prevent implementation drift. -- - **Atomic Versioning:** Use Git aggressively as the primary session handoff mechanism. Commit after every verified logical unit to ensure future sessions can orient via `git diff` and `git log`. -- **Incremental Review:** Implement changes step by step, phase by phase. After successfully writing and validating code for a logical step, **commit work with git before moving on to next step**. +**Rules:** -## 3. Engineering Preferences +- **No Filler or Pleasantries:** Strip out words like "just", "really", "basically", "actually", "simply", "sure", "happy to help", and avoid all hedging. +- **Tone:** Use full sentences and retain articles (a/an/the). Be professional but extremely tight and direct. +- **Precision:** Keep technical terms exact, quote errors verbatim, and leave code blocks completely unchanged. +- **Document Boundaries:** Use this "lite" style for standard responses, plans, specs, and task breakdowns. Write completely normal, standard English for actual source code, commit messages, and Pull Requests. +- **Safety Overrides:** Revert to standard, clear English when issuing security warnings, confirming irreversible actions, or outlining critical multi-step sequences where brevity could risk a misunderstanding. + +**Example Pattern:** + +- *Instead of:* "Sure! I'd be happy to help. The issue you're experiencing is likely caused by the component creating a new object reference each render. You can fix this by wrapping it in `useMemo`." +- *Use:* "Your component re-renders because you create a new object reference each render. Wrap it in `useMemo`." + +## Core Mandate & Skills + +- **Horizontal Integration:** Focus on system-wide flow. Define explicit contracts between modules. Prove the system works beyond unit tests. +- **Strategic Decomposition:** Break vague goals into atomic, verifiable milestones. Own the integration outcome. +- **Proactive Context Gathering:** Do not ask the user for discoverable information. Use search and read tools to understand existing data loaders, models, config patterns, and project standards. +- **Fail Gracefully & Teach Debugging:** Explain how you found the bug, why it occurred, and how to diagnose similar issues. +- **Keep it Simple:** Favor simple, readable code over complex abstractions. Researchers must understand the code. +- **Intellectual Honesty:** Prioritize technical truth over agreement. Critically evaluate and challenge all requests, tasks, and assumptions. Propose superior alternatives with a clear explanation of technical trade-offs and rationale. + +## Operational Workflow + +- **Establish Baseline:** Identify the application's current state. +- **Focused Execution:** Prioritize short, high-intent sessions with narrow, actionable objectives. +- **Durable Artifacts (The Written Plan):** Create or update `_PLAN.md` in `docs/agents/planning//` before implementing non-trivial tasks. +- **Contract-First Design:** Define inputs/outputs and geospatial context (CRS, resolution) between pipeline stages BEFORE implementation. Enforce explicit data contracts (Pydantic Models, Dataclasses). +- **Atomic Versioning:** Use Git aggressively. Commit after every verified logical unit. +- **Incremental Review:** Implement ONE step from the plan at a time. Validate the code, then STOP and ask for user validation before proceeding. + +### Planning + +Read [docs/agents/instructions/planning.md](instructions/planning.md) before starting plans, specifications, or tasks. + +### Implementation + +Read [docs/agents/instructions/software_dev.md](instructions/software_dev.md) before starting plans, specifications, or tasks. + +### Reviewing + +Read [docs/agents/instructions/code_review.md](instructions/code_review.md) before starting plans, specifications, or tasks. + +## Engineering Preferences - **Python:** Strictly use `pathlib.Path`. Use `structlog` for JSON logging (never `print`). Prefer keyword arguments for complex function calls. - **Geospatial Data:** Always explicitly handle CRS (`rasterio.crs.CRS.from_epsg()`). Use windowed reading for rasters > 100MB. Output as Cloud Optimized GeoTIFF (COG), Parquet (Snappy/Zstd), or Zarr. - **Architecture:** Ensure ML/Data pipelines are idempotent. - **Documentation:** Use Google Style docstrings and the Diátaxis framework. -## 4. Domain-Specific Guidelines +## Domain-Specific Guidelines -To assist with specific domains, specialized instruction files are available in `docs/agents/instructions`. -**Mandate:** You MUST read and apply the relevant project-specific context file when working within these domains. These files outline architectural constraints, preferred tools, and forbidden patterns for this specific repository. +Read and apply the relevant project-specific context file for these domains. These files outline architectural constraints, preferred tools, and forbidden patterns. -| Domain | Project-Specific Context File | -| :---------------------- | :----------------------------------------------------------------------------------------- | -| **Orchestrator** | [**docs/agents/instructions/orchestrator.md**](instructions/orchestrator.md) | -| **Planning** | [**docs/agents/instructions/formal_planning.md**](instructions/formal_planning.md) | -| **Plan to tasks** | [**docs/agents/instructions/plan_to_tasks.md**](instructions/plan_to_tasks.md) | -| **ML / Geospatial** | [**docs/agents/instructions/ml.md**](instructions/ml.md) | -| **Python / QA** | [**docs/agents/instructions/python.md**](instructions/python.md) | -| **System Design** | [**docs/agents/instructions/systemdesign.md**](instructions/systemdesign.md) | -| **Infrastructure** | [**docs/agents/instructions/infrastructure.md**](instructions/infrastructure.md) | -| **Root Cause Analysis** | [**docs/agents/instructions/root_cause_analysis.md**](instructions/root_cause_analysis.md) | -| **Analytics** | [**docs/agents/instructions/analytics.md**](instructions/analytics.md) | -| **Security** | [**docs/agents/instructions/security.md**](instructions/security.md) | -| **Spec-Driven Dev** | [**docs/agents/instructions/specdrivendev.md**](instructions/specdrivendev.md) | -| **Knowledge Base** | [**docs/agents/instructions/KNOWLEDGE.md**](instructions/KNOWLEDGE.md) | +| Domain | Project-Specific Context File | +| :----------------------- | :----------------------------------------------------------------------------------------- | +| **Planning** | [**docs/agents/instructions/planning.md**](instructions/planning.md) | +| **Software Development** | [**docs/agents/instructions/software_dev.md**](instructions/software_dev.md) | +| **Root Cause Analysis** | [**docs/agents/instructions/root_cause_analysis.md**](instructions/root_cause_analysis.md) | +| **Review** | [**docs/agents/instructions/review.md**](instructions/code_review.md) | +| **Knowledge Base** | [**docs/agents/instructions/KNOWLEDGE.md**](instructions/KNOWLEDGE.md) | -## 4. Agent Behaviors, Memory & Tactics +## Agent Behaviors, Memory & Tactics -- **Aggressive Checkpointing:** You MUST checkpoint between phases. After research, write the findings to files. After planning, commit the contracts. You MUST NOT let implementation drift from the plan because it's all happening in one tool. -- **Git as Memory:** You MUST use git aggressively. Commit after each logical unit. You can run `git diff` and `git log` to orient yourself in future sessions. This is your substitute for cross-model handoff artifacts — you're handing off between sessions instead. -- **Tribal Knowledge:** Maintain and update `docs/agents/instructions/KNOWLEDGE.md` with non-obvious technical decisions, gotchas, and data quirks. This is your long-term memory. -- **Token Efficiency:** Do not read entire files if a search tool (e.g., `grep_search` / `grep` / `file_search`, `glob` / `find`) will suffice. +- **Aggressive Checkpointing:** Checkpoint between phases. Write findings to files after research. Commit contracts after planning. +- **Git as Memory:** Use git aggressively. Commit after each logical unit. +- **Tribal Knowledge:** Consult, maintain, and update `docs/agents/instructions/KNOWLEDGE.md`. +- **Token Efficiency:** Do not read entire files if search tools suffice. +- **Skill selection:** Select and use the appropriate specialized agent skill listed in 4. Domain-Specific Guidelines based on the task type. -## 5. Forbidden Patterns (The "Please Don't" List) +## Forbidden Patterns (The "Please Don't" List) -Avoid these anti-patterns strictly, even in a rapid research context: +Avoid these anti-patterns strictly: +- ❌ **Vertical Myopia:** Optimizing one file while breaking integration. - ❌ **Hardcoded Paths:** ALWAYS use `pathlib` and relative paths (or config files). -- ❌ **Hardcoded Secrets:** NEVER put API keys/passwords in code. Use `.env` or `config.yaml`. -- ❌ **Silent Failures:** NEVER use bare `except: pass` or `except Exception: pass`. All caught exceptions must be logged or handled specifically. -- ❌ **Global State:** DO NOT use global variables to pass data between functions. It destroys reproducibility and debuggability. -- ❌ **Mega-Functions:** Break down functions longer than ~50-100 lines to ensure testability and readability. -- ❌ **Production `print()`:** Use `structlog` or standard `logging` for application logs. `print()` is only for temporary debugging. +- ❌ **Plan Drift:** Changing architecture without updating `PLAN.md`. +- ❌ **Hardcoded Secrets:** NEVER put API keys/passwords in code. Use `.env`. +- ❌ **Silent Failures:** NEVER use bare `except: pass` or `except Exception: pass`. Log or handle all exceptions. +- ❌ **Global State:** DO NOT use global variables to pass data between functions. +- ❌ **Mega-Functions:** Break down functions longer than ~50-100 lines. +- ❌ **Production `print()`:** Use `structlog` or standard `logging`. +- ❌ **Implied Contracts:** MUST NOT pass raw, untyped dictionaries between components. +- ❌ **Skipping E2E Testing:** MUST NOT declare complex integration complete without verifying data flow end-to-end. diff --git a/docs/agents/instructions/KNOWLEDGE.md b/docs/agents/instructions/KNOWLEDGE.md index 7715f65..4d5a754 100644 --- a/docs/agents/instructions/KNOWLEDGE.md +++ b/docs/agents/instructions/KNOWLEDGE.md @@ -11,7 +11,7 @@ description: Project Knowledge Base - STAC API: `https://catalogue.dataspace.copernicus.eu/stac` - Auth: OIDC Bearer token required for asset downloads. - Collection IDs: `sentinel-2-l2a`, `sentinel-1-slc`, etc. - - Implementation: `src/geospatial_tools/copernicus.py` + - Implementation: `src/geospatial_tools/copernicus/auth.py` and `src/geospatial_tools/copernicus/constants.py` ## Known Issues & Fixes @@ -24,3 +24,29 @@ The project uses a makefile. Use 'make targets' to discover the targets. ## QA - Use 'make precommit', 'make pylint' and 'make test' to validate code. + +## Sentinel-1 (SAR) + +- **`sar:polarizations` query operator must be `eq` with an exact array match on Planetary Computer.** + The STAC API for Planetary Computer does NOT support the `contains` operator for arrays like `sar:polarizations` (it returns an Internal Server Error). You must use `eq` with the exact array (e.g., `{"sar:polarizations": {"eq": ["VV", "VH"]}}`). + +- **Asset keys and property values are different cases — never substitute one for the other.** + `PlanetaryComputerS1Band.VV == "vv"` (lowercase) is used as `item.assets["vv"]`. + `PlanetaryComputerS1Polarization.VV == "VV"` (uppercase) is used in STAC query property values. + Using the wrong one silently returns empty results or causes missing-asset errors. + +- **`abc.ABC` alone does NOT prevent direct instantiation — `@abstractmethod` is required.** + `AbstractSentinel1` (and `AbstractSentinel2`) must define at least one `@abstractmethod` (e.g. + `build_query()`) for `TypeError` to be raised on direct instantiation. An empty ABC subclass is + fully instantiable. + +- **Planetary Computer S1 collection names.** + Standard GRD: `sentinel-1-grd` (`PlanetaryComputerS1Collection.GRD`). + RTC (Radiometric Terrain Corrected): `sentinel-1-rtc` — separate collection, not covered by the + current S1 client. SLC is not available on Planetary Computer. + +## Sentinel-1 (SAR) +- **`sar:polarizations` query operator must be `contains`, not `eq`.** The STAC property is stored as a list (e.g., `["VV","VH"]`). The `eq` operator matches the whole list; `contains` matches a single element. Use `{"sar:polarizations": {"contains": "VV"}}`. +- **Asset keys vs. property values are different cases.** `PlanetaryComputerS1Band.VV == "vv"` (lowercase asset key used in `item.assets`). `PlanetaryComputerS1Polarization.VV == "VV"` (uppercase STAC property value used in queries). Using the wrong one silently returns empty results or missing assets. +- **`AbstractSentinel1` requires `@abstractmethod build_query()`** to enforce non-instantiability. `abc.ABC` alone without any abstract methods does NOT prevent direct instantiation. +- **S1 IW GRD on Planetary Computer uses collection `sentinel-1-grd`.** RTC variant is `sentinel-1-rtc` (separate collection, out of scope here). SLC is not available on PC. diff --git a/docs/agents/instructions/analytics.md b/docs/agents/instructions/analytics.md deleted file mode 100644 index 9e97cc4..0000000 --- a/docs/agents/instructions/analytics.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -name: analytics -description: Analytics Skill Instructions ---- -# Analytics Skill Instructions - -## Primary Directive -Your primary objective is to extract truth from experimental data without fooling yourself or others. -**MANDATE:** Apply the project-specific rules outlined below for all analytics and EDA tasks. - -## Context -In a geospatial research setting, data analysis must account for spatial dimensions, non-standard projections, and highly skewed physical measurements (e.g., radar reflectivity, atmospheric depth). - -## Standards -You MUST adhere to the following project-specific standards when performing or reviewing data analysis: - -### 1. Geospatial Exploratory Data Analysis (EDA) - -- **Tool Selection:** Use `geopandas` for vector data exploration, `xarray` for multidimensional raster data, and `leafmap` for interactive mapping within notebooks. -- **Profile First:** ALWAYS check for missing values (`NaN`), nodata values (which may be encoded as extreme values like `-9999`), and data types before doing any analysis. -- **Coordinate Reference Systems:** ALWAYS verify and harmonize the CRS of all datasets involved in a spatial analysis before calculating areas, distances, or intersections. - -### 2. Visualization Best Practices - -- **Spatial Context:** When plotting maps, ensure coastlines, borders, or a basemap are included to provide geographic context. -- **Visual Integrity:** Use perceptually uniform colormaps (e.g., `viridis`, `plasma`) for continuous geospatial data. Avoid rainbow colormaps (like `jet`) which create false boundaries. -- **Distribution Focus:** Do not just plot maps. MUST generate histograms/boxplots to understand the statistical distribution of the spatial phenomena. - -### 3. Notebook Hygiene - -- **Top-Down Execution:** Notebooks MUST NOT rely on hidden state. They must execute sequentially from top to bottom. -- **Narrative:** Use Markdown to explain the *why* and the *implications* of the result, especially noting any spatial anomalies. - -### 4. Statistical Rigor - -- **Assumptions:** ALWAYS verify statistical assumptions (e.g., Normality) before applying tests (e.g., T-Test). -- **Reporting:** Report effect sizes (e.g., Cohen's d) alongside p-values. Statistical significance != Practical significance. - - -## Forbidden Patterns - -- ❌ **Ignoring Nodata:** You MUST NOT silently calculate statistics over arrays containing raw nodata values (e.g., averaging `-9999` with valid data). Use `xarray.where()` or masked arrays. -- ❌ **"Magic" Outlier Removal:** You MUST NOT remove spatial data points just because they "look wrong" without explicit domain-specific justification. -- ❌ **Pie Charts & Dual Y-Axes:** Avoid these misleading visualization formats entirely. - diff --git a/docs/agents/instructions/code_review.md b/docs/agents/instructions/code_review.md new file mode 100644 index 0000000..c731f3b --- /dev/null +++ b/docs/agents/instructions/code_review.md @@ -0,0 +1,35 @@ +--- +name: review +description: Harsh Security & Architecture Review Protocol +--- +# Review Protocol: Security & Architecture + +## Primary Directive +**MANDATE:** Act as a cynical, senior architect. Tear apart implementation for security flaws, performance bottlenecks, and architectural rot. No sugar-coating. No empathy. Technical perfection only. + +## 1. Security & Data Privacy (Non-Negotiable) +Enforce absolute data safety. If these are violated, the code is trash. + +### Secret Management +- **Zero Hardcoding:** AWS, Copernicus, Planetary Computer tokens MUST be in `.env` or `configs/geospatial_tools_ini.yaml`. +- **Git Safety:** Verify `.gitignore` covers all config/env files. Commit only `.example` versions. + +### Data Safety +- **Path Traversal:** Use `pathlib.Path.resolve()`. No `../` in generated paths from external input. +- **No Deserialization Hacks:** Never use `pickle` or `numpy.load(allow_pickle=True)` on external data. +- **SSL Enforcement:** `verify=False` in `requests`/`aiohttp` is a failure. Never permit it. +- **Injection Prevention:** Use parameterized queries or ORMs. Construction of raw strings with input is forbidden. + +## 2. Bad-Mood Architectural Review +Code must be clean, performant, and maintainable. If it's messy, call it out. + +### Focus Areas +- **Coding Practices:** Strict SOLID and DRY. No magic numbers. No monolithic functions (>50 lines). Explicit typing (`numpy.typing`, `xarray.DataArray`) is mandatory. +- **Performance:** Big O analysis. Flag unnecessary allocations or blocking calls in async code. +- **Error Handling:** No bare `except: pass`. Errors must be handled specifically or logged with `structlog`. + +## 3. Review Execution +1. **Summary:** Start with a blunt assessment of quality. +2. **Findings:** Categorize by Severity (Security, Performance, Practices). +3. **Actionable Fixes:** Explain *why* it fails and demand the exact fix. +4. **No Fluff:** No pleasantries. No "Great job". End abruptly. diff --git a/docs/agents/instructions/formal_planning.md b/docs/agents/instructions/formal_planning.md deleted file mode 100644 index 3187b0a..0000000 --- a/docs/agents/instructions/formal_planning.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -name: formal_planning -description: Formal Planning Protocol ---- -# Formal Planning Protocol - -## Primary Directive -**MANDATE:** Ensure any generated plan adheres to the structure below. - -When the user explicitly asks for a "plan," "architecture," "design," or "proposal"—or when embarking on a multi-step/multi-domain implementation—you must use the **Formal Design Document** structure below, saving it to `docs/agents/planning/_PLAN.md`. - -## 1. Scope & Context - -*State briefly what you are solving and acknowledge any constraints. What are we doing right now?* - -## 2. Architectural Approach (Trade-offs & Strategy) - -*Explain the reasoning behind the proposed approach. Reference established principles (e.g., SOLID, Idempotency, Cloud-Optimized Geospatial Formats). Discuss trade-offs.* - -## 3. Verification & Failure Modes (FMEA) - -*How do we know this works, and how will it break? Outline the test strategy (pytest/nox) and known risks (potential bottlenecks, OOMs, or security considerations).* - -## 4. Granular Implementation Steps - -*Provide a structured, step-by-step list of the implementation process. Focus on one modular chunk at a time.* - -## 5. Next Step - -*End with a single, clear question asking for approval on Step 1 to maintain momentum.* diff --git a/docs/agents/instructions/infrastructure.md b/docs/agents/instructions/infrastructure.md deleted file mode 100644 index 5258124..0000000 --- a/docs/agents/instructions/infrastructure.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -name: infrastructure -description: Infrastructure Skill Instructions ---- -# Infrastructure Skill Instructions - -## Primary Directive -Your objective is to ensure that all research environments, compute jobs, and pipelines are reproducible, resilient, and explicitly defined as code. -**MANDATE:** Apply the project-specific rules outlined below for all infrastructure and environment tasks. - -## Context -This project uses modern Python packaging and infrastructure-as-code principles. - -## Standards -You MUST enforce the following project-specific infrastructure standards: - -### 1. Environment Management - -- **Explicit Definition:** Environments are defined centrally in `pyproject.toml` and locked using `uv` (`uv.lock`). ALWAYS use `uv` for dependency management tasks rather than raw `pip` or `conda` where possible. -- **Isolation:** ALWAYS run tasks within the appropriate `nox` session or `uv` virtual environment. - -### 2. Infrastructure as Code (IaC) - -- **Provisioning:** Prefer `Terraform` or `Pulumi` for defining cloud resources and infrastructure over manual provisioning or ad-hoc bash scripts. -- **Idempotency:** Setup, deployment, and data pipelines MUST be safe to run multiple times without causing errors or duplicate data. - -### 3. Containerization (Docker) - -- **Multi-Stage Builds:** When writing Dockerfiles, use multi-stage builds to keep final image sizes small and secure. -- **Least Privilege:** Containers MUST NOT run as the root user. Pinned, non-root base images are mandatory. - -### 4. HPC & Automation - -- **Explicit Resources:** If interacting with SLURM or cluster job scripts, ALWAYS request specific resources (`cpus-per-task`, memory, etc.). - - -## Forbidden Patterns - -- ❌ **"ClickOps":** You MUST NOT recommend setting up environments or servers manually via a GUI. -- ❌ **Untracked Environments:** Do not add dependencies without ensuring they are reflected in `pyproject.toml` and `uv.lock`. -- ❌ **Hardcoded Secrets:** You MUST NEVER include API keys or tokens in scripts, Makefiles, or Dockerfiles. - diff --git a/docs/agents/instructions/ml.md b/docs/agents/instructions/ml.md deleted file mode 100644 index c387703..0000000 --- a/docs/agents/instructions/ml.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -name: ml -description: Machine Learning & Geospatial Processing Instructions ---- -# Machine Learning & Geospatial Processing Instructions - -## Primary Directive -Your goal is to help build state-of-the-art models and data pipelines that are reproducible, reliable, and well-documented. -**MANDATE:** Apply the project-specific rules outlined below for all ML and geospatial processing tasks. - -## Context -This project deals heavily with geospatial datasets (Sentinel-2, Radar, etc.) which introduce unique memory and projection challenges compared to standard ML pipelines. - -## Standards -You MUST enforce the following project-specific standards: - -### 1. Geospatial Data Handling - -- **Explicit CRS:** Always explicitly handle Coordinate Reference Systems (`rasterio.crs.CRS.from_epsg()`). Do not assume unprojected data is WGS84 without verification. -- **Memory Management:** For large datasets (e.g., geospatial rasters > 100MB), you MUST use windowed reading (via `rasterio` windows) or lazy evaluation (via `dask` and `xarray`) to prevent Out-Of-Memory (OOM) errors. -- **Modern Libraries:** Utilize `xarray`, `rioxarray`, and `geopandas` for multidimensional and vector operations. -- **Output Formats:** Default to writing outputs as Cloud Optimized GeoTIFFs (COG), Parquet (Snappy/Zstd compressed), or Zarr archives for optimal cloud-native read access. - -### 2. Model Training & Evaluation - -- **Deterministic Execution:** ALWAYS set random seeds globally to ensure reproducibility across experimental runs. - -- **Strict Isolation:** NEVER leak spatial information between train, validation, and test sets. Ensure spatial cross-validation is used (e.g., splitting by geographic regions) rather than random pixel splitting, to avoid spatial autocorrelation leakage. - -- **Config-Driven:** Hyperparameters and dataset paths MUST be externalized to configuration files and loaded via Pydantic models. - - - -## Forbidden Patterns - -- ❌ **Silent OOMs:** You MUST NOT write data loaders that attempt to load massive raster datasets entirely into RAM. -- ❌ **Ignoring CRS:** You MUST NEVER perform spatial joins or distance calculations without first asserting both datasets share the exact same CRS. -- ❌ **Fitting on Test Data:** You MUST NEVER allow data transformations to be fitted on the validation or test sets. - diff --git a/docs/agents/instructions/orchestrator.md b/docs/agents/instructions/orchestrator.md deleted file mode 100644 index 61a67ca..0000000 --- a/docs/agents/instructions/orchestrator.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -name: orchestrator -description: Orchestrator Skill Instructions ---- -# Orchestrator Skill Instructions - -## Primary Directive -Your primary responsibility is the horizontal integration of all research components. -**MANDATE:** Apply the project-specific rules outlined below for all orchestration and integration tasks. - -## Context -In this repository, successful orchestration means tying together raw geospatial data fetching (STAC/Copernicus), pre-processing (Rasterio/Xarray), and output generation (COGs/Zarr). - -## Workflow -For any task requiring more than a minor fix, you MUST enforce the following framework: - -### 1. The Written Plan (Mandatory) - -Before writing implementation code, you MUST create or update a `_PLAN.md` in `docs/agents/planning/` (or use the built-in planning tools like `enter_plan_mode` for Gemini or equivalent planning modes for Claude/Codex). - -### 2. Contract Management - -- **Define Boundaries:** Explicitly define the inputs and outputs between pipeline stages BEFORE either stage is implemented. -- **Geospatial Contracts:** When integrating geospatial modules, the contract MUST include the expected CRS and resolution. - -### 3. Granular Execution - -- Implement exactly ONE step from the plan at a time. -- After completing a step, you MUST STOP and ask the user to validate the output before moving to the next step. - - -## Forbidden Patterns - -- ❌ **Vertical Myopia:** You MUST NOT focus entirely on optimizing one specific file while ignoring how it breaks integration with the rest of the project (e.g., changing a config structure without updating `geospatial_tools_ini.yaml.example`). -- ❌ **Implied Contracts:** You MUST NOT build components that pass raw, untyped dictionaries to each other. Always enforce explicit data contracts (e.g., Pydantic Models, Dataclasses). -- ❌ **Skipping E2E Testing:** You MUST NOT declare a complex integration "complete" without verifying that the data flows from start to finish via `nox` testing sessions or test notebooks. - diff --git a/docs/agents/instructions/plan_to_tasks.md b/docs/agents/instructions/plan_to_tasks.md deleted file mode 100644 index 7264ac8..0000000 --- a/docs/agents/instructions/plan_to_tasks.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -name: plan_to_tasks -description: Plan To Tasks ---- -# Plan To Tasks - -## Primary Directive -**MANDATE:** Decompose a plan into modular, atomic tasks, each documented in its own file (or a structured document) with all the context needed for implementation and verification. - -## Core Workflow - -1. **Analyze the Plan**: Review the existing implementation plan (e.g., `PLAN.md` or `SPEC.md`) or a high-level request. -2. **Identify Boundaries**: Break the plan into modular, atomic tasks based on logical boundaries (modules, features, or architectural layers). -3. **Generate Task Documents**: For each task, create a file using the task structure below. -4. **Enforce Quality Standards**: Integrate principles from `orchestrator`, `spec-driven-development`, `systemdesign`, and `formal-planning` into each task. - -## Task Structure Requirements - -Every task document MUST include: - -- **Goal**: A clear, outcome-oriented objective. -- **Context & References**: Links to relevant documentation, specs, and existing code. -- **Subtasks**: Granular, atomic steps for implementation. -- **Requirements & Constraints**: Specific technical or business rules to follow. -- **Acceptance Criteria (AC)**: Measurable pass/fail states that define "done". -- **Testing & Validation**: Concrete commands and steps to verify the implementation. -- **Completion Protocol**: Mandatory steps to verify ACs, run tests, commit work to git, and update the task document. - -## Implementation Principles - -- **Vertical Slices (TDD/Tracer Bullets)**: Prefer tasks that deliver a full slice of functionality (One test → One implementation) over horizontal technical layers. -- **Contract-First (Orchestrator)**: Define interfaces and shared protocols before starting implementation subtasks. -- **Outcome-Orientation (Formal Planning)**: Every subtask must be tied to a verifiable outcome. -- **Fail Fast (QA)**: Include specific test commands that provide immediate feedback. -- **Evolvability (System Design)**: Ensure tasks are decoupled and follow SOLID principles. - -## Next Steps - -- Use the Task Structure Requirements to bootstrap each new task. diff --git a/docs/agents/instructions/planning.md b/docs/agents/instructions/planning.md new file mode 100644 index 0000000..722524d --- /dev/null +++ b/docs/agents/instructions/planning.md @@ -0,0 +1,50 @@ +--- +name: planning +description: Combined Planning, Specification, and Task Decomposition Protocol +--- +# Planning, Spec & Task Decomposition Protocol + +## Primary Directive +**MANDATE:** Follow this protocol for any multi-step implementation, architectural change, or high-level request. Ensure every plan is specified and decomposed into modular, atomic, and verifiable tasks. + +## Phase 1: Formal Design +When embarking on a multi-step implementation, create a **Formal Design Document** at `docs/agents/planning/_PLAN.md`. + +### Structure: +1. **Scope & Context**: Briefly state problem and constraints. +2. **Architectural Approach**: Explain reasoning, trade-offs, and principles (SOLID, Idempotency, Cloud-Optimized formats). +3. **Verification & Failure Modes (FMEA)**: Outline test strategy (pytest/nox) and known risks (bottlenecks, OOM, security). +4. **Granular Implementation Steps**: Structured, step-by-step list of the process. +5. **Next Step**: Single question for approval on Step 1. + +## Phase 2: Technical Specification (SDD) +Before creating tasks or writing logic, define the technical contract. Create `docs/agents/planning/_SPEC.md`. + +### Workflow: +1. **Define Nouns (Dataclasses)**: Use `dataclasses` or Pydantic. Geospatial structures MUST contain metadata (CRS, Affine transform). +2. **Write Contract**: Function signatures with strict type hints (`numpy.typing`, `xarray.DataArray`). Google Style docstrings for inputs, outputs, and spatial projections/shapes. +3. **Stub & Validate**: Use `raise NotImplementedError()`. Present stubs for validation BEFORE implementation logic. + +### SDD Forbidden Patterns: +- ❌ **`Any` Escape Hatch**: Use specific types (e.g., `xarray.Dataset`, `geopandas.GeoDataFrame`). +- ❌ **Logic Before Contract**: Signature and docstring first. + +## Phase 3: Plan to Tasks +Decompose the approved plan and spec into modular, atomic tasks in `docs/agents/planning//tasks/`. + +### Task Structure Requirements: +Every task document MUST include: +- **Goal**: Clear, outcome-oriented objective. +- **Context & References**: Links to docs, specs, and existing code. +- **Subtasks**: Granular, atomic implementation steps. +- **Requirements & Constraints**: Technical or business rules. +- **Acceptance Criteria (AC)**: Measurable pass/fail states. +- **Testing & Validation**: Commands and steps to verify implementation. +- **Completion Protocol**: Mandatory steps: verify ACs, run tests, commit work, update task doc. + +## Implementation Principles +- **Vertical Slices (TDD)**: Deliver full slices (One test → One implementation). +- **Contract-First**: Define interfaces/protocols (Phase 2) before implementation. +- **Outcome-Orientation**: Every subtask must be tied to a verifiable outcome. +- **Fail Fast**: Include specific test commands for immediate feedback. +- **Evolvability**: Ensure tasks are decoupled and follow SOLID. diff --git a/docs/agents/instructions/python.md b/docs/agents/instructions/python.md deleted file mode 100644 index c48de72..0000000 --- a/docs/agents/instructions/python.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: python -description: Python & QA Skill Instructions ---- -# Python & QA Skill Instructions - -## Primary Directive -Your objective is to elevate research scripts into robust, maintainable, and type-safe software. -**MANDATE:** Apply the project-specific rules outlined below for all Python development and QA tasks. - -## Context -This project relies heavily on modern Python tooling and strictly enforced quality assurance. -- **Pre-commit is Central:** All QA tasks (linting, formatting, type checking) are orchestrated via `pre-commit`. -- **Environment & Build:** We use `uv` for package management and `hatchling` as the build backend (defined in `pyproject.toml`). -- **Task Automation:** We use `nox` for isolated test environments and task execution. -- **Makefile:** We use a makefile to automate and orchestrate most things in this project. Use `make targets` to discover the available targets. - -## Standards -You MUST strictly adhere to the following project-specific Python standards: - -### 1. QA & Tooling - -- **QA Workflow:** ALWAYS run `make precommit` after making changes. Do not manually invoke linters unless debugging a specific `pre-commit` hook failure. -- **Tests:** Use `make test` to run tests. -- **Type Checking:** We use `mypy`. All new functions MUST have strict type hints. - -### 2. Modern Project Standards - -- **Strict Typing:** You MUST use type hints for ALL function arguments and return values (e.g., `def process(data: str | Any) -> pd.DataFrame`). -- **Filesystem Paths:** You MUST NEVER use `os.path`. ALWAYS use `pathlib.Path` for all file and directory manipulations. -- **Logging:** Use `structlog` for application flow. NEVER use `print()` for production code. -- **Function Calls:** Prefer keyword arguments for complex function calls to enhance readability and maintainability. -- **Data Structures:** ALWAYS use `@dataclass` or `pydantic` models for complex structures instead of untyped dictionaries. -- **Type Hints Format:** Always prefer X | Y format over Union[X, Y]. -- **Docstrings:** Always add docstrings to your functions and classes. Use the Google standard for docstrings and follow the Diátaxis framework for documentation structure. Don't show types in docstrings. - -### 3. Testing & Performance - -- **Vectorization:** ALWAYS prefer vectorized operations (NumPy, Pandas, Polars, Xarray) over native Python `for` loops when processing geospatial data. - - -## Forbidden Patterns - -- ❌ **Bypassing Pre-commit:** Do not commit code that fails `pre-commit` checks. Fix the underlying linting or typing issue. -- ❌ **Global Mutable State:** You MUST NEVER define or mutate global variables to pass state between functions. -- ❌ **Magic Numbers/Strings:** You MUST NOT hardcode numeric constants. Extract them to Pydantic settings or config classes. -- ❌ **Bare Except Blocks:** You MUST NEVER use `except: pass` or `except Exception: pass`. - diff --git a/docs/agents/instructions/security.md b/docs/agents/instructions/security.md deleted file mode 100644 index 75c73b7..0000000 --- a/docs/agents/instructions/security.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -name: security -description: Security Skill Instructions ---- -# Security Skill Instructions - -## Primary Directive -Your primary objective is to identify vulnerabilities, enforce defense-in-depth, and ensure absolute data privacy. -**MANDATE:** Apply the project-specific rules outlined below for all tasks involving security, authentication, or data privacy. - -## Context -Geospatial research often involves massive downloads from third-party catalogs (STAC, Copernicus) requiring authentication tokens. Exposing these tokens compromises the lab's infrastructure limits. - -## Standards -You MUST actively enforce the following project-specific security standards: - -### 1. Secret Management - -- **Token Protection:** Copernicus, Planetary Computer, and AWS tokens MUST NEVER be hardcoded. They must be loaded via `.env` files, environment variables, or centralized configuration (`configs/geospatial_tools_ini.yaml`). -- **File Exclusions:** Ensure `configs/geospatial_tools_ini.yaml` and `.env` remain in `.gitignore`. Only commit `.example` versions. - -### 2. Data Safety - -- **Path Traversal:** When dynamically generating file paths based on STAC item IDs or user input, use `pathlib.Path.resolve()` to ensure paths do not traverse outside the intended output directory (`../`). -- **Deserialization:** Do not use `pickle` or `numpy.load(allow_pickle=True)` for data acquired from external STAC catalogs. - - -## Forbidden Patterns - -- ❌ **Committing Secrets:** You MUST NEVER allow code containing hardcoded credentials or API tokens to be committed. -- ❌ **Disabling SSL Verification:** You MUST NEVER permit `verify=False` in `requests` or `aiohttp` calls to STAC catalogs or data endpoints. -- ❌ **Raw SQL:** Always use ORMs or parameterized queries to prevent SQL injection. You MUST NEVER construct raw SQL strings with user input. - diff --git a/docs/agents/instructions/software_dev.md b/docs/agents/instructions/software_dev.md new file mode 100644 index 0000000..025336d --- /dev/null +++ b/docs/agents/instructions/software_dev.md @@ -0,0 +1,52 @@ +--- +name: software-dev +description: Unified Software Development, ML, Analytics & Infrastructure Protocol +--- +# Software Development Protocol + +## Primary Directive +**MANDATE:** Elevate research into robust, maintainable, and type-safe systems. Apply these standards to all Python development, system design, ML/geospatial processing, analytics, and infrastructure tasks. + +## 1. Python & QA Standards +- **Strict Typing:** ALL function arguments and return values MUST have type hints. Use `X | Y` format. +- **Paths:** ALWAYS use `pathlib.Path`. Never `os.path`. +- **Logging:** Use `structlog`. NEVER `print()`. +- **Data Structures:** Use `@dataclass` or `Pydantic`. No untyped dictionaries for complex state. +- **Documentation:** Google Style docstrings. Follow Diátaxis framework. No types in docstrings (use hints). +- **Automation:** Orchestrate via `Makefile`. + - Use `make targets` to discover available targets. + - Use `make info` for project environment and configuration info. + - Use `make precommit` and `make test`. +- **Existing project knowledge:** Consult [docs/agents/instructions/KNOWLEDGE.md](KNOWLEDGE.md). Extend when necessary. +- **Finding and fixing bugs:** Use [docs/agents/instructions/root_cause_analysis.md](root_cause_analysis.md) instructions. + +## 2. System Design & Architecture +- **Separation of Concerns:** Isolate data acquisition (STAC/S3) from processing logic. Avoid "God Objects". +- **Config-First:** Centralize all parameters in `configs/geospatial_tools_ini.yaml` (parsed via Pydantic). +- **Idempotency:** Design pipelines to be resumeable and safe to run multiple times. + +## 3. ML & Geospatial Processing + +- **Explicit CRS:** Always handle Coordinate Reference Systems ( + `rasterio.crs.CRS.from_epsg()`). Assert CRS matches before joins/calculations. +- **Memory Management:** Use windowed reading (`rasterio`) or lazy evaluation (`dask`/`xarray`) for rasters > 100MB. +- **Reproducibility:** Set global random seeds. Use geographic region splitting for spatial cross-validation to avoid autocorrelation leakage. +- **Output Formats:** Default to COG, Parquet (Snappy/Zstd), or Zarr. + +## 4. Analytics & Visualization +- **EDA Workflow:** Profile for `NaN`/nodata first. Harmonize CRS before spatial analysis. +- **Visual Integrity:** Use perceptually uniform colormaps (`viridis`, `plasma`). No rainbow maps or pie charts. Provide geographic context (basemaps/borders). +- **Notebook Hygiene:** Ensure top-down sequential execution. No hidden state. + +## 5. Infrastructure & Environment +- **Dependency Management:** Use `uv` and `uv.lock`. Run tasks in `nox` or `uv` environments. +- **IaC & Containers:** Prefer `Terraform`/`Pulumi`. Use multi-stage Docker builds. Containers MUST NOT run as root. +- **HPC:** Explicitly request SLURM resources (CPUs, memory). + +## Consolidated Forbidden Patterns +- ❌ **Secrets:** No hardcoded tokens/keys in code, scripts, or Dockerfiles. +- ❌ **QA Bypass:** No committing code that fails `pre-commit`. No manual dependency additions. +- ❌ **Silent Failures:** No bare `except: pass`. No silent OOMs or nodata averaging. +- ❌ **Global/Magic State:** No global mutable variables. No magic numbers/strings (use configs). +- ❌ **Inefficient Ops:** No Python loops for array processing (use vectorization). No loading massive rasters into RAM. +- ❌ **Analytical Bias:** No fitting on test data. No "magic" outlier removal. No misleading visualizations. diff --git a/docs/agents/instructions/specdrivendev.md b/docs/agents/instructions/specdrivendev.md deleted file mode 100644 index a78d655..0000000 --- a/docs/agents/instructions/specdrivendev.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: specdrivendev -description: Skill: Lightweight Spec-Driven Development (SDD) ---- -# Skill: Lightweight Spec-Driven Development (SDD) - -## Primary Directive -You are an **Educational Architect** teaching a researcher how to use a lightweight version of Spec-Driven Development (SDD). -**MANDATE:** Apply the project-specific rules outlined below for defining new features or interfaces. - -## Context -In geospatial research, jumping straight into implementation often leads to messy code, unclear boundaries (e.g., passing untyped numpy arrays without CRS metadata), and debugging nightmares. -By defining the "Specification" or "Contract" first we force the researcher to think precisely about inputs, spatial bounds, shapes, and edge cases. - -## Workflow -When starting a new feature, you MUST guide the researcher through these steps: - -### Step 1: Define the Nouns (Dataclasses) - -- Avoid raw dictionaries. Use `dataclasses` (or Pydantic models). -- **Geospatial Context:** Ensure structures that hold arrays (like a `SatelliteTile`) also contain metadata (CRS, Affine transform). - -### Step 2: Write the Contract (Signature & Docstring) - -- Write the function definition with strict type hints (`numpy.typing`, `xarray.DataArray`). -- The docstring (Google Style) MUST explicitly state exact inputs, outputs, side-effects, and expected projection/shapes. - -### Step 3: Stub It Out & Validate - -- Use `raise NotImplementedError()` for the function body. -- **STOP.** Present the stub to the researcher and ask for validation BEFORE generating the logic. - - -## Forbidden Patterns - -- ❌ **The `Any` Escape Hatch:** You MUST NOT use `Any` in type hints unless absolutely unavoidable. Use `xarray.Dataset` or `geopandas.GeoDataFrame` specifically. -- ❌ **Logic Before Contract:** You MUST NOT write the function logic before the signature and docstring are established. - diff --git a/docs/agents/instructions/systemdesign.md b/docs/agents/instructions/systemdesign.md deleted file mode 100644 index 9f6df5a..0000000 --- a/docs/agents/instructions/systemdesign.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: systemdesign -description: System Design & Architecture Skill Instructions ---- -# System Design & Architecture Skill Instructions - -## Primary Directive -Your objective is to design systems that are maintainable, evolvable, and robust. -**MANDATE:** Apply the project-specific rules outlined below for all system design and architectural tasks. - -## Context -Geospatial research codebases quickly become tangled if data fetching (STAC), processing (Rasterio), and analysis (Xarray) are all handled in the same script. - -## Standards -You MUST enforce the following project-specific architectural patterns: - -### 1. Configuration-First Design - -- ALL hyperparameters, file paths, auth mechanisms, and STAC catalog endpoints MUST be centralized in a configuration object (e.g., `configs/geospatial_tools_ini.yaml` parsed via Pydantic). Never bury them in processing scripts. - -### 2. Separation of Concerns - -- **Data Acquisition:** Modules fetching from Planetary Computer or Copernicus must be isolated from the logic that processes the bytes. -- **Processing:** Heavy geospatial processing must rely on clean, injected inputs (e.g., passing a local `pathlib.Path` rather than an S3 URL directly to a processing function, if intermediate storage is preferred). - -### 3. Error Handling & Idempotency - -- Design pipelines to resume gracefully. If a 100-tile download fails at tile 99, the pipeline must be able to restart and only fetch the missing tile. - - -## Forbidden Patterns - -- ❌ **God Objects:** You MUST NOT design classes that handle STAC querying, raster clipping, and matplotlib plotting simultaneously. -- ❌ **Hardcoded Configurations:** You MUST NEVER bury STAC endpoints, chunk sizes, or file paths inside logic files. - diff --git a/docs/agents/planning/_completed/add-pc-s1/add-pc-s1-spec.md b/docs/agents/planning/_completed/add-pc-s1/add-pc-s1-spec.md new file mode 100644 index 0000000..f01e667 --- /dev/null +++ b/docs/agents/planning/_completed/add-pc-s1/add-pc-s1-spec.md @@ -0,0 +1,87 @@ +# SPEC: Planetary Computer Sentinel-1 GRD Support + +## 1. Overview + +- **Goal**: Add a `StacSearch`-wrapper class for Sentinel-1 (S1) GRD that builds a SAR query via a builder pattern, executes the search, and downloads assets. +- **Problem Statement**: PC STAC client missing S1 GRD. SAR ignores clouds; it requires polarization / instrument-mode / orbit-state filtering, and has a strict uppercase-property vs. lowercase-asset-key split. +- **Design intent (scope lock)**: A thin, synchronous utility wrapper. Employs a builder pattern for querying (e.g., `.filter_by_instrument_mode()`) allowing fluent and programmatically defined search parameters. The STAC query is derived dynamically from the instance's state rather than an opaque query builder function. **Does not** replicate `BestProductsForFeatures`' tile-coverage workflow, multi-date-range iteration, or standalone module-level search functions. + +## 2. Requirements + +### Functional Requirements + +- [x] Add `PlanetaryComputerS1Collection` (`sentinel-1-grd`) to `constants.py`. +- [x] Add `PlanetaryComputerS1Property` (`sar:instrument_mode`, `sar:polarizations`, `sat:orbit_state`) to `constants.py`. +- [x] Add `PlanetaryComputerS1Band` (`vv`, `vh` — lowercase) to `constants.py`. +- [x] Add `PlanetaryComputerS1InstrumentMode` (`IW`, `EW`, `SM`, `WV`) to `constants.py`. +- [x] Add `PlanetaryComputerS1Polarization` (`VV`, `VH`, `HH`, `HV` — uppercase) to `constants.py`. +- [x] Add `PlanetaryComputerS1OrbitState` (`ascending`, `descending` — lowercase) to `constants.py`. +- [x] Create `AbstractSentinel1` in `sentinel_1.py`. Cannot be instantiated directly. +- [x] `AbstractSentinel1.__init__` stores spatial kwargs (`bbox`, `intersects`) + a single pystac-native `date_range: DateLike` as instance attributes. Initializes SAR properties (`instrument_modes`, `polarizations`, `orbit_states`) to `None` and `custom_query_params` to `{}`. Instantiates an internal `StacSearch(PLANETARY_COMPUTER)` as `self.client`. +- [x] `AbstractSentinel1` exposes builder methods that return `self` to allow chaining: + - `filter_by_instrument_mode(modes: list[PlanetaryComputerS1InstrumentMode] | PlanetaryComputerS1InstrumentMode)` + - `filter_by_polarization(polarizations: list[PlanetaryComputerS1Polarization] | PlanetaryComputerS1Polarization)` + - `filter_by_orbit_state(states: list[PlanetaryComputerS1OrbitState] | PlanetaryComputerS1OrbitState)` + - `with_custom_query(query_params: dict[str, Any])` +- [x] `AbstractSentinel1` exposes `search_results: list[pystac.Item] | None` and `downloaded_assets: list[Asset] | None` state attributes, initialized to `None`. +- [x] Create `Sentinel1Search(AbstractSentinel1)` implementing `search()`, and `download()`. +- [x] `Sentinel1Search.search()` dynamically constructs the STAC `query` dictionary based on the current instance state (`instrument_modes`, `polarizations`, `orbit_states`, `custom_query_params`). Calls `self.client.search(...)` with the built query and stored kwargs, stores the result on `self.search_results`, and returns it. +- [x] `Sentinel1Search.download(bands, base_directory)` calls `self.client.download_search_results(...)`; triggers `self.search()` first if `search_results is None`; stores the result on `self.downloaded_assets`. + +### Non-Functional Requirements + +- **Consistency**: Domain logic is SAR-specific but uses a fluent builder pattern. +- **Type Safety**: `StrEnum` for all domain constants. No magic strings. Spatial kwargs typed as `geotools_types.BBoxLike` / `geotools_types.IntersectsLike` to match `StacSearch.search()`. +- **Simplicity**: One class, fluent builder methods, `search()`, and `download()`. No module-level search functions. No multi-range loops. + +## 3. Technical Constraints & Assumptions + +- **Architecture Decision**: `Sentinel1Search` *is* the wrapper. All STAC interaction lives on the class (composition: `self.client = StacSearch(PLANETARY_COMPUTER)`). The STAC query is represented by the class instance's state and is only serialized into a STAC query dictionary at the moment `search()` is called. +- **Builder Pattern**: Replaces a single `build_query` function. This allows users to chain methods like `.filter_by_polarization([...]).filter_by_orbit_state(...)`. It also accommodates multiple properties at once (e.g., searching for both 'ascending' and 'descending' orbit states). `with_custom_query` provides a fallback for uncovered properties. +- **Date Range**: Single `date_range: DateLike` field, delegated unmodified to `StacSearch.search()`. pystac accepts either a single datetime or a `"start/end"` string — that covers the common case. +- **`sar:polarizations` Query Operator**: `sar:polarizations` is a list property in the STAC item. The builder method accepts a list. The `search()` method translates this into the appropriate STAC query syntax. If the STAC query extension is limited (e.g., only supporting a single `contains`), `search()` will apply the first polarization and document that post-filtering might be required. +- **Casing Invariant**: STAC property values for `sar:polarizations` are uppercase (`VV`, `VH`). PC asset keys are lowercase (`vv`, `vh`). These are distinct enums (`PlanetaryComputerS1Polarization` vs. `PlanetaryComputerS1Band`) and must never be conflated. Captured in `KNOWLEDGE.md`. +- **`sar:product_type`**: Out of scope. GRDH / GRDM / GRDF variants documented in `KNOWLEDGE.md` but not filtered. +- **Single-pol items**: Some GRD products lack `vh`. `Sentinel1Search.download()` delegates to `StacSearch.download_search_results()` → `_download_assets()`, which already skips absent asset keys with a log line. No extra handling needed. + +## 4. Acceptance Criteria + +- [x] SAR constants in `constants.py` are correct (case-distinct `vv`/`vh` vs `VV`/`VH`; three value enums present). +- [x] `sentinel_1.py` exists with `AbstractSentinel1` and `Sentinel1Search`. +- [x] `AbstractSentinel1` stores `bbox`, `intersects`, `date_range`, `collection`, `instrument_modes`, `polarizations`, `orbit_states`, `custom_query_params`, `self.client`, `self.search_results`, `self.downloaded_assets`. +- [x] Builder methods (`filter_by_*` and `with_custom_query`) correctly update instance state and return `self`. +- [x] `Sentinel1Search.search()` dynamically constructs the query dict from the instance's state (using `in` for multiple values where appropriate, and merging with `custom_query_params`), calls `self.client.search(...)`, and stores `self.search_results`. +- [x] `Sentinel1Search.download(bands, base_directory)` calls `self.client.download_search_results(...)`, triggers `search()` if needed, and stores `self.downloaded_assets`. +- [x] Unit and integration tests pass. + +## 5. Dependencies + +- Planetary Computer STAC API. +- `geospatial_tools.stac.core.StacSearch`, `Asset`, `PLANETARY_COMPUTER`. +- `geospatial_tools.geotools_types.BBoxLike`, `IntersectsLike`, `DateLike`. + +## 6. Out of Scope + +- `sar:product_type` sub-variants (GRDH/GRDM/GRDF). +- Sentinel-1 RTC collection (`sentinel-1-rtc`). +- SLC data. +- S1 on Copernicus catalog. +- Multi-date-range iteration (callers loop externally if needed). +- Any tile-coverage / best-product selection workflow. +- Post-download raster merging / reprojection orchestration (already available via `Asset` methods; not wrapped here). + +## 7. Verification Plan + +- **Unit Testing** (in `tests/test_planetary_computer_sentinel1.py`): + - `AbstractSentinel1` direct instantiation is prevented. + - Builder methods (`filter_by_instrument_mode`, `filter_by_polarization`, `filter_by_orbit_state`, `with_custom_query`) correctly update instance state and return `self`. + - `Sentinel1Search.search()` correctly translates instance state into a STAC query dict: + - Lists of values generate `in` operators (for scalar properties) or appropriate `contains` operators. + - Merges with `custom_query_params`. + - `Sentinel1Search.search()` calls `self.client.search` with the built query and stored spatial/date kwargs (mock `StacSearch`). `self.search_results` is populated. + - `Sentinel1Search.download(bands, base_directory)` triggers `search()` when `search_results is None`; when already populated, calls `download_search_results` directly (mock `StacSearch`). `self.downloaded_assets` is populated. +- **Integration Testing**: + - `@pytest.mark.integration` marker; skippable via `pytest -m "not integration"`. + - Instantiate `Sentinel1Search` with pinned `bbox=(-74.0, 45.4, -73.5, 45.7)` (Montreal), pinned `date_range="2023-01-01/2023-01-31"`. + - Chain builder methods: `.filter_by_instrument_mode(PlanetaryComputerS1InstrumentMode.IW).filter_by_polarization([PlanetaryComputerS1Polarization.VV, PlanetaryComputerS1Polarization.VH])`. + - Call `.search()`; assert results non-empty and every item has `properties["sar:instrument_mode"] == "IW"` and `"VV"` in `properties["sar:polarizations"]`. diff --git a/docs/agents/planning/_completed/add-pc-s1/add-pc-s1.md b/docs/agents/planning/_completed/add-pc-s1/add-pc-s1.md new file mode 100644 index 0000000..9c2f01f --- /dev/null +++ b/docs/agents/planning/_completed/add-pc-s1/add-pc-s1.md @@ -0,0 +1,51 @@ +# 1. 🎯 Scope & Context + +Sentinel-1 is SAR (active microwave). Cloud cover and optical-nodata semantics do not apply. Filtering dimensions are polarization, instrument mode, and orbit state. We are adding this data source to the Planetary Computer STAC client as a thin, synchronous utility wrapper. We will use a fluent builder pattern to define search parameters, moving away from a single opaque query generation function. + +# 2. 🏗️ Architectural Approach + +Create `AbstractSentinel1` and `Sentinel1Search` in `src/geospatial_tools/stac/planetary_computer/sentinel_1.py`. + +`Sentinel1Search` **is** the wrapper: it owns a `StacSearch(PLANETARY_COMPUTER)` instance via composition. The STAC query is represented by the class instance's state. + +Instead of a `build_query` method, `AbstractSentinel1` provides fluent builder methods: + +- `filter_by_instrument_mode()` +- `filter_by_polarization()` +- `filter_by_orbit_state()` +- `with_custom_query()` + +These methods update the instance state (`self.instrument_modes`, `self.polarizations`, etc.) and return `self` to allow chaining. The `search()` method dynamically constructs the final STAC `query` dictionary from these named attributes at execution time. This allows searching for multiple properties at once (e.g., multiple orbit states using the `in` operator) while retaining the flexibility of custom queries. + +All six SAR `StrEnum` types live in `constants.py`: `PlanetaryComputerS1Collection`, `PlanetaryComputerS1Property`, `PlanetaryComputerS1Band`, `PlanetaryComputerS1InstrumentMode`, `PlanetaryComputerS1Polarization`, `PlanetaryComputerS1OrbitState`. + +# 3. 🛡️ Verification & FMEA + +**Verification:** + +- Unit tests for all S1 constants. +- Unit tests validating that the builder methods update internal state and return `self`. +- Unit tests verifying that `Sentinel1Search.search()` correctly translates internal state arrays into STAC query dictionaries (e.g., using `in` for lists). +- Integration test for PC STAC S1 GRD products (`@pytest.mark.integration`, pinned AOI `bbox=(-74.0, 45.4, -73.5, 45.7)` (Montreal), pinned date range `"2023-01-01/2023-01-31"`, utilizing the builder methods). + +**Failure Modes:** + +- STAC API failure — handled by `StacSearch` retry loop. +- Polarization mismatch — STAC `query` extension handles arrays. `search()` must construct valid STAC syntax for multiple polarizations. If limitations exist in the PC STAC API, they will be handled and documented gracefully. +- Single-pol product missing `vh` asset during download — `StacSearch._download_assets` already logs-and-skips absent keys. No new handling needed. +- Invalid CRS — handled upstream in `geospatial_tools`. + +# 4. 📝 Implementation Steps + +1. **[COMPLETE]** Add all six SAR enum types to `src/geospatial_tools/stac/planetary_computer/constants.py`. + *Commit: `feat(stac-pc): add S1 constants`* +2. Create `src/geospatial_tools/stac/planetary_computer/sentinel_1.py` and implement `AbstractSentinel1` with spatial kwargs (`bbox: BBoxLike`, `intersects: IntersectsLike`), single `date_range: DateLike`, `self.client`, `self.search_results`, `self.downloaded_assets`. Implement the fluent builder methods (`filter_by_*` and `with_custom_query`) to manage instance state. + *Commit: `feat(stac-pc): implement AbstractSentinel1 base class with builder pattern`* +3. Implement `Sentinel1Search(AbstractSentinel1)` with two main methods: `search()` (dynamically builds the STAC query dict from instance state and wraps `self.client.search`), and `download(bands, base_directory)` (wraps `self.client.download_search_results`, triggers `search()` if needed). + *Commit: `feat(stac-pc): implement Sentinel1Search wrapper and search execution`* +4. **[COMPLETE]** Create unit + integration tests in `tests/test_planetary_computer_sentinel1.py`. + *Commit: `test(stac-pc): add tests for sentinel-1 search builder`* + +# 5. 🔄 Next Step + +Step 4 is complete. All tasks completed. Plan finalized. diff --git a/docs/agents/planning/_completed/add-pc-s1/review.md b/docs/agents/planning/_completed/add-pc-s1/review.md new file mode 100644 index 0000000..e23da67 --- /dev/null +++ b/docs/agents/planning/_completed/add-pc-s1/review.md @@ -0,0 +1,109 @@ +# Review: add-pc-s1 Plan, Spec & Tasks + +**Verdict: NEEDS WORK** + +Reviewed: `add-pc-s1.md`, `add-pc-s1-spec.md`, `tasks/01-add-constants.md`, `tasks/02-abstract-sentinel1.md`, `tasks/03-sentinel1search.md` +Cross-checked against: `src/geospatial_tools/stac/planetary_computer/sentinel_2.py`, `constants.py`, `stac/core.py` + +______________________________________________________________________ + +## Critical Issues + +**1. `sar:polarizations` is a LIST — STAC query extension needs `contains`, not `eq`.** +Plan says "filters by `instrument_mode` and `polarizations`" but never specifies the operator. +`{"sar:polarizations": {"eq": ["VV","VH"]}}` will not match PC STAC items. You need per-polarization +`{"sar:polarizations": {"contains": "VV"}}` or a post-search asset-key check. +Decide and write it down. Affects Spec §4 AC and Task 3 subtask 3. + +**2. `AbstractSentinel2` is not actually abstract — no `@abstractmethod`.** +It inherits `abc.ABC` but defines zero abstract methods, so `AbstractSentinel2()` instantiates fine. +If you mirror it, Task 2 AC "cannot be instantiated directly" will fail at runtime. +Either add a real `@abstractmethod` (e.g. `build_query() -> dict`) or drop the ABC façade. +Do not propagate the existing bug. + +**3. No spatial filter mentioned anywhere.** +A STAC client without `bbox` / `intersects` is useless for S1. Spec and all three tasks ignore it. +Either state "spatial filtering is delegated to `StacSearch.search()` at call time" or define it as an +`AbstractSentinel1` attribute. Silence is not a design. + +**4. Magic-string violation against your own NFR.** +Plan defaults `instrument_mode="IW"` and `polarizations=["VV","VH"]` as raw strings, then states "No magic strings" in NFR §2.2. +Three missing enums: + +- `PlanetaryComputerS1InstrumentMode` — values: `IW`, `EW`, `SM`, `WV` +- `PlanetaryComputerS1Polarization` — values: `VV`, `VH`, `HH`, `HV` (uppercase; these are STAC property values) +- `PlanetaryComputerS1OrbitState` — values: `ascending`, `descending` (lowercase per STAC `sat` extension) + +Without these, Task 1 is incomplete. + +**5. Uppercase/lowercase trap not surfaced anywhere.** +STAC property `sar:polarizations` uses **uppercase** (`"VV"`, `"VH"`). +PC asset keys use **lowercase** (`"vv"`, `"vh"`). +The plan ships both cases but never states the invariant. This belongs in `KNOWLEDGE.md` +and in docstrings on both enums. The next implementer will get this wrong. + +**6. Architectural ambiguity: where does search live?** +`Sentinel2Search` is a state bag; actual STAC calls happen in `sentinel_2_complete_tile_search` +against `StacSearch`. Task 3 subtask 3 hedges: *"Add `search` or equivalent querying logic … +If search logic lives elsewhere … build the equivalent `sentinel_1_search` functional wrapper."* +That is not a decision. Pick one pattern before writing code or the implementer will drift. + +______________________________________________________________________ + +## Moderate Issues + +**7. Typing gap on `polarizations`.** +Plan uses raw `list[str]`. Project mandates strict typing. Use `list[PlanetaryComputerS1Polarization] | None`. + +**8. `orbit_state` default is undocumented.** +Plan says "optional" — set explicit `None` default, document it as "no filter applied". + +**9. Integration test is flaky-by-design.** +"Fetch S1 GRD items and assert `sar:instrument_mode == IW`" — no fixed bbox, no fixed date range, +no `pytest.mark.integration` / network-skip marker. Pin a small AOI + known date window; mark the +test so CI can skip without a live connection. + +**10. Mirroring `successful_results` / `incomplete_results` / `error_results` on the base class.** +Those state containers belong to the S2 tile-coverage workflow, not a generic SAR base class. +The spec's "base structure mimics S2" invites this waste. Do not copy them unless there is an S1 equivalent workflow. + +**11. Single-pol handling is a bullet point, not a spec.** +Spec acknowledges some products lack `vh` but provides no mechanism. Specify: +"Download path iterates `polarizations`, logs `WARNING` when a requested pol is absent in `item.assets`, continues." +The pattern is already used in `core._download_assets`. Write it explicitly so the test can verify it. + +**12. `sar:product_type` not addressed.** +PC `sentinel-1-grd` exposes GRDH / GRDM / GRDF variants. Either filter by `sar:product_type` +(default `GRD`) or state explicitly it is out of scope. Don't leave it ambient. + +**13. `KNOWLEDGE.md` update missing from tasks.** +`docs/agents/agent_instructions.md` §4 mandates tribal-knowledge capture. The +lowercase-asset / uppercase-property split and the `contains` operator caveat for `sar:polarizations` +both belong there. Add a subtask. + +**14. `PlanetaryComputerS1Collection.GRD` naming is undocumented.** +S2 uses `.L2A` (product level). S1 GRD mixes product type and level. The name is fine; +document the rationale. + +**15. Commit message format inconsistent.** +Tasks specify plain commit text. Existing history uses conventional-commit scope: +`feat(stac-pc): add sentinel-1 constants for planetary computer`. + +**16. Plan tone replaces rationale.** +`add-pc-s1.md` reads "Mirroring Sentinel-2 blindly is stupid." Future readers need the *why*, not the attitude. +Replace with: "Sentinel-1 is SAR (active microwave); cloud-cover and optical-nodata semantics do not apply. +Filtering dimensions are polarization, instrument mode, and orbit state." + +______________________________________________________________________ + +## Summary + +16 issue(s) found. + +### Proposed fix order (one section at a time, approval between each) + +1. Rewrite `add-pc-s1-spec.md` — `contains` query pattern, spatial-filter handling, three missing value enums, architecture decision, pinned integration-test AOI. +2. Rewrite `add-pc-s1.md` — reflect decided architecture, replace attitude with rationale. +3. Rewrite `tasks/01-add-constants.md` — add three missing value enums, document asset-key vs. property-value invariant. +4. Rewrite `tasks/02-abstract-sentinel1.md` — real `@abstractmethod`, typed polarizations, drop S2 state containers. +5. Rewrite `tasks/03-sentinel1search.md` — pinned search architecture, single-pol handling, deterministic integration test with marker. diff --git a/docs/agents/planning/_completed/add-pc-s1/tasks/01-add-constants.md b/docs/agents/planning/_completed/add-pc-s1/tasks/01-add-constants.md new file mode 100644 index 0000000..1357eff --- /dev/null +++ b/docs/agents/planning/_completed/add-pc-s1/tasks/01-add-constants.md @@ -0,0 +1,54 @@ +# TASK-1: Add Sentinel-1 Constants + +## Goal + +Add all six S1 StrEnum types to `constants.py`, covering collection, query properties, asset band keys, instrument mode values, polarization values, and orbit state values. + +## Context & References + +- **Source Plan**: docs/agents/planning/add-pc-s1/add-pc-s1.md +- **Relevant Specs**: docs/agents/planning/add-pc-s1/add-pc-s1-spec.md +- **Existing Code**: src/geospatial_tools/stac/planetary_computer/constants.py, tests/test_planetary_computer_constants.py + +## Subtasks + +1. [x] Add `PlanetaryComputerS1Collection` `StrEnum` with value `GRD = "sentinel-1-grd"`. +2. [x] Add `PlanetaryComputerS1Property` `StrEnum` with values `INSTRUMENT_MODE = "sar:instrument_mode"`, `POLARIZATIONS = "sar:polarizations"`, `ORBIT_STATE = "sat:orbit_state"`. +3. [x] Add `PlanetaryComputerS1Band` `StrEnum` with values `VV = "vv"`, `VH = "vh"`. +4. [x] Add `PlanetaryComputerS1InstrumentMode` `StrEnum` with values `IW = "IW"`, `EW = "EW"`, `SM = "SM"`, `WV = "WV"`. +5. [x] Add `PlanetaryComputerS1Polarization` `StrEnum` with values `VV = "VV"`, `VH = "VH"`, `HH = "HH"`, `HV = "HV"`. +6. [x] Add `PlanetaryComputerS1OrbitState` `StrEnum` with values `ASCENDING = "ascending"`, `DESCENDING = "descending"`. +7. [x] Write failing tests for `PlanetaryComputerS1InstrumentMode`, `PlanetaryComputerS1Polarization`, `PlanetaryComputerS1OrbitState` in `tests/test_planetary_computer_constants.py` (TDD Red). +8. [x] Implement the three new enums in `constants.py` until tests pass (TDD Green). +9. [x] Add explicit test `assert PlanetaryComputerS1Band.VV != PlanetaryComputerS1Polarization.VV` to verify the lowercase/uppercase invariant. +10. [x] Export all six new types from `src/geospatial_tools/stac/planetary_computer/__init__.py`. + +## Requirements & Constraints + +- Constants must be implemented as `StrEnum`. +- Property value enums use uppercase (SAR convention). Asset key enums use lowercase (PC STAC spec). These are distinct and must not be substituted. + +## Acceptance Criteria (AC) + +- [x] `PlanetaryComputerS1Collection` has correct value. +- [x] `PlanetaryComputerS1Property` has correct values. +- [x] `PlanetaryComputerS1Band` has correct values. +- [x] `PlanetaryComputerS1InstrumentMode` has correct values. +- [x] `PlanetaryComputerS1Polarization` has correct values. +- [x] `PlanetaryComputerS1OrbitState` has correct values. +- [x] `assert PlanetaryComputerS1Band.VV != PlanetaryComputerS1Polarization.VV` passes. + +## Testing & Validation + +- **Command**: `pytest tests/test_planetary_computer_constants.py` +- **Success State**: All constants evaluate correctly. +- **Manual Verification**: Review `constants.py`. + +## Completion Protocol + +1. [x] All ACs are met. +2. [x] Tests pass without regressions. +3. [x] All new code passes the project's formating, linting and type-checking tools with zero errors. +4. [x] Documentation updated (if applicable). +5. [x] Commit work: `git commit -m "feat(stac-pc): add S1 constants"` +6. [x] Update this document: Mark as COMPLETE. diff --git a/docs/agents/planning/_completed/add-pc-s1/tasks/02-abstract-sentinel1.md b/docs/agents/planning/_completed/add-pc-s1/tasks/02-abstract-sentinel1.md new file mode 100644 index 0000000..0b98551 --- /dev/null +++ b/docs/agents/planning/_completed/add-pc-s1/tasks/02-abstract-sentinel1.md @@ -0,0 +1,81 @@ +# TASK-2: Implement AbstractSentinel1 Base Class + +## Goal + +Create `AbstractSentinel1` in `sentinel_1.py` as an ABC that provides a fluent builder pattern for SAR search parameters, stores spatial and date filters, owns a `StacSearch` client, and declares abstract methods for execution. + +## Context & References + +- **Source Plan**: docs/agents/planning/add-pc-s1/add-pc-s1.md +- **Relevant Specs**: docs/agents/planning/add-pc-s1/add-pc-s1-spec.md +- **Existing Code**: + - `src/geospatial_tools/stac/planetary_computer/sentinel_2.py` — structural reference only. Do NOT copy optical domain logic. + - `src/geospatial_tools/stac/core.py` — `StacSearch`, `PLANETARY_COMPUTER`, `Asset`. + - `src/geospatial_tools/geotools_types.py` — `BBoxLike`, `IntersectsLike`, `DateLike`. + +## Subtasks + +1. [x] Create new file `src/geospatial_tools/stac/planetary_computer/sentinel_1.py`. +2. [x] Implement `AbstractSentinel1` class (inherits `abc.ABC`). +3. [x] Implement typed `__init__` signature with only collection, date, spatial kwargs, and logger: + ```python + def __init__( + self, + collection: PlanetaryComputerS1Collection | str = PlanetaryComputerS1Collection.GRD, + date_range: DateLike = None, + bbox: geotools_types.BBoxLike | None = None, + intersects: geotools_types.IntersectsLike | None = None, + logger: logging.Logger = LOGGER, + ) -> None: ... + ``` +4. [x] Instantiate `self.client: StacSearch = StacSearch(PLANETARY_COMPUTER)` in `__init__`. +5. [x] Initialize SAR properties and results state in `__init__`: + - `self.instrument_modes: list[PlanetaryComputerS1InstrumentMode] | None = None` + - `self.polarizations: list[PlanetaryComputerS1Polarization] | None = None` + - `self.orbit_states: list[PlanetaryComputerS1OrbitState] | None = None` + - `self.custom_query_params: dict[str, Any] = {}` + - `self.search_results: list[pystac.Item] | None = None` + - `self.downloaded_assets: list[Asset] | None = None` +6. [x] Implement fluent builder methods that update state and `return self`: + - `filter_by_instrument_mode(self, modes: list[PlanetaryComputerS1InstrumentMode] | PlanetaryComputerS1InstrumentMode)` (wrap single item in list) + - `filter_by_polarization(self, polarizations: list[PlanetaryComputerS1Polarization] | PlanetaryComputerS1Polarization)` (wrap single item in list) + - `filter_by_orbit_state(self, states: list[PlanetaryComputerS1OrbitState] | PlanetaryComputerS1OrbitState)` (wrap single item in list) + - `with_custom_query(self, query_params: dict[str, Any])` (update dictionary) +7. [x] Declare `@abstractmethod def search(self) -> list[pystac.Item]: ...`. +8. [x] Declare `@abstractmethod def download(self, bands: list[PlanetaryComputerS1Band | str], base_directory: str | Path) -> list[Asset]: ...`. +9. [x] Write failing tests (TDD Red): + - Direct instantiation of `AbstractSentinel1` raises `TypeError`. + - Builder methods correctly update instance state (lists/dicts) and return `self`. +10. [x] Implement `AbstractSentinel1` until tests pass (TDD Green). + +## Requirements & Constraints + +- Must NOT include optical fields: `max_cloud_cover`, `max_no_data_value`. +- Must NOT include the S2 tile-coverage result containers. +- `date_range` is a single `DateLike` (pystac-native). No multi-range support in this class. +- Spatial kwargs use `geotools_types.BBoxLike` / `geotools_types.IntersectsLike`. +- `StacSearch` is owned via composition (`self.client`). + +## Acceptance Criteria (AC) + +- [x] `AbstractSentinel1.__abstractmethods__` includes `search` and `download`. +- [x] `TypeError` on direct instantiation of `AbstractSentinel1`. +- [x] No optical fields, no tile-coverage state containers. +- [x] All `__init__` kwargs stored as instance attributes. +- [x] `self.client` is a `StacSearch` instance bound to `PLANETARY_COMPUTER`. +- [x] Builder methods (`filter_by_*`, `with_custom_query`) properly format inputs into lists/dicts, update state, and return `self`. +- [x] Results containers initialized to `None`. + +## Testing & Validation + +- **Command**: `pytest tests/test_planetary_computer_sentinel1.py` +- **Success State**: Subclass with trivial method implementations initializes correctly; builder methods work; direct instantiation of ABC fails. + +## Completion Protocol + +1. [x] All ACs are met. +2. [x] Tests pass without regressions. +3. [x] All new code passes the project's formating, linting and type-checking tools with zero errors. +4. [x] Documentation updated (if applicable). +5. [x] Commit work: `git commit -m "feat(stac-pc): implement AbstractSentinel1 base class with builder pattern"` +6. [x] Update this document: Mark as COMPLETE. diff --git a/docs/agents/planning/_completed/add-pc-s1/tasks/03-sentinel1search.md b/docs/agents/planning/_completed/add-pc-s1/tasks/03-sentinel1search.md new file mode 100644 index 0000000..64299d0 --- /dev/null +++ b/docs/agents/planning/_completed/add-pc-s1/tasks/03-sentinel1search.md @@ -0,0 +1,74 @@ +# TASK-3: Implement Sentinel1Search Wrapper and Integration Test + +## Goal + +Implement `Sentinel1Search(AbstractSentinel1)` to execute the search and download logic. The `search()` method will dynamically build the STAC query using the instance's builder state. Verify with unit tests (mocked `StacSearch`) and a pinned integration test. + +## Context & References + +- **Source Plan**: docs/agents/planning/add-pc-s1/add-pc-s1.md +- **Relevant Specs**: docs/agents/planning/add-pc-s1/add-pc-s1-spec.md +- **Existing Code**: + - `src/geospatial_tools/stac/planetary_computer/sentinel_1.py` (from Task 2) — `AbstractSentinel1`. + - `src/geospatial_tools/stac/core.py` — `StacSearch.search`, `StacSearch.download_search_results`, `Asset`. + - `src/geospatial_tools/stac/planetary_computer/constants.py` — all six S1 enums. + +## Subtasks + +1. [x] Implement `Sentinel1Search` inheriting from `AbstractSentinel1`. The subclass itself adds no new `__init__` parameters. +2. [x] **`search()`** (and dynamic query building) — TDD. + - [x] Write failing unit tests (Red) for query building inside `search()`: + - Emits `{"sar:instrument_mode": {"eq": "IW"}}` when `self.instrument_modes` has one element. + - Emits `{"sar:instrument_mode": {"in": ["IW", "EW"]}}` when `self.instrument_modes` has multiple elements. + - Emits `{"sar:polarizations": {"contains": "VV"}}` or similar valid STAC array syntax when `self.polarizations` is set. + - Emits `{"sat:orbit_state": {"eq": "ascending"}}` or `{"in": ["ascending", "descending"]}` for `self.orbit_states`. + - Merges with `self.custom_query_params`. + - Omits keys entirely when states are `None`. + - [x] Implement `search()` (Green). Construct the `query` dict from the internal state, call `self.client.search` with stored date/spatial kwargs + query, store results in `self.search_results`, and return them. +3. [x] **`download()`** — TDD. + - [x] Write failing unit test A (Red) — auto-search: `self.search_results is None`. Patch both `self.client.search` and `self.client.download_search_results`. Call `Sentinel1Search(...).download(...)`. Assert `search` was called once, `download_search_results` called with correct `bands`. + - [x] Write failing unit test B (Red) — already-searched: assert `search` was NOT called if `self.search_results` is populated. + - [x] Write failing unit test C (Red) — single-pol: `bands=[PlanetaryComputerS1Band.VV]`. Assert lowercase conversion. + - [x] Implement `download()` (Green). +4. [x] **Integration test** — `@pytest.mark.integration`. + - [x] Instantiate `Sentinel1Search` with: + - `date_range="2023-01-01/2023-01-31"` + - `bbox=(-74.0, 45.4, -73.5, 45.7)` (Montreal region, dense S1 coverage) + - [x] Apply builder methods: + - `.filter_by_instrument_mode(PlanetaryComputerS1InstrumentMode.IW)` + - `.filter_by_polarization([PlanetaryComputerS1Polarization.VV, PlanetaryComputerS1Polarization.VH])` + - [x] Call `.search()`. Assert results non-empty; every item has `properties["sar:instrument_mode"] == "IW"` and `"VV" in properties["sar:polarizations"]`. + - [x] Document skip flag in a module-level comment: `pytest -m "not integration"`. + +## Requirements & Constraints + +- Query building logic resides within `search()`. +- Handle list states correctly (e.g., using `in` for multiple `instrument_modes` or `orbit_states`). For `polarizations`, handle PC STAC API array-query requirements (e.g., using `contains` on the first element if multiple are not supported, and documenting this limitation). +- `search()` must use `self.client.search` (single range). +- `download()` must trigger `search()` when `self.search_results is None`. +- No standalone module-level `sentinel_1_search(...)` function. All behavior lives on the class. + +## Acceptance Criteria (AC) + +- [x] `search()` dynamically builds the STAC query dict: `in` or `eq` on `instrument_mode` / `orbit_state`, appropriate operator for `polarizations`, omitted keys when `None`. +- [x] `search()` unit test passes: `self.client.search` called with stored kwargs + built query, `self.search_results` populated. +- [x] `download()` auto-search unit test passes. +- [x] `download()` cached-results unit test passes. +- [x] `download()` single-pol unit test passes (`bands=["vv"]`). +- [x] Integration test returns non-empty items matching the builder filters. +- [x] Integration test uses `@pytest.mark.integration`, pinned `bbox=(-74.0, 45.4, -73.5, 45.7)`, pinned `date_range="2023-01-01/2023-01-31"`. + +## Testing & Validation + +- **Command**: `pytest tests/test_planetary_computer_sentinel1.py -m "not integration"` +- **Integration**: `pytest tests/test_planetary_computer_sentinel1.py -m integration` +- **Success State**: All unit tests pass without network; integration test passes against live PC STAC API. + +## Completion Protocol + +1. [x] All ACs are met. +2. [x] Tests pass without regressions. +3. [x] All new code passes the project's formating, linting and type-checking tools with zero errors. +4. [x] Documentation updated (if applicable) — add the uppercase-property / lowercase-asset invariant to `KNOWLEDGE.md` if not already captured. +5. [x] Commit work: `git commit -m "feat(stac-pc): implement Sentinel1Search wrapper and builder search execution"` +6. [x] Update this document: Mark as COMPLETE. diff --git a/docs/agents/planning/_completed/add-sentinel3/add-sentinel3-plan.md b/docs/agents/planning/_completed/add-sentinel3/add-sentinel3-plan.md new file mode 100644 index 0000000..3793625 --- /dev/null +++ b/docs/agents/planning/_completed/add-sentinel3/add-sentinel3-plan.md @@ -0,0 +1,57 @@ +# Formal Design Document: Add Sentinel-3 OLCI Constants + +## 1. Overview + +This task adds Sentinel-3 OLCI constants to `src/geospatial_tools/stac/planetary_computer/constants.py`. Focus is Top of Atmosphere (TOA) data and Near-Infrared (NIR) / Water Vapour bands (Oa16 to Oa21). + +## 2. Rationale + +Current STAC constants support Sentinel-1 and Sentinel-2. Extending support to Sentinel-3 OLCI enables automated STAC queries for ocean and land color applications. TOA data requires specific radiance band definitions. + +## 3. Architecture & Implementation + +### 3.1. Add Collection Constants + +Create `PlanetaryComputerS3Collection` inheriting from `StrEnum`. + +- `OLCI_L1B = "sentinel-3-olci-l1b-efr"` (TOA Radiance proxy). +- `OLCI_WFR = "sentinel-3-olci-wfr-l2-netcdf"` (L2 Reflectance). + +### 3.2. Add Band Constants + +Create `PlanetaryComputerS3Band` inheriting from `StrEnum`. Add requested TOA bands and complementary near-infrared / water-vapour absorption bands. + +- `OA16 = "oa16-radiance"` (778.75 nm) +- `OA17 = "oa17-radiance"` (865 nm) +- `OA18 = "oa18-radiance"` (885 nm) +- `OA19 = "oa19-radiance"` (900 nm) +- `OA20 = "oa20-radiance"` (940 nm) +- `OA21 = "oa21-radiance"` (1020 nm) + +Add common aliases: + +- `NIR_865 = "oa17-radiance"` +- `WATER_VAPOUR = "oa19-radiance"` + +### 3.3. Add Property Constants + +Create `PlanetaryComputerS3Property` inheriting from `StrEnum`. + +- `ORBIT_STATE = "sat:orbit_state"` + +### 3.4. Create `Sentinel3Search` Class + +Create `src/geospatial_tools/stac/planetary_computer/sentinel_3.py`. +Implement `Sentinel3Search` inheriting from `AbstractStacWrapper`. + +- Implement `__init__` supporting S3 collections (`OLCI_WFR` by default). +- Implement `filter_by_orbit_state` method similar to S1. +- Implement `_build_collection_query` to apply `ORBIT_STATE` filter. +- Implement `download` method to download assets. S3 bands in Planetary Computer are lowercase by default, similar to S1, so ensure band keys are handled correctly. + +## 4. Testing Strategy + +- Add tests in `tests/test_planetary_computer_constants.py` to verify enum values map exactly to required Planetary Computer asset keys. +- Ensure `PlanetaryComputerS3Band` alias values equal their target enum values. +- Add tests in `tests/test_planetary_computer_sentinel3.py` to verify `Sentinel3Search` query building and state invalidation. +- Run `make precommit`, `make pylint`, `make mypy`, and `make test` to validate code quality and functionality. diff --git a/docs/agents/planning/_completed/add-sentinel3/add-sentinel3-spec.md b/docs/agents/planning/_completed/add-sentinel3/add-sentinel3-spec.md new file mode 100644 index 0000000..23967bd --- /dev/null +++ b/docs/agents/planning/_completed/add-sentinel3/add-sentinel3-spec.md @@ -0,0 +1,52 @@ +# SPEC: Sentinel-3 OLCI STAC Integration + +## 1. Overview + +- **Goal**: Add STAC constants and a search wrapper class for Sentinel-3 OLCI data on Planetary Computer. +- **Problem Statement**: Current Planetary Computer STAC support is limited to Sentinel-1 and Sentinel-2. This blocks automated queries for Sentinel-3 data required for ocean and land color applications. + +## 2. Requirements + +### Functional Requirements + +- [ ] Implement `PlanetaryComputerS3Collection` with `OLCI_L1B` (`sentinel-3-olci-l1b-efr`) and `OLCI_WFR` (`sentinel-3-olci-wfr-l2-netcdf`) constants. +- [ ] Implement `PlanetaryComputerS3Band` for TOA/NIR/Water-Vapour bands (`OA16` to `OA21`) mapping to `oaXX-radiance` values, with common aliases (`NIR_865`, `WATER_VAPOUR`). +- [ ] Implement `PlanetaryComputerS3Property` containing `ORBIT_STATE` (`sat:orbit_state`). +- [ ] Implement `Sentinel3Search` class extending `AbstractStacWrapper`. +- [ ] `Sentinel3Search` must support filtering by orbit state. +- [ ] `Sentinel3Search` must ensure band keys are processed in lowercase during download (similar to `Sentinel1Search`). + +### Non-Functional Requirements + +- Architecture: Must adhere to the existing `AbstractStacWrapper` facade + proxy pattern. + +## 3. Technical Constraints & Assumptions + +- Existing systems/libraries to use: `StrEnum` (Python 3.11+), `AbstractStacWrapper` from `src/geospatial_tools/stac/core.py`. +- Assumptions: Planetary Computer API relies on specific string keys like `oa17-radiance` for these bands. + +## 4. Acceptance Criteria + +- [ ] All `PlanetaryComputerS3Collection`, `PlanetaryComputerS3Band`, and `PlanetaryComputerS3Property` enum values match the planned strings exactly. +- [ ] Aliases in `PlanetaryComputerS3Band` (e.g. `NIR_865`) map correctly to their primary band equivalent. +- [ ] `Sentinel3Search` instantiates successfully and defaults to `OLCI_WFR` if no collection is provided. +- [ ] `Sentinel3Search.filter_by_orbit_state` successfully updates internal state and invalidates cached results. +- [ ] `Sentinel3Search._build_collection_query` correctly constructs the STAC API query dictionary for `sat:orbit_state`. + +## 5. Dependencies + +- Internal modules: `geospatial_tools.stac.core`, `geospatial_tools.geotools_types`. + +## 6. Out of Scope + +- Adding support for other Sentinel-3 instruments (SLSTR, SRAL, Synergy). +- Custom download logic beyond basic casing normalization before delegating to `AbstractStacWrapper`. + +## 7. Verification Plan + +- Unit tests in `tests/test_planetary_computer_constants.py` asserting correct string values for S3 constants. +- Unit tests in `tests/test_planetary_computer_sentinel3.py` asserting: + - Default collection assignment. + - State invalidation on filter application. + - Query dictionary structure for single and multiple orbit states (`eq` and `in` operators). +- Execute `make precommit`, `make pylint`, `make mypy`, and `make test` to ensure project QA standards are met. diff --git a/docs/agents/planning/_completed/add-sentinel3/tasks/TASK-1.md b/docs/agents/planning/_completed/add-sentinel3/tasks/TASK-1.md new file mode 100644 index 0000000..d504221 --- /dev/null +++ b/docs/agents/planning/_completed/add-sentinel3/tasks/TASK-1.md @@ -0,0 +1,47 @@ +# TASK-1: Add Sentinel-3 STAC Constants + +## Goal + +Implement Planetary Computer STAC constants for Sentinel-3 OLCI (Collections, Bands, Properties). + +## Context & References + +- **Source Plan**: `docs/agents/planning/add-sentinel3/add-sentinel3-plan.md` +- **Relevant Specs**: `docs/agents/planning/add-sentinel3/add-sentinel3-spec.md` +- **Existing Code**: `src/geospatial_tools/stac/planetary_computer/constants.py`, `tests/test_planetary_computer_constants.py` + +## Subtasks + +1. [ ] Add `PlanetaryComputerS3Collection` with `OLCI_L1B` and `OLCI_WFR`. +2. [ ] Add `PlanetaryComputerS3Property` with `ORBIT_STATE`. +3. [ ] Add `PlanetaryComputerS3Band` with `OA16` through `OA21` mapping to `oaXX-radiance` values, and `NIR_865`, `WATER_VAPOUR` aliases. +4. [ ] Write unit tests in `tests/test_planetary_computer_constants.py` to verify values and aliases. + +## Requirements & Constraints + +- Must inherit from `StrEnum` (Python 3.11+). +- Band keys must exactly match Planetary Computer API asset keys. + +## Acceptance Criteria (AC) + +- [ ] AC 1: `PlanetaryComputerS3Collection.OLCI_WFR` equals `"sentinel-3-olci-wfr-l2-netcdf"`. +- [ ] AC 2: `PlanetaryComputerS3Band.OA17` equals `"oa17-radiance"`. +- [ ] AC 3: `PlanetaryComputerS3Band.NIR_865` alias correctly resolves to `OA17`'s value. +- [ ] AC 4: All tests pass. + +## Testing & Validation + +- **Command**: `make test` and `make mypy` +- **Success State**: Zero failures, zero type errors. +- **Manual Verification**: Run `make pylint` to ensure no linting regressions. + +## Completion Protocol + +1. [x] All ACs are met. +2. [x] Tests pass without regressions. +3. [x] All new code passes the project's formating, linting and type-checking tools with zero errors. +4. [x] Documentation updated (if applicable). +5. [x] Commit work: `git commit -m "feat: add sentinel-3 stac constants"` +6. [x] Update this document: Mark as COMPLETE. + +**STATUS: COMPLETE** diff --git a/docs/agents/planning/_completed/add-sentinel3/tasks/TASK-2.md b/docs/agents/planning/_completed/add-sentinel3/tasks/TASK-2.md new file mode 100644 index 0000000..4db5ddf --- /dev/null +++ b/docs/agents/planning/_completed/add-sentinel3/tasks/TASK-2.md @@ -0,0 +1,49 @@ +# TASK-2: Create Sentinel3Search Wrapper Class + +## Goal + +Implement `Sentinel3Search` extending `AbstractStacWrapper` for automated STAC queries on Planetary Computer. + +## Context & References + +- **Source Plan**: `docs/agents/planning/add-sentinel3/add-sentinel3-plan.md` +- **Relevant Specs**: `docs/agents/planning/add-sentinel3/add-sentinel3-spec.md` +- **Existing Code**: `src/geospatial_tools/stac/core.py`, `src/geospatial_tools/stac/planetary_computer/sentinel_1.py` (for reference) + +## Subtasks + +1. [ ] Create `src/geospatial_tools/stac/planetary_computer/sentinel_3.py`. +2. [ ] Implement `Sentinel3Search` inheriting from `AbstractStacWrapper`. +3. [ ] Implement `filter_by_orbit_state` and `_build_collection_query` methods. +4. [ ] Override `download` method to normalize bands to lowercase (like S1). +5. [ ] Write unit tests in `tests/test_planetary_computer_sentinel3.py`. + +## Requirements & Constraints + +- Must adhere to the Facade + Proxy pattern defined in `AbstractStacWrapper`. +- S3 bands on Planetary Computer require lowercase asset keys during download. +- Filtering by `ORBIT_STATE` must invalidate the client state. + +## Acceptance Criteria (AC) + +- [ ] AC 1: Instantiates with `OLCI_WFR` by default if no collection provided. +- [ ] AC 2: `filter_by_orbit_state` updates internal state and invalidates caches. +- [ ] AC 3: `_build_collection_query` builds correct `eq` (single) or `in` (multiple) dictionary structures for `sat:orbit_state`. +- [ ] AC 4: Test coverage covers initialization, filtering, query building, and lowercase band handling. + +## Testing & Validation + +- **Command**: `make test`, `make pylint`, `make mypy`, `make precommit` +- **Success State**: All QA steps complete without errors. +- **Manual Verification**: Run full suite to ensure zero side-effects on S1/S2 behavior. + +## Completion Protocol + +1. [x] All ACs are met. +2. [x] Tests pass without regressions. +3. [x] All new code passes the project's formating, linting and type-checking tools with zero errors. +4. [x] Documentation updated (if applicable). +5. [x] Commit work: `git commit -m "feat: implement Sentinel3Search wrapper"` +6. [x] Update this document: Mark as COMPLETE. + +**STATUS: COMPLETE** diff --git a/docs/agents/planning/copernicus_s3_access/refactor_copernicus_s3_access_PLAN.md b/docs/agents/planning/_completed/copernicus_s3_access/refactor_copernicus_s3_access_PLAN.md similarity index 100% rename from docs/agents/planning/copernicus_s3_access/refactor_copernicus_s3_access_PLAN.md rename to docs/agents/planning/_completed/copernicus_s3_access/refactor_copernicus_s3_access_PLAN.md diff --git a/docs/agents/planning/copernicus_s3_access/refactor_copernicus_s3_access_SPEC.md b/docs/agents/planning/_completed/copernicus_s3_access/refactor_copernicus_s3_access_SPEC.md similarity index 100% rename from docs/agents/planning/copernicus_s3_access/refactor_copernicus_s3_access_SPEC.md rename to docs/agents/planning/_completed/copernicus_s3_access/refactor_copernicus_s3_access_SPEC.md diff --git a/docs/agents/planning/copernicus_s3_access/tasks/TASK-1_dependency_config.md b/docs/agents/planning/_completed/copernicus_s3_access/tasks/TASK-1_dependency_config.md similarity index 100% rename from docs/agents/planning/copernicus_s3_access/tasks/TASK-1_dependency_config.md rename to docs/agents/planning/_completed/copernicus_s3_access/tasks/TASK-1_dependency_config.md diff --git a/docs/agents/planning/copernicus_s3_access/tasks/TASK-2_s3_utils.md b/docs/agents/planning/_completed/copernicus_s3_access/tasks/TASK-2_s3_utils.md similarity index 100% rename from docs/agents/planning/copernicus_s3_access/tasks/TASK-2_s3_utils.md rename to docs/agents/planning/_completed/copernicus_s3_access/tasks/TASK-2_s3_utils.md diff --git a/docs/agents/planning/copernicus_s3_access/tasks/TASK-3_refactor_stac.md b/docs/agents/planning/_completed/copernicus_s3_access/tasks/TASK-3_refactor_stac.md similarity index 100% rename from docs/agents/planning/copernicus_s3_access/tasks/TASK-3_refactor_stac.md rename to docs/agents/planning/_completed/copernicus_s3_access/tasks/TASK-3_refactor_stac.md diff --git a/docs/agents/planning/copernicus_s3_access/tasks/TASK-4_integration_testing.md b/docs/agents/planning/_completed/copernicus_s3_access/tasks/TASK-4_integration_testing.md similarity index 100% rename from docs/agents/planning/copernicus_s3_access/tasks/TASK-4_integration_testing.md rename to docs/agents/planning/_completed/copernicus_s3_access/tasks/TASK-4_integration_testing.md diff --git a/docs/agents/planning/mypy-refactor/mypy-refactor-plan.md b/docs/agents/planning/_completed/mypy-refactor/mypy-refactor-plan.md similarity index 100% rename from docs/agents/planning/mypy-refactor/mypy-refactor-plan.md rename to docs/agents/planning/_completed/mypy-refactor/mypy-refactor-plan.md diff --git a/docs/agents/planning/mypy-refactor/tasks/TASK-1_fix_implicit_optionals.md b/docs/agents/planning/_completed/mypy-refactor/tasks/TASK-1_fix_implicit_optionals.md similarity index 100% rename from docs/agents/planning/mypy-refactor/tasks/TASK-1_fix_implicit_optionals.md rename to docs/agents/planning/_completed/mypy-refactor/tasks/TASK-1_fix_implicit_optionals.md diff --git a/docs/agents/planning/mypy-refactor/tasks/TASK-2_resolve_path_mismatches.md b/docs/agents/planning/_completed/mypy-refactor/tasks/TASK-2_resolve_path_mismatches.md similarity index 100% rename from docs/agents/planning/mypy-refactor/tasks/TASK-2_resolve_path_mismatches.md rename to docs/agents/planning/_completed/mypy-refactor/tasks/TASK-2_resolve_path_mismatches.md diff --git a/docs/agents/planning/mypy-refactor/tasks/TASK-3_fix_variance_and_sequences.md b/docs/agents/planning/_completed/mypy-refactor/tasks/TASK-3_fix_variance_and_sequences.md similarity index 100% rename from docs/agents/planning/mypy-refactor/tasks/TASK-3_fix_variance_and_sequences.md rename to docs/agents/planning/_completed/mypy-refactor/tasks/TASK-3_fix_variance_and_sequences.md diff --git a/docs/agents/planning/mypy-refactor/tasks/TASK-4_missing_annotations_and_edge_cases.md b/docs/agents/planning/_completed/mypy-refactor/tasks/TASK-4_missing_annotations_and_edge_cases.md similarity index 100% rename from docs/agents/planning/mypy-refactor/tasks/TASK-4_missing_annotations_and_edge_cases.md rename to docs/agents/planning/_completed/mypy-refactor/tasks/TASK-4_missing_annotations_and_edge_cases.md diff --git a/docs/agents/planning/mypy-refactor/tasks/TASK-5_missed_mypy_errors.md b/docs/agents/planning/_completed/mypy-refactor/tasks/TASK-5_missed_mypy_errors.md similarity index 100% rename from docs/agents/planning/mypy-refactor/tasks/TASK-5_missed_mypy_errors.md rename to docs/agents/planning/_completed/mypy-refactor/tasks/TASK-5_missed_mypy_errors.md diff --git a/docs/agents/planning/_completed/pc-sentinel2-constants/pc-sentinel2-constants-plan.md b/docs/agents/planning/_completed/pc-sentinel2-constants/pc-sentinel2-constants-plan.md new file mode 100644 index 0000000..90d8bce --- /dev/null +++ b/docs/agents/planning/_completed/pc-sentinel2-constants/pc-sentinel2-constants-plan.md @@ -0,0 +1,34 @@ +# 🎯 1. Objective + +Implement constants for Planetary Computer Sentinel-2 STAC catalog. Replace magic strings to provide type safety. Match `copernicus/constants.py` pattern, extending it to STAC properties used in queries. + +# 🏗️ 2. Architectural Approach + +Create `src/geospatial_tools/stac/planetary_computer/constants.py`. Define `PlanetaryComputerS2Collection`, `PlanetaryComputerS2Band`, and `PlanetaryComputerS2Property` enums. Inherit from `enum.StrEnum` (Python 3.11+ standard). Do not use legacy `str, Enum` pattern. Do not override `__str__` or `__repr__` natively handled by `StrEnum`. + +Planetary Computer uses plain base names (e.g., `"B02"`) for band asset keys (unlike Copernicus resolution suffix). `PlanetaryComputerS2Band` is simple: no `at_res()` method, no `native_res` property. + +`PlanetaryComputerS2Property` eliminates hardcoded STAC query properties (`eo:cloud_cover`, `s2:mgrs_tile`, `s2:nodata_pixel_percentage`). STAC API `sortby` requires full JSON path prefix: `"properties.eo:cloud_cover"`. Enum exposes `sortby_field` property returning `f"properties.{self.value}"` (eliminating secondary magic strings). + +# 🧪 3. Verification & Failure Modes + +**Verification:** +Write unit tests for enum string representation. Test STAC search with enum bands and properties. Run `make TEST_ARGS='tests/test_stac.py' test-specific`. Run `mypy`. + +**Failure Modes:** +Wrong asset keys → STAC API rejects request. +Wrong property keys → STAC search returns empty or fails. +Using legacy `str, Enum` → Type checker warnings, poor modernization. + +# 🛠️ 4. Implementation Steps + +1. Create `src/geospatial_tools/stac/planetary_computer/constants.py` with `StrEnum`s for collection, bands, and properties. Add `sortby_field` property. Export from `__init__.py`. +2. Add unit tests in `tests/test_planetary_computer_constants.py`. +3. Update `AbstractSentinel2` and `BestProductsForFeatures` default `collection` to `PlanetaryComputerS2Collection.L2A`. Update type hint to `PlanetaryComputerS2Collection | str`. +4. Update `sentinel_2_complete_tile_search` to use `PlanetaryComputerS2Property` for `query` keys, `filter_no_data`, and `sortby_field` for sort field path. +5. Update `download_and_process_sentinel2_asset` default `collections` to `PlanetaryComputerS2Collection.L2A`. Update type hint. +6. Run full QA suite (`make test`, `make lint`) to verify no regressions. + +# 🚀 5. Next Step + +Approve Step 1? diff --git a/docs/agents/planning/_completed/pc-sentinel2-constants/pc-sentinel2-constants-spec.md b/docs/agents/planning/_completed/pc-sentinel2-constants/pc-sentinel2-constants-spec.md new file mode 100644 index 0000000..7c0fc85 --- /dev/null +++ b/docs/agents/planning/_completed/pc-sentinel2-constants/pc-sentinel2-constants-spec.md @@ -0,0 +1,58 @@ +# SPEC: Planetary Computer Sentinel-2 Constants + +## 1. Overview + +- **Goal**: Implement strongly-typed constants for the Planetary Computer Sentinel-2 STAC catalog. Replace magic strings in the codebase. +- **Problem Statement**: Implementation in `src/geospatial_tools/stac/planetary_computer/sentinel_2.py` relies on hardcoded magic strings for collection names, band names, and STAC query properties. Error-prone, lacks type safety, complicates maintenance. + +## 2. Requirements + +### Functional Requirements + +- [x] Create `src/geospatial_tools/stac/planetary_computer/constants.py` module. +- [x] Define `PlanetaryComputerS2Collection` enum for collection names. +- [x] Define `PlanetaryComputerS2Band` enum for asset band keys. +- [x] Define `PlanetaryComputerS2Property` enum for STAC query properties with a `sortby_field` property. +- [x] Refactor `src/geospatial_tools/stac/planetary_computer/sentinel_2.py` using new enums. +- [x] Export new constants module from `src/geospatial_tools/stac/planetary_computer/__init__.py`. + +### Non-Functional Requirements + +- **Type Safety**: Enums MUST inherit from `enum.StrEnum` (Python 3.11+). Updated parameters reflect enum type (`collection: PlanetaryComputerS2Collection | str`). Do not use legacy `str, Enum`. +- **Simplicity**: PC band enum uses plain base names (no resolution suffix, no `at_res()` method, no `native_res` property). Do not override `__str__` or `__repr__`. + +## 3. Technical Constraints & Assumptions + +- **STAC Asset Keys**: Planetary Computer Sentinel-2 STAC uses base band name as asset key (`"B02"`, not `"B02_10m"`). +- **STAC `sortby` field format**: STAC API `sortby` object requires full JSON path `"properties.eo:cloud_cover"`. `PlanetaryComputerS2Property` exposes `sortby_field` property returning `f"properties.{self.value}"`. +- **Libraries**: Use built-in `enum.StrEnum`. + +## 4. Acceptance Criteria + +- [x] `PlanetaryComputerS2Collection` enum exists. `PlanetaryComputerS2Collection.L2A` == `"sentinel-2-l2a"`. +- [x] `PlanetaryComputerS2Property` enum exists. Contains `CLOUD_COVER = "eo:cloud_cover"`, `MGRS_TILE = "s2:mgrs_tile"`, `NODATA_PIXEL_PERCENTAGE = "s2:nodata_pixel_percentage"`. Its `sortby_field` property returns `f"properties.{self.value}"`. +- [x] `PlanetaryComputerS2Band` enum exists. Inherits from `enum.StrEnum`. Standard bands: `B01`, `B02`, `B03`, `B04`, `B05`, `B06`, `B07`, `B08`, `B8A`, `B09`, `B11`, `B12`, `SCL`, `TCI`, `AOT`, `WVP`. Common name aliases: `COASTAL=B01`, `BLUE=B02`, `GREEN=B03`, `RED=B04`, `RED_EDGE_1=B05`, `RED_EDGE_2=B06`, `RED_EDGE_3=B07`, `NIR=B08`, `NIR_NARROW=B8A`, `SWIR_1=B11`, `SWIR_2=B12`. +- [x] No enum overrides `__str__` or `__repr__`. +- [x] `AbstractSentinel2` default `collection` parameter uses `PlanetaryComputerS2Collection.L2A` with type `PlanetaryComputerS2Collection | str`. +- [x] `BestProductsForFeatures` default `collection` parameter uses `PlanetaryComputerS2Collection.L2A` with type `PlanetaryComputerS2Collection | str`. +- [x] `sentinel_2_complete_tile_search` function uses `PlanetaryComputerS2Property` for all query keys, `filter_no_data`, and `sortby_field` for the sort field path. +- [x] `download_and_process_sentinel2_asset` function uses `PlanetaryComputerS2Collection.L2A` with type `PlanetaryComputerS2Collection | str`. +- [x] New constants exported from `src/geospatial_tools/stac/planetary_computer/__init__.py`. +- [x] Unit tests for new constants pass. +- [x] Full QA suite passes without regressions. + +## 5. Dependencies + +- Relies on existing `pystac` and STAC search implementations. Built-in `enum.StrEnum` requires Python 3.11+. + +## 6. Out of Scope + +- Refactoring Sentinel-2 Copernicus constants (`str, Enum` refactor). +- Modifying core `StacSearch` client logic. +- Modifying vector or raster processing logic. +- Fixing `print(error)` forbidden pattern at `sentinel_2.py:320`. + +## 7. Verification Plan + +- **Unit Tests**: Create `tests/test_planetary_computer_constants.py`. Verify exact string values. +- **Integration Tests**: Run full test suite. Verify STAC workflows un-broken. Verify `test_stac.py` passes. Run `mypy` to verify typing. diff --git a/docs/agents/planning/_completed/pc-sentinel2-constants/tasks/TASK-1_create_constants.md b/docs/agents/planning/_completed/pc-sentinel2-constants/tasks/TASK-1_create_constants.md new file mode 100644 index 0000000..e18d326 --- /dev/null +++ b/docs/agents/planning/_completed/pc-sentinel2-constants/tasks/TASK-1_create_constants.md @@ -0,0 +1,51 @@ +# TASK-1: Create Planetary Computer Constants + +## Goal + +Implement `PlanetaryComputerS2Collection`, `PlanetaryComputerS2Band`, and `PlanetaryComputerS2Property` using `enum.StrEnum`. Write unit tests to verify string representations. + +## Context & References + +- **Source Plan**: `docs/agents/planning/pc-sentinel2-constants/pc-sentinel2-constants-plan.md` +- **Relevant Specs**: `docs/agents/planning/pc-sentinel2-constants/pc-sentinel2-constants-spec.md` + +## Subtasks + +1. [x] Create `src/geospatial_tools/stac/planetary_computer/constants.py`. +2. [x] Define `PlanetaryComputerS2Collection` enum inheriting from `enum.StrEnum`. Set `L2A = "sentinel-2-l2a"`. +3. [x] Define `PlanetaryComputerS2Property` enum inheriting from `enum.StrEnum`. Add `CLOUD_COVER = "eo:cloud_cover"`, `MGRS_TILE = "s2:mgrs_tile"`, `NODATA_PIXEL_PERCENTAGE = "s2:nodata_pixel_percentage"`. Add `sortby_field` property returning `f"properties.{self.value}"`. +4. [x] Define `PlanetaryComputerS2Band` enum inheriting from `enum.StrEnum`. Values are plain base names (no resolution suffix). Standard bands: `B01`, `B02`, `B03`, `B04`, `B05`, `B06`, `B07`, `B08`, `B8A`, `B09`, `B11`, `B12`, `SCL`, `TCI`, `AOT`, `WVP`. Common name aliases: `COASTAL=B01`, `BLUE=B02`, `GREEN=B03`, `RED=B04`, `RED_EDGE_1=B05`, `RED_EDGE_2=B06`, `RED_EDGE_3=B07`, `NIR=B08`, `NIR_NARROW=B8A`, `SWIR_1=B11`, `SWIR_2=B12`. +5. [x] Export constants from `src/geospatial_tools/stac/planetary_computer/__init__.py`. +6. [x] Create `tests/test_planetary_computer_constants.py`. +7. [x] Write unit tests to assert exact string values of all enum members. +8. [x] Write unit test to assert `PlanetaryComputerS2Property.CLOUD_COVER.sortby_field == "properties.eo:cloud_cover"`. + +## Requirements & Constraints + +- Enums MUST inherit from `enum.StrEnum` (Python 3.11+). Do NOT use `str, Enum`. Do NOT override `__str__` and `__repr__`. +- Planetary Computer STAC uses base band names (`"B02"`). Do not append resolutions. No `at_res()` or `native_res`. +- `PlanetaryComputerS2Property` exposes `sortby_field` property (not an enum member) for `"properties."` format. +- Use only built-in `enum.StrEnum`. + +## Acceptance Criteria (AC) + +- [x] AC 1: `PlanetaryComputerS2Collection.L2A == "sentinel-2-l2a"`. +- [x] AC 2: `PlanetaryComputerS2Property.CLOUD_COVER == "eo:cloud_cover"`, `MGRS_TILE == "s2:mgrs_tile"`, `NODATA_PIXEL_PERCENTAGE == "s2:nodata_pixel_percentage"`. `PlanetaryComputerS2Property.CLOUD_COVER.sortby_field == "properties.eo:cloud_cover"`. +- [x] AC 3: `PlanetaryComputerS2Band` contains all 16 standard bands and 11 common aliases. `PlanetaryComputerS2Band.BLUE == "B02"`. +- [x] AC 4: New constants importable from `geospatial_tools.stac.planetary_computer`. +- [x] AC 5: Unit tests in `tests/test_planetary_computer_constants.py` pass. + +## Testing & Validation + +- **Command**: `make TEST_ARGS='tests/test_planetary_computer_constants.py' test-specific` +- **Success State**: All tests pass. +- **Manual Verification**: Review `constants.py` for `StrEnum` inheritance. + +## Completion Protocol + +1. [x] All ACs met. +2. [x] Tests pass without regressions. +3. [x] Code passes formatting, linting, and type-checking (zero errors). +4. [x] Documentation updated. +5. [x] Commit work: `git commit -m "feat: task 1 - create planetary computer constants"` +6. [x] Update document: Mark as COMPLETE. diff --git a/docs/agents/planning/_completed/pc-sentinel2-constants/tasks/TASK-2_refactor_sentinel2.md b/docs/agents/planning/_completed/pc-sentinel2-constants/tasks/TASK-2_refactor_sentinel2.md new file mode 100644 index 0000000..14a2be2 --- /dev/null +++ b/docs/agents/planning/_completed/pc-sentinel2-constants/tasks/TASK-2_refactor_sentinel2.md @@ -0,0 +1,59 @@ +# TASK-2: Refactor Sentinel-2 Module + +## Goal + +Update `src/geospatial_tools/stac/planetary_computer/sentinel_2.py` using new Planetary Computer constants. Eliminate hardcoded STAC magic strings. + +## Context & References + +- **Source Plan**: `docs/agents/planning/pc-sentinel2-constants/pc-sentinel2-constants-plan.md` +- **Relevant Specs**: `docs/agents/planning/pc-sentinel2-constants/pc-sentinel2-constants-spec.md` +- **Existing Code**: + - `src/geospatial_tools/stac/planetary_computer/sentinel_2.py` + +## Subtasks + +1. [x] Import `PlanetaryComputerS2Collection`, `PlanetaryComputerS2Property` in `sentinel_2.py`. +2. [x] Update `AbstractSentinel2.__init__` default `collection` to `PlanetaryComputerS2Collection.L2A`. Update type hint to `PlanetaryComputerS2Collection | str`. +3. [x] Update `BestProductsForFeatures.__init__` default `collection` to `PlanetaryComputerS2Collection.L2A`. Update type hint to `PlanetaryComputerS2Collection | str`. +4. [x] Update `download_and_process_sentinel2_asset` default `collections` to `PlanetaryComputerS2Collection.L2A`. Update type hint to `PlanetaryComputerS2Collection | str`. +5. [x] Refactor `sentinel_2_complete_tile_search` `query` dict keys using `PlanetaryComputerS2Property.CLOUD_COVER` and `PlanetaryComputerS2Property.MGRS_TILE`. +6. [x] Refactor `sentinel_2_complete_tile_search` `sortby` field using `PlanetaryComputerS2Property.CLOUD_COVER.sortby_field`. +7. [x] Refactor `sentinel_2_complete_tile_search` `filter_no_data` using `PlanetaryComputerS2Property.NODATA_PIXEL_PERCENTAGE`. +8. [x] Refactor `optimal_result.properties[...]` accesses in `sentinel_2_complete_tile_search` using `PlanetaryComputerS2Property` keys. +9. [x] Run integration tests (`make TEST_ARGS='tests/test_stac.py' test-specific`). +10. [x] Run full QA suite (`make test`, `make lint`). + +## Requirements & Constraints + +- Do not modify core `StacSearch` logic in `core.py`. +- Do not modify vector or raster processing logic. +- Type hints MUST be updated alongside default values (`PlanetaryComputerS2Collection | str`). +- Do **not** fix `print(error)` at `sentinel_2.py:320` (out of scope). +- `sortby` field uses `PlanetaryComputerS2Property.CLOUD_COVER.sortby_field`. + +## Acceptance Criteria (AC) + +- [x] AC 1: `AbstractSentinel2.__init__` default `collection` is `PlanetaryComputerS2Collection.L2A` with type `PlanetaryComputerS2Collection | str`. +- [x] AC 2: `BestProductsForFeatures.__init__` default `collection` is `PlanetaryComputerS2Collection.L2A` with type `PlanetaryComputerS2Collection | str`. +- [x] AC 3: `download_and_process_sentinel2_asset` default `collections` is `PlanetaryComputerS2Collection.L2A` with type `PlanetaryComputerS2Collection | str`. +- [x] AC 4: `sentinel_2_complete_tile_search` contains no bare string literals for properties. +- [x] AC 5: `sentinel_2_complete_tile_search` `sortby` uses `.sortby_field`. +- [x] AC 6: `mypy` passes with zero errors on `sentinel_2.py`. +- [x] AC 7: `make TEST_ARGS='tests/test_stac.py' test-specific` passes. +- [x] AC 8: `make test` passes without regressions. + +## Testing & Validation + +- **Command**: `make TEST_ARGS='tests/test_stac.py' test-specific` +- **Success State**: All STAC tests pass. No search failures. +- **Manual Verification**: Review `sentinel_2.py` for remaining magic strings. + +## Completion Protocol + +1. [x] All ACs met. +2. [x] Tests pass without regressions. +3. [x] Code passes formatting, linting, type-checking (zero errors). +4. [x] Documentation updated. +5. [x] Commit work: `git commit -m "refactor: task 2 - apply pc constants to sentinel_2.py"` +6. [x] Update document: Mark as COMPLETE. diff --git a/docs/agents/planning/_completed/refactor-s2/refactor-s2-plan.md b/docs/agents/planning/_completed/refactor-s2/refactor-s2-plan.md new file mode 100644 index 0000000..0e2ab45 --- /dev/null +++ b/docs/agents/planning/_completed/refactor-s2/refactor-s2-plan.md @@ -0,0 +1,29 @@ +# 🎯 Scope & Context + +The current `AbstractSentinel2` and `Sentinel2Search` classes inside `src/geospatial_tools/stac/planetary_computer/sentinel_2.py` are prototypical, mixing generic STAC querying with specific tiling coverage logic (`BestProductsForFeatures`). We need to refactor these into a thin, synchronous wrapper using a fluent builder pattern. +Simultaneously, `AbstractSentinel1` and `Sentinel1Search` in `src/geospatial_tools/stac/planetary_computer/sentinel_1.py` already use a builder pattern but suffer from duplicated state management (storing `search_results` and `downloaded_assets` locally instead of delegating to the `StacSearch` client). +To align with the project's strict Python, System Design, and QA guidelines, we will refactor both Sentinel-1 and Sentinel-2 classes to use a strict **Facade + Proxy property pattern**. This provides a clean API while ensuring zero state duplication and strict invalidation of stale cache data. + +# 🏗️ Architectural Approach + +1. **Decouple Tiling Orchestrator**: Sever the inheritance between `BestProductsForFeatures` and `AbstractSentinel2`, making `BestProductsForFeatures` a standalone orchestrator. This enforces the "Composition over Inheritance" principle. +2. **Facade Builder Bases (`AbstractSentinel1`, `AbstractSentinel2`)**: Refactor both base classes to act as pure Facades over `StacSearch`. They will use `@property` proxies to expose `search_results` and `downloaded_assets` from the underlying client, storing NO duplicate state. All builder methods (e.g., `filter_by_cloud_cover`, `filter_by_polarization`) will return `typing.Self` and explicitly call an `_invalidate_state()` method to wipe the client's cache whenever query parameters change. +3. **Execution Wrappers (`Sentinel1Search`, `Sentinel2Search`)**: Update the concrete wrappers to dynamically construct the STAC query dict during `search()`, pass it to the proxy client, and rely on the proxy properties for `download()`. Paths in `download()` must strictly use `pathlib.Path`. +4. **Idempotency & Reliability**: Ensure that running `search()` or `download()` multiple times yields consistent results without duplicating state (e.g., clearing the query dictionary on each `search()` call). Do not use bare `except:` blocks; handle specific STAC/network exceptions explicitly. + +# 🛡️ Verification & FMEA + +- **Verification**: + - Run the project QA tools (`make test`, `make mypy`, `make pylint`, `make precommit`) before and after the refactor to ensure no regressions and strict type compliance. + - Unit tests verifying builder state mutations and successful invalidation of client state for both S1 and S2. + - Pinned integration tests (`@pytest.mark.integration`) for both S1 and S2 on the PC STAC API. +- **Failure Modes**: + - Regressions in `BestProductsForFeatures` or `find_best_product_per_s2_tile` due to shared dependencies. Mitigation: explicitly isolate these legacy components during refactoring and run all related tests. + - Silent failures during STAC queries. Mitigation: Log explicit error messages using `structlog` (or existing `logger`) and avoid generic `except Exception: pass`. + +# 📝 Implementation Steps + +1. **Isolate Legacy Code**: Isolate `BestProductsForFeatures` from `AbstractSentinel2`. Ensure `mypy` and `make test` still pass. +2. **Implement Facade Bases**: Update `AbstractSentinel1` and `AbstractSentinel2` to the Facade + Proxy pattern. Use strict `typing.Self`. +3. **Implement Executable Wrappers**: Update `Sentinel1Search` and `Sentinel2Search` to rely purely on proxy states and correctly map builder states to STAC queries. +4. **Testing & QA**: Write/update unit tests and integration tests for both modules. Run `make pylint`, `make mypy`, `make precommit`, and `make test` to confirm compliance. diff --git a/docs/agents/planning/_completed/refactor-s2/refactor-s2-spec.md b/docs/agents/planning/_completed/refactor-s2/refactor-s2-spec.md new file mode 100644 index 0000000..94ab213 --- /dev/null +++ b/docs/agents/planning/_completed/refactor-s2/refactor-s2-spec.md @@ -0,0 +1,67 @@ +# SPEC: Planetary Computer Sentinel-1 & Sentinel-2 Facade Pattern Refactor + +## 1. Overview + +- **Goal**: Refactor both Sentinel-1 and Sentinel-2 STAC wrappers (`AbstractSentinel1`, `Sentinel1Search`, `AbstractSentinel2`, `Sentinel2Search`) to implement a strict **Facade + Proxy property pattern**. Decouple the legacy `BestProductsForFeatures` orchestrator from the S2 base class to preserve its functionality while enabling the refactor. +- **Problem Statement**: The Sentinel-2 classes are prototypical and lack a builder API. The Sentinel-1 classes have a builder API but duplicate execution state (`search_results`), leading to potential silent data bugs if filters are modified post-search. Both sets of wrappers violate Clean Architecture principles regarding single responsibility and low coupling. +- **Design intent (scope lock)**: Establish thin, synchronous wrappers for STAC query generation on optical and radar data. Base classes must act as pure Facades, delegating all state storage (`search_results`, `downloaded_assets`) and execution to a composed `StacSearch` client. Strict typing (`typing.Self`) and idiomatic Python (e.g., `pathlib.Path`) must be enforced. + +## 2. Requirements + +### Functional Requirements + +- [ ] Isolate `BestProductsForFeatures` by removing its inheritance from `AbstractSentinel2`. Remove the `super().__init__(...)` call. Move legacy state (`date_ranges`, `max_cloud_cover`, `max_no_data_value`, `successful_results`, `incomplete_results`, `error_results`) and the `create_date_ranges` method directly into it. +- [ ] Refactor `AbstractSentinel1` and `AbstractSentinel2` into `abc.ABC` classes that cannot be instantiated directly. +- [ ] Base class `__init__` methods must instantiate an internal `StacSearch(PLANETARY_COMPUTER)` as `self.client`. +- [ ] Base classes must expose `@property` proxies for `search_results` and `downloaded_assets` that point to `self.client.search_results` and `self.client.downloaded_search_assets` respectively. They must NOT store duplicate local state. +- [ ] Base classes must implement `_invalidate_state(self) -> None` that sets `self.client.search_results = None` and `self.client.downloaded_search_assets = None`. +- [ ] All builder methods in `AbstractSentinel1` (e.g., `filter_by_polarization`) and `AbstractSentinel2` (e.g., `filter_by_cloud_cover`) must return `typing.Self` for precise type hinting and MUST call `self._invalidate_state()` before returning. +- [ ] Implement `Sentinel1Search` and `Sentinel2Search` with `search()` and `download()` methods. +- [ ] `search()` must dynamically construct the STAC `query` dictionary, merge `custom_query_params`, execute `self.client.search(...)`, and return the proxy `self.search_results`. The methods must be idempotent. +- [ ] `download(..., base_directory: pathlib.Path | str)` triggers `self.search()` if the proxy `search_results` is `None`, calls `self.client.download_search_results(...)`, and returns the proxy `self.downloaded_assets`. The `base_directory` must be strictly typed and handled as `pathlib.Path`. + +### Non-Functional Requirements + +- **Consistency**: Both S1 and S2 APIs must exactly mirror each other using the Facade pattern, providing a unified developer experience. +- **Type Safety**: Use `StrEnum` for all domain constants. Spatial kwargs typed as `geotools_types.BBoxLike` / `geotools_types.IntersectsLike`. Use strict type hints (`typing.Self`, specific return types). +- **Backward Compatibility**: `BestProductsForFeatures` and its module-level functions must continue to function exactly as before without modification to their internal logic. +- **Code Quality**: Code must pass `make mypy`, `make pylint`, `make precommit`, and existing `make test` checks. Do not use bare `except` blocks; target specific errors (e.g. `pystac.StacError`). + +## 3. Technical Constraints & Assumptions + +- **Architecture Decision**: The wrappers own a `StacSearch` instance via composition. Query-building state (filters, spatial params, date range) lives on the wrapper. Execution results are stored exclusively on `self.client` (`search_results`, `downloaded_search_assets` — both plain settable attributes on `StacSearch`). Mutating query state must call `_invalidate_state()` to nil out those client attributes and prevent stale-result access. +- **Legacy Orchestrator**: `BestProductsForFeatures` acts as a standalone orchestrator. Isolating it is a prerequisite to cleanly refactoring `Sentinel2Search`. +- **PC STAC Validation**: Specific query parameter formatting for optical vs radar properties must align with `pystac_client` operators (`lt`, `in`, `eq`). + +## 4. Acceptance Criteria + +- [ ] `BestProductsForFeatures` no longer inherits from `AbstractSentinel2`, contains no `super()` call, and retains all required state/methods internally. +- [ ] `AbstractSentinel1` and `AbstractSentinel2` implement the Facade + Proxy pattern with proper state invalidation on mutation. +- [ ] `Sentinel1Search` and `Sentinel2Search` dynamically build queries and delegate execution to `self.client` without duplicating state. +- [ ] Unit and live integration tests pass for both S1 and S2 wrappers. +- [ ] The codebase passes all project QA pipelines (`make pylint`, `make mypy`, `make precommit`, `make test`). + +## 5. Dependencies + +- Planetary Computer STAC API. +- `geospatial_tools.stac.core.StacSearch`, `Asset`, `PLANETARY_COMPUTER`. +- `geospatial_tools.geotools_types.BBoxLike`, `IntersectsLike`, `DateLike`. +- `geospatial_tools.stac.planetary_computer.constants.*` + +## 6. Out of Scope + +- Refactoring the internal logic of `BestProductsForFeatures` or its associated helper functions. +- Migrating `BestProductsForFeatures` to use the new `Sentinel2Search` builder pattern. + +## 7. Verification Plan + +- **QA Pipeline**: Run `make precommit`, `make pylint`, and `make mypy` to enforce type safety and code quality standards. +- **Unit Testing**: + - Verify base class instantiation raises `TypeError`. + - Verify builder methods mutate query state AND invalidate client state. + - Verify executable methods trigger searches correctly and generate proper query dictionaries. +- **Integration Testing**: + - `@pytest.mark.integration` tests pinning a specific bounding box and date range for both S1 and S2. + - Chain builder methods. + - Assert results are returned and possess the expected properties. + - Verify that existing legacy tests for `BestProductsForFeatures` still pass. diff --git a/docs/agents/planning/_completed/refactor-s2/tasks/task-01-isolate-legacy-code.md b/docs/agents/planning/_completed/refactor-s2/tasks/task-01-isolate-legacy-code.md new file mode 100644 index 0000000..4ef048c --- /dev/null +++ b/docs/agents/planning/_completed/refactor-s2/tasks/task-01-isolate-legacy-code.md @@ -0,0 +1,48 @@ +# TASK-01: Isolate Legacy Code (BestProductsForFeatures) + +## Goal + +Sever the inheritance between `BestProductsForFeatures` and `AbstractSentinel2` to isolate legacy logic and unblock the refactor of the underlying STAC query base classes. This enforces the "Composition over Inheritance" principle and eliminates tight coupling. + +## Context & References + +- **Source Plan**: `docs/agents/planning/refactor-s2/refactor-s2-plan.md` +- **Relevant Specs**: `docs/agents/planning/refactor-s2/refactor-s2-spec.md` +- **Existing Code**: `src/geospatial_tools/stac/planetary_computer/sentinel_2.py` + +## Subtasks + +1. [x] Remove `AbstractSentinel2` from `BestProductsForFeatures` class inheritance. +2. [x] Remove the `super().__init__(...)` call from `BestProductsForFeatures.__init__` (currently at `sentinel_2.py:173`). Move all referenced state variables (`date_ranges`, `max_cloud_cover`, `max_no_data_value`, `successful_results`, `incomplete_results`, `error_results`) directly into `BestProductsForFeatures.__init__`. +3. [x] Copy the `create_date_ranges` method from `AbstractSentinel2` directly into `BestProductsForFeatures`. +4. [x] Ensure `BestProductsForFeatures` does not depend on any state outside of its own instance. +5. [x] Replace `print(error)` with `LOGGER.warning(str(error))` in `sentinel_2_complete_tile_search` (`sentinel_2.py:327`). This `print` call will cause `make pylint` and `make precommit` to fail in task-04. + +## Requirements & Constraints + +- The `BestProductsForFeatures` class and associated module-level helper functions must function exactly as before. +- No changes should be made to the underlying logic of `BestProductsForFeatures.find_best_complete_products` or related execution logic. +- Code must remain type-safe according to `make mypy`. + +## Acceptance Criteria (AC) + +- [x] AC 1: `BestProductsForFeatures` no longer inherits from `AbstractSentinel2` and contains no `super()` calls. +- [x] AC 2: `BestProductsForFeatures` manages its own `date_ranges`, `max_cloud_cover`, and `max_no_data_value` state. +- [x] AC 3: `sentinel_2_complete_tile_search` uses `LOGGER.warning(str(error))` instead of `print(error)`. +- [x] AC 4: `make test` passes without regression for any existing legacy Sentinel 2 searches. + +## Testing & Validation + +- **Command**: `make test`, `make mypy`, `make pylint` +- **Success State**: All tests pass, zero type/linting errors introduced. +- **Manual Verification**: Review `BestProductsForFeatures` to ensure no residual super() calls or inherited properties are used. + +## Completion Protocol + +1. [x] All ACs are met. +2. [x] Tests pass without regressions. +3. [x] All new code passes the project's formating, linting and type-checking tools with zero errors. +4. [x] Commit work: `git commit -m "refactor: task 01 - isolate BestProductsForFeatures from AbstractSentinel2"` +5. [x] Update this document: Mark as COMPLETE. + +**STATUS: COMPLETE** diff --git a/docs/agents/planning/_completed/refactor-s2/tasks/task-02-implement-abstract-builders.md b/docs/agents/planning/_completed/refactor-s2/tasks/task-02-implement-abstract-builders.md new file mode 100644 index 0000000..d22a5b5 --- /dev/null +++ b/docs/agents/planning/_completed/refactor-s2/tasks/task-02-implement-abstract-builders.md @@ -0,0 +1,56 @@ +# TASK-02: Implement Abstract Builders (Facade + Proxy Pattern) + +## Goal + +Refactor both `AbstractSentinel1` and `AbstractSentinel2` into strict Abstract Base Classes (`abc.ABC`) providing a fluent builder pattern. They must act as pure Facades over `StacSearch`, managing query state while delegating execution and result storage exclusively to the underlying client via `@property` proxies. + +## Context & References + +- **Source Plan**: `docs/agents/planning/refactor-s2/refactor-s2-plan.md` +- **Relevant Specs**: `docs/agents/planning/refactor-s2/refactor-s2-spec.md` +- **Existing Code**: + - `src/geospatial_tools/stac/planetary_computer/sentinel_1.py` + - `src/geospatial_tools/stac/planetary_computer/sentinel_2.py` + +## Subtasks + +1. [x] **(TDD) Define interface contract first**: write the method signatures and docstrings for `_invalidate_state`, proxy properties, and builder methods before implementing. Then write **failing unit test stubs** for both `AbstractSentinel1` and `AbstractSentinel2` validating: + - Instantiation failure (`TypeError`) — requires at least one `@abstractmethod` per `KNOWLEDGE.md`. + - Builder methods mutate instance query state AND set `self.client.search_results = None` and `self.client.downloaded_search_assets = None`. + Tests will remain failing (red) until subtasks 5–7 are complete. +2. [x] Ensure `AbstractSentinel1` and `AbstractSentinel2` inherit from `abc.ABC`. +3. [x] Redefine `AbstractSentinel2.__init__` to accept spatial kwargs (`bbox`, `intersects`) and exactly one `date_range: DateLike`, matching the `AbstractSentinel1` signature. +4. [x] Instantiate `self.client = StacSearch(PLANETARY_COMPUTER)` within `__init__` for both classes. +5. [x] Remove duplicated state properties (`search_results`, `downloaded_assets`) from `AbstractSentinel1`'s `__init__`. +6. [x] Implement `@property` proxies for `search_results` and `downloaded_assets` in both base classes, delegating to `self.client.search_results` and `self.client.downloaded_search_assets` respectively. Do NOT store duplicate state. +7. [x] Implement a `_invalidate_state(self) -> None` method in both base classes that sets `self.client.search_results = None` and `self.client.downloaded_search_assets = None`. +8. [x] Ensure all fluent builder methods in both classes return `typing.Self` and explicitly call `self._invalidate_state()` before returning to prevent stale state: + - Sentinel-1: `filter_by_instrument_mode`, `filter_by_polarization`, `filter_by_orbit_state`, `with_custom_query` + - Sentinel-2: `filter_by_cloud_cover`, `filter_by_nodata_pixel_percentage`, `filter_by_mgrs_tile`, `with_custom_query` + +## Requirements & Constraints + +- Must use `typing.Self` for precise type hinting. +- Base classes must not execute any STAC searches or store duplicate result states. + +## Acceptance Criteria (AC) + +- [x] AC 1: Both abstract classes cannot be instantiated. +- [x] AC 2: `search_results` and `downloaded_assets` correctly proxy the underlying `StacSearch` state in both S1 and S2 wrappers. +- [x] AC 3: Calling any builder method explicitly invalidates the underlying `StacSearch` cached results. +- [x] AC 4: Unit tests pass and `make mypy` reports zero errors. + +## Testing & Validation + +- **Command**: `make test`, `make mypy` +- **Success State**: Unit tests pass. Static typing passes. + +## Completion Protocol + +1. [x] All ACs are met. +2. [x] Tests pass without regressions. +3. [x] All new code passes the project's formating, linting and type-checking tools with zero errors. +4. [x] Commit work: `git commit -m "feat: task 02 - implement Abstract Builders with Facade proxy pattern"` +5. [x] Update this document: Mark as COMPLETE. + +**STATUS: COMPLETE** diff --git a/docs/agents/planning/_completed/refactor-s2/tasks/task-03-implement-executable-wrappers.md b/docs/agents/planning/_completed/refactor-s2/tasks/task-03-implement-executable-wrappers.md new file mode 100644 index 0000000..35df45f --- /dev/null +++ b/docs/agents/planning/_completed/refactor-s2/tasks/task-03-implement-executable-wrappers.md @@ -0,0 +1,56 @@ +# TASK-03: Implement Sentinel1Search and Sentinel2Search Executable Wrappers + +## Goal + +Implement the concrete execution wrappers `Sentinel1Search` and `Sentinel2Search`. These classes dynamically translate their builder states into valid STAC queries and delegate asynchronous downloading to the underlying `StacSearch` client without storing redundant state. + +## Context & References + +- **Source Plan**: `docs/agents/planning/refactor-s2/refactor-s2-plan.md` +- **Relevant Specs**: `docs/agents/planning/refactor-s2/refactor-s2-spec.md` +- **Existing Code**: + - `src/geospatial_tools/stac/planetary_computer/sentinel_1.py` + - `src/geospatial_tools/stac/planetary_computer/sentinel_2.py` + +## Subtasks + +1. [x] **(TDD) Write unit tests first** for both `Sentinel1Search` and `Sentinel2Search` `search()` and `download()` methods validating: + - The STAC query dictionary is compiled correctly based on various permutations of builder state. + - The `download()` method properly triggers `search()` if no results are cached. +2. [x] Implement `Sentinel2Search.search()` and update `Sentinel1Search.search()` to: + - Dynamically construct a STAC query dict based on instance state. + - Execute `self.client.search(...)` using the computed query, `date_range`, `bbox`/`intersects`. + - Return `self.search_results` (which proxies `self.client.search_results`). **Delete the existing local assignments `self.search_results = self.client.search(...)` in `Sentinel1Search.search()` at `sentinel_1.py:131`** — the proxy property replaces them. +3. [x] Implement `Sentinel2Search.download()` and update `Sentinel1Search.download()` to: + - Assert `base_directory` is treated strictly as `pathlib.Path`. + - If `self.search_results` (the proxy property) is `None`, implicitly trigger `self.search()`. + - Call `self.client.download_search_results(...)` and return `self.downloaded_assets` (the proxy property). **Delete the existing local assignment `self.downloaded_assets = self.client.download_search_results(...)` in `Sentinel1Search.download()` at `sentinel_1.py:148`** — the proxy property replaces it. +4. [x] Avoid bare `except:` blocks; handle STAC errors explicitly. + +## Requirements & Constraints + +- Must use `PlanetaryComputerS1Property` and `PlanetaryComputerS2Property` for query keys to ensure correctness. +- Wrappers carry query-building state (`instrument_modes`, `polarizations`, `bbox`, `date_range`, etc.) but must NOT store execution results locally — all result access goes through the Facade proxy properties. +- Strict adherence to `pathlib.Path` in the `download` method. + +## Acceptance Criteria (AC) + +- [x] AC 1: `search()` methods generate valid STAC queries and delegate to `StacSearch` without storing local state. +- [x] AC 2: `download()` methods handle `pathlib.Path` correctly and trigger `search()` implicitly if needed. +- [x] AC 3: No duplicated state variables exist in either wrapper. +- [x] AC 4: Unit tests pass and `make mypy` reports zero errors. + +## Testing & Validation + +- **Command**: `make test`, `make mypy` +- **Success State**: Unit tests covering query dictionary construction and delegation logic pass. + +## Completion Protocol + +1. [x] All ACs are met. +2. [x] Tests pass without regressions. +3. [x] All new code passes the project's formating, linting and type-checking tools with zero errors. +4. [x] Commit work: `git commit -m "feat: task 03 - implement S1 and S2 executable wrappers"` +5. [x] Update this document: Mark as COMPLETE. + +**STATUS: COMPLETE** diff --git a/docs/agents/planning/_completed/refactor-s2/tasks/task-04-testing-and-qa.md b/docs/agents/planning/_completed/refactor-s2/tasks/task-04-testing-and-qa.md new file mode 100644 index 0000000..addde71 --- /dev/null +++ b/docs/agents/planning/_completed/refactor-s2/tasks/task-04-testing-and-qa.md @@ -0,0 +1,50 @@ +# TASK-04: Integration Testing & End-to-End Validation + +## Goal + +Verify the structural integrity, behavioral correctness, and API integration of the refactored Facade pattern across both `Sentinel1Search` and `Sentinel2Search`. Ensure complete compliance with the project QA pipelines. + +## Context & References + +- **Source Plan**: `docs/agents/planning/refactor-s2/refactor-s2-plan.md` +- **Relevant Specs**: `docs/agents/planning/refactor-s2/refactor-s2-spec.md` +- **Existing Code**: + - `tests/test_planetary_computer_sentinel1.py` + - `tests/test_planetary_computer_sentinel2.py` (or create if missing) + +## Subtasks + +1. [x] Update/write integration tests (`@pytest.mark.integration`) for both `Sentinel1Search` and `Sentinel2Search` that: + - Connect to the live PC STAC API. + - Pin a specific bounding box and date range. + - Chain multiple builder methods (e.g., optical filters for S2, radar filters for S1). + - Assert valid `pystac.Item` properties are returned. +2. [x] Verify that legacy searches using `BestProductsForFeatures` continue to pass without regression. +3. [x] Run `make pylint`, `make mypy`, `make precommit`, and `make test`. Resolve any QA failures across the codebase. + +## Requirements & Constraints + +- Integration tests must be explicitly marked with `@pytest.mark.integration` to prevent network requests during standard local testing if configured that way. + +## Acceptance Criteria (AC) + +- [x] AC 1: Live integration tests retrieve correct data reflecting chained filters for both S1 and S2. +- [x] AC 2: Legacy S2 searches function without regression. +- [x] AC 3: `make test` runs without failures. +- [x] AC 4: Code passes all project QA pipelines (`make pylint`, `make mypy`, `make precommit`). + +## Testing & Validation + +- **Command**: `make test`, `make mypy`, `make pylint`, `make precommit` +- **Success State**: All QA tools exit with code 0. +- **Manual Verification**: Ensure the integration tests pass against the live STAC endpoint. + +## Completion Protocol + +1. [x] All ACs are met. +2. [x] Tests pass without regressions. +3. [x] All new code passes the project's formating, linting and type-checking tools with zero errors. +4. [x] Commit work: `git commit -m "test: task 04 - end-to-end integration and QA validation"` +5. [x] Update this document: Mark as COMPLETE. + +**STATUS: COMPLETE** diff --git a/docs/agents/planning/relevant_copernicus_links.md b/docs/agents/planning/relevant_copernicus_links.md deleted file mode 100644 index 87f28e8..0000000 --- a/docs/agents/planning/relevant_copernicus_links.md +++ /dev/null @@ -1,27 +0,0 @@ -# Copernicus End Points and Links - -##STAC API Endpoints & Architecture Changes - -These pages detail the deprecation of the legacy endpoint, the promotion of the v1 endpoint, and the supported STAC extensions (like fields and query). - -[CDSE STAC API Official Documentation](https://documentation.dataspace.copernicus.eu/APIs/STAC.html) - -[Upcoming API Changes & Deprecation Notices (Crucial for 2025/2026)](https://documentation.dataspace.copernicus.eu/APIs/Others/UpcomingChanges.html) - -[CDSE STAC Browser (For visual inspection of the raw JSON metadata and collections)](https://browser.stac.dataspace.copernicus.eu/) - -## Sentinel-2 Band Resolutions & Naming Conventions - -These pages provide the exact ground sample distance (GSD) mappings, physical quantities, and how the Level-2A processor outputs the 10m, 20m, and 60m band variants. - -[Sentinel-2 L2A Band Mapping & Data Format (Sentinel Hub/CDSE)](https://documentation.dataspace.copernicus.eu/APIs/SentinelHub/Data/S2L2A.html) - -[Sentinel-2 Core Mission Documentation (Sensor specs and resolutions)](https://documentation.dataspace.copernicus.eu/Data/Sentinel2.html) - -## Collection Taxonomies & Harmonization - -If you are querying across different providers or building dynamic asset discovery tools, you need to understand how CDSE harmonizes its collection and band names. - -[CDSE Collection Naming Conventions & Harmonization Guidelines](https://documentation.dataspace.copernicus.eu/APIs/openEO/federation/backends/collections.html) - -[List of Main Data Collections in the Ecosystem](https://dataspace.copernicus.eu/data-collections/copernicus-sentinel-missions) diff --git a/docs/agents/planning/stac_current_structure.md b/docs/agents/planning/stac_current_structure.md deleted file mode 100644 index f1dfeec..0000000 --- a/docs/agents/planning/stac_current_structure.md +++ /dev/null @@ -1,67 +0,0 @@ -# STAC Search and Download Structure - -This document outlines the current structure, tools, and approaches used in `geospatial_tools` to search and download images from the Planetary Computer's STAC catalog, based on `src/geospatial_tools/stac.py` and `src/geospatial_tools/utils.py`. - -## 1. Core Components - -The functionality is primarily encapsulated in the `stac.py` module, which leverages `pystac` and `pystac_client` for STAC interactions. - -### 1.1. Catalog Management - -- **`create_planetary_computer_catalog`**: Creates a `pystac_client.Client` specifically for the Microsoft Planetary Computer API (`https://planetarycomputer.microsoft.com/api/stac/v1`). It includes retry logic and uses `planetary_computer.sign_inplace` to sign assets for access. -- **`catalog_generator`**: A factory function to retrieve a STAC client based on a catalog name. Currently, only "planetary_computer" is supported. -- **`list_available_catalogs`**: Returns the list of supported catalogs (currently just `PLANETARY_COMPUTER`). - -### 1.2. Data Structures - -- **`AssetSubItem`**: Represents a single downloaded file (e.g., a specific band of a satellite image). It holds the reference to the original STAC Item, the item ID, the band name, and the local filename/path. -- **`Asset`**: Represents a logical asset, which can contain multiple `AssetSubItem`s (bands). It manages: - - `asset_id`: The ID of the STAC Item. - - `bands`: List of bands associated with this asset. - - `list`: A list of `AssetSubItem` objects. - - `merged_asset_path`: Path to the merged raster file (if merged). - - `reprojected_asset_path`: Path to the reprojected raster file (if reprojected). - - **Methods**: - - `add_asset_item`: Adds a sub-item. - - `merge_asset`: Merges the downloaded bands into a single raster using `geospatial_tools.raster.merge_raster_bands`. - - `reproject_merged_asset`: Reprojects the merged asset using `geospatial_tools.raster.reproject_raster`. - - Cleanup methods: `delete_asset_sub_items`, `delete_merged_asset`, `delete_reprojected_asset`. - -### 1.3. Search Logic (`StacSearch` Class) - -The `StacSearch` class is the main entry point for searching and downloading data. - -- **Initialization**: Takes a `catalog_name` and initializes the corresponding `pystac_client.Client`. -- **Search Methods**: - - **`search`**: A wrapper around `client.search()`. It accepts standard STAC search parameters (date_range, bbox, collections, query, etc.) and handles retries. - - **`search_for_date_ranges`**: Iterates over a list of date ranges and performs a search for each, aggregating the results. This is useful for discontinuous time periods. -- **Filtering and Sorting**: - - **`sort_results_by_cloud_coverage`**: Sorts the search results based on the `eo:cloud_cover` property (ascending). - - **`filter_no_data`**: Filters results based on a maximum threshold for a specific property (often used for nodata values, though the implementation checks `item.properties[property_name] < max_no_data_value`). -- **Download Methods**: - - **`download_search_results`**: Downloads assets for *all* search results. - - **`download_sorted_by_cloud_cover_search_results`**: Sorts results by cloud cover (if not already sorted) and downloads the top `first_x_num_of_items` (or all if not specified). - - **`download_best_cloud_cover_result`**: Downloads only the single result with the lowest cloud cover. - - **`_download_assets`**: Internal method that iterates through requested bands, checks availability in the STAC Item, and downloads them using `geospatial_tools.utils.download_url`. - -## 2. Utilities (`utils.py`) - -Helper functions used by the STAC module: - -- **`download_url`**: Handles the actual HTTP GET request to download a file from a URL to a local path. It includes checks for existing files to avoid re-downloading. -- **`create_date_range_for_specific_period`**: Generates a list of ISO 8601 date range strings (e.g., "2020-03-01T00:00:00Z/2020-05-31T23:59:59Z") given start/end years and start/end months. This is used in conjunction with `search_for_date_ranges`. -- **`create_logger`**: Standard logging setup. - -## 3. Workflow Summary - -1. **Initialize**: Create a `StacSearch` object with "planetary_computer". -2. **Search**: Call `search()` or `search_for_date_ranges()` with criteria (collections, bbox, datetime, etc.). -3. **Process Results**: - - Optionally sort by cloud cover (`sort_results_by_cloud_coverage`). - - Optionally filter by other properties (`filter_no_data`). -4. **Download**: Call one of the download methods (`download_search_results`, `download_best_cloud_cover_result`, etc.) specifying the desired bands and a base directory. - - This triggers `_download_assets`, which uses `utils.download_url`. - - Returns `Asset` objects containing `AssetSubItem`s. -5. **Post-Processing (Optional)**: - - Use `Asset.merge_asset()` to combine bands into a single file. - - Use `Asset.reproject_merged_asset()` to reproject the merged file. diff --git a/notebooks/copernicus_sentinel2_exploration.ipynb b/notebooks/copernicus_sentinel2_exploration.ipynb index 79b3b1f..db233bc 100644 --- a/notebooks/copernicus_sentinel2_exploration.ipynb +++ b/notebooks/copernicus_sentinel2_exploration.ipynb @@ -23,14 +23,23 @@ }, { "cell_type": "code", - "execution_count": 1, "id": "imports", "metadata": { "ExecuteTime": { - "end_time": "2026-04-13T18:50:52.982123262Z", - "start_time": "2026-04-13T18:50:50.873548224Z" + "end_time": "2026-04-20T19:17:17.476535477Z", + "start_time": "2026-04-20T19:17:15.013752457Z" } }, + "source": [ + "\n", + "import leafmap\n", + "from geospatial_tools.stac.core import StacSearch, COPERNICUS\n", + "from geospatial_tools.stac.copernicus import CopernicusS2Collection, CopernicusS2Band\n", + "from geospatial_tools import DATA_DIR\n", + "\n", + "# The .env file is automatically loaded via geospatial_tools.__init__\n", + "print(f\"Data Directory: {DATA_DIR}\")" + ], "outputs": [ { "name": "stdout", @@ -40,17 +49,7 @@ ] } ], - "source": [ - "import os\n", - "from pathlib import Path\n", - "import leafmap\n", - "from geospatial_tools.stac import StacSearch, COPERNICUS\n", - "from geospatial_tools.copernicus.sentinel_2 import CopernicusS2Collection, CopernicusS2Band\n", - "from geospatial_tools import DATA_DIR\n", - "\n", - "# The .env file is automatically loaded via geospatial_tools.__init__\n", - "print(f\"Data Directory: {DATA_DIR}\")" - ] + "execution_count": 1 }, { "cell_type": "markdown", @@ -64,14 +63,21 @@ }, { "cell_type": "code", - "execution_count": 2, "id": "search_params", "metadata": { "ExecuteTime": { - "end_time": "2026-04-13T18:50:53.047974505Z", - "start_time": "2026-04-13T18:50:52.984235300Z" + "end_time": "2026-04-20T19:17:17.536593730Z", + "start_time": "2026-04-20T19:17:17.479422100Z" } }, + "source": [ + "# Bounding box for Rome [min_lon, min_lat, max_lon, max_lat]\n", + "bbox = [12.4, 41.8, 12.5, 41.9]\n", + "date_range = \"2024-07-01/2024-07-31\"\n", + "collections = [CopernicusS2Collection.L2A]\n", + "\n", + "print(f\"Searching in {bbox} for period {date_range}...\")" + ], "outputs": [ { "name": "stdout", @@ -81,14 +87,7 @@ ] } ], - "source": [ - "# Bounding box for Rome [min_lon, min_lat, max_lon, max_lat]\n", - "bbox = [12.4, 41.8, 12.5, 41.9]\n", - "date_range = \"2024-07-01/2024-07-31\"\n", - "collections = [CopernicusS2Collection.L2A]\n", - "\n", - "print(f\"Searching in {bbox} for period {date_range}...\")" - ] + "execution_count": 2 }, { "cell_type": "markdown", @@ -102,25 +101,13 @@ }, { "cell_type": "code", - "execution_count": 3, "id": "search_exec", "metadata": { "ExecuteTime": { - "end_time": "2026-04-13T18:50:54.769506010Z", - "start_time": "2026-04-13T18:50:53.058684946Z" + "end_time": "2026-04-20T19:17:19.332490989Z", + "start_time": "2026-04-20T19:17:17.545800427Z" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[2026-04-13 14:53:30] INFO [MainThread][geospatial_tools.s3_utils] Creating S3 client with endpoint: [https://eodata.dataspace.copernicus.eu]\n", - "[2026-04-13 14:53:30] INFO [MainThread][geospatial_tools.stac] Initiating STAC API search\n", - "Found 1 items.\n" - ] - } - ], "source": [ "stac_search = StacSearch(catalog_name=COPERNICUS)\n", "\n", @@ -132,7 +119,19 @@ ")\n", "\n", "print(f\"Found {len(results)} items.\")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2026-04-20 15:17:18] INFO [MainThread][geospatial_tools.stac.utils] Creating S3 client with endpoint: [https://eodata.dataspace.copernicus.eu]\n", + "[2026-04-20 15:17:18] INFO [MainThread][geospatial_tools.stac.core] Initiating STAC API search\n", + "Found 1 items.\n" + ] + } + ], + "execution_count": 3 }, { "cell_type": "markdown", @@ -146,14 +145,23 @@ }, { "cell_type": "code", - "execution_count": 4, "id": "inspect_exec", "metadata": { "ExecuteTime": { - "end_time": "2026-04-13T18:50:54.875089804Z", - "start_time": "2026-04-13T18:50:54.817556767Z" + "end_time": "2026-04-20T19:17:19.458197525Z", + "start_time": "2026-04-20T19:17:19.387585840Z" } }, + "source": [ + "if results:\n", + " item = results[0]\n", + " print(f\"Item ID: {item.id}\")\n", + " print(f\"Cloud Cover: {item.properties.get('eo:cloud_cover')}% \")\n", + " \n", + " # List a few bands/assets\n", + " available_assets = list(item.assets.keys())\n", + " print(f\"First 10 assets: {available_assets[:10]}\")" + ], "outputs": [ { "name": "stdout", @@ -165,16 +173,7 @@ ] } ], - "source": [ - "if results:\n", - " item = results[0]\n", - " print(f\"Item ID: {item.id}\")\n", - " print(f\"Cloud Cover: {item.properties.get('eo:cloud_cover')}% \")\n", - " \n", - " # List a few bands/assets\n", - " available_assets = list(item.assets.keys())\n", - " print(f\"First 10 assets: {available_assets[:10]}\")" - ] + "execution_count": 4 }, { "cell_type": "markdown", @@ -196,33 +195,13 @@ }, { "cell_type": "code", - "execution_count": 5, "id": "download_exec", "metadata": { "ExecuteTime": { - "end_time": "2026-04-13T18:51:05.058278079Z", - "start_time": "2026-04-13T18:50:54.884830158Z" + "end_time": "2026-04-20T19:17:36.385073891Z", + "start_time": "2026-04-20T19:17:19.470039913Z" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Downloading bands [TCI_10m, B08_10m] to /home/francispelletier/projects/geospatial_tools/data/sentinel-2/copernicus_exploration via S3...\n", - "[2026-04-13 14:53:31] INFO [MainThread][geospatial_tools.stac] Downloading [S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034] ...\n", - "[2026-04-13 14:53:31] INFO [MainThread][geospatial_tools.stac] Retrieving Copernicus credentials...\n", - "[2026-04-13 14:53:31] INFO [MainThread][geospatial_tools.stac] Successfully retrieved Copernicus credentials.\n", - "[2026-04-13 14:53:32] INFO [MainThread][geospatial_tools.stac] Successfully obtained Copernicus access token.\n", - "[2026-04-13 14:53:32] INFO [MainThread][geospatial_tools.stac] Downloading TCI_10m from s3://eodata/Sentinel-2/MSI/L2A/2024/07/28/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034.SAFE/GRANULE/L2A_T33TTG_A038615_20240728T095731/IMG_DATA/R10m/T33TTG_20240728T095549_TCI_10m.jp2 using method [s3]\n", - "[2026-04-13 14:53:32] INFO [MainThread][geospatial_tools.stac] Downloading from S3: bucket=[eodata], key=[Sentinel-2/MSI/L2A/2024/07/28/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034.SAFE/GRANULE/L2A_T33TTG_A038615_20240728T095731/IMG_DATA/R10m/T33TTG_20240728T095549_TCI_10m.jp2] to [/home/francispelletier/projects/geospatial_tools/data/sentinel-2/copernicus_exploration/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034_TCI_10m.tif]\n", - "[2026-04-13 14:53:40] INFO [MainThread][geospatial_tools.stac] Downloading B08_10m from s3://eodata/Sentinel-2/MSI/L2A/2024/07/28/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034.SAFE/GRANULE/L2A_T33TTG_A038615_20240728T095731/IMG_DATA/R10m/T33TTG_20240728T095549_B08_10m.jp2 using method [s3]\n", - "[2026-04-13 14:53:40] INFO [MainThread][geospatial_tools.stac] Downloading from S3: bucket=[eodata], key=[Sentinel-2/MSI/L2A/2024/07/28/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034.SAFE/GRANULE/L2A_T33TTG_A038615_20240728T095731/IMG_DATA/R10m/T33TTG_20240728T095549_B08_10m.jp2] to [/home/francispelletier/projects/geospatial_tools/data/sentinel-2/copernicus_exploration/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034_B08_10m.tif]\n", - "[2026-04-13 14:53:46] INFO [MainThread][geospatial_tools.stac] Asset list for asset [S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034] :\n", - "\t['ID: [S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034], Band: [TCI_10m], filename: [/home/francispelletier/projects/geospatial_tools/data/sentinel-2/copernicus_exploration/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034_TCI_10m.tif]', 'ID: [S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034], Band: [B08_10m], filename: [/home/francispelletier/projects/geospatial_tools/data/sentinel-2/copernicus_exploration/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034_B08_10m.tif]']\n" - ] - } - ], "source": [ "download_dir = DATA_DIR / \"sentinel-2\" / \"copernicus_exploration\"\n", "download_dir.mkdir(parents=True, exist_ok=True)\n", @@ -242,41 +221,61 @@ "\n", "for asset in downloaded_assets:\n", " asset.show_asset_items()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading bands [, ] to /home/francispelletier/projects/geospatial_tools/data/sentinel-2/copernicus_exploration via S3...\n", + "[2026-04-20 15:17:19] INFO [MainThread][geospatial_tools.stac.core] Downloading [S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034] ...\n", + "[2026-04-20 15:17:19] INFO [MainThread][geospatial_tools.stac.core] Retrieving Copernicus credentials...\n", + "[2026-04-20 15:17:19] INFO [MainThread][geospatial_tools.stac.core] Successfully retrieved Copernicus credentials.\n", + "[2026-04-20 15:17:20] INFO [MainThread][geospatial_tools.stac.core] Successfully obtained Copernicus access token.\n", + "[2026-04-20 15:17:20] INFO [MainThread][geospatial_tools.stac.core] Downloading TCI_10m from s3://eodata/Sentinel-2/MSI/L2A/2024/07/28/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034.SAFE/GRANULE/L2A_T33TTG_A038615_20240728T095731/IMG_DATA/R10m/T33TTG_20240728T095549_TCI_10m.jp2 using method [s3]\n", + "[2026-04-20 15:17:20] INFO [MainThread][geospatial_tools.stac.core] Downloading from S3: bucket=[eodata], key=[Sentinel-2/MSI/L2A/2024/07/28/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034.SAFE/GRANULE/L2A_T33TTG_A038615_20240728T095731/IMG_DATA/R10m/T33TTG_20240728T095549_TCI_10m.jp2] to [/home/francispelletier/projects/geospatial_tools/data/sentinel-2/copernicus_exploration/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034_TCI_10m.tif]\n", + "[2026-04-20 15:17:30] INFO [MainThread][geospatial_tools.stac.core] Downloading B08_10m from s3://eodata/Sentinel-2/MSI/L2A/2024/07/28/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034.SAFE/GRANULE/L2A_T33TTG_A038615_20240728T095731/IMG_DATA/R10m/T33TTG_20240728T095549_B08_10m.jp2 using method [s3]\n", + "[2026-04-20 15:17:30] INFO [MainThread][geospatial_tools.stac.core] Downloading from S3: bucket=[eodata], key=[Sentinel-2/MSI/L2A/2024/07/28/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034.SAFE/GRANULE/L2A_T33TTG_A038615_20240728T095731/IMG_DATA/R10m/T33TTG_20240728T095549_B08_10m.jp2] to [/home/francispelletier/projects/geospatial_tools/data/sentinel-2/copernicus_exploration/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034_B08_10m.tif]\n", + "[2026-04-20 15:17:36] INFO [MainThread][geospatial_tools.stac.core] Asset list for asset [S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034] :\n", + "\t['ID: [S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034], Band: [TCI_10m], filename: [/home/francispelletier/projects/geospatial_tools/data/sentinel-2/copernicus_exploration/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034_TCI_10m.tif]', 'ID: [S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034], Band: [B08_10m], filename: [/home/francispelletier/projects/geospatial_tools/data/sentinel-2/copernicus_exploration/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034_B08_10m.tif]']\n" + ] + } + ], + "execution_count": 5 }, { "cell_type": "code", - "execution_count": 6, "id": "17afc08e6f4682c6", "metadata": { "ExecuteTime": { - "end_time": "2026-04-13T18:52:00.383906280Z", - "start_time": "2026-04-13T18:52:00.158839725Z" + "end_time": "2026-04-20T19:17:37.612667941Z", + "start_time": "2026-04-20T19:17:36.433960630Z" } }, + "source": [ + "tci_asset = downloaded_assets[0][CopernicusS2Band.TCI]\n", + "m = leafmap.Map()\n", + "m.add_raster(source=str(tci_asset.filename))\n", + "m" + ], "outputs": [ { "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "eb8f6e50bf5945648dd685403ba2014a", - "version_major": 2, - "version_minor": 0 - }, "text/plain": [ "Map(center=[41.9185435, 12.0389935], controls=(ZoomControl(options=['position', 'zoom_in_text', 'zoom_in_title…" - ] + ], + "application/vnd.jupyter.widget-view+json": { + "version_major": 2, + "version_minor": 0, + "model_id": "578ae0712ee54a7f97460264ffdc75cb" + } }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], - "source": [ - "tci_asset = downloaded_assets[0][CopernicusS2Band.TCI]\n", - "m = leafmap.Map()\n", - "m.add_raster(source=str(tci_asset.filename))\n", - "m" - ] + "execution_count": 6 }, { "cell_type": "markdown", diff --git a/notebooks/planetary_computer_sentinel2_exploration.ipynb b/notebooks/planetary_computer_sentinel2_exploration.ipynb index 5f73455..f7ce0e4 100644 --- a/notebooks/planetary_computer_sentinel2_exploration.ipynb +++ b/notebooks/planetary_computer_sentinel2_exploration.ipynb @@ -6,8 +6,8 @@ "id": "initial_id", "metadata": { "ExecuteTime": { - "end_time": "2026-01-29T21:49:37.845965444Z", - "start_time": "2026-01-29T21:49:35.493264346Z" + "end_time": "2026-04-02T21:28:00.668107999Z", + "start_time": "2026-04-02T21:27:59.443091140Z" } }, "outputs": [], @@ -15,9 +15,9 @@ "import leafmap\n", "import geopandas as gpd\n", "from geospatial_tools import DATA_DIR\n", - "from geospatial_tools.planetary_computer.sentinel_2 import BestProductsForFeatures, download_and_process_sentinel2_asset\n", + "from geospatial_tools.stac.planetary_computer.sentinel_2 import BestProductsForFeatures, download_and_process_sentinel2_asset\n", "from geospatial_tools.raster import clip_raster_with_polygon\n", - "from geospatial_tools.stac import Asset\n", + "from geospatial_tools.stac.core import Asset\n", "from geospatial_tools.utils import get_yaml_config, download_url, unzip_file\n", "from geospatial_tools.vector import create_vector_grid_parallel, to_geopackage, select_polygons_by_location" ] @@ -55,16 +55,26 @@ "id": "687ac922509bf0e4", "metadata": { "ExecuteTime": { - "end_time": "2026-01-29T21:49:37.926580867Z", - "start_time": "2026-01-29T21:49:37.848648030Z" + "end_time": "2026-04-02T21:28:00.677863192Z", + "start_time": "2026-04-02T21:28:00.669607793Z" } }, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2026-04-02 17:28:00] INFO [MainThread][geospatial_tools.utils] Yaml config file [/home/dev/projects/geospatial-tools/configs/data_file_links.yaml] found.\n", + "[2026-04-02 17:28:00] INFO [MainThread][geospatial_tools.utils] Loading YAML config file [/home/dev/projects/geospatial-tools/configs/data_file_links.yaml].\n", + "[2026-04-02 17:28:00] INFO [MainThread][geospatial_tools.utils] File [/home/dev/projects/geospatial-tools/data/raw_usa_polygon.zip] already exists. Skipping download.\n", + "[2026-04-02 17:28:00] INFO [MainThread][geospatial_tools.utils] File [/home/dev/projects/geospatial-tools/data/raw_s2_tiling_grid.zip] already exists. Skipping download.\n" + ] + }, { "data": { "text/plain": [ - "[PosixPath('/home/francispelletier/projects/geospatial_tools/data/raw_usa_polygon.zip'),\n", - " PosixPath('/home/francispelletier/projects/geospatial_tools/data/raw_s2_tiling_grid.zip')]" + "[PosixPath('/home/dev/projects/geospatial-tools/data/raw_usa_polygon.zip'),\n", + " PosixPath('/home/dev/projects/geospatial-tools/data/raw_s2_tiling_grid.zip')]" ] }, "execution_count": 2, @@ -89,22 +99,36 @@ "id": "26a5535d1d05fbbe", "metadata": { "ExecuteTime": { - "end_time": "2026-01-29T21:49:38.536778254Z", - "start_time": "2026-01-29T21:49:37.927928176Z" + "end_time": "2026-04-02T21:28:00.913185284Z", + "start_time": "2026-04-02T21:28:00.678436612Z" } }, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2026-04-02 17:28:00] INFO [MainThread][geospatial_tools.utils] Extracted: [cb_2018_us_nation_20m.shp.ea.iso.xml]\n", + "[2026-04-02 17:28:00] INFO [MainThread][geospatial_tools.utils] Extracted: [cb_2018_us_nation_20m.shp.iso.xml]\n", + "[2026-04-02 17:28:00] INFO [MainThread][geospatial_tools.utils] Extracted: [cb_2018_us_nation_20m.shp]\n", + "[2026-04-02 17:28:00] INFO [MainThread][geospatial_tools.utils] Extracted: [cb_2018_us_nation_20m.shx]\n", + "[2026-04-02 17:28:00] INFO [MainThread][geospatial_tools.utils] Extracted: [cb_2018_us_nation_20m.dbf]\n", + "[2026-04-02 17:28:00] INFO [MainThread][geospatial_tools.utils] Extracted: [cb_2018_us_nation_20m.prj]\n", + "[2026-04-02 17:28:00] INFO [MainThread][geospatial_tools.utils] Extracted: [cb_2018_us_nation_20m.cpg]\n", + "[2026-04-02 17:28:00] INFO [MainThread][geospatial_tools.utils] Extracted: [S2A_OPER_GIP_TILPAR_MPC__20151209T095117_V20150622T000000_21000101T000000_B00.kml]\n" + ] + }, { "data": { "text/plain": [ - "[['/home/francispelletier/projects/geospatial_tools/data/cb_2018_us_nation_20m.shp.ea.iso.xml',\n", - " '/home/francispelletier/projects/geospatial_tools/data/cb_2018_us_nation_20m.shp.iso.xml',\n", - " '/home/francispelletier/projects/geospatial_tools/data/cb_2018_us_nation_20m.shp',\n", - " '/home/francispelletier/projects/geospatial_tools/data/cb_2018_us_nation_20m.shx',\n", - " '/home/francispelletier/projects/geospatial_tools/data/cb_2018_us_nation_20m.dbf',\n", - " '/home/francispelletier/projects/geospatial_tools/data/cb_2018_us_nation_20m.prj',\n", - " '/home/francispelletier/projects/geospatial_tools/data/cb_2018_us_nation_20m.cpg'],\n", - " ['/home/francispelletier/projects/geospatial_tools/data/S2A_OPER_GIP_TILPAR_MPC__20151209T095117_V20150622T000000_21000101T000000_B00.kml']]" + "[['/home/dev/projects/geospatial-tools/data/cb_2018_us_nation_20m.shp.ea.iso.xml',\n", + " '/home/dev/projects/geospatial-tools/data/cb_2018_us_nation_20m.shp.iso.xml',\n", + " '/home/dev/projects/geospatial-tools/data/cb_2018_us_nation_20m.shp',\n", + " '/home/dev/projects/geospatial-tools/data/cb_2018_us_nation_20m.shx',\n", + " '/home/dev/projects/geospatial-tools/data/cb_2018_us_nation_20m.dbf',\n", + " '/home/dev/projects/geospatial-tools/data/cb_2018_us_nation_20m.prj',\n", + " '/home/dev/projects/geospatial-tools/data/cb_2018_us_nation_20m.cpg'],\n", + " ['/home/dev/projects/geospatial-tools/data/S2A_OPER_GIP_TILPAR_MPC__20151209T095117_V20150622T000000_21000101T000000_B00.kml']]" ] }, "execution_count": 3, @@ -143,8 +167,8 @@ "id": "ff487d19985d9368", "metadata": { "ExecuteTime": { - "end_time": "2026-01-29T21:49:38.640837572Z", - "start_time": "2026-01-29T21:49:38.584766210Z" + "end_time": "2026-04-02T21:28:00.962233236Z", + "start_time": "2026-04-02T21:28:00.914204016Z" } }, "outputs": [], @@ -161,8 +185,8 @@ "id": "2767e8432a15bb65", "metadata": { "ExecuteTime": { - "end_time": "2026-01-29T21:49:38.697289852Z", - "start_time": "2026-01-29T21:49:38.642323833Z" + "end_time": "2026-04-02T21:28:00.972160557Z", + "start_time": "2026-04-02T21:28:00.962729328Z" } }, "outputs": [ @@ -228,8 +252,8 @@ "id": "a267092e24a179c7", "metadata": { "ExecuteTime": { - "end_time": "2026-01-29T21:49:38.863936374Z", - "start_time": "2026-01-29T21:49:38.773606241Z" + "end_time": "2026-04-02T21:28:00.980815439Z", + "start_time": "2026-04-02T21:28:00.972758377Z" } }, "outputs": [ @@ -388,8 +412,8 @@ "id": "8bb6ee92232d84c9", "metadata": { "ExecuteTime": { - "end_time": "2026-01-29T21:49:40.242367829Z", - "start_time": "2026-01-29T21:49:39.897771706Z" + "end_time": "2026-04-02T21:28:01.353213283Z", + "start_time": "2026-04-02T21:28:00.981538907Z" } }, "outputs": [ @@ -441,8 +465,8 @@ "id": "7421bd3db699e931", "metadata": { "ExecuteTime": { - "end_time": "2026-01-29T21:49:40.329287852Z", - "start_time": "2026-01-29T21:49:40.281814356Z" + "end_time": "2026-04-02T21:28:01.430967466Z", + "start_time": "2026-04-02T21:28:01.426740658Z" } }, "outputs": [], @@ -458,15 +482,34 @@ "id": "22a58aa5480b7579", "metadata": { "ExecuteTime": { - "end_time": "2026-01-29T21:49:49.746473082Z", - "start_time": "2026-01-29T21:49:40.330652034Z" + "end_time": "2026-04-02T21:28:10.717860571Z", + "start_time": "2026-04-02T21:28:01.431443268Z" } }, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Starting processing for [create_vector_grid_parallel]\n", + "[2026-04-02 17:28:01] INFO [MainThread][geospatial_tools.vector] Creating grid coordinates for bounding box [[-2356113.74289801 301469.31619713 2258154.44089948 3165721.6501298 ]]\n", + "[2026-04-02 17:28:01] INFO [MainThread][geospatial_tools.vector] Creating flattened grid coordinates\n", + "[2026-04-02 17:28:01] INFO [MainThread][geospatial_tools.vector] Number of workers used: 16\n", + "[2026-04-02 17:28:01] INFO [MainThread][geospatial_tools.vector] Allocating polygon array for [528879] polygons\n", + "[2026-04-02 17:28:01] INFO [MainThread][geospatial_tools.vector] Creating polygons from chunks\n", + "[2026-04-02 17:28:05] INFO [MainThread][geospatial_tools.vector] Managing properties\n", + "[2026-04-02 17:28:05] INFO [MainThread][geospatial_tools.utils] Creating EPSG code from following input : [EPSG:5070]\n", + "[2026-04-02 17:28:05] INFO [MainThread][geospatial_tools.vector] Creating spatial index\n", + "[2026-04-02 17:28:05] INFO [MainThread][geospatial_tools.vector] Generating polygon UUIDs\n", + "Printing len(grid_parallel) to check if grid contains same amount of polygons : 528879\n", + "[2026-04-02 17:28:07] INFO [MainThread][geospatial_tools.vector] Starting writing process\n", + "[2026-04-02 17:28:10] INFO [MainThread][geospatial_tools.vector] File [/home/dev/projects/geospatial-tools/data/polygon_grid_5km.gpkg] took 3.3827707767486572 seconds to write.\n" + ] + }, { "data": { "text/plain": [ - "PosixPath('/home/francispelletier/projects/geospatial_tools/data/polygon_grid_5km.gpkg')" + "PosixPath('/home/dev/projects/geospatial-tools/data/polygon_grid_5km.gpkg')" ] }, "execution_count": 9, @@ -487,8 +530,8 @@ "id": "684ba7ab957db26b", "metadata": { "ExecuteTime": { - "end_time": "2026-01-29T21:49:49.870865654Z", - "start_time": "2026-01-29T21:49:49.816949919Z" + "end_time": "2026-04-02T21:28:10.827927850Z", + "start_time": "2026-04-02T21:28:10.818485781Z" } }, "outputs": [ @@ -521,27 +564,27 @@ " \n", " 0\n", " POLYGON ((-2356113.743 301469.316, -2351113.74...\n", - " 85093ed6-a3e6-4e93-adc8-e94d931e4a4b\n", + " ec75a129-ddf6-44cf-95e1-b51e70228399\n", " \n", " \n", " 1\n", " POLYGON ((-2351113.743 301469.316, -2346113.74...\n", - " f9cf7576-f5d4-42a9-8c81-5dd99b4a98e8\n", + " c970f076-7059-4a86-9f35-ed702f017423\n", " \n", " \n", " 2\n", " POLYGON ((-2346113.743 301469.316, -2341113.74...\n", - " 95fd96bf-5803-429a-9f5e-a01f3d86e938\n", + " 7c62f9f8-934d-45e3-a439-3a2389de4012\n", " \n", " \n", " 3\n", " POLYGON ((-2341113.743 301469.316, -2336113.74...\n", - " 8fb98f6b-e669-4f46-a917-75720bff49e2\n", + " 656dbf77-6940-4d52-a292-fa3472cb2481\n", " \n", " \n", " 4\n", " POLYGON ((-2336113.743 301469.316, -2331113.74...\n", - " 797430df-c0e5-48b4-a0bd-677d989773ab\n", + " 4c9d715b-71ee-4aec-8345-81bf87fc7951\n", " \n", " \n", " ...\n", @@ -551,27 +594,27 @@ " \n", " 528874\n", " POLYGON ((2233886.257 3161469.316, 2238886.257...\n", - " 59daf2ca-7350-464f-924d-44b5f176e715\n", + " 7a60b2db-a198-4972-a034-08840d11095f\n", " \n", " \n", " 528875\n", " POLYGON ((2238886.257 3161469.316, 2243886.257...\n", - " 9d59463b-1f0f-4e4f-9ea8-ef41d0a81e4f\n", + " 128ae73b-e96e-49f2-84c9-1f15352b1f11\n", " \n", " \n", " 528876\n", " POLYGON ((2243886.257 3161469.316, 2248886.257...\n", - " 37bb15c2-06fc-4fae-9454-315bdb40d315\n", + " 2e1d6d10-d55a-4ccd-8137-6e9670c1a90c\n", " \n", " \n", " 528877\n", " POLYGON ((2248886.257 3161469.316, 2253886.257...\n", - " abed9791-a490-40b7-8511-2e7f457ad192\n", + " b4859991-92ec-4c9c-8fd0-5c3b0c422494\n", " \n", " \n", " 528878\n", " POLYGON ((2253886.257 3161469.316, 2258886.257...\n", - " a74aee60-206b-4527-90ee-661c3d4d8a4e\n", + " 1949821d-cc04-4143-ac08-e91eedccd968\n", " \n", " \n", "\n", @@ -638,15 +681,28 @@ "id": "1e60a89eaeda85d5", "metadata": { "ExecuteTime": { - "end_time": "2026-01-29T21:49:58.777308041Z", - "start_time": "2026-01-29T21:49:49.951897044Z" + "end_time": "2026-04-02T21:28:19.631468320Z", + "start_time": "2026-04-02T21:28:10.829075991Z" } }, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Starting intersect selection\n", + "[2026-04-02 17:28:10] INFO [MainThread][geospatial_tools.vector] Number of workers used: 4\n", + "[2026-04-02 17:28:10] INFO [MainThread][geospatial_tools.vector] Concatenating results\n", + "[2026-04-02 17:28:17] INFO [MainThread][geospatial_tools.vector] Creating spatial index\n", + "[2026-04-02 17:28:17] INFO [MainThread][geospatial_tools.vector] Filtering columns of the results\n", + "[2026-04-02 17:28:17] INFO [MainThread][geospatial_tools.vector] Starting writing process\n", + "[2026-04-02 17:28:19] INFO [MainThread][geospatial_tools.vector] File [/home/dev/projects/geospatial-tools/data/intersecting_polygon_grid_5km.gpkg] took 2.063347101211548 seconds to write.\n" + ] + }, { "data": { "text/plain": [ - "PosixPath('/home/francispelletier/projects/geospatial_tools/data/intersecting_polygon_grid_5km.gpkg')" + "PosixPath('/home/dev/projects/geospatial-tools/data/intersecting_polygon_grid_5km.gpkg')" ] }, "execution_count": 11, @@ -669,8 +725,8 @@ "id": "2f1db61027a3a573", "metadata": { "ExecuteTime": { - "end_time": "2026-01-29T21:50:01.999031288Z", - "start_time": "2026-01-29T21:50:01.947571276Z" + "end_time": "2026-04-02T21:28:19.925589940Z", + "start_time": "2026-04-02T21:28:19.910250060Z" } }, "outputs": [ @@ -701,29 +757,29 @@ " \n", " \n", " \n", - " 0\n", + " 774\n", " POLYGON ((1513886.257 301469.316, 1518886.257 ...\n", - " eac0413f-10d9-411b-ba46-0e80c1c6fac4\n", + " 5d284fce-67b3-441c-81fd-afee3e79f35b\n", " \n", " \n", - " 1\n", + " 775\n", " POLYGON ((1518886.257 301469.316, 1523886.257 ...\n", - " 867e9b5a-9ad3-41c2-80a0-a09a7938ec1d\n", + " c56cb374-93eb-48c9-adf2-23ba6b84dee0\n", " \n", " \n", - " 2\n", + " 776\n", " POLYGON ((1523886.257 301469.316, 1528886.257 ...\n", - " d4878be3-7e12-41dd-aa00-66c1122e1409\n", + " 96c8e283-4de7-468b-a9e5-aa1a89f623f4\n", " \n", " \n", - " 3\n", + " 777\n", " POLYGON ((1528886.257 301469.316, 1533886.257 ...\n", - " 542bae80-ec55-4dd8-9245-2364252f3558\n", + " 877d7635-f38f-47f7-904d-c722f534edf1\n", " \n", " \n", - " 4\n", + " 1365\n", " POLYGON ((-146113.743 306469.316, -141113.743 ...\n", - " f7e0b384-91b3-4494-8c69-7f328cbcdc29\n", + " 84290da6-a04d-4df3-b468-9b66d1b2ade4\n", " \n", " \n", " ...\n", @@ -731,29 +787,29 @@ " ...\n", " \n", " \n", - " 316126\n", + " 528034\n", " POLYGON ((-1966113.743 3161469.316, -1961113.7...\n", - " c33d198d-7f77-4103-baa4-c2d5c6b39d0c\n", + " dc8056c4-fa45-42d7-95da-f8b81b3833a1\n", " \n", " \n", - " 316127\n", + " 528035\n", " POLYGON ((-1961113.743 3161469.316, -1956113.7...\n", - " 70b5b7f2-705a-493e-8c9b-0374dbc5a1b5\n", + " 86871398-6656-4dca-b90c-ebe4c4cebbec\n", " \n", " \n", - " 316128\n", + " 528036\n", " POLYGON ((-1956113.743 3161469.316, -1951113.7...\n", - " ef96e314-449f-4fe2-977f-1eb8ae374469\n", + " 27417181-cde2-407b-abba-b9722afbc1c1\n", " \n", " \n", - " 316129\n", + " 528037\n", " POLYGON ((-1951113.743 3161469.316, -1946113.7...\n", - " 6977cee1-a730-497c-8815-1f9bf4f82eaf\n", + " f1fa73a6-c3de-4c0f-b162-17b62d8d226f\n", " \n", " \n", - " 316130\n", + " 528038\n", " POLYGON ((-1946113.743 3161469.316, -1941113.7...\n", - " 281aa680-84f0-458b-ad2e-2652467627e3\n", + " faafcff6-99c4-4933-85a2-b3b1fea1919e\n", " \n", " \n", "\n", @@ -817,8 +873,7 @@ "id": "ca8861d72d7dd35c", "metadata": { "ExecuteTime": { - "end_time": "2026-01-29T21:50:39.558904640Z", - "start_time": "2026-01-29T21:50:02.071495134Z" + "start_time": "2026-04-02T21:28:19.926899078Z" } }, "outputs": [ diff --git a/notebooks/stac_api_tools.ipynb b/notebooks/stac_api_tools.ipynb index e82ff93..351ce3d 100644 --- a/notebooks/stac_api_tools.ipynb +++ b/notebooks/stac_api_tools.ipynb @@ -26,8 +26,8 @@ "from pathlib import Path\n", "\n", "from geospatial_tools import DATA_DIR\n", - "from geospatial_tools.stac import StacSearch, PLANETARY_COMPUTER\n", - "from geospatial_tools.utils import create_date_range_for_specific_period" + "from geospatial_tools.stac.core import StacSearch, PLANETARY_COMPUTER\n", + "from geospatial_tools.stac.utils import create_date_range_for_specific_period" ], "outputs": [], "execution_count": 1 diff --git a/pyproject.toml b/pyproject.toml index 599464d..0c00ce6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,14 +3,12 @@ name = "geospatial_tools" version = "0.2.1" description = "" authors = [{ name = "f-PLT", email = "fplt.softwaredeveloper@gmail.com" }] -requires-python = ">=3.11,<3.15" +requires-python = ">=3.12,<3.14" readme = "README.md" classifiers = [ "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", ] dependencies = [ "leafmap>=0.31.9", diff --git a/scripts/sentinel_2_search_and_process/download_and_process.py b/scripts/sentinel_2_search_and_process/download_and_process.py index 9ba618c..64d40a7 100644 --- a/scripts/sentinel_2_search_and_process/download_and_process.py +++ b/scripts/sentinel_2_search_and_process/download_and_process.py @@ -6,11 +6,11 @@ from geopandas import GeoDataFrame from geospatial_tools import DATA_DIR -from geospatial_tools.planetary_computer.sentinel_2 import ( +from geospatial_tools.raster import clip_raster_with_polygon +from geospatial_tools.stac.core import Asset +from geospatial_tools.stac.planetary_computer.sentinel_2 import ( download_and_process_sentinel2_asset, ) -from geospatial_tools.raster import clip_raster_with_polygon -from geospatial_tools.stac import Asset from geospatial_tools.utils import create_logger # Base directory @@ -66,9 +66,10 @@ def _clip_raster( def download_and_process( - product_list: str | pathlib.Path, - download_dir: str | pathlib.Path = PRODUCT_DIR, - best_products_file: str | pathlib.Path = BEST_PRODUCTS_FILE, + product_list: str, + collection: str = "sentinel-2-l2a", + download_dir: str = str(PRODUCT_DIR), + best_products_file: str = str(BEST_PRODUCTS_FILE), target_crs: int = CRS_PROJECTION, num_of_workers: int = 4, delete_products: bool = False, @@ -96,12 +97,14 @@ def download_and_process( LOGGER.info("Grouping results by product") group_by_product = best_results.groupby("best_s2_product_id")["feature_id"].agg(list).reset_index() + group_by_product = GeoDataFrame(group_by_product) bands = ["B02", "B03", "B04", "B08", "visual"] product_asset_list = [ download_and_process_sentinel2_asset( product_id=p, product_bands=bands, + collections=collection, base_directory=download_dir, target_projection=target_crs, delete_intermediate_files=True, diff --git a/scripts/sentinel_2_search_and_process/product_search.py b/scripts/sentinel_2_search_and_process/product_search.py index 2b3deb5..25c754b 100644 --- a/scripts/sentinel_2_search_and_process/product_search.py +++ b/scripts/sentinel_2_search_and_process/product_search.py @@ -10,7 +10,7 @@ from pyogrio.errors import DataSourceError from geospatial_tools import DATA_DIR -from geospatial_tools.planetary_computer.sentinel_2 import BestProductsForFeatures +from geospatial_tools.stac.planetary_computer.sentinel_2 import BestProductsForFeatures from geospatial_tools.utils import create_logger from geospatial_tools.vector import ( create_vector_grid_parallel, @@ -153,8 +153,8 @@ def get_best_results(best_products_client: BestProductsForFeatures, grid_size: i def product_search( - polygon_file: str | pathlib.Path = USA_POLYGON_FILE, - sentinel2_grid_file: str | pathlib.Path = S2_USA_GRID_FILE, + polygon_file: str = str(USA_POLYGON_FILE), + sentinel2_grid_file: str = str(S2_USA_GRID_FILE), output_dir: str = str(S2_SCRIPT_DIR), grid_size: int = GRID_SIZE, target_crs: int = CRS_PROJECTION, @@ -186,6 +186,9 @@ def product_search( # Sentinel 2 dataset and clip the selected Sentinel 2 images. output_path = pathlib.Path(output_dir) + if not output_path.exists(): + output_path.mkdir(parents=True) + grid = get_grid( grid_size=grid_size, num_workers_vector_grid=num_workers_vector_grid, diff --git a/src/geospatial_tools/planetary_computer/__init__.py b/src/geospatial_tools/stac/__init__.py similarity index 100% rename from src/geospatial_tools/planetary_computer/__init__.py rename to src/geospatial_tools/stac/__init__.py diff --git a/src/geospatial_tools/copernicus/__init__.py b/src/geospatial_tools/stac/copernicus/__init__.py similarity index 68% rename from src/geospatial_tools/copernicus/__init__.py rename to src/geospatial_tools/stac/copernicus/__init__.py index 9d7add8..2609574 100644 --- a/src/geospatial_tools/copernicus/__init__.py +++ b/src/geospatial_tools/stac/copernicus/__init__.py @@ -1,13 +1,15 @@ """Copernicus Data Space Ecosystem (CDSE) tools and constants.""" -from .sentinel_2 import ( +from geospatial_tools.stac.copernicus.constants import ( CopernicusS2Band, CopernicusS2Collection, + CopernicusS2Property, CopernicusS2Resolution, ) __all__ = [ "CopernicusS2Band", "CopernicusS2Collection", + "CopernicusS2Property", "CopernicusS2Resolution", ] diff --git a/src/geospatial_tools/auth.py b/src/geospatial_tools/stac/copernicus/auth.py similarity index 100% rename from src/geospatial_tools/auth.py rename to src/geospatial_tools/stac/copernicus/auth.py diff --git a/src/geospatial_tools/copernicus/sentinel_2.py b/src/geospatial_tools/stac/copernicus/constants.py similarity index 85% rename from src/geospatial_tools/copernicus/sentinel_2.py rename to src/geospatial_tools/stac/copernicus/constants.py index 2dd9edd..6b72b2d 100644 --- a/src/geospatial_tools/copernicus/sentinel_2.py +++ b/src/geospatial_tools/stac/copernicus/constants.py @@ -1,7 +1,7 @@ # pylint: disable=C0103 """This module contains Enums for Sentinel-2 on Copernicus Data Space Ecosystem (CDSE).""" -from enum import Enum +from enum import Enum, StrEnum # --- Constants & Mappings --- @@ -30,19 +30,29 @@ } -class CopernicusS2Collection(str, Enum): +class CopernicusS2Collection(StrEnum): """Copernicus Sentinel-2 Collections.""" L2A = "sentinel-2-l2a" L1C = "sentinel-2-l1c" - def __str__(self) -> str: - """Returns the collection name as a string.""" - return f"{self.value}" - def __repr__(self) -> str: - """Returns the band name as a string.""" - return f"{self.value}" +class CopernicusS2Property(StrEnum): + """ + Copernicus Sentinel-2 STAC query properties. + + These are standard STAC properties shared across catalogs. The `sortby_field` + property returns the full JSON path required by the STAC API sortby object. + """ + + CLOUD_COVER = "eo:cloud_cover" + MGRS_TILE = "s2:mgrs_tile" + NODATA_PIXEL_PERCENTAGE = "s2:nodata_pixel_percentage" + + @property + def sortby_field(self) -> str: + """Returns the full JSON path prefix required by the STAC API sortby object.""" + return f"properties.{self.value}" class CopernicusS2Resolution(int, Enum): @@ -61,7 +71,7 @@ def __repr__(self) -> str: return f"{self.value}" -class CopernicusS2Band(str, Enum): +class CopernicusS2Band(StrEnum): """ Copernicus Sentinel-2 Bands for Level-2A. @@ -160,7 +170,7 @@ class CopernicusS2Band(str, Enum): @property def base_name(self) -> str: """Returns the base name of the band (e.g., 'B02').""" - return self.value.split("_")[0] + return self.value.split("_", maxsplit=1)[0] @property def native_res(self) -> int: @@ -183,11 +193,3 @@ def at_res(self, resolution: int | CopernicusS2Resolution) -> str: """ res_val = resolution.value if isinstance(resolution, CopernicusS2Resolution) else resolution return f"{self.base_name}_{res_val}m" - - def __str__(self) -> str: - """Returns the band name as a string.""" - return f"{self.value}" - - def __repr__(self) -> str: - """Returns the band name as a string.""" - return f"{self.value}" diff --git a/src/geospatial_tools/stac.py b/src/geospatial_tools/stac/core.py similarity index 88% rename from src/geospatial_tools/stac.py rename to src/geospatial_tools/stac/core.py index ffa8011..ef2d714 100644 --- a/src/geospatial_tools/stac.py +++ b/src/geospatial_tools/stac/core.py @@ -1,26 +1,27 @@ """This module contains functions that are related to STAC API.""" +import abc import logging import time from collections.abc import Iterator, Sequence from pathlib import Path -from typing import Any, overload +from typing import Any, Self, overload import pystac import pystac_client from planetary_computer import sign_inplace from pystac_client.exceptions import APIError -from geospatial_tools import geotools_types, s3_utils -from geospatial_tools.auth import get_copernicus_token -from geospatial_tools.geotools_types import DateLike +from geospatial_tools import geotools_types +from geospatial_tools.geotools_types import BBoxLike, DateLike, IntersectsLike from geospatial_tools.raster import ( create_merged_raster_bands_metadata, get_total_band_count, merge_raster_bands, reproject_raster, ) -from geospatial_tools.s3_utils import download_url_s3 +from geospatial_tools.stac import utils +from geospatial_tools.stac.copernicus.auth import get_copernicus_token from geospatial_tools.utils import create_logger, download_url LOGGER = create_logger(__name__) @@ -398,7 +399,9 @@ def download_stac_asset( The Path to the downloaded file if successful, else None. """ if method == "s3": - file_path = download_url_s3(asset_url=asset_url, destination=destination, s3_client=s3_client, logger=logger) + file_path = utils.download_url_s3( + asset_url=asset_url, destination=destination, s3_client=s3_client, logger=logger + ) return file_path # Default to HTTP file_path = download_url(url=asset_url, filename=destination, headers=headers, logger=logger) @@ -427,7 +430,7 @@ def __init__(self, catalog_name: str, logger: logging.Logger = LOGGER) -> None: self.logger = logger self.s3_client: Any | None = None if catalog_name == COPERNICUS: - self.s3_client = s3_utils.get_s3_client() + self.s3_client = utils.get_s3_client() def search( self, @@ -869,3 +872,122 @@ def download_best_cloud_cover_result(self, bands: list[str], base_directory: str self.downloaded_best_sorted_asset = downloaded_search_results[0] return downloaded_search_results[0] return None + + +class AbstractStacWrapper(abc.ABC): + """ + Abstract base class for STAC search wrappers using a Facade + Proxy pattern. + + This class provides a common interface and shared logic for different STAC collections + (e.g., Sentinel-1, Sentinel-2). It delegates actual STAC operations to an underlying + `StacSearch` client and exposes results via proxy properties. + """ + + def __init__( + self, + collection: str | None = None, + date_range: DateLike = None, + bbox: BBoxLike | None = None, + intersects: IntersectsLike | None = None, + logger: logging.Logger = LOGGER, + ): + """ + Initialize the STAC wrapper. + + Args: + collection: The STAC collection ID to search. + date_range: Temporal filter for the search. + bbox: Spatial bounding box filter. + intersects: Spatial GeoJSON geometry filter. + logger: Logger instance. + """ + self.client: StacSearch = StacSearch(PLANETARY_COMPUTER) + self.collection = collection + self.date_range = date_range + self.bbox = bbox + self.intersects = intersects + self.logger = logger + self.custom_query_params: dict[str, Any] = {} + + @property + def search_results(self) -> list[pystac.Item] | None: + """Proxy property for STAC search results from the underlying client.""" + return self.client.search_results + + @property + def downloaded_assets(self) -> list[Asset] | None: + """Proxy property for downloaded assets from the underlying client.""" + return self.client.downloaded_search_assets + + @abc.abstractmethod + def _build_collection_query(self) -> dict[str, Any]: + """ + Build the collection-specific query dictionary. + + This method must be implemented by subclasses to handle specific STAC properties. + """ + + def _invalidate_state(self) -> None: + """ + Invalidate the cached results in the underlying client. + + Should be called whenever query parameters are modified to ensure stale results are not accessed. + """ + self.client.search_results = None + self.client.downloaded_search_assets = None + + def with_custom_query(self, query_params: dict[str, Any]) -> Self: + """ + Merge custom STAC query parameters and invalidate current state. + + Args: + query_params: Dictionary of custom STAC query parameters. + + Returns: + The instance itself (Self) for fluent chaining. + """ + self._invalidate_state() + self.custom_query_params.update(query_params) + return self + + def search(self) -> list[pystac.Item] | None: + """ + Execute the STAC search using the built query and parameters. + + Returns: + List of matched pystac Items, or None if no results. + """ + query = self._build_collection_query() + query.update(self.custom_query_params) + + collections = [self.collection] if self.collection else None + + self.client.search( + collections=collections, + bbox=self.bbox, + intersects=self.intersects, + date_range=self.date_range, + query=query if query else None, + ) + return self.search_results + + def download(self, bands: list[str], base_directory: str | Path) -> list[Asset] | None: + """ + Download assets for the matched search results. + + Triggers a search if no results are currently available. + + Args: + bands: List of asset keys (bands) to download. + base_directory: Local directory where assets will be saved. + + Returns: + List of downloaded Asset objects. + """ + if self.search_results is None: + self.search() + + # S1 might need a small override here for lowercase logic, + # but the core logic stays here. + self.client.download_search_results(bands=bands, base_directory=Path(base_directory)) + return self.downloaded_assets diff --git a/src/geospatial_tools/stac/planetary_computer/__init__.py b/src/geospatial_tools/stac/planetary_computer/__init__.py new file mode 100644 index 0000000..ce3f332 --- /dev/null +++ b/src/geospatial_tools/stac/planetary_computer/__init__.py @@ -0,0 +1,29 @@ +from geospatial_tools.stac.planetary_computer.constants import ( + PlanetaryComputerS1Band, + PlanetaryComputerS1Collection, + PlanetaryComputerS1InstrumentMode, + PlanetaryComputerS1OrbitState, + PlanetaryComputerS1Polarization, + PlanetaryComputerS1Property, + PlanetaryComputerS2Band, + PlanetaryComputerS2Collection, + PlanetaryComputerS2Property, + PlanetaryComputerS3Band, + PlanetaryComputerS3Collection, + PlanetaryComputerS3Property, +) + +__all__ = [ + "PlanetaryComputerS1Band", + "PlanetaryComputerS1Collection", + "PlanetaryComputerS1InstrumentMode", + "PlanetaryComputerS1OrbitState", + "PlanetaryComputerS1Polarization", + "PlanetaryComputerS1Property", + "PlanetaryComputerS2Band", + "PlanetaryComputerS2Collection", + "PlanetaryComputerS2Property", + "PlanetaryComputerS3Band", + "PlanetaryComputerS3Collection", + "PlanetaryComputerS3Property", +] diff --git a/src/geospatial_tools/stac/planetary_computer/constants.py b/src/geospatial_tools/stac/planetary_computer/constants.py new file mode 100644 index 0000000..452e334 --- /dev/null +++ b/src/geospatial_tools/stac/planetary_computer/constants.py @@ -0,0 +1,163 @@ +"""Constants for Planetary Computer Sentinel-2 STAC catalog.""" + +from enum import StrEnum + + +class PlanetaryComputerS2Collection(StrEnum): + """Planetary Computer Sentinel-2 Collections.""" + + L2A = "sentinel-2-l2a" + + +class PlanetaryComputerS2Property(StrEnum): + """Planetary Computer Sentinel-2 STAC query properties.""" + + CLOUD_COVER = "eo:cloud_cover" + MGRS_TILE = "s2:mgrs_tile" + NODATA_PIXEL_PERCENTAGE = "s2:nodata_pixel_percentage" + + @property + def sortby_field(self) -> str: + """Returns the full JSON path prefix required by the STAC API sortby object.""" + return f"properties.{self.value}" + + +class PlanetaryComputerS2Band(StrEnum): + """ + Planetary Computer Sentinel-2 asset band keys. + + Planetary Computer uses plain base names (e.g., "B02") as asset keys, unlike Copernicus which appends resolution + suffixes. + """ + + # Standard bands + B01 = "B01" + B02 = "B02" + B03 = "B03" + B04 = "B04" + B05 = "B05" + B06 = "B06" + B07 = "B07" + B08 = "B08" + B8A = "B8A" + B09 = "B09" + B11 = "B11" + B12 = "B12" + SCL = "SCL" + TCI = "TCI" + AOT = "AOT" + WVP = "WVP" + + # Common name aliases (alias members share values with standard bands above) + COASTAL = "B01" + BLUE = "B02" + GREEN = "B03" + RED = "B04" + RED_EDGE_1 = "B05" + RED_EDGE_2 = "B06" + RED_EDGE_3 = "B07" + NIR = "B08" + NIR_NARROW = "B8A" + SWIR_1 = "B11" + SWIR_2 = "B12" + + +class PlanetaryComputerS1Collection(StrEnum): + """Planetary Computer Sentinel-1 Collections.""" + + GRD = "sentinel-1-grd" + + +class PlanetaryComputerS1Property(StrEnum): + """Planetary Computer Sentinel-1 STAC query properties.""" + + INSTRUMENT_MODE = "sar:instrument_mode" + POLARIZATIONS = "sar:polarizations" + ORBIT_STATE = "sat:orbit_state" + + +class PlanetaryComputerS1Band(StrEnum): + """ + Planetary Computer Sentinel-1 asset band keys. + + Used to fetch assets from the STAC item. + """ + + VV = "vv" + VH = "vh" + + +class PlanetaryComputerS1InstrumentMode(StrEnum): + """ + Planetary Computer Sentinel-1 instrument modes. + + Used for STAC queries. + """ + + IW = "IW" + EW = "EW" + SM = "SM" + WV = "WV" + + +class PlanetaryComputerS1Polarization(StrEnum): + """ + Planetary Computer Sentinel-1 polarizations. + + Used for STAC queries. + """ + + VV = "VV" + VH = "VH" + HH = "HH" + HV = "HV" + + +class PlanetaryComputerS1OrbitState(StrEnum): + """ + Planetary Computer Sentinel-1 orbit states. + + Used for STAC queries. + """ + + ASCENDING = "ascending" + DESCENDING = "descending" + + +class PlanetaryComputerS3Collection(StrEnum): + """Planetary Computer Sentinel-3 Collections.""" + + OLCI_L1B = "sentinel-3-olci-l1b-efr" + OLCI_WFR = "sentinel-3-olci-wfr-l2-netcdf" + + +class PlanetaryComputerS3Property(StrEnum): + """Planetary Computer Sentinel-3 STAC query properties.""" + + ORBIT_STATE = "sat:orbit_state" + + +class PlanetaryComputerS3OrbitState(StrEnum): + """ + Planetary Computer Sentinel-3 orbit states. + + Used for STAC queries. + """ + + ASCENDING = "ascending" + DESCENDING = "descending" + + +class PlanetaryComputerS3Band(StrEnum): + """Planetary Computer Sentinel-3 asset band keys.""" + + OA16 = "oa16-radiance" + OA17 = "oa17-radiance" + OA18 = "oa18-radiance" + OA19 = "oa19-radiance" + OA20 = "oa20-radiance" + OA21 = "oa21-radiance" + + # Common name aliases + NIR_865 = "oa17-radiance" + WATER_VAPOUR = "oa19-radiance" diff --git a/src/geospatial_tools/stac/planetary_computer/sentinel_1.py b/src/geospatial_tools/stac/planetary_computer/sentinel_1.py new file mode 100644 index 0000000..813f01a --- /dev/null +++ b/src/geospatial_tools/stac/planetary_computer/sentinel_1.py @@ -0,0 +1,161 @@ +import logging +from pathlib import Path +from typing import Any, Self + +from geospatial_tools.geotools_types import BBoxLike, DateLike, IntersectsLike +from geospatial_tools.stac.core import AbstractStacWrapper, Asset +from geospatial_tools.stac.planetary_computer.constants import ( + PlanetaryComputerS1Band, + PlanetaryComputerS1Collection, + PlanetaryComputerS1InstrumentMode, + PlanetaryComputerS1OrbitState, + PlanetaryComputerS1Polarization, + PlanetaryComputerS1Property, +) + +LOGGER = logging.getLogger(__name__) + + +class Sentinel1Search(AbstractStacWrapper): + """ + Executable wrapper for Sentinel-1 GRD data on Planetary Computer. + + Implements a fluent builder pattern to construct STAC queries for SAR data. + Execution and result storage are delegated to an underlying `StacSearch` client + via proxy properties. + """ + + def __init__( + self, + collection: PlanetaryComputerS1Collection | str = PlanetaryComputerS1Collection.GRD, + date_range: DateLike = None, + bbox: BBoxLike | None = None, + intersects: IntersectsLike | None = None, + logger: logging.Logger = LOGGER, + ) -> None: + """ + Initialize Sentinel1Search. + + Args: + collection: The Sentinel-1 STAC collection (default: sentinel-1-grd). + date_range: Temporal filter, native pystac DateLike. + bbox: Spatial bounding box filter. + intersects: Spatial GeoJSON geometry filter. + logger: Custom logger instance. + """ + super().__init__(collection=collection, date_range=date_range, bbox=bbox, intersects=intersects, logger=logger) + + self.instrument_modes: list[PlanetaryComputerS1InstrumentMode] | None = None + self.polarizations: list[PlanetaryComputerS1Polarization] | None = None + self.orbit_states: list[PlanetaryComputerS1OrbitState] | None = None + self.custom_query_params: dict[str, Any] = {} + + def filter_by_instrument_mode( + self, modes: list[PlanetaryComputerS1InstrumentMode] | PlanetaryComputerS1InstrumentMode + ) -> Self: + """ + Filter SAR products by instrument mode (e.g., IW, EW). + + Invalidates current search results. + + Args: + modes: Single mode or list of `PlanetaryComputerS1InstrumentMode`. + + Returns: + The instance itself (Self) for fluent chaining. + """ + self._invalidate_state() + if isinstance(modes, list): + self.instrument_modes = modes + else: + self.instrument_modes = [modes] + return self + + def filter_by_polarization( + self, polarizations: list[PlanetaryComputerS1Polarization] | PlanetaryComputerS1Polarization + ) -> Self: + """ + Filter SAR products by polarization (e.g., VV, VH). + + Invalidates current search results. Note: PC STAC requires an exact array match + for `sar:polarizations`. + + Args: + polarizations: Single polarization or list of `PlanetaryComputerS1Polarization`. + + Returns: + The instance itself (Self) for fluent chaining. + """ + self._invalidate_state() + if isinstance(polarizations, list): + self.polarizations = polarizations + else: + self.polarizations = [polarizations] + return self + + def filter_by_orbit_state( + self, states: list[PlanetaryComputerS1OrbitState] | PlanetaryComputerS1OrbitState + ) -> Self: + """ + Filter SAR products by orbit state (ascending or descending). + + Invalidates current search results. + + Args: + states: Single state or list of `PlanetaryComputerS1OrbitState`. + + Returns: + The instance itself (Self) for fluent chaining. + """ + self._invalidate_state() + if isinstance(states, list): + self.orbit_states = states + else: + self.orbit_states = [states] + return self + + def _build_collection_query(self) -> dict[str, Any]: + """ + Build the Sentinel-1 specific STAC query. + + Uses `PlanetaryComputerS1Property` for property keys and appropriate + operators (`eq`, `in`) based on filter state. + """ + query: dict[str, Any] = {} + + if self.instrument_modes: + modes_str = [m.value for m in self.instrument_modes] + if len(modes_str) == 1: + query[PlanetaryComputerS1Property.INSTRUMENT_MODE.value] = {"eq": modes_str[0]} + else: + query[PlanetaryComputerS1Property.INSTRUMENT_MODE.value] = {"in": modes_str} + + if self.orbit_states: + states_str = [s.value for s in self.orbit_states] + if len(states_str) == 1: + query[PlanetaryComputerS1Property.ORBIT_STATE.value] = {"eq": states_str[0]} + else: + query[PlanetaryComputerS1Property.ORBIT_STATE.value] = {"in": states_str} + + if self.polarizations: + # PC STAC requires exact array match for sar:polarizations, `contains` is unsupported + pols_str = [p.value for p in self.polarizations] + query[PlanetaryComputerS1Property.POLARIZATIONS.value] = {"eq": pols_str} + + query.update(self.custom_query_params) + return query + + def download(self, bands: list[PlanetaryComputerS1Band | str], base_directory: str | Path) -> list[Asset] | None: + """ + Download Sentinel-1 assets with lowercase band key normalization. + + Args: + bands: List of bands to download. + base_directory: Local directory where assets will be saved. + + Returns: + List of downloaded Asset objects. + """ + # Small specialized override for S1 casing requirements + lower_bands = [str(b).lower() for b in bands] + return super().download(bands=lower_bands, base_directory=base_directory) diff --git a/src/geospatial_tools/planetary_computer/sentinel_2.py b/src/geospatial_tools/stac/planetary_computer/sentinel_2.py similarity index 76% rename from src/geospatial_tools/planetary_computer/sentinel_2.py rename to src/geospatial_tools/stac/planetary_computer/sentinel_2.py index e8d01b6..f01d270 100644 --- a/src/geospatial_tools/planetary_computer/sentinel_2.py +++ b/src/geospatial_tools/stac/planetary_computer/sentinel_2.py @@ -2,18 +2,139 @@ import logging import pathlib from concurrent.futures import ThreadPoolExecutor, as_completed -from typing import Any +from typing import Any, Self from geopandas import GeoDataFrame from geospatial_tools import DATA_DIR -from geospatial_tools.stac import PLANETARY_COMPUTER, Asset, StacSearch -from geospatial_tools.utils import create_date_range_for_specific_period, create_logger +from geospatial_tools.geotools_types import BBoxLike, DateLike, IntersectsLike +from geospatial_tools.stac.core import ( + PLANETARY_COMPUTER, + AbstractStacWrapper, + Asset, + StacSearch, +) +from geospatial_tools.stac.planetary_computer.constants import ( + PlanetaryComputerS2Collection, + PlanetaryComputerS2Property, +) +from geospatial_tools.stac.utils import create_date_range_for_specific_period +from geospatial_tools.utils import create_logger from geospatial_tools.vector import spatial_join_within LOGGER = create_logger(__name__) +class Sentinel2Search(AbstractStacWrapper): + """ + Executable wrapper for Sentinel-2 L2A data on Planetary Computer. + + Implements a fluent builder pattern to construct STAC queries for optical data. + Execution and result storage are delegated to an underlying `StacSearch` client + via proxy properties. + """ + + def __init__( + self, + collection: PlanetaryComputerS2Collection | str = PlanetaryComputerS2Collection.L2A, + date_range: DateLike = None, + bbox: BBoxLike | None = None, + intersects: IntersectsLike | None = None, + logger: logging.Logger = LOGGER, + ) -> None: + """ + Initialize Sentinel2Search. + + Args: + collection: Collection used to search for Sentinel 2 products. + date_range: Temporal filter, native pystac DateLike. + bbox: Spatial bounding box filter. + intersects: Spatial GeoJSON geometry filter. + logger: Custom logger instance. + """ + super().__init__(collection=collection, date_range=date_range, bbox=bbox, intersects=intersects, logger=logger) + + self.max_cloud_cover: int | None = None + self.max_no_data_value: int | None = None + self.mgrs_tiles: list[str] | None = None + self.custom_query_params: dict[str, Any] = {} + + def filter_by_cloud_cover(self, max_cloud_cover: int) -> Self: + """ + Filter by maximum cloud cover percentage. + + Invalidates current search results. + + Args: + max_cloud_cover: Maximum percentage of cloud cover allowed. + + Returns: + The instance itself (Self) for fluent chaining. + """ + self._invalidate_state() + self.max_cloud_cover = max_cloud_cover + return self + + def filter_by_nodata_pixel_percentage(self, max_no_data_value: int) -> Self: + """ + Filter by maximum no-data pixel percentage. + + Invalidates current search results. + + Args: + max_no_data_value: Maximum percentage of no-data pixels allowed. + + Returns: + The instance itself (Self) for fluent chaining. + """ + self._invalidate_state() + self.max_no_data_value = max_no_data_value + return self + + def filter_by_mgrs_tile(self, mgrs_tiles: list[str] | str) -> Self: + """ + Filter by MGRS tile ID(s). + + Invalidates current search results. + + Args: + mgrs_tiles: Single MGRS tile ID or list of IDs. + + Returns: + The instance itself (Self) for fluent chaining. + """ + self._invalidate_state() + if isinstance(mgrs_tiles, list): + self.mgrs_tiles = mgrs_tiles + else: + self.mgrs_tiles = [mgrs_tiles] + return self + + def _build_collection_query(self) -> dict[str, Any]: + """ + Build the Sentinel-2 specific STAC query. + + Uses `PlanetaryComputerS2Property` for property keys and appropriate + operators (`lt`, `eq`, `in`) based on filter state. + """ + query: dict[str, Any] = {} + + if self.max_cloud_cover is not None: + query[PlanetaryComputerS2Property.CLOUD_COVER.value] = {"lt": self.max_cloud_cover} + + if self.max_no_data_value is not None: + query[PlanetaryComputerS2Property.NODATA_PIXEL_PERCENTAGE.value] = {"lt": self.max_no_data_value} + + if self.mgrs_tiles: + if len(self.mgrs_tiles) == 1: + query[PlanetaryComputerS2Property.MGRS_TILE.value] = {"eq": self.mgrs_tiles[0]} + else: + query[PlanetaryComputerS2Property.MGRS_TILE.value] = {"in": self.mgrs_tiles} + + query.update(self.custom_query_params) + return query + + class BestProductsForFeatures: """ Class made to facilitate and automate searching for Sentinel 2 products using the Sentinel 2 tiling grid as a @@ -35,11 +156,12 @@ def __init__( sentinel2_tiling_grid_column: str, vector_features: GeoDataFrame, vector_features_column: str, + collection: PlanetaryComputerS2Collection | str = PlanetaryComputerS2Collection.L2A, date_ranges: list[str] | None = None, max_cloud_cover: int = 5, max_no_data_value: int = 5, logger: logging.Logger = LOGGER, - ) -> None: + ): """ Args: @@ -57,6 +179,11 @@ def __init__( logger: Logger instance """ self.logger = logger + self.collection = collection + self.date_ranges = date_ranges + self._max_cloud_cover = max_cloud_cover + self.max_no_data_value = max_no_data_value + self.sentinel2_tiling_grid = sentinel2_tiling_grid self.sentinel2_tiling_grid_column = sentinel2_tiling_grid_column self.sentinel2_tile_list = sentinel2_tiling_grid["name"].to_list() @@ -64,50 +191,11 @@ def __init__( self.vector_features_column = vector_features_column self.vector_features_best_product_column = "best_s2_product_id" self.vector_features_with_products = None - self._date_ranges = date_ranges - self._max_cloud_cover = max_cloud_cover - self.max_no_data_value = max_no_data_value self.successful_results: dict[Any, Any] = {} self.incomplete_results: list[Any] = [] self.error_results: list[Any] = [] - @property - def max_cloud_cover(self): - """Max % of cloud cover used for Sentinel 2 product search.""" - return self._max_cloud_cover - - @max_cloud_cover.setter - def max_cloud_cover(self, max_cloud_cover: int) -> None: - """ - - Args: - max_cloud_cover: int: Max percentage of cloud cover used for Sentinel 2 product search - - Returns: - - - """ - self._max_cloud_cover = max_cloud_cover - - @property - def date_ranges(self): - """Date range used to search for Sentinel 2 products.""" - return self._date_ranges - - @date_ranges.setter - def date_ranges(self, date_range: list[str]) -> None: - """ - - Args: - date_range: list[str]: - - Returns: - - - """ - self._date_ranges = date_range - - def create_date_ranges(self, start_year: int, end_year: int, start_month: int, end_month: int) -> list[str]: + def create_date_ranges(self, start_year: int, end_year: int, start_month: int, end_month: int) -> list[str] | None: """ This function create a list of date ranges. @@ -133,6 +221,11 @@ def create_date_ranges(self, start_year: int, end_year: int, start_month: int, e ) return self.date_ranges + @property + def max_cloud_cover(self): + """Max % of cloud cover used for Sentinel 2 product search.""" + return self._max_cloud_cover + def find_best_complete_products(self, max_cloud_cover: int | None = None, max_no_data_value: int = 5) -> dict: """ Finds the best complete products for each Sentinel 2 tiles. This function will filter out all products that have @@ -154,8 +247,11 @@ def find_best_complete_products(self, max_cloud_cover: int | None = None, max_no no_data_value = self.max_no_data_value if max_no_data_value: no_data_value = max_no_data_value + if not self.date_ranges: + raise ValueError("date_ranges must be set before searching") tile_dict, incomplete_list, error_list = find_best_product_per_s2_tile( + collection=self.collection, date_ranges=self.date_ranges, max_cloud_cover=cloud_cover, s2_tile_grid_list=self.sentinel2_tile_list, @@ -213,6 +309,7 @@ def to_file(self, output_dir: str | pathlib.Path) -> None: def sentinel_2_complete_tile_search( tile_id: int, + collection: str, date_ranges: list[str], max_cloud_cover: int, max_no_data_value: int = 5, @@ -220,6 +317,7 @@ def sentinel_2_complete_tile_search( """ Args: + collection: tile_id: date_ranges: max_cloud_cover: @@ -230,10 +328,12 @@ def sentinel_2_complete_tile_search( """ client = StacSearch(PLANETARY_COMPUTER) - collection = "sentinel-2-l2a" tile_ids = [tile_id] - query = {"eo:cloud_cover": {"lt": max_cloud_cover}, "s2:mgrs_tile": {"in": tile_ids}} - sortby = [{"field": "properties.eo:cloud_cover", "direction": "asc"}] + query: dict[str, Any] = { + PlanetaryComputerS2Property.CLOUD_COVER: {"lt": max_cloud_cover}, + PlanetaryComputerS2Property.MGRS_TILE: {"in": tile_ids}, + } + sortby = [{"field": PlanetaryComputerS2Property.CLOUD_COVER.sortby_field, "direction": "asc"}] client.search_for_date_ranges( date_ranges=date_ranges, collections=collection, query=query, sortby=sortby, limit=100 @@ -243,7 +343,8 @@ def sentinel_2_complete_tile_search( if not sorted_items: return tile_id, "error: No results found", None, None filtered_items = client.filter_no_data( - property_name="s2:nodata_pixel_percentage", max_no_data_value=max_no_data_value + property_name=PlanetaryComputerS2Property.NODATA_PIXEL_PERCENTAGE, + max_no_data_value=max_no_data_value, ) if not filtered_items: return tile_id, "incomplete: No results found that cover the entire tile", None, None @@ -252,17 +353,18 @@ def sentinel_2_complete_tile_search( return ( tile_id, optimal_result.id, - optimal_result.properties["eo:cloud_cover"], - optimal_result.properties["s2:nodata_pixel_percentage"], + optimal_result.properties[PlanetaryComputerS2Property.CLOUD_COVER], + optimal_result.properties[PlanetaryComputerS2Property.NODATA_PIXEL_PERCENTAGE], ) except (IndexError, TypeError) as error: - print(error) + LOGGER.warning(str(error)) return tile_id, f"error: {error}", None, None return None def find_best_product_per_s2_tile( + collection: str, date_ranges: list[str], max_cloud_cover: int, s2_tile_grid_list: list, @@ -272,6 +374,7 @@ def find_best_product_per_s2_tile( """ Args: + collection: date_ranges: max_cloud_cover: s2_tile_grid_list: @@ -292,6 +395,7 @@ def find_best_product_per_s2_tile( executor.submit( sentinel_2_complete_tile_search, tile_id=tile, + collection=collection, date_ranges=date_ranges, max_cloud_cover=max_cloud_cover, max_no_data_value=max_no_data_value, @@ -404,7 +508,8 @@ def write_results_to_file( """ - output_dir = pathlib.Path(output_dir) + if isinstance(output_dir, str): + output_dir = pathlib.Path(output_dir) tile_filename = output_dir / f"data_lt{cloud_cover}cc.json" with open(tile_filename, "w", encoding="utf-8") as json_file: json.dump(successful_results, json_file, indent=4) @@ -436,7 +541,7 @@ def write_results_to_file( def download_and_process_sentinel2_asset( product_id: str, product_bands: list[str], - collections: str = "sentinel-2-l2a", + collections: PlanetaryComputerS2Collection | str = PlanetaryComputerS2Collection.L2A, target_projection: int | str | None = None, base_directory: str | pathlib.Path = DATA_DIR, delete_intermediate_files: bool = False, diff --git a/src/geospatial_tools/stac/planetary_computer/sentinel_3.py b/src/geospatial_tools/stac/planetary_computer/sentinel_3.py new file mode 100644 index 0000000..3a01783 --- /dev/null +++ b/src/geospatial_tools/stac/planetary_computer/sentinel_3.py @@ -0,0 +1,102 @@ +# pylint: disable=duplicate-code +import logging +from pathlib import Path +from typing import Any, Self + +from geospatial_tools.geotools_types import BBoxLike, DateLike, IntersectsLike +from geospatial_tools.stac.core import AbstractStacWrapper, Asset +from geospatial_tools.stac.planetary_computer.constants import ( + PlanetaryComputerS3Band, + PlanetaryComputerS3Collection, + PlanetaryComputerS3OrbitState, + PlanetaryComputerS3Property, +) + +LOGGER = logging.getLogger(__name__) + + +class Sentinel3Search(AbstractStacWrapper): + """ + Executable wrapper for Sentinel-3 OLCI data on Planetary Computer. + + Implements a fluent builder pattern to construct STAC queries. + Execution and result storage are delegated to an underlying `StacSearch` client + via proxy properties. + """ + + def __init__( + self, + collection: PlanetaryComputerS3Collection | str = PlanetaryComputerS3Collection.OLCI_WFR, + date_range: DateLike = None, + bbox: BBoxLike | None = None, + intersects: IntersectsLike | None = None, + logger: logging.Logger = LOGGER, + ) -> None: + """ + Initialize Sentinel3Search. + + Args: + collection: The Sentinel-3 STAC collection (default: sentinel-3-olci-wfr-l2-netcdf). + date_range: Temporal filter, native pystac DateLike. + bbox: Spatial bounding box filter. + intersects: Spatial GeoJSON geometry filter. + logger: Custom logger instance. + """ + super().__init__(collection=collection, date_range=date_range, bbox=bbox, intersects=intersects, logger=logger) + + self.orbit_states: list[PlanetaryComputerS3OrbitState] | None = None + self.custom_query_params: dict[str, Any] = {} + + def filter_by_orbit_state( + self, states: list[PlanetaryComputerS3OrbitState] | PlanetaryComputerS3OrbitState + ) -> Self: + """ + Filter products by orbit state (ascending or descending). + + Invalidates current search results. + + Args: + states: Single state or list of `PlanetaryComputerS3OrbitState`. + + Returns: + The instance itself (Self) for fluent chaining. + """ + self._invalidate_state() + if isinstance(states, list): + self.orbit_states = states + else: + self.orbit_states = [states] + return self + + def _build_collection_query(self) -> dict[str, Any]: + """ + Build the Sentinel-3 specific STAC query. + + Uses `PlanetaryComputerS3Property` for property keys and appropriate + operators (`eq`, `in`) based on filter state. + """ + query: dict[str, Any] = {} + + if self.orbit_states: + states_str = [s.value for s in self.orbit_states] + if len(states_str) == 1: + query[PlanetaryComputerS3Property.ORBIT_STATE.value] = {"eq": states_str[0]} + else: + query[PlanetaryComputerS3Property.ORBIT_STATE.value] = {"in": states_str} + + query.update(self.custom_query_params) + return query + + def download(self, bands: list[PlanetaryComputerS3Band | str], base_directory: str | Path) -> list[Asset] | None: + """ + Download Sentinel-3 assets with lowercase band key normalization. + + Args: + bands: List of bands to download. + base_directory: Local directory where assets will be saved. + + Returns: + List of downloaded Asset objects. + """ + lower_bands = [str(b).lower() for b in bands] + return super().download(bands=lower_bands, base_directory=base_directory) diff --git a/src/geospatial_tools/s3_utils.py b/src/geospatial_tools/stac/utils.py similarity index 65% rename from src/geospatial_tools/s3_utils.py rename to src/geospatial_tools/stac/utils.py index 8653b86..6df4c51 100644 --- a/src/geospatial_tools/s3_utils.py +++ b/src/geospatial_tools/stac/utils.py @@ -1,5 +1,7 @@ -"""Utility module for S3 operations related to Copernicus Data Space Ecosystem.""" +from __future__ import annotations +import calendar +import datetime import os from urllib.parse import urlparse @@ -7,7 +9,42 @@ from geospatial_tools.utils import create_logger -# Initialize logger + +def create_date_range_for_specific_period( + start_year: int, end_year: int, start_month_range: int, end_month_range: int +) -> list[str]: + """ + This function create a list of date ranges. + + For example, I want to create date ranges for 2020 and 2021, but only for the months from March to May. + I therefore expect to have 2 ranges: [2020-03-01 to 2020-05-30, 2021-03-01 to 2021-05-30]. + + Handles the automatic definition of the last day for the end month, as well as periods that cross over years + + For example, I want to create date ranges for 2020 and 2022, but only for the months from November to January. + I therefore expect to have 2 ranges: [2020-11-01 to 2021-01-31, 2021-11-01 to 2022-01-31]. + + Args: + start_year: Start year for ranges + end_year: End year for ranges + start_month_range: Starting month for each period + end_month_range: End month for each period (inclusively) + + Returns: + """ + date_ranges = [] + year_bump = 0 + if start_month_range > end_month_range: + year_bump = 1 + range_end_year = end_year + 1 - year_bump + for year in range(start_year, range_end_year): + start_date = datetime.datetime(year, start_month_range, 1) + last_day = calendar.monthrange(year + year_bump, end_month_range)[1] + end_date = datetime.datetime(year + year_bump, end_month_range, last_day, 23, 59, 59) + date_ranges.append(f"{start_date.isoformat()}Z/{end_date.isoformat()}Z") + return date_ranges + + LOGGER = create_logger(__name__) diff --git a/src/geospatial_tools/utils.py b/src/geospatial_tools/utils.py index b525fed..0ff300e 100644 --- a/src/geospatial_tools/utils.py +++ b/src/geospatial_tools/utils.py @@ -2,8 +2,6 @@ from __future__ import annotations -import calendar -import datetime import json import logging import os @@ -235,41 +233,6 @@ def unzip_file(zip_path: str | Path, extract_to: str | Path, logger: logging.Log return extracted_files -def create_date_range_for_specific_period( - start_year: int, end_year: int, start_month_range: int, end_month_range: int -) -> list[str]: - """ - This function create a list of date ranges. - - For example, I want to create date ranges for 2020 and 2021, but only for the months from March to May. - I therefore expect to have 2 ranges: [2020-03-01 to 2020-05-30, 2021-03-01 to 2021-05-30]. - - Handles the automatic definition of the last day for the end month, as well as periods that cross over years - - For example, I want to create date ranges for 2020 and 2022, but only for the months from November to January. - I therefore expect to have 2 ranges: [2020-11-01 to 2021-01-31, 2021-11-01 to 2022-01-31]. - - Args: - start_year: Start year for ranges - end_year: End year for ranges - start_month_range: Starting month for each period - end_month_range: End month for each period (inclusively) - - Returns: - """ - date_ranges = [] - year_bump = 0 - if start_month_range > end_month_range: - year_bump = 1 - range_end_year = end_year + 1 - year_bump - for year in range(start_year, range_end_year): - start_date = datetime.datetime(year, start_month_range, 1) - last_day = calendar.monthrange(year + year_bump, end_month_range)[1] - end_date = datetime.datetime(year + year_bump, end_month_range, last_day, 23, 59, 59) - date_ranges.append(f"{start_date.isoformat()}Z/{end_date.isoformat()}Z") - return date_ranges - - def _read_cstring(f) -> bytes: """Read a null-terminated byte string from the current position.""" out = bytearray() diff --git a/src/geospatial_tools/vector.py b/src/geospatial_tools/vector.py index ce8928d..57bc414 100644 --- a/src/geospatial_tools/vector.py +++ b/src/geospatial_tools/vector.py @@ -34,6 +34,7 @@ def create_grid_coordinates( logger: Logger instance. Returns: + A tuple containing two numpy arrays for longitude and latitude coordinates. """ logger.info(f"Creating grid coordinates for bounding box [{bounding_box}]") min_lon, min_lat, max_lon, max_lat = bounding_box @@ -82,10 +83,7 @@ def _create_polygons_from_coords_chunk(chunk: tuple[ndarray, ndarray, float]) -> def create_vector_grid( - bounding_box: list | tuple | ndarray, - grid_size: float, - crs: str | int | None = None, - logger: logging.Logger = LOGGER, + bounding_box: list | tuple, grid_size: float, crs: str = "4326", logger: logging.Logger = LOGGER ) -> GeoDataFrame: """ Create a grid of polygons within the specified bounds and cell size. This function uses NumPy vectorized arrays for @@ -116,7 +114,7 @@ def create_vector_grid( if crs: properties["crs"] = crs grid = GeoDataFrame(**properties) - grid.sindex # pylint: disable=W0104 + _ = grid.sindex _generate_uuid_column(grid) return grid @@ -175,7 +173,7 @@ def create_vector_grid_parallel( properties["crs"] = projection grid: GeoDataFrame = GeoDataFrame(**properties) logger.info("Creating spatial index") - grid.sindex # pylint: disable=W0104 + _ = grid.sindex logger.info("Generating polygon UUIDs") _generate_uuid_column(grid) return grid @@ -200,16 +198,18 @@ def dask_spatial_join( intersected_with: GeoDataFrame, join_type: str = "inner", predicate: str = "intersects", - num_of_workers: int = 4, + num_of_workers=4, + logger: logging.Logger = LOGGER, ) -> GeoDataFrame: """ Args: select_features_from: intersected_with: - join_type: str: - predicate: str: + join_type: + predicate: num_of_workers: + logger: Returns: @@ -217,63 +217,22 @@ def dask_spatial_join( """ dask_select_gdf = dgpd.from_geopandas(select_features_from, npartitions=num_of_workers) dask_intersected_gdf = dgpd.from_geopandas(intersected_with, npartitions=1) + logger.info("Concatenating results") result = dgpd.sjoin(dask_select_gdf, dask_intersected_gdf, how=join_type, predicate=predicate).compute() result = GeoDataFrame(result) - result.sindex # pylint: disable=W0104 + logger.info("Creating spatial index") + _ = result.sindex return result -def multiprocessor_spatial_join( - select_features_from: GeoDataFrame, - intersected_with: GeoDataFrame, - join_type: str = "inner", - predicate: str = "intersects", - num_of_workers: int = 4, - logger: logging.Logger = LOGGER, -) -> GeoDataFrame: - """ - - Args: - select_features_from: Numpy array containing the polygons from which to select features from. - intersected_with: Geodataframe containing the polygons that will be used to select features with via an - intersect operation. - join_type: How the join will be executed. Available join_types are: - ['left', 'right', 'inner']. Defaults to 'inner' - predicate: The predicate to use for selecting features from. Available predicates are: - ['intersects', 'contains', 'within', 'touches', 'crosses', 'overlaps']. Defaults to 'intersects' - num_of_workers: The number of processes to use for parallel execution. Defaults to 4. - logger: Logger instance. - - Returns: - - - """ - select_features_from_chunks = np.array_split(select_features_from, num_of_workers) - with ProcessPoolExecutor(max_workers=num_of_workers) as executor: - futures = [ - executor.submit(gpd.sjoin, chunk, intersected_with, how=join_type, predicate=predicate) - for chunk in select_features_from_chunks - ] - intersecting_polygons_list = [future.result() for future in futures] - logger.info("Concatenating results") - intersecting_polygons = gpd.GeoDataFrame(pd.concat(intersecting_polygons_list, ignore_index=True)) - logger.info("Creating spatial index") - intersecting_polygons.sindex # pylint: disable=W0104 - if len(intersected_with) > 1: - # This last step is necessary when doing a spatial join where `intersected_with` contains multiple features - logger.info("Dropping duplicates") - intersecting_polygons = intersecting_polygons.drop_duplicates(subset="geometry") - return intersecting_polygons - - def select_polygons_by_location( select_features_from: GeoDataFrame, intersected_with: GeoDataFrame, num_of_workers: int | None = None, join_type: str = "inner", - predicate: str = "intersects", - join_function=multiprocessor_spatial_join, + predicate="intersects", + join_function=dask_spatial_join, logger: logging.Logger = LOGGER, ) -> GeoDataFrame: """ @@ -299,7 +258,7 @@ def select_polygons_by_location( Returns: """ - workers = cpu_count() + workers = min(cpu_count(), 4) if num_of_workers: workers = num_of_workers logger.info(f"Number of workers used: {workers}") @@ -378,100 +337,6 @@ def to_geopackage_chunked( return filename -def select_all_within_feature(polygon_feature: gpd.GeoSeries, vector_features: gpd.GeoDataFrame) -> gpd.GeoSeries: - """ - This function is quite small and simple, but exists mostly as a. - - Args: - polygon_feature: Polygon feature that will be used to find which features of `vector_features` are contained - within it. In this function, it is expected to be a GeoSeries, so a single row from a GeoDataFrame. - vector_features: The dataframe containing the features that will be grouped by polygon_feature. - - Returns: - """ - contained_features = vector_features[vector_features.within(polygon_feature.geometry)] - return contained_features - - -def add_and_fill_contained_column( - polygon_feature, polygon_column_name: str, vector_features, vector_column_name: str, logger=LOGGER -) -> None: - """ - This function make in place changes to `vector_geodataframe`. - - The purpose of this function is to first do a spatial search operation on which `vector_features` are within - `polygon_feature`, and then write the contents found in the `polygon_column_name` to the selected `vector_features` - - Args: - polygon_feature: Polygon feature that will be used to find which features of `vector_features` are contained - within it. - polygon_column_name: The name of the column in `polygon_feature` that contains the name/id of each polygon to - be written to `vector_features`. - vector_features: The dataframe containing the features that will be grouped by polygon_feature. - vector_column_name: The name of the column in `vector_features` that will the name/id of each polygon. - logger: Logger instance - - Returns: - """ - feature_name = polygon_feature[polygon_column_name] - logger.info(f"Selecting all vector features that are within {feature_name}") - selected_features = select_all_within_feature(polygon_feature=polygon_feature, vector_features=vector_features) - logger.info(f"Writing [{feature_name}] to selected vector features") - - vector_features.loc[selected_features.index, vector_column_name] = vector_features.loc[ - selected_features.index, vector_column_name - ].apply(lambda s: s | {feature_name}) - - -# Potential outdated function -def find_and_write_all_contained_features( - polygon_features: gpd.GeoDataFrame, - polygon_column: str, - vector_features: gpd.GeoDataFrame, - vector_column_name: str, - logger=LOGGER, -) -> None: - """ - This function make in place changes to `vector_geodataframe`. - - It iterates on all features of a dataframe containing polygons and executes a spatial search with each - polygon to find all vector features from `vector_features` that are contained by it. - - The name/id of each polygon is added to a set in a new column in - `vector_features` to identify which features are within which polygon. - - To make things simple, this is basically a "group by" operation based on the - "within" spatial operator. Each feature in `vector_features` will have a list of - all the polygons that contain it (contain as being completely within the polygon). - - Args: - polygon_features: Dataframes containing polygons. Will be used to find which features of `vector_features` - are contained within which polygon - polygon_column: The name of the column in `polygon_features` that contains the name/id - of each polygon. - vector_features: The dataframe containing the features that will be grouped by polygon. - vector_column_name: The name of the column in `vector_features` that will the name/id of each polygon. - logger: (Default value = LOGGER) - - Returns: - """ - if vector_column_name not in vector_features.columns: - vector_features[vector_column_name] = [set() for _ in range(len(vector_features))] - - logger.info("Starting process to find and identify contained features") - polygon_features.apply( - lambda row: add_and_fill_contained_column( - polygon_feature=row, - polygon_column_name=polygon_column, - vector_features=vector_features, - vector_column_name=vector_column_name, - ), - axis=1, - ) - vector_features[vector_column_name] = vector_features[vector_column_name].apply(sorted) - logger.info("Process to find and identify contained features is completed") - - def spatial_join_within( polygon_features: gpd.GeoDataFrame, polygon_column: str, @@ -482,13 +347,8 @@ def spatial_join_within( logger=LOGGER, ) -> gpd.GeoDataFrame: """ - This function does approximately the same thing as `find_and_write_all_contained_features`, but does not make in - place changes to `vector_features` and instead returns a new dataframe. - - This function is more efficient than `find_and_write_all_contained_features` but offers less flexibility. - - It does a spatial join based on a within operation between features to associate which `vector_features` - are within which `polygon_features`, groups the results by vector feature + This function does a spatial join based on a within operation between features to associate which `vector_features` + are within which `polygon_features`, groups the results by vector feature. Args: polygon_features: Dataframes containing polygons. Will be used to find which features of `vector_features` @@ -497,11 +357,12 @@ def spatial_join_within( of each polygon. vector_features: The dataframe containing the features that will be grouped by polygon. vector_column_name: The name of the column in `vector_features` that will contain the name/id of each polygon. - join_type: + join_type: The type of join to perform. Defaults to 'left'. predicate: The predicate to use for the spatial join operation. Defaults to `within`. logger: Logger instance Returns: + A new GeoDataFrame with the joined features. """ temp_feature_id = "feature_id" uuid_suffix = str(uuid.uuid4()) @@ -518,7 +379,7 @@ def spatial_join_within( logger.info("Cleaning and merging results") features = vector_features.merge(grouped_gdf, on=temp_feature_id, how="left") features = features.rename(columns={polygon_column: vector_column_name}) - features.drop(columns=[temp_feature_id], inplace=True) + features = features.drop(columns=[temp_feature_id]) features[vector_column_name] = features[vector_column_name].apply(sorted) logger.info("Spatial join operation is completed") return gpd.GeoDataFrame(features) diff --git a/tests/test_copernicus.py b/tests/test_copernicus.py index 85232a9..3f89656 100644 --- a/tests/test_copernicus.py +++ b/tests/test_copernicus.py @@ -17,12 +17,12 @@ import pytest -from geospatial_tools.copernicus.sentinel_2 import ( +from geospatial_tools.stac.copernicus import ( CopernicusS2Band, CopernicusS2Collection, CopernicusS2Resolution, ) -from geospatial_tools.stac import COPERNICUS, StacSearch +from geospatial_tools.stac.core import COPERNICUS, StacSearch from geospatial_tools.utils import create_logger LOGGER = create_logger("test_copernicus") diff --git a/tests/test_notebooks/test_copernicus_sentinel2.ipynb b/tests/test_notebooks/test_copernicus_sentinel2.ipynb new file mode 100644 index 0000000..d8a78a3 --- /dev/null +++ b/tests/test_notebooks/test_copernicus_sentinel2.ipynb @@ -0,0 +1,332 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "intro", + "metadata": {}, + "source": [ + "# Copernicus Sentinel-2 Exploration\n", + "\n", + "This notebook showcases how to use the `geospatial_tools` library to search for and download Sentinel-2 products from the **Copernicus Data Space Ecosystem (CDSE)** STAC catalog. \n", + "\n", + "We will demonstrate:\n", + "1. Initializing the `StacSearch` client for Copernicus.\n", + "2. Performing a spatial and temporal search.\n", + "3. Inspecting STAC items and assets.\n", + "4. Downloading data using the **S3 Protocol** for optimized access.\n", + "\n", + "## Prerequisites\n", + "1. Create a Copernicus Account here : []()\n", + "2. Register an S3 access key here : [https://documentation.dataspace.copernicus.eu/APIs/S3.html](https://documentation.dataspace.copernicus.eu/APIs/S3.html)\n", + "3. Create your own .env file from the .env.example file with your copernicus credentials" + ] + }, + { + "cell_type": "code", + "id": "imports", + "metadata": { + "ExecuteTime": { + "end_time": "2026-04-20T17:12:55.759552110Z", + "start_time": "2026-04-20T17:12:55.721725358Z" + } + }, + "source": [ + "\n", + "import leafmap\n", + "import shutil\n", + "from geospatial_tools.stac.core import StacSearch, COPERNICUS\n", + "from geospatial_tools.stac.copernicus import CopernicusS2Collection, CopernicusS2Band, CopernicusS2Property\n", + "from geospatial_tools import TESTS_DIR" + ], + "outputs": [], + "execution_count": 9 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-04-20T17:12:55.832579480Z", + "start_time": "2026-04-20T17:12:55.781912255Z" + } + }, + "cell_type": "code", + "source": [ + "# Folder setup\n", + "TEST_TMP_DIR = TESTS_DIR / \"test_notebooks/tmp_copernicus_sentinel2\"\n", + "TEST_TMP_DIR.mkdir(exist_ok=True)" + ], + "id": "5d1671900aa90729", + "outputs": [], + "execution_count": 10 + }, + { + "cell_type": "markdown", + "id": "search_config", + "metadata": {}, + "source": [ + "## 1. Define Search Parameters\n", + "\n", + "We'll search for Sentinel-2 Level-2A data over Rome, Italy, for a specific period in 2024." + ] + }, + { + "cell_type": "code", + "id": "search_params", + "metadata": { + "ExecuteTime": { + "end_time": "2026-04-20T17:12:55.908335348Z", + "start_time": "2026-04-20T17:12:55.857887635Z" + } + }, + "source": [ + "# Bounding box for Rome [min_lon, min_lat, max_lon, max_lat]\n", + "bbox = [12.4, 41.8, 12.5, 41.9]\n", + "date_range = \"2024-07-01/2024-07-31\"\n", + "collections = [CopernicusS2Collection.L2A]\n", + "\n", + "print(f\"Searching in {bbox} for period {date_range}...\")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Searching in [12.4, 41.8, 12.5, 41.9] for period 2024-07-01/2024-07-31...\n" + ] + } + ], + "execution_count": 11 + }, + { + "cell_type": "markdown", + "id": "perform_search", + "metadata": {}, + "source": [ + "## 2. Initialize StacSearch and Query\n", + "\n", + "Initializing `StacSearch` with `catalog_name=COPERNICUS` automatically configures the S3 client using the credentials found in your `.env` file." + ] + }, + { + "cell_type": "code", + "id": "search_exec", + "metadata": { + "ExecuteTime": { + "end_time": "2026-04-20T17:12:56.894441643Z", + "start_time": "2026-04-20T17:12:55.924355557Z" + } + }, + "source": [ + "stac_search = StacSearch(catalog_name=COPERNICUS)\n", + "\n", + "results = stac_search.search(\n", + " bbox=bbox, \n", + " date_range=date_range, \n", + " collections=collections,\n", + " max_items=1\n", + ")\n", + "\n", + "print(f\"Found {len(results)} items.\")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2026-04-20 13:12:56] INFO [MainThread][geospatial_tools.stac.utils] Creating S3 client with endpoint: [https://eodata.dataspace.copernicus.eu]\n", + "[2026-04-20 13:12:56] INFO [MainThread][geospatial_tools.stac.core] Initiating STAC API search\n", + "Found 1 items.\n" + ] + } + ], + "execution_count": 12 + }, + { + "cell_type": "markdown", + "id": "inspect_results", + "metadata": {}, + "source": [ + "## 3. Inspect Results\n", + "\n", + "Let's look at the first item and its available assets." + ] + }, + { + "cell_type": "code", + "id": "inspect_exec", + "metadata": { + "ExecuteTime": { + "end_time": "2026-04-20T17:12:57.016154248Z", + "start_time": "2026-04-20T17:12:56.944957063Z" + } + }, + "source": [ + "if results:\n", + " item = results[0]\n", + " print(f\"Item ID: {item.id}\")\n", + " print(f\"Cloud Cover: {item.properties.get(CopernicusS2Property.CLOUD_COVER)}% \")\n", + " \n", + " # List a few bands/assets\n", + " available_assets = list(item.assets.keys())\n", + " print(f\"First 10 assets: {available_assets[:10]}\")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Item ID: S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034\n", + "Cloud Cover: 0.0% \n", + "First 10 assets: ['AOT_10m', 'AOT_20m', 'AOT_60m', 'B01_20m', 'B01_60m', 'B02_10m', 'B02_20m', 'B02_60m', 'B03_10m', 'B03_20m']\n" + ] + } + ], + "execution_count": 13 + }, + { + "cell_type": "markdown", + "id": "visualize_search", + "metadata": {}, + "source": [ + "We can visualize the search area and the footprint of the first result using `leafmap`." + ] + }, + { + "cell_type": "markdown", + "id": "download_assets", + "metadata": {}, + "source": [ + "## 4. Download Assets using S3\n", + "\n", + "Now we download the True Color Image (TCI) and the NIR band (B08) using the optimized S3 protocol." + ] + }, + { + "cell_type": "code", + "id": "download_exec", + "metadata": { + "ExecuteTime": { + "end_time": "2026-04-20T17:13:14.597828273Z", + "start_time": "2026-04-20T17:12:57.028239189Z" + } + }, + "source": [ + "download_dir = TEST_TMP_DIR / \"sentinel-2\" / \"copernicus_exploration\"\n", + "download_dir.mkdir(parents=True, exist_ok=True)\n", + "\n", + "bands = [\n", + " CopernicusS2Band.TCI,\n", + " CopernicusS2Band.B08\n", + "]\n", + "\n", + "print(f\"Downloading bands {bands} to {download_dir} via S3...\")\n", + "\n", + "# download_search_results will handle the dispatcher logic automatically\n", + "downloaded_assets = stac_search.download_search_results(\n", + " bands=bands, \n", + " base_directory=download_dir\n", + ")\n", + "\n", + "for asset in downloaded_assets:\n", + " asset.show_asset_items()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading bands [, ] to /home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_copernicus_sentinel2/sentinel-2/copernicus_exploration via S3...\n", + "[2026-04-20 13:12:57] INFO [MainThread][geospatial_tools.stac.core] Downloading [S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034] ...\n", + "[2026-04-20 13:12:57] INFO [MainThread][geospatial_tools.stac.core] Retrieving Copernicus credentials...\n", + "[2026-04-20 13:12:57] INFO [MainThread][geospatial_tools.stac.core] Successfully retrieved Copernicus credentials.\n", + "[2026-04-20 13:12:58] INFO [MainThread][geospatial_tools.stac.core] Successfully obtained Copernicus access token.\n", + "[2026-04-20 13:12:58] INFO [MainThread][geospatial_tools.stac.core] Downloading TCI_10m from s3://eodata/Sentinel-2/MSI/L2A/2024/07/28/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034.SAFE/GRANULE/L2A_T33TTG_A038615_20240728T095731/IMG_DATA/R10m/T33TTG_20240728T095549_TCI_10m.jp2 using method [s3]\n", + "[2026-04-20 13:12:58] INFO [MainThread][geospatial_tools.stac.core] Downloading from S3: bucket=[eodata], key=[Sentinel-2/MSI/L2A/2024/07/28/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034.SAFE/GRANULE/L2A_T33TTG_A038615_20240728T095731/IMG_DATA/R10m/T33TTG_20240728T095549_TCI_10m.jp2] to [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_copernicus_sentinel2/sentinel-2/copernicus_exploration/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034_TCI_10m.tif]\n", + "[2026-04-20 13:13:08] INFO [MainThread][geospatial_tools.stac.core] Downloading B08_10m from s3://eodata/Sentinel-2/MSI/L2A/2024/07/28/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034.SAFE/GRANULE/L2A_T33TTG_A038615_20240728T095731/IMG_DATA/R10m/T33TTG_20240728T095549_B08_10m.jp2 using method [s3]\n", + "[2026-04-20 13:13:08] INFO [MainThread][geospatial_tools.stac.core] Downloading from S3: bucket=[eodata], key=[Sentinel-2/MSI/L2A/2024/07/28/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034.SAFE/GRANULE/L2A_T33TTG_A038615_20240728T095731/IMG_DATA/R10m/T33TTG_20240728T095549_B08_10m.jp2] to [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_copernicus_sentinel2/sentinel-2/copernicus_exploration/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034_B08_10m.tif]\n", + "[2026-04-20 13:13:14] INFO [MainThread][geospatial_tools.stac.core] Asset list for asset [S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034] :\n", + "\t['ID: [S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034], Band: [TCI_10m], filename: [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_copernicus_sentinel2/sentinel-2/copernicus_exploration/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034_TCI_10m.tif]', 'ID: [S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034], Band: [B08_10m], filename: [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_copernicus_sentinel2/sentinel-2/copernicus_exploration/S2B_MSIL2A_20240728T095549_N0511_R122_T33TTG_20240728T114034_B08_10m.tif]']\n" + ] + } + ], + "execution_count": 14 + }, + { + "cell_type": "code", + "id": "17afc08e6f4682c6", + "metadata": { + "ExecuteTime": { + "end_time": "2026-04-20T17:13:14.962236125Z", + "start_time": "2026-04-20T17:13:14.671219459Z" + } + }, + "source": [ + "tci_asset = downloaded_assets[0][CopernicusS2Band.TCI]\n", + "m = leafmap.Map()\n", + "m.add_raster(source=str(tci_asset.filename))\n", + "m" + ], + "outputs": [ + { + "data": { + "text/plain": [ + "Map(center=[41.9185435, 12.0389935], controls=(ZoomControl(options=['position', 'zoom_in_text', 'zoom_in_title\u2026" + ], + "application/vnd.jupyter.widget-view+json": { + "version_major": 2, + "version_minor": 0, + "model_id": "578896f1f43c47fbbd602823901b9c84" + } + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 15 + }, + { + "cell_type": "markdown", + "id": "conclusion", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "By using the `StacSearch` dispatcher with the `COPERNICUS` catalog, you can seamlessly switch from HTTP downloads to direct S3 bucket access, which is significantly faster and more reliable for large-scale data retrieval." + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-04-20T17:13:15.043316476Z", + "start_time": "2026-04-20T17:13:14.966129935Z" + } + }, + "cell_type": "code", + "source": "shutil.rmtree(TEST_TMP_DIR)", + "id": "c6c459159c4721a2", + "outputs": [], + "execution_count": 16 + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.11.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file diff --git a/tests/test_notebooks/test_planetary_computer_sentinel2.ipynb b/tests/test_notebooks/test_planetary_computer_sentinel2.ipynb index dbacd1c..0571a91 100644 --- a/tests/test_notebooks/test_planetary_computer_sentinel2.ipynb +++ b/tests/test_notebooks/test_planetary_computer_sentinel2.ipynb @@ -5,8 +5,8 @@ "id": "26590ffa", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:26:45.182290Z", - "start_time": "2025-10-24T02:26:34.621503Z" + "end_time": "2026-04-20T17:07:03.310825250Z", + "start_time": "2026-04-20T17:06:43.728550903Z" } }, "source": [ @@ -16,9 +16,9 @@ "import leafmap\n", "\n", "from geospatial_tools import DATA_DIR, TESTS_DIR\n", - "from geospatial_tools.planetary_computer.sentinel_2 import BestProductsForFeatures, download_and_process_sentinel2_asset\n", + "from geospatial_tools.stac.planetary_computer.sentinel_2 import BestProductsForFeatures, download_and_process_sentinel2_asset\n", "from geospatial_tools.raster import clip_raster_with_polygon\n", - "from geospatial_tools.stac import Asset\n", + "from geospatial_tools.stac.core import Asset\n", "from geospatial_tools.vector import create_vector_grid_parallel, select_polygons_by_location, to_geopackage" ], "outputs": [], @@ -29,8 +29,8 @@ "id": "bbf8d1aede2a4fd2", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:26:45.308968Z", - "start_time": "2025-10-24T02:26:45.298373Z" + "end_time": "2026-04-20T17:07:03.511075920Z", + "start_time": "2026-04-20T17:07:03.420193130Z" } }, "source": [ @@ -66,8 +66,8 @@ "id": "fcb67d1eb21aafc1", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:26:45.842939Z", - "start_time": "2025-10-24T02:26:45.714239Z" + "end_time": "2026-04-20T17:07:06.145831275Z", + "start_time": "2026-04-20T17:07:05.924787130Z" } }, "source": [ @@ -84,8 +84,8 @@ "id": "314e7c068786ad4d", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:26:45.935556Z", - "start_time": "2025-10-24T02:26:45.903989Z" + "end_time": "2026-04-20T17:07:06.412753518Z", + "start_time": "2026-04-20T17:07:06.233049768Z" } }, "source": [ @@ -151,8 +151,8 @@ "id": "3e9461ed5b602319", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:26:46.503944Z", - "start_time": "2025-10-24T02:26:46.477325Z" + "end_time": "2026-04-20T17:07:06.656475947Z", + "start_time": "2026-04-20T17:07:06.509702249Z" } }, "source": [ @@ -326,8 +326,8 @@ "id": "d4546352d604eaf", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:23.202550Z", - "start_time": "2025-10-24T02:27:14.294676Z" + "end_time": "2026-04-20T17:07:12.212977143Z", + "start_time": "2026-04-20T17:07:08.124119192Z" } }, "source": [ @@ -345,18 +345,18 @@ "output_type": "stream", "text": [ "Starting processing for [create_vector_grid_parallel]\n", - "[2025-10-23 22:27:14] INFO [MainThread][geospatial_tools.vector] Creating grid coordinates for bounding box [[-2356113.74289801 301469.31619713 2258154.44089948 3165721.6501298 ]]\n", - "[2025-10-23 22:27:14] INFO [MainThread][geospatial_tools.vector] Creating flattened grid coordinates\n", - "[2025-10-23 22:27:14] INFO [MainThread][geospatial_tools.vector] Number of workers used: 4\n", - "[2025-10-23 22:27:14] INFO [MainThread][geospatial_tools.vector] Allocating polygon array for [132594] polygons\n", - "[2025-10-23 22:27:14] INFO [MainThread][geospatial_tools.vector] Creating polygons from chunks\n", - "[2025-10-23 22:27:19] INFO [MainThread][geospatial_tools.vector] Managing properties\n", - "[2025-10-23 22:27:19] INFO [MainThread][geospatial_tools.utils] Creating EPSG code from following input : [EPSG:5070]\n", - "[2025-10-23 22:27:19] INFO [MainThread][geospatial_tools.vector] Creating spatial index\n", - "[2025-10-23 22:27:19] INFO [MainThread][geospatial_tools.vector] Generating polygon UUIDs\n", + "[2026-04-20 13:07:08] INFO [MainThread][geospatial_tools.vector] Creating grid coordinates for bounding box [[-2356113.74289801 301469.31619713 2258154.44089948 3165721.6501298 ]]\n", + "[2026-04-20 13:07:08] INFO [MainThread][geospatial_tools.vector] Creating flattened grid coordinates\n", + "[2026-04-20 13:07:08] INFO [MainThread][geospatial_tools.vector] Number of workers used: 4\n", + "[2026-04-20 13:07:08] INFO [MainThread][geospatial_tools.vector] Allocating polygon array for [132594] polygons\n", + "[2026-04-20 13:07:08] INFO [MainThread][geospatial_tools.vector] Creating polygons from chunks\n", + "[2026-04-20 13:07:10] INFO [MainThread][geospatial_tools.vector] Managing properties\n", + "[2026-04-20 13:07:10] INFO [MainThread][geospatial_tools.utils] Creating EPSG code from following input : [EPSG:5070]\n", + "[2026-04-20 13:07:10] INFO [MainThread][geospatial_tools.vector] Creating spatial index\n", + "[2026-04-20 13:07:10] INFO [MainThread][geospatial_tools.vector] Generating polygon UUIDs\n", "Printing len(grid_parallel) to check if grid contains same amount of polygons : 132594\n", - "[2025-10-23 22:27:20] INFO [MainThread][geospatial_tools.vector] Starting writing process\n", - "[2025-10-23 22:27:23] INFO [MainThread][geospatial_tools.vector] File [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/polygon_grid_10km.gpkg] took 2.2846741676330566 seconds to write.\n" + "[2026-04-20 13:07:11] INFO [MainThread][geospatial_tools.vector] Starting writing process\n", + "[2026-04-20 13:07:12] INFO [MainThread][geospatial_tools.vector] File [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/polygon_grid_10km.gpkg] took 0.6583468914031982 seconds to write.\n" ] }, { @@ -392,8 +392,8 @@ "id": "7fb328be7527d9cb", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:32.208219Z", - "start_time": "2025-10-24T02:27:23.565754Z" + "end_time": "2026-04-20T17:07:15.707753221Z", + "start_time": "2026-04-20T17:07:12.232527207Z" } }, "source": [ @@ -410,12 +410,12 @@ "output_type": "stream", "text": [ "Starting intersect selection\n", - "[2025-10-23 22:27:23] INFO [MainThread][geospatial_tools.vector] Number of workers used: 4\n", - "[2025-10-23 22:27:30] INFO [MainThread][geospatial_tools.vector] Concatenating results\n", - "[2025-10-23 22:27:30] INFO [MainThread][geospatial_tools.vector] Creating spatial index\n", - "[2025-10-23 22:27:30] INFO [MainThread][geospatial_tools.vector] Filtering columns of the results\n", - "[2025-10-23 22:27:30] INFO [MainThread][geospatial_tools.vector] Starting writing process\n", - "[2025-10-23 22:27:32] INFO [MainThread][geospatial_tools.vector] File [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/intersecting_polygon_grid_10km.gpkg] took 1.4507484436035156 seconds to write.\n" + "[2026-04-20 13:07:12] INFO [MainThread][geospatial_tools.vector] Number of workers used: 4\n", + "[2026-04-20 13:07:12] INFO [MainThread][geospatial_tools.vector] Concatenating results\n", + "[2026-04-20 13:07:15] INFO [MainThread][geospatial_tools.vector] Creating spatial index\n", + "[2026-04-20 13:07:15] INFO [MainThread][geospatial_tools.vector] Filtering columns of the results\n", + "[2026-04-20 13:07:15] INFO [MainThread][geospatial_tools.vector] Starting writing process\n", + "[2026-04-20 13:07:15] INFO [MainThread][geospatial_tools.vector] File [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/intersecting_polygon_grid_10km.gpkg] took 0.4539949893951416 seconds to write.\n" ] }, { @@ -452,8 +452,8 @@ "id": "89c0d198-d672-4815-904b-7a7c4be6cb03", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:32.634168Z", - "start_time": "2025-10-24T02:27:32.619651Z" + "end_time": "2026-04-20T17:07:15.839200717Z", + "start_time": "2026-04-20T17:07:15.770280422Z" } }, "source": [ @@ -1461,8 +1461,8 @@ "id": "16a81d07b4c374f2", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:33.192429Z", - "start_time": "2025-10-24T02:27:33.188879Z" + "end_time": "2026-04-20T17:07:15.890275248Z", + "start_time": "2026-04-20T17:07:15.841460061Z" } }, "source": [ @@ -1487,8 +1487,8 @@ "id": "a28a39a8", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:33.585993Z", - "start_time": "2025-10-24T02:27:33.538532Z" + "end_time": "2026-04-20T17:07:15.947667271Z", + "start_time": "2026-04-20T17:07:15.892127545Z" } }, "source": [ @@ -1649,8 +1649,8 @@ "id": "ba455cf71d209878", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:33.893620Z", - "start_time": "2025-10-24T02:27:33.867335Z" + "end_time": "2026-04-20T17:07:16.110963473Z", + "start_time": "2026-04-20T17:07:16.048343298Z" } }, "source": [ @@ -1667,8 +1667,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "[2025-10-23 22:27:33] INFO [MainThread][geospatial_tools.vector] Starting writing process\n", - "[2025-10-23 22:27:33] INFO [MainThread][geospatial_tools.vector] File [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/s2_grid_usa_polygon_5070_subset.gpkg] took 0.018416881561279297 seconds to write.\n" + "[2026-04-20 13:07:16] INFO [MainThread][geospatial_tools.vector] Starting writing process\n", + "[2026-04-20 13:07:16] INFO [MainThread][geospatial_tools.vector] File [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/s2_grid_usa_polygon_5070_subset.gpkg] took 0.017882347106933594 seconds to write.\n" ] }, { @@ -1689,8 +1689,8 @@ "id": "1768b409e3462310", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:35.081982Z", - "start_time": "2025-10-24T02:27:35.065342Z" + "end_time": "2026-04-20T17:07:16.857650467Z", + "start_time": "2026-04-20T17:07:16.803581369Z" } }, "source": [ @@ -1774,8 +1774,8 @@ "id": "142cc83267ef999", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:36.239925Z", - "start_time": "2025-10-24T02:27:35.662733Z" + "end_time": "2026-04-20T17:07:17.136333250Z", + "start_time": "2026-04-20T17:07:17.006890488Z" } }, "source": [ @@ -1797,13 +1797,12 @@ "output_type": "stream", "text": [ "Starting intersect selection\n", - "[2025-10-23 22:27:35] INFO [MainThread][geospatial_tools.vector] Number of workers used: 4\n", - "[2025-10-23 22:27:36] INFO [MainThread][geospatial_tools.vector] Concatenating results\n", - "[2025-10-23 22:27:36] INFO [MainThread][geospatial_tools.vector] Creating spatial index\n", - "[2025-10-23 22:27:36] INFO [MainThread][geospatial_tools.vector] Dropping duplicates\n", - "[2025-10-23 22:27:36] INFO [MainThread][geospatial_tools.vector] Filtering columns of the results\n", - "[2025-10-23 22:27:36] INFO [MainThread][geospatial_tools.vector] Starting writing process\n", - "[2025-10-23 22:27:36] INFO [MainThread][geospatial_tools.vector] File [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/intersecting_polygon_grid_10km_subset.gpkg] took 0.02221536636352539 seconds to write.\n" + "[2026-04-20 13:07:17] INFO [MainThread][geospatial_tools.vector] Number of workers used: 4\n", + "[2026-04-20 13:07:17] INFO [MainThread][geospatial_tools.vector] Concatenating results\n", + "[2026-04-20 13:07:17] INFO [MainThread][geospatial_tools.vector] Creating spatial index\n", + "[2026-04-20 13:07:17] INFO [MainThread][geospatial_tools.vector] Filtering columns of the results\n", + "[2026-04-20 13:07:17] INFO [MainThread][geospatial_tools.vector] Starting writing process\n", + "[2026-04-20 13:07:17] INFO [MainThread][geospatial_tools.vector] File [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/intersecting_polygon_grid_10km_subset.gpkg] took 0.014492511749267578 seconds to write.\n" ] }, { @@ -1832,8 +1831,8 @@ "id": "e6ccf064d6ac84c4", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:37.859450Z", - "start_time": "2025-10-24T02:27:37.853007Z" + "end_time": "2026-04-20T17:07:17.745067020Z", + "start_time": "2026-04-20T17:07:17.697539287Z" } }, "source": [ @@ -1858,8 +1857,8 @@ "metadata": { "scrolled": true, "ExecuteTime": { - "end_time": "2025-10-24T02:27:40.766791Z", - "start_time": "2025-10-24T02:27:38.161406Z" + "end_time": "2026-04-20T17:07:19.528378097Z", + "start_time": "2026-04-20T17:07:17.745958849Z" } }, "source": [ @@ -1883,17 +1882,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "[2025-10-23 22:27:38] INFO [ThreadPoolExecutor-0_0][geospatial_tools.stac] Running STAC API search for the following parameters: \n", + "[2026-04-20 13:07:18] INFO [ThreadPoolExecutor-1_0][geospatial_tools.stac.core] Running STAC API search for the following parameters: \n", "\tDate ranges : ['2024-06-01T00:00:00Z/2024-07-31T23:59:59Z'] \n", "\tQuery : {'eo:cloud_cover': {'lt': 15}, 's2:mgrs_tile': {'in': ['10SDJ']}}\n", - "[2025-10-23 22:27:38] INFO [ThreadPoolExecutor-0_1][geospatial_tools.stac] Running STAC API search for the following parameters: \n", - "\tDate ranges : ['2024-06-01T00:00:00Z/2024-07-31T23:59:59Z'] \n", - "\tQuery : {'eo:cloud_cover': {'lt': 15}, 's2:mgrs_tile': {'in': ['10TDK']}}\n", - "[2025-10-23 22:27:38] INFO [ThreadPoolExecutor-0_2][geospatial_tools.stac] Running STAC API search for the following parameters: \n", + "[2026-04-20 13:07:18] INFO [ThreadPoolExecutor-1_2][geospatial_tools.stac.core] Running STAC API search for the following parameters: \n", "\tDate ranges : ['2024-06-01T00:00:00Z/2024-07-31T23:59:59Z'] \n", "\tQuery : {'eo:cloud_cover': {'lt': 15}, 's2:mgrs_tile': {'in': ['10TEK']}}\n", - "[2025-10-23 22:27:40] WARNING [MainThread][geospatial_tools.planetary_computer.sentinel_2] Warning, some of the input Sentinel 2 tiles do not have products covering the entire tile. These tiles will need to be handled differently (ex. creating a mosaic with multiple products\n", - "[2025-10-23 22:27:40] WARNING [MainThread][geospatial_tools.planetary_computer.sentinel_2] Incomplete list: ['10TEK']\n" + "[2026-04-20 13:07:18] INFO [ThreadPoolExecutor-1_1][geospatial_tools.stac.core] Running STAC API search for the following parameters: \n", + "\tDate ranges : ['2024-06-01T00:00:00Z/2024-07-31T23:59:59Z'] \n", + "\tQuery : {'eo:cloud_cover': {'lt': 15}, 's2:mgrs_tile': {'in': ['10TDK']}}\n", + "[2026-04-20 13:07:19] WARNING [MainThread][geospatial_tools.stac.planetary_computer.sentinel_2] Warning, some of the input Sentinel 2 tiles do not have products covering the entire tile. These tiles will need to be handled differently (ex. creating a mosaic with multiple products\n", + "[2026-04-20 13:07:19] WARNING [MainThread][geospatial_tools.stac.planetary_computer.sentinel_2] Incomplete list: ['10TEK']\n" ] } ], @@ -1904,8 +1903,8 @@ "id": "3dfc816677db50aa", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:41.126001Z", - "start_time": "2025-10-24T02:27:41.121528Z" + "end_time": "2026-04-20T17:07:19.667494640Z", + "start_time": "2026-04-20T17:07:19.587467365Z" } }, "source": [ @@ -1935,8 +1934,8 @@ "id": "6a0a1885db3cd559", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:41.678127Z", - "start_time": "2025-10-24T02:27:41.596133Z" + "end_time": "2026-04-20T17:07:19.822418973Z", + "start_time": "2026-04-20T17:07:19.689872658Z" } }, "source": [ @@ -1953,14 +1952,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "[2025-10-23 22:27:41] INFO [MainThread][geospatial_tools.vector] Creating temporary UUID field for join operations\n", - "[2025-10-23 22:27:41] INFO [MainThread][geospatial_tools.vector] Starting process to find and identify contained features using spatial 'within' join operation\n", - "[2025-10-23 22:27:41] INFO [MainThread][geospatial_tools.vector] Grouping results\n", - "[2025-10-23 22:27:41] INFO [MainThread][geospatial_tools.vector] Cleaning and merging results\n", - "[2025-10-23 22:27:41] INFO [MainThread][geospatial_tools.vector] Spatial join operation is completed\n", - "[2025-10-23 22:27:41] INFO [MainThread][geospatial_tools.planetary_computer.sentinel_2] Writing best product IDs to dataframe\n", - "[2025-10-23 22:27:41] INFO [MainThread][geospatial_tools.vector] Starting writing process\n", - "[2025-10-23 22:27:41] INFO [MainThread][geospatial_tools.vector] File [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/vector_tiles_with_s2tiles_subset.gpkg] took 0.026682138442993164 seconds to write.\n" + "[2026-04-20 13:07:19] INFO [MainThread][geospatial_tools.vector] Creating temporary UUID field for join operations\n", + "[2026-04-20 13:07:19] INFO [MainThread][geospatial_tools.vector] Starting process to find and identify contained features using spatial 'within' join operation\n", + "[2026-04-20 13:07:19] INFO [MainThread][geospatial_tools.vector] Grouping results\n", + "[2026-04-20 13:07:19] INFO [MainThread][geospatial_tools.vector] Cleaning and merging results\n", + "[2026-04-20 13:07:19] INFO [MainThread][geospatial_tools.vector] Spatial join operation is completed\n", + "[2026-04-20 13:07:19] INFO [MainThread][geospatial_tools.stac.planetary_computer.sentinel_2] Writing best product IDs to dataframe\n", + "[2026-04-20 13:07:19] INFO [MainThread][geospatial_tools.vector] Starting writing process\n", + "[2026-04-20 13:07:19] INFO [MainThread][geospatial_tools.vector] File [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/vector_tiles_with_s2tiles_subset.gpkg] took 0.01683664321899414 seconds to write.\n" ] }, { @@ -1989,8 +1988,8 @@ "id": "48d5dd0759bc2a51", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:43.456579Z", - "start_time": "2025-10-24T02:27:43.450404Z" + "end_time": "2026-04-20T17:07:19.917958250Z", + "start_time": "2026-04-20T17:07:19.844686713Z" } }, "source": [ @@ -2020,8 +2019,8 @@ "id": "289caace-c963-4fe5-9a9e-b61a3f25473b", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:43.947239Z", - "start_time": "2025-10-24T02:27:43.937921Z" + "end_time": "2026-04-20T17:07:19.995714680Z", + "start_time": "2026-04-20T17:07:19.920227452Z" } }, "source": [ @@ -2046,8 +2045,8 @@ "id": "37ee4600ae353b9c", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:44.733947Z", - "start_time": "2025-10-24T02:27:44.418109Z" + "end_time": "2026-04-20T17:07:20.471594216Z", + "start_time": "2026-04-20T17:07:19.998477521Z" } }, "source": [ @@ -2065,7 +2064,7 @@ "application/vnd.jupyter.widget-view+json": { "version_major": 2, "version_minor": 0, - "model_id": "eed8ce08ce9d4d5f9e80166e7844f697" + "model_id": "d4d9e1b8952f4461b0be73f5a54deb78" } }, "execution_count": 20, @@ -2080,8 +2079,8 @@ "id": "4483f48422d09481", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:45.216065Z", - "start_time": "2025-10-24T02:27:45.208771Z" + "end_time": "2026-04-20T17:07:20.522490481Z", + "start_time": "2026-04-20T17:07:20.476659362Z" } }, "source": [ @@ -2096,8 +2095,8 @@ "id": "33797d5a6fdc1e59", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:27:45.567247Z", - "start_time": "2025-10-24T02:27:45.560156Z" + "end_time": "2026-04-20T17:07:20.601566585Z", + "start_time": "2026-04-20T17:07:20.526282940Z" } }, "source": [ @@ -2140,8 +2139,8 @@ "id": "da281a638f42c0dc", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:29:47.411877Z", - "start_time": "2025-10-24T02:27:46.152643Z" + "end_time": "2026-04-20T17:08:47.230736041Z", + "start_time": "2026-04-20T17:07:20.629359336Z" } }, "source": [ @@ -2162,50 +2161,50 @@ "name": "stdout", "output_type": "stream", "text": [ - "[2025-10-23 22:27:46] INFO [MainThread][geospatial_tools.stac] Initiating STAC API search\n", - "[2025-10-23 22:27:47] INFO [MainThread][geospatial_tools.planetary_computer.sentinel_2] []\n", - "[2025-10-23 22:27:47] INFO [MainThread][geospatial_tools.stac] Downloading [S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346] ...\n", - "[2025-10-23 22:27:47] INFO [MainThread][geospatial_tools.stac] Downloading B04 from https://sentinel2l2a01.blob.core.windows.net/sentinel2-l2/10/S/DJ/2024/07/05/S2A_MSIL2A_20240705T185921_N0510_R013_T10SDJ_20240706T050346.SAFE/GRANULE/L2A_T10SDJ_A047200_20240705T190418/IMG_DATA/R10m/T10SDJ_20240705T185921_B04_10m.tif?st=2025-10-23T02%3A27%3A39Z&se=2025-10-24T03%3A12%3A39Z&sp=rl&sv=2025-07-05&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2025-10-23T16%3A13%3A27Z&ske=2025-10-30T16%3A13%3A27Z&sks=b&skv=2025-07-05&sig=W3M/NVqz3rySDXNmsDbef7pJSE8PqSrhGoo0bDHEM5c%3D\n", - "[2025-10-23 22:28:05] INFO [MainThread][geospatial_tools.utils] Downloaded /home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_B04.tif successfully.\n", - "[2025-10-23 22:28:05] INFO [MainThread][geospatial_tools.stac] Downloading B08 from https://sentinel2l2a01.blob.core.windows.net/sentinel2-l2/10/S/DJ/2024/07/05/S2A_MSIL2A_20240705T185921_N0510_R013_T10SDJ_20240706T050346.SAFE/GRANULE/L2A_T10SDJ_A047200_20240705T190418/IMG_DATA/R10m/T10SDJ_20240705T185921_B08_10m.tif?st=2025-10-23T02%3A27%3A39Z&se=2025-10-24T03%3A12%3A39Z&sp=rl&sv=2025-07-05&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2025-10-23T16%3A13%3A27Z&ske=2025-10-30T16%3A13%3A27Z&sks=b&skv=2025-07-05&sig=W3M/NVqz3rySDXNmsDbef7pJSE8PqSrhGoo0bDHEM5c%3D\n", - "[2025-10-23 22:28:23] INFO [MainThread][geospatial_tools.utils] Downloaded /home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_B08.tif successfully.\n", - "[2025-10-23 22:28:23] INFO [MainThread][geospatial_tools.planetary_computer.sentinel_2] []\n", - "[2025-10-23 22:28:23] INFO [MainThread][geospatial_tools.stac] Creating merged asset metadata\n", - "[2025-10-23 22:28:24] INFO [MainThread][geospatial_tools.raster] Creating merged asset metadata\n", - "[2025-10-23 22:28:24] INFO [MainThread][geospatial_tools.raster] Calculated a total of [2] bands\n", - "[2025-10-23 22:28:24] INFO [MainThread][geospatial_tools.raster] Merging asset [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_merged.tif] ...\n", - "[2025-10-23 22:28:24] INFO [MainThread][geospatial_tools.raster] Writing band image: S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_B04.tif\n", - "[2025-10-23 22:28:24] INFO [MainThread][geospatial_tools.raster] Writing asset sub item band 1 to merged index band 1\n", - "[2025-10-23 22:28:27] INFO [MainThread][geospatial_tools.raster] Writing band image: S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_B08.tif\n", - "[2025-10-23 22:28:27] INFO [MainThread][geospatial_tools.raster] Writing asset sub item band 1 to merged index band 2\n", - "[2025-10-23 22:28:31] INFO [MainThread][geospatial_tools.stac] Asset [S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346] merged successfully\n", - "[2025-10-23 22:28:31] INFO [MainThread][geospatial_tools.stac] Asset location : [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_merged.tif]\n", - "[2025-10-23 22:28:31] INFO [MainThread][geospatial_tools.stac] Reprojecting asset [S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346] ...\n", - "[2025-10-23 22:28:31] INFO [MainThread][geospatial_tools.stac] Creating EPSG code from following input : [5070]\n", - "[2025-10-23 22:28:48] INFO [MainThread][geospatial_tools.stac] Reprojected file created at /home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_reprojected.tif\n", - "[2025-10-23 22:28:48] INFO [MainThread][geospatial_tools.stac] Asset location : [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_reprojected.tif]\n", - "[2025-10-23 22:28:48] INFO [MainThread][geospatial_tools.stac] Initiating STAC API search\n", - "[2025-10-23 22:28:49] INFO [MainThread][geospatial_tools.planetary_computer.sentinel_2] []\n", - "[2025-10-23 22:28:49] INFO [MainThread][geospatial_tools.stac] Downloading [S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412] ...\n", - "[2025-10-23 22:28:49] INFO [MainThread][geospatial_tools.stac] Downloading B04 from https://sentinel2l2a01.blob.core.windows.net/sentinel2-l2/10/T/DK/2024/07/05/S2A_MSIL2A_20240705T185921_N0510_R013_T10TDK_20240706T050412.SAFE/GRANULE/L2A_T10TDK_A047200_20240705T190418/IMG_DATA/R10m/T10TDK_20240705T185921_B04_10m.tif?st=2025-10-23T02%3A27%3A39Z&se=2025-10-24T03%3A12%3A39Z&sp=rl&sv=2025-07-05&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2025-10-23T16%3A13%3A27Z&ske=2025-10-30T16%3A13%3A27Z&sks=b&skv=2025-07-05&sig=W3M/NVqz3rySDXNmsDbef7pJSE8PqSrhGoo0bDHEM5c%3D\n", - "[2025-10-23 22:29:07] INFO [MainThread][geospatial_tools.utils] Downloaded /home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_B04.tif successfully.\n", - "[2025-10-23 22:29:07] INFO [MainThread][geospatial_tools.stac] Downloading B08 from https://sentinel2l2a01.blob.core.windows.net/sentinel2-l2/10/T/DK/2024/07/05/S2A_MSIL2A_20240705T185921_N0510_R013_T10TDK_20240706T050412.SAFE/GRANULE/L2A_T10TDK_A047200_20240705T190418/IMG_DATA/R10m/T10TDK_20240705T185921_B08_10m.tif?st=2025-10-23T02%3A27%3A39Z&se=2025-10-24T03%3A12%3A39Z&sp=rl&sv=2025-07-05&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2025-10-23T16%3A13%3A27Z&ske=2025-10-30T16%3A13%3A27Z&sks=b&skv=2025-07-05&sig=W3M/NVqz3rySDXNmsDbef7pJSE8PqSrhGoo0bDHEM5c%3D\n", - "[2025-10-23 22:29:24] INFO [MainThread][geospatial_tools.utils] Downloaded /home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_B08.tif successfully.\n", - "[2025-10-23 22:29:24] INFO [MainThread][geospatial_tools.planetary_computer.sentinel_2] []\n", - "[2025-10-23 22:29:24] INFO [MainThread][geospatial_tools.stac] Creating merged asset metadata\n", - "[2025-10-23 22:29:24] INFO [MainThread][geospatial_tools.raster] Creating merged asset metadata\n", - "[2025-10-23 22:29:24] INFO [MainThread][geospatial_tools.raster] Calculated a total of [2] bands\n", - "[2025-10-23 22:29:24] INFO [MainThread][geospatial_tools.raster] Merging asset [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_merged.tif] ...\n", - "[2025-10-23 22:29:24] INFO [MainThread][geospatial_tools.raster] Writing band image: S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_B04.tif\n", - "[2025-10-23 22:29:24] INFO [MainThread][geospatial_tools.raster] Writing asset sub item band 1 to merged index band 1\n", - "[2025-10-23 22:29:27] INFO [MainThread][geospatial_tools.raster] Writing band image: S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_B08.tif\n", - "[2025-10-23 22:29:27] INFO [MainThread][geospatial_tools.raster] Writing asset sub item band 1 to merged index band 2\n", - "[2025-10-23 22:29:31] INFO [MainThread][geospatial_tools.stac] Asset [S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412] merged successfully\n", - "[2025-10-23 22:29:31] INFO [MainThread][geospatial_tools.stac] Asset location : [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_merged.tif]\n", - "[2025-10-23 22:29:31] INFO [MainThread][geospatial_tools.stac] Reprojecting asset [S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412] ...\n", - "[2025-10-23 22:29:31] INFO [MainThread][geospatial_tools.stac] Creating EPSG code from following input : [5070]\n", - "[2025-10-23 22:29:47] INFO [MainThread][geospatial_tools.stac] Reprojected file created at /home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_reprojected.tif\n", - "[2025-10-23 22:29:47] INFO [MainThread][geospatial_tools.stac] Asset location : [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_reprojected.tif]\n" + "[2026-04-20 13:07:21] INFO [MainThread][geospatial_tools.stac.core] Initiating STAC API search\n", + "[2026-04-20 13:07:21] INFO [MainThread][geospatial_tools.stac.planetary_computer.sentinel_2] []\n", + "[2026-04-20 13:07:21] INFO [MainThread][geospatial_tools.stac.core] Downloading [S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346] ...\n", + "[2026-04-20 13:07:21] INFO [MainThread][geospatial_tools.stac.core] Downloading B04 from https://sentinel2l2a01.blob.core.windows.net/sentinel2-l2/10/S/DJ/2024/07/05/S2A_MSIL2A_20240705T185921_N0510_R013_T10SDJ_20240706T050346.SAFE/GRANULE/L2A_T10SDJ_A047200_20240705T190418/IMG_DATA/R10m/T10SDJ_20240705T185921_B04_10m.tif?st=2026-04-19T17%3A07%3A19Z&se=2026-04-20T17%3A52%3A19Z&sp=rl&sv=2025-07-05&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2026-04-20T13%3A24%3A47Z&ske=2026-04-27T13%3A24%3A47Z&sks=b&skv=2025-07-05&sig=5dxHNeu4D/jhvGnnlHZi5qrP2OABmlIAjbQxD7FHius%3D using method [http]\n", + "[2026-04-20 13:07:37] INFO [MainThread][geospatial_tools.stac.core] Downloaded /home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_B04.tif successfully.\n", + "[2026-04-20 13:07:37] INFO [MainThread][geospatial_tools.stac.core] Downloading B08 from https://sentinel2l2a01.blob.core.windows.net/sentinel2-l2/10/S/DJ/2024/07/05/S2A_MSIL2A_20240705T185921_N0510_R013_T10SDJ_20240706T050346.SAFE/GRANULE/L2A_T10SDJ_A047200_20240705T190418/IMG_DATA/R10m/T10SDJ_20240705T185921_B08_10m.tif?st=2026-04-19T17%3A07%3A19Z&se=2026-04-20T17%3A52%3A19Z&sp=rl&sv=2025-07-05&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2026-04-20T13%3A24%3A47Z&ske=2026-04-27T13%3A24%3A47Z&sks=b&skv=2025-07-05&sig=5dxHNeu4D/jhvGnnlHZi5qrP2OABmlIAjbQxD7FHius%3D using method [http]\n", + "[2026-04-20 13:07:54] INFO [MainThread][geospatial_tools.stac.core] Downloaded /home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_B08.tif successfully.\n", + "[2026-04-20 13:07:54] INFO [MainThread][geospatial_tools.stac.planetary_computer.sentinel_2] []\n", + "[2026-04-20 13:07:54] INFO [MainThread][geospatial_tools.stac.core] Creating merged asset metadata\n", + "[2026-04-20 13:07:54] INFO [MainThread][geospatial_tools.raster] Creating merged asset metadata\n", + "[2026-04-20 13:07:54] INFO [MainThread][geospatial_tools.raster] Calculated a total of [2] bands\n", + "[2026-04-20 13:07:54] INFO [MainThread][geospatial_tools.raster] Merging asset [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_merged.tif] ...\n", + "[2026-04-20 13:07:54] INFO [MainThread][geospatial_tools.raster] Writing band image: S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_B04.tif\n", + "[2026-04-20 13:07:54] INFO [MainThread][geospatial_tools.raster] Writing asset sub item band 1 to merged index band 1\n", + "[2026-04-20 13:07:55] INFO [MainThread][geospatial_tools.raster] Writing band image: S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_B08.tif\n", + "[2026-04-20 13:07:55] INFO [MainThread][geospatial_tools.raster] Writing asset sub item band 1 to merged index band 2\n", + "[2026-04-20 13:07:56] INFO [MainThread][geospatial_tools.stac.core] Asset [S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346] merged successfully\n", + "[2026-04-20 13:07:56] INFO [MainThread][geospatial_tools.stac.core] Asset location : [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_merged.tif]\n", + "[2026-04-20 13:07:56] INFO [MainThread][geospatial_tools.stac.core] Reprojecting asset [S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346] ...\n", + "[2026-04-20 13:07:56] INFO [MainThread][geospatial_tools.stac.core] Creating EPSG code from following input : [5070]\n", + "[2026-04-20 13:08:04] INFO [MainThread][geospatial_tools.stac.core] Reprojected file created at /home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_reprojected.tif\n", + "[2026-04-20 13:08:04] INFO [MainThread][geospatial_tools.stac.core] Asset location : [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_reprojected.tif]\n", + "[2026-04-20 13:08:05] INFO [MainThread][geospatial_tools.stac.core] Initiating STAC API search\n", + "[2026-04-20 13:08:05] INFO [MainThread][geospatial_tools.stac.planetary_computer.sentinel_2] []\n", + "[2026-04-20 13:08:05] INFO [MainThread][geospatial_tools.stac.core] Downloading [S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412] ...\n", + "[2026-04-20 13:08:05] INFO [MainThread][geospatial_tools.stac.core] Downloading B04 from https://sentinel2l2a01.blob.core.windows.net/sentinel2-l2/10/T/DK/2024/07/05/S2A_MSIL2A_20240705T185921_N0510_R013_T10TDK_20240706T050412.SAFE/GRANULE/L2A_T10TDK_A047200_20240705T190418/IMG_DATA/R10m/T10TDK_20240705T185921_B04_10m.tif?st=2026-04-19T17%3A07%3A19Z&se=2026-04-20T17%3A52%3A19Z&sp=rl&sv=2025-07-05&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2026-04-20T13%3A24%3A47Z&ske=2026-04-27T13%3A24%3A47Z&sks=b&skv=2025-07-05&sig=5dxHNeu4D/jhvGnnlHZi5qrP2OABmlIAjbQxD7FHius%3D using method [http]\n", + "[2026-04-20 13:08:21] INFO [MainThread][geospatial_tools.stac.core] Downloaded /home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_B04.tif successfully.\n", + "[2026-04-20 13:08:21] INFO [MainThread][geospatial_tools.stac.core] Downloading B08 from https://sentinel2l2a01.blob.core.windows.net/sentinel2-l2/10/T/DK/2024/07/05/S2A_MSIL2A_20240705T185921_N0510_R013_T10TDK_20240706T050412.SAFE/GRANULE/L2A_T10TDK_A047200_20240705T190418/IMG_DATA/R10m/T10TDK_20240705T185921_B08_10m.tif?st=2026-04-19T17%3A07%3A19Z&se=2026-04-20T17%3A52%3A19Z&sp=rl&sv=2025-07-05&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2026-04-20T13%3A24%3A47Z&ske=2026-04-27T13%3A24%3A47Z&sks=b&skv=2025-07-05&sig=5dxHNeu4D/jhvGnnlHZi5qrP2OABmlIAjbQxD7FHius%3D using method [http]\n", + "[2026-04-20 13:08:38] INFO [MainThread][geospatial_tools.stac.core] Downloaded /home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_B08.tif successfully.\n", + "[2026-04-20 13:08:38] INFO [MainThread][geospatial_tools.stac.planetary_computer.sentinel_2] []\n", + "[2026-04-20 13:08:38] INFO [MainThread][geospatial_tools.stac.core] Creating merged asset metadata\n", + "[2026-04-20 13:08:38] INFO [MainThread][geospatial_tools.raster] Creating merged asset metadata\n", + "[2026-04-20 13:08:38] INFO [MainThread][geospatial_tools.raster] Calculated a total of [2] bands\n", + "[2026-04-20 13:08:38] INFO [MainThread][geospatial_tools.raster] Merging asset [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_merged.tif] ...\n", + "[2026-04-20 13:08:38] INFO [MainThread][geospatial_tools.raster] Writing band image: S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_B04.tif\n", + "[2026-04-20 13:08:38] INFO [MainThread][geospatial_tools.raster] Writing asset sub item band 1 to merged index band 1\n", + "[2026-04-20 13:08:39] INFO [MainThread][geospatial_tools.raster] Writing band image: S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_B08.tif\n", + "[2026-04-20 13:08:39] INFO [MainThread][geospatial_tools.raster] Writing asset sub item band 1 to merged index band 2\n", + "[2026-04-20 13:08:40] INFO [MainThread][geospatial_tools.stac.core] Asset [S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412] merged successfully\n", + "[2026-04-20 13:08:40] INFO [MainThread][geospatial_tools.stac.core] Asset location : [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_merged.tif]\n", + "[2026-04-20 13:08:40] INFO [MainThread][geospatial_tools.stac.core] Reprojecting asset [S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412] ...\n", + "[2026-04-20 13:08:40] INFO [MainThread][geospatial_tools.stac.core] Creating EPSG code from following input : [5070]\n", + "[2026-04-20 13:08:47] INFO [MainThread][geospatial_tools.stac.core] Reprojected file created at /home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_reprojected.tif\n", + "[2026-04-20 13:08:47] INFO [MainThread][geospatial_tools.stac.core] Asset location : [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/S2A_MSIL2A_20240705T185921_R013_T10TDK_20240706T050412_reprojected.tif]\n" ] } ], @@ -2216,8 +2215,8 @@ "id": "99d6fe45792cd970", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:29:47.599298Z", - "start_time": "2025-10-24T02:29:47.593771Z" + "end_time": "2026-04-20T17:08:47.343341628Z", + "start_time": "2026-04-20T17:08:47.292531885Z" } }, "source": [ @@ -2248,8 +2247,8 @@ "id": "715945b328c8ef71", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:29:47.662843Z", - "start_time": "2025-10-24T02:29:47.657590Z" + "end_time": "2026-04-20T17:08:47.391020075Z", + "start_time": "2026-04-20T17:08:47.344279774Z" } }, "source": [ @@ -2276,8 +2275,8 @@ "id": "77a04eaa79969a9c", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:29:47.751266Z", - "start_time": "2025-10-24T02:29:47.715230Z" + "end_time": "2026-04-20T17:08:47.445581871Z", + "start_time": "2026-04-20T17:08:47.394007139Z" } }, "source": [ @@ -2295,8 +2294,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "[2025-10-23 22:29:47] INFO [MainThread][geospatial_tools.vector] Starting writing process\n", - "[2025-10-23 22:29:47] INFO [MainThread][geospatial_tools.vector] File [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/vector_features.gpkg] took 0.025661706924438477 seconds to write.\n" + "[2026-04-20 13:08:47] INFO [MainThread][geospatial_tools.vector] Starting writing process\n", + "[2026-04-20 13:08:47] INFO [MainThread][geospatial_tools.vector] File [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/vector_features.gpkg] took 0.00923013687133789 seconds to write.\n" ] }, { @@ -2325,8 +2324,8 @@ "id": "398c4fe713929a94", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:29:50.482771Z", - "start_time": "2025-10-24T02:29:47.797285Z" + "end_time": "2026-04-20T17:08:49.631072282Z", + "start_time": "2026-04-20T17:08:47.446864095Z" } }, "source": [ @@ -2343,10 +2342,10 @@ "name": "stdout", "output_type": "stream", "text": [ - "[2025-10-23 22:29:47] INFO [MainThread][geospatial_tools.raster] Number of workers used: 4\n", - "[2025-10-23 22:29:47] INFO [MainThread][geospatial_tools.raster] Output path : [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/test_sentinel2_clip]\n", - "[2025-10-23 22:29:47] INFO [MainThread][geospatial_tools.raster] Clipping raster image with 73 polygons\n", - "[2025-10-23 22:29:50] INFO [MainThread][geospatial_tools.raster] Clipping process finished\n" + "[2026-04-20 13:08:47] INFO [MainThread][geospatial_tools.raster] Number of workers used: 4\n", + "[2026-04-20 13:08:47] INFO [MainThread][geospatial_tools.raster] Output path : [/home/francispelletier/projects/geospatial_tools/tests/test_notebooks/tmp_sentinel2/example_s2_download_and_processing/test_sentinel2_clip]\n", + "[2026-04-20 13:08:47] INFO [MainThread][geospatial_tools.raster] Clipping raster image with 73 polygons\n", + "[2026-04-20 13:08:49] INFO [MainThread][geospatial_tools.raster] Clipping process finished\n" ] } ], @@ -2357,8 +2356,8 @@ "id": "2d24fa3dad57032c", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:29:50.620769Z", - "start_time": "2025-10-24T02:29:50.613361Z" + "end_time": "2026-04-20T17:08:49.747285871Z", + "start_time": "2026-04-20T17:08:49.695519678Z" } }, "source": [ @@ -2455,8 +2454,8 @@ "id": "43a5f61e33592e0b", "metadata": { "ExecuteTime": { - "end_time": "2025-10-24T02:29:52.522678Z", - "start_time": "2025-10-24T02:29:50.716166Z" + "end_time": "2026-04-20T17:08:50.486114262Z", + "start_time": "2026-04-20T17:08:49.748187789Z" } }, "source": [ diff --git a/tests/test_notebooks/test_stac_api_tools.ipynb b/tests/test_notebooks/test_stac_api_tools.ipynb index f46b0d7..5885789 100644 --- a/tests/test_notebooks/test_stac_api_tools.ipynb +++ b/tests/test_notebooks/test_stac_api_tools.ipynb @@ -10,15 +10,13 @@ }, { "cell_type": "code", - "execution_count": 1, "id": "d9905141ab1e36a5", "metadata": { "ExecuteTime": { - "end_time": "2026-04-13T18:15:34.423123454Z", - "start_time": "2026-04-13T18:15:33.856337383Z" + "end_time": "2026-04-20T17:10:31.125046012Z", + "start_time": "2026-04-20T17:10:29.316021918Z" } }, - "outputs": [], "source": [ "import shutil\n", "from pathlib import Path\n", @@ -26,41 +24,43 @@ "import geopandas as gpd\n", "\n", "from geospatial_tools import DATA_DIR, TESTS_DIR\n", - "from geospatial_tools.stac import PLANETARY_COMPUTER, StacSearch\n", - "from geospatial_tools.utils import create_date_range_for_specific_period" - ] + "from geospatial_tools.stac.core import PLANETARY_COMPUTER, StacSearch\n", + "from geospatial_tools.stac.utils import create_date_range_for_specific_period" + ], + "outputs": [], + "execution_count": 1 }, { "cell_type": "code", - "execution_count": 2, "id": "bc3faf4a613adec0", "metadata": { "ExecuteTime": { - "end_time": "2026-04-13T18:15:34.441696996Z", - "start_time": "2026-04-13T18:15:34.424762062Z" + "end_time": "2026-04-20T17:10:31.183463868Z", + "start_time": "2026-04-20T17:10:31.127598477Z" } }, - "outputs": [], "source": [ "TEST_TMP_DIR = TESTS_DIR / \"tmp_stac_api_tools\"\n", "TEST_TMP_DIR.mkdir(exist_ok=True)" - ] + ], + "outputs": [], + "execution_count": 2 }, { "cell_type": "code", - "execution_count": 3, "id": "e93f22661d7785fa", "metadata": { "ExecuteTime": { - "end_time": "2026-04-13T18:15:34.500124556Z", - "start_time": "2026-04-13T18:15:34.443548727Z" + "end_time": "2026-04-20T17:10:31.269378328Z", + "start_time": "2026-04-20T17:10:31.193452763Z" } }, - "outputs": [], "source": [ "S2_USA_GRID_FILE = DATA_DIR / \"s2_grid_usa_polygon_5070.gpkg\"\n", "s2_grid = gpd.read_file(S2_USA_GRID_FILE)" - ] + ], + "outputs": [], + "execution_count": 3 }, { "cell_type": "markdown", @@ -82,25 +82,13 @@ }, { "cell_type": "code", - "execution_count": 4, "id": "ee10a895c05db253", "metadata": { "ExecuteTime": { - "end_time": "2026-04-13T18:15:36.100091976Z", - "start_time": "2026-04-13T18:15:34.512945514Z" + "end_time": "2026-04-20T17:10:32.751467975Z", + "start_time": "2026-04-20T17:10:31.281479209Z" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[2026-04-13 14:15:35] INFO [MainThread][geospatial_tools.stac] Running STAC API search for the following parameters: \n", - "\tDate ranges : ['2024-06-01T00:00:00Z/2024-07-31T23:59:59Z'] \n", - "\tQuery : {'eo:cloud_cover': {'lt': 1}, 's2:mgrs_tile': {'in': ['10SDJ']}}\n" - ] - } - ], "source": [ "# Date ranges\n", "start_year = 2024\n", @@ -131,32 +119,29 @@ "\n", "filtered_items = search_client.filtered_results\n", "optimal_result = filtered_items[0]" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "a847c23f04916c18", - "metadata": { - "ExecuteTime": { - "end_time": "2026-04-13T18:15:36.143598199Z", - "start_time": "2026-04-13T18:15:36.120262810Z" - } - }, + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n", - "Sorted results\n", - "Item: S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346, 2024-07-05 18:59:21.024000+00:00, Cloud cover: 0.006778, Nodata: 1.7e-05\n", - "Item: S2A_MSIL2A_20240725T185921_R013_T10SDJ_20240726T025650, 2024-07-25 18:59:21.024000+00:00, Cloud cover: 0.0543, Nodata: 0.0\n", - "\n", - "Optimal result: S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346, 2024-07-05 18:59:21.024000+00:00, Cloud cover: 0.006778, Nodata: 1.7e-05\n" + "[2026-04-20 13:10:31] INFO [MainThread][geospatial_tools.stac.core] Running STAC API search for the following parameters: \n", + "\tDate ranges : ['2024-06-01T00:00:00Z/2024-07-31T23:59:59Z'] \n", + "\tQuery : {'eo:cloud_cover': {'lt': 1}, 's2:mgrs_tile': {'in': ['10SDJ']}}\n" ] } ], + "execution_count": 4 + }, + { + "cell_type": "code", + "id": "a847c23f04916c18", + "metadata": { + "ExecuteTime": { + "end_time": "2026-04-20T17:10:32.865342252Z", + "start_time": "2026-04-20T17:10:32.802180024Z" + } + }, "source": [ "print(\"\\nSorted results\")\n", "for item in filtered_items:\n", @@ -171,46 +156,63 @@ " f\"Cloud cover: {optimal_result.properties['eo:cloud_cover']}, \"\n", " f\"Nodata: {optimal_result.properties['s2:nodata_pixel_percentage']}\"\n", ")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Sorted results\n", + "Item: S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346, 2024-07-05 18:59:21.024000+00:00, Cloud cover: 0.006778, Nodata: 1.7e-05\n", + "Item: S2A_MSIL2A_20240725T185921_R013_T10SDJ_20240726T025650, 2024-07-25 18:59:21.024000+00:00, Cloud cover: 0.0543, Nodata: 0.0\n", + "\n", + "Optimal result: S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346, 2024-07-05 18:59:21.024000+00:00, Cloud cover: 0.006778, Nodata: 1.7e-05\n" + ] + } + ], + "execution_count": 5 }, { "cell_type": "code", - "execution_count": 6, "id": "f4ec68848b408098", "metadata": { "ExecuteTime": { - "end_time": "2026-04-13T18:16:03.023481905Z", - "start_time": "2026-04-13T18:15:36.153302712Z" + "end_time": "2026-04-20T17:10:58.142056224Z", + "start_time": "2026-04-20T17:10:32.870793334Z" } }, + "source": [ + "# NBVAL_IGNORE_OUTPUT\n", + "bands = [\"visual\"]\n", + "file_base_path = Path(f\"{TEST_TMP_DIR}/sentinel-2/\")\n", + "best_result = search_client.download_best_cloud_cover_result(bands=bands, base_directory=file_base_path)" + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[2026-04-13 14:15:36] INFO [MainThread][geospatial_tools.stac] Downloading [S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346] ...\n", - "[2026-04-13 14:15:36] INFO [MainThread][geospatial_tools.stac] Downloading visual from https://sentinel2l2a01.blob.core.windows.net/sentinel2-l2/10/S/DJ/2024/07/05/S2A_MSIL2A_20240705T185921_N0510_R013_T10SDJ_20240706T050346.SAFE/GRANULE/L2A_T10SDJ_A047200_20240705T190418/IMG_DATA/R10m/T10SDJ_20240705T185921_TCI_10m.tif?st=2026-04-12T18%3A15%3A36Z&se=2026-04-13T19%3A00%3A36Z&sp=rl&sv=2025-07-05&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2026-04-12T22%3A47%3A26Z&ske=2026-04-19T22%3A47%3A26Z&sks=b&skv=2025-07-05&sig=4nxibpuvVXyaejybLCOcHevJ6vfuheW4hSI1U/Gpols%3D using method [http]\n", - "[2026-04-13 14:16:02] INFO [MainThread][geospatial_tools.stac] Downloaded /home/francispelletier/projects/geospatial_tools/tests/tmp_stac_api_tools/sentinel-2/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_visual.tif successfully.\n" + "[2026-04-20 13:10:32] INFO [MainThread][geospatial_tools.stac.core] Downloading [S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346] ...\n", + "[2026-04-20 13:10:32] INFO [MainThread][geospatial_tools.stac.core] Downloading visual from https://sentinel2l2a01.blob.core.windows.net/sentinel2-l2/10/S/DJ/2024/07/05/S2A_MSIL2A_20240705T185921_N0510_R013_T10SDJ_20240706T050346.SAFE/GRANULE/L2A_T10SDJ_A047200_20240705T190418/IMG_DATA/R10m/T10SDJ_20240705T185921_TCI_10m.tif?st=2026-04-19T17%3A10%3A32Z&se=2026-04-20T17%3A55%3A32Z&sp=rl&sv=2025-07-05&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2026-04-20T13%3A08%3A34Z&ske=2026-04-27T13%3A08%3A34Z&sks=b&skv=2025-07-05&sig=O25V2GG/z0jNQVW6tTfsRyhIRo%2BgNg8IMf4wGYq3R5U%3D using method [http]\n", + "[2026-04-20 13:10:58] INFO [MainThread][geospatial_tools.stac.core] Downloaded /home/francispelletier/projects/geospatial_tools/tests/tmp_stac_api_tools/sentinel-2/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_visual.tif successfully.\n" ] } ], - "source": [ - "# NBVAL_IGNORE_OUTPUT\n", - "bands = [\"visual\"]\n", - "file_base_path = Path(f\"{TEST_TMP_DIR}/sentinel-2/\")\n", - "best_result = search_client.download_best_cloud_cover_result(bands=bands, base_directory=file_base_path)" - ] + "execution_count": 6 }, { "cell_type": "code", - "execution_count": 7, "id": "d39afa9f75ed355f", "metadata": { "ExecuteTime": { - "end_time": "2026-04-13T18:16:03.123159186Z", - "start_time": "2026-04-13T18:16:03.047230193Z" + "end_time": "2026-04-20T17:10:58.249788839Z", + "start_time": "2026-04-20T17:10:58.194114197Z" } }, + "source": [ + "best_result.asset_id" + ], "outputs": [ { "data": { @@ -223,66 +225,64 @@ "output_type": "execute_result" } ], - "source": [ - "best_result.asset_id" - ] + "execution_count": 7 }, { "cell_type": "code", - "execution_count": 8, "id": "553190ac13f3f758", "metadata": { "ExecuteTime": { - "end_time": "2026-04-13T18:16:11.582822042Z", - "start_time": "2026-04-13T18:16:03.136197264Z" + "end_time": "2026-04-20T17:11:08.919131644Z", + "start_time": "2026-04-20T17:10:58.250624713Z" } }, + "source": [ + "merged = best_result.merge_asset(base_directory=file_base_path, delete_sub_items=True)\n", + "reprojected = best_result.reproject_merged_asset(\n", + " target_projection=5070, base_directory=file_base_path, delete_merged_asset=True\n", + ")" + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[2026-04-13 14:16:03] INFO [MainThread][geospatial_tools.stac] Creating merged asset metadata\n", - "[2026-04-13 14:16:03] INFO [MainThread][geospatial_tools.raster] Creating merged asset metadata\n", - "[2026-04-13 14:16:03] INFO [MainThread][geospatial_tools.raster] Calculated a total of [3] bands\n", - "[2026-04-13 14:16:03] INFO [MainThread][geospatial_tools.raster] Merging asset [/home/francispelletier/projects/geospatial_tools/tests/tmp_stac_api_tools/sentinel-2/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_merged.tif] ...\n", - "[2026-04-13 14:16:03] INFO [MainThread][geospatial_tools.raster] Writing band image: S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_visual.tif\n", - "[2026-04-13 14:16:03] INFO [MainThread][geospatial_tools.raster] Writing asset sub item band 1 to merged index band 1\n", - "[2026-04-13 14:16:04] INFO [MainThread][geospatial_tools.raster] Writing asset sub item band 2 to merged index band 2\n", - "[2026-04-13 14:16:04] INFO [MainThread][geospatial_tools.raster] Writing asset sub item band 3 to merged index band 3\n", - "[2026-04-13 14:16:05] INFO [MainThread][geospatial_tools.stac] Asset [S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346] merged successfully\n", - "[2026-04-13 14:16:05] INFO [MainThread][geospatial_tools.stac] Asset location : [/home/francispelletier/projects/geospatial_tools/tests/tmp_stac_api_tools/sentinel-2/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_merged.tif]\n", - "[2026-04-13 14:16:05] INFO [MainThread][geospatial_tools.stac] Deleting asset sub items from asset [S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346]\n", - "[2026-04-13 14:16:05] INFO [MainThread][geospatial_tools.stac] Deleting [/home/francispelletier/projects/geospatial_tools/tests/tmp_stac_api_tools/sentinel-2/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_visual.tif] ...\n", - "[2026-04-13 14:16:05] INFO [MainThread][geospatial_tools.stac] Reprojecting asset [S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346] ...\n", - "[2026-04-13 14:16:05] INFO [MainThread][geospatial_tools.stac] Creating EPSG code from following input : [5070]\n", - "[2026-04-13 14:16:11] INFO [MainThread][geospatial_tools.stac] Reprojected file created at /home/francispelletier/projects/geospatial_tools/tests/tmp_stac_api_tools/sentinel-2/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_reprojected.tif\n", - "[2026-04-13 14:16:11] INFO [MainThread][geospatial_tools.stac] Asset location : [/home/francispelletier/projects/geospatial_tools/tests/tmp_stac_api_tools/sentinel-2/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_reprojected.tif]\n", - "[2026-04-13 14:16:11] INFO [MainThread][geospatial_tools.stac] Deleting merged asset file for [/home/francispelletier/projects/geospatial_tools/tests/tmp_stac_api_tools/sentinel-2/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_merged.tif]\n" + "[2026-04-20 13:10:58] INFO [MainThread][geospatial_tools.stac.core] Creating merged asset metadata\n", + "[2026-04-20 13:10:58] INFO [MainThread][geospatial_tools.raster] Creating merged asset metadata\n", + "[2026-04-20 13:10:58] INFO [MainThread][geospatial_tools.raster] Calculated a total of [3] bands\n", + "[2026-04-20 13:10:58] INFO [MainThread][geospatial_tools.raster] Merging asset [/home/francispelletier/projects/geospatial_tools/tests/tmp_stac_api_tools/sentinel-2/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_merged.tif] ...\n", + "[2026-04-20 13:10:58] INFO [MainThread][geospatial_tools.raster] Writing band image: S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_visual.tif\n", + "[2026-04-20 13:10:58] INFO [MainThread][geospatial_tools.raster] Writing asset sub item band 1 to merged index band 1\n", + "[2026-04-20 13:10:59] INFO [MainThread][geospatial_tools.raster] Writing asset sub item band 2 to merged index band 2\n", + "[2026-04-20 13:10:59] INFO [MainThread][geospatial_tools.raster] Writing asset sub item band 3 to merged index band 3\n", + "[2026-04-20 13:11:00] INFO [MainThread][geospatial_tools.stac.core] Asset [S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346] merged successfully\n", + "[2026-04-20 13:11:00] INFO [MainThread][geospatial_tools.stac.core] Asset location : [/home/francispelletier/projects/geospatial_tools/tests/tmp_stac_api_tools/sentinel-2/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_merged.tif]\n", + "[2026-04-20 13:11:00] INFO [MainThread][geospatial_tools.stac.core] Deleting asset sub items from asset [S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346]\n", + "[2026-04-20 13:11:00] INFO [MainThread][geospatial_tools.stac.core] Deleting [/home/francispelletier/projects/geospatial_tools/tests/tmp_stac_api_tools/sentinel-2/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_visual.tif] ...\n", + "[2026-04-20 13:11:00] INFO [MainThread][geospatial_tools.stac.core] Reprojecting asset [S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346] ...\n", + "[2026-04-20 13:11:00] INFO [MainThread][geospatial_tools.stac.core] Creating EPSG code from following input : [5070]\n", + "[2026-04-20 13:11:08] INFO [MainThread][geospatial_tools.stac.core] Reprojected file created at /home/francispelletier/projects/geospatial_tools/tests/tmp_stac_api_tools/sentinel-2/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_reprojected.tif\n", + "[2026-04-20 13:11:08] INFO [MainThread][geospatial_tools.stac.core] Asset location : [/home/francispelletier/projects/geospatial_tools/tests/tmp_stac_api_tools/sentinel-2/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_reprojected.tif]\n", + "[2026-04-20 13:11:08] INFO [MainThread][geospatial_tools.stac.core] Deleting merged asset file for [/home/francispelletier/projects/geospatial_tools/tests/tmp_stac_api_tools/sentinel-2/S2A_MSIL2A_20240705T185921_R013_T10SDJ_20240706T050346_merged.tif]\n" ] } ], - "source": [ - "merged = best_result.merge_asset(base_directory=file_base_path, delete_sub_items=True)\n", - "reprojected = best_result.reproject_merged_asset(\n", - " target_projection=5070, base_directory=file_base_path, delete_merged_asset=True\n", - ")" - ] + "execution_count": 8 }, { "cell_type": "code", - "execution_count": 9, "id": "5be37e4e719010a5", "metadata": { "ExecuteTime": { - "end_time": "2026-04-13T18:16:11.780177397Z", - "start_time": "2026-04-13T18:16:11.622196407Z" + "end_time": "2026-04-20T17:11:09.117832284Z", + "start_time": "2026-04-20T17:11:08.980018228Z" } }, - "outputs": [], "source": [ "shutil.rmtree(TEST_TMP_DIR)" - ] + ], + "outputs": [], + "execution_count": 9 } ], "metadata": { diff --git a/tests/test_planetary_computer_constants.py b/tests/test_planetary_computer_constants.py new file mode 100644 index 0000000..56a0f7b --- /dev/null +++ b/tests/test_planetary_computer_constants.py @@ -0,0 +1,176 @@ +"""Unit tests for Planetary Computer Sentinel-2 constants.""" + +import pytest + +from geospatial_tools.stac.planetary_computer import ( + PlanetaryComputerS1Band, + PlanetaryComputerS1Collection, + PlanetaryComputerS1InstrumentMode, + PlanetaryComputerS1OrbitState, + PlanetaryComputerS1Polarization, + PlanetaryComputerS1Property, + PlanetaryComputerS2Band, + PlanetaryComputerS2Collection, + PlanetaryComputerS2Property, + PlanetaryComputerS3Band, + PlanetaryComputerS3Collection, + PlanetaryComputerS3Property, +) + + +class TestPlanetaryComputerS2Collection: + def test_l2a_value(self) -> None: + assert PlanetaryComputerS2Collection.L2A == "sentinel-2-l2a" + + def test_is_str(self) -> None: + assert isinstance(PlanetaryComputerS2Collection.L2A, str) + + def test_str_representation(self) -> None: + assert str(PlanetaryComputerS2Collection.L2A) == "sentinel-2-l2a" + + +class TestPlanetaryComputerS2Property: + def test_cloud_cover_value(self) -> None: + assert PlanetaryComputerS2Property.CLOUD_COVER == "eo:cloud_cover" + + def test_mgrs_tile_value(self) -> None: + assert PlanetaryComputerS2Property.MGRS_TILE == "s2:mgrs_tile" + + def test_nodata_pixel_percentage_value(self) -> None: + assert PlanetaryComputerS2Property.NODATA_PIXEL_PERCENTAGE == "s2:nodata_pixel_percentage" + + def test_is_str(self) -> None: + assert isinstance(PlanetaryComputerS2Property.CLOUD_COVER, str) + + def test_sortby_field_cloud_cover(self) -> None: + assert PlanetaryComputerS2Property.CLOUD_COVER.sortby_field == "properties.eo:cloud_cover" + + def test_sortby_field_mgrs_tile(self) -> None: + assert PlanetaryComputerS2Property.MGRS_TILE.sortby_field == "properties.s2:mgrs_tile" + + def test_sortby_field_nodata(self) -> None: + assert ( + PlanetaryComputerS2Property.NODATA_PIXEL_PERCENTAGE.sortby_field == "properties.s2:nodata_pixel_percentage" + ) + + +class TestPlanetaryComputerS2Band: + @pytest.mark.parametrize( + "member, expected", + [ + (PlanetaryComputerS2Band.B01, "B01"), + (PlanetaryComputerS2Band.B02, "B02"), + (PlanetaryComputerS2Band.B03, "B03"), + (PlanetaryComputerS2Band.B04, "B04"), + (PlanetaryComputerS2Band.B05, "B05"), + (PlanetaryComputerS2Band.B06, "B06"), + (PlanetaryComputerS2Band.B07, "B07"), + (PlanetaryComputerS2Band.B08, "B08"), + (PlanetaryComputerS2Band.B8A, "B8A"), + (PlanetaryComputerS2Band.B09, "B09"), + (PlanetaryComputerS2Band.B11, "B11"), + (PlanetaryComputerS2Band.B12, "B12"), + (PlanetaryComputerS2Band.SCL, "SCL"), + (PlanetaryComputerS2Band.TCI, "TCI"), + (PlanetaryComputerS2Band.AOT, "AOT"), + (PlanetaryComputerS2Band.WVP, "WVP"), + ], + ) + def test_standard_band_values(self, member: PlanetaryComputerS2Band, expected: str) -> None: + assert member == expected + + @pytest.mark.parametrize( + "alias, expected_value", + [ + (PlanetaryComputerS2Band.COASTAL, "B01"), + (PlanetaryComputerS2Band.BLUE, "B02"), + (PlanetaryComputerS2Band.GREEN, "B03"), + (PlanetaryComputerS2Band.RED, "B04"), + (PlanetaryComputerS2Band.RED_EDGE_1, "B05"), + (PlanetaryComputerS2Band.RED_EDGE_2, "B06"), + (PlanetaryComputerS2Band.RED_EDGE_3, "B07"), + (PlanetaryComputerS2Band.NIR, "B08"), + (PlanetaryComputerS2Band.NIR_NARROW, "B8A"), + (PlanetaryComputerS2Band.SWIR_1, "B11"), + (PlanetaryComputerS2Band.SWIR_2, "B12"), + ], + ) + def test_common_name_aliases(self, alias: PlanetaryComputerS2Band, expected_value: str) -> None: + assert alias == expected_value + + def test_blue_alias_is_b02(self) -> None: + assert PlanetaryComputerS2Band.BLUE == "B02" + + def test_is_str(self) -> None: + assert isinstance(PlanetaryComputerS2Band.B02, str) + + +class TestPlanetaryComputerS1Collection: + def test_grd_value(self) -> None: + assert PlanetaryComputerS1Collection.GRD == "sentinel-1-grd" + + +class TestPlanetaryComputerS1Property: + def test_property_values(self) -> None: + assert PlanetaryComputerS1Property.INSTRUMENT_MODE == "sar:instrument_mode" + assert PlanetaryComputerS1Property.POLARIZATIONS == "sar:polarizations" + assert PlanetaryComputerS1Property.ORBIT_STATE == "sat:orbit_state" + + +class TestPlanetaryComputerS1Band: + def test_band_values(self) -> None: + assert PlanetaryComputerS1Band.VV == "vv" + assert PlanetaryComputerS1Band.VH == "vh" + + +class TestPlanetaryComputerS1InstrumentMode: + def test_instrument_mode_values(self) -> None: + assert PlanetaryComputerS1InstrumentMode.IW == "IW" + assert PlanetaryComputerS1InstrumentMode.EW == "EW" + assert PlanetaryComputerS1InstrumentMode.SM == "SM" + assert PlanetaryComputerS1InstrumentMode.WV == "WV" + + +class TestPlanetaryComputerS1Polarization: + def test_polarization_values(self) -> None: + assert PlanetaryComputerS1Polarization.VV == "VV" + assert PlanetaryComputerS1Polarization.VH == "VH" + assert PlanetaryComputerS1Polarization.HH == "HH" + assert PlanetaryComputerS1Polarization.HV == "HV" + + def test_invariant_uppercase_property_vs_lowercase_asset(self) -> None: + assert PlanetaryComputerS1Polarization.VV != PlanetaryComputerS1Band.VV + assert PlanetaryComputerS1Polarization.VV == "VV" + assert PlanetaryComputerS1Band.VV == "vv" + + +class TestPlanetaryComputerS1OrbitState: + def test_orbit_state_values(self) -> None: + assert PlanetaryComputerS1OrbitState.ASCENDING == "ascending" + assert PlanetaryComputerS1OrbitState.DESCENDING == "descending" + + +class TestPlanetaryComputerS3Collection: + def test_collection_values(self) -> None: + assert PlanetaryComputerS3Collection.OLCI_L1B == "sentinel-3-olci-l1b-efr" + assert PlanetaryComputerS3Collection.OLCI_WFR == "sentinel-3-olci-wfr-l2-netcdf" + + +class TestPlanetaryComputerS3Property: + def test_property_values(self) -> None: + assert PlanetaryComputerS3Property.ORBIT_STATE == "sat:orbit_state" + + +class TestPlanetaryComputerS3Band: + def test_band_values(self) -> None: + assert PlanetaryComputerS3Band.OA16 == "oa16-radiance" + assert PlanetaryComputerS3Band.OA17 == "oa17-radiance" + assert PlanetaryComputerS3Band.OA18 == "oa18-radiance" + assert PlanetaryComputerS3Band.OA19 == "oa19-radiance" + assert PlanetaryComputerS3Band.OA20 == "oa20-radiance" + assert PlanetaryComputerS3Band.OA21 == "oa21-radiance" + + def test_band_aliases(self) -> None: + assert PlanetaryComputerS3Band.NIR_865 == PlanetaryComputerS3Band.OA17 + assert PlanetaryComputerS3Band.WATER_VAPOUR == PlanetaryComputerS3Band.OA19 + assert PlanetaryComputerS3Band.NIR_865 == "oa17-radiance" diff --git a/tests/test_planetary_computer_sentinel1.py b/tests/test_planetary_computer_sentinel1.py new file mode 100644 index 0000000..3f20d3f --- /dev/null +++ b/tests/test_planetary_computer_sentinel1.py @@ -0,0 +1,167 @@ +from pathlib import Path +from unittest.mock import patch + +import pytest +from pystac import Item + +from geospatial_tools.stac.core import AbstractStacWrapper, Asset +from geospatial_tools.stac.planetary_computer.constants import ( + PlanetaryComputerS1Band, + PlanetaryComputerS1Collection, + PlanetaryComputerS1InstrumentMode, + PlanetaryComputerS1OrbitState, + PlanetaryComputerS1Polarization, + PlanetaryComputerS1Property, +) +from geospatial_tools.stac.planetary_computer.sentinel_1 import ( + Sentinel1Search, +) + + +class Sentinel1Mock(Sentinel1Search): + def search(self) -> list[Item]: + return [] + + def download(self, bands: list[PlanetaryComputerS1Band | str], base_directory: str | Path) -> list[Asset]: + return [] + + +def test_abstract_class_cannot_be_instantiated(): + with pytest.raises(TypeError): + AbstractStacWrapper() + + +def test_abstract_sentinel1_initialization(): + mock = Sentinel1Mock( + collection=PlanetaryComputerS1Collection.GRD, + date_range="2023-01-01/2023-01-31", + bbox=(-74.0, 45.4, -73.5, 45.7), + ) + assert mock.collection == PlanetaryComputerS1Collection.GRD + assert mock.date_range == "2023-01-01/2023-01-31" + assert mock.bbox == (-74.0, 45.4, -73.5, 45.7) + assert mock.intersects is None + assert mock.search_results is None + assert mock.downloaded_assets is None + assert mock.client is not None + + +def test_filter_by_instrument_mode(): + mock = Sentinel1Mock() + result = mock.filter_by_instrument_mode(PlanetaryComputerS1InstrumentMode.IW) + assert result is mock + assert mock.instrument_modes == [PlanetaryComputerS1InstrumentMode.IW] + + result2 = mock.filter_by_instrument_mode( + [PlanetaryComputerS1InstrumentMode.EW, PlanetaryComputerS1InstrumentMode.SM] + ) + assert result2 is mock + assert mock.instrument_modes == [PlanetaryComputerS1InstrumentMode.EW, PlanetaryComputerS1InstrumentMode.SM] + + +def test_filter_by_polarization(): + mock = Sentinel1Mock() + result = mock.filter_by_polarization(PlanetaryComputerS1Polarization.VV) + assert result is mock + assert mock.polarizations == [PlanetaryComputerS1Polarization.VV] + + result2 = mock.filter_by_polarization([PlanetaryComputerS1Polarization.HH, PlanetaryComputerS1Polarization.HV]) + assert result2 is mock + assert mock.polarizations == [PlanetaryComputerS1Polarization.HH, PlanetaryComputerS1Polarization.HV] + + +def test_filter_by_orbit_state(): + mock = Sentinel1Mock() + result = mock.filter_by_orbit_state(PlanetaryComputerS1OrbitState.ASCENDING) + assert result is mock + assert mock.orbit_states == [PlanetaryComputerS1OrbitState.ASCENDING] + + result2 = mock.filter_by_orbit_state( + [PlanetaryComputerS1OrbitState.DESCENDING, PlanetaryComputerS1OrbitState.ASCENDING] + ) + assert result2 is mock + assert mock.orbit_states == [PlanetaryComputerS1OrbitState.DESCENDING, PlanetaryComputerS1OrbitState.ASCENDING] + + +def test_with_custom_query(): + mock = Sentinel1Mock() + result = mock.with_custom_query({"sar:resolution_range": {"eq": "high"}}) + assert result is mock + assert mock.custom_query_params == {"sar:resolution_range": {"eq": "high"}} + + +@patch("geospatial_tools.stac.core.StacSearch") +def test_search_dynamic_query_building(mock_stac_search_class): + mock_client = mock_stac_search_class.return_value + mock_client.search.return_value = [] + + searcher = Sentinel1Search() + searcher.filter_by_instrument_mode(PlanetaryComputerS1InstrumentMode.IW) + searcher.filter_by_orbit_state([PlanetaryComputerS1OrbitState.ASCENDING, PlanetaryComputerS1OrbitState.DESCENDING]) + searcher.filter_by_polarization([PlanetaryComputerS1Polarization.VV, PlanetaryComputerS1Polarization.VH]) + searcher.with_custom_query({"custom_key": {"eq": "val"}}) + + searcher.search() + + mock_client.search.assert_called_once() + called_kwargs = mock_client.search.call_args.kwargs + assert called_kwargs["query"] == { + PlanetaryComputerS1Property.INSTRUMENT_MODE.value: {"eq": "IW"}, + PlanetaryComputerS1Property.ORBIT_STATE.value: {"in": ["ascending", "descending"]}, + PlanetaryComputerS1Property.POLARIZATIONS.value: {"eq": ["VV", "VH"]}, + "custom_key": {"eq": "val"}, + } + + +@patch("geospatial_tools.stac.core.StacSearch") +def test_download_triggers_search_if_none(mock_stac_search_class): + mock_client = mock_stac_search_class.return_value + mock_client.search_results = None # Ensure it's None to trigger search + mock_client.search.return_value = [] + mock_client.download_search_results.return_value = [] + + searcher = Sentinel1Search() + searcher.download(bands=[PlanetaryComputerS1Band.VV], base_directory="test") + + mock_client.search.assert_called_once() + mock_client.download_search_results.assert_called_once_with(bands=["vv"], base_directory=Path("test")) + + +@patch("geospatial_tools.stac.core.StacSearch") +def test_download_skips_search_if_already_populated(mock_stac_search_class): + mock_client = mock_stac_search_class.return_value + mock_client.search_results = [] # Already populated + mock_client.download_search_results.return_value = [] + + searcher = Sentinel1Search() + searcher.download(bands=[PlanetaryComputerS1Band.VH], base_directory="test") + + mock_client.search.assert_not_called() + mock_client.download_search_results.assert_called_once() + + +@patch("geospatial_tools.stac.core.StacSearch") +def test_download_converts_bands_to_lowercase(mock_stac_search_class): + mock_client = mock_stac_search_class.return_value + mock_client.search.return_value = [] + + searcher = Sentinel1Search() + searcher.download(bands=["VV", PlanetaryComputerS1Band.VH], base_directory="test") + + called_kwargs = mock_client.download_search_results.call_args.kwargs + assert called_kwargs["bands"] == ["vv", "vh"] + + +@pytest.mark.integration +def test_sentinel1_integration(): + searcher = Sentinel1Search(date_range="2023-01-01/2023-01-31", bbox=(-74.0, 45.4, -73.5, 45.7)) + searcher.filter_by_instrument_mode(PlanetaryComputerS1InstrumentMode.IW) + searcher.filter_by_polarization([PlanetaryComputerS1Polarization.VV, PlanetaryComputerS1Polarization.VH]) + + results = searcher.search() + + assert results is not None + assert len(results) > 0 + for item in results: + assert item.properties["sar:instrument_mode"] == "IW" + assert "VV" in item.properties["sar:polarizations"] diff --git a/tests/test_planetary_computer_sentinel2.py b/tests/test_planetary_computer_sentinel2.py new file mode 100644 index 0000000..7c0a988 --- /dev/null +++ b/tests/test_planetary_computer_sentinel2.py @@ -0,0 +1,32 @@ +import pytest + +from geospatial_tools.stac.planetary_computer.sentinel_2 import Sentinel2Search + + +@pytest.mark.integration +def test_sentinel2_search_integration(): + """Integration test for Sentinel-2 search on Planetary Computer.""" + searcher = Sentinel2Search(date_range="2023-06-01/2023-06-30", bbox=(-74.0, 45.4, -73.5, 45.7)) + searcher.filter_by_cloud_cover(10).filter_by_nodata_pixel_percentage(5) + + results = searcher.search() + + assert results is not None + assert len(results) > 0 + for item in results: + assert item.properties["eo:cloud_cover"] < 10 + assert item.properties["s2:nodata_pixel_percentage"] < 5 + + +@pytest.mark.integration +def test_sentinel2_search_mgrs_integration(): + """Integration test for Sentinel-2 search using MGRS tile.""" + searcher = Sentinel2Search(date_range="2023-06-01/2023-06-07") + searcher.filter_by_mgrs_tile("31UFS") + + results = searcher.search() + + assert results is not None + assert len(results) > 0 + for item in results: + assert item.properties["s2:mgrs_tile"] == "31UFS" diff --git a/tests/test_planetary_computer_sentinel3.py b/tests/test_planetary_computer_sentinel3.py new file mode 100644 index 0000000..870169d --- /dev/null +++ b/tests/test_planetary_computer_sentinel3.py @@ -0,0 +1,102 @@ +"""Unit tests for Planetary Computer Sentinel-3 wrapper.""" + +from unittest.mock import patch + +import pytest + +from geospatial_tools.stac.planetary_computer.constants import ( + PlanetaryComputerS3Band, + PlanetaryComputerS3Collection, + PlanetaryComputerS3OrbitState, + PlanetaryComputerS3Property, +) +from geospatial_tools.stac.planetary_computer.sentinel_3 import Sentinel3Search + + +def test_sentinel3_initialization() -> None: + search = Sentinel3Search() + assert search.collection == PlanetaryComputerS3Collection.OLCI_WFR + assert search.orbit_states is None + assert search.custom_query_params == {} + + +def test_initialization_with_collection() -> None: + search = Sentinel3Search(collection=PlanetaryComputerS3Collection.OLCI_L1B) + assert search.collection == PlanetaryComputerS3Collection.OLCI_L1B + + +def test_filter_by_orbit_state_single() -> None: + search = Sentinel3Search() + search.client.search_results = ["dummy"] # type: ignore + + result = search.filter_by_orbit_state(PlanetaryComputerS3OrbitState.ASCENDING) + + assert result is search + assert search.orbit_states == [PlanetaryComputerS3OrbitState.ASCENDING] + assert search.client.search_results is None # Invalidation test + + +def test_filter_by_orbit_state_multiple() -> None: + search = Sentinel3Search() + search.filter_by_orbit_state([PlanetaryComputerS3OrbitState.ASCENDING, PlanetaryComputerS3OrbitState.DESCENDING]) + assert search.orbit_states == [PlanetaryComputerS3OrbitState.ASCENDING, PlanetaryComputerS3OrbitState.DESCENDING] + + +@patch("geospatial_tools.stac.core.StacSearch") +def test_build_collection_query_dynamic(mock_stac_search_class) -> None: + mock_client = mock_stac_search_class.return_value + mock_client.search.return_value = [] + + searcher = Sentinel3Search() + searcher.filter_by_orbit_state(PlanetaryComputerS3OrbitState.DESCENDING) + searcher.with_custom_query({"custom_key": {"eq": "val"}}) + searcher.search() + + mock_client.search.assert_called_once() + called_kwargs = mock_client.search.call_args.kwargs + assert called_kwargs["query"] == { + PlanetaryComputerS3Property.ORBIT_STATE.value: {"eq": "descending"}, + "custom_key": {"eq": "val"}, + } + + +@patch("geospatial_tools.stac.core.StacSearch") +def test_build_collection_query_multiple_orbits(mock_stac_search_class) -> None: + mock_client = mock_stac_search_class.return_value + mock_client.search.return_value = [] + + searcher = Sentinel3Search() + searcher.filter_by_orbit_state([PlanetaryComputerS3OrbitState.ASCENDING, PlanetaryComputerS3OrbitState.DESCENDING]) + searcher.search() + + mock_client.search.assert_called_once() + called_kwargs = mock_client.search.call_args.kwargs + assert called_kwargs["query"] == { + PlanetaryComputerS3Property.ORBIT_STATE.value: {"in": ["ascending", "descending"]} + } + + +@patch("geospatial_tools.stac.core.StacSearch") +def test_download_lowercases_bands(mock_stac_search_class) -> None: + mock_client = mock_stac_search_class.return_value + mock_client.search.return_value = [] + + searcher = Sentinel3Search() + searcher.download(bands=[PlanetaryComputerS3Band.OA17, "OA18-RADIANCE"], base_directory="test") + + called_kwargs = mock_client.download_search_results.call_args.kwargs + assert called_kwargs["bands"] == ["oa17-radiance", "oa18-radiance"] + + +@pytest.mark.integration +def test_sentinel3_search_integration() -> None: + """Integration test for Sentinel-3 search on Planetary Computer.""" + searcher = Sentinel3Search(date_range="2023-06-01/2023-06-07", bbox=(-74.0, 45.4, -73.5, 45.7)) + searcher.filter_by_orbit_state(PlanetaryComputerS3OrbitState.DESCENDING) + + results = searcher.search() + + assert results is not None + assert len(results) > 0 + for item in results: + assert item.properties["sat:orbit_state"] == "descending" diff --git a/tests/test_s3_utils.py b/tests/test_s3_utils.py index 6de9704..e47d11f 100644 --- a/tests/test_s3_utils.py +++ b/tests/test_s3_utils.py @@ -5,7 +5,7 @@ import pytest -from geospatial_tools.s3_utils import get_s3_client, parse_s3_url +from geospatial_tools.stac.utils import get_s3_client, parse_s3_url def test_parse_s3_url_valid_s3_scheme() -> None: diff --git a/tests/test_stac.py b/tests/test_stac.py index 1cf864c..09c5e08 100644 --- a/tests/test_stac.py +++ b/tests/test_stac.py @@ -5,7 +5,7 @@ import pytest -from geospatial_tools.stac import StacSearch, download_stac_asset +from geospatial_tools.stac.core import StacSearch, download_stac_asset @pytest.fixture @@ -26,7 +26,10 @@ def mock_item(): def test_download_stac_asset_http() -> None: """Test that download_stac_asset calls download_url for http method.""" - with patch("geospatial_tools.stac.download_url") as mock_download_url: + with patch("geospatial_tools.stac.core.download_url") as mock_download_url: + # Important note : Mocking with patch needs to set path where function is used. + # This is why, even though 'download_url' comes from stac.copernicus.auth + # it is still listed here as being from stac.core mock_download_url.return_value = Path("test.tif") result = download_stac_asset("http://example.com/file.tif", Path("test.tif"), method="http") assert result == Path("test.tif") @@ -38,8 +41,8 @@ def test_download_stac_asset_s3(mock_s3_client) -> None: url = "https://eodata.dataspace.copernicus.eu/Sentinel-2/item.tif" dest = Path("test.tif") - # We need to patch s3_utils.parse_s3_url because it's used inside - with patch("geospatial_tools.s3_utils.parse_s3_url") as mock_parse: + # We need to patch utils.parse_s3_url because it's used inside + with patch("geospatial_tools.stac.utils.parse_s3_url") as mock_parse: mock_parse.return_value = ("Sentinel-2", "item.tif") result = download_stac_asset(url, dest, method="s3", s3_client=mock_s3_client) @@ -49,11 +52,14 @@ def test_download_stac_asset_s3(mock_s3_client) -> None: def test_stac_search_dispatch_copernicus(mock_item, mock_s3_client) -> None: """Test that StacSearch uses s3 for Copernicus.""" + # Important note : Mocking with patch needs to set path where function is used. + # This is why, even though 'get_copernicus_token' comes from stac.copernicus.auth + # it is still listed here as being from stac.core with ( - patch("geospatial_tools.stac.catalog_generator"), - patch("geospatial_tools.s3_utils.get_s3_client") as mock_get_s3, - patch("geospatial_tools.stac.get_copernicus_token") as mock_get_token, - patch("geospatial_tools.stac.download_stac_asset") as mock_download, + patch("geospatial_tools.stac.core.catalog_generator"), + patch("geospatial_tools.stac.utils.get_s3_client") as mock_get_s3, + patch("geospatial_tools.stac.core.get_copernicus_token") as mock_get_token, + patch("geospatial_tools.stac.core.download_stac_asset") as mock_download, ): mock_get_s3.return_value = mock_s3_client @@ -78,8 +84,8 @@ def test_stac_search_dispatch_copernicus(mock_item, mock_s3_client) -> None: def test_stac_search_dispatch_other(mock_item) -> None: """Test that StacSearch uses http for other catalogs.""" with ( - patch("geospatial_tools.stac.catalog_generator"), - patch("geospatial_tools.stac.download_stac_asset") as mock_download, + patch("geospatial_tools.stac.core.catalog_generator"), + patch("geospatial_tools.stac.core.download_stac_asset") as mock_download, ): mock_download.return_value = Path("out.tif") diff --git a/tests/test_utils.py b/tests/test_utils.py index 3481d1d..d8ff750 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,6 +1,7 @@ import pytest -from geospatial_tools.utils import create_crs, create_date_range_for_specific_period +from geospatial_tools.stac.utils import create_date_range_for_specific_period +from geospatial_tools.utils import create_crs @pytest.mark.parametrize( diff --git a/uv.lock b/uv.lock index 9f3edef..0fb8c56 100644 --- a/uv.lock +++ b/uv.lock @@ -1,23 +1,11 @@ version = 1 revision = 3 -requires-python = ">=3.11, <3.15" +requires-python = ">=3.12, <3.14" resolution-markers = [ - "python_full_version >= '3.14' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version >= '3.14' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version < '3.12' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version < '3.12' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version < '3.12' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version < '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version >= '3.13' and platform_machine == 'ARM64' and sys_platform == 'win32'", + "python_full_version < '3.13' and platform_machine == 'ARM64' and sys_platform == 'win32'", + "(python_full_version >= '3.13' and platform_machine != 'ARM64') or (python_full_version >= '3.13' and sys_platform != 'win32')", + "(python_full_version < '3.13' and platform_machine != 'ARM64') or (python_full_version < '3.13' and sys_platform != 'win32')", ] [[package]] @@ -122,16 +110,6 @@ dependencies = [ ] 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" }, @@ -249,7 +227,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0f/f0/35240571e1b67ffb19dafb29ab34150b6f59f93f717b041082cdb1bfceb1/backrefs-6.2-py311-none-any.whl", hash = "sha256:08aa7fae530c6b2361d7bdcbda1a7c454e330cc9dbcd03f5c23205e430e5c3be", size = 392874, upload-time = "2026-02-16T19:10:06.314Z" }, { url = "https://files.pythonhosted.org/packages/e3/63/77e8c9745b4d227cce9f5e0a6f68041278c5f9b18588b35905f5f19c1beb/backrefs-6.2-py312-none-any.whl", hash = "sha256:c3f4b9cb2af8cda0d87ab4f57800b57b95428488477be164dd2b47be54db0c90", size = 398787, upload-time = "2026-02-16T19:10:08.274Z" }, { url = "https://files.pythonhosted.org/packages/c5/71/c754b1737ad99102e03fa3235acb6cb6d3ac9d6f596cbc3e5f236705abd8/backrefs-6.2-py313-none-any.whl", hash = "sha256:12df81596ab511f783b7d87c043ce26bc5b0288cf3bb03610fe76b8189282b2b", size = 400747, upload-time = "2026-02-16T19:10:09.791Z" }, - { url = "https://files.pythonhosted.org/packages/af/75/be12ba31a6eb20dccef2320cd8ccb3f7d9013b68ba4c70156259fee9e409/backrefs-6.2-py314-none-any.whl", hash = "sha256:e5f805ae09819caa1aa0623b4a83790e7028604aa2b8c73ba602c4454e665de7", size = 412602, upload-time = "2026-02-16T19:10:12.317Z" }, { url = "https://files.pythonhosted.org/packages/21/f8/d02f650c47d05034dcd6f9c8cf94f39598b7a89c00ecda0ecb2911bc27e9/backrefs-6.2-py39-none-any.whl", hash = "sha256:664e33cd88c6840b7625b826ecf2555f32d491800900f5a541f772c485f7cda7", size = 381077, upload-time = "2026-02-16T19:10:13.74Z" }, ] @@ -280,11 +257,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/e1/c5/61175d618685d42b005847464b8fb4743a67b1b8fdb75e50e5a96c31a27a/black-26.3.1.tar.gz", hash = "sha256:2c50f5063a9641c7eed7795014ba37b0f5fa227f3d408b968936e24bc0566b07", size = 666155, upload-time = "2026-03-12T03:36:03.593Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/17/57/5f11c92861f9c92eb9dddf515530bc2d06db843e44bdcf1c83c1427824bc/black-26.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:28ef38aee69e4b12fda8dba75e21f9b4f979b490c8ac0baa7cb505369ac9e1ff", size = 1851987, upload-time = "2026-03-12T03:40:06.248Z" }, - { url = "https://files.pythonhosted.org/packages/54/aa/340a1463660bf6831f9e39646bf774086dbd8ca7fc3cded9d59bbdf4ad0a/black-26.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf9bf162ed91a26f1adba8efda0b573bc6924ec1408a52cc6f82cb73ec2b142c", size = 1689499, upload-time = "2026-03-12T03:40:07.642Z" }, - { url = "https://files.pythonhosted.org/packages/f3/01/b726c93d717d72733da031d2de10b92c9fa4c8d0c67e8a8a372076579279/black-26.3.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:474c27574d6d7037c1bc875a81d9be0a9a4f9ee95e62800dab3cfaadbf75acd5", size = 1754369, upload-time = "2026-03-12T03:40:09.279Z" }, - { url = "https://files.pythonhosted.org/packages/e3/09/61e91881ca291f150cfc9eb7ba19473c2e59df28859a11a88248b5cbbc4d/black-26.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:5e9d0d86df21f2e1677cc4bd090cd0e446278bcbbe49bf3659c308c3e402843e", size = 1413613, upload-time = "2026-03-12T03:40:10.943Z" }, - { url = "https://files.pythonhosted.org/packages/16/73/544f23891b22e7efe4d8f812371ab85b57f6a01b2fc45e3ba2e52ba985b8/black-26.3.1-cp311-cp311-win_arm64.whl", hash = "sha256:9a5e9f45e5d5e1c5b5c29b3bd4265dcc90e8b92cf4534520896ed77f791f4da5", size = 1219719, upload-time = "2026-03-12T03:40:12.597Z" }, { url = "https://files.pythonhosted.org/packages/dc/f8/da5eae4fc75e78e6dceb60624e1b9662ab00d6b452996046dfa9b8a6025b/black-26.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e6f89631eb88a7302d416594a32faeee9fb8fb848290da9d0a5f2903519fc1", size = 1895920, upload-time = "2026-03-12T03:40:13.921Z" }, { url = "https://files.pythonhosted.org/packages/2c/9f/04e6f26534da2e1629b2b48255c264cabf5eedc5141d04516d9d68a24111/black-26.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cd2012d35b47d589cb8a16faf8a32ef7a336f56356babd9fcf70939ad1897f", size = 1718499, upload-time = "2026-03-12T03:40:15.239Z" }, { url = "https://files.pythonhosted.org/packages/04/91/a5935b2a63e31b331060c4a9fdb5a6c725840858c599032a6f3aac94055f/black-26.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f76ff19ec5297dd8e66eb64deda23631e642c9393ab592826fd4bdc97a4bce7", size = 1794994, upload-time = "2026-03-12T03:40:17.124Z" }, @@ -295,18 +267,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e1/87/af89ad449e8254fdbc74654e6467e3c9381b61472cc532ee350d28cfdafb/black-26.3.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f1cd08e99d2f9317292a311dfe578fd2a24b15dbce97792f9c4d752275c1fa56", size = 1793557, upload-time = "2026-03-12T03:40:25.497Z" }, { url = "https://files.pythonhosted.org/packages/43/10/d6c06a791d8124b843bf325ab4ac7d2f5b98731dff84d6064eafd687ded1/black-26.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:c7e72339f841b5a237ff14f7d3880ddd0fc7f98a1199e8c4327f9a4f478c1839", size = 1422766, upload-time = "2026-03-12T03:40:27.14Z" }, { url = "https://files.pythonhosted.org/packages/59/4f/40a582c015f2d841ac24fed6390bd68f0fc896069ff3a886317959c9daf8/black-26.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:afc622538b430aa4c8c853f7f63bc582b3b8030fd8c80b70fb5fa5b834e575c2", size = 1232140, upload-time = "2026-03-12T03:40:28.882Z" }, - { url = "https://files.pythonhosted.org/packages/d5/da/e36e27c9cebc1311b7579210df6f1c86e50f2d7143ae4fcf8a5017dc8809/black-26.3.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2d6bfaf7fd0993b420bed691f20f9492d53ce9a2bcccea4b797d34e947318a78", size = 1889234, upload-time = "2026-03-12T03:40:30.964Z" }, - { url = "https://files.pythonhosted.org/packages/0e/7b/9871acf393f64a5fa33668c19350ca87177b181f44bb3d0c33b2d534f22c/black-26.3.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f89f2ab047c76a9c03f78d0d66ca519e389519902fa27e7a91117ef7611c0568", size = 1720522, upload-time = "2026-03-12T03:40:32.346Z" }, - { url = "https://files.pythonhosted.org/packages/03/87/e766c7f2e90c07fb7586cc787c9ae6462b1eedab390191f2b7fc7f6170a9/black-26.3.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b07fc0dab849d24a80a29cfab8d8a19187d1c4685d8a5e6385a5ce323c1f015f", size = 1787824, upload-time = "2026-03-12T03:40:33.636Z" }, - { url = "https://files.pythonhosted.org/packages/ac/94/2424338fb2d1875e9e83eed4c8e9c67f6905ec25afd826a911aea2b02535/black-26.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:0126ae5b7c09957da2bdbd91a9ba1207453feada9e9fe51992848658c6c8e01c", size = 1445855, upload-time = "2026-03-12T03:40:35.442Z" }, - { url = "https://files.pythonhosted.org/packages/86/43/0c3338bd928afb8ee7471f1a4eec3bdbe2245ccb4a646092a222e8669840/black-26.3.1-cp314-cp314-win_arm64.whl", hash = "sha256:92c0ec1f2cc149551a2b7b47efc32c866406b6891b0ee4625e95967c8f4acfb1", size = 1258109, upload-time = "2026-03-12T03:40:36.832Z" }, { 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.optional-dependencies] jupyter = [ - { name = "ipython", version = "9.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "ipython", version = "9.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "ipython" }, { name = "tokenize-rt" }, ] @@ -453,10 +419,6 @@ dependencies = [ ] 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/0d/e1/6a52ee21424da0ed30860f4e94d1657ade8d4436f0718485badf0e63011e/cartopy-0.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0e41d52160548a7ab7774423911db3bfb5a8bc0929580958b1945d3a004da872", size = 11006320, upload-time = "2025-08-01T12:43:48.13Z" }, - { url = "https://files.pythonhosted.org/packages/68/06/38bcfeab9822acffc86474659d33c4dc3c5dec4e61e9927fb8cc8617f651/cartopy-0.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:432e2a2688fc58af43b9b6bf1d343bb08e2d6ef298efa91e55445f1d308b5ef3", size = 10995635, upload-time = "2025-08-01T12:43:50.855Z" }, - { url = "https://files.pythonhosted.org/packages/a1/b6/f39407d27d641a949496a52ab00220fe0635758e3cb7afb4b7328abe17e7/cartopy-0.25.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:999e44021db07dcf895b115934fb0816aef39985fbaca6ded61d2536355531de", size = 11808214, upload-time = "2025-08-01T12:43:53.218Z" }, - { url = "https://files.pythonhosted.org/packages/4b/c0/b33ac1f586608e80a5e10f3924e16c117da333fcb5e5240839e6681ac3d5/cartopy-0.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:4139e5ca9faaa037e0576cdcf625b9461a0b404d60e9d20ea24c4d8dbe6f689d", size = 10983301, upload-time = "2025-08-01T12:43:55.427Z" }, { 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" }, @@ -502,19 +464,6 @@ dependencies = [ ] 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/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, - { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, - { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, - { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, - { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, - { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, - { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, - { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, - { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, - { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, - { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, { 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" }, @@ -539,28 +488,6 @@ wheels = [ { 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]] @@ -581,13 +508,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/65/dc/470ffebac2eb8c54151eb893055024fe81b1606e7c6ff8449a588e9cd17f/cftime-1.6.5.tar.gz", hash = "sha256:8225fed6b9b43fb87683ebab52130450fc1730011150d3092096a90e54d1e81e", size = 326605, upload-time = "2025-10-13T18:56:26.352Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/f6/9da7aba9548ede62d25936b8b448acd7e53e5dcc710896f66863dcc9a318/cftime-1.6.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:474e728f5a387299418f8d7cb9c52248dcd5d977b2a01de7ec06bba572e26b02", size = 512733, upload-time = "2025-10-13T18:56:00.189Z" }, - { url = "https://files.pythonhosted.org/packages/1f/d5/d86ad95fc1fd89947c34b495ff6487b6d361cf77500217423b4ebcb1f0c2/cftime-1.6.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab9e80d4de815cac2e2d88a2335231254980e545d0196eb34ee8f7ed612645f1", size = 492946, upload-time = "2025-10-13T18:56:01.262Z" }, - { url = "https://files.pythonhosted.org/packages/4f/93/d7e8dd76b03a9d5be41a3b3185feffc7ea5359228bdffe7aa43ac772a75b/cftime-1.6.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ad24a563784e4795cb3d04bd985895b5db49ace2cbb71fcf1321fd80141f9a52", size = 1689856, upload-time = "2025-10-13T19:39:12.873Z" }, - { url = "https://files.pythonhosted.org/packages/3e/8d/86586c0d75110f774e46e2bd6d134e2d1cca1dedc9bb08c388fa3df76acd/cftime-1.6.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a3cda6fd12c7fb25eff40a6a857a2bf4d03e8cc71f80485d8ddc65ccbd80f16a", size = 1718573, upload-time = "2025-10-13T18:56:02.788Z" }, - { url = "https://files.pythonhosted.org/packages/bb/fe/7956914cfc135992e89098ebbc67d683c51ace5366ba4b114fef1de89b21/cftime-1.6.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:28cda78d685397ba23d06273b9c916c3938d8d9e6872a537e76b8408a321369b", size = 1788563, upload-time = "2025-10-13T18:56:04.075Z" }, - { url = "https://files.pythonhosted.org/packages/e5/c7/6669708fcfe1bb7b2a7ce693b8cc67165eac00d3ac5a5e8f6ce1be551ff9/cftime-1.6.5-cp311-cp311-win_amd64.whl", hash = "sha256:93ead088e3a216bdeb9368733a0ef89a7451dfc1d2de310c1c0366a56ad60dc8", size = 473631, upload-time = "2025-10-13T18:56:05.159Z" }, - { url = "https://files.pythonhosted.org/packages/82/c5/d70cb1ab533ca790d7c9b69f98215fa4fead17f05547e928c8f2b8f96e54/cftime-1.6.5-cp311-cp311-win_arm64.whl", hash = "sha256:3384d69a0a7f3d45bded21a8cbcce66c8ba06c13498eac26c2de41b1b9b6e890", size = 459383, upload-time = "2026-01-02T21:16:47.317Z" }, { url = "https://files.pythonhosted.org/packages/b6/c1/e8cb7f78a3f87295450e7300ebaecf83076d96a99a76190593d4e1d2be40/cftime-1.6.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:eef25caed5ebd003a38719bd3ff8847cd52ef2ea56c3ebdb2c9345ba131fc7c5", size = 504175, upload-time = "2025-10-13T18:56:06.398Z" }, { url = "https://files.pythonhosted.org/packages/50/1a/86e1072b09b2f9049bb7378869f64b6747f96a4f3008142afed8955b52a4/cftime-1.6.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c87d2f3b949e45463e559233c69e6a9cf691b2b378c1f7556166adfabbd1c6b0", size = 485980, upload-time = "2025-10-13T18:56:08.669Z" }, { url = "https://files.pythonhosted.org/packages/35/28/d3177b60da3f308b60dee2aef2eb69997acfab1e863f0bf0d2a418396ce5/cftime-1.6.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:82cb413973cc51b55642b3a1ca5b28db5b93a294edbef7dc049c074b478b4647", size = 1591166, upload-time = "2025-10-13T19:39:14.109Z" }, @@ -602,19 +522,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cf/33/03e0b23d58ea8fab94ecb4f7c5b721e844a0800c13694876149d98830a73/cftime-1.6.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18ab754805233cdd889614b2b3b86a642f6d51a57a1ec327c48053f3414f87d8", size = 1684269, upload-time = "2025-10-13T18:56:17.04Z" }, { url = "https://files.pythonhosted.org/packages/a4/60/a0cfba63847b43599ef1cdbbf682e61894994c22b9a79fd9e1e8c7e9de41/cftime-1.6.5-cp313-cp313-win_amd64.whl", hash = "sha256:6c27add8f907f4a4cd400e89438f2ea33e2eb5072541a157a4d013b7dbe93f9c", size = 465364, upload-time = "2025-10-13T18:56:18.05Z" }, { url = "https://files.pythonhosted.org/packages/3d/e8/ec32f2aef22c15604e6fda39ff8d581a00b5469349f8fba61640d5358d2c/cftime-1.6.5-cp313-cp313-win_arm64.whl", hash = "sha256:31d1ff8f6bbd4ca209099d24459ec16dea4fb4c9ab740fbb66dd057ccbd9b1b9", size = 450468, upload-time = "2026-01-02T21:16:50.193Z" }, - { url = "https://files.pythonhosted.org/packages/ea/6c/a9618f589688358e279720f5c0fe67ef0077fba07334ce26895403ebc260/cftime-1.6.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c69ce3bdae6a322cbb44e9ebc20770d47748002fb9d68846a1e934f1bd5daf0b", size = 502725, upload-time = "2025-10-13T18:56:19.424Z" }, - { url = "https://files.pythonhosted.org/packages/d8/e3/da3c36398bfb730b96248d006cabaceed87e401ff56edafb2a978293e228/cftime-1.6.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e62e9f2943e014c5ef583245bf2e878398af131c97e64f8cd47c1d7baef5c4e2", size = 485445, upload-time = "2025-10-13T18:56:20.853Z" }, - { url = "https://files.pythonhosted.org/packages/32/93/b05939e5abd14bd1ab69538bbe374b4ee2a15467b189ff895e9a8cdaddf6/cftime-1.6.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7da5fdaa4360d8cb89b71b8ded9314f2246aa34581e8105c94ad58d6102d9e4f", size = 1584434, upload-time = "2025-10-13T19:39:17.084Z" }, - { url = "https://files.pythonhosted.org/packages/7f/89/648397f9936e0b330999c4e776ebf296ec3c6a65f9901687dbca4ab820da/cftime-1.6.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bff865b4ea4304f2744a1ad2b8149b8328b321dd7a2b9746ef926d229bd7cd49", size = 1609812, upload-time = "2025-10-13T18:56:21.971Z" }, - { url = "https://files.pythonhosted.org/packages/e7/0f/901b4835aa67ad3e915605d4e01d0af80a44b114eefab74ae33de6d36933/cftime-1.6.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e552c5d1c8a58f25af7521e49237db7ca52ed2953e974fe9f7c4491e95fdd36c", size = 1669768, upload-time = "2025-10-13T18:56:24.027Z" }, - { url = "https://files.pythonhosted.org/packages/22/d5/e605e4b28363e7a9ae98ed12cabbda5b155b6009270e6a231d8f10182a17/cftime-1.6.5-cp314-cp314-win_amd64.whl", hash = "sha256:e645b095dc50a38ac454b7e7f0742f639e7d7f6b108ad329358544a6ff8c9ba2", size = 463818, upload-time = "2025-10-13T18:56:25.376Z" }, - { url = "https://files.pythonhosted.org/packages/3d/89/a8f85ae697ff10206ec401c2621f5ca9f327554f586d62f244739ceeb347/cftime-1.6.5-cp314-cp314-win_arm64.whl", hash = "sha256:b9044d7ac82d3d8af189df1032fdc871bbd3f3dd41a6ec79edceb5029b71e6e0", size = 459862, upload-time = "2026-01-02T20:45:02.625Z" }, - { url = "https://files.pythonhosted.org/packages/ab/05/7410e12fd03a0c52717e74e6a1b49958810807dda212e23b65d43ea99676/cftime-1.6.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:9ef56460cb0576e1a9161e1428c9e1a633f809a23fa9d598f313748c1ae5064e", size = 533781, upload-time = "2026-01-02T20:45:04.818Z" }, - { url = "https://files.pythonhosted.org/packages/44/ba/10e3546426d3ed9f9cc82e4a99836bb6fac1642c7830f7bdd0ac1c3f0805/cftime-1.6.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4f4873d38b10032f9f3111c547a1d485519ae64eee6a7a2d091f1f8b08e1ba50", size = 515218, upload-time = "2026-01-02T20:45:06.788Z" }, - { url = "https://files.pythonhosted.org/packages/bd/68/efa11eae867749e921bfec6a865afdba8166e96188112dde70bb8bb49254/cftime-1.6.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ccce0f4c9d3f38dd948a117e578b50d0e0db11e2ca9435fb358fd524813e4b61", size = 1579932, upload-time = "2026-01-02T20:45:11.194Z" }, - { url = "https://files.pythonhosted.org/packages/9d/6c/0971e602c1390a423e6621dfbad9f1d375186bdaf9c9c7f75e06f1fbf355/cftime-1.6.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:19cbfc5152fb0b34ce03acf9668229af388d7baa63a78f936239cb011ccbe6b1", size = 1555894, upload-time = "2026-01-02T20:45:16.351Z" }, - { url = "https://files.pythonhosted.org/packages/ad/fc/8475a15b7c3209a4a68b563dfc5e01ce74f2d8b9822372c3d30c68ab7f39/cftime-1.6.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4470cd5ef3c2514566f53efbcbb64dd924fa0584637d90285b2f983bd4ee7d97", size = 513027, upload-time = "2026-01-02T20:45:20.023Z" }, - { url = "https://files.pythonhosted.org/packages/f7/80/4ecbda8318fbf40ad4e005a4a93aebba69e81382e5b4c6086251cd5d0ee8/cftime-1.6.5-cp314-cp314t-win_arm64.whl", hash = "sha256:034c15a67144a0a5590ef150c99f844897618b148b87131ed34fda7072614662", size = 469065, upload-time = "2026-01-02T20:45:23.398Z" }, ] [[package]] @@ -623,22 +530,6 @@ version = "3.4.7" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705, upload-time = "2026-04-02T09:26:02.191Z" }, - { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419, upload-time = "2026-04-02T09:26:03.583Z" }, - { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901, upload-time = "2026-04-02T09:26:04.738Z" }, - { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742, upload-time = "2026-04-02T09:26:06.36Z" }, - { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061, upload-time = "2026-04-02T09:26:08.347Z" }, - { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239, upload-time = "2026-04-02T09:26:09.823Z" }, - { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173, upload-time = "2026-04-02T09:26:10.953Z" }, - { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841, upload-time = "2026-04-02T09:26:12.142Z" }, - { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304, upload-time = "2026-04-02T09:26:13.711Z" }, - { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455, upload-time = "2026-04-02T09:26:14.941Z" }, - { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036, upload-time = "2026-04-02T09:26:16.478Z" }, - { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739, upload-time = "2026-04-02T09:26:17.751Z" }, - { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277, upload-time = "2026-04-02T09:26:18.981Z" }, - { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819, upload-time = "2026-04-02T09:26:20.295Z" }, - { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281, upload-time = "2026-04-02T09:26:21.74Z" }, - { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843, upload-time = "2026-04-02T09:26:22.901Z" }, { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, @@ -671,38 +562,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" }, { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" }, { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" }, - { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" }, - { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" }, - { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" }, - { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" }, - { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" }, - { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" }, - { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" }, - { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" }, - { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" }, - { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" }, - { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" }, - { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" }, - { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" }, - { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" }, - { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" }, - { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" }, - { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" }, - { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" }, - { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" }, - { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" }, - { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" }, - { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" }, - { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" }, - { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" }, - { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" }, - { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" }, - { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" }, - { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" }, - { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" }, - { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" }, - { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" }, { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, ] @@ -718,18 +577,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl", hash = "sha256:1924d2c27c5653561cd2cae4548d1406039cb79b858b747cfea24924bbc1616d", size = 108379, upload-time = "2026-04-03T19:14:43.505Z" }, ] -[[package]] -name = "click-plugins" -version = "1.1.1.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click", marker = "python_full_version < '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c3/a4/34847b59150da33690a36da3681d6bbc2ec14ee9a846bc30a6746e5984e4/click_plugins-1.1.1.2.tar.gz", hash = "sha256:d7af3984a99d243c131aa1a828331e7630f4a88a9741fd05c927b204bcf92261", size = 8343, upload-time = "2025-06-25T00:47:37.555Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl", hash = "sha256:008d65743833ffc1f5417bf0e78e8d2c23aab04d9745ba817bd3e71b0feb6aa6", size = 11051, upload-time = "2025-06-25T00:47:36.731Z" }, -] - [[package]] name = "cligj" version = "0.7.2" @@ -760,12 +607,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/49/d5/8daa1179809f0d8eab39bd83ce8131e84691eb6ba55f19b7b365a822fea3/color_operations-0.2.0.tar.gz", hash = "sha256:f1bff5cff5992ec7d240f1979320a981f2e9f77d983e9298291e02f3ffaac9bf", size = 18042, upload-time = "2025-03-27T08:42:14.222Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/18/ed195e388f55ef46b89cee994a5dc7c36a6c76fd3c40ed1960b86dcba4ba/color_operations-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6fb9b74b9dc33832d08afc8f71ec4161531f48e8bf105d0412e9a718904c5369", size = 86416, upload-time = "2025-03-27T09:18:16.848Z" }, - { url = "https://files.pythonhosted.org/packages/32/60/a9955ab7077309241d47f0b88d43b993abd49b753ed69449b8f2ced7c30c/color_operations-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:05838eee03df5304e014de76bd3ff19974964fc57dad8ce52cf56a9a62f5d572", size = 50869, upload-time = "2025-03-27T09:18:17.761Z" }, - { url = "https://files.pythonhosted.org/packages/b5/79/3fb8aee10ceb0278bd256eee35dd9fd9607370e4bb75a75a56173fb04394/color_operations-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5222cf35ca089637d3424eb42a0c9bfa25aa91dbf771759f6c8003b09b5134cc", size = 49243, upload-time = "2025-03-27T09:18:18.814Z" }, - { url = "https://files.pythonhosted.org/packages/ec/b5/1783a6834d10960a13c18b6a34f27597052510142ce89125662276184f99/color_operations-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b807de37a40ee1d6fa91d122b0afe1df5f17ee60b9ef1bd38e8c134ffb3070d", size = 189098, upload-time = "2025-03-27T09:18:20.093Z" }, - { url = "https://files.pythonhosted.org/packages/91/d8/c33469d020f135414a5cd936bd31f4d3d2e3db557df94847ed59cf99a422/color_operations-0.2.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:780685c51e103f378c7bdffbafdd3e24f89b6dcd64079b7d6b3fbab7a23a06bf", size = 195175, upload-time = "2025-03-27T09:18:21.577Z" }, - { url = "https://files.pythonhosted.org/packages/0b/b6/1dbff90606551f6e802fbabb4e422d3261552a7d8b7a5f4e00f5727e7525/color_operations-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:676812cd90ef37e8ca214c376d0a43f223f2717bf37d0b513a4a57c2e1fcfc62", size = 133689, upload-time = "2025-03-27T09:18:22.696Z" }, { url = "https://files.pythonhosted.org/packages/50/69/e8c09a930c45cbdf6d3cf84e32a6e53a44a200c447bed8ddf94a75a3f372/color_operations-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:98a3348d1dab6c5fdd79a9eeb90cd81bf6f5bf6ca65a24414460d90be76c2c37", size = 86112, upload-time = "2025-03-27T09:18:23.824Z" }, { url = "https://files.pythonhosted.org/packages/72/eb/d66611577d721318d5a70dcfcd8d26194cfa14e958bd14a02631c1e712f2/color_operations-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:55a10f40ca59505a260e0f8b1ee392a2c049314177d3858ae477e8cc5daff07d", size = 50735, upload-time = "2025-03-27T09:18:24.727Z" }, { url = "https://files.pythonhosted.org/packages/b1/57/13dbcc9913967489851f0b7d1c8d27840abe86e02d6e2e133d16db16d0d5/color_operations-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3d791eee208f208da9428f38ec9cad80bae4fa55bcde2af1b6d7e939d4f298d7", size = 49066, upload-time = "2025-03-27T09:18:26.084Z" }, @@ -819,17 +660,6 @@ dependencies = [ ] 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/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1", size = 288773, upload-time = "2025-07-26T12:01:02.277Z" }, - { url = "https://files.pythonhosted.org/packages/0d/44/c4b0b6095fef4dc9c420e041799591e3b63e9619e3044f7f4f6c21c0ab24/contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381", size = 270149, upload-time = "2025-07-26T12:01:04.072Z" }, - { url = "https://files.pythonhosted.org/packages/30/2e/dd4ced42fefac8470661d7cb7e264808425e6c5d56d175291e93890cce09/contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7", size = 329222, upload-time = "2025-07-26T12:01:05.688Z" }, - { url = "https://files.pythonhosted.org/packages/f2/74/cc6ec2548e3d276c71389ea4802a774b7aa3558223b7bade3f25787fafc2/contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1", size = 377234, upload-time = "2025-07-26T12:01:07.054Z" }, - { url = "https://files.pythonhosted.org/packages/03/b3/64ef723029f917410f75c09da54254c5f9ea90ef89b143ccadb09df14c15/contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a", size = 380555, upload-time = "2025-07-26T12:01:08.801Z" }, - { url = "https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db", size = 355238, upload-time = "2025-07-26T12:01:10.319Z" }, - { url = "https://files.pythonhosted.org/packages/98/56/f914f0dd678480708a04cfd2206e7c382533249bc5001eb9f58aa693e200/contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620", size = 1326218, upload-time = "2025-07-26T12:01:12.659Z" }, - { url = "https://files.pythonhosted.org/packages/fb/d7/4a972334a0c971acd5172389671113ae82aa7527073980c38d5868ff1161/contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f", size = 1392867, upload-time = "2025-07-26T12:01:15.533Z" }, - { url = "https://files.pythonhosted.org/packages/75/3e/f2cc6cd56dc8cff46b1a56232eabc6feea52720083ea71ab15523daab796/contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff", size = 183677, upload-time = "2025-07-26T12:01:17.088Z" }, - { url = "https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42", size = 225234, upload-time = "2025-07-26T12:01:18.256Z" }, - { url = "https://files.pythonhosted.org/packages/d9/b6/71771e02c2e004450c12b1120a5f488cad2e4d5b590b1af8bad060360fe4/contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470", size = 193123, upload-time = "2025-07-26T12:01:19.848Z" }, { 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" }, @@ -863,33 +693,6 @@ wheels = [ { 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" }, - { url = "https://files.pythonhosted.org/packages/a5/29/8dcfe16f0107943fa92388c23f6e05cff0ba58058c4c95b00280d4c75a14/contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497", size = 278809, upload-time = "2025-07-26T12:02:52.74Z" }, - { url = "https://files.pythonhosted.org/packages/85/a9/8b37ef4f7dafeb335daee3c8254645ef5725be4d9c6aa70b50ec46ef2f7e/contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8", size = 261593, upload-time = "2025-07-26T12:02:54.037Z" }, - { url = "https://files.pythonhosted.org/packages/0a/59/ebfb8c677c75605cc27f7122c90313fd2f375ff3c8d19a1694bda74aaa63/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e", size = 302202, upload-time = "2025-07-26T12:02:55.947Z" }, - { url = "https://files.pythonhosted.org/packages/3c/37/21972a15834d90bfbfb009b9d004779bd5a07a0ec0234e5ba8f64d5736f4/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989", size = 329207, upload-time = "2025-07-26T12:02:57.468Z" }, - { url = "https://files.pythonhosted.org/packages/0c/58/bd257695f39d05594ca4ad60df5bcb7e32247f9951fd09a9b8edb82d1daa/contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77", size = 225315, upload-time = "2025-07-26T12:02:58.801Z" }, ] [[package]] @@ -898,21 +701,6 @@ version = "7.13.5" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", size = 915967, upload-time = "2026-03-17T10:33:18.341Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/37/d24c8f8220ff07b839b2c043ea4903a33b0f455abe673ae3c03bbdb7f212/coverage-7.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66a80c616f80181f4d643b0f9e709d97bcea413ecd9631e1dedc7401c8e6695d", size = 219381, upload-time = "2026-03-17T10:30:14.68Z" }, - { url = "https://files.pythonhosted.org/packages/35/8b/cd129b0ca4afe886a6ce9d183c44d8301acbd4ef248622e7c49a23145605/coverage-7.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:145ede53ccbafb297c1c9287f788d1bc3efd6c900da23bf6931b09eafc931587", size = 219880, upload-time = "2026-03-17T10:30:16.231Z" }, - { url = "https://files.pythonhosted.org/packages/55/2f/e0e5b237bffdb5d6c530ce87cc1d413a5b7d7dfd60fb067ad6d254c35c76/coverage-7.13.5-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0672854dc733c342fa3e957e0605256d2bf5934feeac328da9e0b5449634a642", size = 250303, upload-time = "2026-03-17T10:30:17.748Z" }, - { url = "https://files.pythonhosted.org/packages/92/be/b1afb692be85b947f3401375851484496134c5554e67e822c35f28bf2fbc/coverage-7.13.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec10e2a42b41c923c2209b846126c6582db5e43a33157e9870ba9fb70dc7854b", size = 252218, upload-time = "2026-03-17T10:30:19.804Z" }, - { url = "https://files.pythonhosted.org/packages/da/69/2f47bb6fa1b8d1e3e5d0c4be8ccb4313c63d742476a619418f85740d597b/coverage-7.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be3d4bbad9d4b037791794ddeedd7d64a56f5933a2c1373e18e9e568b9141686", size = 254326, upload-time = "2026-03-17T10:30:21.321Z" }, - { url = "https://files.pythonhosted.org/packages/d5/d0/79db81da58965bd29dabc8f4ad2a2af70611a57cba9d1ec006f072f30a54/coverage-7.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d2afbc5cc54d286bfb54541aa50b64cdb07a718227168c87b9e2fb8f25e1743", size = 256267, upload-time = "2026-03-17T10:30:23.094Z" }, - { url = "https://files.pythonhosted.org/packages/e5/32/d0d7cc8168f91ddab44c0ce4806b969df5f5fdfdbb568eaca2dbc2a04936/coverage-7.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3ad050321264c49c2fa67bb599100456fc51d004b82534f379d16445da40fb75", size = 250430, upload-time = "2026-03-17T10:30:25.311Z" }, - { url = "https://files.pythonhosted.org/packages/4d/06/a055311d891ddbe231cd69fdd20ea4be6e3603ffebddf8704b8ca8e10a3c/coverage-7.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7300c8a6d13335b29bb76d7651c66af6bd8658517c43499f110ddc6717bfc209", size = 252017, upload-time = "2026-03-17T10:30:27.284Z" }, - { url = "https://files.pythonhosted.org/packages/d6/f6/d0fd2d21e29a657b5f77a2fe7082e1568158340dceb941954f776dce1b7b/coverage-7.13.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:eb07647a5738b89baab047f14edd18ded523de60f3b30e75c2acc826f79c839a", size = 250080, upload-time = "2026-03-17T10:30:29.481Z" }, - { url = "https://files.pythonhosted.org/packages/4e/ab/0d7fb2efc2e9a5eb7ddcc6e722f834a69b454b7e6e5888c3a8567ecffb31/coverage-7.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9adb6688e3b53adffefd4a52d72cbd8b02602bfb8f74dcd862337182fd4d1a4e", size = 253843, upload-time = "2026-03-17T10:30:31.301Z" }, - { url = "https://files.pythonhosted.org/packages/ba/6f/7467b917bbf5408610178f62a49c0ed4377bb16c1657f689cc61470da8ce/coverage-7.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7c8d4bc913dd70b93488d6c496c77f3aff5ea99a07e36a18f865bca55adef8bd", size = 249802, upload-time = "2026-03-17T10:30:33.358Z" }, - { url = "https://files.pythonhosted.org/packages/75/2c/1172fb689df92135f5bfbbd69fc83017a76d24ea2e2f3a1154007e2fb9f8/coverage-7.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0e3c426ffc4cd952f54ee9ffbdd10345709ecc78a3ecfd796a57236bfad0b9b8", size = 250707, upload-time = "2026-03-17T10:30:35.2Z" }, - { url = "https://files.pythonhosted.org/packages/67/21/9ac389377380a07884e3b48ba7a620fcd9dbfaf1d40565facdc6b36ec9ef/coverage-7.13.5-cp311-cp311-win32.whl", hash = "sha256:259b69bb83ad9894c4b25be2528139eecba9a82646ebdda2d9db1ba28424a6bf", size = 221880, upload-time = "2026-03-17T10:30:36.775Z" }, - { url = "https://files.pythonhosted.org/packages/af/7f/4cd8a92531253f9d7c1bbecd9fa1b472907fb54446ca768c59b531248dc5/coverage-7.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:258354455f4e86e3e9d0d17571d522e13b4e1e19bf0f8596bcf9476d61e7d8a9", size = 222816, upload-time = "2026-03-17T10:30:38.891Z" }, - { url = "https://files.pythonhosted.org/packages/12/a6/1d3f6155fb0010ca68eba7fe48ca6c9da7385058b77a95848710ecf189b1/coverage-7.13.5-cp311-cp311-win_arm64.whl", hash = "sha256:bff95879c33ec8da99fc9b6fe345ddb5be6414b41d6d1ad1c8f188d26f36e028", size = 221483, upload-time = "2026-03-17T10:30:40.463Z" }, { url = "https://files.pythonhosted.org/packages/a0/c3/a396306ba7db865bf96fc1fb3b7fd29bcbf3d829df642e77b13555163cd6/coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01", size = 219554, upload-time = "2026-03-17T10:30:42.208Z" }, { url = "https://files.pythonhosted.org/packages/a6/16/a68a19e5384e93f811dccc51034b1fd0b865841c390e3c931dcc4699e035/coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422", size = 219908, upload-time = "2026-03-17T10:30:43.906Z" }, { url = "https://files.pythonhosted.org/packages/29/72/20b917c6793af3a5ceb7fb9c50033f3ec7865f2911a1416b34a7cfa0813b/coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f", size = 251419, upload-time = "2026-03-17T10:30:45.545Z" }, @@ -958,36 +746,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/14/4f/f5df9007e50b15e53e01edea486814783a7f019893733d9e4d6caad75557/coverage-7.13.5-cp313-cp313t-win32.whl", hash = "sha256:67e9bc5449801fad0e5dff329499fb090ba4c5800b86805c80617b4e29809b2a", size = 222788, upload-time = "2026-03-17T10:32:02.246Z" }, { url = "https://files.pythonhosted.org/packages/e1/98/aa7fccaa97d0f3192bec013c4e6fd6d294a6ed44b640e6bb61f479e00ed5/coverage-7.13.5-cp313-cp313t-win_amd64.whl", hash = "sha256:da86cdcf10d2519e10cabb8ac2de03da1bcb6e4853790b7fbd48523332e3a819", size = 223851, upload-time = "2026-03-17T10:32:04.416Z" }, { url = "https://files.pythonhosted.org/packages/3d/8b/e5c469f7352651e5f013198e9e21f97510b23de957dd06a84071683b4b60/coverage-7.13.5-cp313-cp313t-win_arm64.whl", hash = "sha256:0ecf12ecb326fe2c339d93fc131816f3a7367d223db37817208905c89bded911", size = 222104, upload-time = "2026-03-17T10:32:06.65Z" }, - { url = "https://files.pythonhosted.org/packages/8e/77/39703f0d1d4b478bfd30191d3c14f53caf596fac00efb3f8f6ee23646439/coverage-7.13.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f", size = 219621, upload-time = "2026-03-17T10:32:08.589Z" }, - { url = "https://files.pythonhosted.org/packages/e2/3e/51dff36d99ae14639a133d9b164d63e628532e2974d8b1edb99dd1ebc733/coverage-7.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e", size = 219953, upload-time = "2026-03-17T10:32:10.507Z" }, - { url = "https://files.pythonhosted.org/packages/6a/6c/1f1917b01eb647c2f2adc9962bd66c79eb978951cab61bdc1acab3290c07/coverage-7.13.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a", size = 250992, upload-time = "2026-03-17T10:32:12.41Z" }, - { url = "https://files.pythonhosted.org/packages/22/e5/06b1f88f42a5a99df42ce61208bdec3bddb3d261412874280a19796fc09c/coverage-7.13.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510", size = 253503, upload-time = "2026-03-17T10:32:14.449Z" }, - { url = "https://files.pythonhosted.org/packages/80/28/2a148a51e5907e504fa7b85490277734e6771d8844ebcc48764a15e28155/coverage-7.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247", size = 254852, upload-time = "2026-03-17T10:32:16.56Z" }, - { url = "https://files.pythonhosted.org/packages/61/77/50e8d3d85cc0b7ebe09f30f151d670e302c7ff4a1bf6243f71dd8b0981fa/coverage-7.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6", size = 257161, upload-time = "2026-03-17T10:32:19.004Z" }, - { url = "https://files.pythonhosted.org/packages/3b/c4/b5fd1d4b7bf8d0e75d997afd3925c59ba629fc8616f1b3aae7605132e256/coverage-7.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0", size = 251021, upload-time = "2026-03-17T10:32:21.344Z" }, - { url = "https://files.pythonhosted.org/packages/f8/66/6ea21f910e92d69ef0b1c3346ea5922a51bad4446c9126db2ae96ee24c4c/coverage-7.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882", size = 252858, upload-time = "2026-03-17T10:32:23.506Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ea/879c83cb5d61aa2a35fb80e72715e92672daef8191b84911a643f533840c/coverage-7.13.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740", size = 250823, upload-time = "2026-03-17T10:32:25.516Z" }, - { url = "https://files.pythonhosted.org/packages/8a/fb/616d95d3adb88b9803b275580bdeee8bd1b69a886d057652521f83d7322f/coverage-7.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16", size = 255099, upload-time = "2026-03-17T10:32:27.944Z" }, - { url = "https://files.pythonhosted.org/packages/1c/93/25e6917c90ec1c9a56b0b26f6cad6408e5f13bb6b35d484a0d75c9cf000d/coverage-7.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0", size = 250638, upload-time = "2026-03-17T10:32:29.914Z" }, - { url = "https://files.pythonhosted.org/packages/fc/7b/dc1776b0464145a929deed214aef9fb1493f159b59ff3c7eeeedf91eddd0/coverage-7.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0", size = 252295, upload-time = "2026-03-17T10:32:31.981Z" }, - { url = "https://files.pythonhosted.org/packages/ea/fb/99cbbc56a26e07762a2740713f3c8f9f3f3106e3a3dd8cc4474954bccd34/coverage-7.13.5-cp314-cp314-win32.whl", hash = "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc", size = 222360, upload-time = "2026-03-17T10:32:34.233Z" }, - { url = "https://files.pythonhosted.org/packages/8d/b7/4758d4f73fb536347cc5e4ad63662f9d60ba9118cb6785e9616b2ce5d7fa/coverage-7.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633", size = 223174, upload-time = "2026-03-17T10:32:36.369Z" }, - { url = "https://files.pythonhosted.org/packages/2c/f2/24d84e1dfe70f8ac9fdf30d338239860d0d1d5da0bda528959d0ebc9da28/coverage-7.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8", size = 221739, upload-time = "2026-03-17T10:32:38.736Z" }, - { url = "https://files.pythonhosted.org/packages/60/5b/4a168591057b3668c2428bff25dd3ebc21b629d666d90bcdfa0217940e84/coverage-7.13.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b", size = 220351, upload-time = "2026-03-17T10:32:41.196Z" }, - { url = "https://files.pythonhosted.org/packages/f5/21/1fd5c4dbfe4a58b6b99649125635df46decdfd4a784c3cd6d410d303e370/coverage-7.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c", size = 220612, upload-time = "2026-03-17T10:32:43.204Z" }, - { url = "https://files.pythonhosted.org/packages/d6/fe/2a924b3055a5e7e4512655a9d4609781b0d62334fa0140c3e742926834e2/coverage-7.13.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9", size = 261985, upload-time = "2026-03-17T10:32:45.514Z" }, - { url = "https://files.pythonhosted.org/packages/d7/0d/c8928f2bd518c45990fe1a2ab8db42e914ef9b726c975facc4282578c3eb/coverage-7.13.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29", size = 264107, upload-time = "2026-03-17T10:32:47.971Z" }, - { url = "https://files.pythonhosted.org/packages/ef/ae/4ae35bbd9a0af9d820362751f0766582833c211224b38665c0f8de3d487f/coverage-7.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607", size = 266513, upload-time = "2026-03-17T10:32:50.1Z" }, - { url = "https://files.pythonhosted.org/packages/9c/20/d326174c55af36f74eac6ae781612d9492f060ce8244b570bb9d50d9d609/coverage-7.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90", size = 267650, upload-time = "2026-03-17T10:32:52.391Z" }, - { url = "https://files.pythonhosted.org/packages/7a/5e/31484d62cbd0eabd3412e30d74386ece4a0837d4f6c3040a653878bfc019/coverage-7.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3", size = 261089, upload-time = "2026-03-17T10:32:54.544Z" }, - { url = "https://files.pythonhosted.org/packages/e9/d8/49a72d6de146eebb0b7e48cc0f4bc2c0dd858e3d4790ab2b39a2872b62bd/coverage-7.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab", size = 263982, upload-time = "2026-03-17T10:32:56.803Z" }, - { url = "https://files.pythonhosted.org/packages/06/3b/0351f1bd566e6e4dd39e978efe7958bde1d32f879e85589de147654f57bb/coverage-7.13.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562", size = 261579, upload-time = "2026-03-17T10:32:59.466Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ce/796a2a2f4017f554d7810f5c573449b35b1e46788424a548d4d19201b222/coverage-7.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2", size = 265316, upload-time = "2026-03-17T10:33:01.847Z" }, - { url = "https://files.pythonhosted.org/packages/3d/16/d5ae91455541d1a78bc90abf495be600588aff8f6db5c8b0dae739fa39c9/coverage-7.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea", size = 260427, upload-time = "2026-03-17T10:33:03.945Z" }, - { url = "https://files.pythonhosted.org/packages/48/11/07f413dba62db21fb3fad5d0de013a50e073cc4e2dc4306e770360f6dfc8/coverage-7.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a", size = 262745, upload-time = "2026-03-17T10:33:06.285Z" }, - { url = "https://files.pythonhosted.org/packages/91/15/d792371332eb4663115becf4bad47e047d16234b1aff687b1b18c58d60ae/coverage-7.13.5-cp314-cp314t-win32.whl", hash = "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215", size = 223146, upload-time = "2026-03-17T10:33:08.756Z" }, - { url = "https://files.pythonhosted.org/packages/db/51/37221f59a111dca5e85be7dbf09696323b5b9f13ff65e0641d535ed06ea8/coverage-7.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43", size = 224254, upload-time = "2026-03-17T10:33:11.174Z" }, - { url = "https://files.pythonhosted.org/packages/54/83/6acacc889de8987441aa7d5adfbdbf33d288dad28704a67e574f1df9bcbb/coverage-7.13.5-cp314-cp314t-win_arm64.whl", hash = "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45", size = 222276, upload-time = "2026-03-17T10:33:13.466Z" }, { url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", size = 211346, upload-time = "2026-03-17T10:33:15.691Z" }, ] @@ -1008,7 +766,6 @@ dependencies = [ { name = "click" }, { name = "cloudpickle" }, { name = "fsspec" }, - { name = "importlib-metadata", marker = "python_full_version < '3.12'" }, { name = "packaging" }, { name = "partd" }, { name = "pyyaml" }, @@ -1050,10 +807,6 @@ version = "1.8.20" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e0/b7/cd8080344452e4874aae67c40d8940e2b4d47b01601a8fd9f44786c757c7/debugpy-1.8.20.tar.gz", hash = "sha256:55bc8701714969f1ab89a6d5f2f3d40c36f91b2cbe2f65d98bf8196f6a6a2c33", size = 1645207, upload-time = "2026-01-29T23:03:28.199Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/56/c3baf5cbe4dd77427fd9aef99fcdade259ad128feeb8a786c246adb838e5/debugpy-1.8.20-cp311-cp311-macosx_15_0_universal2.whl", hash = "sha256:eada6042ad88fa1571b74bd5402ee8b86eded7a8f7b827849761700aff171f1b", size = 2208318, upload-time = "2026-01-29T23:03:36.481Z" }, - { url = "https://files.pythonhosted.org/packages/9a/7d/4fa79a57a8e69fe0d9763e98d1110320f9ecd7f1f362572e3aafd7417c9d/debugpy-1.8.20-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:7de0b7dfeedc504421032afba845ae2a7bcc32ddfb07dae2c3ca5442f821c344", size = 3171493, upload-time = "2026-01-29T23:03:37.775Z" }, - { url = "https://files.pythonhosted.org/packages/7d/f2/1e8f8affe51e12a26f3a8a8a4277d6e60aa89d0a66512f63b1e799d424a4/debugpy-1.8.20-cp311-cp311-win32.whl", hash = "sha256:773e839380cf459caf73cc533ea45ec2737a5cc184cf1b3b796cd4fd98504fec", size = 5209240, upload-time = "2026-01-29T23:03:39.109Z" }, - { url = "https://files.pythonhosted.org/packages/d5/92/1cb532e88560cbee973396254b21bece8c5d7c2ece958a67afa08c9f10dc/debugpy-1.8.20-cp311-cp311-win_amd64.whl", hash = "sha256:1f7650546e0eded1902d0f6af28f787fa1f1dbdbc97ddabaf1cd963a405930cb", size = 5233481, upload-time = "2026-01-29T23:03:40.659Z" }, { url = "https://files.pythonhosted.org/packages/14/57/7f34f4736bfb6e00f2e4c96351b07805d83c9a7b33d28580ae01374430f7/debugpy-1.8.20-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:4ae3135e2089905a916909ef31922b2d733d756f66d87345b3e5e52b7a55f13d", size = 2550686, upload-time = "2026-01-29T23:03:42.023Z" }, { url = "https://files.pythonhosted.org/packages/ab/78/b193a3975ca34458f6f0e24aaf5c3e3da72f5401f6054c0dfd004b41726f/debugpy-1.8.20-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:88f47850a4284b88bd2bfee1f26132147d5d504e4e86c22485dfa44b97e19b4b", size = 4310588, upload-time = "2026-01-29T23:03:43.314Z" }, { url = "https://files.pythonhosted.org/packages/c1/55/f14deb95eaf4f30f07ef4b90a8590fc05d9e04df85ee379712f6fb6736d7/debugpy-1.8.20-cp312-cp312-win32.whl", hash = "sha256:4057ac68f892064e5f98209ab582abfee3b543fb55d2e87610ddc133a954d390", size = 5331372, upload-time = "2026-01-29T23:03:45.526Z" }, @@ -1062,10 +815,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/90/83/fb33dcea789ed6018f8da20c5a9bc9d82adc65c0c990faed43f7c955da46/debugpy-1.8.20-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:84562982dd7cf5ebebfdea667ca20a064e096099997b175fe204e86817f64eaf", size = 4293272, upload-time = "2026-01-29T23:03:50.169Z" }, { url = "https://files.pythonhosted.org/packages/a6/25/b1e4a01bfb824d79a6af24b99ef291e24189080c93576dfd9b1a2815cd0f/debugpy-1.8.20-cp313-cp313-win32.whl", hash = "sha256:da11dea6447b2cadbf8ce2bec59ecea87cc18d2c574980f643f2d2dfe4862393", size = 5331208, upload-time = "2026-01-29T23:03:51.547Z" }, { url = "https://files.pythonhosted.org/packages/13/f7/a0b368ce54ffff9e9028c098bd2d28cfc5b54f9f6c186929083d4c60ba58/debugpy-1.8.20-cp313-cp313-win_amd64.whl", hash = "sha256:eb506e45943cab2efb7c6eafdd65b842f3ae779f020c82221f55aca9de135ed7", size = 5372930, upload-time = "2026-01-29T23:03:53.585Z" }, - { url = "https://files.pythonhosted.org/packages/33/2e/f6cb9a8a13f5058f0a20fe09711a7b726232cd5a78c6a7c05b2ec726cff9/debugpy-1.8.20-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:9c74df62fc064cd5e5eaca1353a3ef5a5d50da5eb8058fcef63106f7bebe6173", size = 2538066, upload-time = "2026-01-29T23:03:54.999Z" }, - { url = "https://files.pythonhosted.org/packages/c5/56/6ddca50b53624e1ca3ce1d1e49ff22db46c47ea5fb4c0cc5c9b90a616364/debugpy-1.8.20-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:077a7447589ee9bc1ff0cdf443566d0ecf540ac8aa7333b775ebcb8ce9f4ecad", size = 4269425, upload-time = "2026-01-29T23:03:56.518Z" }, - { url = "https://files.pythonhosted.org/packages/c5/d9/d64199c14a0d4c476df46c82470a3ce45c8d183a6796cfb5e66533b3663c/debugpy-1.8.20-cp314-cp314-win32.whl", hash = "sha256:352036a99dd35053b37b7803f748efc456076f929c6a895556932eaf2d23b07f", size = 5331407, upload-time = "2026-01-29T23:03:58.481Z" }, - { url = "https://files.pythonhosted.org/packages/e0/d9/1f07395b54413432624d61524dfd98c1a7c7827d2abfdb8829ac92638205/debugpy-1.8.20-cp314-cp314-win_amd64.whl", hash = "sha256:a98eec61135465b062846112e5ecf2eebb855305acc1dfbae43b72903b8ab5be", size = 5372521, upload-time = "2026-01-29T23:03:59.864Z" }, { url = "https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl", hash = "sha256:5be9bed9ae3be00665a06acaa48f8329d2b9632f15fd09f6a9a8c8d9907e54d7", size = 5337658, upload-time = "2026-01-29T23:04:17.404Z" }, ] @@ -1136,13 +885,6 @@ version = "1.5.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0c/66/744b4931b799a42f8cb9bc7a6f169e7b8e51195b62b246db407fd90bf15f/duckdb-1.5.2.tar.gz", hash = "sha256:638da0d5102b6cb6f7d47f83d0600708ac1d3cb46c5e9aaabc845f9ba4d69246", size = 18017166, upload-time = "2026-04-13T11:30:09.065Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/b0/d13e7e396d86c245290b3e93f692a2d27c2fe99f857aaf9205003c00c978/duckdb-1.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7f69164b048e498b9e9140a24343108a5ae5f17bfb3485185f55fdf9b1aa924d", size = 30020978, upload-time = "2026-04-13T11:28:52.486Z" }, - { url = "https://files.pythonhosted.org/packages/70/7b/ae1ec7f516394aa55501d1949af1f731be8d9d7433f0acc3f4632a0ba484/duckdb-1.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:81fc4fbf0b5e25840b39ba2a10b78c6953c0314d5d0434191e7898f34ab1bba3", size = 15947821, upload-time = "2026-04-13T11:28:55.981Z" }, - { url = "https://files.pythonhosted.org/packages/8a/a5/cae0105e01a85f85ead61723bb42dab14c2f8ec49f91e67a2372c02574a4/duckdb-1.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56d38b3c4e0ef2abb58898d0fd423933999ed535c45e75e9d9f72e1d5fed69b8", size = 14201656, upload-time = "2026-04-13T11:28:58.316Z" }, - { url = "https://files.pythonhosted.org/packages/50/db/46c57e8813ac33762bddc9545610ed648751c5b6a379abf2dc6035505ce4/duckdb-1.5.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:376856066c65ccd55fcb3a380bbe33a71ce089fc4623d229ffc6e82251afdb6d", size = 19285181, upload-time = "2026-04-13T11:29:01.041Z" }, - { url = "https://files.pythonhosted.org/packages/dc/a2/67694010693ec8c8c975e6991f48ef886d35ecbdaa2f287234882a403c21/duckdb-1.5.2-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c69907354ffee94ba8cf782daf0480dab7557f21ce27fffa6c0ea8f74ed4b8e2", size = 21394852, upload-time = "2026-04-13T11:29:03.814Z" }, - { url = "https://files.pythonhosted.org/packages/52/9f/2b1618c5a93949a70dcf105293db7e27bb2b2cc4aeb1ff46b806f430ec81/duckdb-1.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:d9b4f5430bf4f05d4c0dc4c55c75def3a5af4be0343be20fa2bfc577343fbfc9", size = 13095526, upload-time = "2026-04-13T11:29:06.265Z" }, - { url = "https://files.pythonhosted.org/packages/b8/e9/cb39e0d94a32f5333e819112fd01439a31f541f9c56a31b66f9bd209704b/duckdb-1.5.2-cp311-cp311-win_arm64.whl", hash = "sha256:2323c1195c10fb2bb982fc0218c730b43d1b92a355d61e68e3c5f3ac9d44c34f", size = 13946215, upload-time = "2026-04-13T11:29:08.672Z" }, { url = "https://files.pythonhosted.org/packages/41/de/ebe66bbe78125fc610f4fd415447a65349d94245950f3b3dfb31d028af02/duckdb-1.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e6495b00cad16888384119842797c49316a96ae1cb132bb03856d980d95afee1", size = 30064950, upload-time = "2026-04-13T11:29:11.468Z" }, { url = "https://files.pythonhosted.org/packages/2d/8a/3e25b5d03bcf1fb99d189912f8ce92b1db4f9c8778e1b1f55745973a855a/duckdb-1.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d72b8856b1839d35648f38301b058f6232f4d36b463fe4dc8f4d3fdff2df1a2e", size = 15969113, upload-time = "2026-04-13T11:29:14.139Z" }, { url = "https://files.pythonhosted.org/packages/19/bb/58001f0815002b1a93431bf907f77854085c7d049b83d521814a07b9db0b/duckdb-1.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2a1de4f4d454b8c97aec546c82003fc834d3422ce4bc6a19902f3462ef293bed", size = 14224774, upload-time = "2026-04-13T11:29:16.758Z" }, @@ -1157,13 +899,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bd/21/d903cc63a5140c822b7b62b373a87dc557e60c29b321dfb435061c5e67cf/duckdb-1.5.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70631c847ca918ee710ec874241b00cf9d2e5be90762cbb2a0389f17823c08f7", size = 21429837, upload-time = "2026-04-13T11:29:41.135Z" }, { url = "https://files.pythonhosted.org/packages/e3/0a/b770d1f60c70597302130d6247f418549b7094251a02348fbaf1c7e147ae/duckdb-1.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:52a21823f3fbb52f0f0e5425e20b07391ad882464b955879499b5ff0b45a376b", size = 13107699, upload-time = "2026-04-13T11:29:43.905Z" }, { url = "https://files.pythonhosted.org/packages/d9/cf/e200fe431d700962d1a908d2ce89f53ccee1cc8db260174ae663ba09686b/duckdb-1.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:411ad438bd4140f189a10e7f515781335962c5d18bd07837dc6d202e3985253d", size = 13927646, upload-time = "2026-04-13T11:29:46.598Z" }, - { url = "https://files.pythonhosted.org/packages/83/a1/f6286c67726cc1ea60a6e3c0d9fbc66527dde24ae089a51bbe298b13ca78/duckdb-1.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:6b0fe75c148000f060aa1a27b293cacc0ea08cc1cad724fbf2143d56070a3785", size = 30078598, upload-time = "2026-04-13T11:29:49.828Z" }, - { url = "https://files.pythonhosted.org/packages/de/6a/59febb02f21a4a5c6b0b0099ef7c965fdd5e61e4904cf813809bb792e35f/duckdb-1.5.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:35579b8e3a064b5eaf15b0eafc558056a13f79a0a62e34cc4baf57119daecfec", size = 15975120, upload-time = "2026-04-13T11:29:52.631Z" }, - { url = "https://files.pythonhosted.org/packages/09/70/ce750854d37bb5a45cccbb2c3cb04df4af56aea8fc30a2499bb643b4a9c0/duckdb-1.5.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ea58ff5b0880593a280cf5511734b17711b32ee1f58b47d726e8600848358160", size = 14227762, upload-time = "2026-04-13T11:29:55.564Z" }, - { url = "https://files.pythonhosted.org/packages/28/dc/ad45ac3c0b6c4687dc649e8f6cf01af1c8b0443932a39b2abb4ebcb3babd/duckdb-1.5.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef461bca07313412dc09961c4a4757a851f56b95ac01c58fac6007632b7b94f2", size = 19315668, upload-time = "2026-04-13T11:29:58.427Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b1/1464f468d2e5813f5808de95df9d3113a645a5bfa2ffcaecbc542ddae272/duckdb-1.5.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be37680ddb380015cb37318e378c53511c45c4f0d8fac5599d22b7d092b9217a", size = 21434056, upload-time = "2026-04-13T11:30:01.238Z" }, - { url = "https://files.pythonhosted.org/packages/ce/32/6673607e024722473fa7aafdd29c0e3dd231dd528f6cd8b5797fbeeb229d/duckdb-1.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:0b291786014df1133f8f18b9df4d004484613146e858d71a21791e0fcca16cf4", size = 13633667, upload-time = "2026-04-13T11:30:04.05Z" }, - { url = "https://files.pythonhosted.org/packages/7a/e3/9d34173ec068631faea3ea6e73050700729363e7e33306a9a3218e5cdc61/duckdb-1.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:c9f3e0b71b8a50fccfb42794899285d9d318ce2503782b9dd54868e5ecd0ad31", size = 14402513, upload-time = "2026-04-13T11:30:06.609Z" }, ] [[package]] @@ -1318,14 +1053,6 @@ version = "4.62.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9a/08/7012b00a9a5874311b639c3920270c36ee0c445b69d9989a85e5c92ebcb0/fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d", size = 3580737, upload-time = "2026-03-13T13:54:25.52Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/39/23ff32561ec8d45a4d48578b4d241369d9270dc50926c017570e60893701/fonttools-4.62.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:40975849bac44fb0b9253d77420c6d8b523ac4dcdcefeff6e4d706838a5b80f7", size = 2871039, upload-time = "2026-03-13T13:52:33.127Z" }, - { url = "https://files.pythonhosted.org/packages/24/7f/66d3f8a9338a9b67fe6e1739f47e1cd5cee78bd3bc1206ef9b0b982289a5/fonttools-4.62.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9dde91633f77fa576879a0c76b1d89de373cae751a98ddf0109d54e173b40f14", size = 2416346, upload-time = "2026-03-13T13:52:35.676Z" }, - { url = "https://files.pythonhosted.org/packages/aa/53/5276ceba7bff95da7793a07c5284e1da901cf00341ce5e2f3273056c0cca/fonttools-4.62.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6acb4109f8bee00fec985c8c7afb02299e35e9c94b57287f3ea542f28bd0b0a7", size = 5100897, upload-time = "2026-03-13T13:52:38.102Z" }, - { url = "https://files.pythonhosted.org/packages/cc/a1/40a5c4d8e28b0851d53a8eeeb46fbd73c325a2a9a165f290a5ed90e6c597/fonttools-4.62.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1c5c25671ce8805e0d080e2ffdeca7f1e86778c5cbfbeae86d7f866d8830517b", size = 5071078, upload-time = "2026-03-13T13:52:41.305Z" }, - { url = "https://files.pythonhosted.org/packages/e3/be/d378fca4c65ea1956fee6d90ace6e861776809cbbc5af22388a090c3c092/fonttools-4.62.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a5d8825e1140f04e6c99bb7d37a9e31c172f3bc208afbe02175339e699c710e1", size = 5076908, upload-time = "2026-03-13T13:52:44.122Z" }, - { url = "https://files.pythonhosted.org/packages/f8/d9/ae6a1d0693a4185a84605679c8a1f719a55df87b9c6e8e817bfdd9ef5936/fonttools-4.62.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:268abb1cb221e66c014acc234e872b7870d8b5d4657a83a8f4205094c32d2416", size = 5202275, upload-time = "2026-03-13T13:52:46.591Z" }, - { url = "https://files.pythonhosted.org/packages/54/6c/af95d9c4efb15cabff22642b608342f2bd67137eea6107202d91b5b03184/fonttools-4.62.1-cp311-cp311-win32.whl", hash = "sha256:942b03094d7edbb99bdf1ae7e9090898cad7bf9030b3d21f33d7072dbcb51a53", size = 2293075, upload-time = "2026-03-13T13:52:48.711Z" }, - { url = "https://files.pythonhosted.org/packages/d3/97/bf54c5b3f2be34e1f143e6db838dfdc54f2ffa3e68c738934c82f3b2a08d/fonttools-4.62.1-cp311-cp311-win_amd64.whl", hash = "sha256:e8514f4924375f77084e81467e63238b095abda5107620f49421c368a6017ed2", size = 2344593, upload-time = "2026-03-13T13:52:50.725Z" }, { url = "https://files.pythonhosted.org/packages/47/d4/dbacced3953544b9a93088cc10ef2b596d348c983d5c67a404fa41ec51ba/fonttools-4.62.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:90365821debbd7db678809c7491ca4acd1e0779b9624cdc6ddaf1f31992bf974", size = 2870219, upload-time = "2026-03-13T13:52:53.664Z" }, { url = "https://files.pythonhosted.org/packages/66/9e/a769c8e99b81e5a87ab7e5e7236684de4e96246aae17274e5347d11ebd78/fonttools-4.62.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12859ff0b47dd20f110804c3e0d0970f7b832f561630cd879969011541a464a9", size = 2414891, upload-time = "2026-03-13T13:52:56.493Z" }, { url = "https://files.pythonhosted.org/packages/69/64/f19a9e3911968c37e1e620e14dfc5778299e1474f72f4e57c5ec771d9489/fonttools-4.62.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c125ffa00c3d9003cdaaf7f2c79e6e535628093e14b5de1dccb08859b680936", size = 5033197, upload-time = "2026-03-13T13:52:59.179Z" }, @@ -1342,22 +1069,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1f/ae/b41f8628ec0be3c1b934fc12b84f4576a5c646119db4d3bdd76a217c90b5/fonttools-4.62.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:403d28ce06ebfc547fbcb0cb8b7f7cc2f7a2d3e1a67ba9a34b14632df9e080f9", size = 5094920, upload-time = "2026-03-13T13:53:29.329Z" }, { url = "https://files.pythonhosted.org/packages/f2/f6/53a1e9469331a23dcc400970a27a4caa3d9f6edbf5baab0260285238b884/fonttools-4.62.1-cp313-cp313-win32.whl", hash = "sha256:93c316e0f5301b2adbe6a5f658634307c096fd5aae60a5b3412e4f3e1728ab24", size = 2279928, upload-time = "2026-03-13T13:53:32.352Z" }, { url = "https://files.pythonhosted.org/packages/38/60/35186529de1db3c01f5ad625bde07c1f576305eab6d86bbda4c58445f721/fonttools-4.62.1-cp313-cp313-win_amd64.whl", hash = "sha256:7aa21ff53e28a9c2157acbc44e5b401149d3c9178107130e82d74ceb500e5056", size = 2330514, upload-time = "2026-03-13T13:53:34.991Z" }, - { url = "https://files.pythonhosted.org/packages/36/f0/2888cdac391807d68d90dcb16ef858ddc1b5309bfc6966195a459dd326e2/fonttools-4.62.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fa1d16210b6b10a826d71bed68dd9ec24a9e218d5a5e2797f37c573e7ec215ca", size = 2864442, upload-time = "2026-03-13T13:53:37.509Z" }, - { url = "https://files.pythonhosted.org/packages/4b/b2/e521803081f8dc35990816b82da6360fa668a21b44da4b53fc9e77efcd62/fonttools-4.62.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:aa69d10ed420d8121118e628ad47d86e4caa79ba37f968597b958f6cceab7eca", size = 2410901, upload-time = "2026-03-13T13:53:40.55Z" }, - { url = "https://files.pythonhosted.org/packages/00/a4/8c3511ff06e53110039358dbbdc1a65d72157a054638387aa2ada300a8b8/fonttools-4.62.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd13b7999d59c5eb1c2b442eb2d0c427cb517a0b7a1f5798fc5c9e003f5ff782", size = 4999608, upload-time = "2026-03-13T13:53:42.798Z" }, - { url = "https://files.pythonhosted.org/packages/28/63/cd0c3b26afe60995a5295f37c246a93d454023726c3261cfbb3559969bb9/fonttools-4.62.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8d337fdd49a79b0d51c4da87bc38169d21c3abbf0c1aa9367eff5c6656fb6dae", size = 4912726, upload-time = "2026-03-13T13:53:45.405Z" }, - { url = "https://files.pythonhosted.org/packages/70/b9/ac677cb07c24c685cf34f64e140617d58789d67a3dd524164b63648c6114/fonttools-4.62.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d241cdc4a67b5431c6d7f115fdf63335222414995e3a1df1a41e1182acd4bcc7", size = 4951422, upload-time = "2026-03-13T13:53:48.326Z" }, - { url = "https://files.pythonhosted.org/packages/e6/10/11c08419a14b85b7ca9a9faca321accccc8842dd9e0b1c8a72908de05945/fonttools-4.62.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c05557a78f8fa514da0f869556eeda40887a8abc77c76ee3f74cf241778afd5a", size = 5060979, upload-time = "2026-03-13T13:53:51.366Z" }, - { url = "https://files.pythonhosted.org/packages/4e/3c/12eea4a4cf054e7ab058ed5ceada43b46809fce2bf319017c4d63ae55bb4/fonttools-4.62.1-cp314-cp314-win32.whl", hash = "sha256:49a445d2f544ce4a69338694cad575ba97b9a75fff02720da0882d1a73f12800", size = 2283733, upload-time = "2026-03-13T13:53:53.606Z" }, - { url = "https://files.pythonhosted.org/packages/6b/67/74b070029043186b5dd13462c958cb7c7f811be0d2e634309d9a1ffb1505/fonttools-4.62.1-cp314-cp314-win_amd64.whl", hash = "sha256:1eecc128c86c552fb963fe846ca4e011b1be053728f798185a1687502f6d398e", size = 2335663, upload-time = "2026-03-13T13:53:56.23Z" }, - { url = "https://files.pythonhosted.org/packages/42/c5/4d2ed3ca6e33617fc5624467da353337f06e7f637707478903c785bd8e20/fonttools-4.62.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:1596aeaddf7f78e21e68293c011316a25267b3effdaccaf4d59bc9159d681b82", size = 2947288, upload-time = "2026-03-13T13:53:59.397Z" }, - { url = "https://files.pythonhosted.org/packages/1f/e9/7ab11ddfda48ed0f89b13380e5595ba572619c27077be0b2c447a63ff351/fonttools-4.62.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8f8fca95d3bb3208f59626a4b0ea6e526ee51f5a8ad5d91821c165903e8d9260", size = 2449023, upload-time = "2026-03-13T13:54:01.642Z" }, - { url = "https://files.pythonhosted.org/packages/b2/10/a800fa090b5e8819942e54e19b55fc7c21fe14a08757c3aa3ca8db358939/fonttools-4.62.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee91628c08e76f77b533d65feb3fbe6d9dad699f95be51cf0d022db94089cdc4", size = 5137599, upload-time = "2026-03-13T13:54:04.495Z" }, - { url = "https://files.pythonhosted.org/packages/37/dc/8ccd45033fffd74deb6912fa1ca524643f584b94c87a16036855b498a1ed/fonttools-4.62.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5f37df1cac61d906e7b836abe356bc2f34c99d4477467755c216b72aa3dc748b", size = 4920933, upload-time = "2026-03-13T13:54:07.557Z" }, - { url = "https://files.pythonhosted.org/packages/99/eb/e618adefb839598d25ac8136cd577925d6c513dc0d931d93b8af956210f0/fonttools-4.62.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:92bb00a947e666169c99b43753c4305fc95a890a60ef3aeb2a6963e07902cc87", size = 5016232, upload-time = "2026-03-13T13:54:10.611Z" }, - { url = "https://files.pythonhosted.org/packages/d9/5f/9b5c9bfaa8ec82def8d8168c4f13615990d6ce5996fe52bd49bfb5e05134/fonttools-4.62.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bdfe592802ef939a0e33106ea4a318eeb17822c7ee168c290273cbd5fabd746c", size = 5042987, upload-time = "2026-03-13T13:54:13.569Z" }, - { url = "https://files.pythonhosted.org/packages/90/aa/dfbbe24c6a6afc5c203d90cc0343e24bcbb09e76d67c4d6eef8c2558d7ba/fonttools-4.62.1-cp314-cp314t-win32.whl", hash = "sha256:b820fcb92d4655513d8402d5b219f94481c4443d825b4372c75a2072aa4b357a", size = 2348021, upload-time = "2026-03-13T13:54:16.98Z" }, - { url = "https://files.pythonhosted.org/packages/13/6f/ae9c4e4dd417948407b680855c2c7790efb52add6009aaecff1e3bc50e8e/fonttools-4.62.1-cp314-cp314t-win_amd64.whl", hash = "sha256:59b372b4f0e113d3746b88985f1c796e7bf830dd54b28374cd85c2b8acd7583e", size = 2414147, upload-time = "2026-03-13T13:54:19.416Z" }, { url = "https://files.pythonhosted.org/packages/fd/ba/56147c165442cc5ba7e82ecf301c9a68353cede498185869e6e02b4c264f/fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd", size = 1152647, upload-time = "2026-03-13T13:54:22.735Z" }, ] @@ -1388,7 +1099,6 @@ dependencies = [ { name = "filelock" }, { name = "requests", extra = ["socks"] }, { name = "tqdm" }, - { name = "typing-extensions", marker = "python_full_version < '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/72/01/9e0280ba321f73295374765dc3c0b1e03058188a592a48a321376f9eb092/gdown-6.0.0.tar.gz", hash = "sha256:1f1f735a174ef3599fca95786aafac1219b9d85d4c729ccb95e674996c47fd44", size = 262729, upload-time = "2026-04-12T06:37:40.182Z" } wheels = [ @@ -1440,12 +1150,9 @@ dependencies = [ { name = "pyogrio" }, { name = "pystac-client" }, { name = "python-dotenv" }, - { name = "rasterio", version = "1.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "rasterio", version = "1.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "rioxarray", version = "0.19.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "rioxarray", version = "0.22.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "scitools-iris", version = "3.14.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "scitools-iris", version = "3.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "rasterio" }, + { name = "rioxarray" }, + { name = "scitools-iris" }, { name = "typer" }, { name = "xarray" }, ] @@ -1635,18 +1342,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] -[[package]] -name = "importlib-metadata" -version = "9.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "zipp", marker = "python_full_version < '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl", hash = "sha256:2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7", size = 27789, upload-time = "2026-03-20T06:42:55.665Z" }, -] - [[package]] name = "importlib-resources" version = "7.1.0" @@ -1697,8 +1392,7 @@ dependencies = [ { name = "appnope", marker = "sys_platform == 'darwin'" }, { name = "comm" }, { name = "debugpy" }, - { name = "ipython", version = "9.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "ipython", version = "9.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "ipython" }, { name = "jupyter-client" }, { name = "jupyter-core" }, { name = "matplotlib-inline" }, @@ -1730,63 +1424,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/49/69/e9858f2c0b99bf9f036348d1c84b8026f438bb6875effe6a9bcd9883dada/ipyleaflet-0.20.0-py3-none-any.whl", hash = "sha256:b4c20ddc0b17d68e226cd3367ca2215a4db7e2b14374468c0eeaa54b53e4d173", size = 31578, upload-time = "2025-06-13T08:33:37.353Z" }, ] -[[package]] -name = "ipython" -version = "9.10.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.12' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version < '3.12' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version < '3.12' and sys_platform == 'emscripten'", - "python_full_version < '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] -dependencies = [ - { name = "colorama", marker = "python_full_version < '3.12' and sys_platform == 'win32'" }, - { name = "decorator", marker = "python_full_version < '3.12'" }, - { name = "ipython-pygments-lexers", marker = "python_full_version < '3.12'" }, - { name = "jedi", marker = "python_full_version < '3.12'" }, - { name = "matplotlib-inline", marker = "python_full_version < '3.12'" }, - { name = "pexpect", marker = "python_full_version < '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "prompt-toolkit", marker = "python_full_version < '3.12'" }, - { name = "pygments", marker = "python_full_version < '3.12'" }, - { name = "stack-data", marker = "python_full_version < '3.12'" }, - { name = "traitlets", marker = "python_full_version < '3.12'" }, - { name = "typing-extensions", marker = "python_full_version < '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/25/daae0e764047b0a2480c7bbb25d48f4f509b5818636562eeac145d06dfee/ipython-9.10.1.tar.gz", hash = "sha256:e170e9b2a44312484415bdb750492699bf329233b03f2557a9692cce6466ada4", size = 4426663, upload-time = "2026-03-27T09:53:26.244Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/09/ba70f8d662d5671687da55ad2cc0064cf795b15e1eea70907532202e7c97/ipython-9.10.1-py3-none-any.whl", hash = "sha256:82d18ae9fb9164ded080c71ef92a182ee35ee7db2395f67616034bebb020a232", size = 622827, upload-time = "2026-03-27T09:53:24.566Z" }, -] - [[package]] name = "ipython" version = "9.12.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version >= '3.14' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] -dependencies = [ - { name = "colorama", marker = "python_full_version >= '3.12' and sys_platform == 'win32'" }, - { name = "decorator", marker = "python_full_version >= '3.12'" }, - { name = "ipython-pygments-lexers", marker = "python_full_version >= '3.12'" }, - { name = "jedi", marker = "python_full_version >= '3.12'" }, - { name = "matplotlib-inline", marker = "python_full_version >= '3.12'" }, - { name = "pexpect", marker = "python_full_version >= '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "prompt-toolkit", marker = "python_full_version >= '3.12'" }, - { name = "pygments", marker = "python_full_version >= '3.12'" }, - { name = "stack-data", marker = "python_full_version >= '3.12'" }, - { name = "traitlets", marker = "python_full_version >= '3.12'" }, +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 = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3a/73/7114f80a8f9cabdb13c27732dce24af945b2923dcab80723602f7c8bc2d8/ipython-9.12.0.tar.gz", hash = "sha256:01daa83f504b693ba523b5a407246cabde4eb4513285a3c6acaff11a66735ee4", size = 4428879, upload-time = "2026-03-27T09:42:45.312Z" } wheels = [ @@ -1847,8 +1499,7 @@ version = "8.1.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "comm" }, - { name = "ipython", version = "9.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "ipython", version = "9.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "ipython" }, { name = "jupyterlab-widgets" }, { name = "traitlets" }, { name = "widgetsnbextension" }, @@ -2062,7 +1713,6 @@ dependencies = [ { name = "jupyter-server-terminals" }, { name = "nbconvert" }, { name = "nbformat" }, - { name = "overrides", marker = "python_full_version < '3.12'" }, { name = "packaging" }, { name = "prometheus-client" }, { name = "pywinpty", marker = "os_name == 'nt'" }, @@ -2170,21 +1820,6 @@ version = "1.5.0" source = { registry = "https://pypi.org/simple" } 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/12/dd/a495a9c104be1c476f0386e714252caf2b7eca883915422a64c50b88c6f5/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9eed0f7edbb274413b6ee781cca50541c8c0facd3d6fd289779e494340a2b85c", size = 122798, upload-time = "2026-03-09T13:12:58.963Z" }, - { url = "https://files.pythonhosted.org/packages/11/60/37b4047a2af0cf5ef6d8b4b26e91829ae6fc6a2d1f74524bcb0e7cd28a32/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c4923e404d6bcd91b6779c009542e5647fef32e4a5d75e115e3bbac6f2335eb", size = 66216, upload-time = "2026-03-09T13:13:00.155Z" }, - { url = "https://files.pythonhosted.org/packages/0a/aa/510dc933d87767584abfe03efa445889996c70c2990f6f87c3ebaa0a18c5/kiwisolver-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0df54df7e686afa55e6f21fb86195224a6d9beb71d637e8d7920c95cf0f89aac", size = 63911, upload-time = "2026-03-09T13:13:01.671Z" }, - { url = "https://files.pythonhosted.org/packages/80/46/bddc13df6c2a40741e0cc7865bb1c9ed4796b6760bd04ce5fae3928ef917/kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2517e24d7315eb51c10664cdb865195df38ab74456c677df67bb47f12d088a27", size = 1438209, upload-time = "2026-03-09T13:13:03.385Z" }, - { url = "https://files.pythonhosted.org/packages/fd/d6/76621246f5165e5372f02f5e6f3f48ea336a8f9e96e43997d45b240ed8cd/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff710414307fefa903e0d9bdf300972f892c23477829f49504e59834f4195398", size = 1248888, upload-time = "2026-03-09T13:13:05.231Z" }, - { url = "https://files.pythonhosted.org/packages/b2/c1/31559ec6fb39a5b48035ce29bb63ade628f321785f38c384dee3e2c08bc1/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6176c1811d9d5a04fa391c490cc44f451e240697a16977f11c6f722efb9041db", size = 1266304, upload-time = "2026-03-09T13:13:06.743Z" }, - { url = "https://files.pythonhosted.org/packages/5e/ef/1cb8276f2d29cc6a41e0a042f27946ca347d3a4a75acf85d0a16aa6dcc82/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50847dca5d197fcbd389c805aa1a1cf32f25d2e7273dc47ab181a517666b68cc", size = 1319650, upload-time = "2026-03-09T13:13:08.607Z" }, - { url = "https://files.pythonhosted.org/packages/4c/e4/5ba3cecd7ce6236ae4a80f67e5d5531287337d0e1f076ca87a5abe4cd5d0/kiwisolver-1.5.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:01808c6d15f4c3e8559595d6d1fe6411c68e4a3822b4b9972b44473b24f4e679", size = 970949, upload-time = "2026-03-09T13:13:10.299Z" }, - { url = "https://files.pythonhosted.org/packages/5a/69/dc61f7ae9a2f071f26004ced87f078235b5507ab6e5acd78f40365655034/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f1f9f4121ec58628c96baa3de1a55a4e3a333c5102c8e94b64e23bf7b2083309", size = 2199125, upload-time = "2026-03-09T13:13:11.841Z" }, - { url = "https://files.pythonhosted.org/packages/e5/7b/abbe0f1b5afa85f8d084b73e90e5f801c0939eba16ac2e49af7c61a6c28d/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b7d335370ae48a780c6e6a6bbfa97342f563744c39c35562f3f367665f5c1de2", size = 2293783, upload-time = "2026-03-09T13:13:14.399Z" }, - { url = "https://files.pythonhosted.org/packages/8a/80/5908ae149d96d81580d604c7f8aefd0e98f4fd728cf172f477e9f2a81744/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:800ee55980c18545af444d93fdd60c56b580db5cc54867d8cbf8a1dc0829938c", size = 1960726, upload-time = "2026-03-09T13:13:16.047Z" }, - { url = "https://files.pythonhosted.org/packages/84/08/a78cb776f8c085b7143142ce479859cfec086bd09ee638a317040b6ef420/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c438f6ca858697c9ab67eb28246c92508af972e114cac34e57a6d4ba17a3ac08", size = 2464738, upload-time = "2026-03-09T13:13:17.897Z" }, - { url = "https://files.pythonhosted.org/packages/b1/e1/65584da5356ed6cb12c63791a10b208860ac40a83de165cb6a6751a686e3/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c63c91f95173f9c2a67c7c526b2cea976828a0e7fced9cdcead2802dc10f8a4", size = 2270718, upload-time = "2026-03-09T13:13:19.421Z" }, - { url = "https://files.pythonhosted.org/packages/be/6c/28f17390b62b8f2f520e2915095b3c94d88681ecf0041e75389d9667f202/kiwisolver-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:beb7f344487cdcb9e1efe4b7a29681b74d34c08f0043a327a74da852a6749e7b", size = 73480, upload-time = "2026-03-09T13:13:20.818Z" }, - { url = "https://files.pythonhosted.org/packages/d8/0e/2ee5debc4f77a625778fec5501ff3e8036fe361b7ee28ae402a485bb9694/kiwisolver-1.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:ad4ae4ffd1ee9cd11357b4c66b612da9888f4f4daf2f36995eda64bd45370cac", size = 64930, upload-time = "2026-03-09T13:13:21.997Z" }, { 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" }, @@ -2229,45 +1864,10 @@ wheels = [ { 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" }, - { url = "https://files.pythonhosted.org/packages/e9/eb/5fcbbbf9a0e2c3a35effb88831a483345326bbc3a030a3b5b69aee647f84/kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ec4c85dc4b687c7f7f15f553ff26a98bfe8c58f5f7f0ac8905f0ba4c7be60232", size = 59532, upload-time = "2026-03-09T13:15:47.047Z" }, - { url = "https://files.pythonhosted.org/packages/c3/9b/e17104555bb4db148fd52327feea1e96be4b88e8e008b029002c281a21ab/kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:12e91c215a96e39f57989c8912ae761286ac5a9584d04030ceb3368a357f017a", size = 57420, upload-time = "2026-03-09T13:15:48.199Z" }, - { url = "https://files.pythonhosted.org/packages/48/44/2b5b95b7aa39fb2d8d9d956e0f3d5d45aef2ae1d942d4c3ffac2f9cfed1a/kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be4a51a55833dc29ab5d7503e7bcb3b3af3402d266018137127450005cdfe737", size = 79892, upload-time = "2026-03-09T13:15:49.694Z" }, - { url = "https://files.pythonhosted.org/packages/52/7d/7157f9bba6b455cfb4632ed411e199fc8b8977642c2b12082e1bd9e6d173/kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:daae526907e262de627d8f70058a0f64acc9e2641c164c99c8f594b34a799a16", size = 77603, upload-time = "2026-03-09T13:15:50.945Z" }, - { url = "https://files.pythonhosted.org/packages/0a/dd/8050c947d435c8d4bc94e3252f4d8bb8a76cfb424f043a8680be637a57f1/kiwisolver-1.5.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:59cd8683f575d96df5bb48f6add94afc055012c29e28124fcae2b63661b9efb1", size = 73558, upload-time = "2026-03-09T13:15:52.112Z" }, ] [[package]] @@ -2318,19 +1918,11 @@ name = "libcst" version = "1.8.6" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyyaml", marker = "python_full_version != '3.13.*'" }, - { name = "pyyaml-ft", marker = "python_full_version == '3.13.*'" }, + { name = "pyyaml", marker = "python_full_version < '3.13'" }, + { name = "pyyaml-ft", marker = "python_full_version >= '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/de/cd/337df968b38d94c5aabd3e1b10630f047a2b345f6e1d4456bd9fe7417537/libcst-1.8.6.tar.gz", hash = "sha256:f729c37c9317126da9475bdd06a7208eb52fcbd180a6341648b45a56b4ba708b", size = 891354, upload-time = "2025-11-03T22:33:30.621Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/15/95c2ecadc0fb4af8a7057ac2012a4c0ad5921b9ef1ace6c20006b56d3b5f/libcst-1.8.6-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3649a813660fbffd7bc24d3f810b1f75ac98bd40d9d6f56d1f0ee38579021073", size = 2211289, upload-time = "2025-11-03T22:32:04.673Z" }, - { url = "https://files.pythonhosted.org/packages/80/c3/7e1107acd5ed15cf60cc07c7bb64498a33042dc4821874aea3ec4942f3cd/libcst-1.8.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0cbe17067055829607c5ba4afa46bfa4d0dd554c0b5a583546e690b7367a29b6", size = 2092927, upload-time = "2025-11-03T22:32:06.209Z" }, - { url = "https://files.pythonhosted.org/packages/c1/ff/0d2be87f67e2841a4a37d35505e74b65991d30693295c46fc0380ace0454/libcst-1.8.6-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:59a7e388c57d21d63722018978a8ddba7b176e3a99bd34b9b84a576ed53f2978", size = 2237002, upload-time = "2025-11-03T22:32:07.559Z" }, - { url = "https://files.pythonhosted.org/packages/69/99/8c4a1b35c7894ccd7d33eae01ac8967122f43da41325223181ca7e4738fe/libcst-1.8.6-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:b6c1248cc62952a3a005792b10cdef2a4e130847be9c74f33a7d617486f7e532", size = 2301048, upload-time = "2025-11-03T22:32:08.869Z" }, - { url = "https://files.pythonhosted.org/packages/9b/8b/d1aa811eacf936cccfb386ae0585aa530ea1221ccf528d67144e041f5915/libcst-1.8.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6421a930b028c5ef4a943b32a5a78b7f1bf15138214525a2088f11acbb7d3d64", size = 2300675, upload-time = "2025-11-03T22:32:10.579Z" }, - { url = "https://files.pythonhosted.org/packages/c6/6b/7b65cd41f25a10c1fef2389ddc5c2b2cc23dc4d648083fa3e1aa7e0eeac2/libcst-1.8.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6d8b67874f2188399a71a71731e1ba2d1a2c3173b7565d1cc7ffb32e8fbaba5b", size = 2407934, upload-time = "2025-11-03T22:32:11.856Z" }, - { url = "https://files.pythonhosted.org/packages/c5/8b/401cfff374bb3b785adfad78f05225225767ee190997176b2a9da9ed9460/libcst-1.8.6-cp311-cp311-win_amd64.whl", hash = "sha256:b0d8c364c44ae343937f474b2e492c1040df96d94530377c2f9263fb77096e4f", size = 2119247, upload-time = "2025-11-03T22:32:13.279Z" }, - { url = "https://files.pythonhosted.org/packages/f1/17/085f59eaa044b6ff6bc42148a5449df2b7f0ba567307de7782fe85c39ee2/libcst-1.8.6-cp311-cp311-win_arm64.whl", hash = "sha256:5dcaaebc835dfe5755bc85f9b186fb7e2895dda78e805e577fef1011d51d5a5c", size = 2001774, upload-time = "2025-11-03T22:32:14.647Z" }, { url = "https://files.pythonhosted.org/packages/0c/3c/93365c17da3d42b055a8edb0e1e99f1c60c776471db6c9b7f1ddf6a44b28/libcst-1.8.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0c13d5bd3d8414a129e9dccaf0e5785108a4441e9b266e1e5e9d1f82d1b943c9", size = 2206166, upload-time = "2025-11-03T22:32:16.012Z" }, { url = "https://files.pythonhosted.org/packages/1d/cb/7530940e6ac50c6dd6022349721074e19309eb6aa296e942ede2213c1a19/libcst-1.8.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1472eeafd67cdb22544e59cf3bfc25d23dc94058a68cf41f6654ff4fcb92e09", size = 2083726, upload-time = "2025-11-03T22:32:17.312Z" }, { url = "https://files.pythonhosted.org/packages/1b/cf/7e5eaa8c8f2c54913160671575351d129170db757bb5e4b7faffed022271/libcst-1.8.6-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:089c58e75cb142ec33738a1a4ea7760a28b40c078ab2fd26b270dac7d2633a4d", size = 2235755, upload-time = "2025-11-03T22:32:18.859Z" }, @@ -2355,22 +1947,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ad/cd/15762659a3f5799d36aab1bc2b7e732672722e249d7800e3c5f943b41250/libcst-1.8.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f04febcd70e1e67917be7de513c8d4749d2e09206798558d7fe632134426ea4", size = 2392661, upload-time = "2025-11-03T22:32:47.232Z" }, { url = "https://files.pythonhosted.org/packages/e4/6b/b7f9246c323910fcbe021241500f82e357521495dcfe419004dbb272c7cb/libcst-1.8.6-cp313-cp313t-win_amd64.whl", hash = "sha256:1dc3b897c8b0f7323412da3f4ad12b16b909150efc42238e19cbf19b561cc330", size = 2105068, upload-time = "2025-11-03T22:32:49.145Z" }, { url = "https://files.pythonhosted.org/packages/a6/0b/4fd40607bc4807ec2b93b054594373d7fa3d31bb983789901afcb9bcebe9/libcst-1.8.6-cp313-cp313t-win_arm64.whl", hash = "sha256:44f38139fa95e488db0f8976f9c7ca39a64d6bc09f2eceef260aa1f6da6a2e42", size = 1985181, upload-time = "2025-11-03T22:32:50.597Z" }, - { url = "https://files.pythonhosted.org/packages/3a/60/4105441989e321f7ad0fd28ffccb83eb6aac0b7cfb0366dab855dcccfbe5/libcst-1.8.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:b188e626ce61de5ad1f95161b8557beb39253de4ec74fc9b1f25593324a0279c", size = 2204202, upload-time = "2025-11-03T22:32:52.311Z" }, - { url = "https://files.pythonhosted.org/packages/67/2f/51a6f285c3a183e50cfe5269d4a533c21625aac2c8de5cdf2d41f079320d/libcst-1.8.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:87e74f7d7dfcba9efa91127081e22331d7c42515f0a0ac6e81d4cf2c3ed14661", size = 2083581, upload-time = "2025-11-03T22:32:54.269Z" }, - { url = "https://files.pythonhosted.org/packages/2f/64/921b1c19b638860af76cdb28bc81d430056592910b9478eea49e31a7f47a/libcst-1.8.6-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:3a926a4b42015ee24ddfc8ae940c97bd99483d286b315b3ce82f3bafd9f53474", size = 2236495, upload-time = "2025-11-03T22:32:55.723Z" }, - { url = "https://files.pythonhosted.org/packages/12/a8/b00592f9bede618cbb3df6ffe802fc65f1d1c03d48a10d353b108057d09c/libcst-1.8.6-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:3f4fbb7f569e69fd9e89d9d9caa57ca42c577c28ed05062f96a8c207594e75b8", size = 2301466, upload-time = "2025-11-03T22:32:57.337Z" }, - { url = "https://files.pythonhosted.org/packages/af/df/790d9002f31580fefd0aec2f373a0f5da99070e04c5e8b1c995d0104f303/libcst-1.8.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:08bd63a8ce674be431260649e70fca1d43f1554f1591eac657f403ff8ef82c7a", size = 2300264, upload-time = "2025-11-03T22:32:58.852Z" }, - { url = "https://files.pythonhosted.org/packages/21/de/dc3f10e65bab461be5de57850d2910a02c24c3ddb0da28f0e6e4133c3487/libcst-1.8.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e00e275d4ba95d4963431ea3e409aa407566a74ee2bf309a402f84fc744abe47", size = 2408572, upload-time = "2025-11-03T22:33:00.552Z" }, - { url = "https://files.pythonhosted.org/packages/20/3b/35645157a7590891038b077db170d6dd04335cd2e82a63bdaa78c3297dfe/libcst-1.8.6-cp314-cp314-win_amd64.whl", hash = "sha256:fea5c7fa26556eedf277d4f72779c5ede45ac3018650721edd77fd37ccd4a2d4", size = 2193917, upload-time = "2025-11-03T22:33:02.354Z" }, - { url = "https://files.pythonhosted.org/packages/b3/a2/1034a9ba7d3e82f2c2afaad84ba5180f601aed676d92b76325797ad60951/libcst-1.8.6-cp314-cp314-win_arm64.whl", hash = "sha256:bb9b4077bdf8857b2483879cbbf70f1073bc255b057ec5aac8a70d901bb838e9", size = 2078748, upload-time = "2025-11-03T22:33:03.707Z" }, - { url = "https://files.pythonhosted.org/packages/95/a1/30bc61e8719f721a5562f77695e6154e9092d1bdf467aa35d0806dcd6cea/libcst-1.8.6-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:55ec021a296960c92e5a33b8d93e8ad4182b0eab657021f45262510a58223de1", size = 2188980, upload-time = "2025-11-03T22:33:05.152Z" }, - { url = "https://files.pythonhosted.org/packages/2c/14/c660204532407c5628e3b615015a902ed2d0b884b77714a6bdbe73350910/libcst-1.8.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ba9ab2b012fbd53b36cafd8f4440a6b60e7e487cd8b87428e57336b7f38409a4", size = 2074828, upload-time = "2025-11-03T22:33:06.864Z" }, - { url = "https://files.pythonhosted.org/packages/82/e2/c497c354943dff644749f177ee9737b09ed811b8fc842b05709a40fe0d1b/libcst-1.8.6-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c0a0cc80aebd8aa15609dd4d330611cbc05e9b4216bcaeabba7189f99ef07c28", size = 2225568, upload-time = "2025-11-03T22:33:08.354Z" }, - { url = "https://files.pythonhosted.org/packages/86/ef/45999676d07bd6d0eefa28109b4f97124db114e92f9e108de42ba46a8028/libcst-1.8.6-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:42a4f68121e2e9c29f49c97f6154e8527cd31021809cc4a941c7270aa64f41aa", size = 2286523, upload-time = "2025-11-03T22:33:10.206Z" }, - { url = "https://files.pythonhosted.org/packages/f4/6c/517d8bf57d9f811862f4125358caaf8cd3320a01291b3af08f7b50719db4/libcst-1.8.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a434c521fadaf9680788b50d5c21f4048fa85ed19d7d70bd40549fbaeeecab1", size = 2288044, upload-time = "2025-11-03T22:33:11.628Z" }, - { url = "https://files.pythonhosted.org/packages/83/ce/24d7d49478ffb61207f229239879845da40a374965874f5ee60f96b02ddb/libcst-1.8.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6a65f844d813ab4ef351443badffa0ae358f98821561d19e18b3190f59e71996", size = 2392605, upload-time = "2025-11-03T22:33:12.962Z" }, - { url = "https://files.pythonhosted.org/packages/39/c3/829092ead738b71e96a4e96896c96f276976e5a8a58b4473ed813d7c962b/libcst-1.8.6-cp314-cp314t-win_amd64.whl", hash = "sha256:bdb14bc4d4d83a57062fed2c5da93ecb426ff65b0dc02ddf3481040f5f074a82", size = 2181581, upload-time = "2025-11-03T22:33:14.514Z" }, - { url = "https://files.pythonhosted.org/packages/98/6d/5d6a790a02eb0d9d36c4aed4f41b277497e6178900b2fa29c35353aa45ed/libcst-1.8.6-cp314-cp314t-win_arm64.whl", hash = "sha256:819c8081e2948635cab60c603e1bbdceccdfe19104a242530ad38a36222cb88f", size = 2065000, upload-time = "2025-11-03T22:33:16.257Z" }, ] [[package]] @@ -2379,19 +1955,6 @@ version = "0.9.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/eb/6b/3d5c13fb3e3c4f43206c8f9dfed13778c2ed4f000bacaa0b7ce3c402a265/librt-0.9.0.tar.gz", hash = "sha256:a0951822531e7aee6e0dfb556b30d5ee36bbe234faf60c20a16c01be3530869d", size = 184368, upload-time = "2026-04-09T16:06:26.173Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/1e/2ec7afcebcf3efea593d13aee18bbcfdd3a243043d848ebf385055e9f636/librt-0.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90904fac73c478f4b83f4ed96c99c8208b75e6f9a8a1910548f69a00f1eaa671", size = 67155, upload-time = "2026-04-09T16:04:42.933Z" }, - { url = "https://files.pythonhosted.org/packages/18/77/72b85afd4435268338ad4ec6231b3da8c77363f212a0227c1ff3b45e4d35/librt-0.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:789fff71757facc0738e8d89e3b84e4f0251c1c975e85e81b152cdaca927cc2d", size = 69916, upload-time = "2026-04-09T16:04:44.042Z" }, - { url = "https://files.pythonhosted.org/packages/27/fb/948ea0204fbe2e78add6d46b48330e58d39897e425560674aee302dca81c/librt-0.9.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1bf465d1e5b0a27713862441f6467b5ab76385f4ecf8f1f3a44f8aa3c695b4b6", size = 199635, upload-time = "2026-04-09T16:04:45.5Z" }, - { url = "https://files.pythonhosted.org/packages/ac/cd/894a29e251b296a27957856804cfd21e93c194aa131de8bb8032021be07e/librt-0.9.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f819e0c6413e259a17a7c0d49f97f405abadd3c2a316a3b46c6440b7dbbedbb1", size = 211051, upload-time = "2026-04-09T16:04:47.016Z" }, - { url = "https://files.pythonhosted.org/packages/18/8f/dcaed0bc084a35f3721ff2d081158db569d2c57ea07d35623ddaca5cfc8e/librt-0.9.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e0785c2fb4a81e1aece366aa3e2e039f4a4d7d21aaaded5227d7f3c703427882", size = 224031, upload-time = "2026-04-09T16:04:48.207Z" }, - { url = "https://files.pythonhosted.org/packages/03/44/88f6c1ed1132cd418601cc041fbd92fed28b3a09f39de81978e0822d13ff/librt-0.9.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:80b25c7b570a86c03b5da69e665809deb39265476e8e21d96a9328f9762f9990", size = 218069, upload-time = "2026-04-09T16:04:50.025Z" }, - { url = "https://files.pythonhosted.org/packages/a3/90/7d02e981c2db12188d82b4410ff3e35bfdb844b26aecd02233626f46af2b/librt-0.9.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d4d16b608a1c43d7e33142099a75cd93af482dadce0bf82421e91cad077157f4", size = 224857, upload-time = "2026-04-09T16:04:51.684Z" }, - { url = "https://files.pythonhosted.org/packages/ef/c3/c77e706b7215ca32e928d47535cf13dbc3d25f096f84ddf8fbc06693e229/librt-0.9.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:194fc1a32e1e21fe809d38b5faea66cc65eaa00217c8901fbdb99866938adbdb", size = 219865, upload-time = "2026-04-09T16:04:52.949Z" }, - { url = "https://files.pythonhosted.org/packages/52/d1/32b0c1a0eb8461c70c11656c46a29f760b7c7edf3c36d6f102470c17170f/librt-0.9.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:8c6bc1384d9738781cfd41d09ad7f6e8af13cfea2c75ece6bd6d2566cdea2076", size = 218451, upload-time = "2026-04-09T16:04:54.174Z" }, - { url = "https://files.pythonhosted.org/packages/74/d1/adfd0f9c44761b1d49b1bec66173389834c33ee2bd3c7fd2e2367f1942d4/librt-0.9.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:15cb151e52a044f06e54ac7f7b47adbfc89b5c8e2b63e1175a9d587c43e8942a", size = 241300, upload-time = "2026-04-09T16:04:55.452Z" }, - { url = "https://files.pythonhosted.org/packages/09/b0/9074b64407712f0003c27f5b1d7655d1438979155f049720e8a1abd9b1a1/librt-0.9.0-cp311-cp311-win32.whl", hash = "sha256:f100bfe2acf8a3689af9d0cc660d89f17286c9c795f9f18f7b62dd1a6b247ae6", size = 55668, upload-time = "2026-04-09T16:04:56.689Z" }, - { url = "https://files.pythonhosted.org/packages/24/19/40b77b77ce80b9389fb03971431b09b6b913911c38d412059e0b3e2a9ef2/librt-0.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:0b73e4266307e51c95e09c0750b7ec383c561d2e97d58e473f6f6a209952fbb8", size = 62976, upload-time = "2026-04-09T16:04:57.733Z" }, - { url = "https://files.pythonhosted.org/packages/70/9d/9fa7a64041e29035cb8c575af5f0e3840be1b97b4c4d9061e0713f171849/librt-0.9.0-cp311-cp311-win_arm64.whl", hash = "sha256:bc5518873822d2faa8ebdd2c1a4d7c8ef47b01a058495ab7924cb65bdbf5fc9a", size = 53502, upload-time = "2026-04-09T16:04:58.806Z" }, { url = "https://files.pythonhosted.org/packages/bf/90/89ddba8e1c20b0922783cd93ed8e64f34dc05ab59c38a9c7e313632e20ff/librt-0.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9b3e3bc363f71bda1639a4ee593cb78f7fbfeacc73411ec0d4c92f00730010a4", size = 68332, upload-time = "2026-04-09T16:05:00.09Z" }, { url = "https://files.pythonhosted.org/packages/a8/40/7aa4da1fb08bdeeb540cb07bfc8207cb32c5c41642f2594dbd0098a0662d/librt-0.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0a09c2f5869649101738653a9b7ab70cf045a1105ac66cbb8f4055e61df78f2d", size = 70581, upload-time = "2026-04-09T16:05:01.213Z" }, { url = "https://files.pythonhosted.org/packages/48/ac/73a2187e1031041e93b7e3a25aae37aa6f13b838c550f7e0f06f66766212/librt-0.9.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5ca8e133d799c948db2ab1afc081c333a825b5540475164726dcbf73537e5c2f", size = 203984, upload-time = "2026-04-09T16:05:02.542Z" }, @@ -2418,32 +1981,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/28/527df8ad0d1eb6c8bdfa82fc190f1f7c4cca5a1b6d7b36aeabf95b52d74d/librt-0.9.0-cp313-cp313-win32.whl", hash = "sha256:850d6d03177e52700af605fd60db7f37dcb89782049a149674d1a9649c2138fd", size = 56039, upload-time = "2026-04-09T16:05:30.709Z" }, { url = "https://files.pythonhosted.org/packages/f3/a7/413652ad0d92273ee5e30c000fc494b361171177c83e57c060ecd3c21538/librt-0.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:a5af136bfba820d592f86c67affcef9b3ff4d4360ac3255e341e964489b48519", size = 63264, upload-time = "2026-04-09T16:05:31.881Z" }, { url = "https://files.pythonhosted.org/packages/a4/0a/92c244309b774e290ddb15e93363846ae7aa753d9586b8aad511c5e6145b/librt-0.9.0-cp313-cp313-win_arm64.whl", hash = "sha256:4c4d0440a3a8e31d962340c3e1cc3fc9ee7febd34c8d8f770d06adb947779ea5", size = 53728, upload-time = "2026-04-09T16:05:33.31Z" }, - { url = "https://files.pythonhosted.org/packages/cd/c1/184e539543f06ea2912f4b92a5ffaede4f9b392689e3f00acbf8134bee92/librt-0.9.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:3f05d145df35dca5056a8bc3838e940efebd893a54b3e19b2dda39ceaa299bcb", size = 67830, upload-time = "2026-04-09T16:05:34.517Z" }, - { url = "https://files.pythonhosted.org/packages/f3/ad/23399bdcb7afca819acacdef31b37ee59de261bd66b503a7995c03c4b0dc/librt-0.9.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1c587494461ebd42229d0f1739f3aa34237dd9980623ecf1be8d3bcba79f4499", size = 70280, upload-time = "2026-04-09T16:05:35.649Z" }, - { url = "https://files.pythonhosted.org/packages/9f/0b/4542dc5a2b8772dbf92cafb9194701230157e73c14b017b6961a23598b03/librt-0.9.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b0a2040f801406b93657a70b72fa12311063a319fee72ce98e1524da7200171f", size = 201925, upload-time = "2026-04-09T16:05:36.739Z" }, - { url = "https://files.pythonhosted.org/packages/31/d4/8ee7358b08fd0cfce051ef96695380f09b3c2c11b77c9bfbc367c921cce5/librt-0.9.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f38bc489037eca88d6ebefc9c4d41a4e07c8e8b4de5188a9e6d290273ad7ebb1", size = 212381, upload-time = "2026-04-09T16:05:38.043Z" }, - { url = "https://files.pythonhosted.org/packages/f2/94/a2025fe442abedf8b038038dab3dba942009ad42b38ea064a1a9e6094241/librt-0.9.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3fd278f5e6bf7c75ccd6d12344eb686cc020712683363b66f46ac79d37c799f", size = 227065, upload-time = "2026-04-09T16:05:39.394Z" }, - { url = "https://files.pythonhosted.org/packages/7c/e9/b9fcf6afa909f957cfbbf918802f9dada1bd5d3c1da43d722fd6a310dc3f/librt-0.9.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fcbdf2a9ca24e87bbebb47f1fe34e531ef06f104f98c9ccfc953a3f3344c567a", size = 221333, upload-time = "2026-04-09T16:05:40.999Z" }, - { url = "https://files.pythonhosted.org/packages/ac/7c/ba54cd6aa6a3c8cd12757a6870e0c79a64b1e6327f5248dcff98423f4d43/librt-0.9.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e306d956cfa027fe041585f02a1602c32bfa6bb8ebea4899d373383295a6c62f", size = 229051, upload-time = "2026-04-09T16:05:42.605Z" }, - { url = "https://files.pythonhosted.org/packages/4b/4b/8cfdbad314c8677a0148bf0b70591d6d18587f9884d930276098a235461b/librt-0.9.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:465814ab157986acb9dfa5ccd7df944be5eefc0d08d31ec6e8d88bc71251d845", size = 222492, upload-time = "2026-04-09T16:05:43.842Z" }, - { url = "https://files.pythonhosted.org/packages/1f/d1/2eda69563a1a88706808decdce035e4b32755dbfbb0d05e1a65db9547ed1/librt-0.9.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:703f4ae36d6240bfe24f542bac784c7e4194ec49c3ba5a994d02891649e2d85b", size = 223849, upload-time = "2026-04-09T16:05:45.054Z" }, - { url = "https://files.pythonhosted.org/packages/04/44/b2ed37df6be5b3d42cfe36318e0598e80843d5c6308dd63d0bf4e0ce5028/librt-0.9.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3be322a15ee5e70b93b7a59cfd074614f22cc8c9ff18bd27f474e79137ea8d3b", size = 245001, upload-time = "2026-04-09T16:05:46.34Z" }, - { url = "https://files.pythonhosted.org/packages/47/e7/617e412426df89169dd2a9ed0cc8752d5763336252c65dbf945199915119/librt-0.9.0-cp314-cp314-win32.whl", hash = "sha256:b8da9f8035bb417770b1e1610526d87ad4fc58a2804dc4d79c53f6d2cf5a6eb9", size = 51799, upload-time = "2026-04-09T16:05:47.738Z" }, - { url = "https://files.pythonhosted.org/packages/24/ed/c22ca4db0ca3cbc285e4d9206108746beda561a9792289c3c31281d7e9df/librt-0.9.0-cp314-cp314-win_amd64.whl", hash = "sha256:b8bd70d5d816566a580d193326912f4a76ec2d28a97dc4cd4cc831c0af8e330e", size = 59165, upload-time = "2026-04-09T16:05:49.198Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/875398fafa4cbc8f15b89366fc3287304ddd3314d861f182a4b87595ace0/librt-0.9.0-cp314-cp314-win_arm64.whl", hash = "sha256:fc5758e2b7a56532dc33e3c544d78cbaa9ecf0a0f2a2da2df882c1d6b99a317f", size = 49292, upload-time = "2026-04-09T16:05:50.362Z" }, - { url = "https://files.pythonhosted.org/packages/4c/61/bc448ecbf9b2d69c5cff88fe41496b19ab2a1cbda0065e47d4d0d51c0867/librt-0.9.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:f24b90b0e0c8cc9491fb1693ae91fe17cb7963153a1946395acdbdd5818429a4", size = 70175, upload-time = "2026-04-09T16:05:51.564Z" }, - { url = "https://files.pythonhosted.org/packages/60/f2/c47bb71069a73e2f04e70acbd196c1e5cc411578ac99039a224b98920fd4/librt-0.9.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3fe56e80badb66fdcde06bef81bbaa5bfcf6fbd7aefb86222d9e369c38c6b228", size = 72951, upload-time = "2026-04-09T16:05:52.699Z" }, - { url = "https://files.pythonhosted.org/packages/29/19/0549df59060631732df758e8886d92088da5fdbedb35b80e4643664e8412/librt-0.9.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:527b5b820b47a09e09829051452bb0d1dd2122261254e2a6f674d12f1d793d54", size = 225864, upload-time = "2026-04-09T16:05:53.895Z" }, - { url = "https://files.pythonhosted.org/packages/9d/f8/3b144396d302ac08e50f89e64452c38db84bc7b23f6c60479c5d3abd303c/librt-0.9.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d429bdd4ac0ab17c8e4a8af0ed2a7440b16eba474909ab357131018fe8c7e71", size = 241155, upload-time = "2026-04-09T16:05:55.191Z" }, - { url = "https://files.pythonhosted.org/packages/7a/ce/ee67ec14581de4043e61d05786d2aed6c9b5338816b7859bcf07455c6a9f/librt-0.9.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7202bdcac47d3a708271c4304a474a8605a4a9a4a709e954bf2d3241140aa938", size = 252235, upload-time = "2026-04-09T16:05:56.549Z" }, - { url = "https://files.pythonhosted.org/packages/8a/fa/0ead15daa2b293a54101550b08d4bafe387b7d4a9fc6d2b985602bae69b6/librt-0.9.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0d620e74897f8c2613b3c4e2e9c1e422eb46d2ddd07df540784d44117836af3", size = 244963, upload-time = "2026-04-09T16:05:57.858Z" }, - { url = "https://files.pythonhosted.org/packages/29/68/9fbf9a9aa704ba87689e40017e720aced8d9a4d2b46b82451d8142f91ec9/librt-0.9.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d69fc39e627908f4c03297d5a88d9284b73f4d90b424461e32e8c2485e21c283", size = 257364, upload-time = "2026-04-09T16:05:59.686Z" }, - { url = "https://files.pythonhosted.org/packages/1a/8d/9d60869f1b6716c762e45f66ed945b1e5dd649f7377684c3b176ae424648/librt-0.9.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:c2640e23d2b7c98796f123ffd95cf2022c7777aa8a4a3b98b36c570d37e85eee", size = 247661, upload-time = "2026-04-09T16:06:00.938Z" }, - { url = "https://files.pythonhosted.org/packages/70/ff/a5c365093962310bfdb4f6af256f191085078ffb529b3f0cbebb5b33ebe2/librt-0.9.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:451daa98463b7695b0a30aa56bf637831ea559e7b8101ac2ef6382e8eb15e29c", size = 248238, upload-time = "2026-04-09T16:06:02.537Z" }, - { url = "https://files.pythonhosted.org/packages/a0/3c/2d34365177f412c9e19c0a29f969d70f5343f27634b76b765a54d8b27705/librt-0.9.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:928bd06eca2c2bbf4349e5b817f837509b0604342e65a502de1d50a7570afd15", size = 269457, upload-time = "2026-04-09T16:06:03.833Z" }, - { url = "https://files.pythonhosted.org/packages/bc/cd/de45b239ea3bdf626f982a00c14bfcf2e12d261c510ba7db62c5969a27cd/librt-0.9.0-cp314-cp314t-win32.whl", hash = "sha256:a9c63e04d003bc0fb6a03b348018b9a3002f98268200e22cc80f146beac5dc40", size = 52453, upload-time = "2026-04-09T16:06:05.229Z" }, - { url = "https://files.pythonhosted.org/packages/7f/f9/bfb32ae428aa75c0c533915622176f0a17d6da7b72b5a3c6363685914f70/librt-0.9.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f162af66a2ed3f7d1d161a82ca584efd15acd9c1cff190a373458c32f7d42118", size = 60044, upload-time = "2026-04-09T16:06:06.398Z" }, - { url = "https://files.pythonhosted.org/packages/aa/47/7d70414bcdbb3bc1f458a8d10558f00bbfdb24e5a11740fc8197e12c3255/librt-0.9.0-cp314-cp314t-win_arm64.whl", hash = "sha256:a4b25c6c25cac5d0d9d6d6da855195b254e0021e513e0249f0e3b444dc6e0e61", size = 50009, upload-time = "2026-04-09T16:06:07.995Z" }, ] [[package]] @@ -2519,17 +2056,6 @@ version = "3.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, - { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, - { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, - { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, - { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, - { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, - { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, - { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, - { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, - { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, @@ -2563,28 +2089,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, - { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, - { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, - { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, - { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, - { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, - { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, - { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, - { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, - { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, - { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, - { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, - { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, - { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, - { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, - { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, - { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, - { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, - { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, - { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, - { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, - { 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]] @@ -2604,13 +2108,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269, upload-time = "2025-12-10T22:56:51.155Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/86/de7e3a1cdcfc941483af70609edc06b83e7c8a0e0dc9ac325200a3f4d220/matplotlib-3.10.8-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6be43b667360fef5c754dda5d25a32e6307a03c204f3c0fc5468b78fa87b4160", size = 8251215, upload-time = "2025-12-10T22:55:16.175Z" }, - { url = "https://files.pythonhosted.org/packages/fd/14/baad3222f424b19ce6ad243c71de1ad9ec6b2e4eb1e458a48fdc6d120401/matplotlib-3.10.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2b336e2d91a3d7006864e0990c83b216fcdca64b5a6484912902cef87313d78", size = 8139625, upload-time = "2025-12-10T22:55:17.712Z" }, - { url = "https://files.pythonhosted.org/packages/8f/a0/7024215e95d456de5883e6732e708d8187d9753a21d32f8ddb3befc0c445/matplotlib-3.10.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:efb30e3baaea72ce5928e32bab719ab4770099079d66726a62b11b1ef7273be4", size = 8712614, upload-time = "2025-12-10T22:55:20.8Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f4/b8347351da9a5b3f41e26cf547252d861f685c6867d179a7c9d60ad50189/matplotlib-3.10.8-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d56a1efd5bfd61486c8bc968fa18734464556f0fb8e51690f4ac25d85cbbbbc2", size = 9540997, upload-time = "2025-12-10T22:55:23.258Z" }, - { url = "https://files.pythonhosted.org/packages/9e/c0/c7b914e297efe0bc36917bf216b2acb91044b91e930e878ae12981e461e5/matplotlib-3.10.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:238b7ce5717600615c895050239ec955d91f321c209dd110db988500558e70d6", size = 9596825, upload-time = "2025-12-10T22:55:25.217Z" }, - { url = "https://files.pythonhosted.org/packages/6f/d3/a4bbc01c237ab710a1f22b4da72f4ff6d77eb4c7735ea9811a94ae239067/matplotlib-3.10.8-cp311-cp311-win_amd64.whl", hash = "sha256:18821ace09c763ec93aef5eeff087ee493a24051936d7b9ebcad9662f66501f9", size = 8135090, upload-time = "2025-12-10T22:55:27.162Z" }, - { url = "https://files.pythonhosted.org/packages/89/dd/a0b6588f102beab33ca6f5218b31725216577b2a24172f327eaf6417d5c9/matplotlib-3.10.8-cp311-cp311-win_arm64.whl", hash = "sha256:bab485bcf8b1c7d2060b4fcb6fc368a9e6f4cd754c9c2fea281f4be21df394a2", size = 8012377, upload-time = "2025-12-10T22:55:29.185Z" }, { url = "https://files.pythonhosted.org/packages/9e/67/f997cdcbb514012eb0d10cd2b4b332667997fb5ebe26b8d41d04962fa0e6/matplotlib-3.10.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:64fcc24778ca0404ce0cb7b6b77ae1f4c7231cdd60e6778f999ee05cbd581b9a", size = 8260453, upload-time = "2025-12-10T22:55:30.709Z" }, { url = "https://files.pythonhosted.org/packages/7e/65/07d5f5c7f7c994f12c768708bd2e17a4f01a2b0f44a1c9eccad872433e2e/matplotlib-3.10.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b9a5ca4ac220a0cdd1ba6bcba3608547117d30468fefce49bb26f55c1a3d5c58", size = 8148321, upload-time = "2025-12-10T22:55:33.265Z" }, { url = "https://files.pythonhosted.org/packages/3e/f3/c5195b1ae57ef85339fd7285dfb603b22c8b4e79114bae5f4f0fcf688677/matplotlib-3.10.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3ab4aabc72de4ff77b3ec33a6d78a68227bf1123465887f9905ba79184a1cc04", size = 8716944, upload-time = "2025-12-10T22:55:34.922Z" }, @@ -2632,23 +2129,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c0/3d/8b94a481456dfc9dfe6e39e93b5ab376e50998cddfd23f4ae3b431708f16/matplotlib-3.10.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0a33deb84c15ede243aead39f77e990469fff93ad1521163305095b77b72ce4a", size = 9614000, upload-time = "2025-12-10T22:56:05.411Z" }, { url = "https://files.pythonhosted.org/packages/bd/cd/bc06149fe5585ba800b189a6a654a75f1f127e8aab02fd2be10df7fa500c/matplotlib-3.10.8-cp313-cp313t-win_amd64.whl", hash = "sha256:3a48a78d2786784cc2413e57397981fb45c79e968d99656706018d6e62e57958", size = 8220043, upload-time = "2025-12-10T22:56:07.551Z" }, { url = "https://files.pythonhosted.org/packages/e3/de/b22cf255abec916562cc04eef457c13e58a1990048de0c0c3604d082355e/matplotlib-3.10.8-cp313-cp313t-win_arm64.whl", hash = "sha256:15d30132718972c2c074cd14638c7f4592bd98719e2308bccea40e0538bc0cb5", size = 8062075, upload-time = "2025-12-10T22:56:09.178Z" }, - { url = "https://files.pythonhosted.org/packages/3c/43/9c0ff7a2f11615e516c3b058e1e6e8f9614ddeca53faca06da267c48345d/matplotlib-3.10.8-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b53285e65d4fa4c86399979e956235deb900be5baa7fc1218ea67fbfaeaadd6f", size = 8262481, upload-time = "2025-12-10T22:56:10.885Z" }, - { url = "https://files.pythonhosted.org/packages/6f/ca/e8ae28649fcdf039fda5ef554b40a95f50592a3c47e6f7270c9561c12b07/matplotlib-3.10.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32f8dce744be5569bebe789e46727946041199030db8aeb2954d26013a0eb26b", size = 8151473, upload-time = "2025-12-10T22:56:12.377Z" }, - { url = "https://files.pythonhosted.org/packages/f1/6f/009d129ae70b75e88cbe7e503a12a4c0670e08ed748a902c2568909e9eb5/matplotlib-3.10.8-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4cf267add95b1c88300d96ca837833d4112756045364f5c734a2276038dae27d", size = 9553896, upload-time = "2025-12-10T22:56:14.432Z" }, - { url = "https://files.pythonhosted.org/packages/f5/26/4221a741eb97967bc1fd5e4c52b9aa5a91b2f4ec05b59f6def4d820f9df9/matplotlib-3.10.8-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2cf5bd12cecf46908f286d7838b2abc6c91cda506c0445b8223a7c19a00df008", size = 9824193, upload-time = "2025-12-10T22:56:16.29Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f3/3abf75f38605772cf48a9daf5821cd4f563472f38b4b828c6fba6fa6d06e/matplotlib-3.10.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:41703cc95688f2516b480f7f339d8851a6035f18e100ee6a32bc0b8536a12a9c", size = 9615444, upload-time = "2025-12-10T22:56:18.155Z" }, - { url = "https://files.pythonhosted.org/packages/93/a5/de89ac80f10b8dc615807ee1133cd99ac74082581196d4d9590bea10690d/matplotlib-3.10.8-cp314-cp314-win_amd64.whl", hash = "sha256:83d282364ea9f3e52363da262ce32a09dfe241e4080dcedda3c0db059d3c1f11", size = 8272719, upload-time = "2025-12-10T22:56:20.366Z" }, - { url = "https://files.pythonhosted.org/packages/69/ce/b006495c19ccc0a137b48083168a37bd056392dee02f87dba0472f2797fe/matplotlib-3.10.8-cp314-cp314-win_arm64.whl", hash = "sha256:2c1998e92cd5999e295a731bcb2911c75f597d937341f3030cc24ef2733d78a8", size = 8144205, upload-time = "2025-12-10T22:56:22.239Z" }, - { url = "https://files.pythonhosted.org/packages/68/d9/b31116a3a855bd313c6fcdb7226926d59b041f26061c6c5b1be66a08c826/matplotlib-3.10.8-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b5a2b97dbdc7d4f353ebf343744f1d1f1cca8aa8bfddb4262fcf4306c3761d50", size = 8305785, upload-time = "2025-12-10T22:56:24.218Z" }, - { url = "https://files.pythonhosted.org/packages/1e/90/6effe8103f0272685767ba5f094f453784057072f49b393e3ea178fe70a5/matplotlib-3.10.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3f5c3e4da343bba819f0234186b9004faba952cc420fbc522dc4e103c1985908", size = 8198361, upload-time = "2025-12-10T22:56:26.787Z" }, - { url = "https://files.pythonhosted.org/packages/d7/65/a73188711bea603615fc0baecca1061429ac16940e2385433cc778a9d8e7/matplotlib-3.10.8-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f62550b9a30afde8c1c3ae450e5eb547d579dd69b25c2fc7a1c67f934c1717a", size = 9561357, upload-time = "2025-12-10T22:56:28.953Z" }, - { url = "https://files.pythonhosted.org/packages/f4/3d/b5c5d5d5be8ce63292567f0e2c43dde9953d3ed86ac2de0a72e93c8f07a1/matplotlib-3.10.8-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:495672de149445ec1b772ff2c9ede9b769e3cb4f0d0aa7fa730d7f59e2d4e1c1", size = 9823610, upload-time = "2025-12-10T22:56:31.455Z" }, - { url = "https://files.pythonhosted.org/packages/4d/4b/e7beb6bbd49f6bae727a12b270a2654d13c397576d25bd6786e47033300f/matplotlib-3.10.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:595ba4d8fe983b88f0eec8c26a241e16d6376fe1979086232f481f8f3f67494c", size = 9614011, upload-time = "2025-12-10T22:56:33.85Z" }, - { url = "https://files.pythonhosted.org/packages/7c/e6/76f2813d31f032e65f6f797e3f2f6e4aab95b65015924b1c51370395c28a/matplotlib-3.10.8-cp314-cp314t-win_amd64.whl", hash = "sha256:25d380fe8b1dc32cf8f0b1b448470a77afb195438bafdf1d858bfb876f3edf7b", size = 8362801, upload-time = "2025-12-10T22:56:36.107Z" }, - { url = "https://files.pythonhosted.org/packages/5d/49/d651878698a0b67f23aa28e17f45a6d6dd3d3f933fa29087fa4ce5947b5a/matplotlib-3.10.8-cp314-cp314t-win_arm64.whl", hash = "sha256:113bb52413ea508ce954a02c10ffd0d565f9c3bc7f2eddc27dfe1731e71c7b5f", size = 8192560, upload-time = "2025-12-10T22:56:38.008Z" }, - { url = "https://files.pythonhosted.org/packages/04/30/3afaa31c757f34b7725ab9d2ba8b48b5e89c2019c003e7d0ead143aabc5a/matplotlib-3.10.8-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6da7c2ce169267d0d066adcf63758f0604aa6c3eebf67458930f9d9b79ad1db1", size = 8249198, upload-time = "2025-12-10T22:56:45.584Z" }, - { url = "https://files.pythonhosted.org/packages/48/2f/6334aec331f57485a642a7c8be03cb286f29111ae71c46c38b363230063c/matplotlib-3.10.8-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9153c3292705be9f9c64498a8872118540c3f4123d1a1c840172edf262c8be4a", size = 8136817, upload-time = "2025-12-10T22:56:47.339Z" }, - { url = "https://files.pythonhosted.org/packages/73/e4/6d6f14b2a759c622f191b2d67e9075a3f56aaccb3be4bb9bb6890030d0a0/matplotlib-3.10.8-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ae029229a57cd1e8fe542485f27e7ca7b23aa9e8944ddb4985d0bc444f1eca2", size = 8713867, upload-time = "2025-12-10T22:56:48.954Z" }, ] [[package]] @@ -2955,13 +2435,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/0b/3d/5b373635b3146264eb7a68d09e5ca11c305bbb058dfffbb47c47daf4f632/mypy-1.20.1.tar.gz", hash = "sha256:6fc3f4ecd52de81648fed1945498bf42fa2993ddfad67c9056df36ae5757f804", size = 3815892, upload-time = "2026-04-13T02:46:51.474Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/0d/555ab7453cc4a4a8643b7f21c842b1a84c36b15392061ae7b052ee119320/mypy-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c01eb9bac2c6a962d00f9d23421cd2913840e65bba365167d057bd0b4171a92e", size = 14336012, upload-time = "2026-04-13T02:45:39.935Z" }, - { url = "https://files.pythonhosted.org/packages/57/26/85a28893f7db8a16ebb41d1e9dfcb4475844d06a88480b6639e32a74d6ef/mypy-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:55d12ddbd8a9cac5b276878bd534fa39fff5bf543dc6ae18f25d30c8d7d27fca", size = 13224636, upload-time = "2026-04-13T02:45:49.659Z" }, - { url = "https://files.pythonhosted.org/packages/93/41/bd4cd3c2caeb6c448b669222b8cfcbdee4a03b89431527b56fca9e56b6f3/mypy-1.20.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0aa322c1468b6cdfc927a44ce130f79bb44bcd34eb4a009eb9f96571fd80955", size = 13663471, upload-time = "2026-04-13T02:46:20.276Z" }, - { url = "https://files.pythonhosted.org/packages/3e/56/7ee8c471e10402d64b6517ae10434541baca053cffd81090e4097d5609d4/mypy-1.20.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3f8bc95899cf676b6e2285779a08a998cc3a7b26f1026752df9d2741df3c79e8", size = 14532344, upload-time = "2026-04-13T02:46:44.205Z" }, - { url = "https://files.pythonhosted.org/packages/b5/95/b37d1fa859a433f6156742e12f62b0bb75af658544fb6dada9363918743a/mypy-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:47c2b90191a870a04041e910277494b0d92f0711be9e524d45c074fe60c00b65", size = 14776670, upload-time = "2026-04-13T02:45:52.481Z" }, - { url = "https://files.pythonhosted.org/packages/03/77/b302e4cb0b80d2bdf6bf4fce5864bb4cbfa461f7099cea544eaf2457df78/mypy-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:9857dc8d2ec1a392ffbda518075beb00ac58859979c79f9e6bdcb7277082c2f2", size = 10816524, upload-time = "2026-04-13T02:45:37.711Z" }, - { url = "https://files.pythonhosted.org/packages/7f/21/d969d7a68eb964993ebcc6170d5ecaf0cf65830c58ac3344562e16dc42a9/mypy-1.20.1-cp311-cp311-win_arm64.whl", hash = "sha256:09d8df92bb25b6065ab91b178da843dda67b33eb819321679a6e98a907ce0e10", size = 9750419, upload-time = "2026-04-13T02:45:08.542Z" }, { url = "https://files.pythonhosted.org/packages/69/1b/75a7c825a02781ca10bc2f2f12fba2af5202f6d6005aad8d2d1f264d8d78/mypy-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:36ee2b9c6599c230fea89bbd79f401f9f9f8e9fcf0c777827789b19b7da90f51", size = 14494077, upload-time = "2026-04-13T02:45:55.085Z" }, { url = "https://files.pythonhosted.org/packages/b0/54/5e5a569ea5c2b4d48b729fb32aa936eeb4246e4fc3e6f5b3d36a2dfbefb9/mypy-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fba3fb0968a7b48806b0c90f38d39296f10766885a94c83bd21399de1e14eb28", size = 13319495, upload-time = "2026-04-13T02:45:29.674Z" }, { url = "https://files.pythonhosted.org/packages/6f/a4/a1945b19f33e91721b59deee3abb484f2fa5922adc33bb166daf5325d76d/mypy-1.20.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef1415a637cd3627d6304dfbeddbadd21079dafc2a8a753c477ce4fc0c2af54f", size = 13696948, upload-time = "2026-04-13T02:46:15.006Z" }, @@ -2976,20 +2449,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a1/57/b3779e134e1b7250d05f874252780d0a88c068bc054bcff99ca20a3a2986/mypy-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4bbb0f6b54ce7cc350ef4a770650d15fa70edd99ad5267e227133eda9c94218", size = 14936093, upload-time = "2026-04-13T02:45:32.087Z" }, { url = "https://files.pythonhosted.org/packages/be/33/81b64991b0f3f278c3b55c335888794af190b2d59031a5ad1401bcb69f1e/mypy-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:c3dc20f8ec76eecd77148cdd2f1542ed496e51e185713bf488a414f862deb8f2", size = 10889659, upload-time = "2026-04-13T02:46:02.926Z" }, { url = "https://files.pythonhosted.org/packages/1b/fd/7adcb8053572edf5ef8f3db59599dfeeee3be9cc4c8c97e2d28f66f42ac5/mypy-1.20.1-cp313-cp313-win_arm64.whl", hash = "sha256:a9d62bbac5d6d46718e2b0330b25e6264463ed832722b8f7d4440ff1be3ca895", size = 9815515, upload-time = "2026-04-13T02:46:32.103Z" }, - { url = "https://files.pythonhosted.org/packages/40/cd/db831e84c81d57d4886d99feee14e372f64bbec6a9cb1a88a19e243f2ef5/mypy-1.20.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:12927b9c0ed794daedcf1dab055b6c613d9d5659ac511e8d936d96f19c087d12", size = 14483064, upload-time = "2026-04-13T02:45:26.901Z" }, - { url = "https://files.pythonhosted.org/packages/d5/82/74e62e7097fa67da328ac8ece8de09133448c04d20ddeaeba251a3000f01/mypy-1.20.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:752507dd481e958b2c08fc966d3806c962af5a9433b5bf8f3bdd7175c20e34fe", size = 13335694, upload-time = "2026-04-13T02:46:12.514Z" }, - { url = "https://files.pythonhosted.org/packages/74/c4/97e9a0abe4f3cdbbf4d079cb87a03b786efeccf5bf2b89fe4f96939ab2e6/mypy-1.20.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c614655b5a065e56274c6cbbe405f7cf7e96c0654db7ba39bc680238837f7b08", size = 13726365, upload-time = "2026-04-13T02:45:17.422Z" }, - { url = "https://files.pythonhosted.org/packages/d7/aa/a19d884a8d28fcd3c065776323029f204dbc774e70ec9c85eba228b680de/mypy-1.20.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2c3f6221a76f34d5100c6d35b3ef6b947054123c3f8d6938a4ba00b1308aa572", size = 14693472, upload-time = "2026-04-13T02:46:41.253Z" }, - { url = "https://files.pythonhosted.org/packages/84/44/cc9324bd21cf786592b44bf3b5d224b3923c1230ec9898d508d00241d465/mypy-1.20.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4bdfc06303ac06500af71ea0cdbe995c502b3c9ba32f3f8313523c137a25d1b6", size = 14919266, upload-time = "2026-04-13T02:46:28.37Z" }, - { url = "https://files.pythonhosted.org/packages/6e/dc/779abb25a8c63e8f44bf5a336217fa92790fa17e0c40e0c725d10cb01bbd/mypy-1.20.1-cp314-cp314-win_amd64.whl", hash = "sha256:0131edd7eba289973d1ba1003d1a37c426b85cdef76650cd02da6420898a5eb3", size = 11049713, upload-time = "2026-04-13T02:45:57.673Z" }, - { url = "https://files.pythonhosted.org/packages/28/08/4172be2ad7de9119b5a92ca36abbf641afdc5cb1ef4ae0c3a8182f29674f/mypy-1.20.1-cp314-cp314-win_arm64.whl", hash = "sha256:33f02904feb2c07e1fdf7909026206396c9deeb9e6f34d466b4cfedb0aadbbe4", size = 9999819, upload-time = "2026-04-13T02:46:35.039Z" }, - { url = "https://files.pythonhosted.org/packages/2d/af/af9e46b0c8eabbce9fc04a477564170f47a1c22b308822282a59b7ff315f/mypy-1.20.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:168472149dd8cc505c98cefd21ad77e4257ed6022cd5ed2fe2999bed56977a5a", size = 15547508, upload-time = "2026-04-13T02:46:25.588Z" }, - { url = "https://files.pythonhosted.org/packages/a7/cd/39c9e4ad6ba33e069e5837d772a9e6c304b4a5452a14a975d52b36444650/mypy-1.20.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:eb674600309a8f22790cca883a97c90299f948183ebb210fbef6bcee07cb1986", size = 14399557, upload-time = "2026-04-13T02:46:10.021Z" }, - { url = "https://files.pythonhosted.org/packages/83/c1/3fd71bdc118ffc502bf57559c909927bb7e011f327f7bb8e0488e98a5870/mypy-1.20.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef2b2e4cc464ba9795459f2586923abd58a0055487cbe558cb538ea6e6bc142a", size = 15045789, upload-time = "2026-04-13T02:45:10.81Z" }, - { url = "https://files.pythonhosted.org/packages/8e/73/6f07ff8b57a7d7b3e6e5bf34685d17632382395c8bb53364ec331661f83e/mypy-1.20.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dee461d396dd46b3f0ed5a098dbc9b8860c81c46ad44fa071afcfbc149f167c9", size = 15850795, upload-time = "2026-04-13T02:45:03.349Z" }, - { url = "https://files.pythonhosted.org/packages/ec/e2/f7dffec1c7767078f9e9adf0c786d1fe0ff30964a77eb213c09b8b58cb76/mypy-1.20.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e364926308b3e66f1361f81a566fc1b2f8cd47fc8525e8136d4058a65a4b4f02", size = 16088539, upload-time = "2026-04-13T02:46:17.841Z" }, - { url = "https://files.pythonhosted.org/packages/1a/76/e0dee71035316e75a69d73aec2f03c39c21c967b97e277fd0ef8fd6aec66/mypy-1.20.1-cp314-cp314t-win_amd64.whl", hash = "sha256:a0c17fbd746d38c70cbc42647cfd884f845a9708a4b160a8b4f7e70d41f4d7fa", size = 12575567, upload-time = "2026-04-13T02:45:34.795Z" }, - { url = "https://files.pythonhosted.org/packages/22/a8/7ed43c9d9c3d1468f86605e323a5d97e411a448790a00f07e779f3211a46/mypy-1.20.1-cp314-cp314t-win_arm64.whl", hash = "sha256:db2cb89654626a912efda69c0d5c1d22d948265e2069010d3dde3abf751c7d08", size = 10378823, upload-time = "2026-04-13T02:45:13.35Z" }, { url = "https://files.pythonhosted.org/packages/d8/28/926bd972388e65a39ee98e188ccf67e81beb3aacfd5d6b310051772d974b/mypy-1.20.1-py3-none-any.whl", hash = "sha256:1aae28507f253fe82d883790d1c0a0d35798a810117c88184097fe8881052f06", size = 2636553, upload-time = "2026-04-13T02:46:30.45Z" }, ] @@ -3108,16 +2567,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/7a/a8d32501bb95ecff342004a674720164f95ad616f269450b3bc13dc88ae3/netcdf4-1.7.4-cp311-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a72c9f58767779ec14cb7451c3b56bdd8fdc027a792fac2062b14e090c5617f3", size = 10123122, upload-time = "2026-01-05T21:31:22.773Z" }, { url = "https://files.pythonhosted.org/packages/18/68/e89b4fa9242e59326c849c39ce0f49eb68499603c639405a8449900a4f15/netcdf4-1.7.4-cp311-abi3-win_amd64.whl", hash = "sha256:9476e1f23161ae5159cd1548c50c8a37922e77d76583e247133f256ef7b825fc", size = 21299637, upload-time = "2026-01-05T02:27:11.856Z" }, { url = "https://files.pythonhosted.org/packages/6c/fc/edd41a3607241027aa4533e7f18e0cd647e74dde10a63274c65350f59967/netcdf4-1.7.4-cp311-abi3-win_arm64.whl", hash = "sha256:876ad9d58f09c98741c066c726164c45a098a58fb90e5fac9e74de4bb8a793fd", size = 2386377, upload-time = "2026-01-05T02:27:13.808Z" }, - { url = "https://files.pythonhosted.org/packages/f1/3e/1e83534ba68459bc5ae39df46fa71003984df58aabf31f7dcd6e22ecddb0/netcdf4-1.7.4-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56688c03444fffe0d0c7512cb45245e650389cd841c955b30e4552fa681c4cd9", size = 10519821, upload-time = "2026-01-05T02:27:15.413Z" }, - { url = "https://files.pythonhosted.org/packages/c0/8c/a15d6fe97f81d6d5202b17838a9a298b5955b3e9971e20609195112829b5/netcdf4-1.7.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ecf471ba8a6ddb2200121949bedfa0095db228822f38227d5da680694a38358", size = 10371133, upload-time = "2026-01-05T02:27:17.224Z" }, - { url = "https://files.pythonhosted.org/packages/d8/2b/684b15dd4791f8be295b2f6fa97377bbc07a768478a63b7d3c4951712e36/netcdf4-1.7.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5841de0735e8e4875b367c668e81d334287858d64dd9f3e3e2261e808c84922", size = 10395635, upload-time = "2026-01-05T02:27:19.655Z" }, - { url = "https://files.pythonhosted.org/packages/37/dc/44d21524cf1b1c64254f92e22395a7a10f70c18f3a13a18ac9db258760f7/netcdf4-1.7.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86fac03a8c5b250d57866e7d98918a64742e4b0de1681c5c86bac5726bab8aee", size = 10237725, upload-time = "2026-01-05T02:27:22.298Z" }, - { url = "https://files.pythonhosted.org/packages/d4/9d/c3ddf54296ad8f18f02f77f23452bdb0971aece1b87e84bab9d734bf72cc/netcdf4-1.7.4-cp314-cp314t-macosx_13_0_x86_64.whl", hash = "sha256:ad083d260301b5add74b1669c75ab0df03bdf986decfcc092cb45eec2615b5f1", size = 23515258, upload-time = "2026-01-05T02:27:24.837Z" }, - { url = "https://files.pythonhosted.org/packages/dd/44/bc0346e995d436d03fab682b7fbd2a9adcf0db6a05790b8f24853bf08170/netcdf4-1.7.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:7f22014092cc9da3f056b0368e2e38c42afd5725c87ad4843eb2f467e16dd4f6", size = 22910171, upload-time = "2026-01-05T02:27:27.166Z" }, - { url = "https://files.pythonhosted.org/packages/30/6b/f9bc3f43c55e2dac72ee9f98d77860789bdd5d50c29adf164a6bdb303078/netcdf4-1.7.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:224a15434c165a5e0225e5831f591edf62533044b1ce62fdfee815195bbd077d", size = 10567579, upload-time = "2026-01-05T02:27:29.382Z" }, - { url = "https://files.pythonhosted.org/packages/6d/d5/e7685c66b7f011c73cd746127f986358a26c642a4e4a1aa5ab51481b6586/netcdf4-1.7.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31a2318305de6831a18df25ad0df9f03b6d68666af0356d4f6057d66c02ffeb6", size = 10255032, upload-time = "2026-01-05T02:27:31.744Z" }, - { url = "https://files.pythonhosted.org/packages/a6/14/7506738bb6c8bc373b01e5af8f3b727f83f4f496c6b108490ea2609dc2cf/netcdf4-1.7.4-cp314-cp314t-win_amd64.whl", hash = "sha256:6c4a0aa9446c3a616ef3be015b629dc6173643f8b09546de26a4e40e272cd1ed", size = 22289653, upload-time = "2026-01-05T02:27:34.294Z" }, - { url = "https://files.pythonhosted.org/packages/af/2e/39d5e9179c543f2e6e149a65908f83afd9b6d64379a90789b323111761db/netcdf4-1.7.4-cp314-cp314t-win_arm64.whl", hash = "sha256:034220887d48da032cb2db5958f69759dbb04eb33e279ec6390571d4aea734fe", size = 2531682, upload-time = "2026-01-05T02:27:37.062Z" }, ] [[package]] @@ -3184,14 +2633,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/cb/2f/fdba158c9dbe5caca9c3eca3eaffffb251f2fb8674bf8e2d0aed5f38d319/numexpr-2.14.1.tar.gz", hash = "sha256:4be00b1086c7b7a5c32e31558122b7b80243fe098579b170967da83f3152b48b", size = 119400, upload-time = "2025-10-13T16:17:27.351Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b2/a3/67999bdd1ed1f938d38f3fedd4969632f2f197b090e50505f7cc1fa82510/numexpr-2.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d03fcb4644a12f70a14d74006f72662824da5b6128bf1bcd10cc3ed80e64c34", size = 163195, upload-time = "2025-10-13T16:16:31.212Z" }, - { url = "https://files.pythonhosted.org/packages/25/95/d64f680ea1fc56d165457287e0851d6708800f9fcea346fc1b9957942ee6/numexpr-2.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2773ee1133f77009a1fc2f34fe236f3d9823779f5f75450e183137d49f00499f", size = 152088, upload-time = "2025-10-13T16:16:33.186Z" }, - { url = "https://files.pythonhosted.org/packages/0e/7f/3bae417cb13ae08afd86d08bb0301c32440fe0cae4e6262b530e0819aeda/numexpr-2.14.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ebe4980f9494b9f94d10d2e526edc29e72516698d3bf95670ba79415492212a4", size = 451126, upload-time = "2025-10-13T16:13:22.248Z" }, - { url = "https://files.pythonhosted.org/packages/4c/1a/edbe839109518364ac0bd9e918cf874c755bb2c128040e920f198c494263/numexpr-2.14.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a381e5e919a745c9503bcefffc1c7f98c972c04ec58fc8e999ed1a929e01ba6", size = 442012, upload-time = "2025-10-13T16:14:51.416Z" }, - { url = "https://files.pythonhosted.org/packages/66/b1/be4ce99bff769a5003baddac103f34681997b31d4640d5a75c0e8ed59c78/numexpr-2.14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d08856cfc1b440eb1caaa60515235369654321995dd68eb9377577392020f6cb", size = 1415975, upload-time = "2025-10-13T16:13:26.088Z" }, - { url = "https://files.pythonhosted.org/packages/e7/33/b33b8fdc032a05d9ebb44a51bfcd4b92c178a2572cd3e6c1b03d8a4b45b2/numexpr-2.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03130afa04edf83a7b590d207444f05a00363c9b9ea5d81c0f53b1ea13fad55a", size = 1464683, upload-time = "2025-10-13T16:14:58.87Z" }, - { url = "https://files.pythonhosted.org/packages/d0/b2/ddcf0ac6cf0a1d605e5aecd4281507fd79a9628a67896795ab2e975de5df/numexpr-2.14.1-cp311-cp311-win32.whl", hash = "sha256:db78fa0c9fcbaded3ae7453faf060bd7a18b0dc10299d7fcd02d9362be1213ed", size = 166838, upload-time = "2025-10-13T16:17:06.765Z" }, - { url = "https://files.pythonhosted.org/packages/64/72/4ca9bd97b2eb6dce9f5e70a3b6acec1a93e1fb9b079cb4cba2cdfbbf295d/numexpr-2.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:e9b2f957798c67a2428be96b04bce85439bed05efe78eb78e4c2ca43737578e7", size = 160069, upload-time = "2025-10-13T16:17:08.752Z" }, { url = "https://files.pythonhosted.org/packages/9d/20/c473fc04a371f5e2f8c5749e04505c13e7a8ede27c09e9f099b2ad6f43d6/numexpr-2.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ebae0ab18c799b0e6b8c5a8d11e1fa3848eb4011271d99848b297468a39430", size = 162790, upload-time = "2025-10-13T16:16:34.903Z" }, { url = "https://files.pythonhosted.org/packages/45/93/b6760dd1904c2a498e5f43d1bb436f59383c3ddea3815f1461dfaa259373/numexpr-2.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:47041f2f7b9e69498fb311af672ba914a60e6e6d804011caacb17d66f639e659", size = 152196, upload-time = "2025-10-13T16:16:36.593Z" }, { url = "https://files.pythonhosted.org/packages/72/94/cc921e35593b820521e464cbbeaf8212bbdb07f16dc79fe283168df38195/numexpr-2.14.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d686dfb2c1382d9e6e0ee0b7647f943c1886dba3adbf606c625479f35f1956c1", size = 452468, upload-time = "2025-10-13T16:13:29.531Z" }, @@ -3216,22 +2657,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1e/ce/0d4fcd31ab49319740d934fba1734d7dad13aa485532ca754e555ca16c8b/numexpr-2.14.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:67ea4771029ce818573b1998f5ca416bd255156feea017841b86176a938f7d19", size = 1474214, upload-time = "2025-10-13T16:15:38.893Z" }, { url = "https://files.pythonhosted.org/packages/b7/47/b2a93cbdb3ba4e009728ad1b9ef1550e2655ea2c86958ebaf03b9615f275/numexpr-2.14.1-cp313-cp313t-win32.whl", hash = "sha256:15015d47d3d1487072d58c0e7682ef2eb608321e14099c39d52e2dd689483611", size = 167676, upload-time = "2025-10-13T16:17:17.351Z" }, { url = "https://files.pythonhosted.org/packages/86/99/ee3accc589ed032eea68e12172515ed96a5568534c213ad109e1f4411df1/numexpr-2.14.1-cp313-cp313t-win_amd64.whl", hash = "sha256:94c711f6d8f17dfb4606842b403699603aa591ab9f6bf23038b488ea9cfb0f09", size = 161096, upload-time = "2025-10-13T16:17:19.174Z" }, - { url = "https://files.pythonhosted.org/packages/ac/36/9db78dfbfdfa1f8bf0872993f1a334cdd8fca5a5b6567e47dcb128bcb7c2/numexpr-2.14.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ede79f7ff06629f599081de644546ce7324f1581c09b0ac174da88a470d39c21", size = 162848, upload-time = "2025-10-13T16:16:46.216Z" }, - { url = "https://files.pythonhosted.org/packages/13/c1/a5c78ae637402c5550e2e0ba175275d2515d432ec28af0cdc23c9b476e65/numexpr-2.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2eac7a5a2f70b3768c67056445d1ceb4ecd9b853c8eda9563823b551aeaa5082", size = 152270, upload-time = "2025-10-13T16:16:47.92Z" }, - { url = "https://files.pythonhosted.org/packages/9a/ed/aabd8678077848dd9a751c5558c2057839f5a09e2a176d8dfcd0850ee00e/numexpr-2.14.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5aedf38d4c0c19d3cecfe0334c3f4099fb496f54c146223d30fa930084bc8574", size = 455918, upload-time = "2025-10-13T16:13:50.338Z" }, - { url = "https://files.pythonhosted.org/packages/88/e1/3db65117f02cdefb0e5e4c440daf1c30beb45051b7f47aded25b7f4f2f34/numexpr-2.14.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439ec4d57b853792ebe5456e3160312281c3a7071ecac5532ded3278ede614de", size = 446512, upload-time = "2025-10-13T16:15:42.313Z" }, - { url = "https://files.pythonhosted.org/packages/9a/fb/7ceb9ee55b5f67e4a3e4d73d5af4c7e37e3c9f37f54bee90361b64b17e3f/numexpr-2.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e23b87f744e04e302d82ac5e2189ae20a533566aec76a46885376e20b0645bf8", size = 1417845, upload-time = "2025-10-13T16:13:53.836Z" }, - { url = "https://files.pythonhosted.org/packages/45/2d/9b5764d0eafbbb2889288f80de773791358acf6fad1a55767538d8b79599/numexpr-2.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:44f84e0e5af219dbb62a081606156420815890e041b87252fbcea5df55214c4c", size = 1466211, upload-time = "2025-10-13T16:15:48.985Z" }, - { url = "https://files.pythonhosted.org/packages/5d/21/204db708eccd71aa8bc55bcad55bc0fc6c5a4e01ad78e14ee5714a749386/numexpr-2.14.1-cp314-cp314-win32.whl", hash = "sha256:1f1a5e817c534539351aa75d26088e9e1e0ef1b3a6ab484047618a652ccc4fc3", size = 168835, upload-time = "2025-10-13T16:17:20.82Z" }, - { url = "https://files.pythonhosted.org/packages/4f/3e/d83e9401a1c3449a124f7d4b3fb44084798e0d30f7c11e60712d9b94cf11/numexpr-2.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:587c41509bc373dfb1fe6086ba55a73147297247bedb6d588cda69169fc412f2", size = 162608, upload-time = "2025-10-13T16:17:22.228Z" }, - { url = "https://files.pythonhosted.org/packages/7f/d6/ec947806bb57836d6379a8c8a253c2aeaa602b12fef2336bfd2462bb4ed5/numexpr-2.14.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ec368819502b64f190c3f71be14a304780b5935c42aae5bf22c27cc2cbba70b5", size = 163525, upload-time = "2025-10-13T16:16:50.133Z" }, - { url = "https://files.pythonhosted.org/packages/0d/77/048f30dcf661a3d52963a88c29b52b6d5ce996d38e9313a56a922451c1e0/numexpr-2.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7e87f6d203ac57239de32261c941e9748f9309cbc0da6295eabd0c438b920d3a", size = 152917, upload-time = "2025-10-13T16:16:52.055Z" }, - { url = "https://files.pythonhosted.org/packages/9e/d3/956a13e628d722d649fbf2fded615134a308c082e122a48bad0e90a99ce9/numexpr-2.14.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dd72d8c2a165fe45ea7650b16eb8cc1792a94a722022006bb97c86fe51fd2091", size = 466242, upload-time = "2025-10-13T16:13:55.795Z" }, - { url = "https://files.pythonhosted.org/packages/d6/dd/abe848678d82486940892f2cacf39e82eec790e8930d4d713d3f9191063b/numexpr-2.14.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70d80fcb418a54ca208e9a38e58ddc425c07f66485176b261d9a67c7f2864f73", size = 457149, upload-time = "2025-10-13T16:15:52.036Z" }, - { url = "https://files.pythonhosted.org/packages/fd/bb/797b583b5fb9da5700a5708ca6eb4f889c94d81abb28de4d642c0f4b3258/numexpr-2.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:edea2f20c2040df8b54ee8ca8ebda63de9545b2112872466118e9df4d0ae99f3", size = 1426493, upload-time = "2025-10-13T16:13:59.244Z" }, - { url = "https://files.pythonhosted.org/packages/77/c4/0519ab028fdc35e3e7ee700def7f2b4631b175cd9e1202bd7966c1695c33/numexpr-2.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:790447be6879a6c51b9545f79612d24c9ea0a41d537a84e15e6a8ddef0b6268e", size = 1474413, upload-time = "2025-10-13T16:15:59.211Z" }, - { url = "https://files.pythonhosted.org/packages/d4/4a/33044878c8f4a75213cfe9c11d4c02058bb710a7a063fe14f362e8de1077/numexpr-2.14.1-cp314-cp314t-win32.whl", hash = "sha256:538961096c2300ea44240209181e31fae82759d26b51713b589332b9f2a4117e", size = 169502, upload-time = "2025-10-13T16:17:23.829Z" }, - { url = "https://files.pythonhosted.org/packages/41/a2/5a1a2c72528b429337f49911b18c302ecd36eeab00f409147e1aa4ae4519/numexpr-2.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:a40b350cd45b4446076fa11843fa32bbe07024747aeddf6d467290bf9011b392", size = 163589, upload-time = "2025-10-13T16:17:25.696Z" }, ] [[package]] @@ -3240,17 +2665,6 @@ version = "2.4.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d7/9f/b8cef5bffa569759033adda9481211426f12f53299629b410340795c2514/numpy-2.4.4.tar.gz", hash = "sha256:2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0", size = 20731587, upload-time = "2026-03-29T13:22:01.298Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/c6/4218570d8c8ecc9704b5157a3348e486e84ef4be0ed3e38218ab473c83d2/numpy-2.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f983334aea213c99992053ede6168500e5f086ce74fbc4acc3f2b00f5762e9db", size = 16976799, upload-time = "2026-03-29T13:18:15.438Z" }, - { url = "https://files.pythonhosted.org/packages/dd/92/b4d922c4a5f5dab9ed44e6153908a5c665b71acf183a83b93b690996e39b/numpy-2.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:72944b19f2324114e9dc86a159787333b77874143efcf89a5167ef83cfee8af0", size = 14971552, upload-time = "2026-03-29T13:18:18.606Z" }, - { url = "https://files.pythonhosted.org/packages/8a/dc/df98c095978fa6ee7b9a9387d1d58cbb3d232d0e69ad169a4ce784bde4fd/numpy-2.4.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:86b6f55f5a352b48d7fbfd2dbc3d5b780b2d79f4d3c121f33eb6efb22e9a2015", size = 5476566, upload-time = "2026-03-29T13:18:21.532Z" }, - { url = "https://files.pythonhosted.org/packages/28/34/b3fdcec6e725409223dd27356bdf5a3c2cc2282e428218ecc9cb7acc9763/numpy-2.4.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:ba1f4fc670ed79f876f70082eff4f9583c15fb9a4b89d6188412de4d18ae2f40", size = 6806482, upload-time = "2026-03-29T13:18:23.634Z" }, - { url = "https://files.pythonhosted.org/packages/68/62/63417c13aa35d57bee1337c67446761dc25ea6543130cf868eace6e8157b/numpy-2.4.4-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a87ec22c87be071b6bdbd27920b129b94f2fc964358ce38f3822635a3e2e03d", size = 15973376, upload-time = "2026-03-29T13:18:26.677Z" }, - { url = "https://files.pythonhosted.org/packages/cf/c5/9fcb7e0e69cef59cf10c746b84f7d58b08bc66a6b7d459783c5a4f6101a6/numpy-2.4.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df3775294accfdd75f32c74ae39fcba920c9a378a2fc18a12b6820aa8c1fb502", size = 16925137, upload-time = "2026-03-29T13:18:30.14Z" }, - { url = "https://files.pythonhosted.org/packages/7e/43/80020edacb3f84b9efdd1591120a4296462c23fd8db0dde1666f6ef66f13/numpy-2.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d4e437e295f18ec29bc79daf55e8a47a9113df44d66f702f02a293d93a2d6dd", size = 17329414, upload-time = "2026-03-29T13:18:33.733Z" }, - { url = "https://files.pythonhosted.org/packages/fd/06/af0658593b18a5f73532d377188b964f239eb0894e664a6c12f484472f97/numpy-2.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6aa3236c78803afbcb255045fbef97a9e25a1f6c9888357d205ddc42f4d6eba5", size = 18658397, upload-time = "2026-03-29T13:18:37.511Z" }, - { url = "https://files.pythonhosted.org/packages/e6/ce/13a09ed65f5d0ce5c7dd0669250374c6e379910f97af2c08c57b0608eee4/numpy-2.4.4-cp311-cp311-win32.whl", hash = "sha256:30caa73029a225b2d40d9fae193e008e24b2026b7ee1a867b7ee8d96ca1a448e", size = 6239499, upload-time = "2026-03-29T13:18:40.372Z" }, - { url = "https://files.pythonhosted.org/packages/bd/63/05d193dbb4b5eec1eca73822d80da98b511f8328ad4ae3ca4caf0f4db91d/numpy-2.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:6bbe4eb67390b0a0265a2c25458f6b90a409d5d069f1041e6aff1e27e3d9a79e", size = 12614257, upload-time = "2026-03-29T13:18:42.95Z" }, - { url = "https://files.pythonhosted.org/packages/87/c5/8168052f080c26fa984c413305012be54741c9d0d74abd7fbeeccae3889f/numpy-2.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:fcfe2045fd2e8f3cb0ce9d4ba6dba6333b8fa05bb8a4939c908cd43322d14c7e", size = 10486775, upload-time = "2026-03-29T13:18:45.835Z" }, { url = "https://files.pythonhosted.org/packages/28/05/32396bec30fb2263770ee910142f49c1476d08e8ad41abf8403806b520ce/numpy-2.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15716cfef24d3a9762e3acdf87e27f58dc823d1348f765bbea6bef8c639bfa1b", size = 16689272, upload-time = "2026-03-29T13:18:49.223Z" }, { url = "https://files.pythonhosted.org/packages/c5/f3/a983d28637bfcd763a9c7aafdb6d5c0ebf3d487d1e1459ffdb57e2f01117/numpy-2.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23cbfd4c17357c81021f21540da84ee282b9c8fba38a03b7b9d09ba6b951421e", size = 14699573, upload-time = "2026-03-29T13:18:52.629Z" }, { url = "https://files.pythonhosted.org/packages/9b/fd/e5ecca1e78c05106d98028114f5c00d3eddb41207686b2b7de3e477b0e22/numpy-2.4.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8b3b60bb7cba2c8c81837661c488637eee696f59a877788a396d33150c35d842", size = 5204782, upload-time = "2026-03-29T13:18:55.579Z" }, @@ -3283,43 +2697,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c2/c9/fcfd5d0639222c6eac7f304829b04892ef51c96a75d479214d77e3ce6e33/numpy-2.4.4-cp313-cp313t-win32.whl", hash = "sha256:9c585a1790d5436a5374bac930dad6ed244c046ed91b2b2a3634eb2971d21008", size = 6083477, upload-time = "2026-03-29T13:20:20.195Z" }, { url = "https://files.pythonhosted.org/packages/d5/e3/3938a61d1c538aaec8ed6fd6323f57b0c2d2d2219512434c5c878db76553/numpy-2.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:93e15038125dc1e5345d9b5b68aa7f996ec33b98118d18c6ca0d0b7d6198b7e8", size = 12457487, upload-time = "2026-03-29T13:20:22.946Z" }, { url = "https://files.pythonhosted.org/packages/97/6a/7e345032cc60501721ef94e0e30b60f6b0bd601f9174ebd36389a2b86d40/numpy-2.4.4-cp313-cp313t-win_arm64.whl", hash = "sha256:0dfd3f9d3adbe2920b68b5cd3d51444e13a10792ec7154cd0a2f6e74d4ab3233", size = 10292002, upload-time = "2026-03-29T13:20:25.909Z" }, - { url = "https://files.pythonhosted.org/packages/6e/06/c54062f85f673dd5c04cbe2f14c3acb8c8b95e3384869bb8cc9bff8cb9df/numpy-2.4.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f169b9a863d34f5d11b8698ead99febeaa17a13ca044961aa8e2662a6c7766a0", size = 16684353, upload-time = "2026-03-29T13:20:29.504Z" }, - { url = "https://files.pythonhosted.org/packages/4c/39/8a320264a84404c74cc7e79715de85d6130fa07a0898f67fb5cd5bd79908/numpy-2.4.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2483e4584a1cb3092da4470b38866634bafb223cbcd551ee047633fd2584599a", size = 14704914, upload-time = "2026-03-29T13:20:33.547Z" }, - { url = "https://files.pythonhosted.org/packages/91/fb/287076b2614e1d1044235f50f03748f31fa287e3dbe6abeb35cdfa351eca/numpy-2.4.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:2d19e6e2095506d1736b7d80595e0f252d76b89f5e715c35e06e937679ea7d7a", size = 5210005, upload-time = "2026-03-29T13:20:36.45Z" }, - { url = "https://files.pythonhosted.org/packages/63/eb/fcc338595309910de6ecabfcef2419a9ce24399680bfb149421fa2df1280/numpy-2.4.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:6a246d5914aa1c820c9443ddcee9c02bec3e203b0c080349533fae17727dfd1b", size = 6544974, upload-time = "2026-03-29T13:20:39.014Z" }, - { url = "https://files.pythonhosted.org/packages/44/5d/e7e9044032a716cdfaa3fba27a8e874bf1c5f1912a1ddd4ed071bf8a14a6/numpy-2.4.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:989824e9faf85f96ec9c7761cd8d29c531ad857bfa1daa930cba85baaecf1a9a", size = 15684591, upload-time = "2026-03-29T13:20:42.146Z" }, - { url = "https://files.pythonhosted.org/packages/98/7c/21252050676612625449b4807d6b695b9ce8a7c9e1c197ee6216c8a65c7c/numpy-2.4.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:27a8d92cd10f1382a67d7cf4db7ce18341b66438bdd9f691d7b0e48d104c2a9d", size = 16637700, upload-time = "2026-03-29T13:20:46.204Z" }, - { url = "https://files.pythonhosted.org/packages/b1/29/56d2bbef9465db24ef25393383d761a1af4f446a1df9b8cded4fe3a5a5d7/numpy-2.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e44319a2953c738205bf3354537979eaa3998ed673395b964c1176083dd46252", size = 17035781, upload-time = "2026-03-29T13:20:50.242Z" }, - { url = "https://files.pythonhosted.org/packages/e3/2b/a35a6d7589d21f44cea7d0a98de5ddcbb3d421b2622a5c96b1edf18707c3/numpy-2.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e892aff75639bbef0d2a2cfd55535510df26ff92f63c92cd84ef8d4ba5a5557f", size = 18362959, upload-time = "2026-03-29T13:20:54.019Z" }, - { url = "https://files.pythonhosted.org/packages/64/c9/d52ec581f2390e0f5f85cbfd80fb83d965fc15e9f0e1aec2195faa142cde/numpy-2.4.4-cp314-cp314-win32.whl", hash = "sha256:1378871da56ca8943c2ba674530924bb8ca40cd228358a3b5f302ad60cf875fc", size = 6008768, upload-time = "2026-03-29T13:20:56.912Z" }, - { url = "https://files.pythonhosted.org/packages/fa/22/4cc31a62a6c7b74a8730e31a4274c5dc80e005751e277a2ce38e675e4923/numpy-2.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:715d1c092715954784bc79e1174fc2a90093dc4dc84ea15eb14dad8abdcdeb74", size = 12449181, upload-time = "2026-03-29T13:20:59.548Z" }, - { url = "https://files.pythonhosted.org/packages/70/2e/14cda6f4d8e396c612d1bf97f22958e92148801d7e4f110cabebdc0eef4b/numpy-2.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:2c194dd721e54ecad9ad387c1d35e63dce5c4450c6dc7dd5611283dda239aabb", size = 10496035, upload-time = "2026-03-29T13:21:02.524Z" }, - { url = "https://files.pythonhosted.org/packages/b1/e8/8fed8c8d848d7ecea092dc3469643f9d10bc3a134a815a3b033da1d2039b/numpy-2.4.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2aa0613a5177c264ff5921051a5719d20095ea586ca88cc802c5c218d1c67d3e", size = 14824958, upload-time = "2026-03-29T13:21:05.671Z" }, - { url = "https://files.pythonhosted.org/packages/05/1a/d8007a5138c179c2bf33ef44503e83d70434d2642877ee8fbb230e7c0548/numpy-2.4.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:42c16925aa5a02362f986765f9ebabf20de75cdefdca827d14315c568dcab113", size = 5330020, upload-time = "2026-03-29T13:21:08.635Z" }, - { url = "https://files.pythonhosted.org/packages/99/64/ffb99ac6ae93faf117bcbd5c7ba48a7f45364a33e8e458545d3633615dda/numpy-2.4.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:874f200b2a981c647340f841730fc3a2b54c9d940566a3c4149099591e2c4c3d", size = 6650758, upload-time = "2026-03-29T13:21:10.949Z" }, - { url = "https://files.pythonhosted.org/packages/6e/6e/795cc078b78a384052e73b2f6281ff7a700e9bf53bcce2ee579d4f6dd879/numpy-2.4.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9b39d38a9bd2ae1becd7eac1303d031c5c110ad31f2b319c6e7d98b135c934d", size = 15729948, upload-time = "2026-03-29T13:21:14.047Z" }, - { url = "https://files.pythonhosted.org/packages/5f/86/2acbda8cc2af5f3d7bfc791192863b9e3e19674da7b5e533fded124d1299/numpy-2.4.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b268594bccac7d7cf5844c7732e3f20c50921d94e36d7ec9b79e9857694b1b2f", size = 16679325, upload-time = "2026-03-29T13:21:17.561Z" }, - { url = "https://files.pythonhosted.org/packages/bc/59/cafd83018f4aa55e0ac6fa92aa066c0a1877b77a615ceff1711c260ffae8/numpy-2.4.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ac6b31e35612a26483e20750126d30d0941f949426974cace8e6b5c58a3657b0", size = 17084883, upload-time = "2026-03-29T13:21:21.106Z" }, - { url = "https://files.pythonhosted.org/packages/f0/85/a42548db84e65ece46ab2caea3d3f78b416a47af387fcbb47ec28e660dc2/numpy-2.4.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8e3ed142f2728df44263aaf5fb1f5b0b99f4070c553a0d7f033be65338329150", size = 18403474, upload-time = "2026-03-29T13:21:24.828Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ad/483d9e262f4b831000062e5d8a45e342166ec8aaa1195264982bca267e62/numpy-2.4.4-cp314-cp314t-win32.whl", hash = "sha256:dddbbd259598d7240b18c9d87c56a9d2fb3b02fe266f49a7c101532e78c1d871", size = 6155500, upload-time = "2026-03-29T13:21:28.205Z" }, - { url = "https://files.pythonhosted.org/packages/c7/03/2fc4e14c7bd4ff2964b74ba90ecb8552540b6315f201df70f137faa5c589/numpy-2.4.4-cp314-cp314t-win_amd64.whl", hash = "sha256:a7164afb23be6e37ad90b2f10426149fd75aee07ca55653d2aa41e66c4ef697e", size = 12637755, upload-time = "2026-03-29T13:21:31.107Z" }, - { url = "https://files.pythonhosted.org/packages/58/78/548fb8e07b1a341746bfbecb32f2c268470f45fa028aacdbd10d9bc73aab/numpy-2.4.4-cp314-cp314t-win_arm64.whl", hash = "sha256:ba203255017337d39f89bdd58417f03c4426f12beed0440cfd933cb15f8669c7", size = 10566643, upload-time = "2026-03-29T13:21:34.339Z" }, - { url = "https://files.pythonhosted.org/packages/6b/33/8fae8f964a4f63ed528264ddf25d2b683d0b663e3cba26961eb838a7c1bd/numpy-2.4.4-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:58c8b5929fcb8287cbd6f0a3fae19c6e03a5c48402ae792962ac465224a629a4", size = 16854491, upload-time = "2026-03-29T13:21:38.03Z" }, - { url = "https://files.pythonhosted.org/packages/bc/d0/1aabee441380b981cf8cdda3ae7a46aa827d1b5a8cce84d14598bc94d6d9/numpy-2.4.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:eea7ac5d2dce4189771cedb559c738a71512768210dc4e4753b107a2048b3d0e", size = 14895830, upload-time = "2026-03-29T13:21:41.509Z" }, - { url = "https://files.pythonhosted.org/packages/a5/b8/aafb0d1065416894fccf4df6b49ef22b8db045187949545bced89c034b8e/numpy-2.4.4-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:51fc224f7ca4d92656d5a5eb315f12eb5fe2c97a66249aa7b5f562528a3be38c", size = 5400927, upload-time = "2026-03-29T13:21:44.747Z" }, - { url = "https://files.pythonhosted.org/packages/d6/77/063baa20b08b431038c7f9ff5435540c7b7265c78cf56012a483019ca72d/numpy-2.4.4-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:28a650663f7314afc3e6ec620f44f333c386aad9f6fc472030865dc0ebb26ee3", size = 6715557, upload-time = "2026-03-29T13:21:47.406Z" }, - { url = "https://files.pythonhosted.org/packages/c7/a8/379542d45a14f149444c5c4c4e7714707239ce9cc1de8c2803958889da14/numpy-2.4.4-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:19710a9ca9992d7174e9c52f643d4272dcd1558c5f7af7f6f8190f633bd651a7", size = 15804253, upload-time = "2026-03-29T13:21:50.753Z" }, - { url = "https://files.pythonhosted.org/packages/a2/c8/f0a45426d6d21e7ea3310a15cf90c43a14d9232c31a837702dba437f3373/numpy-2.4.4-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b2aec6af35c113b05695ebb5749a787acd63cafc83086a05771d1e1cd1e555f", size = 16753552, upload-time = "2026-03-29T13:21:54.344Z" }, - { url = "https://files.pythonhosted.org/packages/04/74/f4c001f4714c3ad9ce037e18cf2b9c64871a84951eaa0baf683a9ca9301c/numpy-2.4.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f2cf083b324a467e1ab358c105f6cad5ea950f50524668a80c486ff1db24e119", size = 12509075, upload-time = "2026-03-29T13:21:57.644Z" }, -] - -[[package]] -name = "overrides" -version = "7.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, ] [[package]] @@ -3352,13 +2729,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/fa/7ac648108144a095b4fb6aa3de1954689f7af60a14cf25583f4960ecb878/pandas-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523", size = 11578790, upload-time = "2025-09-29T23:18:30.065Z" }, - { url = "https://files.pythonhosted.org/packages/9b/35/74442388c6cf008882d4d4bdfc4109be87e9b8b7ccd097ad1e7f006e2e95/pandas-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45", size = 10833831, upload-time = "2025-09-29T23:38:56.071Z" }, - { url = "https://files.pythonhosted.org/packages/fe/e4/de154cbfeee13383ad58d23017da99390b91d73f8c11856f2095e813201b/pandas-2.3.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66", size = 12199267, upload-time = "2025-09-29T23:18:41.627Z" }, - { url = "https://files.pythonhosted.org/packages/bf/c9/63f8d545568d9ab91476b1818b4741f521646cbdd151c6efebf40d6de6f7/pandas-2.3.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b", size = 12789281, upload-time = "2025-09-29T23:18:56.834Z" }, - { url = "https://files.pythonhosted.org/packages/f2/00/a5ac8c7a0e67fd1a6059e40aa08fa1c52cc00709077d2300e210c3ce0322/pandas-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791", size = 13240453, upload-time = "2025-09-29T23:19:09.247Z" }, - { url = "https://files.pythonhosted.org/packages/27/4d/5c23a5bc7bd209231618dd9e606ce076272c9bc4f12023a70e03a86b4067/pandas-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151", size = 13890361, upload-time = "2025-09-29T23:19:25.342Z" }, - { url = "https://files.pythonhosted.org/packages/8e/59/712db1d7040520de7a4965df15b774348980e6df45c129b8c64d0dbe74ef/pandas-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c", size = 11348702, upload-time = "2025-09-29T23:19:38.296Z" }, { url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846, upload-time = "2025-09-29T23:19:48.856Z" }, { url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618, upload-time = "2025-09-29T23:39:08.659Z" }, { url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212, upload-time = "2025-09-29T23:19:59.765Z" }, @@ -3379,19 +2749,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912, upload-time = "2025-09-29T23:23:05.042Z" }, { url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160, upload-time = "2025-09-29T23:23:28.57Z" }, { url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233, upload-time = "2025-09-29T23:24:24.876Z" }, - { url = "https://files.pythonhosted.org/packages/04/fd/74903979833db8390b73b3a8a7d30d146d710bd32703724dd9083950386f/pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", size = 11540635, upload-time = "2025-09-29T23:25:52.486Z" }, - { url = "https://files.pythonhosted.org/packages/21/00/266d6b357ad5e6d3ad55093a7e8efc7dd245f5a842b584db9f30b0f0a287/pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", size = 10759079, upload-time = "2025-09-29T23:26:33.204Z" }, - { url = "https://files.pythonhosted.org/packages/ca/05/d01ef80a7a3a12b2f8bbf16daba1e17c98a2f039cbc8e2f77a2c5a63d382/pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", size = 11814049, upload-time = "2025-09-29T23:27:15.384Z" }, - { url = "https://files.pythonhosted.org/packages/15/b2/0e62f78c0c5ba7e3d2c5945a82456f4fac76c480940f805e0b97fcbc2f65/pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", size = 12332638, upload-time = "2025-09-29T23:27:51.625Z" }, - { url = "https://files.pythonhosted.org/packages/c5/33/dd70400631b62b9b29c3c93d2feee1d0964dc2bae2e5ad7a6c73a7f25325/pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", size = 12886834, upload-time = "2025-09-29T23:28:21.289Z" }, - { url = "https://files.pythonhosted.org/packages/d3/18/b5d48f55821228d0d2692b34fd5034bb185e854bdb592e9c640f6290e012/pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", size = 13409925, upload-time = "2025-09-29T23:28:58.261Z" }, - { url = "https://files.pythonhosted.org/packages/a6/3d/124ac75fcd0ecc09b8fdccb0246ef65e35b012030defb0e0eba2cbbbe948/pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", size = 11109071, upload-time = "2025-09-29T23:32:27.484Z" }, - { url = "https://files.pythonhosted.org/packages/89/9c/0e21c895c38a157e0faa1fb64587a9226d6dd46452cac4532d80c3c4a244/pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", size = 12048504, upload-time = "2025-09-29T23:29:31.47Z" }, - { url = "https://files.pythonhosted.org/packages/d7/82/b69a1c95df796858777b68fbe6a81d37443a33319761d7c652ce77797475/pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", size = 11410702, upload-time = "2025-09-29T23:29:54.591Z" }, - { url = "https://files.pythonhosted.org/packages/f9/88/702bde3ba0a94b8c73a0181e05144b10f13f29ebfc2150c3a79062a8195d/pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", size = 11634535, upload-time = "2025-09-29T23:30:21.003Z" }, - { url = "https://files.pythonhosted.org/packages/a4/1e/1bac1a839d12e6a82ec6cb40cda2edde64a2013a66963293696bbf31fbbb/pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", size = 12121582, upload-time = "2025-09-29T23:30:43.391Z" }, - { url = "https://files.pythonhosted.org/packages/44/91/483de934193e12a3b1d6ae7c8645d083ff88dec75f46e827562f1e4b4da6/pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", size = 12699963, upload-time = "2025-09-29T23:31:10.009Z" }, - { url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175, upload-time = "2025-09-29T23:31:59.173Z" }, ] [[package]] @@ -3439,7 +2796,7 @@ name = "pexpect" version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "ptyprocess", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "ptyprocess", marker = "platform_machine != 'ARM64' or 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 = [ @@ -3452,17 +2809,6 @@ version = "12.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/68/e1/748f5663efe6edcfc4e74b2b93edfb9b8b99b67f21a854c3ae416500a2d9/pillow-12.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:8be29e59487a79f173507c30ddf57e733a357f67881430449bb32614075a40ab", size = 5354347, upload-time = "2026-04-01T14:42:44.255Z" }, - { url = "https://files.pythonhosted.org/packages/47/a1/d5ff69e747374c33a3b53b9f98cca7889fce1fd03d79cdc4e1bccc6c5a87/pillow-12.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:71cde9a1e1551df7d34a25462fc60325e8a11a82cc2e2f54578e5e9a1e153d65", size = 4695873, upload-time = "2026-04-01T14:42:46.452Z" }, - { url = "https://files.pythonhosted.org/packages/df/21/e3fbdf54408a973c7f7f89a23b2cb97a7ef30c61ab4142af31eee6aebc88/pillow-12.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f490f9368b6fc026f021db16d7ec2fbf7d89e2edb42e8ec09d2c60505f5729c7", size = 6280168, upload-time = "2026-04-01T14:42:49.228Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f1/00b7278c7dd52b17ad4329153748f87b6756ec195ff786c2bdf12518337d/pillow-12.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8bd7903a5f2a4545f6fd5935c90058b89d30045568985a71c79f5fd6edf9b91e", size = 8088188, upload-time = "2026-04-01T14:42:51.735Z" }, - { url = "https://files.pythonhosted.org/packages/ad/cf/220a5994ef1b10e70e85748b75649d77d506499352be135a4989c957b701/pillow-12.2.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3997232e10d2920a68d25191392e3a4487d8183039e1c74c2297f00ed1c50705", size = 6394401, upload-time = "2026-04-01T14:42:54.343Z" }, - { url = "https://files.pythonhosted.org/packages/e9/bd/e51a61b1054f09437acfbc2ff9106c30d1eb76bc1453d428399946781253/pillow-12.2.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e74473c875d78b8e9d5da2a70f7099549f9eb37ded4e2f6a463e60125bccd176", size = 7079655, upload-time = "2026-04-01T14:42:56.954Z" }, - { url = "https://files.pythonhosted.org/packages/6b/3d/45132c57d5fb4b5744567c3817026480ac7fc3ce5d4c47902bc0e7f6f853/pillow-12.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:56a3f9c60a13133a98ecff6197af34d7824de9b7b38c3654861a725c970c197b", size = 6503105, upload-time = "2026-04-01T14:42:59.847Z" }, - { url = "https://files.pythonhosted.org/packages/7d/2e/9df2fc1e82097b1df3dce58dc43286aa01068e918c07574711fcc53e6fb4/pillow-12.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90e6f81de50ad6b534cab6e5aef77ff6e37722b2f5d908686f4a5c9eba17a909", size = 7203402, upload-time = "2026-04-01T14:43:02.664Z" }, - { url = "https://files.pythonhosted.org/packages/bd/2e/2941e42858ebb67e50ae741473de81c2984e6eff7b397017623c676e2e8d/pillow-12.2.0-cp311-cp311-win32.whl", hash = "sha256:8c984051042858021a54926eb597d6ee3012393ce9c181814115df4c60b9a808", size = 6378149, upload-time = "2026-04-01T14:43:05.274Z" }, - { url = "https://files.pythonhosted.org/packages/69/42/836b6f3cd7f3e5fa10a1f1a5420447c17966044c8fbf589cc0452d5502db/pillow-12.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e6b2a0c538fc200b38ff9eb6628228b77908c319a005815f2dde585a0664b60", size = 7082626, upload-time = "2026-04-01T14:43:08.557Z" }, - { url = "https://files.pythonhosted.org/packages/c2/88/549194b5d6f1f494b485e493edc6693c0a16f4ada488e5bd974ed1f42fad/pillow-12.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:9a8a34cc89c67a65ea7437ce257cea81a9dad65b29805f3ecee8c8fe8ff25ffe", size = 2463531, upload-time = "2026-04-01T14:43:10.743Z" }, { url = "https://files.pythonhosted.org/packages/58/be/7482c8a5ebebbc6470b3eb791812fff7d5e0216c2be3827b30b8bb6603ed/pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5", size = 5308279, upload-time = "2026-04-01T14:43:13.246Z" }, { url = "https://files.pythonhosted.org/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421", size = 4695490, upload-time = "2026-04-01T14:43:15.584Z" }, { url = "https://files.pythonhosted.org/packages/de/af/4e8e6869cbed569d43c416fad3dc4ecb944cb5d9492defaed89ddd6fe871/pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987", size = 6284462, upload-time = "2026-04-01T14:43:18.268Z" }, @@ -3499,38 +2845,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ad/4b/926ab182c07fccae9fcb120043464e1ff1564775ec8864f21a0ebce6ac25/pillow-12.2.0-cp313-cp313t-win32.whl", hash = "sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24", size = 6379592, upload-time = "2026-04-01T14:44:40.336Z" }, { url = "https://files.pythonhosted.org/packages/c2/c4/f9e476451a098181b30050cc4c9a3556b64c02cf6497ea421ac047e89e4b/pillow-12.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98", size = 7085542, upload-time = "2026-04-01T14:44:43.251Z" }, { url = "https://files.pythonhosted.org/packages/00/a4/285f12aeacbe2d6dc36c407dfbbe9e96d4a80b0fb710a337f6d2ad978c75/pillow-12.2.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453", size = 2465765, upload-time = "2026-04-01T14:44:45.996Z" }, - { url = "https://files.pythonhosted.org/packages/bf/98/4595daa2365416a86cb0d495248a393dfc84e96d62ad080c8546256cb9c0/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8", size = 4100848, upload-time = "2026-04-01T14:44:48.48Z" }, - { url = "https://files.pythonhosted.org/packages/0b/79/40184d464cf89f6663e18dfcf7ca21aae2491fff1a16127681bf1fa9b8cf/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b", size = 4176515, upload-time = "2026-04-01T14:44:51.353Z" }, - { url = "https://files.pythonhosted.org/packages/b0/63/703f86fd4c422a9cf722833670f4f71418fb116b2853ff7da722ea43f184/pillow-12.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295", size = 3640159, upload-time = "2026-04-01T14:44:53.588Z" }, - { url = "https://files.pythonhosted.org/packages/71/e0/fb22f797187d0be2270f83500aab851536101b254bfa1eae10795709d283/pillow-12.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed", size = 5312185, upload-time = "2026-04-01T14:44:56.039Z" }, - { url = "https://files.pythonhosted.org/packages/ba/8c/1a9e46228571de18f8e28f16fabdfc20212a5d019f3e3303452b3f0a580d/pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae", size = 4695386, upload-time = "2026-04-01T14:44:58.663Z" }, - { url = "https://files.pythonhosted.org/packages/70/62/98f6b7f0c88b9addd0e87c217ded307b36be024d4ff8869a812b241d1345/pillow-12.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601", size = 6280384, upload-time = "2026-04-01T14:45:01.5Z" }, - { url = "https://files.pythonhosted.org/packages/5e/03/688747d2e91cfbe0e64f316cd2e8005698f76ada3130d0194664174fa5de/pillow-12.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be", size = 8091599, upload-time = "2026-04-01T14:45:04.5Z" }, - { url = "https://files.pythonhosted.org/packages/f6/35/577e22b936fcdd66537329b33af0b4ccfefaeabd8aec04b266528cddb33c/pillow-12.2.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f", size = 6396021, upload-time = "2026-04-01T14:45:07.117Z" }, - { url = "https://files.pythonhosted.org/packages/11/8d/d2532ad2a603ca2b93ad9f5135732124e57811d0168155852f37fbce2458/pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286", size = 7083360, upload-time = "2026-04-01T14:45:09.763Z" }, - { url = "https://files.pythonhosted.org/packages/5e/26/d325f9f56c7e039034897e7380e9cc202b1e368bfd04d4cbe6a441f02885/pillow-12.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50", size = 6507628, upload-time = "2026-04-01T14:45:12.378Z" }, - { url = "https://files.pythonhosted.org/packages/5f/f7/769d5632ffb0988f1c5e7660b3e731e30f7f8ec4318e94d0a5d674eb65a4/pillow-12.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104", size = 7209321, upload-time = "2026-04-01T14:45:15.122Z" }, - { url = "https://files.pythonhosted.org/packages/6a/7a/c253e3c645cd47f1aceea6a8bacdba9991bf45bb7dfe927f7c893e89c93c/pillow-12.2.0-cp314-cp314-win32.whl", hash = "sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7", size = 6479723, upload-time = "2026-04-01T14:45:17.797Z" }, - { url = "https://files.pythonhosted.org/packages/cd/8b/601e6566b957ca50e28725cb6c355c59c2c8609751efbecd980db44e0349/pillow-12.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150", size = 7217400, upload-time = "2026-04-01T14:45:20.529Z" }, - { url = "https://files.pythonhosted.org/packages/d6/94/220e46c73065c3e2951bb91c11a1fb636c8c9ad427ac3ce7d7f3359b9b2f/pillow-12.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1", size = 2554835, upload-time = "2026-04-01T14:45:23.162Z" }, - { url = "https://files.pythonhosted.org/packages/b6/ab/1b426a3974cb0e7da5c29ccff4807871d48110933a57207b5a676cccc155/pillow-12.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463", size = 5314225, upload-time = "2026-04-01T14:45:25.637Z" }, - { url = "https://files.pythonhosted.org/packages/19/1e/dce46f371be2438eecfee2a1960ee2a243bbe5e961890146d2dee1ff0f12/pillow-12.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3", size = 4698541, upload-time = "2026-04-01T14:45:28.355Z" }, - { url = "https://files.pythonhosted.org/packages/55/c3/7fbecf70adb3a0c33b77a300dc52e424dc22ad8cdc06557a2e49523b703d/pillow-12.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166", size = 6322251, upload-time = "2026-04-01T14:45:30.924Z" }, - { url = "https://files.pythonhosted.org/packages/1c/3c/7fbc17cfb7e4fe0ef1642e0abc17fc6c94c9f7a16be41498e12e2ba60408/pillow-12.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe", size = 8127807, upload-time = "2026-04-01T14:45:33.908Z" }, - { url = "https://files.pythonhosted.org/packages/ff/c3/a8ae14d6defd2e448493ff512fae903b1e9bd40b72efb6ec55ce0048c8ce/pillow-12.2.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd", size = 6433935, upload-time = "2026-04-01T14:45:36.623Z" }, - { url = "https://files.pythonhosted.org/packages/6e/32/2880fb3a074847ac159d8f902cb43278a61e85f681661e7419e6596803ed/pillow-12.2.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e", size = 7116720, upload-time = "2026-04-01T14:45:39.258Z" }, - { url = "https://files.pythonhosted.org/packages/46/87/495cc9c30e0129501643f24d320076f4cc54f718341df18cc70ec94c44e1/pillow-12.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06", size = 6540498, upload-time = "2026-04-01T14:45:41.879Z" }, - { url = "https://files.pythonhosted.org/packages/18/53/773f5edca692009d883a72211b60fdaf8871cbef075eaa9d577f0a2f989e/pillow-12.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43", size = 7239413, upload-time = "2026-04-01T14:45:44.705Z" }, - { url = "https://files.pythonhosted.org/packages/c9/e4/4b64a97d71b2a83158134abbb2f5bd3f8a2ea691361282f010998f339ec7/pillow-12.2.0-cp314-cp314t-win32.whl", hash = "sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354", size = 6482084, upload-time = "2026-04-01T14:45:47.568Z" }, - { url = "https://files.pythonhosted.org/packages/ba/13/306d275efd3a3453f72114b7431c877d10b1154014c1ebbedd067770d629/pillow-12.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1", size = 7225152, upload-time = "2026-04-01T14:45:50.032Z" }, - { url = "https://files.pythonhosted.org/packages/ff/6e/cf826fae916b8658848d7b9f38d88da6396895c676e8086fc0988073aaf8/pillow-12.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb", size = 2556579, upload-time = "2026-04-01T14:45:52.529Z" }, - { url = "https://files.pythonhosted.org/packages/4e/b7/2437044fb910f499610356d1352e3423753c98e34f915252aafecc64889f/pillow-12.2.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538bd5e05efec03ae613fd89c4ce0368ecd2ba239cc25b9f9be7ed426b0af1f", size = 5273969, upload-time = "2026-04-01T14:45:55.538Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f4/8316e31de11b780f4ac08ef3654a75555e624a98db1056ecb2122d008d5a/pillow-12.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:394167b21da716608eac917c60aa9b969421b5dcbbe02ae7f013e7b85811c69d", size = 4659674, upload-time = "2026-04-01T14:45:58.093Z" }, - { url = "https://files.pythonhosted.org/packages/d4/37/664fca7201f8bb2aa1d20e2c3d5564a62e6ae5111741966c8319ca802361/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5d04bfa02cc2d23b497d1e90a0f927070043f6cbf303e738300532379a4b4e0f", size = 5288479, upload-time = "2026-04-01T14:46:01.141Z" }, - { url = "https://files.pythonhosted.org/packages/49/62/5b0ed78fce87346be7a5cfcfaaad91f6a1f98c26f86bdbafa2066c647ef6/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0c838a5125cee37e68edec915651521191cef1e6aa336b855f495766e77a366e", size = 7032230, upload-time = "2026-04-01T14:46:03.874Z" }, - { url = "https://files.pythonhosted.org/packages/c3/28/ec0fc38107fc32536908034e990c47914c57cd7c5a3ece4d8d8f7ffd7e27/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a6c9fa44005fa37a91ebfc95d081e8079757d2e904b27103f4f5fa6f0bf78c0", size = 5355404, upload-time = "2026-04-01T14:46:06.33Z" }, - { url = "https://files.pythonhosted.org/packages/5e/8b/51b0eddcfa2180d60e41f06bd6d0a62202b20b59c68f5a132e615b75aecf/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:25373b66e0dd5905ed63fa3cae13c82fbddf3079f2c8bf15c6fb6a35586324c1", size = 6002215, upload-time = "2026-04-01T14:46:08.83Z" }, - { url = "https://files.pythonhosted.org/packages/bc/60/5382c03e1970de634027cee8e1b7d39776b778b81812aaf45b694dfe9e28/pillow-12.2.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bfa9c230d2fe991bed5318a5f119bd6780cda2915cca595393649fc118ab895e", size = 7080946, upload-time = "2026-04-01T14:46:11.734Z" }, ] [[package]] @@ -3655,12 +2969,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b8/b5/9182c9af3836cca61696dabe4fd1304e17bc56cb62f17439e1154f225dd3/psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312", size = 184062, upload-time = "2026-01-28T18:15:04.436Z" }, { url = "https://files.pythonhosted.org/packages/16/ba/0756dca669f5a9300d0cbcbfae9a4c30e446dfc7440ffe43ded5724bfd93/psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b", size = 139893, upload-time = "2026-01-28T18:15:06.378Z" }, { url = "https://files.pythonhosted.org/packages/1c/61/8fa0e26f33623b49949346de05ec1ddaad02ed8ba64af45f40a147dbfa97/psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9", size = 135589, upload-time = "2026-01-28T18:15:08.03Z" }, - { url = "https://files.pythonhosted.org/packages/81/69/ef179ab5ca24f32acc1dac0c247fd6a13b501fd5534dbae0e05a1c48b66d/psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00", size = 130664, upload-time = "2026-01-28T18:15:09.469Z" }, - { url = "https://files.pythonhosted.org/packages/7b/64/665248b557a236d3fa9efc378d60d95ef56dd0a490c2cd37dafc7660d4a9/psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9", size = 131087, upload-time = "2026-01-28T18:15:11.724Z" }, - { url = "https://files.pythonhosted.org/packages/d5/2e/e6782744700d6759ebce3043dcfa661fb61e2fb752b91cdeae9af12c2178/psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a", size = 182383, upload-time = "2026-01-28T18:15:13.445Z" }, - { url = "https://files.pythonhosted.org/packages/57/49/0a41cefd10cb7505cdc04dab3eacf24c0c2cb158a998b8c7b1d27ee2c1f5/psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf", size = 185210, upload-time = "2026-01-28T18:15:16.002Z" }, - { url = "https://files.pythonhosted.org/packages/dd/2c/ff9bfb544f283ba5f83ba725a3c5fec6d6b10b8f27ac1dc641c473dc390d/psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1", size = 141228, upload-time = "2026-01-28T18:15:18.385Z" }, - { url = "https://files.pythonhosted.org/packages/f2/fc/f8d9c31db14fcec13748d373e668bc3bed94d9077dbc17fb0eebc073233c/psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841", size = 136284, upload-time = "2026-01-28T18:15:19.912Z" }, { url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" }, { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" }, { url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" }, @@ -3677,11 +2985,6 @@ version = "0.15.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4e/79/20c3e23e75272e9ddf018097cf872ab088bccba978888472656629efa4a3/psygnal-0.15.1.tar.gz", hash = "sha256:f64f62dee2306fc1c22050a59b6c6cdad126e04b0cf50e393ff858a1da719096", size = 123147, upload-time = "2026-01-04T16:38:41.959Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/a7/69495410025cc4298765545ce3b8c635cd4c8d3a362b7fbbc15b80e9fc8f/psygnal-0.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1adc41515f648696990964433f1e25d8dfd306813a3645366c85e01986ba57a0", size = 581002, upload-time = "2026-01-04T16:38:12.753Z" }, - { url = "https://files.pythonhosted.org/packages/75/1f/19a8126ccf3cd3974ba5d08a435a049b666961d90f5848ba83599d7a29de/psygnal-0.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:38ff18455b2ac73d4e8eea82ef298ce904b52e4dfdc603a24380c9c440e37519", size = 567775, upload-time = "2026-01-04T16:38:14.04Z" }, - { url = "https://files.pythonhosted.org/packages/54/c5/b1348880d603edb82128a721397a1ddcf3dfcf5384fe5689db6e471118ae/psygnal-0.15.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c923c322eeefb1140886927cfe7bda7c32341087e290e812b9c69a624ab72d54", size = 855961, upload-time = "2026-01-04T16:38:15.612Z" }, - { url = "https://files.pythonhosted.org/packages/e6/42/3da2d6f3583bd1a849f7faa2fd3492b14bfda05012519ceaea5992658af0/psygnal-0.15.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2714ddaa41ea3134c0ee91cebd5fb11a88f254ea1d5948806ab0ad5f8be603d5", size = 862721, upload-time = "2026-01-04T16:38:17.059Z" }, - { url = "https://files.pythonhosted.org/packages/4d/14/6fc7e97fdecf7e8c5c105684bab784920312a3259800d8b53e3cf8783f42/psygnal-0.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:877516056a5a383427a647fff2fad5179eaa3e12de2c083c273e748435414aef", size = 415696, upload-time = "2026-01-04T16:38:18.355Z" }, { url = "https://files.pythonhosted.org/packages/76/65/b7bbca96bc477aa9ac2264e5907b2f4ccfcd1319f776dd1f35eec06cc2f4/psygnal-0.15.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d56f0f35eaf4a21f660de76885222faf9e8c7112454528d3394d464f3d4d1a3", size = 598340, upload-time = "2026-01-04T16:38:19.752Z" }, { url = "https://files.pythonhosted.org/packages/40/f2/56577465a1b42a5e6780bb5fab53fb68f8bfd72f0131ed397576529af724/psygnal-0.15.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0febcf757a1323d9b8bd75735ee3569213d8110012a7bf0f478e85c5ab459fc6", size = 575311, upload-time = "2026-01-04T16:38:21.137Z" }, { url = "https://files.pythonhosted.org/packages/79/81/f642ac08104049383076f83480ed412c9626e068769a1c34873c595bec0e/psygnal-0.15.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b5e4837dfbfa4974dabe0795e32be9aadcd87603adf734738ce1114f72238a05", size = 889770, upload-time = "2026-01-04T16:38:22.629Z" }, @@ -3692,11 +2995,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2d/4f/3593e5adb88a188c798604aed95fbc1479f30230e7f51e8f2c770e6a3832/psygnal-0.15.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e9fca977f5335deea39aed22e31d9795983e4f243e59a7d3c4105793adb7693d", size = 885616, upload-time = "2026-01-04T16:38:30.081Z" }, { url = "https://files.pythonhosted.org/packages/58/4c/14779ed4c3a1d71fa1a9a87ecfb184ad3335dd64681067f77c1c47b14ae9/psygnal-0.15.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0c85b7d05b92ccbec47c75ab8a5545eda462e81a492c82424aba5ab81a3ad89d", size = 876516, upload-time = "2026-01-04T16:38:31.422Z" }, { url = "https://files.pythonhosted.org/packages/3e/bc/4f771e3cdcde4db4023dbf36d6f0aab44e02b9de719353c22954b655e2ff/psygnal-0.15.1-cp313-cp313-win_amd64.whl", hash = "sha256:ac0e693b29e0a429e97315a52313321855bef6140e9975b7ae78b4d93c8fbb42", size = 419172, upload-time = "2026-01-04T16:38:32.82Z" }, - { url = "https://files.pythonhosted.org/packages/f4/2e/975bd61727578d88df62797f78390965ca7905780cf01eb59cb095a13638/psygnal-0.15.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:803fc33c4280c822c6f4b22e6c3ea7c4483e190f3cc69e69350098b3799476f3", size = 595706, upload-time = "2026-01-04T16:38:34.139Z" }, - { url = "https://files.pythonhosted.org/packages/b8/55/e487f1d91497eb75e86c3fdfef69a21b1cab24d023383dd7648b08797d6a/psygnal-0.15.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4f53b4b83355b0a785b745987fd04e59bbf169a9028ed81a68ca7e05fb76d458", size = 575133, upload-time = "2026-01-04T16:38:35.448Z" }, - { url = "https://files.pythonhosted.org/packages/bf/2f/f286355accd0e68d3eef52e63c8b9ab6ba33ec3107177719a036b3319657/psygnal-0.15.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bcbca12190f5aa65c1f8fb04a81fa6f4463c5f5dde25cd74c3a56ceff6f37b02", size = 889565, upload-time = "2026-01-04T16:38:37.003Z" }, - { url = "https://files.pythonhosted.org/packages/fc/dc/40c6026c88d7f9220ecc913afe0501045a512c9b82f9b7e036bb089dc287/psygnal-0.15.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1ac399566852fe4354ce26a1acbe12319232e8c2b615fe5ad1e114c547095cf6", size = 880863, upload-time = "2026-01-04T16:38:38.381Z" }, - { url = "https://files.pythonhosted.org/packages/b7/85/b4f45ec3057c473b5622fc002b3a636a698c34d3a0917a064ff5247f1984/psygnal-0.15.1-cp314-cp314-win_amd64.whl", hash = "sha256:d3a03055f331ce91d44581c71edb79938ccc133a94af2ce7ad3a18fa57ac7be5", size = 423654, upload-time = "2026-01-04T16:38:39.7Z" }, { url = "https://files.pythonhosted.org/packages/46/49/7742544684bee728ec123515d2694cee859aa2a705951a461230b00f18cc/psygnal-0.15.1-py3-none-any.whl", hash = "sha256:4221140e633e45b076953c64bcb9b41a744833527f9a037c1ca98bc270798cbf", size = 90638, upload-time = "2026-01-04T16:38:40.841Z" }, ] @@ -3724,13 +3022,6 @@ version = "23.0.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/88/22/134986a4cc224d593c1afde5494d18ff629393d74cc2eddb176669f234a4/pyarrow-23.0.1.tar.gz", hash = "sha256:b8c5873e33440b2bc2f4a79d2b47017a89c5a24116c055625e6f2ee50523f019", size = 1167336, upload-time = "2026-02-16T10:14:12.39Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/41/8e6b6ef7e225d4ceead8459427a52afdc23379768f54dd3566014d7618c1/pyarrow-23.0.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:6f0147ee9e0386f519c952cc670eb4a8b05caa594eeffe01af0e25f699e4e9bb", size = 34302230, upload-time = "2026-02-16T10:09:03.859Z" }, - { url = "https://files.pythonhosted.org/packages/bf/4a/1472c00392f521fea03ae93408bf445cc7bfa1ab81683faf9bc188e36629/pyarrow-23.0.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:0ae6e17c828455b6265d590100c295193f93cc5675eb0af59e49dbd00d2de350", size = 35850050, upload-time = "2026-02-16T10:09:11.877Z" }, - { url = "https://files.pythonhosted.org/packages/0c/b2/bd1f2f05ded56af7f54d702c8364c9c43cd6abb91b0e9933f3d77b4f4132/pyarrow-23.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:fed7020203e9ef273360b9e45be52a2a47d3103caf156a30ace5247ffb51bdbd", size = 44491918, upload-time = "2026-02-16T10:09:18.144Z" }, - { url = "https://files.pythonhosted.org/packages/0b/62/96459ef5b67957eac38a90f541d1c28833d1b367f014a482cb63f3b7cd2d/pyarrow-23.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:26d50dee49d741ac0e82185033488d28d35be4d763ae6f321f97d1140eb7a0e9", size = 47562811, upload-time = "2026-02-16T10:09:25.792Z" }, - { url = "https://files.pythonhosted.org/packages/7d/94/1170e235add1f5f45a954e26cd0e906e7e74e23392dcb560de471f7366ec/pyarrow-23.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3c30143b17161310f151f4a2bcfe41b5ff744238c1039338779424e38579d701", size = 48183766, upload-time = "2026-02-16T10:09:34.645Z" }, - { url = "https://files.pythonhosted.org/packages/0e/2d/39a42af4570377b99774cdb47f63ee6c7da7616bd55b3d5001aa18edfe4f/pyarrow-23.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db2190fa79c80a23fdd29fef4b8992893f024ae7c17d2f5f4db7171fa30c2c78", size = 50607669, upload-time = "2026-02-16T10:09:44.153Z" }, - { url = "https://files.pythonhosted.org/packages/00/ca/db94101c187f3df742133ac837e93b1f269ebdac49427f8310ee40b6a58f/pyarrow-23.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:f00f993a8179e0e1c9713bcc0baf6d6c01326a406a9c23495ec1ba9c9ebf2919", size = 27527698, upload-time = "2026-02-16T10:09:50.263Z" }, { url = "https://files.pythonhosted.org/packages/9a/4b/4166bb5abbfe6f750fc60ad337c43ecf61340fa52ab386da6e8dbf9e63c4/pyarrow-23.0.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:f4b0dbfa124c0bb161f8b5ebb40f1a680b70279aa0c9901d44a2b5a20806039f", size = 34214575, upload-time = "2026-02-16T10:09:56.225Z" }, { url = "https://files.pythonhosted.org/packages/e1/da/3f941e3734ac8088ea588b53e860baeddac8323ea40ce22e3d0baa865cc9/pyarrow-23.0.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:7707d2b6673f7de054e2e83d59f9e805939038eebe1763fe811ee8fa5c0cd1a7", size = 35832540, upload-time = "2026-02-16T10:10:03.428Z" }, { url = "https://files.pythonhosted.org/packages/88/7c/3d841c366620e906d54430817531b877ba646310296df42ef697308c2705/pyarrow-23.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:86ff03fb9f1a320266e0de855dee4b17da6794c595d207f89bba40d16b5c78b9", size = 44470940, upload-time = "2026-02-16T10:10:10.704Z" }, @@ -3752,20 +3043,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/84/a7/90007d476b9f0dc308e3bc57b832d004f848fd6c0da601375d20d92d1519/pyarrow-23.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c2139549494445609f35a5cda4eb94e2c9e4d704ce60a095b342f82460c73a83", size = 48236269, upload-time = "2026-02-16T10:12:04.47Z" }, { url = "https://files.pythonhosted.org/packages/b0/3f/b16fab3e77709856eb6ac328ce35f57a6d4a18462c7ca5186ef31b45e0e0/pyarrow-23.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7044b442f184d84e2351e5084600f0d7343d6117aabcbc1ac78eb1ae11eb4125", size = 50604794, upload-time = "2026-02-16T10:12:11.797Z" }, { url = "https://files.pythonhosted.org/packages/e9/a1/22df0620a9fac31d68397a75465c344e83c3dfe521f7612aea33e27ab6c0/pyarrow-23.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a35581e856a2fafa12f3f54fce4331862b1cfb0bef5758347a858a4aa9d6bae8", size = 27660642, upload-time = "2026-02-16T10:12:17.746Z" }, - { url = "https://files.pythonhosted.org/packages/8d/1b/6da9a89583ce7b23ac611f183ae4843cd3a6cf54f079549b0e8c14031e73/pyarrow-23.0.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:5df1161da23636a70838099d4aaa65142777185cc0cdba4037a18cee7d8db9ca", size = 34238755, upload-time = "2026-02-16T10:12:32.819Z" }, - { url = "https://files.pythonhosted.org/packages/ae/b5/d58a241fbe324dbaeb8df07be6af8752c846192d78d2272e551098f74e88/pyarrow-23.0.1-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:fa8e51cb04b9f8c9c5ace6bab63af9a1f88d35c0d6cbf53e8c17c098552285e1", size = 35847826, upload-time = "2026-02-16T10:12:38.949Z" }, - { url = "https://files.pythonhosted.org/packages/54/a5/8cbc83f04aba433ca7b331b38f39e000efd9f0c7ce47128670e737542996/pyarrow-23.0.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:0b95a3994f015be13c63148fef8832e8a23938128c185ee951c98908a696e0eb", size = 44536859, upload-time = "2026-02-16T10:12:45.467Z" }, - { url = "https://files.pythonhosted.org/packages/36/2e/c0f017c405fcdc252dbccafbe05e36b0d0eb1ea9a958f081e01c6972927f/pyarrow-23.0.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:4982d71350b1a6e5cfe1af742c53dfb759b11ce14141870d05d9e540d13bc5d1", size = 47614443, upload-time = "2026-02-16T10:12:55.525Z" }, - { url = "https://files.pythonhosted.org/packages/af/6b/2314a78057912f5627afa13ba43809d9d653e6630859618b0fd81a4e0759/pyarrow-23.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c250248f1fe266db627921c89b47b7c06fee0489ad95b04d50353537d74d6886", size = 48232991, upload-time = "2026-02-16T10:13:04.729Z" }, - { url = "https://files.pythonhosted.org/packages/40/f2/1bcb1d3be3460832ef3370d621142216e15a2c7c62602a4ea19ec240dd64/pyarrow-23.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5f4763b83c11c16e5f4c15601ba6dfa849e20723b46aa2617cb4bffe8768479f", size = 50645077, upload-time = "2026-02-16T10:13:14.147Z" }, - { url = "https://files.pythonhosted.org/packages/eb/3f/b1da7b61cd66566a4d4c8383d376c606d1c34a906c3f1cb35c479f59d1aa/pyarrow-23.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:3a4c85ef66c134161987c17b147d6bffdca4566f9a4c1d81a0a01cdf08414ea5", size = 28234271, upload-time = "2026-02-16T10:14:09.397Z" }, - { url = "https://files.pythonhosted.org/packages/b5/78/07f67434e910a0f7323269be7bfbf58699bd0c1d080b18a1ab49ba943fe8/pyarrow-23.0.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:17cd28e906c18af486a499422740298c52d7c6795344ea5002a7720b4eadf16d", size = 34488692, upload-time = "2026-02-16T10:13:21.541Z" }, - { url = "https://files.pythonhosted.org/packages/50/76/34cf7ae93ece1f740a04910d9f7e80ba166b9b4ab9596a953e9e62b90fe1/pyarrow-23.0.1-cp314-cp314t-macosx_12_0_x86_64.whl", hash = "sha256:76e823d0e86b4fb5e1cf4a58d293036e678b5a4b03539be933d3b31f9406859f", size = 35964383, upload-time = "2026-02-16T10:13:28.63Z" }, - { url = "https://files.pythonhosted.org/packages/46/90/459b827238936d4244214be7c684e1b366a63f8c78c380807ae25ed92199/pyarrow-23.0.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:a62e1899e3078bf65943078b3ad2a6ddcacf2373bc06379aac61b1e548a75814", size = 44538119, upload-time = "2026-02-16T10:13:35.506Z" }, - { url = "https://files.pythonhosted.org/packages/28/a1/93a71ae5881e99d1f9de1d4554a87be37da11cd6b152239fb5bd924fdc64/pyarrow-23.0.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:df088e8f640c9fae3b1f495b3c64755c4e719091caf250f3a74d095ddf3c836d", size = 47571199, upload-time = "2026-02-16T10:13:42.504Z" }, - { url = "https://files.pythonhosted.org/packages/88/a3/d2c462d4ef313521eaf2eff04d204ac60775263f1fb08c374b543f79f610/pyarrow-23.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:46718a220d64677c93bc243af1d44b55998255427588e400677d7192671845c7", size = 48259435, upload-time = "2026-02-16T10:13:49.226Z" }, - { url = "https://files.pythonhosted.org/packages/cc/f1/11a544b8c3d38a759eb3fbb022039117fd633e9a7b19e4841cc3da091915/pyarrow-23.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a09f3876e87f48bc2f13583ab551f0379e5dfb83210391e68ace404181a20690", size = 50629149, upload-time = "2026-02-16T10:13:57.238Z" }, - { url = "https://files.pythonhosted.org/packages/50/f2/c0e76a0b451ffdf0cf788932e182758eb7558953f4f27f1aff8e2518b653/pyarrow-23.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:527e8d899f14bd15b740cd5a54ad56b7f98044955373a17179d5956ddb93d9ce", size = 28365807, upload-time = "2026-02-16T10:14:03.892Z" }, ] [[package]] @@ -3810,21 +3087,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/6f/0a/9414cddf82eda3976b14048cc0fa8f5b5d1aecb0b22e1dcd2dbfe0e139b1/pydantic_core-2.46.0.tar.gz", hash = "sha256:82d2498c96be47b47e903e1378d1d0f770097ec56ea953322f39936a7cf34977", size = 471441, upload-time = "2026-04-13T09:06:33.813Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/43/9bc38d43a6a48794209e4eb6d61e9c68395f69b7949f66842854b0cd1344/pydantic_core-2.46.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0027da787ae711f7fbd5a76cb0bb8df526acba6c10c1e44581de1b838db10b7b", size = 2121004, upload-time = "2026-04-13T09:05:17.531Z" }, - { url = "https://files.pythonhosted.org/packages/8c/1d/f43342b7107939b305b5e4efeef7d54e267a5ef51515570a5c1d77726efb/pydantic_core-2.46.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:63e288fc18d7eaeef5f16c73e65c4fd0ad95b25e7e21d8a5da144977b35eb997", size = 1947505, upload-time = "2026-04-13T09:04:48.975Z" }, - { url = "https://files.pythonhosted.org/packages/4a/cd/ccf48cbbcaf0d99ba65969459ebfbf7037600b2cfdcca3062084dd83a008/pydantic_core-2.46.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:080a3bdc6807089a1fe1fbc076519cea287f1a964725731d80b49d8ecffaa217", size = 1973301, upload-time = "2026-04-13T09:05:42.149Z" }, - { url = "https://files.pythonhosted.org/packages/c2/ff/a7bb1e7a762fb1f40ad5ef4e6a92c012864a017b7b1fdfb71cf91faa8b73/pydantic_core-2.46.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c065f1c3e54c3e79d909927a8cb48ccbc17b68733552161eba3e0628c38e5d19", size = 2042208, upload-time = "2026-04-13T09:05:32.591Z" }, - { url = "https://files.pythonhosted.org/packages/ea/64/d3f11c6f6ace71526f3b03646df95eaab3f21edd13e00daae3f20f4e5a09/pydantic_core-2.46.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e2db58ab46cfe602d4255381cce515585998c3b6699d5b1f909f519bc44a5aa", size = 2229046, upload-time = "2026-04-13T09:04:18.59Z" }, - { url = "https://files.pythonhosted.org/packages/d0/64/93db9a63cce71630c58b376d63de498aa93cb341c72cd5f189b5c08f5c28/pydantic_core-2.46.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c660974890ec1e4c65cff93f5670a5f451039f65463e9f9c03ad49746b49fc78", size = 2292138, upload-time = "2026-04-13T09:04:13.816Z" }, - { url = "https://files.pythonhosted.org/packages/e9/96/936fccce22f1f2ae8b2b694de651c2c929847be5f701c927a0bb3b1eb679/pydantic_core-2.46.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3be91482a8db77377c902cca87697388a4fb68addeb3e943ac74f425201a099", size = 2093333, upload-time = "2026-04-13T09:05:15.729Z" }, - { url = "https://files.pythonhosted.org/packages/75/76/c325e7fda69d589e26e772272044fe704c7e525c47d0d32a74f8345ac657/pydantic_core-2.46.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:1c72de82115233112d70d07f26a48cf6996eb86f7e143423ec1a182148455a9d", size = 2138802, upload-time = "2026-04-13T09:03:51.142Z" }, - { url = "https://files.pythonhosted.org/packages/c0/6f/ccaa2ff7d53a017b66841e2d38edd1f38d19ae1a2d0c5efee17f2d432229/pydantic_core-2.46.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7904e58768cd79304b992868d7710bfc85dc6c7ed6163f0f68dbc1dcd72dc231", size = 2181358, upload-time = "2026-04-13T09:04:30.737Z" }, - { url = "https://files.pythonhosted.org/packages/6c/71/0c4b6303e92d63edcb81f5301695cdf70bb351775b4733eea65acdac8384/pydantic_core-2.46.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1af8d88718005f57bb4768f92f4ff16bf31a747d39dfc919b22211b84e72c053", size = 2183985, upload-time = "2026-04-13T09:04:06.792Z" }, - { url = "https://files.pythonhosted.org/packages/71/eb/f6bf255de38a4393aaa10bff224e882b630576bc26ebfb401e42bb965092/pydantic_core-2.46.0-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:a5b891301b02770a5852253f4b97f8bd192e5710067bc129e20d43db5403ede2", size = 2328559, upload-time = "2026-04-13T09:06:14.143Z" }, - { url = "https://files.pythonhosted.org/packages/f2/71/93895a1545f50823a24b21d7761c2bd1b1afea7a6ddc019787caec237361/pydantic_core-2.46.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:48b671fe59031fd9754c7384ac05b3ed47a0cccb7d4db0ec56121f0e6a541b90", size = 2367466, upload-time = "2026-04-13T09:05:59.613Z" }, - { url = "https://files.pythonhosted.org/packages/78/39/62331b3e71f41fb13d486621e2aec49900ba56567fb3a0ae5999fded0005/pydantic_core-2.46.0-cp311-cp311-win32.whl", hash = "sha256:0a52b7262b6cc67033823e9549a41bb77580ac299dc964baae4e9c182b2e335c", size = 1981367, upload-time = "2026-04-13T09:07:37.563Z" }, - { url = "https://files.pythonhosted.org/packages/9f/51/caac70958420e2d6115962f550676df59647c11f96a44c2fcb61662fcd16/pydantic_core-2.46.0-cp311-cp311-win_amd64.whl", hash = "sha256:4103fea1beeef6b3a9fed8515f27d4fa30c929a1973655adf8f454dc49ee0662", size = 2065942, upload-time = "2026-04-13T09:06:37.873Z" }, - { url = "https://files.pythonhosted.org/packages/b2/cf/576b2a4eb5500a1a5da485613b1ea8bc0d7279b27e0426801574b284ae65/pydantic_core-2.46.0-cp311-cp311-win_arm64.whl", hash = "sha256:3137cd88938adb8e567c5e938e486adc7e518ffc96b4ae1ec268e6a4275704d7", size = 2052532, upload-time = "2026-04-13T09:06:03.697Z" }, { url = "https://files.pythonhosted.org/packages/a7/d2/206c72ad47071559142a35f71efc29eb16448a4a5ae9487230ab8e4e292b/pydantic_core-2.46.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:66ccedb02c934622612448489824955838a221b3a35875458970521ef17b2f9c", size = 2117060, upload-time = "2026-04-13T09:04:47.443Z" }, { url = "https://files.pythonhosted.org/packages/17/2c/7a53b33f91c8b77e696b1a6aa3bed609bf9374bdc0f8dcda681bc7d922b8/pydantic_core-2.46.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a44f27f4d2788ef9876ec47a43739b118c5904d74f418f53398f6ced3bbcacf2", size = 1951802, upload-time = "2026-04-13T09:05:34.591Z" }, { url = "https://files.pythonhosted.org/packages/fc/20/90e548c1f6d38800ef11c915881525770ce270d8e5e887563ff046a08674/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26a1032bcce6ca4b4670eb3f7d8195bd0a8b8f255f1307823e217ca3cfa7c27", size = 1976621, upload-time = "2026-04-13T09:04:03.909Z" }, @@ -3855,52 +3117,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/c9/2ddd10f50e4b7350d2574629a0f53d8d4eb6573f9c19a6b43e6b1487a31d/pydantic_core-2.46.0-cp313-cp313-win32.whl", hash = "sha256:59d24ec8d5eaabad93097525a69d0f00f2667cb353eb6cda578b1cfff203ceef", size = 1965660, upload-time = "2026-04-13T09:06:05.877Z" }, { url = "https://files.pythonhosted.org/packages/b5/e7/1efc38ed6f2680c032bcefa0e3ebd496a8c77e92dfdb86b07d0f2fc632b1/pydantic_core-2.46.0-cp313-cp313-win_amd64.whl", hash = "sha256:71186dad5ac325c64d68fe0e654e15fd79802e7cc42bc6f0ff822d5ad8b1ab25", size = 2069563, upload-time = "2026-04-13T09:07:14.738Z" }, { url = "https://files.pythonhosted.org/packages/c3/1e/a325b4989e742bf7e72ed35fa124bc611fd76539c9f8cd2a9a7854473533/pydantic_core-2.46.0-cp313-cp313-win_arm64.whl", hash = "sha256:8e4503f3213f723842c9a3b53955c88a9cfbd0b288cbd1c1ae933aebeec4a1b4", size = 2034966, upload-time = "2026-04-13T09:04:21.629Z" }, - { url = "https://files.pythonhosted.org/packages/36/3b/914891d384cdbf9a6f464eb13713baa22ea1e453d4da80fb7da522079370/pydantic_core-2.46.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:4fc801c290342350ffc82d77872054a934b2e24163727263362170c1db5416ca", size = 2113349, upload-time = "2026-04-13T09:04:59.407Z" }, - { url = "https://files.pythonhosted.org/packages/35/95/3a0c6f65e231709fb3463e32943c69d10285cb50203a2130a4732053a06d/pydantic_core-2.46.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0a36f2cc88170cc177930afcc633a8c15907ea68b59ac16bd180c2999d714940", size = 1949170, upload-time = "2026-04-13T09:06:09.935Z" }, - { url = "https://files.pythonhosted.org/packages/d1/63/d845c36a608469fe7bee226edeff0984c33dbfe7aecd755b0e7ab5a275c4/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a3912e0c568a1f99d4d6d3e41def40179d61424c0ca1c8c87c4877d7f6fd7fb", size = 1977914, upload-time = "2026-04-13T09:04:56.16Z" }, - { url = "https://files.pythonhosted.org/packages/08/6f/f2e7a7f85931fb31671f5378d1c7fc70606e4b36d59b1b48e1bd1ef5d916/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3534c3415ed1a19ab23096b628916a827f7858ec8db49ad5d7d1e44dc13c0d7b", size = 2050538, upload-time = "2026-04-13T09:05:06.789Z" }, - { url = "https://files.pythonhosted.org/packages/8c/97/f4aa7181dd9a16dd9059a99fc48fdab0c2aab68307283a5c04cf56de68c4/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21067396fc285609323a4db2f63a87570044abe0acddfcca8b135fc7948e3db7", size = 2236294, upload-time = "2026-04-13T09:07:03.2Z" }, - { url = "https://files.pythonhosted.org/packages/24/c1/6a5042fc32765c87101b500f394702890af04239c318b6002cfd627b710d/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2afd85b7be186e2fe7cdbb09a3d964bcc2042f65bbcc64ad800b3c7915032655", size = 2312954, upload-time = "2026-04-13T09:06:11.919Z" }, - { url = "https://files.pythonhosted.org/packages/cb/e4/566101a561492ce8454f0844ca29c3b675a6b3a7b3ff577db85ed05c8c50/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67e2c2e171b78db8154da602de72ffdc473c6ee51de8a9d80c0f1cd4051abfc7", size = 2102533, upload-time = "2026-04-13T09:06:58.664Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ac/adc11ee1646a5c4dd9abb09a00e7909e6dc25beddc0b1310ca734bb9b48e/pydantic_core-2.46.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c16ae1f3170267b1a37e16dba5c297bdf60c8b5657b147909ca8774ce7366644", size = 2169447, upload-time = "2026-04-13T09:04:11.143Z" }, - { url = "https://files.pythonhosted.org/packages/26/73/408e686b45b82d28ac19e8229e07282254dbee6a5d24c5c7cf3cf3716613/pydantic_core-2.46.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:133b69e1c1ba34d3702eed73f19f7f966928f9aa16663b55c2ebce0893cca42e", size = 2200672, upload-time = "2026-04-13T09:03:54.056Z" }, - { url = "https://files.pythonhosted.org/packages/0a/3b/807d5b035ec891b57b9079ce881f48263936c37bd0d154a056e7fd152afb/pydantic_core-2.46.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:15ed8e5bde505133d96b41702f31f06829c46b05488211a5b1c7877e11de5eb5", size = 2188293, upload-time = "2026-04-13T09:07:07.614Z" }, - { url = "https://files.pythonhosted.org/packages/f1/ed/719b307516285099d1196c52769fdbe676fd677da007b9c349ae70b7226d/pydantic_core-2.46.0-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:8cfc29a1c66a7f0fcb36262e92f353dd0b9c4061d558fceb022e698a801cb8ae", size = 2335023, upload-time = "2026-04-13T09:04:05.176Z" }, - { url = "https://files.pythonhosted.org/packages/8d/90/8718e4ae98c4e8a7325afdc079be82be1e131d7a47cb6c098844a9531ffe/pydantic_core-2.46.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e1155708540f13845bf68d5ac511a55c76cfe2e057ed12b4bf3adac1581fc5c2", size = 2377155, upload-time = "2026-04-13T09:06:18.081Z" }, - { url = "https://files.pythonhosted.org/packages/dd/dc/7172789283b963f81da2fc92b186e22de55687019079f71c4d570822502b/pydantic_core-2.46.0-cp314-cp314-win32.whl", hash = "sha256:de5635a48df6b2eef161d10ea1bc2626153197333662ba4cd700ee7ec1aba7f5", size = 1963078, upload-time = "2026-04-13T09:05:30.615Z" }, - { url = "https://files.pythonhosted.org/packages/e0/69/03a7ea4b6264def3a44eabf577528bcec2f49468c5698b2044dea54dc07e/pydantic_core-2.46.0-cp314-cp314-win_amd64.whl", hash = "sha256:f07a5af60c5e7cf53dd1ff734228bd72d0dc9938e64a75b5bb308ca350d9681e", size = 2068439, upload-time = "2026-04-13T09:04:57.729Z" }, - { url = "https://files.pythonhosted.org/packages/f5/eb/1c3afcfdee2ab6634b802ab0a0f1966df4c8b630028ec56a1cb0a710dc58/pydantic_core-2.46.0-cp314-cp314-win_arm64.whl", hash = "sha256:e7a77eca3c7d5108ff509db20aae6f80d47c7ed7516d8b96c387aacc42f3ce0f", size = 2026470, upload-time = "2026-04-13T09:05:08.654Z" }, - { url = "https://files.pythonhosted.org/packages/5c/30/1177dde61b200785c4739665e3aa03a9d4b2c25d2d0408b07d585e633965/pydantic_core-2.46.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:5e7cdd4398bee1aaeafe049ac366b0f887451d9ae418fd8785219c13fea2f928", size = 2107447, upload-time = "2026-04-13T09:05:46.314Z" }, - { url = "https://files.pythonhosted.org/packages/b1/60/4e0f61f99bdabbbc309d364a2791e1ba31e778a4935bc43391a7bdec0744/pydantic_core-2.46.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5c2c92d82808e27cef3f7ab3ed63d657d0c755e0dbe5b8a58342e37bdf09bd2e", size = 1926927, upload-time = "2026-04-13T09:06:20.371Z" }, - { url = "https://files.pythonhosted.org/packages/1d/d0/67f89a8269152c1d6eaa81f04e75a507372ebd8ca7382855a065222caa80/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bab80af91cd7014b45d1089303b5f844a9d91d7da60eabf3d5f9694b32a6655", size = 1966613, upload-time = "2026-04-13T09:07:05.389Z" }, - { url = "https://files.pythonhosted.org/packages/cd/07/8dfdc3edc78f29a80fb31f366c50203ec904cff6a4c923599bf50ac0d0ff/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e49ffdb714bc990f00b39d1ad1d683033875b5af15582f60c1f34ad3eeccfaa", size = 2032902, upload-time = "2026-04-13T09:06:42.47Z" }, - { url = "https://files.pythonhosted.org/packages/b0/2a/111c5e8fe24f99c46bcad7d3a82a8f6dbc738066e2c72c04c71f827d8c78/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ca877240e8dbdeef3a66f751dc41e5a74893767d510c22a22fc5c0199844f0ce", size = 2244456, upload-time = "2026-04-13T09:05:36.484Z" }, - { url = "https://files.pythonhosted.org/packages/6b/7c/cfc5d11c15a63ece26e148572c77cfbb2c7f08d315a7b63ef0fe0711d753/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87e6843f89ecd2f596d7294e33196c61343186255b9880c4f1b725fde8b0e20d", size = 2294535, upload-time = "2026-04-13T09:06:01.689Z" }, - { url = "https://files.pythonhosted.org/packages/c4/2c/f0d744e3dab7bd026a3f4670a97a295157cff923a2666d30a15a70a7e3d0/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e20bc5add1dd9bc3b9a3600d40632e679376569098345500799a6ad7c5d46c72", size = 2104621, upload-time = "2026-04-13T09:04:34.388Z" }, - { url = "https://files.pythonhosted.org/packages/a7/64/e7cc4698dc024264d214b51d5a47a2404221b12060dd537d76f831b2120a/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:ee6ff79a5f0289d64a9d6696a3ce1f98f925b803dd538335a118231e26d6d827", size = 2130718, upload-time = "2026-04-13T09:04:26.23Z" }, - { url = "https://files.pythonhosted.org/packages/0b/a8/224e655fec21f7d4441438ad2ecaccb33b5a3876ce7bb2098c74a49efc14/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:52d35cfb58c26323101c7065508d7bb69bb56338cda9ea47a7b32be581af055d", size = 2180738, upload-time = "2026-04-13T09:05:50.253Z" }, - { url = "https://files.pythonhosted.org/packages/32/7b/b3025618ed4c4e4cbaa9882731c19625db6669896b621760ea95bc1125ef/pydantic_core-2.46.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d14cc5a6f260fa78e124061eebc5769af6534fc837e9a62a47f09a2c341fa4ea", size = 2171222, upload-time = "2026-04-13T09:07:29.929Z" }, - { url = "https://files.pythonhosted.org/packages/7b/e3/68170aa1d891920af09c1f2f34df61dc5ff3a746400027155523e3400e89/pydantic_core-2.46.0-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:4f7ff859d663b6635f6307a10803d07f0d09487e16c3d36b1744af51dbf948b2", size = 2320040, upload-time = "2026-04-13T09:06:35.732Z" }, - { url = "https://files.pythonhosted.org/packages/67/1b/5e65807001b84972476300c1f49aea2b4971b7e9fffb5c2654877dadd274/pydantic_core-2.46.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:8ef749be6ed0d69dba31902aaa8255a9bb269ae50c93888c4df242d8bb7acd9e", size = 2377062, upload-time = "2026-04-13T09:07:39.945Z" }, - { url = "https://files.pythonhosted.org/packages/75/03/48caa9dd5f28f7662bd52bff454d9a451f6b7e5e4af95e289e5e170749c9/pydantic_core-2.46.0-cp314-cp314t-win32.whl", hash = "sha256:d93ca72870133f86360e4bb0c78cd4e6ba2a0f9f3738a6486909ffc031463b32", size = 1951028, upload-time = "2026-04-13T09:04:20.224Z" }, - { url = "https://files.pythonhosted.org/packages/87/ed/e97ff55fe28c0e6e3cba641d622b15e071370b70e5f07c496b07b65db7c9/pydantic_core-2.46.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6ebb2668afd657e2127cb40f2ceb627dd78e74e9dfde14d9bf6cdd532a29ff59", size = 2048519, upload-time = "2026-04-13T09:05:10.464Z" }, - { url = "https://files.pythonhosted.org/packages/b6/51/e0db8267a287994546925f252e329eeae4121b1e77e76353418da5a3adf0/pydantic_core-2.46.0-cp314-cp314t-win_arm64.whl", hash = "sha256:4864f5bbb7993845baf9209bae1669a8a76769296a018cb569ebda9dcb4241f5", size = 2026791, upload-time = "2026-04-13T09:04:37.724Z" }, - { url = "https://files.pythonhosted.org/packages/2d/f1/6731c2d6caf03efe822101edb4783eb3f212f34b7b005a34f039f67e76e1/pydantic_core-2.46.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:ce2e38e27de73ff6a0312a9e3304c398577c418d90bbde97f0ba1ee3ab7ac39f", size = 2121259, upload-time = "2026-04-13T09:07:34.845Z" }, - { url = "https://files.pythonhosted.org/packages/72/fd/ac34d4c92e739e37a040be9e7ea84d116afec5f983a7db856c27135fba77/pydantic_core-2.46.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:f0d34ba062396de0be7421e6e69c9a6821bf6dc73a0ab9959a48a5a6a1e24754", size = 1945798, upload-time = "2026-04-13T09:04:24.729Z" }, - { url = "https://files.pythonhosted.org/packages/b6/a4/f413a522c4047c46b109be6805a3095d35e5a4882fd5b4fdc0909693dfc0/pydantic_core-2.46.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4c0a12147b4026dd68789fb9f22f1a8769e457f9562783c181880848bbd6412", size = 1986062, upload-time = "2026-04-13T09:05:57.177Z" }, - { url = "https://files.pythonhosted.org/packages/91/2e/9760025ea8b0f49903c0ceebdfc2d8ef839da872426f2b03cae9de036a7c/pydantic_core-2.46.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a99896d9db56df901ab4a63cd6a36348a569cff8e05f049db35f4016a817a3d9", size = 2145344, upload-time = "2026-04-13T09:03:56.924Z" }, { url = "https://files.pythonhosted.org/packages/74/0c/106ed5cc50393d90523f09adcc50d05e42e748eb107dc06aea971137f02d/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:bc0e2fefe384152d7da85b5c2fe8ce2bf24752f68a58e3f3ea42e28a29dfdeb2", size = 2104968, upload-time = "2026-04-13T09:06:26.967Z" }, { url = "https://files.pythonhosted.org/packages/f5/71/b494cef3165e3413ee9bbbb5a9eedc9af0ea7b88d8638beef6c2061b110e/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:a2ab0e785548be1b4362a62c4004f9217598b7ee465f1f420fc2123e2a5b5b02", size = 1940442, upload-time = "2026-04-13T09:06:29.332Z" }, { url = "https://files.pythonhosted.org/packages/7e/3e/a4d578c8216c443e26a1124f8c1e07c0654264ce5651143d3883d85ff140/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16d45aecb18b8cba1c68eeb17c2bb2d38627ceed04c5b30b882fc9134e01f187", size = 1999672, upload-time = "2026-04-13T09:04:42.798Z" }, { url = "https://files.pythonhosted.org/packages/cd/c1/9114560468685525a21770138382fd0cb849aaf351ff2c7b97f760d121e0/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5078f6c377b002428e984259ac327ef8902aacae6c14b7de740dd4869a491501", size = 2154533, upload-time = "2026-04-13T09:04:50.868Z" }, - { url = "https://files.pythonhosted.org/packages/09/ed/fbd8127e4a19c4fdbb2f4983cf72c7b3534086df640c813c5c0ec4218177/pydantic_core-2.46.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:be3e04979ba4d68183f247202c7f4f483f35df57690b3f875c06340a1579b47c", size = 2119951, upload-time = "2026-04-13T09:04:35.923Z" }, - { url = "https://files.pythonhosted.org/packages/ec/77/df8711ebb45910412f90d75198430fa1120f5618336b71fa00303601c5a4/pydantic_core-2.46.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b1eae8d7d9b8c2a90b34d3d9014804dca534f7f40180197062634499412ea14e", size = 1953812, upload-time = "2026-04-13T09:05:40.293Z" }, - { url = "https://files.pythonhosted.org/packages/12/fe/14b35df69112bd812d6818a395eeab22eeaa2befc6f85bc54ed648430186/pydantic_core-2.46.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a95a2773680dd4b6b999d4eccdd1b577fd71c31739fb4849f6ada47eabb9c56", size = 2139585, upload-time = "2026-04-13T09:06:46.94Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f0/4fea4c14ebbdeb87e5f6edd2620735fcbd384865f06707fe229c021ce041/pydantic_core-2.46.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:25988c3159bb097e06abfdf7b21b1fcaf90f187c74ca6c7bb842c1f72ce74fa8", size = 2179154, upload-time = "2026-04-13T09:04:15.639Z" }, - { url = "https://files.pythonhosted.org/packages/5c/36/6329aa79ba32b73560e6e453164fb29702b115fd3b2b650e796e1dc27862/pydantic_core-2.46.0-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:747d89bd691854c719a3381ba46b6124ef916ae85364c79e11db9c84995d8d03", size = 2182917, upload-time = "2026-04-13T09:07:24.483Z" }, - { url = "https://files.pythonhosted.org/packages/92/61/edbf7aea71052d410347846a2ea43394f74651bf6822b8fad8703ca00575/pydantic_core-2.46.0-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:909a7327b83ca93b372f7d48df0ebc7a975a5191eb0b6e024f503f4902c24124", size = 2327716, upload-time = "2026-04-13T09:06:31.681Z" }, - { url = "https://files.pythonhosted.org/packages/a4/11/aa5089b941e85294b1d5d526840b18f0d4464f842d43d8999ce50ef881c1/pydantic_core-2.46.0-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:2f7e6a3752378a69fadf3f5ee8bc5fa082f623703eec0f4e854b12c548322de0", size = 2365925, upload-time = "2026-04-13T09:05:38.338Z" }, - { url = "https://files.pythonhosted.org/packages/0c/75/e187b0ea247f71f2009d156df88b7d8449c52a38810c9a1bd55dd4871206/pydantic_core-2.46.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:ef47ee0a3ac4c2bb25a083b3acafb171f65be4a0ac1e84edef79dd0016e25eaa", size = 2193856, upload-time = "2026-04-13T09:05:03.114Z" }, ] [[package]] @@ -3986,12 +3206,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/49/d4/12f86b1ed09721363da4c09622464b604c851a9223fc0c6b393fb2012208/pyogrio-0.12.1.tar.gz", hash = "sha256:e548ab705bb3e5383693717de1e6c76da97f3762ab92522cb310f93128a75ff1", size = 303289, upload-time = "2025-11-28T19:04:53.341Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/02/46/b2c2dcdfd88759b56f103365905fffb85e8b08c1db1ec7c8f8b4c4c26016/pyogrio-0.12.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:01b322dac2a258d24b024d1028dcaa03c9bb6d9c3988b86d298a64873d10dc65", size = 23670744, upload-time = "2025-11-28T19:03:11.299Z" }, - { url = "https://files.pythonhosted.org/packages/d9/21/b69f1bc51d805c00dd7c484a18e1fd2e75b41da1d9f5b8591d7d9d4a7d2f/pyogrio-0.12.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:e10087abcbd6b7e8212560a7002984e5078ac7b3a969ddc2c9929044dbb0d403", size = 25246184, upload-time = "2025-11-28T19:03:13.997Z" }, - { url = "https://files.pythonhosted.org/packages/19/8c/b6aae08e8fcc4f2a903da5f6bd8f888d2b6d7290e54dde5abe15b4cca8df/pyogrio-0.12.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1f6c621972b09fd81a32317e742c69ff4a7763a803da211361a78317f9577765", size = 31434449, upload-time = "2025-11-28T19:03:16.777Z" }, - { url = "https://files.pythonhosted.org/packages/70/f9/9538fa893c29a3fdfeddf3b4c9f8db77f2d4134bc766587929fec8405ebf/pyogrio-0.12.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:c38253427b688464caad5316d4ebcec116b5e13f1f02cc4e3588502f136ca1b4", size = 30987586, upload-time = "2025-11-28T19:03:19.586Z" }, - { url = "https://files.pythonhosted.org/packages/89/a4/0aef5837b4e11840f501e48e01c31242838476c4f4aff9c05e228a083982/pyogrio-0.12.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:5f47787251de7ce13cc06038da93a1214dc283cbccf816be6e03c080358226c8", size = 32534386, upload-time = "2025-11-28T19:03:22.292Z" }, - { url = "https://files.pythonhosted.org/packages/34/97/e8f2ed8a339152b86f8403c258ae5d5f23ab32d690eeb0545bb3473d0c69/pyogrio-0.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:c1d756cf2da4cdf5609779f260d1e1e89be023184225855d6f3dcd33bbe17cb0", size = 22941718, upload-time = "2025-11-28T19:03:24.82Z" }, { url = "https://files.pythonhosted.org/packages/ad/e0/656b6536549d41b5aec57e0deca1f269b4f17532f0636836f587e581603a/pyogrio-0.12.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:7a0d5ca39184030aec4cde30f4258f75b227a854530d2659babc8189d76e657d", size = 23661857, upload-time = "2025-11-28T19:03:27.744Z" }, { url = "https://files.pythonhosted.org/packages/14/78/313259e40da728bdb60106ffdc7ea8224d164498cb838ecb79b634aab967/pyogrio-0.12.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:feaff42bbe8087ca0b30e33b09d1ce049ca55fe83ad83db1139ef37d1d04f30c", size = 25237106, upload-time = "2025-11-28T19:03:30.018Z" }, { url = "https://files.pythonhosted.org/packages/8f/ca/5368571a8b00b941ccfbe6ea29a5566aaffd45d4eb1553b956f7755af43e/pyogrio-0.12.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:81096a5139532de5a8003ef02b41d5d2444cb382a9aecd1165b447eb549180d3", size = 31417048, upload-time = "2025-11-28T19:03:32.572Z" }, @@ -4010,18 +3224,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/18/d7/da88c566e67d741a03851eb8d01358949d52e0b0fc2cd953582dc6d89ff8/pyogrio-0.12.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:f3dcc59b3316b8a0f59346bcc638a4d69997864a4d21da839192f50c4c92369a", size = 31035589, upload-time = "2025-11-28T19:04:12.993Z" }, { url = "https://files.pythonhosted.org/packages/11/ac/8f0199f0d31b8ddbc4b4ea1918df8070fdf3e0a63100b898633ec9396224/pyogrio-0.12.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:a0643e041dee3e8e038fce69f52a915ecb486e6d7b674c0f9919f3c9e9629689", size = 32487973, upload-time = "2025-11-28T19:04:16.103Z" }, { url = "https://files.pythonhosted.org/packages/bd/64/8541a27e9635a335835d234dfaeb19d6c26097fd88224eda7791f83ca98d/pyogrio-0.12.1-cp313-cp313t-win_amd64.whl", hash = "sha256:5881017f29e110d3613819667657844d8e961b747f2d35cf92f273c27af6d068", size = 22987374, upload-time = "2025-11-28T19:04:18.91Z" }, - { url = "https://files.pythonhosted.org/packages/f4/6f/b4d5e285e08c0c60bcc23b50d73038ddc7335d8de79cc25678cd486a3db0/pyogrio-0.12.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:5a1b0453d1c9e7b03715dd57296c8f3790acb8b50d7e3b5844b3074a18f50709", size = 23660673, upload-time = "2025-11-28T19:04:21.662Z" }, - { url = "https://files.pythonhosted.org/packages/8d/75/4b29e71489c5551aa1a1c5ca8c5160a60203c94f2f68c87c0e3614d58965/pyogrio-0.12.1-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:e7ee560422239dd09ca7f8284cc8483a8919c30d25f3049bb0249bff4c38dec4", size = 25232194, upload-time = "2025-11-28T19:04:23.975Z" }, - { url = "https://files.pythonhosted.org/packages/89/6e/e9929d2261a07c36301983de2767bcde90d441ab5bf1d767ce56dd07f8b4/pyogrio-0.12.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:648c6f7f5f214d30e6cf493b4af1d59782907ac068af9119ca35f18153d6865a", size = 31336936, upload-time = "2025-11-28T19:04:26.594Z" }, - { url = "https://files.pythonhosted.org/packages/1d/9e/c59941d734ed936d4e5c89b4b99cb5541307cc42b3fd466ee78a1850c177/pyogrio-0.12.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:58042584f3fd4cabb0f55d26c1405053f656be8a5c266c38140316a1e981aca0", size = 30902210, upload-time = "2025-11-28T19:04:29.143Z" }, - { url = "https://files.pythonhosted.org/packages/d1/68/cc07320a63f9c2586e60bf11d148b00e12d0e707673bffe609bbdcb7e754/pyogrio-0.12.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:b438e38e4ccbaedaa5cb5824ff5de5539315d9b2fde6547c1e816576924ee8ca", size = 32461674, upload-time = "2025-11-28T19:04:31.792Z" }, - { url = "https://files.pythonhosted.org/packages/13/bc/e4522f429c45a3b6ad28185849dd76e5c8718b780883c4795e7ee41841ae/pyogrio-0.12.1-cp314-cp314-win_amd64.whl", hash = "sha256:f1d8d8a2fea3781dc2a05982c050259261ebc0f6c5e03732d6d79d582adf9363", size = 23550575, upload-time = "2025-11-28T19:04:34.556Z" }, - { url = "https://files.pythonhosted.org/packages/bd/ac/34f0664d0e391994a7b68529ae07a96432b2b4926dbac173ddc4ec94d310/pyogrio-0.12.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:9fe7286946f35a73e6370dc5855bc7a5e8e7babf9e4a8bad7a3279a1d94c7ea9", size = 23694285, upload-time = "2025-11-28T19:04:37.833Z" }, - { url = "https://files.pythonhosted.org/packages/8a/93/873255529faff1da09d0b27287e85ec805a318c60c0c74fd7df77f94e557/pyogrio-0.12.1-cp314-cp314t-macosx_12_0_x86_64.whl", hash = "sha256:2c50345b382f1be801d654ec22c70ee974d6057d4ba7afe984b55f2192bc94ee", size = 25259825, upload-time = "2025-11-28T19:04:40.125Z" }, - { url = "https://files.pythonhosted.org/packages/27/95/4d4c3644695d99c6fa0b0b42f0d6266ae9dfaf64478a3371eaac950bdd02/pyogrio-0.12.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0db95765ac0ca935c7fe579e29451294e3ab19c317b0c59c31fbe92a69155e0", size = 31371995, upload-time = "2025-11-28T19:04:42.736Z" }, - { url = "https://files.pythonhosted.org/packages/4c/6f/71f6bcca8754c8bf55a4b7153c61c91f8ac5ba992568e9fa3e54a0ee76fd/pyogrio-0.12.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:fc882779075982b93064b3bf3d8642514a6df00d9dd752493b104817072cfb01", size = 31035498, upload-time = "2025-11-28T19:04:45.79Z" }, - { url = "https://files.pythonhosted.org/packages/fd/47/75c1aa165a988347317afab9b938a01ad25dbca559b582ea34473703dc38/pyogrio-0.12.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:806f620e0c54b54dbdd65e9b6368d24f344cda84c9343364b40a57eb3e1c4dca", size = 32496390, upload-time = "2025-11-28T19:04:48.786Z" }, - { url = "https://files.pythonhosted.org/packages/31/93/4641dc5d952f6bdb71dabad2c50e3f8a5d58396cdea6ff8f8a08bfd4f4a6/pyogrio-0.12.1-cp314-cp314t-win_amd64.whl", hash = "sha256:5399f66730978d8852ef5f44dbafa0f738e7f28f4f784349f36830b69a9d2134", size = 23620996, upload-time = "2025-11-28T19:04:51.132Z" }, ] [[package]] @@ -4042,15 +3244,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/04/90/67bd7260b4ea9b8b20b4f58afef6c223ecb3abf368eb4ec5bc2cdef81b49/pyproj-3.7.2.tar.gz", hash = "sha256:39a0cf1ecc7e282d1d30f36594ebd55c9fae1fda8a2622cee5d100430628f88c", size = 226279, upload-time = "2025-08-14T12:05:42.18Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a6/bd/f205552cd1713b08f93b09e39a3ec99edef0b3ebbbca67b486fdf1abe2de/pyproj-3.7.2-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:2514d61f24c4e0bb9913e2c51487ecdaeca5f8748d8313c933693416ca41d4d5", size = 6227022, upload-time = "2025-08-14T12:03:51.474Z" }, - { url = "https://files.pythonhosted.org/packages/75/4c/9a937e659b8b418ab573c6d340d27e68716928953273e0837e7922fcac34/pyproj-3.7.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:8693ca3892d82e70de077701ee76dd13d7bca4ae1c9d1e739d72004df015923a", size = 4625810, upload-time = "2025-08-14T12:03:53.808Z" }, - { url = "https://files.pythonhosted.org/packages/c0/7d/a9f41e814dc4d1dc54e95b2ccaf0b3ebe3eb18b1740df05fe334724c3d89/pyproj-3.7.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5e26484d80fea56273ed1555abaea161e9661d81a6c07815d54b8e883d4ceb25", size = 9638694, upload-time = "2025-08-14T12:03:55.669Z" }, - { url = "https://files.pythonhosted.org/packages/ad/ab/9bdb4a6216b712a1f9aab1c0fcbee5d3726f34a366f29c3e8c08a78d6b70/pyproj-3.7.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:281cb92847814e8018010c48b4069ff858a30236638631c1a91dd7bfa68f8a8a", size = 9493977, upload-time = "2025-08-14T12:03:57.937Z" }, - { url = "https://files.pythonhosted.org/packages/c9/db/2db75b1b6190f1137b1c4e8ef6a22e1c338e46320f6329bfac819143e063/pyproj-3.7.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9c8577f0b7bb09118ec2e57e3babdc977127dd66326d6c5d755c76b063e6d9dc", size = 10841151, upload-time = "2025-08-14T12:04:00.271Z" }, - { url = "https://files.pythonhosted.org/packages/89/f7/989643394ba23a286e9b7b3f09981496172f9e0d4512457ffea7dc47ffc7/pyproj-3.7.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a23f59904fac3a5e7364b3aa44d288234af267ca041adb2c2b14a903cd5d3ac5", size = 10751585, upload-time = "2025-08-14T12:04:02.228Z" }, - { url = "https://files.pythonhosted.org/packages/53/6d/ad928fe975a6c14a093c92e6a319ca18f479f3336bb353a740bdba335681/pyproj-3.7.2-cp311-cp311-win32.whl", hash = "sha256:f2af4ed34b2cf3e031a2d85b067a3ecbd38df073c567e04b52fa7a0202afde8a", size = 5908533, upload-time = "2025-08-14T12:04:04.821Z" }, - { url = "https://files.pythonhosted.org/packages/79/e0/b95584605cec9ed50b7ebaf7975d1c4ddeec5a86b7a20554ed8b60042bd7/pyproj-3.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:0b7cb633565129677b2a183c4d807c727d1c736fcb0568a12299383056e67433", size = 6320742, upload-time = "2025-08-14T12:04:06.357Z" }, - { url = "https://files.pythonhosted.org/packages/b7/4d/536e8f93bca808175c2d0a5ac9fdf69b960d8ab6b14f25030dccb07464d7/pyproj-3.7.2-cp311-cp311-win_arm64.whl", hash = "sha256:38b08d85e3a38e455625b80e9eb9f78027c8e2649a21dec4df1f9c3525460c71", size = 6245772, upload-time = "2025-08-14T12:04:08.365Z" }, { url = "https://files.pythonhosted.org/packages/8d/ab/9893ea9fb066be70ed9074ae543914a618c131ed8dff2da1e08b3a4df4db/pyproj-3.7.2-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:0a9bb26a6356fb5b033433a6d1b4542158fb71e3c51de49b4c318a1dff3aeaab", size = 6219832, upload-time = "2025-08-14T12:04:10.264Z" }, { url = "https://files.pythonhosted.org/packages/53/78/4c64199146eed7184eb0e85bedec60a4aa8853b6ffe1ab1f3a8b962e70a0/pyproj-3.7.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:567caa03021178861fad27fabde87500ec6d2ee173dd32f3e2d9871e40eebd68", size = 4620650, upload-time = "2025-08-14T12:04:11.978Z" }, { url = "https://files.pythonhosted.org/packages/b6/ac/14a78d17943898a93ef4f8c6a9d4169911c994e3161e54a7cedeba9d8dde/pyproj-3.7.2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:c203101d1dc3c038a56cff0447acc515dd29d6e14811406ac539c21eed422b2a", size = 9667087, upload-time = "2025-08-14T12:04:13.964Z" }, @@ -4078,24 +3271,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f2/bc/8fc7d3963d87057b7b51ebe68c1e7c51c23129eee5072ba6b86558544a46/pyproj-3.7.2-cp313-cp313t-win32.whl", hash = "sha256:2da731876d27639ff9d2d81c151f6ab90a1546455fabd93368e753047be344a2", size = 5953057, upload-time = "2025-08-14T12:04:58.466Z" }, { url = "https://files.pythonhosted.org/packages/cc/27/ea9809966cc47d2d51e6d5ae631ea895f7c7c7b9b3c29718f900a8f7d197/pyproj-3.7.2-cp313-cp313t-win_amd64.whl", hash = "sha256:f54d91ae18dd23b6c0ab48126d446820e725419da10617d86a1b69ada6d881d3", size = 6375414, upload-time = "2025-08-14T12:04:59.861Z" }, { url = "https://files.pythonhosted.org/packages/5b/f8/1ef0129fba9a555c658e22af68989f35e7ba7b9136f25758809efec0cd6e/pyproj-3.7.2-cp313-cp313t-win_arm64.whl", hash = "sha256:fc52ba896cfc3214dc9f9ca3c0677a623e8fdd096b257c14a31e719d21ff3fdd", size = 6262501, upload-time = "2025-08-14T12:05:01.39Z" }, - { url = "https://files.pythonhosted.org/packages/42/17/c2b050d3f5b71b6edd0d96ae16c990fdc42a5f1366464a5c2772146de33a/pyproj-3.7.2-cp314-cp314-macosx_13_0_x86_64.whl", hash = "sha256:2aaa328605ace41db050d06bac1adc11f01b71fe95c18661497763116c3a0f02", size = 6214541, upload-time = "2025-08-14T12:05:03.166Z" }, - { url = "https://files.pythonhosted.org/packages/03/68/68ada9c8aea96ded09a66cfd9bf87aa6db8c2edebe93f5bf9b66b0143fbc/pyproj-3.7.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:35dccbce8201313c596a970fde90e33605248b66272595c061b511c8100ccc08", size = 4617456, upload-time = "2025-08-14T12:05:04.563Z" }, - { url = "https://files.pythonhosted.org/packages/81/e4/4c50ceca7d0e937977866b02cb64e6ccf4df979a5871e521f9e255df6073/pyproj-3.7.2-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:25b0b7cb0042444c29a164b993c45c1b8013d6c48baa61dc1160d834a277e83b", size = 9615590, upload-time = "2025-08-14T12:05:06.094Z" }, - { url = "https://files.pythonhosted.org/packages/05/1e/ada6fb15a1d75b5bd9b554355a69a798c55a7dcc93b8d41596265c1772e3/pyproj-3.7.2-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:85def3a6388e9ba51f964619aa002a9d2098e77c6454ff47773bb68871024281", size = 9474960, upload-time = "2025-08-14T12:05:07.973Z" }, - { url = "https://files.pythonhosted.org/packages/51/07/9d48ad0a8db36e16f842f2c8a694c1d9d7dcf9137264846bef77585a71f3/pyproj-3.7.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b1bccefec3875ab81eabf49059e2b2ea77362c178b66fd3528c3e4df242f1516", size = 10799478, upload-time = "2025-08-14T12:05:14.102Z" }, - { url = "https://files.pythonhosted.org/packages/85/cf/2f812b529079f72f51ff2d6456b7fef06c01735e5cfd62d54ffb2b548028/pyproj-3.7.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d5371ca114d6990b675247355a801925814eca53e6c4b2f1b5c0a956336ee36e", size = 10710030, upload-time = "2025-08-14T12:05:16.317Z" }, - { url = "https://files.pythonhosted.org/packages/99/9b/4626a19e1f03eba4c0e77b91a6cf0f73aa9cb5d51a22ee385c22812bcc2c/pyproj-3.7.2-cp314-cp314-win32.whl", hash = "sha256:77f066626030f41be543274f5ac79f2a511fe89860ecd0914f22131b40a0ec25", size = 5991181, upload-time = "2025-08-14T12:05:19.492Z" }, - { url = "https://files.pythonhosted.org/packages/04/b2/5a6610554306a83a563080c2cf2c57565563eadd280e15388efa00fb5b33/pyproj-3.7.2-cp314-cp314-win_amd64.whl", hash = "sha256:5a964da1696b8522806f4276ab04ccfff8f9eb95133a92a25900697609d40112", size = 6434721, upload-time = "2025-08-14T12:05:21.022Z" }, - { url = "https://files.pythonhosted.org/packages/ae/ce/6c910ea2e1c74ef673c5d48c482564b8a7824a44c4e35cca2e765b68cfcc/pyproj-3.7.2-cp314-cp314-win_arm64.whl", hash = "sha256:e258ab4dbd3cf627809067c0ba8f9884ea76c8e5999d039fb37a1619c6c3e1f6", size = 6363821, upload-time = "2025-08-14T12:05:22.627Z" }, - { url = "https://files.pythonhosted.org/packages/e4/e4/5532f6f7491812ba782a2177fe9de73fd8e2912b59f46a1d056b84b9b8f2/pyproj-3.7.2-cp314-cp314t-macosx_13_0_x86_64.whl", hash = "sha256:bbbac2f930c6d266f70ec75df35ef851d96fdb3701c674f42fd23a9314573b37", size = 6241773, upload-time = "2025-08-14T12:05:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/20/1f/0938c3f2bbbef1789132d1726d9b0e662f10cfc22522743937f421ad664e/pyproj-3.7.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:b7544e0a3d6339dc9151e9c8f3ea62a936ab7cc446a806ec448bbe86aebb979b", size = 4652537, upload-time = "2025-08-14T12:05:26.391Z" }, - { url = "https://files.pythonhosted.org/packages/c7/a8/488b1ed47d25972f33874f91f09ca8f2227902f05f63a2b80dc73e7b1c97/pyproj-3.7.2-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:f7f5133dca4c703e8acadf6f30bc567d39a42c6af321e7f81975c2518f3ed357", size = 9940864, upload-time = "2025-08-14T12:05:27.985Z" }, - { url = "https://files.pythonhosted.org/packages/c7/cc/7f4c895d0cb98e47b6a85a6d79eaca03eb266129eed2f845125c09cf31ff/pyproj-3.7.2-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:5aff3343038d7426aa5076f07feb88065f50e0502d1b0d7c22ddfdd2c75a3f81", size = 9688868, upload-time = "2025-08-14T12:05:30.425Z" }, - { url = "https://files.pythonhosted.org/packages/b2/b7/c7e306b8bb0f071d9825b753ee4920f066c40fbfcce9372c4f3cfb2fc4ed/pyproj-3.7.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b0552178c61f2ac1c820d087e8ba6e62b29442debddbb09d51c4bf8acc84d888", size = 11045910, upload-time = "2025-08-14T12:05:32.507Z" }, - { url = "https://files.pythonhosted.org/packages/42/fb/538a4d2df695980e2dde5c04d965fbdd1fe8c20a3194dc4aaa3952a4d1be/pyproj-3.7.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:47d87db2d2c436c5fd0409b34d70bb6cdb875cca2ebe7a9d1c442367b0ab8d59", size = 10895724, upload-time = "2025-08-14T12:05:35.465Z" }, - { url = "https://files.pythonhosted.org/packages/e8/8b/a3f0618b03957de9db5489a04558a8826f43906628bb0b766033aa3b5548/pyproj-3.7.2-cp314-cp314t-win32.whl", hash = "sha256:c9b6f1d8ad3e80a0ee0903a778b6ece7dca1d1d40f6d114ae01bc8ddbad971aa", size = 6056848, upload-time = "2025-08-14T12:05:37.553Z" }, - { url = "https://files.pythonhosted.org/packages/bc/56/413240dd5149dd3291eda55aa55a659da4431244a2fd1319d0ae89407cfb/pyproj-3.7.2-cp314-cp314t-win_amd64.whl", hash = "sha256:1914e29e27933ba6f9822663ee0600f169014a2859f851c054c88cf5ea8a333c", size = 6517676, upload-time = "2025-08-14T12:05:39.126Z" }, - { url = "https://files.pythonhosted.org/packages/15/73/a7141a1a0559bf1a7aa42a11c879ceb19f02f5c6c371c6d57fd86cefd4d1/pyproj-3.7.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d9d25bae416a24397e0d85739f84d323b55f6511e45a522dd7d7eae70d10c7e4", size = 6391844, upload-time = "2025-08-14T12:05:40.745Z" }, ] [[package]] @@ -4169,17 +3344,12 @@ version = "7.4.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0f/0f/34e7ee0a72f1464b4c7a2e8bafb389f230477256af586bc82bcfad85295a/python_box-7.4.1.tar.gz", hash = "sha256:e412e36c25fca8223560516d53ef6c7993591c3b0ec8bb4ec582bf7defdd79f0", size = 49859, upload-time = "2026-02-21T16:21:16.008Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/a8/c8bcd3ff0905ec549273ea3485e6b9f2039f57baab419123fb18f964f829/python_box-7.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3f76dad8be9d57d65a3edc792b952f7afe3991515aa6eba616cf5efb2fbb2e0c", size = 1870869, upload-time = "2026-02-21T16:21:34.16Z" }, - { url = "https://files.pythonhosted.org/packages/0f/bc/9382766d388e258363a18a094e251d2624e3c524614c733d1afa989d9770/python_box-7.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c66582f41a94d46cb0896d468b0efebf9bc4c3a5634cd15373d871767c2e741d", size = 4494287, upload-time = "2026-02-21T16:26:03.131Z" }, - { url = "https://files.pythonhosted.org/packages/8c/cf/b9d1d4550615f69f6f9c72767f026543442739e5c56adf6f844b50d88251/python_box-7.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:43c62f66d694eb6410f51eb2eb5726f9b466e6f685e5dc90b5cd11f7b3047362", size = 1321085, upload-time = "2026-02-21T16:22:01.093Z" }, { url = "https://files.pythonhosted.org/packages/4d/d9/d05f317b38b42253422d8483f5d7dc16d382c99ddc253e426639a0f2f235/python_box-7.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dfb91effff00d9e23486c4f0db3b19e03d602ebb7c9e20fc6a287c704fad2552", size = 1849441, upload-time = "2026-02-21T16:21:37.314Z" }, { url = "https://files.pythonhosted.org/packages/ba/a3/383eb3d658f36c6e531c8cf1e348ccb4b5031231df4aeb7742bb159a3166/python_box-7.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f977f00e715b030cee6ffef2322ff8ce100ffbf1dbcc4ef91099c75752d5f8", size = 4485153, upload-time = "2026-02-21T16:26:04.507Z" }, { url = "https://files.pythonhosted.org/packages/65/f9/5de3c18415dd6f5286f00e6539c0ae3cceb1c6aaf28d1d5f17b0b568c97f/python_box-7.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:2ca9a18fd15326bc267e9cc7e0e6e3a0cb78d11507940f43f687adf7e156d882", size = 1295520, upload-time = "2026-02-21T16:22:26.192Z" }, { url = "https://files.pythonhosted.org/packages/ec/e9/48d1b1eb21efc3f82a31b037b6903c9139018f686d96d251faa4cb0d593a/python_box-7.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:85db37b43094bf6c4884b931fb149a7850db5ce331f6e191edf98b453e6cf2d6", size = 1845195, upload-time = "2026-02-21T16:21:46.235Z" }, { url = "https://files.pythonhosted.org/packages/da/79/48d38c855f277223caf3aa79518476f95abc07f04386940855b7bd3d95f6/python_box-7.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bb204822c7638bd2dbed5c55d6ab264c6903c37d18dee5c45bdbda58b2e1e17a", size = 4468245, upload-time = "2026-02-21T16:26:05.701Z" }, { url = "https://files.pythonhosted.org/packages/17/1d/7a1e04f37674399e0f3076cfe1fa358f6a51540ae98299a06f2c0424c471/python_box-7.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:615da3fafd41572aec1b905832555c0ea08b6fbc27cc917356e257a9a5721af7", size = 1295564, upload-time = "2026-02-21T16:22:36.547Z" }, - { url = "https://files.pythonhosted.org/packages/94/a2/771b5e526bba2214ac2d30e321209a66680c40788616a45cf01005e95204/python_box-7.4.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:33c6701faa51fd87f0dcc538873c0fad2b3a1cc3750eab85835cd071cadf1948", size = 1875508, upload-time = "2026-02-21T16:21:37.432Z" }, - { url = "https://files.pythonhosted.org/packages/a6/5f/0e7ea7640ba60ff459ce37e340d816ac5e91b7a9a7c3c161f9dabe622be6/python_box-7.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:ae8c540a0457f52350211d24690211251912018e1e0c1857f50792729d6f562c", size = 1314304, upload-time = "2026-02-21T16:22:22.173Z" }, { url = "https://files.pythonhosted.org/packages/06/a6/5d3f3abf46b37aa44b1f6788d287c8b4f2319b55013191dddf25b9e6d62c/python_box-7.4.1-py3-none-any.whl", hash = "sha256:a3b0d84d003882fb6abe505b1b883b3a5dcbf226b0fe168d24bc5ff75d9826e5", size = 30402, upload-time = "2026-02-21T16:21:14.78Z" }, ] @@ -4232,11 +3402,6 @@ version = "0.4.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/92/790ebe03f07b57e53b10884c329b9a1a308648fc083a6d4a39a10a28c8fc/pytokens-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d70e77c55ae8380c91c0c18dea05951482e263982911fc7410b1ffd1dadd3440", size = 160864, upload-time = "2026-01-30T01:02:57.882Z" }, - { url = "https://files.pythonhosted.org/packages/13/25/a4f555281d975bfdd1eba731450e2fe3a95870274da73fb12c40aeae7625/pytokens-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a58d057208cb9075c144950d789511220b07636dd2e4708d5645d24de666bdc", size = 248565, upload-time = "2026-01-30T01:02:59.912Z" }, - { url = "https://files.pythonhosted.org/packages/17/50/bc0394b4ad5b1601be22fa43652173d47e4c9efbf0044c62e9a59b747c56/pytokens-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b49750419d300e2b5a3813cf229d4e5a4c728dae470bcc89867a9ad6f25a722d", size = 260824, upload-time = "2026-01-30T01:03:01.471Z" }, - { url = "https://files.pythonhosted.org/packages/4e/54/3e04f9d92a4be4fc6c80016bc396b923d2a6933ae94b5f557c939c460ee0/pytokens-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9907d61f15bf7261d7e775bd5d7ee4d2930e04424bab1972591918497623a16", size = 264075, upload-time = "2026-01-30T01:03:04.143Z" }, - { url = "https://files.pythonhosted.org/packages/d1/1b/44b0326cb5470a4375f37988aea5d61b5cc52407143303015ebee94abfd6/pytokens-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:ee44d0f85b803321710f9239f335aafe16553b39106384cef8e6de40cb4ef2f6", size = 103323, upload-time = "2026-01-30T01:03:05.412Z" }, { url = "https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", size = 160663, upload-time = "2026-01-30T01:03:06.473Z" }, { url = "https://files.pythonhosted.org/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", size = 255626, upload-time = "2026-01-30T01:03:08.177Z" }, { url = "https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", size = 269779, upload-time = "2026-01-30T01:03:09.756Z" }, @@ -4247,16 +3412,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e0/d2/afe5c7f8607018beb99971489dbb846508f1b8f351fcefc225fcf4b2adc0/pytokens-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29d1d8fb1030af4d231789959f21821ab6325e463f0503a61d204343c9b355d1", size = 268423, upload-time = "2026-01-30T01:03:15.936Z" }, { url = "https://files.pythonhosted.org/packages/68/d4/00ffdbd370410c04e9591da9220a68dc1693ef7499173eb3e30d06e05ed1/pytokens-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b08dd6b86058b6dc07efe9e98414f5102974716232d10f32ff39701e841c4", size = 266859, upload-time = "2026-01-30T01:03:17.458Z" }, { url = "https://files.pythonhosted.org/packages/a7/c9/c3161313b4ca0c601eeefabd3d3b576edaa9afdefd32da97210700e47652/pytokens-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:9bd7d7f544d362576be74f9d5901a22f317efc20046efe2034dced238cbbfe78", size = 103520, upload-time = "2026-01-30T01:03:18.652Z" }, - { url = "https://files.pythonhosted.org/packages/8f/a7/b470f672e6fc5fee0a01d9e75005a0e617e162381974213a945fcd274843/pytokens-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4a14d5f5fc78ce85e426aa159489e2d5961acf0e47575e08f35584009178e321", size = 160821, upload-time = "2026-01-30T01:03:19.684Z" }, - { url = "https://files.pythonhosted.org/packages/80/98/e83a36fe8d170c911f864bfded690d2542bfcfacb9c649d11a9e6eb9dc41/pytokens-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f50fd18543be72da51dd505e2ed20d2228c74e0464e4262e4899797803d7fa", size = 254263, upload-time = "2026-01-30T01:03:20.834Z" }, - { url = "https://files.pythonhosted.org/packages/0f/95/70d7041273890f9f97a24234c00b746e8da86df462620194cef1d411ddeb/pytokens-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc74c035f9bfca0255c1af77ddd2d6ae8419012805453e4b0e7513e17904545d", size = 268071, upload-time = "2026-01-30T01:03:21.888Z" }, - { url = "https://files.pythonhosted.org/packages/da/79/76e6d09ae19c99404656d7db9c35dfd20f2086f3eb6ecb496b5b31163bad/pytokens-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f66a6bbe741bd431f6d741e617e0f39ec7257ca1f89089593479347cc4d13324", size = 271716, upload-time = "2026-01-30T01:03:23.633Z" }, - { url = "https://files.pythonhosted.org/packages/79/37/482e55fa1602e0a7ff012661d8c946bafdc05e480ea5a32f4f7e336d4aa9/pytokens-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:b35d7e5ad269804f6697727702da3c517bb8a5228afa450ab0fa787732055fc9", size = 104539, upload-time = "2026-01-30T01:03:24.788Z" }, - { url = "https://files.pythonhosted.org/packages/30/e8/20e7db907c23f3d63b0be3b8a4fd1927f6da2395f5bcc7f72242bb963dfe/pytokens-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8fcb9ba3709ff77e77f1c7022ff11d13553f3c30299a9fe246a166903e9091eb", size = 168474, upload-time = "2026-01-30T01:03:26.428Z" }, - { url = "https://files.pythonhosted.org/packages/d6/81/88a95ee9fafdd8f5f3452107748fd04c24930d500b9aba9738f3ade642cc/pytokens-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79fc6b8699564e1f9b521582c35435f1bd32dd06822322ec44afdeba666d8cb3", size = 290473, upload-time = "2026-01-30T01:03:27.415Z" }, - { url = "https://files.pythonhosted.org/packages/cf/35/3aa899645e29b6375b4aed9f8d21df219e7c958c4c186b465e42ee0a06bf/pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975", size = 303485, upload-time = "2026-01-30T01:03:28.558Z" }, - { url = "https://files.pythonhosted.org/packages/52/a0/07907b6ff512674d9b201859f7d212298c44933633c946703a20c25e9d81/pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a", size = 306698, upload-time = "2026-01-30T01:03:29.653Z" }, - { url = "https://files.pythonhosted.org/packages/39/2a/cbbf9250020a4a8dd53ba83a46c097b69e5eb49dd14e708f496f548c6612/pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918", size = 116287, upload-time = "2026-01-30T01:03:30.912Z" }, { 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" }, ] @@ -4275,18 +3430,12 @@ version = "3.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f7/54/37c7370ba91f579235049dc26cd2c5e657d2a943e01820844ffc81f32176/pywinpty-3.0.3.tar.gz", hash = "sha256:523441dc34d231fb361b4b00f8c99d3f16de02f5005fd544a0183112bcc22412", size = 31309, upload-time = "2026-02-04T21:51:09.524Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/79/c3/3e75075c7f71735f22b66fab0481f2c98e3a4d58cba55cb50ba29114bcf6/pywinpty-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:dff25a9a6435f527d7c65608a7e62783fc12076e7d44487a4911ee91be5a8ac8", size = 2114430, upload-time = "2026-02-04T21:54:19.485Z" }, - { url = "https://files.pythonhosted.org/packages/8d/1e/8a54166a8c5e4f5cb516514bdf4090be4d51a71e8d9f6d98c0aa00fe45d4/pywinpty-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:fbc1e230e5b193eef4431cba3f39996a288f9958f9c9f092c8a961d930ee8f68", size = 236191, upload-time = "2026-02-04T21:50:36.239Z" }, { url = "https://files.pythonhosted.org/packages/7c/d4/aeb5e1784d2c5bff6e189138a9ca91a090117459cea0c30378e1f2db3d54/pywinpty-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:c9081df0e49ffa86d15db4a6ba61530630e48707f987df42c9d3313537e81fc0", size = 2113098, upload-time = "2026-02-04T21:54:37.711Z" }, { url = "https://files.pythonhosted.org/packages/b9/53/7278223c493ccfe4883239cf06c823c56460a8010e0fc778eef67858dc14/pywinpty-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:15e79d870e18b678fb8a5a6105fd38496b55697c66e6fc0378236026bc4d59e9", size = 234901, upload-time = "2026-02-04T21:53:31.35Z" }, { url = "https://files.pythonhosted.org/packages/e5/cb/58d6ed3fd429c96a90ef01ac9a617af10a6d41469219c25e7dc162abbb71/pywinpty-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9c91dbb026050c77bdcef964e63a4f10f01a639113c4d3658332614544c467ab", size = 2112686, upload-time = "2026-02-04T21:52:03.035Z" }, { url = "https://files.pythonhosted.org/packages/fd/50/724ed5c38c504d4e58a88a072776a1e880d970789deaeb2b9f7bd9a5141a/pywinpty-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:fe1f7911805127c94cf51f89ab14096c6f91ffdcacf993d2da6082b2142a2523", size = 234591, upload-time = "2026-02-04T21:52:29.821Z" }, { url = "https://files.pythonhosted.org/packages/f7/ad/90a110538696b12b39fd8758a06d70ded899308198ad2305ac68e361126e/pywinpty-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:3f07a6cf1c1d470d284e614733c3d0f726d2c85e78508ea10a403140c3c0c18a", size = 2112360, upload-time = "2026-02-04T21:55:33.397Z" }, { url = "https://files.pythonhosted.org/packages/44/0f/7ffa221757a220402bc79fda44044c3f2cc57338d878ab7d622add6f4581/pywinpty-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:15c7c0b6f8e9d87aabbaff76468dabf6e6121332c40fc1d83548d02a9d6a3759", size = 233107, upload-time = "2026-02-04T21:51:45.455Z" }, - { url = "https://files.pythonhosted.org/packages/28/88/2ff917caff61e55f38bcdb27de06ee30597881b2cae44fbba7627be015c4/pywinpty-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:d4b6b7b0fe0cdcd02e956bd57cfe9f4e5a06514eecf3b5ae174da4f951b58be9", size = 2113282, upload-time = "2026-02-04T21:52:08.188Z" }, - { url = "https://files.pythonhosted.org/packages/63/32/40a775343ace542cc43ece3f1d1fce454021521ecac41c4c4573081c2336/pywinpty-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:34789d685fc0d547ce0c8a65e5a70e56f77d732fa6e03c8f74fefb8cbb252019", size = 234207, upload-time = "2026-02-04T21:51:58.687Z" }, - { url = "https://files.pythonhosted.org/packages/8d/54/5d5e52f4cb75028104ca6faf36c10f9692389b1986d34471663b4ebebd6d/pywinpty-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:0c37e224a47a971d1a6e08649a1714dac4f63c11920780977829ed5c8cadead1", size = 2112910, upload-time = "2026-02-04T21:52:30.976Z" }, - { url = "https://files.pythonhosted.org/packages/0a/44/dcd184824e21d4620b06c7db9fbb15c3ad0a0f1fa2e6de79969fb82647ec/pywinpty-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:c4e9c3dff7d86ba81937438d5819f19f385a39d8f592d4e8af67148ceb4f6ab5", size = 233425, upload-time = "2026-02-04T21:51:56.754Z" }, ] [[package]] @@ -4295,15 +3444,6 @@ version = "6.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, - { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, - { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, - { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, - { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, - { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, - { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, - { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, - { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, @@ -4324,24 +3464,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, - { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, - { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, - { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, - { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, - { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, - { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, - { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, - { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, - { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, - { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, - { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, - { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, ] [[package]] @@ -4389,16 +3511,6 @@ dependencies = [ ] 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/06/5d/305323ba86b284e6fcb0d842d6adaa2999035f70f8c38a9b6d21ad28c3d4/pyzmq-27.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:226b091818d461a3bef763805e75685e478ac17e9008f49fce2d3e52b3d58b86", size = 1333328, upload-time = "2025-09-08T23:07:45.946Z" }, - { url = "https://files.pythonhosted.org/packages/bd/a0/fc7e78a23748ad5443ac3275943457e8452da67fda347e05260261108cbc/pyzmq-27.1.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0790a0161c281ca9723f804871b4027f2e8b5a528d357c8952d08cd1a9c15581", size = 908803, upload-time = "2025-09-08T23:07:47.551Z" }, - { url = "https://files.pythonhosted.org/packages/7e/22/37d15eb05f3bdfa4abea6f6d96eb3bb58585fbd3e4e0ded4e743bc650c97/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c895a6f35476b0c3a54e3eb6ccf41bf3018de937016e6e18748317f25d4e925f", size = 668836, upload-time = "2025-09-08T23:07:49.436Z" }, - { url = "https://files.pythonhosted.org/packages/b1/c4/2a6fe5111a01005fc7af3878259ce17684fabb8852815eda6225620f3c59/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bbf8d3630bf96550b3be8e1fc0fea5cbdc8d5466c1192887bd94869da17a63e", size = 857038, upload-time = "2025-09-08T23:07:51.234Z" }, - { url = "https://files.pythonhosted.org/packages/cb/eb/bfdcb41d0db9cd233d6fb22dc131583774135505ada800ebf14dfb0a7c40/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15c8bd0fe0dabf808e2d7a681398c4e5ded70a551ab47482067a572c054c8e2e", size = 1657531, upload-time = "2025-09-08T23:07:52.795Z" }, - { url = "https://files.pythonhosted.org/packages/ab/21/e3180ca269ed4a0de5c34417dfe71a8ae80421198be83ee619a8a485b0c7/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bafcb3dd171b4ae9f19ee6380dfc71ce0390fefaf26b504c0e5f628d7c8c54f2", size = 2034786, upload-time = "2025-09-08T23:07:55.047Z" }, - { url = "https://files.pythonhosted.org/packages/3b/b1/5e21d0b517434b7f33588ff76c177c5a167858cc38ef740608898cd329f2/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e829529fcaa09937189178115c49c504e69289abd39967cd8a4c215761373394", size = 1894220, upload-time = "2025-09-08T23:07:57.172Z" }, - { url = "https://files.pythonhosted.org/packages/03/f2/44913a6ff6941905efc24a1acf3d3cb6146b636c546c7406c38c49c403d4/pyzmq-27.1.0-cp311-cp311-win32.whl", hash = "sha256:6df079c47d5902af6db298ec92151db82ecb557af663098b92f2508c398bb54f", size = 567155, upload-time = "2025-09-08T23:07:59.05Z" }, - { url = "https://files.pythonhosted.org/packages/23/6d/d8d92a0eb270a925c9b4dd039c0b4dc10abc2fcbc48331788824ef113935/pyzmq-27.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:190cbf120fbc0fc4957b56866830def56628934a9d112aec0e2507aa6a032b97", size = 633428, upload-time = "2025-09-08T23:08:00.663Z" }, - { url = "https://files.pythonhosted.org/packages/ae/14/01afebc96c5abbbd713ecfc7469cfb1bc801c819a74ed5c9fad9a48801cb/pyzmq-27.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:eca6b47df11a132d1745eb3b5b5e557a7dae2c303277aa0e69c6ba91b8736e07", size = 559497, upload-time = "2025-09-08T23:08:02.15Z" }, { 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" }, @@ -4421,21 +3533,6 @@ wheels = [ { 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" }, - { url = "https://files.pythonhosted.org/packages/4c/c6/c4dcdecdbaa70969ee1fdced6d7b8f60cfabe64d25361f27ac4665a70620/pyzmq-27.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:18770c8d3563715387139060d37859c02ce40718d1faf299abddcdcc6a649066", size = 836265, upload-time = "2025-09-08T23:09:49.376Z" }, - { url = "https://files.pythonhosted.org/packages/3e/79/f38c92eeaeb03a2ccc2ba9866f0439593bb08c5e3b714ac1d553e5c96e25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ac25465d42f92e990f8d8b0546b01c391ad431c3bf447683fdc40565941d0604", size = 800208, upload-time = "2025-09-08T23:09:51.073Z" }, - { url = "https://files.pythonhosted.org/packages/49/0e/3f0d0d335c6b3abb9b7b723776d0b21fa7f3a6c819a0db6097059aada160/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53b40f8ae006f2734ee7608d59ed661419f087521edbfc2149c3932e9c14808c", size = 567747, upload-time = "2025-09-08T23:09:52.698Z" }, - { url = "https://files.pythonhosted.org/packages/a1/cf/f2b3784d536250ffd4be70e049f3b60981235d70c6e8ce7e3ef21e1adb25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f605d884e7c8be8fe1aa94e0a783bf3f591b84c24e4bc4f3e7564c82ac25e271", size = 747371, upload-time = "2025-09-08T23:09:54.563Z" }, - { url = "https://files.pythonhosted.org/packages/01/1b/5dbe84eefc86f48473947e2f41711aded97eecef1231f4558f1f02713c12/pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355", size = 544862, upload-time = "2025-09-08T23:09:56.509Z" }, ] [[package]] @@ -4450,92 +3547,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3c/26/1062c7ec1b053db9e499b4d2d5bc231743201b74051c973dadeac80a8f43/questionary-2.1.1-py3-none-any.whl", hash = "sha256:a51af13f345f1cdea62347589fbb6df3b290306ab8930713bfae4d475a7d4a59", size = 36753, upload-time = "2025-08-28T19:00:19.56Z" }, ] -[[package]] -name = "rasterio" -version = "1.4.4" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.12' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version < '3.12' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version < '3.12' and sys_platform == 'emscripten'", - "python_full_version < '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] -dependencies = [ - { name = "affine", marker = "python_full_version < '3.12'" }, - { name = "attrs", marker = "python_full_version < '3.12'" }, - { name = "certifi", marker = "python_full_version < '3.12'" }, - { name = "click", marker = "python_full_version < '3.12'" }, - { name = "click-plugins", marker = "python_full_version < '3.12'" }, - { name = "cligj", marker = "python_full_version < '3.12'" }, - { name = "numpy", marker = "python_full_version < '3.12'" }, - { name = "pyparsing", marker = "python_full_version < '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ec/fa/fce8dc9f09e5bc6520b6fc1b4ecfa510af9ca06eb42ad7bdff9c9b8989d0/rasterio-1.4.4.tar.gz", hash = "sha256:c95424e2c7f009b8f7df1095d645c52895cd332c0c2e1b4c2e073ea28b930320", size = 445004, upload-time = "2025-12-12T18:01:08.971Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/0d/d3859e49ab94464de2623fec82c6798d8d7c8bea2473cd2696fc5e09f717/rasterio-1.4.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:b8eea428b5f0c78a963f6003a19b60777df83a0aba8c28231d65431e32ac160e", size = 21144125, upload-time = "2025-12-12T17:58:59.511Z" }, - { url = "https://files.pythonhosted.org/packages/aa/3c/97ba4b146309cdc0e36f289b02ac69465b026a21afc828e4e4e1dc39466a/rasterio-1.4.4-cp311-cp311-macosx_15_0_x86_64.whl", hash = "sha256:1cc0ea5aa0d22f5f349aa221674481de689b7b3a99607ce6bb58a29e5be54d17", size = 25746406, upload-time = "2025-12-12T17:59:02.902Z" }, - { url = "https://files.pythonhosted.org/packages/ce/33/75f81bd837ac2336b24456fdb249597a4b9af2a212b7151f64d09022be36/rasterio-1.4.4-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:7eb25b23666b29dadfc49a59206cead62c99190584b61771bba0e95f7da06801", size = 34587242, upload-time = "2025-12-12T17:59:05.848Z" }, - { url = "https://files.pythonhosted.org/packages/f9/77/3869a426f6e752dde13f3868cdf16253ca0214f92107db79c1583c9aa07b/rasterio-1.4.4-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e24b7b8c2df801dde2a1dffb44c58902bd76b5cab740dc11de4ff9963992a71a", size = 35881871, upload-time = "2025-12-12T17:59:09.779Z" }, - { url = "https://files.pythonhosted.org/packages/66/d0/3818859ddbd3750d0ef5a6580a3272e81764286d943c689dd41e49b8b786/rasterio-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:0718630f607be2f5742d8e4b34b434746fd788a192d77eefc9bb924399fea802", size = 25716477, upload-time = "2025-12-12T17:59:13.519Z" }, - { url = "https://files.pythonhosted.org/packages/4b/02/039eb4970c93aaef4c9eb1ee159abad18e6e7f932c2eed575c95f78d94f6/rasterio-1.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:0308ff4762ae9eb40a991f12d758626b59af4376b13675480391dd7295d17bbf", size = 24075993, upload-time = "2025-12-12T17:59:16.407Z" }, - { url = "https://files.pythonhosted.org/packages/4c/fc/63d89ddfcb4643730553683ee322566b9b15fe56d026e4c21c4f4f5d9d26/rasterio-1.4.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:f3c4f0cbd188f893011f2a0a6dc2852b3892799b3a0d79eddf92f2b115ec7ed7", size = 21120715, upload-time = "2025-12-12T17:59:19.35Z" }, - { url = "https://files.pythonhosted.org/packages/43/70/2c003f76a23dbb078fdee35c8e2ec490d2ad8982f4dc956ba08b56027b87/rasterio-1.4.4-cp312-cp312-macosx_15_0_x86_64.whl", hash = "sha256:6fce26090b9f509eab337228420145947c491a13628965410f25bc3e6e05cf75", size = 25732944, upload-time = "2025-12-12T17:59:22.533Z" }, - { url = "https://files.pythonhosted.org/packages/f6/cc/4a8e92362c0ff496dd1007c3dcba66e9ededf1a45eca8ad1db302b071c49/rasterio-1.4.4-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:c1c722da390dc264aeccdc0dc200ca37923875d910ca4cd5bec0fec351bb818e", size = 34295209, upload-time = "2025-12-12T17:59:26.035Z" }, - { url = "https://files.pythonhosted.org/packages/e6/6d/717d2dec47fbefad33ca0d27bd5f0d543b1d1bc9fcab5ef82a13adaaf38d/rasterio-1.4.4-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:98b6dfb8282b2a54b9d75c3dc8d2520a69bbc66916c7d43de8e0bbf6e0240ca1", size = 35661866, upload-time = "2025-12-12T17:59:29.928Z" }, - { url = "https://files.pythonhosted.org/packages/ed/60/ae3351fba2726ec0976974ce2eb030c159edd3363b8771e832b8db571c24/rasterio-1.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:9513f4c7a6d93b45098f8dff2421fa9516604e3bfbf35aa144484a88d36a321f", size = 25682853, upload-time = "2025-12-12T17:59:35.869Z" }, - { url = "https://files.pythonhosted.org/packages/38/ee/35387296bbacfc5cbbb4273228b1b959793d3ce38b0402a07f11a248420b/rasterio-1.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:60b49a482e0f12f12ce9d2cc3090add02f89f3d422e85f2cffaa9207adb83c04", size = 24043249, upload-time = "2025-12-12T17:59:39.915Z" }, - { url = "https://files.pythonhosted.org/packages/c1/fe/e3e37041c49956f4f4cbe473c3fe290aaba96ed20e9c07da304e0cad2015/rasterio-1.4.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:df26c96aa81ffbd0b33189680859211eadf9950123c21579f84de73bb0f91d81", size = 21107336, upload-time = "2025-12-12T17:59:43.585Z" }, - { url = "https://files.pythonhosted.org/packages/f3/02/c217fdcc8e80a4b7d1b1bc4529d78f98452816e9add53ff8742049a77ae7/rasterio-1.4.4-cp313-cp313-macosx_15_0_x86_64.whl", hash = "sha256:b3af0ecc922a80f3755516629f7948e37bade9077b5f5c12a3869a5e7f01619b", size = 25719929, upload-time = "2025-12-12T17:59:47.64Z" }, - { url = "https://files.pythonhosted.org/packages/c0/d0/7f177f37bc9595d809dabb0073abd0c42358469f6b10875192b46331c652/rasterio-1.4.4-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:7ce3b0f9a22e95a27790087908753973644d7c3877d495ec9bd6e04a25233ca4", size = 34198845, upload-time = "2025-12-12T17:59:52.405Z" }, - { url = "https://files.pythonhosted.org/packages/7b/84/66c0d9cca2a09074ec2ce6fffa87709ca51b0d197ae742d835e841bac660/rasterio-1.4.4-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c072450caa96428b1218b030500bb908fd6f09bc013a88969ff81a124b6a112a", size = 35576074, upload-time = "2025-12-12T17:59:56.392Z" }, - { url = "https://files.pythonhosted.org/packages/32/68/f7df5478458ace2fa50be43e9fab1a39957a0e71afaa3e6147ec289e0fc8/rasterio-1.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:16ee92ef10c0ba89f45f9c2b40fca9f971f357385f04ee9b716fb09cbd9ce20c", size = 25680573, upload-time = "2025-12-12T18:00:00.45Z" }, - { url = "https://files.pythonhosted.org/packages/34/e5/1bdaccb658430dfd391ad4a63d206546f36639d7e4130bf31f125c6525b4/rasterio-1.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:65c10afe64b5e488185aaff0b659e08eda22c89285b54a3e433b80e6c6621770", size = 24040367, upload-time = "2025-12-12T18:00:04.443Z" }, - { url = "https://files.pythonhosted.org/packages/32/76/54643a7d1d650fd7f1acea9093c298603e4c01bba6f90be2254310b48507/rasterio-1.4.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:18c2c1130e789dc2771d0aa5ec4b56d5b8a0097c648ccb94882d5ff3ab55c928", size = 21247203, upload-time = "2025-12-12T18:00:07.547Z" }, - { url = "https://files.pythonhosted.org/packages/76/ef/434b4849ccd6a3e03a0b1ac37c963c1771564945745613d15c5d96ce768d/rasterio-1.4.4-cp313-cp313t-macosx_15_0_x86_64.whl", hash = "sha256:2d1654b7ffa6f3dde42c5fd27159ae45148c11e352de26f12fe7313a3236aeed", size = 25822050, upload-time = "2025-12-12T18:00:11.081Z" }, - { url = "https://files.pythonhosted.org/packages/2d/fa/fe9a478aa0cde246da58baeb0df3248c7ca174e4d9c9b27e81b504e40a76/rasterio-1.4.4-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c4022cbddb659856e120603b12233cec8913ae760fff220657ce888c3c6b9f9d", size = 34833783, upload-time = "2025-12-12T18:00:14.525Z" }, - { url = "https://files.pythonhosted.org/packages/04/cd/ed4716590dbcd4b8ae633417d758564e510bee4d6aaac5050a0f6d5179c5/rasterio-1.4.4-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:96b88880551a07b7a3b50439483cefbd9af91a09e19ff2b736815994e5671314", size = 35738114, upload-time = "2025-12-12T18:00:17.96Z" }, - { url = "https://files.pythonhosted.org/packages/7e/29/da7050d11ba1d041e0333ac14768e6e9ca1aa2b9fa8416f317d2650ed276/rasterio-1.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:def75d486d0ab8f306f918a913c425ed57159495518c54efe8e18d5164d37d90", size = 25896835, upload-time = "2025-12-12T18:00:21.411Z" }, - { url = "https://files.pythonhosted.org/packages/88/80/304dbe5434c4aa8dfaf90480c16d770161796a6a61fa88e72e8a402153df/rasterio-1.4.4-cp313-cp313t-win_arm64.whl", hash = "sha256:770b7e86f6c565e6f9cf30f6fa4479a5a2bab4e10ff44fe7acfd518ca4a71d1b", size = 24128074, upload-time = "2025-12-12T18:00:24.653Z" }, - { url = "https://files.pythonhosted.org/packages/03/01/d5a3dc51cd5fef62b76ecc77d33c1ca20de305fed7e16c71bcdf4858e466/rasterio-1.4.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:019693f14a83ae9225cb57c16e466901d0e6284962dcf13a9f4bb1175b979011", size = 21120237, upload-time = "2025-12-12T18:00:27.723Z" }, - { url = "https://files.pythonhosted.org/packages/50/da/db18362602b17327c0e00c9e9c0847c1c4ac657c1a289169ca06a26faccb/rasterio-1.4.4-cp314-cp314-macosx_15_0_x86_64.whl", hash = "sha256:87d7c3e97e3b40c9041d1602e2dcb4fc2d88abe6c645fccb4939dec297a91cf8", size = 25720506, upload-time = "2025-12-12T18:00:30.592Z" }, - { url = "https://files.pythonhosted.org/packages/5a/8f/a15d66c9c05bffb176c9707ef1f2bfcf9c0b835272937c80ac7207a20b5c/rasterio-1.4.4-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:a2401e4c43a31c7382154d4042b60a63b9bca5886802983c5c9362cdc5b09548", size = 34153931, upload-time = "2025-12-12T18:00:33.852Z" }, - { url = "https://files.pythonhosted.org/packages/05/2d/cd778286b910db7a3f0bc1743ca362173f1fbb7365137e4982ca857b6d26/rasterio-1.4.4-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:6c4287d8934d953f7870b8e2a1df1096fbf47eba39ad0f777a31ea500f4e5010", size = 35421139, upload-time = "2025-12-12T18:00:37.482Z" }, - { url = "https://files.pythonhosted.org/packages/70/97/13a2e33aede8d7a42178c696a6a93868d1f9560f73de05033a1675f0806a/rasterio-1.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:c3ba1871549221140661227dd4fa1f9a472ded4a6d2f2c2e367b0648bb15b99d", size = 26419132, upload-time = "2025-12-12T18:00:40.871Z" }, - { url = "https://files.pythonhosted.org/packages/27/d8/2dcfcb362d6a2fd07c14cfb803a345a7926d4d9fb6243e196df105671e97/rasterio-1.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:7c9d7dc824cb8d222808be153643cd4e65ea3e1f66019ada1ccd630221edfe30", size = 24800998, upload-time = "2025-12-12T18:00:45.332Z" }, - { url = "https://files.pythonhosted.org/packages/13/f8/16e9b648e7f16cadb41df7c0116dbab26b4a2ba02c85cbe3f744065bdf56/rasterio-1.4.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:98e17bded830a59992d9f8f8d9f227ce1c4be0694930afcc4360358f5cb1a5db", size = 21247046, upload-time = "2025-12-12T18:00:49.429Z" }, - { url = "https://files.pythonhosted.org/packages/a8/ea/f3dc3a25d7591821d488f5c5eb89f6abcd1f5c8e2ef4bd2792f965cbc9c8/rasterio-1.4.4-cp314-cp314t-macosx_15_0_x86_64.whl", hash = "sha256:56134ca203f952855e60774b06672033cf65057eb9810fcc5c1a75f1921053a3", size = 25821677, upload-time = "2025-12-12T18:00:52.458Z" }, - { url = "https://files.pythonhosted.org/packages/2e/d3/1e038350218e852f904c8dc4ab751aa023a2e82e68998767b7b42e33832c/rasterio-1.4.4-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:52edde65515b33fe4314c8a44a9ee2fc00b550deed6d56e1a8d085d42bbca3e6", size = 34829572, upload-time = "2025-12-12T18:00:56.294Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ce/28abf7a5f5d9cb014c2e14cc396bebe953b3deefbf604d49f4322e73fa35/rasterio-1.4.4-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:d61d3f2c171c64050bd75e54a5d964ff7f165b3f5d2b92c9ee09b9716aa1b8bf", size = 35735171, upload-time = "2025-12-12T18:00:59.531Z" }, - { url = "https://files.pythonhosted.org/packages/54/91/1ce35cfda2d56dacd6395faf20a5290268bd9009c53393ac42b5f9bb2c4c/rasterio-1.4.4-cp314-cp314t-win_amd64.whl", hash = "sha256:40137fe512c0d6e96c0167a0ae4e56d82c488f244163c45494b7392e51c844de", size = 26700712, upload-time = "2025-12-12T18:01:03.023Z" }, - { url = "https://files.pythonhosted.org/packages/3b/33/4d13f48a8f01d782ffc1eece20821586518f3f515dca7cf152bca9fd22d4/rasterio-1.4.4-cp314-cp314t-win_arm64.whl", hash = "sha256:29ec3a794454b5bb255c9c0374cc380030a8a1e295c81eee7feb036802d2a9e3", size = 24875933, upload-time = "2025-12-12T18:01:06.134Z" }, -] - [[package]] name = "rasterio" version = "1.5.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version >= '3.14' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] -dependencies = [ - { name = "affine", marker = "python_full_version >= '3.12'" }, - { name = "attrs", marker = "python_full_version >= '3.12'" }, - { name = "certifi", marker = "python_full_version >= '3.12'" }, - { name = "click", marker = "python_full_version >= '3.12'" }, - { name = "cligj", marker = "python_full_version >= '3.12'" }, - { name = "numpy", marker = "python_full_version >= '3.12'" }, - { name = "pyparsing", marker = "python_full_version >= '3.12'" }, +dependencies = [ + { name = "affine" }, + { name = "attrs" }, + { name = "certifi" }, + { name = "click" }, + { name = "cligj" }, + { name = "numpy" }, + { name = "pyparsing" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f6/88/edb4b66b6cb2c13f123af5a3896bf70c0cbe73ab3cd4243cb4eb0212a0f6/rasterio-1.5.0.tar.gz", hash = "sha256:1e0ea56b02eea4989b36edf8e58a5a3ef40e1b7edcb04def2603accd5ab3ee7b", size = 452184, upload-time = "2026-01-05T16:06:47.169Z" } wheels = [ @@ -4557,18 +3580,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cf/ef/5354c47de16c6e289728c3a3d6961ffcf7a9ad6313aef7e8db5d6a40c46e/rasterio-1.5.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:592a485e2057b1aaeab4f843c9897628e60e3ff45e2509325c3e1479116599cb", size = 37686456, upload-time = "2026-01-05T16:06:02.772Z" }, { url = "https://files.pythonhosted.org/packages/b7/fc/fe1f034b1acd1900d9fbd616826d001a3d5811f1d0c97c785f88f525853e/rasterio-1.5.0-cp313-cp313t-win_amd64.whl", hash = "sha256:0c739e70a72fb080f039ee1570c5d02b974dde32ded1a3216e1f13fe38ac4844", size = 30355842, upload-time = "2026-01-05T16:06:06.359Z" }, { url = "https://files.pythonhosted.org/packages/e0/cb/4dee9697891c9c6474b240d00e27688e03ecd882d3c83cc97eb25c2266ff/rasterio-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:a3539a2f401a7b4b2e94ff2db334878c0e15a2d1c9fe90bb0879c52f89367ae5", size = 28589538, upload-time = "2026-01-05T16:06:09.662Z" }, - { url = "https://files.pythonhosted.org/packages/77/9f/f84dfa54110c1c82f9f4fd929465d12519569b6f5d015273aa0957013b2e/rasterio-1.5.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:597be8df418d5ba7b6a927b6b9febfcb42b192882448a8d5b2e2e75a1296631f", size = 22788832, upload-time = "2026-01-05T16:06:12.247Z" }, - { url = "https://files.pythonhosted.org/packages/20/f1/de55255c918b17afd7292f793a3500c4aea7e9530b2b3f5b3a57836c7d49/rasterio-1.5.0-cp314-cp314-macosx_15_0_x86_64.whl", hash = "sha256:dd292030d39d685c0b35eddef233e7f1cb8b43052578a3ec97a2da57799693be", size = 24405917, upload-time = "2026-01-05T16:06:14.603Z" }, - { url = "https://files.pythonhosted.org/packages/a9/57/054087a9d5011ad5dfa799277ba8814e41775e1967d37a59ab7b8e2f1876/rasterio-1.5.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:62c3f97a3c72643c74f2d0f310621a09c35c0c412229c327ae6bcc1ee4b9c3bc", size = 35987536, upload-time = "2026-01-05T16:06:17.707Z" }, - { url = "https://files.pythonhosted.org/packages/c9/72/5fbe5f67ae75d7e89ffb718c500d5fecbaa84f6ba354db306de689faf961/rasterio-1.5.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:19577f0f0c5f1158af47b57f73356961cbd1782a5f6ae6f3adf6f2650f4eb369", size = 37408048, upload-time = "2026-01-05T16:06:20.82Z" }, - { url = "https://files.pythonhosted.org/packages/c4/3e/0c4ef19980204bdcbc8f9e084056adebc97916ff4edcc718750ef34e5bf9/rasterio-1.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:015c1ab6e5453312c5e29692752e7ad73568fe4d13567cbd448d7893128cbd2d", size = 30949590, upload-time = "2026-01-05T16:06:23.425Z" }, - { url = "https://files.pythonhosted.org/packages/c2/d8/2e6b81505408926c00e629d7d3d73fd0454213201bd9907450e0fe82f3dd/rasterio-1.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:ff677c0a9d3ba667c067227ef2b76872488b37ff29b061bc3e576fad9baa3286", size = 29337287, upload-time = "2026-01-05T16:06:26.599Z" }, - { url = "https://files.pythonhosted.org/packages/19/49/7b6e6afb28d4e3f69f2229f990ed87dfdc21a3e15ca63b96b2fd9ba17d89/rasterio-1.5.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:508251b9c746d8d008771a30c2160ff321bfc3b41f6a1aa8e8ef1dd4a00d97ba", size = 22926149, upload-time = "2026-01-05T16:06:29.617Z" }, - { url = "https://files.pythonhosted.org/packages/24/30/19345d8bc7d2b96c1172594026b9009702e9ab9f0baf07079d3612aaadae/rasterio-1.5.0-cp314-cp314t-macosx_15_0_x86_64.whl", hash = "sha256:742841ed48bc70f6ef517b8fa3521f231780bf408fde0aa6d73770337a36374e", size = 24516040, upload-time = "2026-01-05T16:06:32.964Z" }, - { url = "https://files.pythonhosted.org/packages/9e/43/dc7a4518fa78904bc41952cbf346c3c2a88a20e61b479154058392914c0b/rasterio-1.5.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c9a9eee49ce9410c2f352b34c370bb3a96bb518b6a7f97b3a72ee4c835fd4b5c", size = 36589519, upload-time = "2026-01-05T16:06:35.922Z" }, - { url = "https://files.pythonhosted.org/packages/8f/f2/8f706083c6c163054d12c7ed6d5ac4e4ed02252b761288d74e6158871b34/rasterio-1.5.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:b9fd87a0b63ab5c6267dfb0bc96f54fdf49d000651b9ee85ed37798141cff046", size = 37714599, upload-time = "2026-01-05T16:06:38.818Z" }, - { url = "https://files.pythonhosted.org/packages/a6/d5/bbca726d5fea5864f7e4bcf3ee893095369e93ad51120495e8c40e2aa1a0/rasterio-1.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f459db8953ba30ca04fcef2b5e1260eeeff0eae8158bd9c3d6adbe56289765cc", size = 31233931, upload-time = "2026-01-05T16:06:42.208Z" }, - { 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]] @@ -4673,8 +3684,7 @@ dependencies = [ { name = "click" }, { name = "morecantile" }, { name = "pydantic" }, - { name = "rasterio", version = "1.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "rasterio", version = "1.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "rasterio" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4a/01/3b88154233db4cb29cc54df64006537fadb8d7c2ace872af985dac972fd3/rio_cogeo-7.0.2.tar.gz", hash = "sha256:1454ff94dca8652db68862d667bf47e54ecabfe8872c939f2c16ebb62d432f69", size = 19282, upload-time = "2026-03-27T08:25:27.554Z" } wheels = [ @@ -4695,8 +3705,7 @@ dependencies = [ { name = "numpy" }, { name = "pydantic" }, { name = "pystac" }, - { name = "rasterio", version = "1.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "rasterio", version = "1.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "rasterio" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d4/57/586669b6df34e5d164bdcaa246fd2afbb6d7a5cb512d0f68243b0bd4401b/rio_tiler-9.0.6.tar.gz", hash = "sha256:20aa64760a2dd8ee40fb3b925d62fc0a87b9e01f352456fa96d4fd5e41b19c78", size = 190893, upload-time = "2026-04-08T07:35:38.994Z" } @@ -4704,52 +3713,16 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ad/59/fab64b94bdba99b738047653d34469cac634965b1cba02578413946f5fb8/rio_tiler-9.0.6-py3-none-any.whl", hash = "sha256:6c86d6e98692d0e851bd29cc47e237aedd82450b019192f791d5a77a7b5043be", size = 287490, upload-time = "2026-04-08T07:35:37.07Z" }, ] -[[package]] -name = "rioxarray" -version = "0.19.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.12' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version < '3.12' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version < '3.12' and sys_platform == 'emscripten'", - "python_full_version < '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] -dependencies = [ - { name = "numpy", marker = "python_full_version < '3.12'" }, - { name = "packaging", marker = "python_full_version < '3.12'" }, - { name = "pyproj", marker = "python_full_version < '3.12'" }, - { name = "rasterio", version = "1.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "xarray", marker = "python_full_version < '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3d/8e/fe4e87460f8c62d8d5c683e09f19fbde5d9cfcfd0342d02df1f452999b5d/rioxarray-0.19.0.tar.gz", hash = "sha256:7819a0036fd874c8c8e280447cbbe43d8dc72fc4a14ac7852a665b1bdb7d4b04", size = 54600, upload-time = "2025-04-21T17:46:54.183Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/2f/63d2cacc0e525f8e3398bcf32bd3620385f22cd1600834ec49d7f3597a7b/rioxarray-0.19.0-py3-none-any.whl", hash = "sha256:494ee4fff1781072d55ee5276f5d07b63d93b05093cb33b926a12186ba5bb8ef", size = 62151, upload-time = "2025-04-21T17:46:52.801Z" }, -] - [[package]] name = "rioxarray" version = "0.22.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version >= '3.14' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] -dependencies = [ - { name = "numpy", marker = "python_full_version >= '3.12'" }, - { name = "packaging", marker = "python_full_version >= '3.12'" }, - { name = "pyproj", marker = "python_full_version >= '3.12'" }, - { name = "rasterio", version = "1.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "xarray", marker = "python_full_version >= '3.12'" }, +dependencies = [ + { name = "numpy" }, + { name = "packaging" }, + { name = "pyproj" }, + { name = "rasterio" }, + { name = "xarray" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4b/04/9e43477ab0fce7c4c949e1131bfae55ec5228da4ba30f55760660db224b2/rioxarray-0.22.0.tar.gz", hash = "sha256:3f55f23a632ffd9eff13463634227f4afbbcf298947536e161f6cf2ce88d4373", size = 61337, upload-time = "2026-03-06T17:11:00.16Z" } wheels = [ @@ -4762,21 +3735,6 @@ version = "0.30.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/6e/f964e88b3d2abee2a82c1ac8366da848fce1c6d834dc2132c3fda3970290/rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425", size = 370157, upload-time = "2025-11-30T20:21:53.789Z" }, - { url = "https://files.pythonhosted.org/packages/94/ba/24e5ebb7c1c82e74c4e4f33b2112a5573ddc703915b13a073737b59b86e0/rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d", size = 359676, upload-time = "2025-11-30T20:21:55.475Z" }, - { url = "https://files.pythonhosted.org/packages/84/86/04dbba1b087227747d64d80c3b74df946b986c57af0a9f0c98726d4d7a3b/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4", size = 389938, upload-time = "2025-11-30T20:21:57.079Z" }, - { url = "https://files.pythonhosted.org/packages/42/bb/1463f0b1722b7f45431bdd468301991d1328b16cffe0b1c2918eba2c4eee/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f", size = 402932, upload-time = "2025-11-30T20:21:58.47Z" }, - { url = "https://files.pythonhosted.org/packages/99/ee/2520700a5c1f2d76631f948b0736cdf9b0acb25abd0ca8e889b5c62ac2e3/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4", size = 525830, upload-time = "2025-11-30T20:21:59.699Z" }, - { url = "https://files.pythonhosted.org/packages/e0/ad/bd0331f740f5705cc555a5e17fdf334671262160270962e69a2bdef3bf76/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97", size = 412033, upload-time = "2025-11-30T20:22:00.991Z" }, - { url = "https://files.pythonhosted.org/packages/f8/1e/372195d326549bb51f0ba0f2ecb9874579906b97e08880e7a65c3bef1a99/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89", size = 390828, upload-time = "2025-11-30T20:22:02.723Z" }, - { url = "https://files.pythonhosted.org/packages/ab/2b/d88bb33294e3e0c76bc8f351a3721212713629ffca1700fa94979cb3eae8/rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d", size = 404683, upload-time = "2025-11-30T20:22:04.367Z" }, - { url = "https://files.pythonhosted.org/packages/50/32/c759a8d42bcb5289c1fac697cd92f6fe01a018dd937e62ae77e0e7f15702/rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038", size = 421583, upload-time = "2025-11-30T20:22:05.814Z" }, - { url = "https://files.pythonhosted.org/packages/2b/81/e729761dbd55ddf5d84ec4ff1f47857f4374b0f19bdabfcf929164da3e24/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7", size = 572496, upload-time = "2025-11-30T20:22:07.713Z" }, - { url = "https://files.pythonhosted.org/packages/14/f6/69066a924c3557c9c30baa6ec3a0aa07526305684c6f86c696b08860726c/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed", size = 598669, upload-time = "2025-11-30T20:22:09.312Z" }, - { url = "https://files.pythonhosted.org/packages/5f/48/905896b1eb8a05630d20333d1d8ffd162394127b74ce0b0784ae04498d32/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85", size = 561011, upload-time = "2025-11-30T20:22:11.309Z" }, - { url = "https://files.pythonhosted.org/packages/22/16/cd3027c7e279d22e5eb431dd3c0fbc677bed58797fe7581e148f3f68818b/rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c", size = 221406, upload-time = "2025-11-30T20:22:13.101Z" }, - { url = "https://files.pythonhosted.org/packages/fa/5b/e7b7aa136f28462b344e652ee010d4de26ee9fd16f1bfd5811f5153ccf89/rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825", size = 236024, upload-time = "2025-11-30T20:22:14.853Z" }, - { url = "https://files.pythonhosted.org/packages/14/a6/364bba985e4c13658edb156640608f2c9e1d3ea3c81b27aa9d889fff0e31/rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229", size = 229069, upload-time = "2025-11-30T20:22:16.577Z" }, { url = "https://files.pythonhosted.org/packages/03/e7/98a2f4ac921d82f33e03f3835f5bf3a4a40aa1bfdc57975e74a97b2b4bdd/rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad", size = 375086, upload-time = "2025-11-30T20:22:17.93Z" }, { url = "https://files.pythonhosted.org/packages/4d/a1/bca7fd3d452b272e13335db8d6b0b3ecde0f90ad6f16f3328c6fb150c889/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05", size = 359053, upload-time = "2025-11-30T20:22:19.297Z" }, { url = "https://files.pythonhosted.org/packages/65/1c/ae157e83a6357eceff62ba7e52113e3ec4834a84cfe07fa4b0757a7d105f/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28", size = 390763, upload-time = "2025-11-30T20:22:21.661Z" }, @@ -4821,47 +3779,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6d/61/21b8c41f68e60c8cc3b2e25644f0e3681926020f11d06ab0b78e3c6bbff1/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27", size = 555806, upload-time = "2025-11-30T20:23:22.488Z" }, { url = "https://files.pythonhosted.org/packages/f9/39/7e067bb06c31de48de3eb200f9fc7c58982a4d3db44b07e73963e10d3be9/rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6", size = 211341, upload-time = "2025-11-30T20:23:24.449Z" }, { url = "https://files.pythonhosted.org/packages/0a/4d/222ef0b46443cf4cf46764d9c630f3fe4abaa7245be9417e56e9f52b8f65/rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d", size = 225768, upload-time = "2025-11-30T20:23:25.908Z" }, - { url = "https://files.pythonhosted.org/packages/86/81/dad16382ebbd3d0e0328776d8fd7ca94220e4fa0798d1dc5e7da48cb3201/rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0", size = 362099, upload-time = "2025-11-30T20:23:27.316Z" }, - { url = "https://files.pythonhosted.org/packages/2b/60/19f7884db5d5603edf3c6bce35408f45ad3e97e10007df0e17dd57af18f8/rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be", size = 353192, upload-time = "2025-11-30T20:23:29.151Z" }, - { url = "https://files.pythonhosted.org/packages/bf/c4/76eb0e1e72d1a9c4703c69607cec123c29028bff28ce41588792417098ac/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f", size = 384080, upload-time = "2025-11-30T20:23:30.785Z" }, - { url = "https://files.pythonhosted.org/packages/72/87/87ea665e92f3298d1b26d78814721dc39ed8d2c74b86e83348d6b48a6f31/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f", size = 394841, upload-time = "2025-11-30T20:23:32.209Z" }, - { url = "https://files.pythonhosted.org/packages/77/ad/7783a89ca0587c15dcbf139b4a8364a872a25f861bdb88ed99f9b0dec985/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87", size = 516670, upload-time = "2025-11-30T20:23:33.742Z" }, - { url = "https://files.pythonhosted.org/packages/5b/3c/2882bdac942bd2172f3da574eab16f309ae10a3925644e969536553cb4ee/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18", size = 408005, upload-time = "2025-11-30T20:23:35.253Z" }, - { url = "https://files.pythonhosted.org/packages/ce/81/9a91c0111ce1758c92516a3e44776920b579d9a7c09b2b06b642d4de3f0f/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad", size = 382112, upload-time = "2025-11-30T20:23:36.842Z" }, - { url = "https://files.pythonhosted.org/packages/cf/8e/1da49d4a107027e5fbc64daeab96a0706361a2918da10cb41769244b805d/rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07", size = 399049, upload-time = "2025-11-30T20:23:38.343Z" }, - { url = "https://files.pythonhosted.org/packages/df/5a/7ee239b1aa48a127570ec03becbb29c9d5a9eb092febbd1699d567cae859/rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f", size = 415661, upload-time = "2025-11-30T20:23:40.263Z" }, - { url = "https://files.pythonhosted.org/packages/70/ea/caa143cf6b772f823bc7929a45da1fa83569ee49b11d18d0ada7f5ee6fd6/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65", size = 565606, upload-time = "2025-11-30T20:23:42.186Z" }, - { url = "https://files.pythonhosted.org/packages/64/91/ac20ba2d69303f961ad8cf55bf7dbdb4763f627291ba3d0d7d67333cced9/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f", size = 591126, upload-time = "2025-11-30T20:23:44.086Z" }, - { url = "https://files.pythonhosted.org/packages/21/20/7ff5f3c8b00c8a95f75985128c26ba44503fb35b8e0259d812766ea966c7/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53", size = 553371, upload-time = "2025-11-30T20:23:46.004Z" }, - { url = "https://files.pythonhosted.org/packages/72/c7/81dadd7b27c8ee391c132a6b192111ca58d866577ce2d9b0ca157552cce0/rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed", size = 215298, upload-time = "2025-11-30T20:23:47.696Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d2/1aaac33287e8cfb07aab2e6b8ac1deca62f6f65411344f1433c55e6f3eb8/rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950", size = 228604, upload-time = "2025-11-30T20:23:49.501Z" }, - { url = "https://files.pythonhosted.org/packages/e8/95/ab005315818cc519ad074cb7784dae60d939163108bd2b394e60dc7b5461/rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6", size = 222391, upload-time = "2025-11-30T20:23:50.96Z" }, - { url = "https://files.pythonhosted.org/packages/9e/68/154fe0194d83b973cdedcdcc88947a2752411165930182ae41d983dcefa6/rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb", size = 364868, upload-time = "2025-11-30T20:23:52.494Z" }, - { url = "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8", size = 353747, upload-time = "2025-11-30T20:23:54.036Z" }, - { url = "https://files.pythonhosted.org/packages/ab/00/ba2e50183dbd9abcce9497fa5149c62b4ff3e22d338a30d690f9af970561/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7", size = 383795, upload-time = "2025-11-30T20:23:55.556Z" }, - { url = "https://files.pythonhosted.org/packages/05/6f/86f0272b84926bcb0e4c972262f54223e8ecc556b3224d281e6598fc9268/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898", size = 393330, upload-time = "2025-11-30T20:23:57.033Z" }, - { url = "https://files.pythonhosted.org/packages/cb/e9/0e02bb2e6dc63d212641da45df2b0bf29699d01715913e0d0f017ee29438/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e", size = 518194, upload-time = "2025-11-30T20:23:58.637Z" }, - { url = "https://files.pythonhosted.org/packages/ee/ca/be7bca14cf21513bdf9c0606aba17d1f389ea2b6987035eb4f62bd923f25/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419", size = 408340, upload-time = "2025-11-30T20:24:00.2Z" }, - { url = "https://files.pythonhosted.org/packages/c2/c7/736e00ebf39ed81d75544c0da6ef7b0998f8201b369acf842f9a90dc8fce/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551", size = 383765, upload-time = "2025-11-30T20:24:01.759Z" }, - { url = "https://files.pythonhosted.org/packages/4a/3f/da50dfde9956aaf365c4adc9533b100008ed31aea635f2b8d7b627e25b49/rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8", size = 396834, upload-time = "2025-11-30T20:24:03.687Z" }, - { url = "https://files.pythonhosted.org/packages/4e/00/34bcc2565b6020eab2623349efbdec810676ad571995911f1abdae62a3a0/rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5", size = 415470, upload-time = "2025-11-30T20:24:05.232Z" }, - { url = "https://files.pythonhosted.org/packages/8c/28/882e72b5b3e6f718d5453bd4d0d9cf8df36fddeb4ddbbab17869d5868616/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404", size = 565630, upload-time = "2025-11-30T20:24:06.878Z" }, - { url = "https://files.pythonhosted.org/packages/3b/97/04a65539c17692de5b85c6e293520fd01317fd878ea1995f0367d4532fb1/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856", size = 591148, upload-time = "2025-11-30T20:24:08.445Z" }, - { url = "https://files.pythonhosted.org/packages/85/70/92482ccffb96f5441aab93e26c4d66489eb599efdcf96fad90c14bbfb976/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40", size = 556030, upload-time = "2025-11-30T20:24:10.956Z" }, - { url = "https://files.pythonhosted.org/packages/20/53/7c7e784abfa500a2b6b583b147ee4bb5a2b3747a9166bab52fec4b5b5e7d/rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0", size = 211570, upload-time = "2025-11-30T20:24:12.735Z" }, - { url = "https://files.pythonhosted.org/packages/d0/02/fa464cdfbe6b26e0600b62c528b72d8608f5cc49f96b8d6e38c95d60c676/rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3", size = 226532, upload-time = "2025-11-30T20:24:14.634Z" }, - { url = "https://files.pythonhosted.org/packages/69/71/3f34339ee70521864411f8b6992e7ab13ac30d8e4e3309e07c7361767d91/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58", size = 372292, upload-time = "2025-11-30T20:24:16.537Z" }, - { url = "https://files.pythonhosted.org/packages/57/09/f183df9b8f2d66720d2ef71075c59f7e1b336bec7ee4c48f0a2b06857653/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a", size = 362128, upload-time = "2025-11-30T20:24:18.086Z" }, - { url = "https://files.pythonhosted.org/packages/7a/68/5c2594e937253457342e078f0cc1ded3dd7b2ad59afdbf2d354869110a02/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb", size = 391542, upload-time = "2025-11-30T20:24:20.092Z" }, - { url = "https://files.pythonhosted.org/packages/49/5c/31ef1afd70b4b4fbdb2800249f34c57c64beb687495b10aec0365f53dfc4/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c", size = 404004, upload-time = "2025-11-30T20:24:22.231Z" }, - { url = "https://files.pythonhosted.org/packages/e3/63/0cfbea38d05756f3440ce6534d51a491d26176ac045e2707adc99bb6e60a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3", size = 527063, upload-time = "2025-11-30T20:24:24.302Z" }, - { url = "https://files.pythonhosted.org/packages/42/e6/01e1f72a2456678b0f618fc9a1a13f882061690893c192fcad9f2926553a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5", size = 413099, upload-time = "2025-11-30T20:24:25.916Z" }, - { url = "https://files.pythonhosted.org/packages/b8/25/8df56677f209003dcbb180765520c544525e3ef21ea72279c98b9aa7c7fb/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738", size = 392177, upload-time = "2025-11-30T20:24:27.834Z" }, - { url = "https://files.pythonhosted.org/packages/4a/b4/0a771378c5f16f8115f796d1f437950158679bcd2a7c68cf251cfb00ed5b/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f", size = 406015, upload-time = "2025-11-30T20:24:29.457Z" }, - { url = "https://files.pythonhosted.org/packages/36/d8/456dbba0af75049dc6f63ff295a2f92766b9d521fa00de67a2bd6427d57a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877", size = 423736, upload-time = "2025-11-30T20:24:31.22Z" }, - { url = "https://files.pythonhosted.org/packages/13/64/b4d76f227d5c45a7e0b796c674fd81b0a6c4fbd48dc29271857d8219571c/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a", size = 573981, upload-time = "2025-11-30T20:24:32.934Z" }, - { url = "https://files.pythonhosted.org/packages/20/91/092bacadeda3edf92bf743cc96a7be133e13a39cdbfd7b5082e7ab638406/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4", size = 599782, upload-time = "2025-11-30T20:24:35.169Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" }, ] [[package]] @@ -4910,16 +3827,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/df/75/b4ce781849931fef6fd529afa6b63711d5a733065722d0c3e2724af9e40a/scipy-1.17.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:1f95b894f13729334fb990162e911c9e5dc1ab390c58aa6cbecb389c5b5e28ec", size = 31613675, upload-time = "2026-02-23T00:16:00.13Z" }, - { url = "https://files.pythonhosted.org/packages/f7/58/bccc2861b305abdd1b8663d6130c0b3d7cc22e8d86663edbc8401bfd40d4/scipy-1.17.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:e18f12c6b0bc5a592ed23d3f7b891f68fd7f8241d69b7883769eb5d5dfb52696", size = 28162057, upload-time = "2026-02-23T00:16:09.456Z" }, - { url = "https://files.pythonhosted.org/packages/6d/ee/18146b7757ed4976276b9c9819108adbc73c5aad636e5353e20746b73069/scipy-1.17.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a3472cfbca0a54177d0faa68f697d8ba4c80bbdc19908c3465556d9f7efce9ee", size = 20334032, upload-time = "2026-02-23T00:16:17.358Z" }, - { url = "https://files.pythonhosted.org/packages/ec/e6/cef1cf3557f0c54954198554a10016b6a03b2ec9e22a4e1df734936bd99c/scipy-1.17.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:766e0dc5a616d026a3a1cffa379af959671729083882f50307e18175797b3dfd", size = 22709533, upload-time = "2026-02-23T00:16:25.791Z" }, - { url = "https://files.pythonhosted.org/packages/4d/60/8804678875fc59362b0fb759ab3ecce1f09c10a735680318ac30da8cd76b/scipy-1.17.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:744b2bf3640d907b79f3fd7874efe432d1cf171ee721243e350f55234b4cec4c", size = 33062057, upload-time = "2026-02-23T00:16:36.931Z" }, - { url = "https://files.pythonhosted.org/packages/09/7d/af933f0f6e0767995b4e2d705a0665e454d1c19402aa7e895de3951ebb04/scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43af8d1f3bea642559019edfe64e9b11192a8978efbd1539d7bc2aaa23d92de4", size = 35349300, upload-time = "2026-02-23T00:16:49.108Z" }, - { url = "https://files.pythonhosted.org/packages/b4/3d/7ccbbdcbb54c8fdc20d3b6930137c782a163fa626f0aef920349873421ba/scipy-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd96a1898c0a47be4520327e01f874acfd61fb48a9420f8aa9f6483412ffa444", size = 35127333, upload-time = "2026-02-23T00:17:01.293Z" }, - { url = "https://files.pythonhosted.org/packages/e8/19/f926cb11c42b15ba08e3a71e376d816ac08614f769b4f47e06c3580c836a/scipy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4eb6c25dd62ee8d5edf68a8e1c171dd71c292fdae95d8aeb3dd7d7de4c364082", size = 37741314, upload-time = "2026-02-23T00:17:12.576Z" }, - { url = "https://files.pythonhosted.org/packages/95/da/0d1df507cf574b3f224ccc3d45244c9a1d732c81dcb26b1e8a766ae271a8/scipy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:d30e57c72013c2a4fe441c2fcb8e77b14e152ad48b5464858e07e2ad9fbfceff", size = 36607512, upload-time = "2026-02-23T00:17:23.424Z" }, - { url = "https://files.pythonhosted.org/packages/68/7f/bdd79ceaad24b671543ffe0ef61ed8e659440eb683b66f033454dcee90eb/scipy-1.17.1-cp311-cp311-win_arm64.whl", hash = "sha256:9ecb4efb1cd6e8c4afea0daa91a87fbddbce1b99d2895d151596716c0b2e859d", size = 24599248, upload-time = "2026-02-23T00:17:34.561Z" }, { url = "https://files.pythonhosted.org/packages/35/48/b992b488d6f299dbe3f11a20b24d3dda3d46f1a635ede1c46b5b17a7b163/scipy-1.17.1-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:35c3a56d2ef83efc372eaec584314bd0ef2e2f0d2adb21c55e6ad5b344c0dcb8", size = 31610954, upload-time = "2026-02-23T00:17:49.855Z" }, { url = "https://files.pythonhosted.org/packages/b2/02/cf107b01494c19dc100f1d0b7ac3cc08666e96ba2d64db7626066cee895e/scipy-1.17.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:fcb310ddb270a06114bb64bbe53c94926b943f5b7f0842194d585c65eb4edd76", size = 28172662, upload-time = "2026-02-23T00:18:01.64Z" }, { url = "https://files.pythonhosted.org/packages/cf/a9/599c28631bad314d219cf9ffd40e985b24d603fc8a2f4ccc5ae8419a535b/scipy-1.17.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:cc90d2e9c7e5c7f1a482c9875007c095c3194b1cfedca3c2f3291cdc2bc7c086", size = 20344366, upload-time = "2026-02-23T00:18:12.015Z" }, @@ -4950,86 +3857,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bd/12/d19da97efde68ca1ee5538bb261d5d2c062f0c055575128f11a2730e3ac1/scipy-1.17.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94055a11dfebe37c656e70317e1996dc197e1a15bbcc351bcdd4610e128fe1ca", size = 37665910, upload-time = "2026-02-23T00:20:34.743Z" }, { url = "https://files.pythonhosted.org/packages/06/1c/1172a88d507a4baaf72c5a09bb6c018fe2ae0ab622e5830b703a46cc9e44/scipy-1.17.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e30bdeaa5deed6bc27b4cc490823cd0347d7dae09119b8803ae576ea0ce52e4c", size = 36562980, upload-time = "2026-02-23T00:20:40.575Z" }, { url = "https://files.pythonhosted.org/packages/70/b0/eb757336e5a76dfa7911f63252e3b7d1de00935d7705cf772db5b45ec238/scipy-1.17.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a720477885a9d2411f94a93d16f9d89bad0f28ca23c3f8daa521e2dcc3f44d49", size = 24856543, upload-time = "2026-02-23T00:20:45.313Z" }, - { url = "https://files.pythonhosted.org/packages/cf/83/333afb452af6f0fd70414dc04f898647ee1423979ce02efa75c3b0f2c28e/scipy-1.17.1-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:a48a72c77a310327f6a3a920092fa2b8fd03d7deaa60f093038f22d98e096717", size = 31584510, upload-time = "2026-02-23T00:21:01.015Z" }, - { url = "https://files.pythonhosted.org/packages/ed/a6/d05a85fd51daeb2e4ea71d102f15b34fedca8e931af02594193ae4fd25f7/scipy-1.17.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:45abad819184f07240d8a696117a7aacd39787af9e0b719d00285549ed19a1e9", size = 28170131, upload-time = "2026-02-23T00:21:05.888Z" }, - { url = "https://files.pythonhosted.org/packages/db/7b/8624a203326675d7746a254083a187398090a179335b2e4a20e2ddc46e83/scipy-1.17.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3fd1fcdab3ea951b610dc4cef356d416d5802991e7e32b5254828d342f7b7e0b", size = 20342032, upload-time = "2026-02-23T00:21:09.904Z" }, - { url = "https://files.pythonhosted.org/packages/c9/35/2c342897c00775d688d8ff3987aced3426858fd89d5a0e26e020b660b301/scipy-1.17.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7bdf2da170b67fdf10bca777614b1c7d96ae3ca5794fd9587dce41eb2966e866", size = 22678766, upload-time = "2026-02-23T00:21:14.313Z" }, - { url = "https://files.pythonhosted.org/packages/ef/f2/7cdb8eb308a1a6ae1e19f945913c82c23c0c442a462a46480ce487fdc0ac/scipy-1.17.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:adb2642e060a6549c343603a3851ba76ef0b74cc8c079a9a58121c7ec9fe2350", size = 32957007, upload-time = "2026-02-23T00:21:19.663Z" }, - { url = "https://files.pythonhosted.org/packages/0b/2e/7eea398450457ecb54e18e9d10110993fa65561c4f3add5e8eccd2b9cd41/scipy-1.17.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee2cfda04c00a857206a4330f0c5e3e56535494e30ca445eb19ec624ae75118", size = 35221333, upload-time = "2026-02-23T00:21:25.278Z" }, - { url = "https://files.pythonhosted.org/packages/d9/77/5b8509d03b77f093a0d52e606d3c4f79e8b06d1d38c441dacb1e26cacf46/scipy-1.17.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d2650c1fb97e184d12d8ba010493ee7b322864f7d3d00d3f9bb97d9c21de4068", size = 35042066, upload-time = "2026-02-23T00:21:31.358Z" }, - { url = "https://files.pythonhosted.org/packages/f9/df/18f80fb99df40b4070328d5ae5c596f2f00fffb50167e31439e932f29e7d/scipy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:08b900519463543aa604a06bec02461558a6e1cef8fdbb8098f77a48a83c8118", size = 37612763, upload-time = "2026-02-23T00:21:37.247Z" }, - { url = "https://files.pythonhosted.org/packages/4b/39/f0e8ea762a764a9dc52aa7dabcfad51a354819de1f0d4652b6a1122424d6/scipy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:3877ac408e14da24a6196de0ddcace62092bfc12a83823e92e49e40747e52c19", size = 37290984, upload-time = "2026-02-23T00:22:35.023Z" }, - { url = "https://files.pythonhosted.org/packages/7c/56/fe201e3b0f93d1a8bcf75d3379affd228a63d7e2d80ab45467a74b494947/scipy-1.17.1-cp314-cp314-win_arm64.whl", hash = "sha256:f8885db0bc2bffa59d5c1b72fad7a6a92d3e80e7257f967dd81abb553a90d293", size = 25192877, upload-time = "2026-02-23T00:22:39.798Z" }, - { url = "https://files.pythonhosted.org/packages/96/ad/f8c414e121f82e02d76f310f16db9899c4fcde36710329502a6b2a3c0392/scipy-1.17.1-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:1cc682cea2ae55524432f3cdff9e9a3be743d52a7443d0cba9017c23c87ae2f6", size = 31949750, upload-time = "2026-02-23T00:21:42.289Z" }, - { url = "https://files.pythonhosted.org/packages/7c/b0/c741e8865d61b67c81e255f4f0a832846c064e426636cd7de84e74d209be/scipy-1.17.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:2040ad4d1795a0ae89bfc7e8429677f365d45aa9fd5e4587cf1ea737f927b4a1", size = 28585858, upload-time = "2026-02-23T00:21:47.706Z" }, - { url = "https://files.pythonhosted.org/packages/ed/1b/3985219c6177866628fa7c2595bfd23f193ceebbe472c98a08824b9466ff/scipy-1.17.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:131f5aaea57602008f9822e2115029b55d4b5f7c070287699fe45c661d051e39", size = 20757723, upload-time = "2026-02-23T00:21:52.039Z" }, - { url = "https://files.pythonhosted.org/packages/c0/19/2a04aa25050d656d6f7b9e7b685cc83d6957fb101665bfd9369ca6534563/scipy-1.17.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:9cdc1a2fcfd5c52cfb3045feb399f7b3ce822abdde3a193a6b9a60b3cb5854ca", size = 23043098, upload-time = "2026-02-23T00:21:56.185Z" }, - { url = "https://files.pythonhosted.org/packages/86/f1/3383beb9b5d0dbddd030335bf8a8b32d4317185efe495374f134d8be6cce/scipy-1.17.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e3dcd57ab780c741fde8dc68619de988b966db759a3c3152e8e9142c26295ad", size = 33030397, upload-time = "2026-02-23T00:22:01.404Z" }, - { url = "https://files.pythonhosted.org/packages/41/68/8f21e8a65a5a03f25a79165ec9d2b28c00e66dc80546cf5eb803aeeff35b/scipy-1.17.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9956e4d4f4a301ebf6cde39850333a6b6110799d470dbbb1e25326ac447f52a", size = 35281163, upload-time = "2026-02-23T00:22:07.024Z" }, - { url = "https://files.pythonhosted.org/packages/84/8d/c8a5e19479554007a5632ed7529e665c315ae7492b4f946b0deb39870e39/scipy-1.17.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a4328d245944d09fd639771de275701ccadf5f781ba0ff092ad141e017eccda4", size = 35116291, upload-time = "2026-02-23T00:22:12.585Z" }, - { url = "https://files.pythonhosted.org/packages/52/52/e57eceff0e342a1f50e274264ed47497b59e6a4e3118808ee58ddda7b74a/scipy-1.17.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a77cbd07b940d326d39a1d1b37817e2ee4d79cb30e7338f3d0cddffae70fcaa2", size = 37682317, upload-time = "2026-02-23T00:22:18.513Z" }, - { url = "https://files.pythonhosted.org/packages/11/2f/b29eafe4a3fbc3d6de9662b36e028d5f039e72d345e05c250e121a230dd4/scipy-1.17.1-cp314-cp314t-win_amd64.whl", hash = "sha256:eb092099205ef62cd1782b006658db09e2fed75bffcae7cc0d44052d8aa0f484", size = 37345327, upload-time = "2026-02-23T00:22:24.442Z" }, - { url = "https://files.pythonhosted.org/packages/07/39/338d9219c4e87f3e708f18857ecd24d22a0c3094752393319553096b98af/scipy-1.17.1-cp314-cp314t-win_arm64.whl", hash = "sha256:200e1050faffacc162be6a486a984a0497866ec54149a01270adc8a59b7c7d21", size = 25489165, upload-time = "2026-02-23T00:22:29.563Z" }, -] - -[[package]] -name = "scitools-iris" -version = "3.14.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.12' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version < '3.12' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version < '3.12' and sys_platform == 'emscripten'", - "python_full_version < '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] -dependencies = [ - { name = "cartopy", marker = "python_full_version < '3.12'" }, - { name = "cf-units", marker = "python_full_version < '3.12'" }, - { name = "cftime", marker = "python_full_version < '3.12'" }, - { name = "dask", extra = ["array"], marker = "python_full_version < '3.12'" }, - { name = "matplotlib", marker = "python_full_version < '3.12'" }, - { name = "netcdf4", marker = "python_full_version < '3.12'" }, - { name = "numpy", marker = "python_full_version < '3.12'" }, - { name = "pyproj", marker = "python_full_version < '3.12'" }, - { name = "scipy", marker = "python_full_version < '3.12'" }, - { name = "shapely", marker = "python_full_version < '3.12'" }, - { name = "xxhash", marker = "python_full_version < '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ba/42/d60c130acfee440e604b795d5426ef777ec37ab6f01cca4c1550ff948b34/scitools_iris-3.14.1.tar.gz", hash = "sha256:ccc8025d24b74d86ab780266cb9f708c468ac53426a45fab20bfc315c68383f7", size = 1995413, upload-time = "2025-12-05T14:19:51.238Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/17/449e21379ac07669279ec25a1428eac6a02b76c9cc2fe55f885ce18fcdb2/scitools_iris-3.14.1-py3-none-any.whl", hash = "sha256:aabc44e347c82dacb188f0d0e577055feef3b643bd5fc58c09fe78b334866f80", size = 2632366, upload-time = "2025-12-05T14:19:49.263Z" }, ] [[package]] name = "scitools-iris" version = "3.15.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version >= '3.14' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and platform_machine == 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and platform_machine != 'ARM64' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] -dependencies = [ - { name = "cartopy", marker = "python_full_version >= '3.12'" }, - { name = "cf-units", marker = "python_full_version >= '3.12'" }, - { name = "cftime", marker = "python_full_version >= '3.12'" }, - { name = "dask", extra = ["array"], marker = "python_full_version >= '3.12'" }, - { name = "matplotlib", marker = "python_full_version >= '3.12'" }, - { name = "netcdf4", marker = "python_full_version >= '3.12'" }, - { name = "numpy", marker = "python_full_version >= '3.12'" }, - { name = "pyproj", marker = "python_full_version >= '3.12'" }, - { name = "scipy", marker = "python_full_version >= '3.12'" }, - { name = "shapely", marker = "python_full_version >= '3.12'" }, - { name = "xxhash", marker = "python_full_version >= '3.12'" }, +dependencies = [ + { name = "cartopy" }, + { name = "cf-units" }, + { name = "cftime" }, + { name = "dask", extra = ["array"] }, + { name = "matplotlib" }, + { name = "netcdf4" }, + { name = "numpy" }, + { name = "pyproj" }, + { name = "scipy" }, + { name = "shapely" }, + { name = "xxhash" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e8/f1/ebf8a0ecf557ab3e790f961667118d79abcc4eb40000504c190477fd87a5/scitools_iris-3.15.0.tar.gz", hash = "sha256:ad59f8ca134850bb5fea8e5f73a0fb0f5d47b26ffb2a0de3d77a769b532fac94", size = 2000376, upload-time = "2026-04-02T09:12:05.354Z" } wheels = [ @@ -5086,14 +3931,6 @@ dependencies = [ ] 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/8f/8d/1ff672dea9ec6a7b5d422eb6d095ed886e2e523733329f75fdcb14ee1149/shapely-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:91121757b0a36c9aac3427a651a7e6567110a4a67c97edf04f8d55d4765f6618", size = 1820038, upload-time = "2025-09-24T13:50:15.628Z" }, - { url = "https://files.pythonhosted.org/packages/4f/ce/28fab8c772ce5db23a0d86bf0adaee0c4c79d5ad1db766055fa3dab442e2/shapely-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:16a9c722ba774cf50b5d4541242b4cce05aafd44a015290c82ba8a16931ff63d", size = 1626039, upload-time = "2025-09-24T13:50:16.881Z" }, - { url = "https://files.pythonhosted.org/packages/70/8b/868b7e3f4982f5006e9395c1e12343c66a8155c0374fdc07c0e6a1ab547d/shapely-2.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cc4f7397459b12c0b196c9efe1f9d7e92463cbba142632b4cc6d8bbbbd3e2b09", size = 3001519, upload-time = "2025-09-24T13:50:18.606Z" }, - { url = "https://files.pythonhosted.org/packages/13/02/58b0b8d9c17c93ab6340edd8b7308c0c5a5b81f94ce65705819b7416dba5/shapely-2.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:136ab87b17e733e22f0961504d05e77e7be8c9b5a8184f685b4a91a84efe3c26", size = 3110842, upload-time = "2025-09-24T13:50:21.77Z" }, - { url = "https://files.pythonhosted.org/packages/af/61/8e389c97994d5f331dcffb25e2fa761aeedfb52b3ad9bcdd7b8671f4810a/shapely-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:16c5d0fc45d3aa0a69074979f4f1928ca2734fb2e0dde8af9611e134e46774e7", size = 4021316, upload-time = "2025-09-24T13:50:23.626Z" }, - { url = "https://files.pythonhosted.org/packages/d3/d4/9b2a9fe6039f9e42ccf2cb3e84f219fd8364b0c3b8e7bbc857b5fbe9c14c/shapely-2.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6ddc759f72b5b2b0f54a7e7cde44acef680a55019eb52ac63a7af2cf17cb9cd2", size = 4178586, upload-time = "2025-09-24T13:50:25.443Z" }, - { url = "https://files.pythonhosted.org/packages/16/f6/9840f6963ed4decf76b08fd6d7fed14f8779fb7a62cb45c5617fa8ac6eab/shapely-2.1.2-cp311-cp311-win32.whl", hash = "sha256:2fa78b49485391224755a856ed3b3bd91c8455f6121fee0db0e71cefb07d0ef6", size = 1543961, upload-time = "2025-09-24T13:50:26.968Z" }, - { url = "https://files.pythonhosted.org/packages/38/1e/3f8ea46353c2a33c1669eb7327f9665103aa3a8dfe7f2e4ef714c210b2c2/shapely-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:c64d5c97b2f47e3cd9b712eaced3b061f2b71234b3fc263e0fcf7d889c6559dc", size = 1722856, upload-time = "2025-09-24T13:50:28.497Z" }, { 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" }, @@ -5118,22 +3955,6 @@ wheels = [ { 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]] @@ -5383,9 +4204,6 @@ version = "6.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" }, - { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" }, - { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" }, { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, @@ -5520,21 +4338,6 @@ version = "3.6.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/17/d4/cc2f0400e9154df4b9964249da78ebd72f318e35ccc425e9f403c392f22a/xxhash-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b47bbd8cf2d72797f3c2772eaaac0ded3d3af26481a26d7d7d41dc2d3c46b04a", size = 32844, upload-time = "2025-10-02T14:34:14.037Z" }, - { url = "https://files.pythonhosted.org/packages/5e/ec/1cc11cd13e26ea8bc3cb4af4eaadd8d46d5014aebb67be3f71fb0b68802a/xxhash-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2b6821e94346f96db75abaa6e255706fb06ebd530899ed76d32cd99f20dc52fa", size = 30809, upload-time = "2025-10-02T14:34:15.484Z" }, - { url = "https://files.pythonhosted.org/packages/04/5f/19fe357ea348d98ca22f456f75a30ac0916b51c753e1f8b2e0e6fb884cce/xxhash-3.6.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d0a9751f71a1a65ce3584e9cae4467651c7e70c9d31017fa57574583a4540248", size = 194665, upload-time = "2025-10-02T14:34:16.541Z" }, - { url = "https://files.pythonhosted.org/packages/90/3b/d1f1a8f5442a5fd8beedae110c5af7604dc37349a8e16519c13c19a9a2de/xxhash-3.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b29ee68625ab37b04c0b40c3fafdf24d2f75ccd778333cfb698f65f6c463f62", size = 213550, upload-time = "2025-10-02T14:34:17.878Z" }, - { url = "https://files.pythonhosted.org/packages/c4/ef/3a9b05eb527457d5db13a135a2ae1a26c80fecd624d20f3e8dcc4cb170f3/xxhash-3.6.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6812c25fe0d6c36a46ccb002f40f27ac903bf18af9f6dd8f9669cb4d176ab18f", size = 212384, upload-time = "2025-10-02T14:34:19.182Z" }, - { url = "https://files.pythonhosted.org/packages/0f/18/ccc194ee698c6c623acbf0f8c2969811a8a4b6185af5e824cd27b9e4fd3e/xxhash-3.6.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4ccbff013972390b51a18ef1255ef5ac125c92dc9143b2d1909f59abc765540e", size = 445749, upload-time = "2025-10-02T14:34:20.659Z" }, - { url = "https://files.pythonhosted.org/packages/a5/86/cf2c0321dc3940a7aa73076f4fd677a0fb3e405cb297ead7d864fd90847e/xxhash-3.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:297b7fbf86c82c550e12e8fb71968b3f033d27b874276ba3624ea868c11165a8", size = 193880, upload-time = "2025-10-02T14:34:22.431Z" }, - { url = "https://files.pythonhosted.org/packages/82/fb/96213c8560e6f948a1ecc9a7613f8032b19ee45f747f4fca4eb31bb6d6ed/xxhash-3.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dea26ae1eb293db089798d3973a5fc928a18fdd97cc8801226fae705b02b14b0", size = 210912, upload-time = "2025-10-02T14:34:23.937Z" }, - { url = "https://files.pythonhosted.org/packages/40/aa/4395e669b0606a096d6788f40dbdf2b819d6773aa290c19e6e83cbfc312f/xxhash-3.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7a0b169aafb98f4284f73635a8e93f0735f9cbde17bd5ec332480484241aaa77", size = 198654, upload-time = "2025-10-02T14:34:25.644Z" }, - { url = "https://files.pythonhosted.org/packages/67/74/b044fcd6b3d89e9b1b665924d85d3f400636c23590226feb1eb09e1176ce/xxhash-3.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:08d45aef063a4531b785cd72de4887766d01dc8f362a515693df349fdb825e0c", size = 210867, upload-time = "2025-10-02T14:34:27.203Z" }, - { url = "https://files.pythonhosted.org/packages/bc/fd/3ce73bf753b08cb19daee1eb14aa0d7fe331f8da9c02dd95316ddfe5275e/xxhash-3.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:929142361a48ee07f09121fe9e96a84950e8d4df3bb298ca5d88061969f34d7b", size = 414012, upload-time = "2025-10-02T14:34:28.409Z" }, - { url = "https://files.pythonhosted.org/packages/ba/b3/5a4241309217c5c876f156b10778f3ab3af7ba7e3259e6d5f5c7d0129eb2/xxhash-3.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:51312c768403d8540487dbbfb557454cfc55589bbde6424456951f7fcd4facb3", size = 191409, upload-time = "2025-10-02T14:34:29.696Z" }, - { url = "https://files.pythonhosted.org/packages/c0/01/99bfbc15fb9abb9a72b088c1d95219fc4782b7d01fc835bd5744d66dd0b8/xxhash-3.6.0-cp311-cp311-win32.whl", hash = "sha256:d1927a69feddc24c987b337ce81ac15c4720955b667fe9b588e02254b80446fd", size = 30574, upload-time = "2025-10-02T14:34:31.028Z" }, - { url = "https://files.pythonhosted.org/packages/65/79/9d24d7f53819fe301b231044ea362ce64e86c74f6e8c8e51320de248b3e5/xxhash-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:26734cdc2d4ffe449b41d186bbeac416f704a482ed835d375a5c0cb02bc63fef", size = 31481, upload-time = "2025-10-02T14:34:32.062Z" }, - { url = "https://files.pythonhosted.org/packages/30/4e/15cd0e3e8772071344eab2961ce83f6e485111fed8beb491a3f1ce100270/xxhash-3.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:d72f67ef8bf36e05f5b6c65e8524f265bd61071471cd4cf1d36743ebeeeb06b7", size = 27861, upload-time = "2025-10-02T14:34:33.555Z" }, { url = "https://files.pythonhosted.org/packages/9a/07/d9412f3d7d462347e4511181dea65e47e0d0e16e26fbee2ea86a2aefb657/xxhash-3.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:01362c4331775398e7bb34e3ab403bc9ee9f7c497bc7dee6272114055277dd3c", size = 32744, upload-time = "2025-10-02T14:34:34.622Z" }, { url = "https://files.pythonhosted.org/packages/79/35/0429ee11d035fc33abe32dca1b2b69e8c18d236547b9a9b72c1929189b9a/xxhash-3.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7b2df81a23f8cb99656378e72501b2cb41b1827c0f5a86f87d6b06b69f9f204", size = 30816, upload-time = "2025-10-02T14:34:36.043Z" }, { url = "https://files.pythonhosted.org/packages/b7/f2/57eb99aa0f7d98624c0932c5b9a170e1806406cdbcdb510546634a1359e0/xxhash-3.6.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dc94790144e66b14f67b10ac8ed75b39ca47536bf8800eb7c24b50271ea0c490", size = 194035, upload-time = "2025-10-02T14:34:37.354Z" }, @@ -5580,41 +4383,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/19/fa/0172e350361d61febcea941b0cc541d6e6c8d65d153e85f850a7b256ff8a/xxhash-3.6.0-cp313-cp313t-win32.whl", hash = "sha256:1244460adc3a9be84731d72b8e80625788e5815b68da3da8b83f78115a40a7ec", size = 30916, upload-time = "2025-10-02T14:35:35.107Z" }, { url = "https://files.pythonhosted.org/packages/ad/e6/e8cf858a2b19d6d45820f072eff1bea413910592ff17157cabc5f1227a16/xxhash-3.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b1e420ef35c503869c4064f4a2f2b08ad6431ab7b229a05cce39d74268bca6b8", size = 31799, upload-time = "2025-10-02T14:35:36.165Z" }, { url = "https://files.pythonhosted.org/packages/56/15/064b197e855bfb7b343210e82490ae672f8bc7cdf3ddb02e92f64304ee8a/xxhash-3.6.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ec44b73a4220623235f67a996c862049f375df3b1052d9899f40a6382c32d746", size = 28044, upload-time = "2025-10-02T14:35:37.195Z" }, - { url = "https://files.pythonhosted.org/packages/7e/5e/0138bc4484ea9b897864d59fce9be9086030825bc778b76cb5a33a906d37/xxhash-3.6.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a40a3d35b204b7cc7643cbcf8c9976d818cb47befcfac8bbefec8038ac363f3e", size = 32754, upload-time = "2025-10-02T14:35:38.245Z" }, - { url = "https://files.pythonhosted.org/packages/18/d7/5dac2eb2ec75fd771957a13e5dda560efb2176d5203f39502a5fc571f899/xxhash-3.6.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a54844be970d3fc22630b32d515e79a90d0a3ddb2644d8d7402e3c4c8da61405", size = 30846, upload-time = "2025-10-02T14:35:39.6Z" }, - { url = "https://files.pythonhosted.org/packages/fe/71/8bc5be2bb00deb5682e92e8da955ebe5fa982da13a69da5a40a4c8db12fb/xxhash-3.6.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:016e9190af8f0a4e3741343777710e3d5717427f175adfdc3e72508f59e2a7f3", size = 194343, upload-time = "2025-10-02T14:35:40.69Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/52badfb2aecec2c377ddf1ae75f55db3ba2d321c5e164f14461c90837ef3/xxhash-3.6.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f6f72232f849eb9d0141e2ebe2677ece15adfd0fa599bc058aad83c714bb2c6", size = 213074, upload-time = "2025-10-02T14:35:42.29Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2b/ae46b4e9b92e537fa30d03dbc19cdae57ed407e9c26d163895e968e3de85/xxhash-3.6.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:63275a8aba7865e44b1813d2177e0f5ea7eadad3dd063a21f7cf9afdc7054063", size = 212388, upload-time = "2025-10-02T14:35:43.929Z" }, - { url = "https://files.pythonhosted.org/packages/f5/80/49f88d3afc724b4ac7fbd664c8452d6db51b49915be48c6982659e0e7942/xxhash-3.6.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cd01fa2aa00d8b017c97eb46b9a794fbdca53fc14f845f5a328c71254b0abb7", size = 445614, upload-time = "2025-10-02T14:35:45.216Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ba/603ce3961e339413543d8cd44f21f2c80e2a7c5cfe692a7b1f2cccf58f3c/xxhash-3.6.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0226aa89035b62b6a86d3c68df4d7c1f47a342b8683da2b60cedcddb46c4d95b", size = 194024, upload-time = "2025-10-02T14:35:46.959Z" }, - { url = "https://files.pythonhosted.org/packages/78/d1/8e225ff7113bf81545cfdcd79eef124a7b7064a0bba53605ff39590b95c2/xxhash-3.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c6e193e9f56e4ca4923c61238cdaced324f0feac782544eb4c6d55ad5cc99ddd", size = 210541, upload-time = "2025-10-02T14:35:48.301Z" }, - { url = "https://files.pythonhosted.org/packages/6f/58/0f89d149f0bad89def1a8dd38feb50ccdeb643d9797ec84707091d4cb494/xxhash-3.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9176dcaddf4ca963d4deb93866d739a343c01c969231dbe21680e13a5d1a5bf0", size = 198305, upload-time = "2025-10-02T14:35:49.584Z" }, - { url = "https://files.pythonhosted.org/packages/11/38/5eab81580703c4df93feb5f32ff8fa7fe1e2c51c1f183ee4e48d4bb9d3d7/xxhash-3.6.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c1ce4009c97a752e682b897aa99aef84191077a9433eb237774689f14f8ec152", size = 210848, upload-time = "2025-10-02T14:35:50.877Z" }, - { url = "https://files.pythonhosted.org/packages/5e/6b/953dc4b05c3ce678abca756416e4c130d2382f877a9c30a20d08ee6a77c0/xxhash-3.6.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:8cb2f4f679b01513b7adbb9b1b2f0f9cdc31b70007eaf9d59d0878809f385b11", size = 414142, upload-time = "2025-10-02T14:35:52.15Z" }, - { url = "https://files.pythonhosted.org/packages/08/a9/238ec0d4e81a10eb5026d4a6972677cbc898ba6c8b9dbaec12ae001b1b35/xxhash-3.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:653a91d7c2ab54a92c19ccf43508b6a555440b9be1bc8be553376778be7f20b5", size = 191547, upload-time = "2025-10-02T14:35:53.547Z" }, - { url = "https://files.pythonhosted.org/packages/f1/ee/3cf8589e06c2164ac77c3bf0aa127012801128f1feebf2a079272da5737c/xxhash-3.6.0-cp314-cp314-win32.whl", hash = "sha256:a756fe893389483ee8c394d06b5ab765d96e68fbbfe6fde7aa17e11f5720559f", size = 31214, upload-time = "2025-10-02T14:35:54.746Z" }, - { url = "https://files.pythonhosted.org/packages/02/5d/a19552fbc6ad4cb54ff953c3908bbc095f4a921bc569433d791f755186f1/xxhash-3.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:39be8e4e142550ef69629c9cd71b88c90e9a5db703fecbcf265546d9536ca4ad", size = 32290, upload-time = "2025-10-02T14:35:55.791Z" }, - { url = "https://files.pythonhosted.org/packages/b1/11/dafa0643bc30442c887b55baf8e73353a344ee89c1901b5a5c54a6c17d39/xxhash-3.6.0-cp314-cp314-win_arm64.whl", hash = "sha256:25915e6000338999236f1eb68a02a32c3275ac338628a7eaa5a269c401995679", size = 28795, upload-time = "2025-10-02T14:35:57.162Z" }, - { url = "https://files.pythonhosted.org/packages/2c/db/0e99732ed7f64182aef4a6fb145e1a295558deec2a746265dcdec12d191e/xxhash-3.6.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c5294f596a9017ca5a3e3f8884c00b91ab2ad2933cf288f4923c3fd4346cf3d4", size = 32955, upload-time = "2025-10-02T14:35:58.267Z" }, - { url = "https://files.pythonhosted.org/packages/55/f4/2a7c3c68e564a099becfa44bb3d398810cc0ff6749b0d3cb8ccb93f23c14/xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1cf9dcc4ab9cff01dfbba78544297a3a01dafd60f3bde4e2bfd016cf7e4ddc67", size = 31072, upload-time = "2025-10-02T14:35:59.382Z" }, - { url = "https://files.pythonhosted.org/packages/c6/d9/72a29cddc7250e8a5819dad5d466facb5dc4c802ce120645630149127e73/xxhash-3.6.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:01262da8798422d0685f7cef03b2bd3f4f46511b02830861df548d7def4402ad", size = 196579, upload-time = "2025-10-02T14:36:00.838Z" }, - { url = "https://files.pythonhosted.org/packages/63/93/b21590e1e381040e2ca305a884d89e1c345b347404f7780f07f2cdd47ef4/xxhash-3.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51a73fb7cb3a3ead9f7a8b583ffd9b8038e277cdb8cb87cf890e88b3456afa0b", size = 215854, upload-time = "2025-10-02T14:36:02.207Z" }, - { url = "https://files.pythonhosted.org/packages/ce/b8/edab8a7d4fa14e924b29be877d54155dcbd8b80be85ea00d2be3413a9ed4/xxhash-3.6.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b9c6df83594f7df8f7f708ce5ebeacfc69f72c9fbaaababf6cf4758eaada0c9b", size = 214965, upload-time = "2025-10-02T14:36:03.507Z" }, - { url = "https://files.pythonhosted.org/packages/27/67/dfa980ac7f0d509d54ea0d5a486d2bb4b80c3f1bb22b66e6a05d3efaf6c0/xxhash-3.6.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:627f0af069b0ea56f312fd5189001c24578868643203bca1abbc2c52d3a6f3ca", size = 448484, upload-time = "2025-10-02T14:36:04.828Z" }, - { url = "https://files.pythonhosted.org/packages/8c/63/8ffc2cc97e811c0ca5d00ab36604b3ea6f4254f20b7bc658ca825ce6c954/xxhash-3.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa912c62f842dfd013c5f21a642c9c10cd9f4c4e943e0af83618b4a404d9091a", size = 196162, upload-time = "2025-10-02T14:36:06.182Z" }, - { url = "https://files.pythonhosted.org/packages/4b/77/07f0e7a3edd11a6097e990f6e5b815b6592459cb16dae990d967693e6ea9/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b465afd7909db30168ab62afe40b2fcf79eedc0b89a6c0ab3123515dc0df8b99", size = 213007, upload-time = "2025-10-02T14:36:07.733Z" }, - { url = "https://files.pythonhosted.org/packages/ae/d8/bc5fa0d152837117eb0bef6f83f956c509332ce133c91c63ce07ee7c4873/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a881851cf38b0a70e7c4d3ce81fc7afd86fbc2a024f4cfb2a97cf49ce04b75d3", size = 200956, upload-time = "2025-10-02T14:36:09.106Z" }, - { url = "https://files.pythonhosted.org/packages/26/a5/d749334130de9411783873e9b98ecc46688dad5db64ca6e04b02acc8b473/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9b3222c686a919a0f3253cfc12bb118b8b103506612253b5baeaac10d8027cf6", size = 213401, upload-time = "2025-10-02T14:36:10.585Z" }, - { url = "https://files.pythonhosted.org/packages/89/72/abed959c956a4bfc72b58c0384bb7940663c678127538634d896b1195c10/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:c5aa639bc113e9286137cec8fadc20e9cd732b2cc385c0b7fa673b84fc1f2a93", size = 417083, upload-time = "2025-10-02T14:36:12.276Z" }, - { url = "https://files.pythonhosted.org/packages/0c/b3/62fd2b586283b7d7d665fb98e266decadf31f058f1cf6c478741f68af0cb/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5c1343d49ac102799905e115aee590183c3921d475356cb24b4de29a4bc56518", size = 193913, upload-time = "2025-10-02T14:36:14.025Z" }, - { url = "https://files.pythonhosted.org/packages/9a/9a/c19c42c5b3f5a4aad748a6d5b4f23df3bed7ee5445accc65a0fb3ff03953/xxhash-3.6.0-cp314-cp314t-win32.whl", hash = "sha256:5851f033c3030dd95c086b4a36a2683c2ff4a799b23af60977188b057e467119", size = 31586, upload-time = "2025-10-02T14:36:15.603Z" }, - { url = "https://files.pythonhosted.org/packages/03/d6/4cc450345be9924fd5dc8c590ceda1db5b43a0a889587b0ae81a95511360/xxhash-3.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0444e7967dac37569052d2409b00a8860c2135cff05502df4da80267d384849f", size = 32526, upload-time = "2025-10-02T14:36:16.708Z" }, - { url = "https://files.pythonhosted.org/packages/0f/c9/7243eb3f9eaabd1a88a5a5acadf06df2d83b100c62684b7425c6a11bcaa8/xxhash-3.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:bb79b1e63f6fd84ec778a4b1916dfe0a7c3fdb986c06addd5db3a0d413819d95", size = 28898, upload-time = "2025-10-02T14:36:17.843Z" }, - { url = "https://files.pythonhosted.org/packages/93/1e/8aec23647a34a249f62e2398c42955acd9b4c6ed5cf08cbea94dc46f78d2/xxhash-3.6.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0f7b7e2ec26c1666ad5fc9dbfa426a6a3367ceaf79db5dd76264659d509d73b0", size = 30662, upload-time = "2025-10-02T14:37:01.743Z" }, - { url = "https://files.pythonhosted.org/packages/b8/0b/b14510b38ba91caf43006209db846a696ceea6a847a0c9ba0a5b1adc53d6/xxhash-3.6.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5dc1e14d14fa0f5789ec29a7062004b5933964bb9b02aae6622b8f530dc40296", size = 41056, upload-time = "2025-10-02T14:37:02.879Z" }, - { url = "https://files.pythonhosted.org/packages/50/55/15a7b8a56590e66ccd374bbfa3f9ffc45b810886c8c3b614e3f90bd2367c/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:881b47fc47e051b37d94d13e7455131054b56749b91b508b0907eb07900d1c13", size = 36251, upload-time = "2025-10-02T14:37:04.44Z" }, - { url = "https://files.pythonhosted.org/packages/62/b2/5ac99a041a29e58e95f907876b04f7067a0242cb85b5f39e726153981503/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6dc31591899f5e5666f04cc2e529e69b4072827085c1ef15294d91a004bc1bd", size = 32481, upload-time = "2025-10-02T14:37:05.869Z" }, - { url = "https://files.pythonhosted.org/packages/7b/d9/8d95e906764a386a3d3b596f3c68bb63687dfca806373509f51ce8eea81f/xxhash-3.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:15e0dac10eb9309508bfc41f7f9deaa7755c69e35af835db9cb10751adebc35d", size = 31565, upload-time = "2025-10-02T14:37:06.966Z" }, ] [[package]] @@ -5625,12 +4393,3 @@ sdist = { url = "https://files.pythonhosted.org/packages/f6/08/3cb9f67a8d48021ac wheels = [ { url = "https://files.pythonhosted.org/packages/a8/a9/d23012099dc88ec69a29c6407b41d89681cb674c2043cd5b467c7e299c08/xyzservices-2026.3.0-py3-none-any.whl", hash = "sha256:503183d4b322bfebc3c50cdd21192aa3e81e36c5efbf9133d54ae82143e0576b", size = 94101, upload-time = "2026-03-30T14:42:24.608Z" }, ] - -[[package]] -name = "zipp" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, -]