atlas-python 0.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- atlas_python-0.9.0/.github/workflows/atlas-python-release.yaml +115 -0
- atlas_python-0.9.0/.github/workflows/atlas-rust-release.yaml +53 -0
- atlas_python-0.9.0/.github/workflows/ci.yaml +51 -0
- atlas_python-0.9.0/.gitignore +31 -0
- atlas_python-0.9.0/CONTRIBUTING.md +218 -0
- atlas_python-0.9.0/Cargo.lock +2875 -0
- atlas_python-0.9.0/Cargo.toml +44 -0
- atlas_python-0.9.0/LICENSE +201 -0
- atlas_python-0.9.0/PKG-INFO +17 -0
- atlas_python-0.9.0/README.md +363 -0
- atlas_python-0.9.0/atlas-python/.python-version +1 -0
- atlas_python-0.9.0/atlas-python/Cargo.toml +20 -0
- atlas_python-0.9.0/atlas-python/README.md +275 -0
- atlas_python-0.9.0/atlas-python/benchmarks/README.md +249 -0
- atlas_python-0.9.0/atlas-python/benchmarks/_common.py +258 -0
- atlas_python-0.9.0/atlas-python/benchmarks/bench_collection.py +757 -0
- atlas_python-0.9.0/atlas-python/benchmarks/generate_bench_charts.py +141 -0
- atlas_python-0.9.0/atlas-python/docs/assets/bench_gridded.svg +1622 -0
- atlas_python-0.9.0/atlas-python/docs/assets/bench_profile.svg +1570 -0
- atlas_python-0.9.0/atlas-python/docs/benchmarks.md +187 -0
- atlas_python-0.9.0/atlas-python/docs/examples.md +36 -0
- atlas_python-0.9.0/atlas-python/docs/guides/attributes.md +103 -0
- atlas_python-0.9.0/atlas-python/docs/guides/bulk-reads.md +107 -0
- atlas_python-0.9.0/atlas-python/docs/guides/cloud-storage.md +151 -0
- atlas_python-0.9.0/atlas-python/docs/guides/codecs-and-meta.md +95 -0
- atlas_python-0.9.0/atlas-python/docs/guides/dask.md +100 -0
- atlas_python-0.9.0/atlas-python/docs/guides/datasets-and-arrays.md +144 -0
- atlas_python-0.9.0/atlas-python/docs/guides/dtypes.md +91 -0
- atlas_python-0.9.0/atlas-python/docs/guides/durability.md +98 -0
- atlas_python-0.9.0/atlas-python/docs/guides/shared-arrays.md +87 -0
- atlas_python-0.9.0/atlas-python/docs/guides/stats.md +87 -0
- atlas_python-0.9.0/atlas-python/docs/guides/xarray.md +123 -0
- atlas_python-0.9.0/atlas-python/docs/index.md +82 -0
- atlas_python-0.9.0/atlas-python/docs/installation.md +91 -0
- atlas_python-0.9.0/atlas-python/docs/quickstart.md +64 -0
- atlas_python-0.9.0/atlas-python/docs/reference/atlas.md +10 -0
- atlas_python-0.9.0/atlas-python/docs/reference/dataset-view.md +10 -0
- atlas_python-0.9.0/atlas-python/docs/reference/xarray-accessor.md +42 -0
- atlas_python-0.9.0/atlas-python/docs/vs-zarr-netcdf.md +139 -0
- atlas_python-0.9.0/atlas-python/examples/01_basics.py +67 -0
- atlas_python-0.9.0/atlas-python/examples/02_xarray.py +75 -0
- atlas_python-0.9.0/atlas-python/examples/03_dask_streaming.py +57 -0
- atlas_python-0.9.0/atlas-python/examples/04_meta_formats.py +83 -0
- atlas_python-0.9.0/atlas-python/examples/05_codecs.py +91 -0
- atlas_python-0.9.0/atlas-python/examples/06_stats_scan.py +77 -0
- atlas_python-0.9.0/atlas-python/examples/07_shared_arrays.py +82 -0
- atlas_python-0.9.0/atlas-python/examples/08_object_store.py +142 -0
- atlas_python-0.9.0/atlas-python/mkdocs.yml +90 -0
- atlas_python-0.9.0/atlas-python/src/attr.rs +60 -0
- atlas_python-0.9.0/atlas-python/src/dataset.rs +603 -0
- atlas_python-0.9.0/atlas-python/src/dtype.rs +101 -0
- atlas_python-0.9.0/atlas-python/src/error.rs +32 -0
- atlas_python-0.9.0/atlas-python/src/lib.rs +23 -0
- atlas_python-0.9.0/atlas-python/src/logging.rs +70 -0
- atlas_python-0.9.0/atlas-python/src/runtime.rs +12 -0
- atlas_python-0.9.0/atlas-python/src/store.rs +440 -0
- atlas_python-0.9.0/atlas-python/tests/GL_PR_BO_JLKU.nc +0 -0
- atlas_python-0.9.0/atlas-python/tests/test_smoke.py +556 -0
- atlas_python-0.9.0/atlas-python/tests/test_xarray.py +450 -0
- atlas_python-0.9.0/examples/lifecycle.rs +213 -0
- atlas_python-0.9.0/examples/sensor_fleet.rs +154 -0
- atlas_python-0.9.0/examples/weather_store.rs +340 -0
- atlas_python-0.9.0/pyproject.toml +40 -0
- atlas_python-0.9.0/python/atlas/__init__.py +4 -0
- atlas_python-0.9.0/python/atlas/__init__.pyi +332 -0
- atlas_python-0.9.0/python/atlas/py.typed +0 -0
- atlas_python-0.9.0/python/atlas/xarray.py +578 -0
- atlas_python-0.9.0/src/array.rs +115 -0
- atlas_python-0.9.0/src/config.rs +94 -0
- atlas_python-0.9.0/src/dataset.rs +797 -0
- atlas_python-0.9.0/src/error.rs +58 -0
- atlas_python-0.9.0/src/lib.rs +184 -0
- atlas_python-0.9.0/src/meta.rs +398 -0
- atlas_python-0.9.0/src/schema.rs +164 -0
- atlas_python-0.9.0/src/store.rs +851 -0
- atlas_python-0.9.0/tests/integration.rs +414 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
name: atlas-python release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
release:
|
|
6
|
+
types: [published]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
linux:
|
|
13
|
+
runs-on: ${{ matrix.runner }}
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
include:
|
|
18
|
+
- target: x86_64
|
|
19
|
+
runner: ubuntu-latest
|
|
20
|
+
- target: aarch64
|
|
21
|
+
runner: ubuntu-24.04-arm
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
- uses: actions/setup-python@v6
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.10"
|
|
27
|
+
- name: Build wheels
|
|
28
|
+
uses: PyO3/maturin-action@v1
|
|
29
|
+
with:
|
|
30
|
+
target: ${{ matrix.target }}
|
|
31
|
+
manylinux: auto
|
|
32
|
+
sccache: "true"
|
|
33
|
+
args: --release --out dist --manifest-path atlas-python/Cargo.toml
|
|
34
|
+
- uses: actions/upload-artifact@v4
|
|
35
|
+
with:
|
|
36
|
+
name: wheels-linux-${{ matrix.target }}
|
|
37
|
+
path: dist
|
|
38
|
+
|
|
39
|
+
macos:
|
|
40
|
+
runs-on: macos-latest
|
|
41
|
+
strategy:
|
|
42
|
+
fail-fast: false
|
|
43
|
+
matrix:
|
|
44
|
+
target: [x86_64, aarch64]
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v4
|
|
47
|
+
- uses: actions/setup-python@v6
|
|
48
|
+
with:
|
|
49
|
+
python-version: "3.10"
|
|
50
|
+
- name: Build wheels
|
|
51
|
+
uses: PyO3/maturin-action@v1
|
|
52
|
+
with:
|
|
53
|
+
target: ${{ matrix.target }}
|
|
54
|
+
sccache: "true"
|
|
55
|
+
args: --release --out dist --manifest-path atlas-python/Cargo.toml
|
|
56
|
+
- uses: actions/upload-artifact@v4
|
|
57
|
+
with:
|
|
58
|
+
name: wheels-macos-${{ matrix.target }}
|
|
59
|
+
path: dist
|
|
60
|
+
|
|
61
|
+
windows:
|
|
62
|
+
runs-on: windows-latest
|
|
63
|
+
strategy:
|
|
64
|
+
fail-fast: false
|
|
65
|
+
matrix:
|
|
66
|
+
target: [x64]
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v4
|
|
69
|
+
- uses: actions/setup-python@v6
|
|
70
|
+
with:
|
|
71
|
+
python-version: "3.10"
|
|
72
|
+
architecture: ${{ matrix.target }}
|
|
73
|
+
- name: Build wheels
|
|
74
|
+
uses: PyO3/maturin-action@v1
|
|
75
|
+
with:
|
|
76
|
+
target: ${{ matrix.target }}
|
|
77
|
+
sccache: "true"
|
|
78
|
+
args: --release --out dist --manifest-path atlas-python/Cargo.toml
|
|
79
|
+
- uses: actions/upload-artifact@v4
|
|
80
|
+
with:
|
|
81
|
+
name: wheels-windows-${{ matrix.target }}
|
|
82
|
+
path: dist
|
|
83
|
+
|
|
84
|
+
sdist:
|
|
85
|
+
runs-on: ubuntu-latest
|
|
86
|
+
steps:
|
|
87
|
+
- uses: actions/checkout@v4
|
|
88
|
+
- name: Build sdist
|
|
89
|
+
uses: PyO3/maturin-action@v1
|
|
90
|
+
with:
|
|
91
|
+
command: sdist
|
|
92
|
+
args: --out dist --manifest-path atlas-python/Cargo.toml
|
|
93
|
+
- uses: actions/upload-artifact@v4
|
|
94
|
+
with:
|
|
95
|
+
name: wheels-sdist
|
|
96
|
+
path: dist
|
|
97
|
+
|
|
98
|
+
release:
|
|
99
|
+
name: Publish to PyPI
|
|
100
|
+
runs-on: ubuntu-latest
|
|
101
|
+
if: github.event_name == 'release'
|
|
102
|
+
needs: [linux, macos, windows, sdist]
|
|
103
|
+
permissions:
|
|
104
|
+
id-token: write
|
|
105
|
+
environment:
|
|
106
|
+
name: pypi
|
|
107
|
+
url: https://pypi.org/p/atlas-python
|
|
108
|
+
steps:
|
|
109
|
+
- uses: actions/download-artifact@v4
|
|
110
|
+
with:
|
|
111
|
+
pattern: wheels-*
|
|
112
|
+
path: dist
|
|
113
|
+
merge-multiple: true
|
|
114
|
+
- name: Publish to PyPI
|
|
115
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: atlas-rust release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
release:
|
|
6
|
+
types: [published]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
name: Test
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
18
|
+
- uses: Swatinem/rust-cache@v2
|
|
19
|
+
- name: Build workspace
|
|
20
|
+
run: cargo build --workspace --verbose
|
|
21
|
+
- name: Test atlas crate
|
|
22
|
+
# atlas-python links `pyo3/extension-module` (no libpython), so a
|
|
23
|
+
# plain `cargo test` binary can't link there — test the core crate.
|
|
24
|
+
run: cargo test -p atlas-rust --verbose
|
|
25
|
+
|
|
26
|
+
publish:
|
|
27
|
+
name: Publish to crates.io
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
needs: test
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v4
|
|
32
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
33
|
+
- uses: Swatinem/rust-cache@v2
|
|
34
|
+
|
|
35
|
+
- name: Verify tag matches crate version
|
|
36
|
+
if: github.event_name == 'release'
|
|
37
|
+
run: |
|
|
38
|
+
crate_version="$(cargo metadata --no-deps --format-version 1 \
|
|
39
|
+
| python3 -c "import json,sys; print(next(p['version'] for p in json.load(sys.stdin)['packages'] if p['name']=='atlas-rust'))")"
|
|
40
|
+
tag_version="${GITHUB_REF_NAME#v}"
|
|
41
|
+
echo "crate=$crate_version tag=$tag_version"
|
|
42
|
+
if [ "$crate_version" != "$tag_version" ]; then
|
|
43
|
+
echo "::error::Tag $GITHUB_REF_NAME does not match crate version $crate_version"
|
|
44
|
+
exit 1
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
- name: Package (dry run)
|
|
48
|
+
run: cargo publish -p atlas-rust --locked --dry-run
|
|
49
|
+
|
|
50
|
+
- name: Publish
|
|
51
|
+
env:
|
|
52
|
+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
|
53
|
+
run: cargo publish -p atlas-rust --locked
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ci-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
rust:
|
|
18
|
+
name: Rust tests
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
23
|
+
- uses: Swatinem/rust-cache@v2
|
|
24
|
+
- name: Build workspace
|
|
25
|
+
run: cargo build --workspace --verbose
|
|
26
|
+
- name: Test atlas crate
|
|
27
|
+
# atlas-python links `pyo3/extension-module` (no libpython), so a
|
|
28
|
+
# plain `cargo test` binary can't link there — test the core crate.
|
|
29
|
+
run: cargo test -p atlas-rust --verbose
|
|
30
|
+
|
|
31
|
+
python:
|
|
32
|
+
name: Python tests
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
strategy:
|
|
35
|
+
fail-fast: false
|
|
36
|
+
matrix:
|
|
37
|
+
python-version: ["3.10", "3.13"]
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
- uses: actions/setup-python@v6
|
|
41
|
+
with:
|
|
42
|
+
python-version: ${{ matrix.python-version }}
|
|
43
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
44
|
+
- uses: Swatinem/rust-cache@v2
|
|
45
|
+
- name: Build extension and run pytest
|
|
46
|
+
run: |
|
|
47
|
+
python -m venv .venv
|
|
48
|
+
source .venv/bin/activate
|
|
49
|
+
python -m pip install --upgrade pip maturin
|
|
50
|
+
maturin develop --extras test --manifest-path atlas-python/Cargo.toml
|
|
51
|
+
pytest atlas-python/tests -v
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Generated by Cargo
|
|
2
|
+
# will have compiled files and executables
|
|
3
|
+
debug
|
|
4
|
+
target
|
|
5
|
+
|
|
6
|
+
# These are backup files generated by rustfmt
|
|
7
|
+
**/*.rs.bk
|
|
8
|
+
|
|
9
|
+
# MSVC Windows builds of rustc generate these, which store debugging information
|
|
10
|
+
*.pdb
|
|
11
|
+
|
|
12
|
+
# Generated by cargo mutants
|
|
13
|
+
# Contains mutation testing data
|
|
14
|
+
**/mutants.out*/
|
|
15
|
+
|
|
16
|
+
# RustRover
|
|
17
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
18
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
19
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
20
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
21
|
+
#.idea/
|
|
22
|
+
.venv/
|
|
23
|
+
__pycache__/
|
|
24
|
+
.pytest_cache/
|
|
25
|
+
raw_smoke_tests/
|
|
26
|
+
.DS_Store
|
|
27
|
+
.claude/
|
|
28
|
+
pyatlas/python/pyatlas/_pyatlas.pyd
|
|
29
|
+
pyatlas/python/pyatlas/_pyatlas.abi3.so
|
|
30
|
+
playground/
|
|
31
|
+
data/
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Contributing to ATLAS
|
|
2
|
+
|
|
3
|
+
Thanks for your interest. This document walks through what the project is, how the pieces fit, and how to set up a development environment.
|
|
4
|
+
|
|
5
|
+
For end-user docs see the top-level [README.md](README.md) (Rust crate) and [pyatlas/README.md](pyatlas/README.md) (Python bindings).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What this is
|
|
10
|
+
|
|
11
|
+
**ATLAS** (Aggregated Tensor Large Array Store) is a directory-based store for many similarly-shaped, named, N-dimensional arrays. The design goal is fast cross-dataset variable scans — opening a single file to read variable `X` across N datasets, rather than N files.
|
|
12
|
+
|
|
13
|
+
The repository is a Cargo workspace containing two crates:
|
|
14
|
+
|
|
15
|
+
| Crate | Purpose |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `atlas` (workspace root) | Rust library implementing the store and on-disk format. |
|
|
18
|
+
| `pyatlas` ([pyatlas/](pyatlas/)) | PyO3 Python bindings + xarray integration. |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## How it works (architecture)
|
|
23
|
+
|
|
24
|
+
### On-disk layout
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
my_store/
|
|
28
|
+
├── atlas.json ← dataset registry + per-dataset attributes (JSON)
|
|
29
|
+
├── temperature/
|
|
30
|
+
│ └── data.af ← ArrayFile: every dataset's "temperature" in one file
|
|
31
|
+
├── pressure/
|
|
32
|
+
│ └── data.af
|
|
33
|
+
└── time/
|
|
34
|
+
└── data.af
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Every variable name owns one physical `.af` file shared by all datasets that define it (variable-first). The `.af` format comes from the [`array-format`](https://github.com/robinskil/array-format) crate — it's a columnar, chunk-oriented binary container with per-block compression and persisted statistics.
|
|
38
|
+
|
|
39
|
+
`atlas.json` is the catalog. It records:
|
|
40
|
+
- Store version, store-level codec.
|
|
41
|
+
- Each dataset: its array schemas (dtype, shape, chunk shape, dimension names) and typed attributes.
|
|
42
|
+
|
|
43
|
+
### Rust crate (`atlas`)
|
|
44
|
+
|
|
45
|
+
| File | Role |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| [src/lib.rs](src/lib.rs) | Public re-exports; `validate_name`; thread-safety asserts. |
|
|
48
|
+
| [src/store.rs](src/store.rs) | The `Atlas` struct: open/create, dataset CRUD, path-based wrappers (`open_path` / `create_path`). |
|
|
49
|
+
| [src/dataset.rs](src/dataset.rs) | The `DatasetView` struct: define/read/write arrays, attributes, flush, compact. Also the shared `ArrayFile` cache. |
|
|
50
|
+
| [src/meta.rs](src/meta.rs) | `atlas.json` (de)serialisation. |
|
|
51
|
+
| [src/schema.rs](src/schema.rs) | `ArraySchema` and the typed `Attr` enum. |
|
|
52
|
+
| [src/config.rs](src/config.rs) | `StoreConfig`, `Codec` (`Zstd` / `Lz4` / `Uncompressed`). |
|
|
53
|
+
| [src/error.rs](src/error.rs) | `Error` / `Result`. |
|
|
54
|
+
|
|
55
|
+
The API is async (tokio). Each physical array file is guarded by a `tokio::sync::RwLock` — reads share, writes are exclusive. The cache map uses `parking_lot::RwLock` and is never held across an `await`.
|
|
56
|
+
|
|
57
|
+
### Python bindings (`pyatlas`)
|
|
58
|
+
|
|
59
|
+
Mixed Python/Rust maturin layout:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
pyatlas/
|
|
63
|
+
├── Cargo.toml ← cdylib named `_pyatlas`
|
|
64
|
+
├── pyproject.toml ← maturin build backend
|
|
65
|
+
├── python/pyatlas/
|
|
66
|
+
│ ├── __init__.py ← re-exports + xarray accessor registration
|
|
67
|
+
│ ├── __init__.pyi ← type stubs (PEP 561)
|
|
68
|
+
│ ├── py.typed ← marker
|
|
69
|
+
│ └── xarray.py ← xarray integration + ds.atlas accessor
|
|
70
|
+
├── src/
|
|
71
|
+
│ ├── lib.rs ← #[pymodule] _pyatlas wiring
|
|
72
|
+
│ ├── runtime.rs ← shared OnceLock<tokio::Runtime>
|
|
73
|
+
│ ├── error.rs ← atlas::Error → PyErr mapping
|
|
74
|
+
│ ├── dtype.rs ← dtype string parsing & DType ↔ name
|
|
75
|
+
│ ├── attr.rs ← Attr ↔ Python primitive conversion
|
|
76
|
+
│ ├── store.rs ← PyAtlas (wraps atlas::Atlas)
|
|
77
|
+
│ └── dataset.rs ← PyDatasetView (wraps atlas::DatasetView)
|
|
78
|
+
├── tests/ ← pytest tests
|
|
79
|
+
└── examples/ ← runnable example scripts
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Key design points:
|
|
83
|
+
- **Sync Python API, backed by an internal multi-threaded tokio runtime.** Each blocking call uses `py.allow_threads(|| RT.block_on(...))` so other Python threads can run.
|
|
84
|
+
- **Type dispatch via macros.** Atlas's read/write methods are generic over dtype (`T: ArrayElement`); the bindings dispatch at runtime via a `numeric_dispatch!` macro in [pyatlas/src/dataset.rs](pyatlas/src/dataset.rs).
|
|
85
|
+
- **`numpy`-zero-copy on the numeric path.** Python `np.ndarray` ↔ `ndarray::ArrayView` via the `numpy` crate.
|
|
86
|
+
- **xarray integration** lives in [pyatlas/python/pyatlas/xarray.py](pyatlas/python/pyatlas/xarray.py). The `Atlas.add_xr_dataset` Rust pymethod and the `ds.atlas.write` accessor both delegate to the `_write_xarray_new_dataset` helper. dask-backed variables are streamed one chunk at a time via `arr.blocks[idx].compute()`.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Prerequisites
|
|
91
|
+
|
|
92
|
+
| Tool | Why |
|
|
93
|
+
| --- | --- |
|
|
94
|
+
| **Rust** (stable, 1.85+ for edition 2024 in the atlas crate) | Build the workspace. |
|
|
95
|
+
| **Python ≥ 3.9** | Run / build pyatlas (wheel targets `abi3-py39`). |
|
|
96
|
+
| **`maturin`** | Build the Python extension. `pip install maturin`. |
|
|
97
|
+
|
|
98
|
+
Install Rust via [rustup.rs](https://rustup.rs). Python 3.13 is what the maintainers develop against.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Building & testing the Rust crate
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
cargo build # compile the atlas crate + workspace
|
|
106
|
+
cargo test # run all tests (60 in atlas, plus pyatlas check-only)
|
|
107
|
+
cargo test -p atlas # just the atlas crate (50 unit + 10 integration)
|
|
108
|
+
cargo run --example lifecycle # try one of the Rust examples
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Examples live in [examples/](examples/) — `lifecycle.rs`, `sensor_fleet.rs`, `weather_store.rs`.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Building & installing the Python library
|
|
116
|
+
|
|
117
|
+
The Python extension links against libpython, so plain `cargo build -p pyatlas` will fail at link time. Use `maturin develop` (which sets the right flags and installs into the active virtualenv).
|
|
118
|
+
|
|
119
|
+
### One-time setup
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# From the repo root
|
|
123
|
+
python3.13 -m venv .venv
|
|
124
|
+
source .venv/bin/activate
|
|
125
|
+
pip install --upgrade pip maturin
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`pyatlas` already lists `numpy`, `xarray`, and `dask` as required runtime deps, so `maturin develop` will pull them in automatically.
|
|
129
|
+
|
|
130
|
+
### Development build
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
cd pyatlas
|
|
134
|
+
maturin develop --release # builds, then editable-installs into the active venv
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
After `maturin develop`, the package is editable: changes to `python/pyatlas/*.py` take effect immediately, but Rust changes require re-running `maturin develop`.
|
|
138
|
+
|
|
139
|
+
### Building a distributable wheel
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
cd pyatlas
|
|
143
|
+
maturin build --release # produces pyatlas-0.1.0-*.whl in target/wheels/
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Verification
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
.venv/bin/python -c "import pyatlas; print(pyatlas.__version__)"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Running the Python tests
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
.venv/bin/pip install pytest # one-time
|
|
158
|
+
.venv/bin/pytest pyatlas/tests/ -v
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The two test files:
|
|
162
|
+
- [pyatlas/tests/test_smoke.py](pyatlas/tests/test_smoke.py) — exercises the core pyatlas API.
|
|
163
|
+
- [pyatlas/tests/test_xarray.py](pyatlas/tests/test_xarray.py) — xarray accessor + dask streaming.
|
|
164
|
+
|
|
165
|
+
After every Rust change re-run `maturin develop` first, otherwise pytest will run against the previously-built binary.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Running the Python examples
|
|
170
|
+
|
|
171
|
+
Self-contained scripts under [pyatlas/examples/](pyatlas/examples/) that write to temp directories:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
.venv/bin/python pyatlas/examples/01_basics.py
|
|
175
|
+
.venv/bin/python pyatlas/examples/02_xarray.py
|
|
176
|
+
.venv/bin/python pyatlas/examples/03_dask_streaming.py
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Common dev workflows
|
|
182
|
+
|
|
183
|
+
### Adding a new array dtype
|
|
184
|
+
|
|
185
|
+
1. Add the variant to `atlas::DType` (depends on `array-format` supporting it).
|
|
186
|
+
2. Add the dispatch arm in [pyatlas/src/dataset.rs](pyatlas/src/dataset.rs)'s `numeric_dispatch!` (or the explicit String/Binary branches).
|
|
187
|
+
3. Extend [pyatlas/src/dtype.rs](pyatlas/src/dtype.rs) to parse the new dtype name.
|
|
188
|
+
4. Update [pyatlas/python/pyatlas/xarray.py](pyatlas/python/pyatlas/xarray.py)'s `_NUMPY_TO_ATLAS` map if it has a numpy equivalent.
|
|
189
|
+
5. Add a smoke test in [pyatlas/tests/test_smoke.py](pyatlas/tests/test_smoke.py).
|
|
190
|
+
|
|
191
|
+
### Exposing a new `DatasetView` / `Atlas` method to Python
|
|
192
|
+
|
|
193
|
+
1. Implement on the Rust side in [src/store.rs](src/store.rs) or [src/dataset.rs](src/dataset.rs).
|
|
194
|
+
2. Wrap as a pymethod in [pyatlas/src/store.rs](pyatlas/src/store.rs) / [pyatlas/src/dataset.rs](pyatlas/src/dataset.rs). Use `py.allow_threads(|| runtime().block_on(...))` for async calls.
|
|
195
|
+
3. Add the stub in [pyatlas/python/pyatlas/\_\_init\_\_.pyi](pyatlas/python/pyatlas/__init__.pyi).
|
|
196
|
+
4. `cd pyatlas && maturin develop --release`.
|
|
197
|
+
5. Write a test.
|
|
198
|
+
|
|
199
|
+
### Touching the on-disk format
|
|
200
|
+
|
|
201
|
+
Format changes are breaking — bump the `version` field in `StoreMeta` ([src/meta.rs](src/meta.rs)) and load both versions during `load_meta` until a migration path is clear.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Code style
|
|
206
|
+
|
|
207
|
+
- Rust: `cargo fmt` before committing; we follow the default rustfmt configuration. `cargo clippy --all-targets` should be clean.
|
|
208
|
+
- Python: top-level scripts and tests use ordinary 4-space indentation and import ordering (stdlib, third-party, local). No formatter is enforced; match the existing style.
|
|
209
|
+
- Comments and docstrings explain *why*, not what — the code already shows what.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Pull requests
|
|
214
|
+
|
|
215
|
+
1. Branch from `main`.
|
|
216
|
+
2. Make sure `cargo test`, `cargo clippy --all-targets`, and `pytest pyatlas/tests/` all pass.
|
|
217
|
+
3. If you change the on-disk format, the public API, or any behaviour visible to end users, update the relevant README.
|
|
218
|
+
4. Keep commits focused; squash trivial fixups before review.
|