Skip to content

Commit 7d28da9

Browse files
authored
Merge pull request #14 from d-v-b/docs/add-doctests
docs: add doctests
2 parents 0e3b66d + 665d628 commit 7d28da9

4 files changed

Lines changed: 147 additions & 40 deletions

File tree

README.md

Lines changed: 105 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@
3030

3131
# cast-value.py
3232

33-
A python implementation of the `cast_value` codec for [Zarr](https://zarr.dev/),
33+
A Python implementation of the `cast_value` codec for [Zarr](https://zarr.dev/),
3434
with [zarr-python](https://zarr.readthedocs.io/en/stable/) integration.
3535

36-
## what
36+
## What
3737

3838
The `cast_value` codec defines how to _safely_ convert arrays between integer
3939
and float data types. In Zarr terminology, this codec is an "array -> array"
@@ -44,55 +44,133 @@ You can find the
4444
in the
4545
[zarr-extensions repository](https://github.com/zarr-developers/zarr-extensions).
4646

47-
## why
47+
## Why
4848

49-
This codec is commonly used to for lossy data compression: when decoded data
50-
should be high-precision floats, but the absolute range of the values fits
51-
within the range of a smaller integer data type, then encoding the floats as
52-
ints before writing data can vastly shrink the stored values.
49+
This codec is commonly used for lossy data compression: when decoded data should
50+
be high-precision floats, but the absolute range of the values fits within the
51+
range of a smaller integer data type, then encoding the floats as ints before
52+
writing data can vastly shrink the stored values.
5353

5454
For example, if your data is a sequence of `float64` values like
5555
`[100.1, 120.3, 125.5]`, storing those values as `uint8`, e.g.
5656
`[100, 120, 125]`, offers 8-fold reduction in storage size, provided the
5757
precision lost due to rounding is acceptable.
5858

59-
## how
59+
## Installation
60+
61+
<!--pytest.mark.skip-->
62+
63+
```bash
64+
pip install cast-value
65+
```
66+
67+
For the optional Rust backend (faster for large arrays):
68+
69+
<!--pytest.mark.skip-->
70+
71+
```bash
72+
pip install 'cast-value[rs]'
73+
```
74+
75+
## Usage
76+
77+
The codec is automatically registered with zarr-python via the `zarr.codecs`
78+
entrypoint. When `cast-value[rs]` is installed, the Rust backend is used;
79+
otherwise it falls back to the pure-NumPy backend.
6080

6181
```python
62-
# import the codec that uses the rust backend
63-
from cast_value import CastValueRustV1
82+
import numpy as np
83+
import zarr
84+
import zarr.storage
6485

65-
# Create an in-memory zarr array with float64 dtype, stored as uint8.
66-
# The cast_value codec handles the conversion: float64 -> uint8 on write,
67-
# uint8 -> float64 on read.
86+
from cast_value import CastValueNumpyV1
6887

69-
codec = CastValueRustV1(
88+
codec = CastValueNumpyV1(
7089
data_type="uint8",
7190
rounding="nearest-even",
7291
out_of_range="clamp",
73-
scalar_map={
74-
"encode": [(np.nan, 0), (np.inf, 1), (-np.inf, 2)],
75-
"decode": [(0, np.nan), (1, np.inf), (2, -np.inf)],
76-
},
7792
)
78-
# Create array and write float64 data — values are rounded and clamped to [0, 255]
79-
data = np.array([np.nan, np.inf, -np.inf, 3.3, 4])
80-
arr = zarr.create_array(data=data, store=zarr.storage.MemoryStore(), filters=codec)
8193

82-
# Read it back — comes back as float64, but with uint8 precision
94+
# Write float64 data -- values are rounded and clamped to [0, 255]
95+
data = np.array([1.5, 100.7, 255.9, -3.0], dtype=np.float64)
96+
arr = zarr.create_array(store={}, data=data, filters=codec)
97+
98+
# Read it back -- comes back as float64, but with uint8 precision
8399
result = arr[:]
84100

85101
print(f"Array dtype: {arr.dtype}")
86102
print(f"Values written: {data}")
87103
print(f"Values read: {result}")
104+
```
105+
106+
<!--pytest-codeblocks:expected-output-->
88107

89-
"""
108+
```
90109
Array dtype: float64
91-
Values written: [ nan inf -inf 3.3 4. ]
92-
Values read: [ nan inf -inf 3. 4.]
93-
"""
110+
Values written: [ 1.5 100.7 255.9 -3. ]
111+
Values read: [ 2. 101. 255. 0.]
112+
```
113+
114+
## Development
115+
116+
This project uses [uv](https://docs.astral.sh/uv/) for dependency management.
117+
118+
### Setup
119+
120+
<!--pytest.mark.skip-->
121+
122+
```bash
123+
# Clone the repo
124+
git clone https://github.com/zarr-developers/cast-value.py.git
125+
cd cast-value.py
126+
127+
# Install dev dependencies (includes test + benchmark deps)
128+
uv sync --group dev
129+
```
130+
131+
### Running tests
132+
133+
<!--pytest.mark.skip-->
134+
135+
```bash
136+
# Run the full test suite
137+
uv run pytest tests
138+
139+
# Run with coverage
140+
uv run pytest tests --cov=cast_value --cov-report=term-missing
141+
```
142+
143+
### Running all checks
144+
145+
<!--pytest.mark.skip-->
146+
147+
```bash
148+
# Run the full CI suite locally (tests, linting, type checking)
149+
uvx nox
150+
151+
# Or run just linting and type checking
152+
uvx prek
153+
```
154+
155+
### Building docs
156+
157+
<!--pytest.mark.skip-->
158+
159+
```bash
160+
uv sync --group docs
161+
uv run zensical build
162+
# Output is in site/
163+
```
164+
165+
### Running examples
166+
167+
<!--pytest.mark.skip-->
168+
169+
```bash
170+
uv run python examples/zarr_integration/zarr_cast_value.py
171+
uv run python examples/benchmarks/bench_numpy_vs_rust.py
94172
```
95173

96-
# who
174+
## Who
97175

98176
Davis Bennett (@d-v-b)

docs/index.md

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@ explicit scalar mappings.
1010

1111
## Installation
1212

13+
<!--pytest.mark.skip-->
14+
1315
```bash
1416
pip install cast-value
1517
```
1618

1719
For the optional Rust-accelerated backend:
1820

21+
<!--pytest.mark.skip-->
22+
1923
```bash
2024
pip install cast-value[rs]
2125
```
@@ -25,27 +29,29 @@ pip install cast-value[rs]
2529
```python
2630
import numpy as np
2731
import zarr
28-
from cast_value import CastValueNumpyV1
2932

30-
zarr.registry.register_codec("cast_value", CastValueNumpyV1)
33+
from cast_value import CastValueNumpyV1
3134

3235
codec = CastValueNumpyV1(
3336
data_type="uint8",
3437
rounding="nearest-even",
3538
out_of_range="clamp",
3639
)
3740

38-
arr = zarr.create(
39-
shape=(100,),
40-
dtype="float64",
41-
chunks=(10,),
42-
store=zarr.storage.MemoryStore(),
43-
codecs=[codec, zarr.codecs.BytesCodec()],
44-
fill_value=0.0,
45-
)
41+
# float64 values with fractional parts and values outside [0, 255]
42+
data = np.array([1.5, 2.5, 3.5, 100.7, 255.9, -3.0, 999.0], dtype=np.float64)
43+
arr = zarr.create_array(data=data, store={}, filters=codec)
4644

47-
arr[:] = np.linspace(0, 300, 100)
48-
print(arr[:10]) # [0. 3. 6. 9. 12. 15. 18. 21. 24. 27.]
45+
# Read back: fractional values are rounded (nearest-even),
46+
# out-of-range values are clamped to [0, 255]
47+
result = arr[:]
48+
print(result)
49+
```
50+
51+
<!--pytest-codeblocks:expected-output-->
52+
53+
```
54+
[ 2. 2. 4. 101. 255. 0. 255.]
4955
```
5056

5157
## Backends

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Changelog = "https://github.com/zarr-developers/cast-value/releases"
5151
test = [
5252
"pytest >=9",
5353
"pytest-cov >=7",
54+
"pytest-codeblocks",
5455
]
5556
test-rs = [
5657
{ include-group = "test" },
@@ -84,14 +85,16 @@ env-vars.PYTHONWARNDEFAULTENCODING = "1"
8485

8586
[tool.pytest]
8687
minversion = "9.0"
87-
addopts = ["-ra", "--showlocals", "--ignore=tests/benchmark"]
88+
addopts = ["-ra", "--showlocals", "--ignore=tests/benchmark", "--codeblocks"]
8889
strict = true
8990
filterwarnings = [
9091
"error",
9192
]
9293
log_level = "INFO"
9394
testpaths = [
9495
"tests",
96+
"README.md",
97+
"docs",
9598
]
9699

97100

uv.lock

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)