PyOPIA 2.16.14__tar.gz → 2.16.16__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.
- {pyopia-2.16.14 → pyopia-2.16.16}/.gitignore +1 -1
- {pyopia-2.16.14 → pyopia-2.16.16}/PKG-INFO +51 -35
- {pyopia-2.16.14 → pyopia-2.16.16}/README.md +46 -33
- pyopia-2.16.16/pyopia/__init__.py +1 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/auxillarydata.py +14 -7
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/cli.py +198 -93
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/instrument/holo.py +1 -1
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/pipeline.py +3 -1
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/statistics.py +11 -2
- pyopia-2.16.16/pyopia/tests/conftest.py +186 -0
- pyopia-2.16.16/pyopia/tests/test_classify.py +229 -0
- pyopia-2.16.16/pyopia/tests/test_cli.py +290 -0
- pyopia-2.16.16/pyopia/tests/test_notebooks.py +85 -0
- pyopia-2.16.16/pyopia/tests/test_pipeline.py +344 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyproject.toml +22 -0
- pyopia-2.16.14/pyopia/__init__.py +0 -1
- pyopia-2.16.14/pyopia/tests/test_classify.py +0 -256
- pyopia-2.16.14/pyopia/tests/test_notebooks.py +0 -26
- pyopia-2.16.14/pyopia/tests/test_pipeline.py +0 -330
- {pyopia-2.16.14 → pyopia-2.16.16}/LICENSE +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/background.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/cf_metadata.json +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/classify.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/classify_torch.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/dataexport/__init__.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/dataexport/ecotaxa.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/exampledata.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/instrument/__init__.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/instrument/common.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/instrument/silcam.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/instrument/uvp.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/io.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/metadata.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/plotting.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/process.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/realtime.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/simulator/__init__.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/simulator/silcam.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/tests/__init__.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/tests/test_auxillarydata.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/tests/test_io.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/tests/test_process.py +0 -0
- {pyopia-2.16.14 → pyopia-2.16.16}/pyopia/tests/test_realtime.py +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: PyOPIA
|
|
3
|
-
Version: 2.16.
|
|
3
|
+
Version: 2.16.16
|
|
4
4
|
Summary: A Python Ocean Particle Image Analysis toolbox.
|
|
5
5
|
Project-URL: Repository, https://github.com/sintef/pyopia
|
|
6
6
|
Project-URL: Documentation, https://pyopia.readthedocs.io
|
|
7
7
|
Author-email: Emlyn Davies <emlyn.davies@sintef.no>, Alex Nimmo Smith <alex@nimmosmith.co.uk>
|
|
8
|
+
License-Expression: BSD-3-Clause
|
|
8
9
|
License-File: LICENSE
|
|
9
10
|
Keywords: Imaging,Measurement,Ocean,Particles,Size distribution
|
|
10
11
|
Requires-Python: ~=3.12.0
|
|
@@ -27,6 +28,8 @@ Requires-Dist: pandas[computation]<3,>=2.1.1
|
|
|
27
28
|
Requires-Dist: poetry-version-plugin<0.3,>=0.2.0
|
|
28
29
|
Requires-Dist: pydantic>=2.11.7
|
|
29
30
|
Requires-Dist: pytest-error-for-skips<3,>=2.0.2
|
|
31
|
+
Requires-Dist: pytest-rerunfailures<15,>=14.0
|
|
32
|
+
Requires-Dist: pytest-timeout<3,>=2.3.1
|
|
30
33
|
Requires-Dist: pytest>=7.2.0
|
|
31
34
|
Requires-Dist: readthedocs-sphinx-search<0.4,>=0.3.2
|
|
32
35
|
Requires-Dist: scikit-image<0.25,>=0.24.0
|
|
@@ -55,10 +58,12 @@ PyOPIA
|
|
|
55
58
|
|
|
56
59
|
A Python Ocean Particle Image Analysis toolbox
|
|
57
60
|
|
|
61
|
+
PyOPIA processes images of particles suspended in water (e.g. from SilCam, holographic, or UVP imaging systems) into particle size, shape, and concentration statistics.
|
|
62
|
+
|
|
58
63
|
# Quick tryout of PyOPIA
|
|
59
64
|
|
|
60
65
|
1) Install [uv](https://docs.astral.sh/uv/getting-started/installation)
|
|
61
|
-
2) Initialize PyOPIA project with a small example image dataset and run processing
|
|
66
|
+
2) Initialize a PyOPIA project with example data (`--example-data` downloads a small example image dataset and generates a matching `config.toml`), then run processing:
|
|
62
67
|
```bash
|
|
63
68
|
uvx --python 3.12 --from pyopia[classification] pyopia init-project pyopiatest --example-data
|
|
64
69
|
```
|
|
@@ -76,19 +81,15 @@ uvx --python 3.12 --from pyopia[classification] pyopia merge-mfdata processed
|
|
|
76
81
|
```
|
|
77
82
|
|
|
78
83
|
```bash
|
|
79
|
-
uvx --python 3.12 --from pyopia[classification] pyopia make-montage processed
|
|
80
|
-
```
|
|
81
|
-
5) Visualise the monatge of all processed singular particle images in one
|
|
82
|
-
```bash
|
|
83
|
-
montage.png
|
|
84
|
+
uvx --python 3.12 --from pyopia[classification] pyopia make-montage processed/pyopiatest-STATS.nc
|
|
84
85
|
```
|
|
85
|
-
|
|
86
|
+
5) This creates `montage.png` in the current folder - open it to see a single image made up of all the processed particle images.
|
|
86
87
|
|
|
87
88
|
See the documentation for more information on how to install and use PyOPIA.
|
|
88
89
|
|
|
89
90
|
# Running with Docker
|
|
90
91
|
|
|
91
|
-
A prebuilt container image is published to GitHub Container Registry on every release
|
|
92
|
+
A prebuilt container image is published to GitHub Container Registry on every release. Docker is worth reaching for if you'd rather not install PyOPIA's dependencies directly: it avoids the install overhead of heavier optional dependencies (e.g. TensorFlow/PyTorch for classification), guarantees a consistent, reproducible environment regardless of your host OS, and is well suited to running on servers or HPC systems.
|
|
92
93
|
|
|
93
94
|
## One-off invocation
|
|
94
95
|
|
|
@@ -161,41 +162,57 @@ PYOPIA_CONFIG=my_run.toml docker compose run --rm pyopia
|
|
|
161
162
|
[pyopia.readthedocs.io](https://pyopia.readthedocs.io)
|
|
162
163
|
# Current status:
|
|
163
164
|
|
|
164
|
-
- Under development. See/
|
|
165
|
+
- Under development. See/register issues, [here](https://github.com/SINTEF/pyopia/issues)
|
|
165
166
|
|
|
166
167
|
----
|
|
167
|
-
#
|
|
168
|
+
# Releases
|
|
168
169
|
|
|
169
|
-
|
|
170
|
-
2) Not hardware specific
|
|
171
|
-
3) Smaller dependency list than PySilCam -Eventual optional dependencies (e.g. for classification)
|
|
172
|
-
4) Can be imported by pysilcam or other hardware-specific tools
|
|
173
|
-
5) Work on a single-image basis (...primarily, with options for multiprocess to be considered later)
|
|
174
|
-
6) No use of settings/config files within the core code - pass arguments directly. Eventual use of settings/config files should be handled by high-level wrappers that provide arguments to functions.
|
|
175
|
-
7) Github workflows
|
|
176
|
-
8) Tests
|
|
170
|
+
Releases are cut when a finished, documented, and tested piece of work is ready to be used, rather than on a fixed schedule. If a feature has landed on `main` and meets the Contributions guidelines below, it should go out in the next release rather than sit unreleased. We aim to keep the Docker image (see Running with Docker above) in sync with each release, publishing it as part of the release process rather than as a separate manual step.
|
|
177
171
|
|
|
178
|
-
|
|
172
|
+
----
|
|
173
|
+
# Design principles
|
|
179
174
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
175
|
+
- PyOPIA is instrument-agnostic at its core: SilCam, holographic, and UVP support are all built as pluggable instrument modules on top of a shared `Pipeline`.
|
|
176
|
+
- Processing is config-driven: a `Pipeline` is built from a TOML/dict `settings` object describing an ordered list of steps, each mapping to a Python class. Steps update a shared `data` dict as the pipeline runs.
|
|
177
|
+
- Heavy, optional dependencies (e.g. TensorFlow/PyTorch for classification) are kept out of the core install and available via extras (`pyopia[classification]`, `pyopia[classification-torch]`).
|
|
178
|
+
- Multi-file, multi-core processing is supported via chunked/parallel processing (`pyopia process --num-chunks`).
|
|
184
179
|
|
|
185
180
|
## Contributions
|
|
186
181
|
|
|
187
182
|
We welcome additions and improvements to the code! We request that you follow a few guidelines. These are in place to make sure the code improves over time.
|
|
188
183
|
|
|
189
184
|
1. All code changes must be submitted as pull requests, either from a branch or a fork.
|
|
190
|
-
2. Good documentation of the code is needed for
|
|
185
|
+
2. Good documentation of the code is needed for PyOPIA to succeed and so please include up-to-date docstrings as you make changes, so that the auto-build on readthedocs is complete and useful for users. (A version of the new docs will compile when you make a pull request and a link to this can be found in the pull request checks)
|
|
191
186
|
3. All pull requests are required to pass all tests before merging. Please do not disable or remove tests just to make your branch pass the pull request.
|
|
192
|
-
4. All pull requests must be reviewed by a person. The benefits from code review are plenty, but we like to emphasise that code reviews help spreading the
|
|
187
|
+
4. All pull requests must be reviewed by a person. The benefits from code review are plenty, but we like to emphasise that code reviews help spreading the awareness of code changes. Please note that code reviews should be a pleasant experience, so be pleasant, polite and remember that there is a human being with good intentions on the other side of the screen.
|
|
193
188
|
5. All contributions are linted with flake8. We recommend that you run flake8 on your code while developing to fix any issues as you go. We recommend using autopep8 to autoformat your Python code (but please check the code behaviour is not affected by autoformatting before pushing). This makes flake8 happy, and makes it easier for us all to maintain a consistent and readable code base.
|
|
194
189
|
|
|
190
|
+
### Using AI tools
|
|
191
|
+
|
|
192
|
+
AI coding tools (e.g. Claude, Copilot, ChatGPT) are welcome as an aid to writing PyOPIA contributions. They are tools, not authors: whoever submits a pull request is responsible for the code in it, regardless of how much of it an AI tool helped produce. Please review, understand, and test any AI-assisted changes yourself before submitting them - the same guidelines above (documentation, tests, review, flake8) apply either way.
|
|
193
|
+
|
|
195
194
|
## Docstrings
|
|
196
195
|
|
|
197
196
|
Use the NumPy style in docstrings. See style guide [here](https://numpydoc.readthedocs.io/en/latest/format.html#documenting-classes)
|
|
198
197
|
|
|
198
|
+
## Testing
|
|
199
|
+
|
|
200
|
+
PyOPIA's test suite lives in `pyopia/tests/` and runs via `pytest` (see `uv run pytest` below). A few things are useful to know before running or adding to it:
|
|
201
|
+
|
|
202
|
+
**Markers**: some tests are tagged with pytest markers to indicate how expensive they are.
|
|
203
|
+
|
|
204
|
+
- `@pytest.mark.slow` - tests that do real network downloads and/or real model inference (e.g. downloading the example classifier model and running real predictions on it). These run in routine CI, but you can skip them for a fast local feedback loop:
|
|
205
|
+
```bash
|
|
206
|
+
uv run pytest -m "not slow"
|
|
207
|
+
```
|
|
208
|
+
Unmarked tests are fast and have no external dependencies; they always run.
|
|
209
|
+
|
|
210
|
+
**Shared fixtures**: tests that need real example data (an example image, the trained classifier model, the classifier training database, an example hologram) get it from session-scoped fixtures defined in `pyopia/tests/conftest.py`, rather than each downloading their own copy. The download happens once per test run and is shared across every test file that needs it.
|
|
211
|
+
|
|
212
|
+
**Notebooks**: `pyopia/tests/test_notebooks.py` executes the notebooks in `notebooks/` and `docs/notebooks/` to check they still run against the current codebase. Each notebook is its own parametrized test (`test_notebook[<name>.ipynb]`), tagged `slow` as above where relevant. Not every notebook is included - a couple depend on state produced by another notebook, or by a user's own prior processing run, and would fail if executed standalone; see the comments in `test_notebooks.py` for which ones and why. These tests also get a longer timeout (1800s) and up to 2 automatic retries on failure, since running a Jupyter kernel via nbconvert has shown real, platform-specific flakiness on macOS CI runners rather than a reproducible bug.
|
|
213
|
+
|
|
214
|
+
Please do not disable or remove tests just to make a pull request pass - see Contributions guideline 3 above.
|
|
215
|
+
|
|
199
216
|
# Installing
|
|
200
217
|
|
|
201
218
|
## For users
|
|
@@ -205,7 +222,7 @@ Users are expected to be familiar with Python. Please refer to the recommended i
|
|
|
205
222
|
## For developers from source
|
|
206
223
|
|
|
207
224
|
|
|
208
|
-
Install (
|
|
225
|
+
Install [uv](https://docs.astral.sh/uv/getting-started/installation/)
|
|
209
226
|
|
|
210
227
|
1. Navigate to the folder where you want to install pyopia using the 'cd' command.
|
|
211
228
|
|
|
@@ -222,10 +239,10 @@ For the next steps, you need to be located in the PyOPIA root directory that con
|
|
|
222
239
|
2. Install all requirements with
|
|
223
240
|
|
|
224
241
|
```bash
|
|
225
|
-
uv sync --all-extras
|
|
242
|
+
uv sync --all-extras --dev
|
|
226
243
|
```
|
|
227
244
|
|
|
228
|
-
3. (optional) Run local tests:
|
|
245
|
+
3. (optional) Run local tests (see the Testing section above for markers and how to run a fast subset):
|
|
229
246
|
|
|
230
247
|
```bash
|
|
231
248
|
uv run pytest
|
|
@@ -241,13 +258,12 @@ The version number of PyOPIA is split into three sections: MAJOR.MINOR.PATCH
|
|
|
241
258
|
|
|
242
259
|
## Build docs locally
|
|
243
260
|
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
sphinx-build -b html ./docs/ ./docs/build
|
|
261
|
+
```bash
|
|
262
|
+
uv sync --extra classification --group docs
|
|
263
|
+
uv run sphinx-build -b html docs/ docs/_build/html
|
|
248
264
|
```
|
|
249
265
|
|
|
250
266
|
----
|
|
251
267
|
# License
|
|
252
268
|
|
|
253
|
-
|
|
269
|
+
PyOPIA is licensed under the BSD3 license. See LICENSE. All contributors should be recognised & acknowledged.
|
|
@@ -3,10 +3,12 @@ PyOPIA
|
|
|
3
3
|
|
|
4
4
|
A Python Ocean Particle Image Analysis toolbox
|
|
5
5
|
|
|
6
|
+
PyOPIA processes images of particles suspended in water (e.g. from SilCam, holographic, or UVP imaging systems) into particle size, shape, and concentration statistics.
|
|
7
|
+
|
|
6
8
|
# Quick tryout of PyOPIA
|
|
7
9
|
|
|
8
10
|
1) Install [uv](https://docs.astral.sh/uv/getting-started/installation)
|
|
9
|
-
2) Initialize PyOPIA project with a small example image dataset and run processing
|
|
11
|
+
2) Initialize a PyOPIA project with example data (`--example-data` downloads a small example image dataset and generates a matching `config.toml`), then run processing:
|
|
10
12
|
```bash
|
|
11
13
|
uvx --python 3.12 --from pyopia[classification] pyopia init-project pyopiatest --example-data
|
|
12
14
|
```
|
|
@@ -24,19 +26,15 @@ uvx --python 3.12 --from pyopia[classification] pyopia merge-mfdata processed
|
|
|
24
26
|
```
|
|
25
27
|
|
|
26
28
|
```bash
|
|
27
|
-
uvx --python 3.12 --from pyopia[classification] pyopia make-montage processed
|
|
28
|
-
```
|
|
29
|
-
5) Visualise the monatge of all processed singular particle images in one
|
|
30
|
-
```bash
|
|
31
|
-
montage.png
|
|
29
|
+
uvx --python 3.12 --from pyopia[classification] pyopia make-montage processed/pyopiatest-STATS.nc
|
|
32
30
|
```
|
|
33
|
-
|
|
31
|
+
5) This creates `montage.png` in the current folder - open it to see a single image made up of all the processed particle images.
|
|
34
32
|
|
|
35
33
|
See the documentation for more information on how to install and use PyOPIA.
|
|
36
34
|
|
|
37
35
|
# Running with Docker
|
|
38
36
|
|
|
39
|
-
A prebuilt container image is published to GitHub Container Registry on every release
|
|
37
|
+
A prebuilt container image is published to GitHub Container Registry on every release. Docker is worth reaching for if you'd rather not install PyOPIA's dependencies directly: it avoids the install overhead of heavier optional dependencies (e.g. TensorFlow/PyTorch for classification), guarantees a consistent, reproducible environment regardless of your host OS, and is well suited to running on servers or HPC systems.
|
|
40
38
|
|
|
41
39
|
## One-off invocation
|
|
42
40
|
|
|
@@ -109,41 +107,57 @@ PYOPIA_CONFIG=my_run.toml docker compose run --rm pyopia
|
|
|
109
107
|
[pyopia.readthedocs.io](https://pyopia.readthedocs.io)
|
|
110
108
|
# Current status:
|
|
111
109
|
|
|
112
|
-
- Under development. See/
|
|
110
|
+
- Under development. See/register issues, [here](https://github.com/SINTEF/pyopia/issues)
|
|
113
111
|
|
|
114
112
|
----
|
|
115
|
-
#
|
|
113
|
+
# Releases
|
|
116
114
|
|
|
117
|
-
|
|
118
|
-
2) Not hardware specific
|
|
119
|
-
3) Smaller dependency list than PySilCam -Eventual optional dependencies (e.g. for classification)
|
|
120
|
-
4) Can be imported by pysilcam or other hardware-specific tools
|
|
121
|
-
5) Work on a single-image basis (...primarily, with options for multiprocess to be considered later)
|
|
122
|
-
6) No use of settings/config files within the core code - pass arguments directly. Eventual use of settings/config files should be handled by high-level wrappers that provide arguments to functions.
|
|
123
|
-
7) Github workflows
|
|
124
|
-
8) Tests
|
|
115
|
+
Releases are cut when a finished, documented, and tested piece of work is ready to be used, rather than on a fixed schedule. If a feature has landed on `main` and meets the Contributions guidelines below, it should go out in the next release rather than sit unreleased. We aim to keep the Docker image (see Running with Docker above) in sync with each release, publishing it as part of the release process rather than as a separate manual step.
|
|
125
116
|
|
|
126
|
-
|
|
117
|
+
----
|
|
118
|
+
# Design principles
|
|
127
119
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
120
|
+
- PyOPIA is instrument-agnostic at its core: SilCam, holographic, and UVP support are all built as pluggable instrument modules on top of a shared `Pipeline`.
|
|
121
|
+
- Processing is config-driven: a `Pipeline` is built from a TOML/dict `settings` object describing an ordered list of steps, each mapping to a Python class. Steps update a shared `data` dict as the pipeline runs.
|
|
122
|
+
- Heavy, optional dependencies (e.g. TensorFlow/PyTorch for classification) are kept out of the core install and available via extras (`pyopia[classification]`, `pyopia[classification-torch]`).
|
|
123
|
+
- Multi-file, multi-core processing is supported via chunked/parallel processing (`pyopia process --num-chunks`).
|
|
132
124
|
|
|
133
125
|
## Contributions
|
|
134
126
|
|
|
135
127
|
We welcome additions and improvements to the code! We request that you follow a few guidelines. These are in place to make sure the code improves over time.
|
|
136
128
|
|
|
137
129
|
1. All code changes must be submitted as pull requests, either from a branch or a fork.
|
|
138
|
-
2. Good documentation of the code is needed for
|
|
130
|
+
2. Good documentation of the code is needed for PyOPIA to succeed and so please include up-to-date docstrings as you make changes, so that the auto-build on readthedocs is complete and useful for users. (A version of the new docs will compile when you make a pull request and a link to this can be found in the pull request checks)
|
|
139
131
|
3. All pull requests are required to pass all tests before merging. Please do not disable or remove tests just to make your branch pass the pull request.
|
|
140
|
-
4. All pull requests must be reviewed by a person. The benefits from code review are plenty, but we like to emphasise that code reviews help spreading the
|
|
132
|
+
4. All pull requests must be reviewed by a person. The benefits from code review are plenty, but we like to emphasise that code reviews help spreading the awareness of code changes. Please note that code reviews should be a pleasant experience, so be pleasant, polite and remember that there is a human being with good intentions on the other side of the screen.
|
|
141
133
|
5. All contributions are linted with flake8. We recommend that you run flake8 on your code while developing to fix any issues as you go. We recommend using autopep8 to autoformat your Python code (but please check the code behaviour is not affected by autoformatting before pushing). This makes flake8 happy, and makes it easier for us all to maintain a consistent and readable code base.
|
|
142
134
|
|
|
135
|
+
### Using AI tools
|
|
136
|
+
|
|
137
|
+
AI coding tools (e.g. Claude, Copilot, ChatGPT) are welcome as an aid to writing PyOPIA contributions. They are tools, not authors: whoever submits a pull request is responsible for the code in it, regardless of how much of it an AI tool helped produce. Please review, understand, and test any AI-assisted changes yourself before submitting them - the same guidelines above (documentation, tests, review, flake8) apply either way.
|
|
138
|
+
|
|
143
139
|
## Docstrings
|
|
144
140
|
|
|
145
141
|
Use the NumPy style in docstrings. See style guide [here](https://numpydoc.readthedocs.io/en/latest/format.html#documenting-classes)
|
|
146
142
|
|
|
143
|
+
## Testing
|
|
144
|
+
|
|
145
|
+
PyOPIA's test suite lives in `pyopia/tests/` and runs via `pytest` (see `uv run pytest` below). A few things are useful to know before running or adding to it:
|
|
146
|
+
|
|
147
|
+
**Markers**: some tests are tagged with pytest markers to indicate how expensive they are.
|
|
148
|
+
|
|
149
|
+
- `@pytest.mark.slow` - tests that do real network downloads and/or real model inference (e.g. downloading the example classifier model and running real predictions on it). These run in routine CI, but you can skip them for a fast local feedback loop:
|
|
150
|
+
```bash
|
|
151
|
+
uv run pytest -m "not slow"
|
|
152
|
+
```
|
|
153
|
+
Unmarked tests are fast and have no external dependencies; they always run.
|
|
154
|
+
|
|
155
|
+
**Shared fixtures**: tests that need real example data (an example image, the trained classifier model, the classifier training database, an example hologram) get it from session-scoped fixtures defined in `pyopia/tests/conftest.py`, rather than each downloading their own copy. The download happens once per test run and is shared across every test file that needs it.
|
|
156
|
+
|
|
157
|
+
**Notebooks**: `pyopia/tests/test_notebooks.py` executes the notebooks in `notebooks/` and `docs/notebooks/` to check they still run against the current codebase. Each notebook is its own parametrized test (`test_notebook[<name>.ipynb]`), tagged `slow` as above where relevant. Not every notebook is included - a couple depend on state produced by another notebook, or by a user's own prior processing run, and would fail if executed standalone; see the comments in `test_notebooks.py` for which ones and why. These tests also get a longer timeout (1800s) and up to 2 automatic retries on failure, since running a Jupyter kernel via nbconvert has shown real, platform-specific flakiness on macOS CI runners rather than a reproducible bug.
|
|
158
|
+
|
|
159
|
+
Please do not disable or remove tests just to make a pull request pass - see Contributions guideline 3 above.
|
|
160
|
+
|
|
147
161
|
# Installing
|
|
148
162
|
|
|
149
163
|
## For users
|
|
@@ -153,7 +167,7 @@ Users are expected to be familiar with Python. Please refer to the recommended i
|
|
|
153
167
|
## For developers from source
|
|
154
168
|
|
|
155
169
|
|
|
156
|
-
Install (
|
|
170
|
+
Install [uv](https://docs.astral.sh/uv/getting-started/installation/)
|
|
157
171
|
|
|
158
172
|
1. Navigate to the folder where you want to install pyopia using the 'cd' command.
|
|
159
173
|
|
|
@@ -170,10 +184,10 @@ For the next steps, you need to be located in the PyOPIA root directory that con
|
|
|
170
184
|
2. Install all requirements with
|
|
171
185
|
|
|
172
186
|
```bash
|
|
173
|
-
uv sync --all-extras
|
|
187
|
+
uv sync --all-extras --dev
|
|
174
188
|
```
|
|
175
189
|
|
|
176
|
-
3. (optional) Run local tests:
|
|
190
|
+
3. (optional) Run local tests (see the Testing section above for markers and how to run a fast subset):
|
|
177
191
|
|
|
178
192
|
```bash
|
|
179
193
|
uv run pytest
|
|
@@ -189,13 +203,12 @@ The version number of PyOPIA is split into three sections: MAJOR.MINOR.PATCH
|
|
|
189
203
|
|
|
190
204
|
## Build docs locally
|
|
191
205
|
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
sphinx-build -b html ./docs/ ./docs/build
|
|
206
|
+
```bash
|
|
207
|
+
uv sync --extra classification --group docs
|
|
208
|
+
uv run sphinx-build -b html docs/ docs/_build/html
|
|
196
209
|
```
|
|
197
210
|
|
|
198
211
|
----
|
|
199
212
|
# License
|
|
200
213
|
|
|
201
|
-
|
|
214
|
+
PyOPIA is licensed under the BSD3 license. See LICENSE. All contributors should be recognised & acknowledged.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.16.16"
|
|
@@ -4,6 +4,11 @@ import xarray as xr
|
|
|
4
4
|
|
|
5
5
|
logger = logging.getLogger()
|
|
6
6
|
|
|
7
|
+
|
|
8
|
+
class AuxillaryDataError(Exception):
|
|
9
|
+
"""Raised when an auxiliary data file exists but cannot be parsed into the expected format."""
|
|
10
|
+
|
|
11
|
+
|
|
7
12
|
AUXILLARY_DATA_FILE_TEMPLATE = """% COMMENT LINE: PLEASE UPDATE THIS FILE WITH PROJECT RELEVANT DATA. EACH COLUMN WILL BECOME A NETCDF VARIABLE.
|
|
8
13
|
% COMMENT LINE: ONE LINE PER MEASUREMENT, TIME IS INTERPOLATED TO IMAGE DATA TIMES IN PYOPIA. FOLLOWING LINES ARE UNITS, DESCRIPTION AND VARIABLE NAME.
|
|
9
14
|
,metres,degC
|
|
@@ -50,17 +55,19 @@ class AuxillaryData:
|
|
|
50
55
|
def __init__(self, auxillary_data_path=None):
|
|
51
56
|
self.auxillary_data_path = auxillary_data_path
|
|
52
57
|
|
|
53
|
-
# Create empty dataframe for cases where no file was specified
|
|
58
|
+
# Create empty dataframe for cases where no file was specified
|
|
54
59
|
self.auxillary_data = pd.DataFrame(index=pd.Index([], name="time")).to_xarray()
|
|
55
60
|
if auxillary_data_path is not None:
|
|
56
61
|
try:
|
|
57
62
|
self.auxillary_data = self.load_auxillary_data(auxillary_data_path)
|
|
58
|
-
except
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
except Exception as e:
|
|
64
|
+
# Re-raise as a single, specific error type that names the file and the
|
|
65
|
+
# underlying cause, so callers can recognise this failure mode (the same
|
|
66
|
+
# auxiliary data file applies to every image, so it is not worth retrying)
|
|
67
|
+
# and report something more useful than a bare KeyError/ValueError.
|
|
68
|
+
raise AuxillaryDataError(
|
|
69
|
+
f"Failed to load auxiliary data from '{auxillary_data_path}': {e}"
|
|
70
|
+
) from e
|
|
64
71
|
|
|
65
72
|
def load_auxillary_data(self, auxillary_data_path):
|
|
66
73
|
"""Load and format uxillary data from .csv file"""
|