PyOPIA 2.16.9__tar.gz → 2.16.11__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.
Files changed (38) hide show
  1. {pyopia-2.16.9 → pyopia-2.16.11}/PKG-INFO +1 -1
  2. pyopia-2.16.11/pyopia/__init__.py +1 -0
  3. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/cli.py +16 -0
  4. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/process.py +1 -1
  5. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/tests/test_pipeline.py +48 -0
  6. pyopia-2.16.9/pyopia/__init__.py +0 -1
  7. {pyopia-2.16.9 → pyopia-2.16.11}/.gitignore +0 -0
  8. {pyopia-2.16.9 → pyopia-2.16.11}/LICENSE +0 -0
  9. {pyopia-2.16.9 → pyopia-2.16.11}/README.md +0 -0
  10. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/auxillarydata.py +0 -0
  11. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/background.py +0 -0
  12. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/cf_metadata.json +0 -0
  13. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/classify.py +0 -0
  14. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/classify_torch.py +0 -0
  15. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/dataexport/__init__.py +0 -0
  16. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/dataexport/ecotaxa.py +0 -0
  17. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/exampledata.py +0 -0
  18. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/instrument/__init__.py +0 -0
  19. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/instrument/common.py +0 -0
  20. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/instrument/holo.py +0 -0
  21. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/instrument/silcam.py +0 -0
  22. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/instrument/uvp.py +0 -0
  23. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/io.py +0 -0
  24. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/metadata.py +0 -0
  25. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/pipeline.py +0 -0
  26. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/plotting.py +0 -0
  27. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/realtime.py +0 -0
  28. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/simulator/__init__.py +0 -0
  29. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/simulator/silcam.py +0 -0
  30. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/statistics.py +0 -0
  31. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/tests/__init__.py +0 -0
  32. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/tests/test_auxillarydata.py +0 -0
  33. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/tests/test_classify.py +0 -0
  34. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/tests/test_io.py +0 -0
  35. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/tests/test_notebooks.py +0 -0
  36. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/tests/test_process.py +0 -0
  37. {pyopia-2.16.9 → pyopia-2.16.11}/pyopia/tests/test_realtime.py +0 -0
  38. {pyopia-2.16.9 → pyopia-2.16.11}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyOPIA
3
- Version: 2.16.9
3
+ Version: 2.16.11
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
@@ -0,0 +1 @@
1
+ __version__ = "2.16.11"
@@ -54,6 +54,22 @@ def docs():
54
54
  typer.launch("https://pyopia.readthedocs.io")
55
55
 
56
56
 
57
+ def version_callback(value: bool):
58
+ if value:
59
+ print(f"PyOPIA version: {pyopia.__version__}")
60
+ raise typer.Exit()
61
+
62
+
63
+ @app.callback()
64
+ def main(
65
+ version: Annotated[
66
+ bool,
67
+ typer.Option("--version", callback=version_callback, is_eager=True, help="Show version and exit.")
68
+ ] = False
69
+ ):
70
+ pass
71
+
72
+
57
73
  @app.command()
58
74
  def modify_config(
59
75
  existing_filename: str,
@@ -734,7 +734,7 @@ class CalculateImageStats():
734
734
  d50 = pyopia.statistics.d50_from_stats(data['stats'], pixel_size)
735
735
  data['image_stats'].loc[data['timestamp'], 'd50'] = d50
736
736
 
737
- path_length = getattr(data['settings']['general'], 'path_length', 40)
737
+ path_length = data['settings']['general'].get('path_length', 40)
738
738
  if path_length is not None:
739
739
  # Get image dimensions from the corrected image
740
740
  image = data.get('imraw')
@@ -189,6 +189,54 @@ def test_silcam_pipeline():
189
189
  ' Something has altered the number of particles detected')
190
190
 
191
191
 
192
+ def test_calculate_image_stats_uses_configured_path_length():
193
+ '''Verifies CalculateImageStats uses the path_length configured in general settings,
194
+ rather than silently falling back to the default of 40mm.
195
+
196
+ Regression test: data['settings']['general'] is a plain dict, so a previous
197
+ implementation using getattr(general, 'path_length', 40) always returned the
198
+ default, silently ignoring any configured path_length.
199
+ '''
200
+ import pandas as pd
201
+ from pyopia.statistics import nc_vc_from_stats
202
+
203
+ pixel_size = 28.0
204
+ path_length = 123.0 # deliberately not the default of 40, to catch silent fallback
205
+ imy, imx = 100, 200
206
+
207
+ timestamp = pd.Timestamp('2026-01-01T00:00:00')
208
+ stats = pd.DataFrame({
209
+ 'major_axis_length': [10.0],
210
+ 'minor_axis_length': [8.0],
211
+ 'equivalent_diameter': [9.0],
212
+ 'saturation': [1.0],
213
+ 'export_name': ['D20260101T000000.000000-PN0'],
214
+ 'timestamp': [timestamp],
215
+ })
216
+
217
+ data = {
218
+ 'settings': {'general': {'pixel_size': pixel_size, 'path_length': path_length}},
219
+ 'imraw': np.zeros((imy, imx, 3), dtype=np.uint8),
220
+ 'stats': stats,
221
+ 'timestamp': timestamp,
222
+ }
223
+
224
+ step = pyopia.process.CalculateImageStats()
225
+ data = step(data)
226
+
227
+ expected_nc, expected_vc, expected_sample_volume, expected_junge = nc_vc_from_stats(
228
+ stats, pixel_size, path_length, imx=imx, imy=imy)
229
+
230
+ result = data['image_stats'].loc[data['timestamp']]
231
+ np.testing.assert_allclose(result['vc'], expected_vc)
232
+ np.testing.assert_allclose(result['sample_volume'], expected_sample_volume)
233
+
234
+ # Sanity check that this isn't coincidentally matching the old (broken) default of 40mm
235
+ wrong_nc, wrong_vc, wrong_sample_volume, wrong_junge = nc_vc_from_stats(
236
+ stats, pixel_size, 40, imx=imx, imy=imy)
237
+ assert not np.isclose(result['vc'], wrong_vc)
238
+
239
+
192
240
  def test_per_class_concentration():
193
241
  '''Verifies PerClassConcentration writes timestamp-indexed per-class
194
242
  number concentrations (numbers/L) to CSV across multiple images.
@@ -1 +0,0 @@
1
- __version__ = "2.16.9"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes