From 7788c1efe686150ba7f0940b84da6008e44c4344 Mon Sep 17 00:00:00 2001 From: prrao87 Date: Sat, 24 Oct 2026 10:28:53 -0400 Subject: [PATCH 1/5] docs: state the project's goals and scope, credit DataFusion Add a Goals section (single-machine, openCypher on Lance, multimodal knowledge graphs, DataFusion for graph traversal), mark distributed execution as out of scope, and move the credits to the end with Apache DataFusion's contributors alongside lance-graph's. --- README.md | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0c9d964..d548864 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,27 @@ Apache DataFusion, with Python bindings. It is a fork of [lance-graph](https://g and a research test bed: it pushes the limits of CSR indexes and DataFusion on top of the Lance format, with the goal of making multi-hop path traversal fast. +## Goals + +lance-csr is built for single-machine execution. It aims to: + +- **Provide a fast, lightweight and portable query engine.** An openCypher-compatible engine on top of the Lance + format that runs on one machine, inside your process, with no server to operate. +- **Enable multimodal knowledge graphs.** Lance stores images, video, audio and other media alongside vectors and + structured columns. lance-csr runs fast path traversal queries over those same datasets, so a knowledge graph + works on a single copy of the data instead of a second copy in a separate graph database. +- **Push the limits of DataFusion for graph traversal.** We want to find out how far DataFusion's execution engine + can go in powering multi-hop graph traversal, an area with little open-source work so far. + +### Out of scope: distributed execution + +Graph queries across multiple machines are **explicitly out of scope** for this repository, to keep it free of +complexity that works against the goals above. **Issues and pull requests that target distributed execution will +be closed as out of scope.** + +If your use case involves distributed graph query processing or graph algorithms, that is exactly the kind of +engine we're building at HDC Labs. [Reach out to us](https://hyperdimensionalcomputing.ai/contact/) to chat more. + ## Why a CSR lance-graph runs each relationship hop as a join between the edge and node tables. A multi-hop query repeats that @@ -30,21 +51,13 @@ DataFusion as extension operators, falling back to a join for any hop the CSR ca - **Current dependencies** (Lance 13, DataFusion 54, Arrow 58, PyO3 0.28), with Delta Lake and Unity Catalog support removed. -## Credits - -lance-csr exists thanks to the maintainers and contributors of lance-graph, who built the foundation it stands on: -the Cypher parser, semantic analysis, the DataFusion planner, the graph configuration and the Python bindings. -See [`NOTICE`](NOTICE) for the fork point. -maintainers. - -This repository contains: +## Repository layout - `crates/lance-graph` – the Cypher-capable query engine implemented in Rust - `python/` – PyO3 bindings and Python packages: - `lance_csr` – thin wrapper around the Rust query engine -See `docs/project_structure.md` for the proposed workspace-based structure from -issue #92. +See [`docs/project_structure.md`](docs/project_structure.md) for the full workspace layout. ## Prerequisites @@ -174,3 +187,14 @@ Numbers are illustrative; your hardware, compiler, and runtime load will affect ## External Wiki For additional documentation, architecture, and examples, see the DeepWiki page: [DeepWiki — lance-graph](https://deepwiki.com/lancedb/lance-graph) + +## Credits + +lance-csr builds on the work of two open-source projects: + +- The maintainers and contributors of [lance-graph](https://github.com/lance-format/lance-graph), who built the + foundation lance-csr stands on: the Cypher parser, semantic analysis, the DataFusion planner, the graph + configuration and the Python bindings. See [`NOTICE`](NOTICE) for the fork point. +- The contributors of [Apache DataFusion](https://github.com/apache/datafusion), whose query engine does much of + the work here: planning, optimization and vectorized execution, which lance-csr extends with its CSR traversal + operators. From d48e7c617d7f32f6274418b206b0eb779da39dc4 Mon Sep 17 00:00:00 2001 From: prrao87 Date: Sat, 24 Oct 2026 10:46:22 -0400 Subject: [PATCH 2/5] docs: show the LDBC 30-query benchmark, drop stale upstream references Replace the old Criterion numbers with lance-csr's results on graph-benchmark-ldbc next to Neo4j, Kuzu, Ladybug and lance-graph, remove the upstream DeepWiki link, describe the actual workspace layout, and point the examples at lance-csr and a working build command. --- README.md | 85 ++++++++++++++++++++++----------------- docs/project_structure.md | 77 ++++++++++++----------------------- examples/README.md | 16 +++++--- examples/basic_cypher.py | 4 +- examples/kg_traversal.py | 4 +- 5 files changed, 89 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index d548864..319efbe 100644 --- a/README.md +++ b/README.md @@ -151,42 +151,55 @@ r2 = engine.execute("SELECT name FROM person ORDER BY age DESC LIMIT 2") ## Benchmarks -- Requirements: - - protoc: install `protobuf-compiler` (Debian/Ubuntu: `sudo apt-get install -y protobuf-compiler`). - - Optional: gnuplot for Criterion's gnuplot backend; otherwise the plotters backend is used. - -- Run (from `crates/lance-graph`): - -```bash -cargo bench --bench graph_execution - -# Quicker local run (shorter warm-up/measurement): -cargo bench --bench graph_execution -- --warm-up-time 1 --measurement-time 2 --sample-size 10 -``` - -- Reports: - - Global index: `crates/lance-graph/target/criterion/report/index.html` - - Group index: `crates/lance-graph/target/criterion/cypher_execution/report/index.html` - -- Typical results (x86_64, quick run: warm-up 1s, measurement 2s, sample size 10): - -| Benchmark | Size | Median time | Approx. throughput | -|--------------------------|-----------|-------------|--------------------| -| basic_node_filter | 100 | ~680 µs | ~147 Kelem/s | -| basic_node_filter | 10,000 | ~715 µs | ~13.98 Melem/s | -| basic_node_filter | 1,000,000 | ~743 µs | ~1.35 Gelem/s | -| single_hop_expand | 100 | ~2.79 ms | ~35.9 Kelem/s | -| single_hop_expand | 10,000 | ~3.77 ms | ~2.65 Melem/s | -| single_hop_expand | 1,000,000 | ~3.70 ms | ~270 Melem/s | -| two_hop_expand | 100 | ~4.52 ms | ~22.1 Kelem/s | -| two_hop_expand | 10,000 | ~6.41 ms | ~1.56 Melem/s | -| two_hop_expand | 1,000,000 | ~6.16 ms | ~162 Melem/s | - -Numbers are illustrative; your hardware, compiler, and runtime load will affect results. - -## External Wiki - -For additional documentation, architecture, and examples, see the DeepWiki page: [DeepWiki — lance-graph](https://deepwiki.com/lancedb/lance-graph) +lance-csr is benchmarked with [graph-benchmark-ldbc](https://github.com/hyperdimensionalcomputingai/graph-benchmark-ldbc): +30 Cypher queries over the LDBC SNB SF1 dataset (3.18M nodes, 17.3M relationships), with every result checked +against an expected answer. These are independent, unaudited measurements, not LDBC Benchmark Results. + +Mean query latency in milliseconds (lower is better, fastest per query in bold), on an Apple M5 MacBook Pro running +macOS 26.6. lance-csr runs with the CSR (`use_csr=True`) in two modes: *in memory* holds every table as Arrow in +memory, and *lazy* reads Lance datasets from disk as queries need them. + +| Query | lance-csr 0.1.0, in memory | lance-csr 0.1.0, lazy | Neo4j 2026.09.0 | Kuzu 0.11.3 | Ladybug 0.21.2 | lance-graph 0.5.4 | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | +| Q1 | **0.64** | 1.34 | 3.14 | 3.25 | 1.00 | 1.40 | +| Q2 | **0.55** | 1.45 | 4.66 | 1.58 | 1.17 | 2.29 | +| Q3 | **0.66** | 0.80 | 1.59 | 1.61 | 0.78 | 1.95 | +| Q4 | 0.52 | 0.81 | 3.11 | 1.07 | **0.37** | 3.02 | +| Q5 | **0.79** | 2.15 | 3.51 | 3.99 | 3.98 | 2.04 | +| Q6 | **0.45** | 0.72 | 2.52 | 1.04 | 0.79 | 0.72 | +| Q7 | 1.07 | 1.08 | **0.91** | 28.76 | 25.46 | 16.59 | +| Q8 | **0.66** | 1.77 | 13.51 | 2.80 | 3.52 | 1.61 | +| Q9 | **0.84** | 1.36 | 1.62 | 1.91 | 1.33 | 2.33 | +| Q10 | **0.75** | 0.96 | 5.11 | 1.60 | 1.56 | 32.58 | +| Q11 | **1.50** | 1.98 | 14.94 | 8.93 | 4.08 | 3.27 | +| Q12 | **0.72** | 6.81 | 3.71 | 21.03 | 8.10 | 21.67 | +| Q13 | **0.76** | 1.01 | 9.45 | 44.76 | 5.70 | 9.79 | +| Q14 | **0.50** | 0.64 | 0.83 | 1.76 | 0.89 | 2.50 | +| Q15 | **0.53** | 0.71 | 2.71 | 3.03 | 1.10 | 2.17 | +| Q16 | **0.66** | 1.08 | 1.45 | 2.05 | 1.00 | 4.19 | +| Q17 | **0.93** | 1.40 | 3.61 | 3.16 | 1.72 | 2.39 | +| Q18 | **0.66** | 1.06 | 3.72 | 1.48 | 1.20 | 1.89 | +| Q19 | **0.96** | 1.33 | 6.82 | 16.76 | 3.15 | 20.96 | +| Q20 | **2.05** | 16.54 | 478.58 | 11.64 | 13.61 | 2.98 | +| Q21 | 0.72 | 0.80 | 1.00 | **0.43** | 0.52 | 1.51 | +| Q22 | **0.68** | 0.88 | 3.14 | 28.00 | 7.88 | 14.27 | +| Q23 | **0.70** | 1.22 | 4.78 | 1.17 | 0.73 | 2.47 | +| Q24 | **0.66** | 1.03 | 1.16 | 1.16 | 0.79 | 1.79 | +| Q25 | **0.76** | 1.14 | 3.74 | 1.43 | 1.37 | 1.35 | +| Q26 | **0.71** | 1.02 | 1.18 | 3.46 | 1.15 | 2.88 | +| Q27 | **0.82** | 1.26 | 2.77 | 14.32 | 4.50 | 24.70 | +| Q28 | **1.29** | 2.25 | 4.12 | 1.48 | 2.32 | 2.50 | +| Q29 | **0.65** | 0.98 | 3.36 | 1.00 | 0.76 | 2.73 | +| Q30 | **36.17** | 37.09 | 1,255.75 | 149.55 | 92.89 | 38.17 | + +Over the 30 queries (geometric mean), lance-csr in memory is 5.1× faster than Neo4j, 4.4× faster than Kuzu, 2.5× +faster than Ladybug and 4.6× faster than lance-graph; in lazy mode it is 3.0×, 2.6×, 1.5× and 2.7× faster. + +- Neo4j, Kuzu, Ladybug and lance-graph numbers are from graph-benchmark-ldbc's 2026-10-16 run. lance-csr was measured + on 2026-10-23 on the same machine with the same pytest-benchmark settings (the faster of two passes); its runner + is not yet part of that repository. +- Neo4j runs as a server in a Docker VM; the other engines run embedded in the Python process. See the benchmark + repository for each engine's configuration and how to reproduce the runs. ## Credits diff --git a/docs/project_structure.md b/docs/project_structure.md index 09296f0..1382766 100644 --- a/docs/project_structure.md +++ b/docs/project_structure.md @@ -1,59 +1,32 @@ -Project Structure Proposal (Issue #92) -====================================== +# Project structure -This document captures a pragmatic "proper" structure for lance-graph based on -issue #92. It focuses on clearer separation of concerns, a Cargo workspace, and -first-class Python bindings. - -Goals ------ -- Keep lightweight crates usable without pulling in heavy dependencies. -- Allow custom graph-native operators without forcing everything through SQL. -- Make Python bindings and examples first-class citizens. - -Current Layout (after refactor) -------------------------------- -- `crates/lance-graph/` hosts the Rust engine crate. -- `python/` contains PyO3 bindings plus the `lance_csr` Python package. -- `examples/` holds simple Cypher usage examples. - -Proposed Layout (Workspace) ---------------------------- -The issue recommends moving to a Cargo workspace to split functionality and -avoid pulling DataFusion/Tokio into every consumer: +lance-csr is a Cargo workspace with Python bindings. The Rust crates keep the `lance-graph*` names of the project +it was forked from. ``` -lance-graph/ -├── Cargo.toml # Workspace definition -├── README.md # Unified docs -├── docs/ # ADRs + design notes +. +├── Cargo.toml # Workspace: lance-graph, lance-graph-catalog, lance-graph-benches ├── crates/ -│ ├── lance-graph/ # Facade crate (re-exports) -│ ├── lance-graph-core/ # AST + schema types (no heavy deps) -│ └── lance-graph-planner/ # Cypher -> LogicalPlan -├── python/ # PyO3 + Python packages -└── examples/ # End-to-end examples +│ ├── lance-graph/ # The engine: Cypher parser, semantic analysis, logical planner, +│ │ # DataFusion planner, CSR index and traversal operators +│ ├── lance-graph-catalog/ # Graph source catalog and DirNamespace +│ ├── lance-graph-python/ # PyO3 bindings (built by maturin; outside the workspace) +│ └── lance-graph-benches/ # Criterion benchmarks (not published) +├── python/ +│ ├── pyproject.toml # The lance-csr package, built with maturin +│ ├── python/lance_csr/ # Python package that wraps the bindings +│ ├── python/tests/ # Python tests +│ └── benchmarks/ # Engine benchmarks (catalog reuse, bounded memory, CSR) +├── examples/ # Runnable Python examples +├── ci/check_wheel.py # Checks a built wheel in a clean environment, without Rust +└── docs/ # Documentation ``` -Why this helps --------------- -- `lance-graph-core` can be reused by tooling and schema validators without - DataFusion or Tokio. -- `lance-graph-planner` keeps translation logic isolated for easier evolution. -- A future `lance-graph-physical` crate can be introduced once we have - substantial graph-native kernels (traversal, vector search). -- The facade crate offers a stable public API while allowing internal churn. +A query goes through four stages, all in `crates/lance-graph/src/`: -Suggested Migration Steps -------------------------- -1. Add a top-level `Cargo.toml` workspace and move the existing Rust crate into - `crates/lance-graph/` without changing its internal module layout. -2. Extract AST + schema types into `crates/lance-graph-core/` and update - references. -3. Split the planner (`Cypher -> LogicalPlan`) into `lance-graph-planner`. -4. Refactor the Simple executor so it lives in the workspace cleanly (either - inside the facade crate or as a `lance-graph-simple` crate). -5. Update `crates/lance-graph-python/Cargo.toml` to depend on the workspace crates. -6. Add ADRs for each step under `docs/` to document tradeoffs. -7. Update GitHub workflows to match the new workspace paths (build, test, - release/publish), otherwise releases will fail. +1. **Parse** (`parser.rs`) the Cypher text into an AST (`ast.rs`). +2. **Analyze** (`semantic.rs`) variables and scopes, and substitute parameters. +3. **Plan** (`logical_plan.rs`) graph operators: scans, expansions, variable-length paths, OPTIONAL MATCH, + comprehensions and shortest paths. +4. **Build** (`datafusion_planner/`) a DataFusion plan from them, with CSR expansions (`csr_expand.rs`) and the + shortest-path search (`shortest_path.rs`) as DataFusion extension operators. diff --git a/examples/README.md b/examples/README.md index e324855..04ae0e3 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,4 +1,4 @@ -# Examples for lance-graph +# Examples for lance-csr ## How to Run Examples @@ -9,7 +9,7 @@ Pick one of the two approaches: ```bash # From the repo root; installs the Python extension in editable mode pip install pyarrow # or: uv pip install pyarrow -maturin develop -m crates/lance-graph-python/Cargo.toml +(cd python && maturin develop) # Run examples python examples/basic_cypher.py @@ -24,7 +24,7 @@ uv venv .venv && . .venv/bin/activate # Install dependencies and build editable extension uv pip install pyarrow -uvx --from maturin maturin develop -m crates/lance-graph-python/Cargo.toml +(cd python && uvx --from maturin maturin develop) # Run examples using the venv's Python python examples/basic_cypher.py @@ -33,10 +33,10 @@ python examples/kg_traversal.py ### 2) Install the package, then run -- From PyPI (when published): +- From PyPI: ```bash -pip install lance-graph pyarrow +pip install lance-csr pyarrow python examples/basic_cypher.py python examples/kg_traversal.py ``` @@ -71,3 +71,9 @@ python examples/basic_cypher.py ```bash python examples/kg_traversal.py ``` + +- `lance_snapshot_refresh.py`: lazy Lance datasets, snapshots and `refresh()`. + +```bash +python examples/lance_snapshot_refresh.py +``` diff --git a/examples/basic_cypher.py b/examples/basic_cypher.py index cbdc5bd..ccf20b2 100644 --- a/examples/basic_cypher.py +++ b/examples/basic_cypher.py @@ -1,9 +1,9 @@ """ -Basic Cypher graph query using the lance-graph Python bindings. +Basic Cypher graph query using the lance-csr Python bindings. Requirements: - Build/install the Python extension first (from repo root): - maturin develop -m crates/lance-graph-python/Cargo.toml + cd python && maturin develop - Python deps: pyarrow Run: diff --git a/examples/kg_traversal.py b/examples/kg_traversal.py index deef3f2..08dabe2 100644 --- a/examples/kg_traversal.py +++ b/examples/kg_traversal.py @@ -1,9 +1,9 @@ """ -Simple knowledge-graph multi-hop traversal with lance-graph Python bindings. +Simple knowledge-graph multi-hop traversal with lance-csr Python bindings. Requirements: - Build/install the Python extension first (from repo root): - maturin develop -m crates/lance-graph-python/Cargo.toml + cd python && maturin develop - Python deps: pyarrow Run: From ccfaba567e734cb66b1be5642fd435ac7513aecb Mon Sep 17 00:00:00 2001 From: prrao87 Date: Sat, 24 Oct 2026 10:52:12 -0400 Subject: [PATCH 3/5] docs: bring the build steps up to date One build, maturin develop --extras tests,dev, instead of an editable install followed by maturin develop; protoc listed as a requirement; workspace-wide cargo commands from the repository root. The Makefile's targets now work (test ran one file through a broken uv invocation), and DEVELOPMENT.md describes this project instead of Lance's tracing, S3 tests, vector benchmarks and manylinux2014 wheels. The package authors are lance-csr's, not lance-graph's. --- AGENTS.md | 9 +- README.md | 51 ++++--- python/CLAUDE.md | 6 +- python/DEVELOPMENT.md | 347 +++++++----------------------------------- python/Makefile | 36 +++-- python/README.md | 35 +---- python/pyproject.toml | 2 +- 7 files changed, 114 insertions(+), 372 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index deb11b4..cd3be7d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,15 +9,14 @@ - `examples/` demonstrates Cypher usage; update or add examples when introducing new public APIs. ## Build, Test, and Development Commands -- `cargo check` / `cargo test --all` (run inside `crates/lance-graph`) validate Rust code paths. +- `cargo test --workspace` (from the repository root) runs the Rust tests; building needs `protoc`. - `cargo bench --bench graph_execution -p lance-graph-benches` measures performance-critical changes; include shortened runs with `--warm-up-time 1`. -- `uv venv --python 3.12 .venv` and `uv pip install -e '.[tests]'` bootstrap the Python workspace. -- `maturin develop` rebuilds the extension after Rust edits; `pytest python/python/tests/ -v` exercises Python bindings. -- `make lint` (in `python/`) runs `ruff`, formatting checks, and `pyright`. +- In `python/`: `make venv` and `make install` (`maturin develop --extras tests,dev`) bootstrap the Python environment with a debug build; re-run `make install` after Rust edits. +- `make test` runs the Python tests; `make lint` runs `ruff`, formatting checks, and `pyright`. ## Coding Style & Naming Conventions - Format Rust with `cargo fmt --all`; keep modules and functions snake_case, types PascalCase, and reuse `snafu` error patterns. -- Run `cargo clippy --all-targets --all-features` to catch lint regressions. +- Run `cargo clippy --workspace --all-targets -- -D warnings` to catch lint regressions, as CI does. - Use 4-space indentation in Python; maintain snake_case modules, CamelCase classes, and type-annotated public APIs. - Apply `ruff format python/` before committing; `ruff check` and `pyright` enforce import hygiene and typing. diff --git a/README.md b/README.md index 319efbe..180b1a9 100644 --- a/README.md +++ b/README.md @@ -59,20 +59,6 @@ DataFusion as extension operators, falling back to a join for any hop the CSR ca See [`docs/project_structure.md`](docs/project_structure.md) for the full workspace layout. -## Prerequisites - -- Rust toolchain (`rust-toolchain.toml` pins the version; rustup installs it automatically) -- Python 3.12 or newer -- [`uv`](https://docs.astral.sh/uv/) available on your `PATH` - -## Rust crate quick start - -```bash -cd crates/lance-graph -cargo check -cargo test -``` - ## Install ```bash @@ -82,20 +68,39 @@ pip install lance-csr Prebuilt wheels cover Linux x86-64 and native Apple Silicon (CPython 3.12+); no Rust toolchain is needed. See [`python/README.md`](python/README.md) for details and usage. -## Python package quick start (from source) +## Build from source + +You need: + +- Rust, through [rustup](https://rustup.rs): `rust-toolchain.toml` pins the version, and rustup installs it on the + first build. +- `protoc`, which Lance's build needs: `brew install protobuf` on macOS, or + `sudo apt-get install -y protobuf-compiler` on Debian and Ubuntu. +- Python 3.12 or newer, and [`uv`](https://docs.astral.sh/uv/). + +Rust crates, from the repository root: + +```bash +cargo test --workspace +cargo clippy --workspace --all-targets -- -D warnings +cargo fmt --all --check +``` + +Python package, from `python/`: ```bash cd python -uv venv --python 3.12 .venv # create the local virtualenv -source .venv/bin/activate # activate the virtual environment -uv pip install 'maturin[patchelf]' # install build tool -uv pip install -e '.[tests]' # editable install with test extras -maturin develop # build and install the Rust extension -pytest python/tests/ -v # run the test suite +uv venv --python 3.12 .venv +source .venv/bin/activate +uv pip install 'maturin[patchelf]' +maturin develop --extras tests,dev # builds the extension, installs lance-csr with test and lint tools +pytest python/tests # run the tests +make lint # ruff and pyright ``` -> If another virtual environment is already active, run `deactivate` (or -> `unset VIRTUAL_ENV`) before the `uv run` command so uv binds to `.venv`. +`maturin develop` makes a debug build, which compiles quickly; re-run it after changing Rust code. For timing +queries, build with `maturin develop --release` instead: release builds use thin LTO and take several minutes. +See [`python/DEVELOPMENT.md`](python/DEVELOPMENT.md) for more. ## Python example: Cypher query diff --git a/python/CLAUDE.md b/python/CLAUDE.md index 5dc645d..d301abc 100644 --- a/python/CLAUDE.md +++ b/python/CLAUDE.md @@ -1,8 +1,8 @@ -Use the makefile for most actions: +Use the Makefile for most actions (from `python/`): -* Build: `maturin develop` +* Set up: `make venv`, then `make install` (debug build with test and lint tools) +* Rebuild after Rust changes: `make install` or `maturin develop` * Test: `make test` * Run single test: `pytest python/tests/.py::` -* Doctest: `make doctest` * Lint: `make lint` * Format: `make format` diff --git a/python/DEVELOPMENT.md b/python/DEVELOPMENT.md index 7c9a9c3..76cb0d5 100644 --- a/python/DEVELOPMENT.md +++ b/python/DEVELOPMENT.md @@ -1,347 +1,102 @@ # Development -## Building the project +## Requirements -This project is built with [maturin](https://github.com/PyO3/maturin) and uses -[uv](https://docs.astral.sh/uv/) to manage a local virtual environment. The Rust -extension crate now lives at `crates/lance-graph-python/`; `pyproject.toml` -already points maturin at that manifest, so `maturin develop` from `python/` -continues to work. +- Rust, through [rustup](https://rustup.rs). `rust-toolchain.toml` at the repository root pins the version, with + `clippy` and `rustfmt`; rustup installs it on the first build. +- `protoc` for Lance's build: `brew install protobuf` on macOS, `sudo apt-get install -y protobuf-compiler` on + Debian and Ubuntu. +- Python 3.12 or newer, and [uv](https://docs.astral.sh/uv/). -Recommended uv workflow: +## Building the extension -```shell -cd python -uv venv --python 3.12 .venv -source .venv/bin/activate -uv pip install maturin[patchelf] -uv pip install -e '.[tests]' -maturin develop -``` - -Notes: -- If another virtual environment is active, run `deactivate` first so uv binds to `.venv`. -- After changing Rust code, re-run `maturin develop`. Pure-Python changes do not require rebuilds. - -## Running tests - -You can run tests either via the Makefile (uses uv under the hood) or directly with uv. - -Using Makefile (recommended): - -```shell -cd python -make test -``` - -Directly with uv: +The package is built with [maturin](https://github.com/PyO3/maturin). `pyproject.toml` points it at the bindings +crate in `crates/lance-graph-python/`, so run maturin from this `python/` directory. ```shell cd python -uv run pytest -v python/python/tests +make venv # uv venv --python 3.12 .venv +make install # maturin develop --extras tests,dev: debug build, plus pytest, pandas, ruff and pyright ``` -To check the documentation examples, use +Or by hand, with the environment activated: ```shell -make doctest +uv venv --python 3.12 .venv +source .venv/bin/activate +uv pip install 'maturin[patchelf]' +maturin develop --extras tests,dev ``` -## Formatting and linting +`maturin develop` installs the package in editable mode: changes to `python/lance_csr/` take effect immediately, +while Rust changes need another `maturin develop`. -To run formatters, run: +Debug builds compile quickly but run queries much more slowly. To time queries, build optimized code with +`maturin develop --release`. Release builds use thin LTO and one codegen unit (`.cargo/config.toml`), so they take +several minutes. Alternating `maturin develop` and `maturin build` in the same environment invalidates each other's +build cache, so pick one per environment. -```shell -make format -``` - -(To run for just Python or just Rust, use `make format-python` or `cargo fmt`.) +If another virtual environment is active, run `deactivate` first so the commands use `.venv`. -To run format checker and linters, run: +## Tests ```shell -make lint +make test # every Python test +pytest python/tests/test_engine_csr.py -k undirected # a subset ``` -(To run for just Python or just Rust, use `make lint-python` or `make lint-rust`.) - -### Format and lint on commit - -If you would like to run the formatters and linters when you commit your code -then you can use the pre-commit tool. The project includes a pre-commit config -file already. First, install the pre-commit tool: +The Rust tests run from the repository root: ```shell -pip install pre-commit +cargo test --workspace ``` -Then install the hooks: +## Formatting and linting ```shell -pre-commit install +make format # ruff format +make lint # ruff check, ruff format --check, pyright ``` -From now any, any attempt to commit, will first run the linters against the -modified files: - -```shell -$ git commit -m "Changed some python files" -black....................................................................Passed -isort (python)...........................................................Passed -ruff.....................................................................Passed -[main daf91ed] Changed some python files - 1 file changed, 1 insertion(+), 1 deletion(-) -``` +For Rust, from the repository root (CI runs the same checks): -## Cleaning build artifacts -To clean up build artifacts, run: ```shell -make clean +cargo fmt --all --check +cargo clippy --workspace --all-targets -- -D warnings ``` ## Benchmarks -The benchmarks in `python/benchmarks` can be used to identify and diagnose -performance issues. They are run with [pytest-benchmark](https://pytest-benchmark.readthedocs.io/en/latest/). -These benchmarks aren't mean to showcase performance on full-scale real world -datasets; rather they are meant to be useful for developers to iterate on -performance improvements and to catch performance regressions. Therefore, any -benchmarks added there should run in less than 5 seconds. - -Before running benchmarks, you should build pylance in release mode: +`python/benchmarks/` holds scripts for the engine's own costs: catalog reuse, bounded-memory streaming, CSR expansion +and incremental CSR maintenance. Build with `maturin develop --release` before running them. The Rust Criterion +benchmarks live in the `lance-graph-benches` crate: ```shell -maturin develop --profile release-with-debug --extras benchmarks --features datagen +cargo bench -p lance-graph-benches --bench graph_execution -- --warm-up-time 1 ``` -(You can also use `--release` or `--profile release`, but `--profile release-with-debug` -will provide debug symbols for profiling.) +For comparisons with other graph engines on LDBC SNB SF1, see +[graph-benchmark-ldbc](https://github.com/hyperdimensionalcomputingai/graph-benchmark-ldbc). -Then you can run the benchmarks with +## Building wheels -```shell -pytest python/benchmarks -m "not slow" -``` - -Note: the first time you run the benchmarks, they may take a while, since they -will write out test datasets and build vector indices. Once these are built, -they are re-used between benchmark runs. - -Some benchmarks are especially slow, so they are skipped `-m "not slow"`. To run -the slow benchmarks, use: - -```shell -pytest python/benchmarks -``` +The published wheels are built by `.github/workflows/python-publish.yml`: Linux x86-64 for glibc 2.28 +(manylinux_2_28) and native Apple Silicon, plus an sdist. Each wheel is tested in a clean environment without Rust, +by `ci/check_wheel.py` and the full test suite. -### Run a particular benchmark - -To filter benchmarks by name, use the usual pytest `-k` flag (this can be a -substring match, so you don't need to type the full name): +To build a wheel for your own machine: ```shell -pytest python/benchmarks -k test_ivf_pq_index_search +make wheel # maturin build --release --out dist --sdist ``` -### Profile a benchmark - -If you have [cargo-flamegraph](https://github.com/flamegraph-rs/flamegraph) -installed, you can create a flamegraph of a benchmark by running: - -```shell -flamegraph -F 100 --no-inline -- $(which python) \ - -m pytest python/benchmarks \ - --benchmark-min-time=2 \ - -k test_ivf_pq_index_search -``` - -Note the parameter `--benchmark-min-time`: this controls how many seconds to run -the benchmark in each round (default 5 rounds). The default is very low but you -can increase this so that the profile gets more samples. - -You can drop the `--no-inline` to have the program try to identify which functions -were inlined to get more detail, though this will make the processing take -considerably longer. - -This will only work on Linux. - -Note that you'll want to run the benchmarks once prior to profiling, so that -the setup is complete and not captured as part of profiling. - -### Compare benchmarks against previous version - -You can easily compare the performance of the current version against `main`. -Checkout `main` branch, run the benchmarks, and save -the output using `--benchmark-save`. Then install the current version and run -the benchmarks again with `--benchmark-compare`. - -```shell -CURRENT_BRANCH=$(git branch --show-current) -git checkout main -maturin develop --profile release-with-debug --features datagen -pytest --benchmark-save=baseline python/benchmarks -m "not slow" -COMPARE_ID=$(ls .benchmarks/*/ | tail -1 | cut -c1-4) -git checkout $CURRENT_BRANCH -maturin develop --profile release-with-debug --features datagen -pytest --benchmark-compare=$COMPARE_ID python/benchmarks -m "not slow" -``` - -## Tracing - -Rust has great integration with tools like criterion and pprof which make it easy -to profile and debug CPU intensive tasks. However, these tools are not as effective -at profiling I/O intensive work or providing a high level trace of an operation. - -To fill this gap the lance code utlizies the Rust tracing crate to provide tracing -information for lance operations. User applications can receive these events and -forward them on for logging purposes. Developers can also use this information to -get a sense of the I/O that happens during an operation. - -### Instrumenting code - -When instrumenting code you can use the `#[instrument]` macro from the Rust tracing -crate. See the crate docs for more information on the various parameters that can -be set. As a general guideline we should aim to instrument the following methods: - -- Top-level methods that will often be called by external libraries and could be slow -- Compute intensive methods that will perform a significant amount of CPU compute -- Any point where we are waiting on external resources (e.g. disk) - -To begin with, instrument methods as close to the user as possible and refine downwards -as you need. For example, start by instrumenting the entire dataset write operation -and then instrument any individual parts of the operation that you would like to see -details for. - -### Tracing a unit test - -If you would like tracing information for a rust unit test then you will need to -decorate your test with the lance_test_macros::test attribute. This will wrap any -existing test attributes that you are using: - -```rust -#[lance_test_macros::test(tokio::test)] -async fn test() { - ... -} -``` - -Then, when running your test, you will need to set the environment variable -LANCE_TRACING to the your desired verbosity level (trace, debug, info, warn, error): - -```bash -LANCE_TESTING=debug cargo test dataset::tests::test_create_dataset -``` - -This will create a .json file (named with a timestamp) in your working directory. This -.json file can be loaded by chrome or by - -### Tracing a python script - -If you would like to trace a python script (application, benchmark, test) then you can easily -do so using the lance.tracing module. Simply call: - -```python -from lance.tracing import trace_to_chrome - -trace_to_chrome(level="debug") - -# rest of script -``` - -A single .json trace file will be generated after python has exited. - -You can use the `trace_to_chrome` function within the benchmarks, but for -sensible results you'll want to force the benchmark to just run only once. -To do this, rewrite the benchmark using the pedantic API: - -```python -def run(): - "Put code to benchmark here" - ... -benchmark.pedantic(run, iterations=1, rounds=1) -``` - -### Trace visualization limitations - -The current tracing implementation is slightly flawed when it comes to async -operations that run in parallel. The rust tracing-chrome library emits -trace events into the chrome trace events JSON format. This format is not -sophisticated enough to represent asynchronous parallel work. - -As a result, a single instrumented async method may appear as many different -spans in the UI. - -## Running S3 Integration tests - -The integration tests run against local minio and local dynamodb. To start the -services, run - -```shell -docker compose up -``` - -Then you can run the tests with - -```shell -pytest --run-integration python/tests/test_s3_ddb.py -``` - -## Building wheels locally - -### Linux - -On Mac or Linux, you can build manylinux wheels locally for Linux. The easiest -way to do this is to use `zig` with `maturin build`. Before you do this, you'll -need to make you (1) [install zig](https://github.com/ziglang/zig/wiki/Install-Zig-from-a-Package-Manager) -and (2) install the toolchains: +To build the Linux x86-64 wheel the way CI does, on macOS or Linux, install [zig](https://ziglang.org) (for example +`pip install ziglang`) and the target, then: ```shell rustup target add x86_64-unknown-linux-gnu -rustup target add aarch64-unknown-linux-gnu -``` - -For x86 Linux: - -```shell -maturin build --release --zig \ +maturin build --release --locked --strip --zig \ --target x86_64-unknown-linux-gnu \ - --compatibility manylinux2014 \ - --out wheels -``` - -For ARM / aarch64 Linux: - -```shell -maturin build --release --zig \ - --target aarch_64-unknown-linux-gnu \ - --compatibility manylinux2014 \ - --out wheels -``` - -### MacOS - -On a Mac, you can build wheels locally for MacOS: - -```shell -maturin build --release \ - --target aarch64-apple-darwin \ - --out wheels + --compatibility manylinux_2_28 \ + --out dist ``` - -```shell -maturin build --release \ - --target x86_64-apple-darwin \ - --out wheels -``` - -## Picking a thread pool - -When an operation should run in parallel you typically need to specify how many threads -to use. For example, as input to `StreamExt::buffered`. There are two numbers you can -use. You can use `ObjectStore::io_parallelism` or `get_num_compute_intensive_cpus`. - -Often, operations will do a little of both compute and I/O, and you will need to make -a judgement call. If you are unsure, and you are doing any I/O, then picking the -`io_parallelism` is a good fallback behavior. The worst case is just that we over-parallelize -and there is more CPU contention then there needs to be. If this becomes a problem we -can always split the operation into two parts and use the two different thread pools. diff --git a/python/Makefile b/python/Makefile index 70f5b47..1f7859e 100644 --- a/python/Makefile +++ b/python/Makefile @@ -1,28 +1,34 @@ UV ?= uv PYTHON ?= 3.12 -PYTEST_ARGS ?= -vv -s +VENV ?= .venv +PYTEST_ARGS ?= -q +BIN := $(VENV)/bin -export PATH := $(HOME)/.local/bin:$(PATH) - -.PHONY: venv install test lint clean publish +.PHONY: venv install test lint format wheel clean +# A virtual environment for development. venv: - $(UV) venv --python $(PYTHON) .venv + $(UV) venv --python $(PYTHON) $(VENV) +# Debug build of the extension, installed with the test and lint tools. install: - $(UV) pip install --project . --editable . --extra tests + $(UV) pip install --python $(BIN)/python 'maturin[patchelf]' + VIRTUAL_ENV=$(abspath $(VENV)) $(BIN)/maturin develop --extras tests,dev test: - $(UV) run --project . --with tests pytest $(PYTEST_ARGS) python/python/tests/test_graph.py + $(BIN)/pytest $(PYTEST_ARGS) python/tests lint: - $(UV) run --project . --with dev ruff check python - $(UV) run --project . --with dev ruff format --check python - $(UV) run --project . --with dev pyright + $(BIN)/ruff check python + $(BIN)/ruff format --check python + $(BIN)/pyright -clean: - rm -rf .venv - rm -rf ../target +format: + $(BIN)/ruff format python -publish: - maturin build --release --out dist --sdist +# Release wheel and sdist for this platform, in dist/ (CI builds the published ones). +wheel: + VIRTUAL_ENV=$(abspath $(VENV)) $(BIN)/maturin build --release --out dist --sdist + +clean: + rm -rf $(VENV) dist ../crates/lance-graph-python/target diff --git a/python/README.md b/python/README.md index 6537d3f..b117297 100644 --- a/python/README.md +++ b/python/README.md @@ -187,40 +187,17 @@ r2 = engine.execute( ## Contributing -### Quick start +Building from source needs Rust (through rustup), `protoc` and uv; see [DEVELOPMENT.md](./DEVELOPMENT.md). ```bash cd python -uv venv --python 3.12 .venv -source .venv/bin/activate -uv pip install maturin[patchelf] -uv pip install -e '.[tests]' -maturin develop -pytest python/tests/ -v +make venv # uv venv --python 3.12 .venv +make install # maturin develop --extras tests,dev +make test # pytest python/tests +make lint # ruff and pyright ``` -### Development workflow - -For linting and type checks: - -```bash -# Install dev dependencies -uv pip install -e '.[dev]' - -# Run linters and type checker -ruff format python/ # format code -ruff check python/ # lint code -pyright # type check - -# Run specific tests -pytest python/tests/test_graph.py::test_basic_node_selection -v - -# Rebuild extension after Rust changes -maturin develop -``` - -> If another virtual environment is already active, run `deactivate` (or -> `unset VIRTUAL_ENV`) before invoking `uv run` so uv binds to `.venv`. +Re-run `make install` (or `maturin develop`) after changing Rust code; Python changes apply immediately. ## Repository layout diff --git a/python/pyproject.toml b/python/pyproject.toml index 768c0fe..9b84ab9 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -6,7 +6,7 @@ dependencies = [ "pylance>=13.0.0,<14", ] description = "Cypher graph queries over Lance datasets, built on DataFusion with a CSR adjacency index (a fork of lance-graph)" -authors = [{ name = "Lance Devs", email = "dev@lancedb.com" }] +authors = [{ name = "The lance-csr Authors" }] license = { file = "LICENSE" } readme = "README.md" requires-python = ">=3.12" From c0d32f94f4429b59a9c74268ed73b0b5ac7f2edb Mon Sep 17 00:00:00 2001 From: prrao87 Date: Sat, 24 Oct 2026 11:13:21 -0400 Subject: [PATCH 4/5] build: manage Python dependencies with uv sync --locked, never pip Development tools move from published extras into a uv dev dependency group, and every documented setup, the Makefile and both Python workflows install with uv sync --locked (relocked for the 3.12 floor). The publish workflow gets zig and twine through uv, tests each built wheel by path so PyPI's copy of the same version can't stand in, and builds wheels on pull requests only when the wheel build itself changes. The doctest step, which never imported the package, is gone. --- .github/workflows/python-publish.yml | 36 +++-- .github/workflows/python-test.yml | 58 ++------ AGENTS.md | 2 +- README.md | 22 +-- ci/check_wheel.py | 4 +- examples/README.md | 67 ++------- examples/basic_cypher.py | 6 +- examples/kg_traversal.py | 6 +- python/CLAUDE.md | 9 +- python/DEVELOPMENT.md | 50 ++++--- python/Makefile | 34 ++--- python/README.md | 19 ++- python/pyproject.toml | 6 +- python/uv.lock | 213 ++++++++------------------- 14 files changed, 192 insertions(+), 340 deletions(-) diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index d55f34b..a0ec82a 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -1,7 +1,9 @@ # Build, test and publish lance-csr wheels: Linux x86-64 (manylinux_2_28) and native # Apple Silicon (macOS arm64), plus an sdist for every other platform. # -# Pull requests that touch packaging build and test the wheels without publishing. +# Pull requests that change how wheels are built (this workflow, the wheel check, the +# release build profile) build and test them without publishing. Other changes rely on a +# manual mode=dry_run run before a release, to spare the ~30-minute macOS build. # A published GitHub release (tag vX.Y.Z) publishes to PyPI after every build and test # passes, through PyPI trusted publishing and the protected `pypi` environment; so does # a manual run with mode=release. mode=dry_run builds and tests only. @@ -15,10 +17,7 @@ on: paths: - .github/workflows/python-publish.yml - ci/check_wheel.py - - python/pyproject.toml - python/.cargo/** - - crates/lance-graph-python/Cargo.toml - - crates/lance-graph-python/Cargo.lock workflow_dispatch: inputs: mode: @@ -54,12 +53,16 @@ jobs: with: python-version: "3.12" + - uses: astral-sh/setup-uv@v4 + - name: Install build dependencies run: | # protoc is needed by Lance's build scripts, not by wheel users. sudo apt-get update sudo apt-get install -y protobuf-compiler - pip install ziglang + # maturin finds zig through `python3 -m ziglang`: put a Python that has it first on PATH. + uv tool install ziglang + echo "$(uv tool dir)/ziglang/bin" >> "$GITHUB_PATH" - name: Build manylinux_2_28 x86-64 wheel uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1 @@ -81,8 +84,7 @@ jobs: - name: Inspect distributions working-directory: python run: | - pip install twine - twine check dist/* + uvx twine check dist/* sha256sum dist/* - uses: actions/upload-artifact@v4 @@ -104,6 +106,8 @@ jobs: with: python-version: "3.12" + - uses: astral-sh/setup-uv@v4 + - name: Install build dependencies run: brew install protobuf @@ -119,8 +123,7 @@ jobs: - name: Inspect wheel working-directory: python run: | - pip install twine - twine check dist/*.whl + uvx twine check dist/*.whl shasum -a 256 dist/*.whl - uses: actions/upload-artifact@v4 @@ -161,13 +164,18 @@ jobs: run: | export PATH=$(echo "$PATH" | tr ':' '\n' | grep -v -e cargo -e rustup | paste -sd: -) ! command -v cargo && ! command -v rustc - uv venv --python ${{ matrix.python }} "$RUNNER_TEMP/venv" - py="$RUNNER_TEMP/venv/bin/python" - uv pip install --python "$py" --only-binary=:all: --find-links dist lance-csr pytest pandas - "$py" -I ci/check_wheel.py + # This platform's wheel, by path, so PyPI's copy of the same version can't stand in. + case "$RUNNER_OS" in + Linux) wheel=$(ls "$PWD"/dist/*manylinux*.whl) ;; + macOS) wheel=$(ls "$PWD"/dist/*macosx*.whl) ;; + esac + # A fresh environment with the wheel and test tools; --no-build refuses any sdist. + run=(uv run --isolated --no-project --no-build --python ${{ matrix.python }} + --with "$wheel" --with pytest --with pandas) + "${run[@]}" python -I ci/check_wheel.py cp -r python/python/tests "$RUNNER_TEMP/tests" cd "$RUNNER_TEMP" - "$py" -I -m pytest "$RUNNER_TEMP/tests" -q -p no:cacheprovider + "${run[@]}" python -I -m pytest "$RUNNER_TEMP/tests" -q -p no:cacheprovider publish: needs: [build-linux, build-macos, test] diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index ca80244..e8c9ef9 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -29,10 +29,6 @@ jobs: python-version: ["3.12"] steps: - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - name: Setup Rust uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: Swatinem/rust-cache@v2 @@ -45,63 +41,35 @@ jobs: sudo apt update sudo apt install -y protobuf-compiler - name: Install uv - uses: astral-sh/setup-uv@v3 - - name: Create virtual environment and install dependencies + uses: astral-sh/setup-uv@v4 + - name: Install locked dependencies working-directory: python - run: | - uv venv - source .venv/bin/activate - uv pip install maturin[patchelf] - # Install test dependencies only (skip editable install to avoid double-building Rust) - uv pip install pytest pyarrow pandas ruff + # The package itself is built by maturin develop below, in debug mode. + run: uv sync --locked --no-install-project --python ${{ matrix.python-version }} - name: Build Python extension working-directory: python - run: | - source .venv/bin/activate - maturin develop + run: uv run --no-sync maturin develop - name: Run tests working-directory: python - run: | - source .venv/bin/activate - pytest python/tests/ -v - - name: Run doctests - working-directory: python - run: | - source .venv/bin/activate - if [ -f python/lance_csr/__init__.py ]; then - python -m doctest python/lance_csr/__init__.py || echo "No doctests found" - fi + run: uv run --no-sync pytest python/tests/ -v lint: runs-on: ubuntu-24.04 timeout-minutes: 15 steps: - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: "3.12" - name: Install uv - uses: astral-sh/setup-uv@v3 - - name: Install linting tools + uses: astral-sh/setup-uv@v4 + - name: Install locked dependencies working-directory: python - run: | - uv venv - source .venv/bin/activate - # Install only linting tools without building the Rust extension - uv pip install ruff pyright + # Linting needs no build of the Rust extension. + run: uv sync --locked --no-install-project --python 3.12 - name: Run ruff format check working-directory: python - run: | - source .venv/bin/activate - ruff format --check python/ + run: uv run --no-sync ruff format --check python/ - name: Run ruff lint working-directory: python - run: | - source .venv/bin/activate - ruff check python/ + run: uv run --no-sync ruff check python/ - name: Run pyright type check working-directory: python - run: | - source .venv/bin/activate - pyright + run: uv run --no-sync pyright diff --git a/AGENTS.md b/AGENTS.md index cd3be7d..b44ddff 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,7 +11,7 @@ ## Build, Test, and Development Commands - `cargo test --workspace` (from the repository root) runs the Rust tests; building needs `protoc`. - `cargo bench --bench graph_execution -p lance-graph-benches` measures performance-critical changes; include shortened runs with `--warm-up-time 1`. -- In `python/`: `make venv` and `make install` (`maturin develop --extras tests,dev`) bootstrap the Python environment with a debug build; re-run `make install` after Rust edits. +- Never use `pip`. In `python/`, `make install` runs `uv sync --locked --no-install-project` (locked dependencies and the `dev` group) and then a debug build with `uv run --no-sync maturin develop`; re-run it after Rust edits. Change dependencies with `uv add`/`uv remove` and commit `uv.lock`. - `make test` runs the Python tests; `make lint` runs `ruff`, formatting checks, and `pyright`. ## Coding Style & Naming Conventions diff --git a/README.md b/README.md index 180b1a9..480e131 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ See [`docs/project_structure.md`](docs/project_structure.md) for the full worksp ## Install ```bash -pip install lance-csr +uv add lance-csr ``` Prebuilt wheels cover Linux x86-64 and native Apple Silicon (CPython 3.12+); no Rust toolchain is needed. @@ -86,21 +86,21 @@ cargo clippy --workspace --all-targets -- -D warnings cargo fmt --all --check ``` -Python package, from `python/`: +Python package, from `python/`. `uv sync --locked` installs the exact dependency versions in `uv.lock`, +including the development tools (maturin, pytest, ruff, pyright), into `python/.venv`: ```bash cd python -uv venv --python 3.12 .venv -source .venv/bin/activate -uv pip install 'maturin[patchelf]' -maturin develop --extras tests,dev # builds the extension, installs lance-csr with test and lint tools -pytest python/tests # run the tests -make lint # ruff and pyright +uv sync --locked --no-install-project # locked dependencies and dev tools +uv run --no-sync maturin develop # debug build of the extension into .venv +uv run --no-sync pytest python/tests # run the tests ``` -`maturin develop` makes a debug build, which compiles quickly; re-run it after changing Rust code. For timing -queries, build with `maturin develop --release` instead: release builds use thin LTO and take several minutes. -See [`python/DEVELOPMENT.md`](python/DEVELOPMENT.md) for more. +`--no-install-project` leaves the package itself to `maturin develop`, which makes a debug build that compiles +quickly; uv would otherwise build it in release mode. `--no-sync` stops `uv run` from re-syncing, which would remove +that build. Re-run `maturin develop` after changing Rust code. `make install`, `make test` and `make lint` wrap +these steps. For timing queries, build with `maturin develop --release`: release builds use thin LTO and take +several minutes. See [`python/DEVELOPMENT.md`](python/DEVELOPMENT.md) for more. ## Python example: Cypher query diff --git a/ci/check_wheel.py b/ci/check_wheel.py index 513e021..240e1c8 100644 --- a/ci/check_wheel.py +++ b/ci/check_wheel.py @@ -32,8 +32,10 @@ def main(): assert sys.prefix != sys.base_prefix, "Use a clean virtual environment" assert shutil.which("cargo") is None, "Remove Cargo from the smoke-test PATH" assert shutil.which("rustc") is None, "Remove rustc from the smoke-test PATH" + # An installed wheel, not the source tree (uv's environments may layer site-packages + # outside sys.prefix, so check for site-packages itself). extension = Path(_internal.__file__).resolve() - assert extension.is_relative_to(Path(sys.prefix).resolve()), extension + assert "site-packages" in extension.parts, extension config = ( GraphConfig.builder() diff --git a/examples/README.md b/examples/README.md index 04ae0e3..de2e6d9 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,61 +1,24 @@ # Examples for lance-csr -## How to Run Examples +## How to run the examples -Pick one of the two approaches: - -### 1) Local build (editable) with maturin - -```bash -# From the repo root; installs the Python extension in editable mode -pip install pyarrow # or: uv pip install pyarrow -(cd python && maturin develop) - -# Run examples -python examples/basic_cypher.py -python examples/kg_traversal.py -``` - -With `uv` (persistent venv recommended): - -```bash -# Create and activate a reusable environment -uv venv .venv && . .venv/bin/activate - -# Install dependencies and build editable extension -uv pip install pyarrow -(cd python && uvx --from maturin maturin develop) - -# Run examples using the venv's Python -python examples/basic_cypher.py -python examples/kg_traversal.py -``` - -### 2) Install the package, then run - -- From PyPI: +With the released package, from the repository root (uv creates a temporary environment with lance-csr and its +dependencies): ```bash -pip install lance-csr pyarrow -python examples/basic_cypher.py -python examples/kg_traversal.py +uv run --with lance-csr python examples/basic_cypher.py +uv run --with lance-csr python examples/kg_traversal.py +uv run --with lance-csr python examples/lance_snapshot_refresh.py ``` -- From git (editable): - -```bash -pip install -e python -python examples/basic_cypher.py -python examples/kg_traversal.py -``` - -### 3) Single-shot with uv (no install, run from source) - -uv creates a fresh isolated environment per run. If you prefer a one-liner without installing the package, point `PYTHONPATH` to the source package and let uv provide `pyarrow`: +With a local build, so the examples use your changes, set up `python/.venv` as in +[`python/DEVELOPMENT.md`](../python/DEVELOPMENT.md) and run them from it: ```bash -PYTHONPATH=python/python uv run --with pyarrow python examples/basic_cypher.py -PYTHONPATH=python/python uv run --with pyarrow python examples/kg_traversal.py +cd python +uv sync --locked --no-install-project +uv run --no-sync maturin develop +uv run --no-sync python ../examples/basic_cypher.py ``` ## Examples @@ -63,17 +26,17 @@ PYTHONPATH=python/python uv run --with pyarrow python examples/kg_traversal.py - `basic_cypher.py`: simple node filter and projection. ```bash -python examples/basic_cypher.py +uv run --with lance-csr python examples/basic_cypher.py ``` - `kg_traversal.py`: multi-hop traversal on a small synthetic knowledge graph. ```bash -python examples/kg_traversal.py +uv run --with lance-csr python examples/kg_traversal.py ``` - `lance_snapshot_refresh.py`: lazy Lance datasets, snapshots and `refresh()`. ```bash -python examples/lance_snapshot_refresh.py +uv run --with lance-csr python examples/lance_snapshot_refresh.py ``` diff --git a/examples/basic_cypher.py b/examples/basic_cypher.py index ccf20b2..81cdaa2 100644 --- a/examples/basic_cypher.py +++ b/examples/basic_cypher.py @@ -1,10 +1,8 @@ """ Basic Cypher graph query using the lance-csr Python bindings. -Requirements: -- Build/install the Python extension first (from repo root): - cd python && maturin develop -- Python deps: pyarrow +Run from the repository root: + uv run --with lance-csr python examples/basic_cypher.py Run: python examples/basic_cypher.py diff --git a/examples/kg_traversal.py b/examples/kg_traversal.py index 08dabe2..8edd982 100644 --- a/examples/kg_traversal.py +++ b/examples/kg_traversal.py @@ -1,10 +1,8 @@ """ Simple knowledge-graph multi-hop traversal with lance-csr Python bindings. -Requirements: -- Build/install the Python extension first (from repo root): - cd python && maturin develop -- Python deps: pyarrow +Run from the repository root: + uv run --with lance-csr python examples/kg_traversal.py Run: python examples/kg_traversal.py diff --git a/python/CLAUDE.md b/python/CLAUDE.md index d301abc..3cb9247 100644 --- a/python/CLAUDE.md +++ b/python/CLAUDE.md @@ -1,8 +1,9 @@ -Use the Makefile for most actions (from `python/`): +Never use `pip`; dependencies are managed with uv and locked in `uv.lock`. Use the Makefile for most actions (from `python/`): -* Set up: `make venv`, then `make install` (debug build with test and lint tools) -* Rebuild after Rust changes: `make install` or `maturin develop` +* Set up and build: `make install` (`uv sync --locked --no-install-project`, then `uv run --no-sync maturin develop`) +* Rebuild after Rust changes: `make install` * Test: `make test` -* Run single test: `pytest python/tests/.py::` +* Run single test: `uv run --no-sync pytest python/tests/.py::` * Lint: `make lint` * Format: `make format` +* Add a dependency: `uv add ` (development tools: `uv add --group dev `) diff --git a/python/DEVELOPMENT.md b/python/DEVELOPMENT.md index 76cb0d5..61d4c20 100644 --- a/python/DEVELOPMENT.md +++ b/python/DEVELOPMENT.md @@ -10,39 +10,40 @@ ## Building the extension -The package is built with [maturin](https://github.com/PyO3/maturin). `pyproject.toml` points it at the bindings -crate in `crates/lance-graph-python/`, so run maturin from this `python/` directory. +Dependencies are managed with uv and pinned in `uv.lock`. The package is built with +[maturin](https://github.com/PyO3/maturin): `pyproject.toml` points it at the bindings crate in +`crates/lance-graph-python/`, so run these commands from this `python/` directory. ```shell cd python -make venv # uv venv --python 3.12 .venv -make install # maturin develop --extras tests,dev: debug build, plus pytest, pandas, ruff and pyright +uv sync --locked --no-install-project # locked dependencies and the dev group into .venv +uv run --no-sync maturin develop # debug build of the extension, installed in editable mode ``` -Or by hand, with the environment activated: +`make install` runs both. The `dev` dependency group in `pyproject.toml` holds maturin, pytest, pandas, ruff and +pyright, and `uv sync` installs it by default. -```shell -uv venv --python 3.12 .venv -source .venv/bin/activate -uv pip install 'maturin[patchelf]' -maturin develop --extras tests,dev -``` +- `--no-install-project` leaves the package to `maturin develop`. Without it, uv builds the package through + maturin's build backend, in release mode. +- `--no-sync` on `uv run` uses `.venv` as it is. A plain `uv run` or `uv sync` re-syncs exactly to the lockfile and + uninstalls the `maturin develop` build, which the lockfile doesn't list. To re-sync and keep the build, add + `--inexact` (as `make sync` does). +- To change dependencies, use `uv add` and `uv remove` (`uv add --group dev ` for development tools), and + commit the updated `uv.lock`. `maturin develop` installs the package in editable mode: changes to `python/lance_csr/` take effect immediately, while Rust changes need another `maturin develop`. Debug builds compile quickly but run queries much more slowly. To time queries, build optimized code with -`maturin develop --release`. Release builds use thin LTO and one codegen unit (`.cargo/config.toml`), so they take -several minutes. Alternating `maturin develop` and `maturin build` in the same environment invalidates each other's -build cache, so pick one per environment. - -If another virtual environment is active, run `deactivate` first so the commands use `.venv`. +`uv run --no-sync maturin develop --release`. Release builds use thin LTO and one codegen unit +(`.cargo/config.toml`), so they take several minutes. Alternating `maturin develop` and `maturin build` invalidates +each other's build cache, so pick one per environment. ## Tests ```shell -make test # every Python test -pytest python/tests/test_engine_csr.py -k undirected # a subset +make test # every Python test +uv run --no-sync pytest python/tests/test_engine_csr.py -k undirected # a subset ``` The Rust tests run from the repository root: @@ -68,8 +69,8 @@ cargo clippy --workspace --all-targets -- -D warnings ## Benchmarks `python/benchmarks/` holds scripts for the engine's own costs: catalog reuse, bounded-memory streaming, CSR expansion -and incremental CSR maintenance. Build with `maturin develop --release` before running them. The Rust Criterion -benchmarks live in the `lance-graph-benches` crate: +and incremental CSR maintenance. Build with `uv run --no-sync maturin develop --release` before running them. The +Rust Criterion benchmarks live in the `lance-graph-benches` crate: ```shell cargo bench -p lance-graph-benches --bench graph_execution -- --warm-up-time 1 @@ -87,15 +88,16 @@ by `ci/check_wheel.py` and the full test suite. To build a wheel for your own machine: ```shell -make wheel # maturin build --release --out dist --sdist +make wheel # uv run --no-sync maturin build --release --out dist --sdist ``` -To build the Linux x86-64 wheel the way CI does, on macOS or Linux, install [zig](https://ziglang.org) (for example -`pip install ziglang`) and the target, then: +To build the Linux x86-64 wheel the way CI does, on macOS or Linux, add the target and run maturin with its `zig` +extra, which brings the zig linker. Use `uv run --with` rather than `uvx`: maturin finds zig through `python3` on +`PATH`, which `uv run` sets up and `uvx` does not. ```shell rustup target add x86_64-unknown-linux-gnu -maturin build --release --locked --strip --zig \ +uv run --no-project --with 'maturin[zig]>=1.9,<2' maturin build --release --locked --strip --zig \ --target x86_64-unknown-linux-gnu \ --compatibility manylinux_2_28 \ --out dist diff --git a/python/Makefile b/python/Makefile index 1f7859e..6951799 100644 --- a/python/Makefile +++ b/python/Makefile @@ -1,34 +1,34 @@ UV ?= uv PYTHON ?= 3.12 -VENV ?= .venv PYTEST_ARGS ?= -q -BIN := $(VENV)/bin +# Run tools in .venv as synced; a plain `uv run` would re-sync and drop the extension build. +RUN := $(UV) run --no-sync -.PHONY: venv install test lint format wheel clean +.PHONY: sync install test lint format wheel clean -# A virtual environment for development. -venv: - $(UV) venv --python $(PYTHON) $(VENV) +# Locked dependencies and dev tools (maturin, pytest, ruff, pyright) into .venv. The project +# itself is left out (uv would build it in release mode), and --inexact keeps an existing build. +sync: + $(UV) sync --locked --no-install-project --inexact --python $(PYTHON) -# Debug build of the extension, installed with the test and lint tools. -install: - $(UV) pip install --python $(BIN)/python 'maturin[patchelf]' - VIRTUAL_ENV=$(abspath $(VENV)) $(BIN)/maturin develop --extras tests,dev +# Debug build of the extension into .venv; re-run after changing Rust code. +install: sync + $(RUN) maturin develop test: - $(BIN)/pytest $(PYTEST_ARGS) python/tests + $(RUN) pytest $(PYTEST_ARGS) python/tests lint: - $(BIN)/ruff check python - $(BIN)/ruff format --check python - $(BIN)/pyright + $(RUN) ruff check python + $(RUN) ruff format --check python + $(RUN) pyright format: - $(BIN)/ruff format python + $(RUN) ruff format python # Release wheel and sdist for this platform, in dist/ (CI builds the published ones). wheel: - VIRTUAL_ENV=$(abspath $(VENV)) $(BIN)/maturin build --release --out dist --sdist + $(RUN) maturin build --release --out dist --sdist clean: - rm -rf $(VENV) dist ../crates/lance-graph-python/target + rm -rf .venv dist ../crates/lance-graph-python/target diff --git a/python/README.md b/python/README.md index b117297..9643ada 100644 --- a/python/README.md +++ b/python/README.md @@ -6,16 +6,24 @@ endorsed by the lance-graph maintainers. ## Installation +Add it to a [uv](https://docs.astral.sh/uv/) project: + +```bash +uv add lance-csr +``` + +Or run a script with it, without a project: + ```bash -pip install lance-csr +uv run --with lance-csr python your_script.py ``` Prebuilt wheels are published for Linux x86-64 (glibc 2.28 or newer: RHEL 8, Ubuntu 20.04 and later) and native Apple Silicon (macOS 11 or newer), for CPython 3.12 and later. Installing from a wheel needs -no Rust toolchain; to make sure pip never falls back to compiling from source, use: +no Rust toolchain; to make sure uv never falls back to compiling from source, use: ```bash -pip install --only-binary=:all: lance-csr +uv add lance-csr --no-build-package lance-csr ``` Other platforms install from the source distribution, which needs Rust and `protoc`. @@ -191,13 +199,12 @@ Building from source needs Rust (through rustup), `protoc` and uv; see [DEVELOPM ```bash cd python -make venv # uv venv --python 3.12 .venv -make install # maturin develop --extras tests,dev +make install # uv sync --locked --no-install-project, then a debug build with maturin develop make test # pytest python/tests make lint # ruff and pyright ``` -Re-run `make install` (or `maturin develop`) after changing Rust code; Python changes apply immediately. +Re-run `make install` after changing Rust code; Python changes apply immediately. ## Repository layout diff --git a/python/pyproject.toml b/python/pyproject.toml index 9b84ab9..7372f2a 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -38,9 +38,9 @@ manifest-path = "../crates/lance-graph-python/Cargo.toml" requires = ["maturin>=1.4"] build-backend = "maturin" -[project.optional-dependencies] -tests = ["pytest", "pandas", "ruff"] -dev = ["ruff", "pyright"] +# Development tools, installed by `uv sync` (the `dev` group is uv's default). +[dependency-groups] +dev = ["maturin[patchelf]>=1.9,<2", "pytest", "pandas", "ruff", "pyright"] [tool.ruff] lint.select = ["F", "E", "W", "I", "G", "TCH", "PERF", "B019"] diff --git a/python/uv.lock b/python/uv.lock index eb96ed5..fba193c 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -5,12 +5,10 @@ resolution-markers = [ "python_full_version >= '3.14' 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.12' and python_full_version < '3.14' and sys_platform == 'win32'", - "python_full_version < '3.12' and sys_platform == 'win32'", - "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten'", - "python_full_version < '3.12' and sys_platform == 'emscripten'", - "python_full_version >= '3.12' and python_full_version < '3.14' 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.14' 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_version < '0'", ] [[package]] @@ -49,28 +47,29 @@ dependencies = [ { name = "pylance" }, ] -[package.optional-dependencies] +[package.dev-dependencies] dev = [ - { name = "pyright" }, - { name = "ruff" }, -] -tests = [ + { name = "maturin", extra = ["patchelf"] }, { name = "pandas" }, + { name = "pyright" }, { name = "pytest" }, { name = "ruff" }, ] [package.metadata] requires-dist = [ - { name = "pandas", marker = "extra == 'tests'" }, { name = "pyarrow", specifier = ">=14" }, { name = "pylance", specifier = ">=13.0.0,<14" }, - { name = "pyright", marker = "extra == 'dev'" }, - { name = "pytest", marker = "extra == 'tests'" }, - { name = "ruff", marker = "extra == 'dev'" }, - { name = "ruff", marker = "extra == 'tests'" }, ] -provides-extras = ["tests", "dev"] + +[package.metadata.requires-dev] +dev = [ + { name = "maturin", extras = ["patchelf"], specifier = ">=1.9,<2" }, + { name = "pandas" }, + { name = "pyright" }, + { name = "pytest" }, + { name = "ruff" }, +] [[package]] name = "lance-namespace" @@ -100,110 +99,44 @@ wheels = [ ] [[package]] -name = "nodeenv" -version = "1.11.0" +name = "maturin" +version = "1.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/105de02c1322cfada6d9710d9146ef8026419d433c9d08359a2d35805811/nodeenv-1.11.0.tar.gz", hash = "sha256:3ce8fe5b71d16e8af7039ca65257354100bc772965d6bc549070649e53b1b146", size = 99301, upload-time = "2026-09-26T11:29:21.367Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/c8/22e5e21b2679c9bce6415ca578034ca2cc9316be0642ae21e051a2d5198c/maturin-1.15.0.tar.gz", hash = "sha256:94b26cc8e8aba61a5f2099715fe640e18c5f678e9a500408b38761263954228a", size = 385504, upload-time = "2026-08-24T12:11:22.665Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/c8/12811c9b48fde162bb72b6f2e78fada9a247a09d7bb5be2050a5d099c77b/nodeenv-1.11.0-py2.py3-none-any.whl", hash = "sha256:edaa16e6c14d7cf395d75d4bbd5a26390f4dc06501a33b4e76282b02cc688a25", size = 34277, upload-time = "2026-09-26T11:29:19.933Z" }, + { url = "https://files.pythonhosted.org/packages/14/69/5c01b461044eb1f45ddcce006706eb88110c793cdb11c7ae0b5e08492e94/maturin-1.15.0-py3-none-linux_armv6l.whl", hash = "sha256:6bf6dc62e22d4dcfd5a51244ff0d58975fa4979c48209fe84159617648956d82", size = 10206220, upload-time = "2026-08-24T12:10:53.327Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1f/2b431554e11687cdb1077e0cdadcc118c53f611086b3af00c8545a67c6a5/maturin-1.15.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:cd35772633f489841132bc8e71d6fc7f842df30b9c05cd5cdf1ee1ddcb744cc7", size = 19416513, upload-time = "2026-08-24T12:10:56.126Z" }, + { url = "https://files.pythonhosted.org/packages/51/36/e23a21cb34a648b711036b9b2fe1d4f3f4ee24f8db54215d73f1a9a3a3ec/maturin-1.15.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c40b4eae7bf5ef1f4b1af8d623fe4105016f93578fb15b764e741d08ec3b92dd", size = 10014962, upload-time = "2026-08-24T12:10:58.486Z" }, + { url = "https://files.pythonhosted.org/packages/8c/80/33b15cb2d8f30f12c807955e8f2fd775027692904e30ec0784744ce8cd83/maturin-1.15.0-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:7eb066372f541f8eb4909c79c5d9bd0b9e8125980bdf1ec9e8aba23c6c8d6c55", size = 10196223, upload-time = "2026-08-24T12:11:00.696Z" }, + { url = "https://files.pythonhosted.org/packages/fe/91/b495e19e2f5c503b540452b2039115e7b2363867e8c5ad4179eb752fa92c/maturin-1.15.0-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:653020a63525bb224e5ab0adf02e17a2e08bc86dbea7fc1399c9a56d7529b99e", size = 10541186, upload-time = "2026-08-24T12:11:02.857Z" }, + { url = "https://files.pythonhosted.org/packages/5d/2b/2abff58037188d852b124871b1f0d720e1c2bfb3d4f1b03d87c52cd66488/maturin-1.15.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:0ebf9767892725083138e671c34482c660317a2f3d6a29fc0e0f34e9d8c99136", size = 10083468, upload-time = "2026-08-24T12:11:05.012Z" }, + { url = "https://files.pythonhosted.org/packages/3f/07/b7e9f8be99a6627849e81ac7b6694876bce8f50a92995fe17e3cf2610f0a/maturin-1.15.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:7ab7eebffd7b8debca2265985de4eaeb332141276d24b9560b5ad484d4b3add1", size = 10047786, upload-time = "2026-08-24T12:11:07.042Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ab/167e3cb7accee11b507dbe53e0e87aeccb376d44ae66284c96ee4df3a9fd/maturin-1.15.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:126e12e618b4db42f68c779a56d41f82a390145ba36ac3f621d057eb34f5ad9d", size = 13315332, upload-time = "2026-08-24T12:11:09.433Z" }, + { url = "https://files.pythonhosted.org/packages/14/4d/801379f646cbc6b00998e5289b0630a886be3a4ee4c75b6bc9b87478a7f1/maturin-1.15.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4f9d33e6c3f9615c8caceecbbbd440f8eb25a3ddeb687077682cd5eca2e9ae15", size = 10807183, upload-time = "2026-08-24T12:11:11.73Z" }, + { url = "https://files.pythonhosted.org/packages/89/27/2e612e1cbd1580e9e94d4722c227b5180dca27b32b955a34b79918aa1292/maturin-1.15.0-py3-none-manylinux_2_31_riscv64.musllinux_1_1_riscv64.whl", hash = "sha256:bf29beddd0c6708f112db51d5275fc28b28b9e9c9c5faae387eaef662918b176", size = 10413274, upload-time = "2026-08-24T12:11:14.04Z" }, + { url = "https://files.pythonhosted.org/packages/70/d8/202a7b4d75a51f20f84ec9ce3b7345b12b822207072164e2b1c6ef665125/maturin-1.15.0-py3-none-win32.whl", hash = "sha256:da649988be98e87e009e51b1bf0d301b6a301bc0cecbdd60d40d8ba60748d1ca", size = 8928744, upload-time = "2026-08-24T12:11:16.269Z" }, + { url = "https://files.pythonhosted.org/packages/40/dc/4e90da594986ba78dd3bc8a5921ecdcdb11085b22b02a412caab3b225601/maturin-1.15.0-py3-none-win_amd64.whl", hash = "sha256:552c2be4afd43fe8d5c9f3ec8d4c4756d973b8dcbe94c14084390301f50243e1", size = 10335085, upload-time = "2026-08-24T12:11:18.326Z" }, + { url = "https://files.pythonhosted.org/packages/8b/10/15d4314edf130955edf2dc237aa393a8a7c10f2b9b57b89fa2f61f915659/maturin-1.15.0-py3-none-win_arm64.whl", hash = "sha256:c7dc0c66c78d3debdd9c5aa807e861fbcbf07f3505d34b125df74c03986b0f48", size = 9713795, upload-time = "2026-08-24T12:11:20.83Z" }, +] + +[package.optional-dependencies] +patchelf = [ + { name = "patchelf" }, ] [[package]] -name = "numpy" -version = "2.4.6" +name = "nodeenv" +version = "1.11.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.12' 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'", -] -sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/105de02c1322cfada6d9710d9146ef8026419d433c9d08359a2d35805811/nodeenv-1.11.0.tar.gz", hash = "sha256:3ce8fe5b71d16e8af7039ca65257354100bc772965d6bc549070649e53b1b146", size = 99301, upload-time = "2026-09-26T11:29:21.367Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/49/ec46835a70be8fa6446c495126ac84fdb28cb2558e1620ffb87a10c8b64c/numpy-2.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0280e0356c0829a18d9de1cb7eee50ec22ca639878d7240307ca0943d73cd2c4", size = 16969194, upload-time = "2026-05-18T23:33:13.503Z" }, - { url = "https://files.pythonhosted.org/packages/0e/0d/f5957185c0ee2f3e12f78715aa9e3b353fd83633316c8532b38faa37e3f6/numpy-2.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:110f8b71aacb688ec69062bb7f6938a0f8acb01b7c1c4beb453c65b6d234584d", size = 14964111, upload-time = "2026-05-18T23:33:17.795Z" }, - { url = "https://files.pythonhosted.org/packages/ad/40/40a40ee0ddf7ceb782c49af278894b686e586d65d8c1889c8b5da01a3d7d/numpy-2.4.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4cfe66903cc32a9921a6733d96b19bb6abf310397581bbad89c228f5abaf0ee8", size = 5469159, upload-time = "2026-05-18T23:33:20.654Z" }, - { url = "https://files.pythonhosted.org/packages/63/13/f9a8046535cb21deae82f8d03de9617e08882d274fad2539630761888228/numpy-2.4.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8155154c7c691289fe18f510b5d4657c68c67989f293f0535a91360392ff6538", size = 6798936, upload-time = "2026-05-18T23:33:22.987Z" }, - { url = "https://files.pythonhosted.org/packages/33/a8/6fa8c1a345a8c85dbb21932c447bee07c30a2c2a3f31e369c0a84b300147/numpy-2.4.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ab0a9c4ffb1a6d95ef519fe4247dba8eb6b18ad93999f76b7f657039acabd47", size = 15966692, upload-time = "2026-05-18T23:33:26.62Z" }, - { url = "https://files.pythonhosted.org/packages/02/03/74fe2a4cb3817d94d86402f2506554130a2f01414e299b5a843e5a8a957f/numpy-2.4.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89cd468399cfd2504718f0ba50e410dca55a170b61a02ad92bb18c8a65186e93", size = 16918164, upload-time = "2026-05-18T23:33:29.955Z" }, - { url = "https://files.pythonhosted.org/packages/c5/80/3615be3313f7e7696609bc194b9f0101da809df79e859bdb84e0cd043f46/numpy-2.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2d37ab77531417474168eb79d6d80b14f821a966818505d03013d0833edb7a8", size = 17322877, upload-time = "2026-05-18T23:33:34.724Z" }, - { url = "https://files.pythonhosted.org/packages/ca/ac/a691e0fe2675e370d0e08ff905adc49a1c8830e8cae03efe4477e92cd55d/numpy-2.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f407cb6b8e9d6d8c626bc73c945db1706035af8fd632295547bf1c9e46d092d6", size = 18651487, upload-time = "2026-05-18T23:33:38.217Z" }, - { url = "https://files.pythonhosted.org/packages/15/a7/9bc1cd626d7bf6869bfedf27b91b6ab5dd607758bf8e959d6fa80c6a59cb/numpy-2.4.6-cp311-cp311-win32.whl", hash = "sha256:ddea102b48f9e339f3948bf22040944184627a30fdf7f858667673b9c5f033c8", size = 6233945, upload-time = "2026-05-18T23:33:41.331Z" }, - { url = "https://files.pythonhosted.org/packages/c5/31/7fc6239c12bce7e931463251cca4426c465e1876ba3cc785402ef4dd8f4e/numpy-2.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:1e254a00cdf42b1e4d5b3d68d33af63268d41340d8885df2ab6470f2e1500147", size = 12608406, upload-time = "2026-05-18T23:33:44.131Z" }, - { url = "https://files.pythonhosted.org/packages/27/83/140f85a466595a16382996a1bf06b2b54bcd597488921b0c9daaeeda72af/numpy-2.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:ed9749eef4cbd126da3dc1d6bcb3a57f5eb7ac6a6484146bdbf743f552dfc577", size = 10479528, upload-time = "2026-05-18T23:33:50.725Z" }, - { url = "https://files.pythonhosted.org/packages/95/2a/3d7b5ac8aac24feaf9ad7ed58f45b0bbc06d37e4338ae84c9f2298b570f9/numpy-2.4.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:001fbb8e08d942dd57599e781f2472269ee7f2755fae407b4f67b2f0b17da3f1", size = 16689119, upload-time = "2026-05-18T23:33:54.065Z" }, - { url = "https://files.pythonhosted.org/packages/ea/12/92c4c131527599e8288d6918e888d88726f84d805d784b771f32408aeaef/numpy-2.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ebfb099f8dcf083deef3ac1ca4c1503f387cf76296fcb3816b66f5ecb5f54fdb", size = 14699246, upload-time = "2026-05-18T23:33:57.621Z" }, - { url = "https://files.pythonhosted.org/packages/ad/fe/c0a6b7b2ca128a8fb228575147073b660656734b8ebe4d76c8fd748dcc79/numpy-2.4.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3213d622a0283a39a93d188f3cf72b26862df52fbb4ca3697f51705016523d41", size = 5204410, upload-time = "2026-05-18T23:34:00.302Z" }, - { url = "https://files.pythonhosted.org/packages/f3/d4/9770d14ba719432bb90a421bfd443872ed0f70f7264b64bec12ea363d5fd/numpy-2.4.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:357cc07a6d7b0b182ff02249616a03742827ebb1277546b5c7cd7f7620a45698", size = 6551240, upload-time = "2026-05-18T23:34:02.852Z" }, - { url = "https://files.pythonhosted.org/packages/c9/c6/50a46a6205feba2343f1d6d17438107c5dc491ed1c736e6ea68689fd906b/numpy-2.4.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f9fb9157b4ce2971008323afe46053787b526ef624fea915b261468a8421a0f", size = 15671012, upload-time = "2026-05-18T23:34:05.485Z" }, - { url = "https://files.pythonhosted.org/packages/99/60/14115e6364fa676c5397c2ad3004e527e9aa487abf5d0706ec81bbd08529/numpy-2.4.6-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90f9849678c75fe7afa2d348ac842c168b0a4d3d61919687216dfc547976d853", size = 16645538, upload-time = "2026-05-18T23:34:09.265Z" }, - { url = "https://files.pythonhosted.org/packages/ae/c5/693cbe59e57db94d2231fa519ca3978dc9e19da5a8f088588f5c6e947ff2/numpy-2.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1a2af6c6ef86344a6b0db6b97834208bf598db514f2b155042439b62605601a", size = 17020706, upload-time = "2026-05-18T23:34:13.053Z" }, - { url = "https://files.pythonhosted.org/packages/ef/fc/85b7c4eff9b4966ade25c2273cf7e7012e92366c032058653934b37de044/numpy-2.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5805d5a22fd19c8ccff10a9561f9df94436b0545619ea579db2d3c35294bce2", size = 18368541, upload-time = "2026-05-18T23:34:17.024Z" }, - { url = "https://files.pythonhosted.org/packages/f6/81/e1b27545deedce7f4a0b348618c6b62d74e36a4dc9ccd42f3eb2f85eee32/numpy-2.4.6-cp312-cp312-win32.whl", hash = "sha256:e3eeb0aabd6bd5ce64faae67e9935203a6991b4bc2a485a767fbafb2c5125f45", size = 5962825, upload-time = "2026-05-18T23:34:20.3Z" }, - { url = "https://files.pythonhosted.org/packages/ab/ca/feab00bd44aa5fe1ad2c18f08b4d3bb92e26484b0b1d1443897809ed528c/numpy-2.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:d8e8286dd7cea7895157318d1b91cdacac64c479f3cbc8dce548331728484751", size = 12321687, upload-time = "2026-05-18T23:34:23.095Z" }, - { url = "https://files.pythonhosted.org/packages/63/cf/5a6d34850a39d1093558564f77ee8e8e0bee5061151b8f05a55711001ec7/numpy-2.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:4081eb135ac24158bd51cdfbef16f1c64df7063b1143f24731387137c092bec8", size = 10221482, upload-time = "2026-05-18T23:34:25.876Z" }, - { url = "https://files.pythonhosted.org/packages/fb/82/bdab26d7438c6791ca31b7c024ca37c1eab8b726ba236129005cd4a06e45/numpy-2.4.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:511dbaf848decaaaf4b4ca48032619fb3138710c4bf7da7617765edad1ef96b0", size = 16684648, upload-time = "2026-05-18T23:34:29.41Z" }, - { url = "https://files.pythonhosted.org/packages/1b/30/a80189bcc7f5e4258b3fbc3968d909d1756f54d023299ecc39ad6fdb9ef8/numpy-2.4.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bf162abab1c1a736333192707cef898e735a5ca00f38f27eeedf44b39d9e85eb", size = 14693902, upload-time = "2026-05-18T23:34:33.013Z" }, - { url = "https://files.pythonhosted.org/packages/97/12/70b5d0d7c15e1ebb8a6a84a8caa1d19e181d84fb58bb6d70aca29099dec1/numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:043191bfa8eab18c776647b62723ac9dddece59743b13f49b2016094129c2b3f", size = 5198992, upload-time = "2026-05-18T23:34:36.132Z" }, - { url = "https://files.pythonhosted.org/packages/ba/8c/ebd2a8f8a83541f8d38cc5667e8c2b69cecfd30da6e45693e8158857d44b/numpy-2.4.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:6180d8b35af935aed8ece3a85e0a43f87393ae0ac87c8d2c8bd2c993f7270ef3", size = 6546944, upload-time = "2026-05-18T23:34:38.484Z" }, - { url = "https://files.pythonhosted.org/packages/bb/c5/7b863a97a91671a0338f4253bd3b5a3d3852f0692dae91711c9f4a10e787/numpy-2.4.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72fbe16c6fac95aedf5937fa873445cec2110be35d8a4e9433d7501fd98dae6b", size = 15669392, upload-time = "2026-05-18T23:34:41.257Z" }, - { url = "https://files.pythonhosted.org/packages/a5/9d/3584b9984ca4c047aea75214ce1a4c4c73d849bd71b604264b7f5653f8a8/numpy-2.4.6-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7830bab239b79cda9c08c2da014761cafb48da6150e1da17ac06283f43b6089", size = 16633220, upload-time = "2026-05-18T23:34:45.075Z" }, - { url = "https://files.pythonhosted.org/packages/05/ae/7c67fba23bd98caec7c99261f3a16072ade14813486b0282cb29846de832/numpy-2.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ef4aea96ce4d3b074422cb4f2f64e216bf9e213004bb58ecfdf50ea02ea8eb9a", size = 17020800, upload-time = "2026-05-18T23:34:49.065Z" }, - { url = "https://files.pythonhosted.org/packages/d9/5d/3b6725cb31d983c5e66916f5d36f6d7e5521129e4c4404d64f918292a5b6/numpy-2.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfa20cc6ca228e6b155b11da03825975ce66aea520985dbbddf0f2a5a495c605", size = 18357600, upload-time = "2026-05-18T23:34:52.709Z" }, - { url = "https://files.pythonhosted.org/packages/f7/da/2ccc6c2fe8898dee01d90c75c5f5f914a23daf99e3e0f59516a08760c8b5/numpy-2.4.6-cp313-cp313-win32.whl", hash = "sha256:56b39e5e0622a09a25bf5baf62f4bcf0cb8a41ae6e2819cf49bbc5a74c083f91", size = 5961134, upload-time = "2026-05-18T23:34:55.618Z" }, - { url = "https://files.pythonhosted.org/packages/b5/cd/9cc4dc876fb065d5c220aae4d5e14826b2715331bb7618ce1fb07a679d99/numpy-2.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:c4fc99836233ea196540b17ab0983aff60ed07941751930f5f4d05bc3b3b7359", size = 12318598, upload-time = "2026-05-18T23:34:58.928Z" }, - { url = "https://files.pythonhosted.org/packages/39/1e/c0bcba1f8694116485fe28fd1be698c278fcda4141c5b0e53a2aed8b12a8/numpy-2.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a7c711e21628b52034bb5ab8d1bce291f752fcc5e92accc615778acee1ff4778", size = 10222272, upload-time = "2026-05-18T23:35:02.167Z" }, - { url = "https://files.pythonhosted.org/packages/63/6d/cc5619247c8f4204e507f5883528372e4ac4bb189e579fb859a12e480b1f/numpy-2.4.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:112b06a867b235ef466ed3508ddf0238050df9c727cafb5301ac385b899189a1", size = 14821197, upload-time = "2026-05-18T23:35:05.468Z" }, - { url = "https://files.pythonhosted.org/packages/00/58/f1c39161c87d9e9bed660f1ed4bafc0e403d5ec9650b6dd77aead07d489b/numpy-2.4.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:eaf7fa2de5c0be8ae6ff8e9bea2ccd725e980541244521d8d4b5f3354a27babe", size = 5326287, upload-time = "2026-05-18T23:35:08.693Z" }, - { url = "https://files.pythonhosted.org/packages/af/57/3917ab0fd97f271a8694513581b8a36c655f111c446852c302f04ccdb6fc/numpy-2.4.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7265a2f3d436e54ef9f2b52b5c937e6be778781bd97a590319d7348f1c1ca997", size = 6646763, upload-time = "2026-05-18T23:35:11.459Z" }, - { url = "https://files.pythonhosted.org/packages/eb/0f/037e64c494b67581ae18193d770adef354c41f3f2c8ebf865602d949bf8f/numpy-2.4.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f74a575920ab21fe304421a3fc28793d82e299cae9eccb37084e9fc7f3617c20", size = 15728070, upload-time = "2026-05-18T23:35:14.79Z" }, - { url = "https://files.pythonhosted.org/packages/21/a6/5d2bae9c9542eb4df16dc9c46dc79c186e9bad53805dfa5399a6023c6db0/numpy-2.4.6-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ede83e07a75dd06bc501566c1eca2afc0d61677c1472ac9ad93fdee6e638a48d", size = 16681752, upload-time = "2026-05-18T23:35:18.836Z" }, - { url = "https://files.pythonhosted.org/packages/92/14/23d1dfb410ae362cd59ce53e936b1513d545eb40db3949ced632e19a459e/numpy-2.4.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:68bb27509ac1b9a3443094260f6326150663b06abe40b73a2f81160623da5b67", size = 17086024, upload-time = "2026-05-18T23:35:22.52Z" }, - { url = "https://files.pythonhosted.org/packages/4b/6e/23595a2c642cdf3bc567877064bdd7f91c8b0038a4453cf2daf7248eafe9/numpy-2.4.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a0df0043bdb289bde1f62da130d20df23d58b45429f752bc7a8fc5325a225ecd", size = 18403398, upload-time = "2026-05-18T23:35:26.398Z" }, - { url = "https://files.pythonhosted.org/packages/8a/90/0ac3bc947217e66dec77e7cbc6a1979d1af70b6461b82f620d3bccd5e4c8/numpy-2.4.6-cp313-cp313t-win32.whl", hash = "sha256:29a287e0cf63ff528da061de6b9f64a4618da591ca1046aafc54062e40ca7eab", size = 6084971, upload-time = "2026-05-18T23:35:29.387Z" }, - { url = "https://files.pythonhosted.org/packages/77/71/5673e351671a1d2bd6063b91b44f70c0affea7d1516fa7a6572941ba4aa1/numpy-2.4.6-cp313-cp313t-win_amd64.whl", hash = "sha256:25c692919ac5a01f170a3bfcd62d745b24fd095c353d50812637d6fcab442e75", size = 12458532, upload-time = "2026-05-18T23:35:32.175Z" }, - { url = "https://files.pythonhosted.org/packages/3f/88/19d3503c5046e688f049274b27a3ef3d771152fa80d3ba3d01a3dff61abe/numpy-2.4.6-cp313-cp313t-win_arm64.whl", hash = "sha256:1e978ec1e8bd0e0e4de6bb75de9d30cbb74db6b6a2bb727618613703ca0167dd", size = 10291881, upload-time = "2026-05-18T23:35:35.465Z" }, - { url = "https://files.pythonhosted.org/packages/f8/91/3ab2044d05fd16d343c5ac2e69b127f1b2854040dd20b193257c78028bd3/numpy-2.4.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06ca2f61ec4385a07a6977c55ba998a4466c123642b4a32694d3128fce18c079", size = 16683458, upload-time = "2026-05-18T23:35:38.353Z" }, - { url = "https://files.pythonhosted.org/packages/8e/62/764ce66fa4147ae6d73071a3abf804ffe606f174618697c571acdf26a7c9/numpy-2.4.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:38efbc8de75c7a0fc1ac190162d892787f3f47b57cc291231aafee36b80982b7", size = 14704559, upload-time = "2026-05-18T23:35:42.14Z" }, - { url = "https://files.pythonhosted.org/packages/60/61/23f27c172f022e04025b7dc2367f4d63c1a398120607ec896228649a6f48/numpy-2.4.6-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:d581b735e177fdcdce6fed8e7e8880a3fb6ee4e3653a3ac6af01c6f4c03effc5", size = 5209716, upload-time = "2026-05-18T23:35:45.377Z" }, - { url = "https://files.pythonhosted.org/packages/03/71/21cf70dc6ea3e3acb95fc53a265b2fc248b981f0194ceb5b475271b8809d/numpy-2.4.6-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:0a041d3d761dc3c35cc56ce0351506a02bcbc25f7b169f652435141a17db9096", size = 6543947, upload-time = "2026-05-18T23:35:47.926Z" }, - { url = "https://files.pythonhosted.org/packages/d5/91/64288395ee1799bd2e0b04a305dce9666da90c961e1f3fe982a05ee1c036/numpy-2.4.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40fdc1ae7125e518ea98e53e69a4ebc27e1fd50510c47b7ea130cf21e5e1d42b", size = 15685197, upload-time = "2026-05-18T23:35:50.863Z" }, - { url = "https://files.pythonhosted.org/packages/f3/eb/ebffaa97dc55502df69584a8f0dcf07f69a3e0b3e2323670a2722db9aa39/numpy-2.4.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2c306dea656c12c68f51f4cea133cbe78ca7435eb28c735eac1d3ebe73be6e8", size = 16638245, upload-time = "2026-05-18T23:35:54.752Z" }, - { url = "https://files.pythonhosted.org/packages/b8/0b/54f9da33128d7e350fab89c7455902eeae70349ee52bddb448dc4a576f45/numpy-2.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:33111801a01c12a8a1e3721f0a9232f8cfc8ae2c6b7098167e6f623c6073f402", size = 17036587, upload-time = "2026-05-18T23:35:58.355Z" }, - { url = "https://files.pythonhosted.org/packages/b6/f0/fdebc1052db1cc37c64beb22072d67cd6d1c71adca1299f53dec2b5e20d3/numpy-2.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae506e6902902557576a26ff33eda8695e7ecb3cb36c3b573a0765dee114ebdb", size = 18363226, upload-time = "2026-05-18T23:36:02.845Z" }, - { url = "https://files.pythonhosted.org/packages/aa/b4/298628d98c72b57e57f7165ae6a481a1deaf6f3c28262a6e4c739c275930/numpy-2.4.6-cp314-cp314-win32.whl", hash = "sha256:aaf159caa35993cb1f56fb9b8e4610d35758e7ca005412eb1daa856a78c9c4b1", size = 6010196, upload-time = "2026-05-18T23:36:05.92Z" }, - { url = "https://files.pythonhosted.org/packages/df/ac/46de6dda46478f7942f839e094970be2d4a861e005c4b3bf07c92e291a09/numpy-2.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:b507f5c4c1d508876d1819b6bf9a49d365b96320b5d4993426b33a23ca4b8261", size = 12450334, upload-time = "2026-05-18T23:36:09.107Z" }, - { url = "https://files.pythonhosted.org/packages/78/92/b8b798ac784102c0da830d2257d59358e3d3d90d1e2b3f2575dad976c5cf/numpy-2.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:6f41ae150c4e32db4f3310cdaf64b1593a03dbabe29eec77fc9b50fe64061df6", size = 10495678, upload-time = "2026-05-18T23:36:12.766Z" }, - { url = "https://files.pythonhosted.org/packages/30/34/ec28d1aa8115971537c01469ab2011ee96827930f0a124de1000cc2a7ed7/numpy-2.4.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ece3d2cfe132e7d51f44a832b303895e6f2d499c5e74dfbdb06ee246147a304a", size = 14823672, upload-time = "2026-05-18T23:36:16.473Z" }, - { url = "https://files.pythonhosted.org/packages/16/bd/f6d1fede4e54e8042a7ff97bb495510f3c220f94bcd9e8b228e87c92cc0d/numpy-2.4.6-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:e3e5193ef5a3dc73bceee50f7fdc2c90dbb76c42df8d8fae3d1067a583df579e", size = 5328731, upload-time = "2026-05-18T23:36:19.767Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f0/e105b9e2fd728a9910103884decd6951d9dd73896b914a98d9a231de02ee/numpy-2.4.6-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:17f9ade344e7d9b464a084d69bcf18fc691cb1db67c62ed80820bf4926d78f0e", size = 6649805, upload-time = "2026-05-18T23:36:22.266Z" }, - { url = "https://files.pythonhosted.org/packages/82/dd/1206a7ca6ab15e3f02069707ca96222e202af681bb73756da7527f3cb837/numpy-2.4.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd5ffd25db4e7ba6a375693b3fc0fc1791ec636c17db3720da19bde7180ec43", size = 15730496, upload-time = "2026-05-18T23:36:25.713Z" }, - { url = "https://files.pythonhosted.org/packages/51/e7/38d3ea825dcab85a591734decb2f6c67caa7c8367d374df1a1c3842f9b07/numpy-2.4.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d92c3819208a60205a12a245c91ad70cb0a85336659b19b834205573ac8456e", size = 16679616, upload-time = "2026-05-18T23:36:29.652Z" }, - { url = "https://files.pythonhosted.org/packages/93/b7/caabfdf53edf663e0b4eb74d7d405d83baef09eb5e83bcd32d601d72b93e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e85b752a1e912b70eaad4fafbd4d1238007ab221de2009b9a2f5ae7461239895", size = 17085145, upload-time = "2026-05-18T23:36:33.449Z" }, - { url = "https://files.pythonhosted.org/packages/f9/45/68d7c33a6bcf3e5aa3bdbd57a367e6f615286dfd6482f97e8ffeb734306e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:29cb7f67d10b479ff07c17d33e39f78c07f71c40ef30d63c153d340e96cd3fb4", size = 18403813, upload-time = "2026-05-18T23:36:37.369Z" }, - { url = "https://files.pythonhosted.org/packages/9c/50/0753655aa844c99cd9e018aacf76f130f1bd81d881bb74bc0aef5d73a8ba/numpy-2.4.6-cp314-cp314t-win32.whl", hash = "sha256:260a5d70215b61ab4fadf5c7baacd64821842975eea312125ed3c39a6391b063", size = 6156982, upload-time = "2026-05-18T23:36:40.817Z" }, - { url = "https://files.pythonhosted.org/packages/b2/d4/7c67becf668f973cb490cec3e98dfd799d866f9c989a54d355672cfa0db6/numpy-2.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:81a1cca95ed5bb92aa8b10dd2cdc9a0d3853a50fad926c28b5d7e8ea54389627", size = 12638908, upload-time = "2026-05-18T23:36:43.996Z" }, - { url = "https://files.pythonhosted.org/packages/43/bb/e1c71a4295b1b1d1393d50dbb4f2a36283c6859d9d3892e84f00ec5a91d5/numpy-2.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:0c9136e14ed34a9e343a31c533d78a9813a69a3148332bce5e9821cb2f996e66", size = 10565867, upload-time = "2026-05-18T23:36:47.114Z" }, - { url = "https://files.pythonhosted.org/packages/de/12/b422cc84439adc0d00de605bf4a308890ae5c26f2c71fbd73e5d08fbb0dd/numpy-2.4.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:55cced7c52e981362f708ad635198e97a752dfba412cc03c23bbf3bd8d5cd662", size = 16847511, upload-time = "2026-05-18T23:36:50.673Z" }, - { url = "https://files.pythonhosted.org/packages/44/53/f481bef68011740f8849418d82db07230e825013f31f4eef5ba5b805316a/numpy-2.4.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6da64deb6b8ed903e7560180a92f2d804ee1ba5eeb849ac2748b8c1aba1f6d7", size = 14889064, upload-time = "2026-05-18T23:36:53.879Z" }, - { url = "https://files.pythonhosted.org/packages/7f/57/42ed575c10ced8af951d426bc4e1f8aff16fd851db33f067036215a7f860/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:68a5124b13fa6cc2086764a20005d30bc0548146f7f5322f02fce212ca14317f", size = 5394157, upload-time = "2026-05-18T23:36:57.194Z" }, - { url = "https://files.pythonhosted.org/packages/6a/ef/f66cc724fcc36c1e364c67f51ae9146090b8b584f27d58b97fdae3edd737/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:948424b06129ce883307e8cff868c31396d8dc7630a59c61d70d98dbe70f222c", size = 6708728, upload-time = "2026-05-18T23:36:59.575Z" }, - { url = "https://files.pythonhosted.org/packages/1a/9c/c531f2293b91265d8b48e9b329f54fdd7ffae73cb4134ea10cca4237e9cc/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbbdb29840ca3d91ee0fece42fc29278886d908280bfec0a5846c6f901a3eb0", size = 15798374, upload-time = "2026-05-18T23:37:02.674Z" }, - { url = "https://files.pythonhosted.org/packages/1a/b0/413077f6b1153ed3cba361401c6783bbad6114804a000cc22eb71c13e190/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ad03c0965fb3c692200e74d458ca28c1dbb4ce96f9a479a8aa041ad5fabca02", size = 16747286, upload-time = "2026-05-18T23:37:06.327Z" }, - { url = "https://files.pythonhosted.org/packages/15/ce/e5ec180bc41812edcd8daeb8639d205622c0e8c02259d8ab25a0201b3c2a/numpy-2.4.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2803abfebfc990042cd494d8ce2d5f82e9d847af6d35ec486923aa19dbad5e73", size = 12504263, upload-time = "2026-05-18T23:37:09.715Z" }, + { url = "https://files.pythonhosted.org/packages/54/c8/12811c9b48fde162bb72b6f2e78fada9a247a09d7bb5be2050a5d099c77b/nodeenv-1.11.0-py2.py3-none-any.whl", hash = "sha256:edaa16e6c14d7cf395d75d4bbd5a26390f4dc06501a33b4e76282b02cc688a25", size = 34277, upload-time = "2026-09-26T11:29:19.933Z" }, ] [[package]] name = "numpy" version = "2.5.4" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' 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.12' and python_full_version < '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] sdist = { url = "https://files.pythonhosted.org/packages/95/b0/c7453d0b6e2073c3264468b106ee1563750cecc910965e67357e3698c83e/numpy-2.5.4.tar.gz", hash = "sha256:9a94cf751c9ad8ebaa835bcd3d40dacf8534ad086b88c38029b65123c7999d2a", size = 20866315, upload-time = "2026-10-10T20:05:31.422Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d0/97/ba2074e92b7befea137e77ea8471e768bbd87c339b7e8c9f5a931949f977/numpy-2.5.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c6342f54c67093cae5c0227eb0eb772fdb79f2a2c37a6eb278b9909ee06aa356", size = 17001609, upload-time = "2026-10-10T20:02:40.843Z" }, @@ -287,21 +220,12 @@ name = "pandas" version = "3.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "numpy", version = "2.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "numpy" }, { name = "python-dateutil" }, { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/55/b1/a10c0d1a7e3ce44eb42635771004aa503e3b9ddde0bd39c524dda65f7eff/pandas-3.1.0.tar.gz", hash = "sha256:ecb9b2d8a817b1e1ba1fdb90c0abe9eab31b4fdf2562b7a56b86ac66ace17e49", size = 5933421, upload-time = "2026-10-22T11:57:03.087Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/f2/d8d89ee886df6d959d7b9f483a55a0e5a1d5b034f08c32f4343a524af802/pandas-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d53387f8bbff4e7aa567619d4034ffdb1836db1e768a482851b904bbeeed8ef9", size = 11595013, upload-time = "2026-10-22T11:54:48.33Z" }, - { url = "https://files.pythonhosted.org/packages/ec/73/e5243378792b79d3d08f9a6782a0e23ae65cc8c6d2f476b9d2825946b071/pandas-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d2ca3b380f0f6cc788780430eb23762619730c11d53989f3982ec96835bfb9e", size = 11159002, upload-time = "2026-10-22T11:54:51.011Z" }, - { url = "https://files.pythonhosted.org/packages/bf/4a/1064a6ec84ae047379a5969f6b331bd8d57013f08b30976564780fb0c9bd/pandas-3.1.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:388fad0c683ad061baabe23a76f43bf43c1d2c2fd46572b687082cfa195b7275", size = 11758276, upload-time = "2026-10-22T11:54:53.367Z" }, - { url = "https://files.pythonhosted.org/packages/14/41/2d264868728f7cb2add91a605bea5f2aabd3da41889ee97746a586ec34ee/pandas-3.1.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0a28602573f50453b57802d282f9f8cb7663aa10201127ecbbe95ed4a41c64ce", size = 12330371, upload-time = "2026-10-22T11:54:55.654Z" }, - { url = "https://files.pythonhosted.org/packages/7e/04/790ac6114ceb45575d7d7a909126210f829978f18f4f10ea8c6c847f0118/pandas-3.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e6f83e44846f9386e3593965bac017a54a5b5c611ea7b836ceab7f465bb4cb24", size = 12777723, upload-time = "2026-10-22T11:54:58.08Z" }, - { url = "https://files.pythonhosted.org/packages/56/b1/0513aaaac23bc1400b831881448665565a1b9b327d3eb7c5aca2b23c0b84/pandas-3.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebbc0e652844e52e06d1525e5084ec1609158c086c8646aa6ccb34802102e533", size = 13411658, upload-time = "2026-10-22T11:55:00.372Z" }, - { url = "https://files.pythonhosted.org/packages/f5/1a/e33f6637445dd4b7323aa7bdaf4cc15c383805b4a2e99f958b7e32296e58/pandas-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:a7704e3d7367cfae71d3f8c95ee81e178c7a90bef8d6eac30df9815010722259", size = 10977787, upload-time = "2026-10-22T11:55:02.967Z" }, - { url = "https://files.pythonhosted.org/packages/2e/f7/86bd686a20a5052e15581fdc7f220098426b1982604fb545e78bdd5b5b2e/pandas-3.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:d3e660af30a6683fa57a5a2969555df117e873eaaeb418ad3b2e59249405ee70", size = 10305708, upload-time = "2026-10-22T11:55:05.046Z" }, { url = "https://files.pythonhosted.org/packages/e9/12/b94c28870f351e9650c724e6daedf661455b348a9dca6d717c42c30fa216/pandas-3.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f4772320b7735d96dbbef437129f840dec4175f8a18a2391bd1222ed8943825c", size = 11587014, upload-time = "2026-10-22T11:55:07.208Z" }, { url = "https://files.pythonhosted.org/packages/1b/4b/af8ca15261db52ab07f5d0c2d4c1bc28d822ea4c2a79756bc2606c012e7c/pandas-3.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cc5e4e12d287ea77bbf4c4d4bf47ed152d82a990d3a6794dee7c350f887532b5", size = 11167712, upload-time = "2026-10-22T11:55:09.523Z" }, { url = "https://files.pythonhosted.org/packages/49/c4/cd5127751e2bef3d10f07e0d856e120916a3df0df6450f759ddb48c78b1c/pandas-3.1.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b4e696ff70ed06e986feeec09356c491ce878d0df69a36c8e591b6a38afa29b", size = 11476964, upload-time = "2026-10-22T11:55:11.889Z" }, @@ -353,6 +277,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/99/35/e60fd8228db4eb848802988dbc6e3a0f1a81c57f06ad95ebe4cd534fa655/pandas-3.1.0-cp315-cp315t-win_arm64.whl", hash = "sha256:f1a93c24175129bfc9922ef748ddae1d8137c743ed835e2615be329f606fed4d", size = 10597861, upload-time = "2026-10-22T11:57:00.776Z" }, ] +[[package]] +name = "patchelf" +version = "0.19.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/0b/691b49b40201a80cb09dbf2003eef0e36270ae07b00de99baa915df1d274/patchelf-0.19.1.0.tar.gz", hash = "sha256:8976fbdef7d3e461d623e703024b70db6b6e3308f7e389930f39a71a1e347a2c", size = 371787, upload-time = "2026-08-08T05:07:29.253Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/44/e2d33d8adbe206bc003aeb24840f62ad27b0bc44ec8baf97692d2bd3e5ef/patchelf-0.19.1.0-py3-none-macosx_10_9_universal2.whl", hash = "sha256:f97a0e9e657882b89d397418b76b667c0d8af7058a3775cf14c0e105e8ce3a58", size = 281233, upload-time = "2026-08-08T05:07:19.101Z" }, + { url = "https://files.pythonhosted.org/packages/83/03/29cd947cc94b2c91f5bd368c1b5d3469bec6b8ea538db67dcaf6e4ac065a/patchelf-0.19.1.0-py3-none-manylinux1_i686.manylinux_2_5_i686.musllinux_1_1_i686.whl", hash = "sha256:f16f44fbcf0da4f2d1dd841d49f849fe9ea1b8fb952d5c4e9b8234f09d3f149a", size = 624780, upload-time = "2026-08-08T05:07:20.401Z" }, + { url = "https://files.pythonhosted.org/packages/e7/03/afd9bdd2ba5f96997196109f25dadbe5141bc6e70dffd85f3f84cc85d69c/patchelf-0.19.1.0-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:a8f6331ccf40c345507279f755f4a38c2cb00b9efda746fd43c17713cce0aba4", size = 549422, upload-time = "2026-08-08T05:07:21.583Z" }, + { url = "https://files.pythonhosted.org/packages/cc/e6/1c78ad10adfc4b00a642ab518c246dd88dc826d641eb31faca5eaddc8b97/patchelf-0.19.1.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:b5c3dec03b89db2bb0df301d316360847eeaf72c6fb6ddde0227326655edabb4", size = 542031, upload-time = "2026-08-08T05:07:22.836Z" }, + { url = "https://files.pythonhosted.org/packages/e3/b8/a8bcf0a627b688ed0798048e585f1c1c8dbef5070db3f6c30c6895d73ce9/patchelf-0.19.1.0-py3-none-manylinux2014_armv7l.manylinux_2_17_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:2ffad3734be73b83ac2f46709264a34dd2aee40a7dd5deccf84856684d606ec6", size = 487087, upload-time = "2026-08-08T05:07:24.03Z" }, + { url = "https://files.pythonhosted.org/packages/a5/05/816af7bf3a51106e3558d32e10dc021a306d64f257fc0c404e4a9fcb1fba/patchelf-0.19.1.0-py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:89760f542fac28c7798e5f56e66601a78ef20e088fc80a493b6a9161438b8dc5", size = 612621, upload-time = "2026-08-08T05:07:25.276Z" }, + { url = "https://files.pythonhosted.org/packages/99/fc/48c07d0f74251946e62881a89ef105bed242e855928ac4f834a9bde85f73/patchelf-0.19.1.0-py3-none-manylinux2014_s390x.manylinux_2_17_s390x.musllinux_1_1_s390x.whl", hash = "sha256:efed44482d740e86d84e3f40e0ee9876c4249c7ac1128b5b1639e31287fa14a4", size = 674133, upload-time = "2026-08-08T05:07:26.541Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f3/dffc8a228ff8a2a627c48c7356ae36eb6d0c2497ba549a98a3b5a55f24af/patchelf-0.19.1.0-py3-none-manylinux_2_31_riscv64.musllinux_1_1_riscv64.whl", hash = "sha256:c2311d99eac1b9c40f5acd673e3b3581cde320bc4647e7f997e5e063731fc438", size = 572865, upload-time = "2026-08-08T05:07:27.867Z" }, +] + [[package]] name = "pluggy" version = "1.7.0" @@ -368,13 +308,6 @@ version = "26.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ec/34/17c34cb38e5d940e38f0f0d9fdfa0e8a506676409ea9b85aff7e3079f831/pyarrow-26.0.0.tar.gz", hash = "sha256:0cccd36e00ea3afeb52ded61f2721ce71f604853d70c45365c58324eb773d6ae", size = 1239433, upload-time = "2026-10-09T08:26:25.315Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/68/e0707097cee93be7f693e7e89495fabfeb8bf95ee30619063f8b30fffc29/pyarrow-26.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:fcdd1e04982637c6042337d3e24d472f938f01fdc502e2b994844b726d12c3f4", size = 36370896, upload-time = "2026-10-09T08:13:28.874Z" }, - { url = "https://files.pythonhosted.org/packages/5c/f0/591211c00612aef83236daff1620412b24aeb07c646de08c18a8a6c95a39/pyarrow-26.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:f800e9e722c145ccd18012d82a864cb21bfee4ba4ceffde77100d25eced511a9", size = 38709806, upload-time = "2026-10-09T08:13:33.417Z" }, - { url = "https://files.pythonhosted.org/packages/50/ea/9b035a9d1556e06e64ea86169d9a985d0fc092d427ac5edbb3af7183289c/pyarrow-26.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:7aa12ab8e236789b1ecd2d6ecaef036b4e63d675ddf1864a43c6799d18f2d028", size = 50885975, upload-time = "2026-10-09T08:13:37.737Z" }, - { url = "https://files.pythonhosted.org/packages/e1/81/8e685683897a6d3d5887c3e2fd24f3c14bc5d6d6bb3a2387484e665c580e/pyarrow-26.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:6e89dee53aaeb50505ed6152ea55bc7ddfd4f4df264f5427ea255288d8f0e580", size = 53904793, upload-time = "2026-10-09T08:13:42.984Z" }, - { url = "https://files.pythonhosted.org/packages/9a/ad/d474a0b1b00110f3a879aa5df654f857c81929a32b2a4222869240de5220/pyarrow-26.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f1c1b4263fd13abbc339a16f2bf19f3a5cbf2a620853d812b1256f03c5342cb8", size = 54458010, upload-time = "2026-10-09T08:13:47.778Z" }, - { url = "https://files.pythonhosted.org/packages/d4/86/2c2861e905810c59fed4d98c85b994c21e8613730c5c3b436781d89110f2/pyarrow-26.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ff1e816af7abff71f289242e109217036723ce36aca74ad6691e52d964a74afa", size = 57368406, upload-time = "2026-10-09T08:13:52.651Z" }, - { url = "https://files.pythonhosted.org/packages/0e/02/823e606633c15155bb965c7a0f3750c4f20dd47c4ab48213c7693df0e0ba/pyarrow-26.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:13b0972a3dc71b642050d1bc72664a3916e14f59c943d8c1368154d6e4b0c2d5", size = 28522657, upload-time = "2026-10-09T08:13:56.513Z" }, { url = "https://files.pythonhosted.org/packages/b3/60/6793778f2617cce469383dac0ba08c4f2401cf342df0c7b9ca53939d9b46/pyarrow-26.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:90ddaf7c625307ad52f31a9b25c34fe5e4897c7529ee3481135822b2b6842ff1", size = 36333953, upload-time = "2026-10-09T08:14:00.387Z" }, { url = "https://files.pythonhosted.org/packages/db/81/f944cc63ce8a753e5fbff25de6d1d475ebd7fffdf9cf98c65130294fc896/pyarrow-26.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:ee341973f78a0b46e073d065e88e75026a9c584051e97f98a0d05d96c6bac7dd", size = 38688456, upload-time = "2026-10-09T08:14:04.344Z" }, { url = "https://files.pythonhosted.org/packages/f5/2d/7e5c722fa5d5d9f3b75e62fe11694b34217664d4f05ac88031197166b277/pyarrow-26.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:01c863a18bd9c8412453dd0d92de6d0ee7b2b3d6fb079d9734a4b2a3c8bd4453", size = 50867603, upload-time = "2026-10-09T08:14:09.115Z" }, @@ -443,21 +376,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/a6/24/af4ec4be49fbc810f35b0bdcacc3d433b56bbfa469fd3bfd4ae116cd9bf1/pydantic_core-2.50.1.tar.gz", hash = "sha256:e50d7b94baac6c7d09927fa5ca5800a0c7ee5015c7fcff65beb3a1931b5a6e09", size = 513515, upload-time = "2026-10-11T18:35:44.82Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/45/1b/ca81811da3d2aea724fb3c4ba6b83f50ab8f210576306ccd601973142d35/pydantic_core-2.50.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c531166c42ea7bdfecc8c50049581f05dd1993b09cc7c52bb36a14e96deaec7d", size = 2152145, upload-time = "2026-10-11T18:31:58.046Z" }, - { url = "https://files.pythonhosted.org/packages/59/20/938ef7e0541af0a314e2f9d63848dbd1656ba2ebfe5ca0469f7ebee00d5e/pydantic_core-2.50.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b6d0c2183008c188e19f4906d426b293bdc4f67ab17df8e180fe16cda208fa71", size = 2045761, upload-time = "2026-10-11T18:31:59.35Z" }, - { url = "https://files.pythonhosted.org/packages/2f/4b/456497fe2affa18f49b226e89bde31e8a204751ee343dd9beaac5438123e/pydantic_core-2.50.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94be440c03fede26969a5ce75468e0e6a9927a1b46d9b679ee8adc1b057b0350", size = 2049557, upload-time = "2026-10-11T18:32:01.121Z" }, - { url = "https://files.pythonhosted.org/packages/a5/9d/cd5dfe13928f55e236dff3a1bee06721d318ca6c955d9ca993b0a5d09f39/pydantic_core-2.50.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:36c426eac0af8d1529ff8467e612b933346caec1fdc0d774f78f67a1a11e16c1", size = 2188153, upload-time = "2026-10-11T18:32:02.442Z" }, - { url = "https://files.pythonhosted.org/packages/fb/8d/d0b25bc484f8d9136ea76ece69e0b2d24ab370cc2e7bbd1b79e61723b763/pydantic_core-2.50.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:028e2f212273d4a39b1ec1e0de8166b1165a65fc0f1111452a9d94fc7c625c63", size = 2388308, upload-time = "2026-10-11T18:32:03.767Z" }, - { url = "https://files.pythonhosted.org/packages/c5/64/6513cac7c9f78492abafa01d57a69de1d246bf3085fd7b0330bf14b025b3/pydantic_core-2.50.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6f0cc1bb9900dc558960894adeb30b0c083366fc1d69b856209fb2ca5c36fe5", size = 2431187, upload-time = "2026-10-11T18:32:05.159Z" }, - { url = "https://files.pythonhosted.org/packages/ed/60/7f2ae89c37e69a3dc0da9ff57b0388c285542c688d05f36767770429de85/pydantic_core-2.50.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8812592c85d0edf423f10eadcef42716d71e8219085ad9e85b775057b7306133", size = 2157623, upload-time = "2026-10-11T18:32:06.616Z" }, - { url = "https://files.pythonhosted.org/packages/87/02/e3a71373b85a7973099b9a229a4302c7792262717e0b4997e41c01f7dd16/pydantic_core-2.50.1-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:bbce99252ba3167b2b6277f1829d5bf4b43b754524bddf7f944707c3db7d2253", size = 2254539, upload-time = "2026-10-11T18:32:07.968Z" }, - { url = "https://files.pythonhosted.org/packages/3f/d5/5b620aaf40dc631d911565b64d49d3fa8422027c046a7a96dc4e4921ae98/pydantic_core-2.50.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:476f6ed8e43cd1e0b460920e23571700872b284e77331cb30c4faf459cf48a4b", size = 2267344, upload-time = "2026-10-11T18:32:09.399Z" }, - { url = "https://files.pythonhosted.org/packages/e0/48/f46baf4580d8a56ca4782aa65842e16d3cf39736b29fcce8e9c0521b3422/pydantic_core-2.50.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2cbd1b75b09e976ed0d6b6ca297675632ca35df86130088457cdc60ef36970ae", size = 2300877, upload-time = "2026-10-11T18:32:10.903Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9d/e7d28505e6092c1fe075838a4f793ccbe6dd676e44ab16175815ee06cfe0/pydantic_core-2.50.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:5958c72adb417c39b12ac87525ac60b0d73315fcdc59e21f44ee4a5e2512c9ef", size = 2464270, upload-time = "2026-10-11T18:32:12.329Z" }, - { url = "https://files.pythonhosted.org/packages/22/b1/3bf63b82efd93ebc9968f9c12fc46037a28bcb452c88e4688f33e5ff7dca/pydantic_core-2.50.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d8f9e8a6c4ab04b78d61f78627370d834eb004b2869dcb28cfffa647b4ea1980", size = 2478653, upload-time = "2026-10-11T18:32:13.735Z" }, - { url = "https://files.pythonhosted.org/packages/28/17/26d1e4b9c2ba6a92b7dc75bbcb99ef44456b7e3af1bced868403667ea7d3/pydantic_core-2.50.1-cp311-cp311-win32.whl", hash = "sha256:4be846f55c9477f5f3ddde8f2ce941137e16862a56d018ed885d422bb6ae02f2", size = 2120246, upload-time = "2026-10-11T18:32:15.591Z" }, - { url = "https://files.pythonhosted.org/packages/24/65/3e875e7991eaecd4d70686293ff0d8a99aa8f93dc295e6a21c3d702912fb/pydantic_core-2.50.1-cp311-cp311-win_amd64.whl", hash = "sha256:0048b6dddc8ef4b64fccaad878bd143b0c3882ea9936279dc11d613f6b7dd1bc", size = 2176332, upload-time = "2026-10-11T18:32:17.153Z" }, - { url = "https://files.pythonhosted.org/packages/ab/5c/58dbd17c61f209d91c70f549eb7a3bbec7023e89ea12dead091462d6d658/pydantic_core-2.50.1-cp311-cp311-win_arm64.whl", hash = "sha256:6a733778df2f7087ec1100ed0b41533e4f3001976e99570fa34f57c66e7f8e3e", size = 2182471, upload-time = "2026-10-11T18:32:18.49Z" }, { url = "https://files.pythonhosted.org/packages/ee/94/101b49a6c63f99586755690696eae14532772587d9e39e93f7b8d28a49da/pydantic_core-2.50.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:704075d10b74f2f3c6e15407c696d88701df35fc8953f434a431add0d0074db0", size = 2222428, upload-time = "2026-10-11T18:32:20.228Z" }, { url = "https://files.pythonhosted.org/packages/db/a3/f8b1b39349c33037c73d7a1b794c9c29d8f07d5bd2b74399c1375a529cc6/pydantic_core-2.50.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e8e1d6ce820aa23317e8209a86bd65a540973c12dc7552b48a4f6c8e9926815e", size = 2025779, upload-time = "2026-10-11T18:32:21.723Z" }, { url = "https://files.pythonhosted.org/packages/d2/2d/862a7d115305cc621358e51ba13f296e0ffdf4fbd984be9f63bc7862730b/pydantic_core-2.50.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c18db21573bd2c6489f9a544b7499f0df2853958c568e5e783536ee1f690af41", size = 2048429, upload-time = "2026-10-11T18:32:23.3Z" }, @@ -549,22 +467,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/31/5c/e47e28281f20326ff6f3c31d626f0a83e615d2d94ba41bb0ad6ec237184a/pydantic_core-2.50.1-cp315-cp315t-win32.whl", hash = "sha256:3fde4fdc6487a58d944ca87cf5adc95d5f266e872c19599f5f4c0a8a1b1f9f9f", size = 2098535, upload-time = "2026-10-11T18:34:59.313Z" }, { url = "https://files.pythonhosted.org/packages/03/ad/759e181e69c1b472c60b2049e5f61d5da1deefdd5ce1df4bb2ebcf771f25/pydantic_core-2.50.1-cp315-cp315t-win_amd64.whl", hash = "sha256:1c8632d4ac04e6f91128fca584b3a8a507d81604c24eeaaad00d4be42765c32b", size = 2148645, upload-time = "2026-10-11T18:35:01.571Z" }, { url = "https://files.pythonhosted.org/packages/6d/56/8a702c27e5be9f47e5f19d8669227424290e4c024e7c370279cbaf244b4e/pydantic_core-2.50.1-cp315-cp315t-win_arm64.whl", hash = "sha256:c3ede305158e75510be50869b319550ab072008c13d64d4ab1e094fb286b6f44", size = 2175297, upload-time = "2026-10-11T18:35:04.079Z" }, - { url = "https://files.pythonhosted.org/packages/e7/73/a23a327237d9bb985298ce47702e196f995ce850224c12c70886bd66bb5c/pydantic_core-2.50.1-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:062e891facce5ca296a1c37098e5e466780457f86413894b399f0cf22934f769", size = 2162560, upload-time = "2026-10-11T18:35:06.274Z" }, - { url = "https://files.pythonhosted.org/packages/df/b2/33b37b5e82408f402a5e82649a43e7c95cd5dab7beaeef2c35cedbfd18f2/pydantic_core-2.50.1-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:49c2cbb2397fe4d0987e84606e691af6cb87bc0ee1bd3e7b737f7e10b4c142f9", size = 2075250, upload-time = "2026-10-11T18:35:08.455Z" }, - { url = "https://files.pythonhosted.org/packages/04/62/c7d5b9249466ccab90f3ce4790c2399dbfb8172ae9e74a7753dd295fe65a/pydantic_core-2.50.1-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e4472072de0137ee0d8e72d6620e85939c271d2f90f6bbb4b15c24638b79f92", size = 2107891, upload-time = "2026-10-11T18:35:10.918Z" }, - { url = "https://files.pythonhosted.org/packages/d4/7e/28d29bc1657195933147f772dee0558d9e0f045bbc11db7f992f40c37bb5/pydantic_core-2.50.1-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ed4f3cef55164b026fefb41341b7754cc6b624c75dfe7142d2ecceb5ad21c87", size = 2268026, upload-time = "2026-10-11T18:35:13.336Z" }, { url = "https://files.pythonhosted.org/packages/a5/09/1bcf160f3cd6333e2a76982fae5963e5032de0bcaaba38464223dc266bfe/pydantic_core-2.50.1-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:76e2e83fa6ec8cdc972d438dafc2522b3a47bee4ec0ae668b29cfb1977ab5242", size = 2217070, upload-time = "2026-10-11T18:35:15.688Z" }, { url = "https://files.pythonhosted.org/packages/3d/81/f02de95eec7794dfc7a5bc69a834f0e834b31b3009014ce6de903855f775/pydantic_core-2.50.1-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:a51eee75939cf811ac09b278745a6cee7dc873ccfbc8b9af3cc88fe4b7ce25b5", size = 2039027, upload-time = "2026-10-11T18:35:18.07Z" }, { url = "https://files.pythonhosted.org/packages/4d/16/227746ed3771d9bf2304568b55134849ece34e13b38b1d76de763015c77f/pydantic_core-2.50.1-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae28183297fb0d2b8dc46a1f01d51f5e45825fc5afe76a835a6cb7fb34821295", size = 2109009, upload-time = "2026-10-11T18:35:20.218Z" }, { url = "https://files.pythonhosted.org/packages/e5/b9/7664d1592a0e5a74903f357cd5b28ceb7336f3473256c5a4e8c8432f1881/pydantic_core-2.50.1-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88e492e8b9d0312e7dc13667c30222abf284dc3b79b5302b3607b41a5784ce61", size = 2269883, upload-time = "2026-10-11T18:35:22.48Z" }, - { url = "https://files.pythonhosted.org/packages/bd/35/002a378302ff91d2a7f149bc8d22363faf581ba40ac39d0123444315a32d/pydantic_core-2.50.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7456d699b13954e9c0164dcb267250a10ae0dfb03e6e26d6796ab0d46e189c84", size = 2154076, upload-time = "2026-10-11T18:35:24.743Z" }, - { url = "https://files.pythonhosted.org/packages/4b/5c/7a034330082c00f3c9795052bd9b161aaaf6e1951e897ac00a094823ef7e/pydantic_core-2.50.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0d955195bbbe489ad343fcc956eacea9357b79cb22192c66cacdefcbc14b32f", size = 2085850, upload-time = "2026-10-11T18:35:27.009Z" }, - { url = "https://files.pythonhosted.org/packages/57/fa/d5b44a7d3d4eceed6ef8713a0003af56fefde6ec75915513bcdd5d730cd9/pydantic_core-2.50.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2c634642694e6a0dad2ab1d375589fa671fd442edd5caf7d9737b8f6ca22906", size = 2259754, upload-time = "2026-10-11T18:35:29.763Z" }, - { url = "https://files.pythonhosted.org/packages/b6/88/e01dd37301710bd8b3b2daf34ec9e2a6e83a333130831c0d468b0292a48c/pydantic_core-2.50.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ee6db2fbed51a7991302e8fac498cd67e336246026d0dfa84cf5166ce1412760", size = 2268712, upload-time = "2026-10-11T18:35:32.654Z" }, - { url = "https://files.pythonhosted.org/packages/3e/43/5bb80d4a4d2b2d84612a30205662cc521a20d209c94abc079ea48b4e0df2/pydantic_core-2.50.1-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:79490e33c4c0fcb933bbbcfc3a62184d8803b99f535863dfbb925e1bcb6945ad", size = 2305049, upload-time = "2026-10-11T18:35:35.392Z" }, - { url = "https://files.pythonhosted.org/packages/e8/7b/e3ef76b269cfe4a5bd3bdcf5d7124cf05e5a8909d443b91639307116bdae/pydantic_core-2.50.1-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:48569b0ade9edfbe065cad1d700175546592aebbb42f02adcebcc26e75b896fe", size = 2466001, upload-time = "2026-10-11T18:35:37.791Z" }, - { url = "https://files.pythonhosted.org/packages/8f/7a/ea0947aadc1d9f72d4be00d2e19939611ec17363bcb5e6eb9ec7d8221c34/pydantic_core-2.50.1-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5f3cae32fc46121f787cb2486de9cf95a8bf72aec5cc78f64c606fa1735a6ef5", size = 2481777, upload-time = "2026-10-11T18:35:40.287Z" }, - { url = "https://files.pythonhosted.org/packages/24/f3/d15bc0b1fb0c4f1e07b3326ffb7489f7ae70da2b56a0884d22641b0eb47c/pydantic_core-2.50.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:7f476456ac2bb0d937f75191494a09c83a30765fea4f70f3b404942fe25f6cdf", size = 2336787, upload-time = "2026-10-11T18:35:42.558Z" }, ] [[package]] @@ -582,8 +488,7 @@ version = "13.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "lance-namespace" }, - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "numpy", version = "2.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "numpy" }, { name = "pyarrow" }, ] wheels = [ From 65fa0ee787b0eb27227a7c4261e847646cef082a Mon Sep 17 00:00:00 2001 From: prrao87 Date: Sat, 24 Oct 2026 11:38:24 -0400 Subject: [PATCH 5/5] ci: put the zig binary on PATH instead of the ziglang tool's Python maturin-action runs python3 -m pip install, and the uv tool environment's Python has no pip. The zig binary that ziglang ships is found on PATH first, leaving python3 to the runner. --- .github/workflows/python-publish.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index a0ec82a..1f19356 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -60,9 +60,10 @@ jobs: # protoc is needed by Lance's build scripts, not by wheel users. sudo apt-get update sudo apt-get install -y protobuf-compiler - # maturin finds zig through `python3 -m ziglang`: put a Python that has it first on PATH. + # The ziglang package ships a zig binary: put its directory on PATH, where maturin + # looks first. (Not the tool's python3, which has no pip for maturin-action to use.) uv tool install ziglang - echo "$(uv tool dir)/ziglang/bin" >> "$GITHUB_PATH" + "$(uv tool dir)/ziglang/bin/python" -c "import os, ziglang; print(os.path.dirname(ziglang.__file__))" >> "$GITHUB_PATH" - name: Build manylinux_2_28 x86-64 wheel uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1