xarray-dbd 0.2.2__tar.gz → 0.2.3__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 (61) hide show
  1. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/PKG-INFO +6 -8
  2. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/README.md +5 -7
  3. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/pyproject.toml +2 -2
  4. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/tests/test_dbdreader2.py +50 -3
  5. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/dbdreader2/__init__.py +2 -0
  6. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/dbdreader2/_core.py +74 -5
  7. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/dbdreader2/_errors.py +3 -0
  8. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/.clang-tidy +0 -0
  9. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/.gitignore +0 -0
  10. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/.pre-commit-config.yaml +0 -0
  11. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/CHANGELOG.md +0 -0
  12. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/CMakeLists.txt +0 -0
  13. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/CONTRIBUTING.md +0 -0
  14. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/License.txt +0 -0
  15. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/benchmark_performance.py +0 -0
  16. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/conda/recipe.yaml +0 -0
  17. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/ColumnData.C +0 -0
  18. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/ColumnData.H +0 -0
  19. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/Data.C +0 -0
  20. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/Data.H +0 -0
  21. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/Decompress.C +0 -0
  22. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/Decompress.H +0 -0
  23. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/FileInfo.H +0 -0
  24. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/Header.C +0 -0
  25. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/Header.H +0 -0
  26. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/KnownBytes.C +0 -0
  27. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/KnownBytes.H +0 -0
  28. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/Logger.H +0 -0
  29. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/MyException.H +0 -0
  30. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/Sensor.C +0 -0
  31. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/Sensor.H +0 -0
  32. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/Sensors.C +0 -0
  33. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/Sensors.H +0 -0
  34. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/SensorsMap.C +0 -0
  35. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/SensorsMap.H +0 -0
  36. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/config.h +0 -0
  37. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/dbd_python.cpp +0 -0
  38. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/lz4.c +0 -0
  39. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/csrc/lz4.h +0 -0
  40. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/examples/README.md +0 -0
  41. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/scripts/README.md +0 -0
  42. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/tests/conftest.py +0 -0
  43. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/tests/test_backend.py +0 -0
  44. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/tests/test_cli.py +0 -0
  45. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/tests/test_cpp_backend.py +0 -0
  46. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/__init__.py +0 -0
  47. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/_dbd_cpp.pyi +0 -0
  48. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/backend.py +0 -0
  49. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/cli/__init__.py +0 -0
  50. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/cli/cache.py +0 -0
  51. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/cli/csv.py +0 -0
  52. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/cli/dbd2nc.py +0 -0
  53. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/cli/logger.py +0 -0
  54. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/cli/main.py +0 -0
  55. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/cli/missions.py +0 -0
  56. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/cli/mkone.py +0 -0
  57. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/cli/sensors.py +0 -0
  58. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/dbdreader2/_cache.py +0 -0
  59. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/dbdreader2/_list.py +0 -0
  60. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/dbdreader2/_util.py +0 -0
  61. {xarray_dbd-0.2.2 → xarray_dbd-0.2.3}/xarray_dbd/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xarray-dbd
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Efficient xarray backend for reading glider DBD files
5
5
  Keywords: glider,oceanography,dbd,slocum,xarray,netcdf
6
6
  Author-Email: Pat Welch <pat@mousebrains.com>
@@ -209,9 +209,10 @@ Open multiple DBD files as a single concatenated xarray Dataset.
209
209
 
210
210
  ## Migration from dbdreader
211
211
 
212
- xarray-dbd provides drop-in `DBD` and `MultiDBD` classes that mirror the
213
- [dbdreader](https://pypi.org/project/dbdreader/) API. For a fully
214
- transparent swap, alias the import:
212
+ The dbdreader2 API is derived from Lucas Merckelbach's
213
+ [dbdreader](https://github.com/smerckel/dbdreader) library. xarray-dbd
214
+ provides drop-in `DBD` and `MultiDBD` classes that mirror the dbdreader API.
215
+ For a fully transparent swap, alias the import:
215
216
 
216
217
  ```python
217
218
  # Before (dbdreader)
@@ -249,7 +250,7 @@ dbd = xdbd.DBD("file.dcd", cacheDir="cache")
249
250
  | `get_xy()`, `get_CTD_sync()` | Yes | Yes |
250
251
  | `decimalLatLon` | Yes | Yes |
251
252
  | `set_time_limits()` | Yes | Yes |
252
- | `include_source` | No | Yes |
253
+ | `include_source` | Yes | Yes |
253
254
 
254
255
  ### Use-case examples
255
256
 
@@ -366,9 +367,6 @@ mdbd = dbdreader.MultiDBD(
366
367
  individual records within a file. dbdreader also filters by file open
367
368
  time, so this is operationally the same for most use cases.
368
369
 
369
- - **`include_source` not supported.** Passing `include_source=True` to
370
- `get()` raises `NotImplementedError`.
371
-
372
370
  - **Error handling.** The same `DbdError` exception class and numeric
373
371
  error codes (`DBD_ERROR_CACHE_NOT_FOUND`, etc.) are provided for
374
372
  compatibility.
@@ -173,9 +173,10 @@ Open multiple DBD files as a single concatenated xarray Dataset.
173
173
 
174
174
  ## Migration from dbdreader
175
175
 
176
- xarray-dbd provides drop-in `DBD` and `MultiDBD` classes that mirror the
177
- [dbdreader](https://pypi.org/project/dbdreader/) API. For a fully
178
- transparent swap, alias the import:
176
+ The dbdreader2 API is derived from Lucas Merckelbach's
177
+ [dbdreader](https://github.com/smerckel/dbdreader) library. xarray-dbd
178
+ provides drop-in `DBD` and `MultiDBD` classes that mirror the dbdreader API.
179
+ For a fully transparent swap, alias the import:
179
180
 
180
181
  ```python
181
182
  # Before (dbdreader)
@@ -213,7 +214,7 @@ dbd = xdbd.DBD("file.dcd", cacheDir="cache")
213
214
  | `get_xy()`, `get_CTD_sync()` | Yes | Yes |
214
215
  | `decimalLatLon` | Yes | Yes |
215
216
  | `set_time_limits()` | Yes | Yes |
216
- | `include_source` | No | Yes |
217
+ | `include_source` | Yes | Yes |
217
218
 
218
219
  ### Use-case examples
219
220
 
@@ -330,9 +331,6 @@ mdbd = dbdreader.MultiDBD(
330
331
  individual records within a file. dbdreader also filters by file open
331
332
  time, so this is operationally the same for most use cases.
332
333
 
333
- - **`include_source` not supported.** Passing `include_source=True` to
334
- `get()` raises `NotImplementedError`.
335
-
336
334
  - **Error handling.** The same `DbdError` exception class and numeric
337
335
  error codes (`DBD_ERROR_CACHE_NOT_FOUND`, etc.) are provided for
338
336
  compatibility.
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "xarray-dbd"
7
- version = "0.2.2"
7
+ version = "0.2.3"
8
8
  description = "Efficient xarray backend for reading glider DBD files"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -132,7 +132,7 @@ testpaths = ["tests"]
132
132
  python_files = "test_*.py"
133
133
 
134
134
  [tool.cibuildwheel]
135
- build = ["cp310-*", "cp311-*", "cp312-*", "cp313-*"]
135
+ build = ["cp310-*", "cp311-*", "cp312-*", "cp313-*", "cp314-*"]
136
136
  skip = ["*-musllinux_i686", "*-win32", "pp*"]
137
137
  test-skip = ["*-manylinux_*", "*-musllinux_*"]
138
138
  test-command = "python -c \"import xarray_dbd; print(xarray_dbd.__version__)\""
@@ -433,10 +433,57 @@ class TestMultiDBD:
433
433
  assert MultiDBD.isScienceDataFile("test.dcd") is False
434
434
  assert MultiDBD.isScienceDataFile("test.sbd") is False
435
435
 
436
- def test_include_source_not_implemented(self):
436
+ def test_include_source_single_param(self):
437
437
  mdbd = MultiDBD(filenames=_all_files(), cacheDir=CACHE_DIR)
438
- with pytest.raises(NotImplementedError):
439
- mdbd.get("m_depth", include_source=True)
438
+ result = mdbd.get("m_depth", include_source=True)
439
+ (t, v), sources = result
440
+ assert len(sources) == len(t)
441
+ assert len(sources) == len(v)
442
+ assert len(t) > 0
443
+ for src in sources:
444
+ assert hasattr(src, "filename")
445
+ assert isinstance(src, DBD)
446
+ mdbd.close()
447
+
448
+ def test_include_source_multi_param(self):
449
+ mdbd = MultiDBD(filenames=_all_files(), cacheDir=CACHE_DIR)
450
+ results = mdbd.get("m_depth", "m_heading", include_source=True)
451
+ assert isinstance(results, list)
452
+ assert len(results) == 2
453
+ for (t, v), sources in results:
454
+ assert len(sources) == len(t)
455
+ assert len(sources) == len(v)
456
+ mdbd.close()
457
+
458
+ def test_include_source_sources_match_files(self):
459
+ files = _all_files()
460
+ mdbd = MultiDBD(filenames=files, cacheDir=CACHE_DIR)
461
+ (t, v), sources = mdbd.get("m_depth", include_source=True)
462
+ source_filenames = {src.filename for src in sources}
463
+ # Every source file must be one of the input files
464
+ assert source_filenames <= set(files)
465
+ mdbd.close()
466
+
467
+ def test_include_source_max_values(self):
468
+ mdbd = MultiDBD(filenames=_all_files(), cacheDir=CACHE_DIR)
469
+ n = 5
470
+ (t, v), sources = mdbd.get("m_depth", include_source=True, max_values_to_read=n)
471
+ assert len(t) == n
472
+ assert len(v) == n
473
+ assert len(sources) == n
474
+ mdbd.close()
475
+
476
+ def test_continue_on_reading_error_accepted(self):
477
+ mdbd = MultiDBD(filenames=_all_files(), cacheDir=CACHE_DIR)
478
+ t, v = mdbd.get("m_depth", continue_on_reading_error=True)
479
+ assert len(t) > 0
480
+ mdbd.close()
481
+
482
+ def test_continue_on_reading_error_with_include_source(self):
483
+ mdbd = MultiDBD(filenames=_all_files(), cacheDir=CACHE_DIR)
484
+ (t, v), sources = mdbd.get("m_depth", include_source=True, continue_on_reading_error=True)
485
+ assert len(t) > 0
486
+ assert len(sources) == len(t)
440
487
  mdbd.close()
441
488
 
442
489
  def test_close_guards(self):
@@ -26,6 +26,7 @@ from ._errors import (
26
26
  DBD_ERROR_NO_FILES_FOUND,
27
27
  DBD_ERROR_NO_TIME_VARIABLE,
28
28
  DBD_ERROR_NO_VALID_PARAMETERS,
29
+ DBD_ERROR_READ_ERROR,
29
30
  DbdError,
30
31
  )
31
32
  from ._list import DBDList, DBDPatternSelect
@@ -60,6 +61,7 @@ __all__ = [
60
61
  "DBD_ERROR_NO_FILES_FOUND",
61
62
  "DBD_ERROR_NO_TIME_VARIABLE",
62
63
  "DBD_ERROR_NO_VALID_PARAMETERS",
64
+ "DBD_ERROR_READ_ERROR",
63
65
  "DbdError",
64
66
  "LATLON_PARAMS",
65
67
  "MultiDBD",
@@ -496,21 +496,17 @@ class MultiDBD:
496
496
  return_nans=False,
497
497
  include_source=False,
498
498
  max_values_to_read=-1,
499
+ continue_on_reading_error=False,
499
500
  ):
500
501
  """Return ``(t, v)`` per parameter."""
501
502
  self._check_closed()
502
503
 
503
- if include_source:
504
- raise NotImplementedError("include_source is not yet supported in dbdreader2")
505
-
506
504
  if max_values_to_read > 0 and len(parameters) != 1:
507
505
  raise ValueError(
508
506
  "Limiting the values to be read for multiple parameters "
509
507
  "potentially yields undefined behaviour.\n"
510
508
  )
511
509
 
512
- self._ensure_loaded(parameters)
513
-
514
510
  # Validate parameters
515
511
  all_known = set(self.parameterNames.get("eng", [])) | set(
516
512
  self.parameterNames.get("sci", [])
@@ -523,6 +519,18 @@ class MultiDBD:
523
519
  mesg = f"Parameters {{{','.join(invalid)}}} are unknown glider sensor names."
524
520
  raise DbdError(value=DBD_ERROR_NO_VALID_PARAMETERS, mesg=mesg, data=invalid)
525
521
 
522
+ if include_source:
523
+ return self._get_with_source(
524
+ parameters,
525
+ return_nans=return_nans,
526
+ decimalLatLon=decimalLatLon,
527
+ discardBadLatLon=discardBadLatLon,
528
+ max_values_to_read=max_values_to_read,
529
+ continue_on_reading_error=continue_on_reading_error,
530
+ )
531
+
532
+ self._ensure_loaded(parameters)
533
+
526
534
  results = []
527
535
  for p in parameters:
528
536
  t, v = self._extract(p, return_nans, decimalLatLon, discardBadLatLon)
@@ -849,6 +857,67 @@ class MultiDBD:
849
857
 
850
858
  return t, v
851
859
 
860
+ def _get_with_source(
861
+ self,
862
+ parameters,
863
+ *,
864
+ return_nans,
865
+ decimalLatLon, # noqa: N803
866
+ discardBadLatLon, # noqa: N803
867
+ max_values_to_read,
868
+ continue_on_reading_error=False,
869
+ ):
870
+ """Implement ``get(..., include_source=True)`` by iterating per-file DBD objects."""
871
+ eng_names_set = set(self._eng_param_names)
872
+
873
+ results = []
874
+ for p in parameters:
875
+ dbds = self.dbds["sci"] if p not in eng_names_set else self.dbds["eng"]
876
+ t_chunks: list[numpy.ndarray] = []
877
+ v_chunks: list[numpy.ndarray] = []
878
+ src_chunks: list[list[DBD]] = []
879
+ for dbd in dbds:
880
+ if not dbd.has_parameter(p):
881
+ continue
882
+ try:
883
+ tv = dbd.get(
884
+ p,
885
+ decimalLatLon=decimalLatLon,
886
+ discardBadLatLon=discardBadLatLon,
887
+ return_nans=return_nans,
888
+ check_for_invalid_parameters=False,
889
+ )
890
+ except (RuntimeError, OSError) as e:
891
+ if continue_on_reading_error:
892
+ logger.warning("Reading from %s returned an error (%s).", dbd.filename, e)
893
+ continue
894
+ raise
895
+ t, v = tv
896
+ if len(t) == 0:
897
+ continue
898
+ t_chunks.append(t)
899
+ v_chunks.append(v)
900
+ src_chunks.append([dbd] * len(t))
901
+ if t_chunks:
902
+ t_cat = numpy.hstack(t_chunks)
903
+ v_cat = numpy.hstack(v_chunks)
904
+ sources: list[DBD] = []
905
+ for chunk in src_chunks:
906
+ sources.extend(chunk)
907
+ else:
908
+ t_cat = numpy.array([], dtype=numpy.float64)
909
+ v_cat = numpy.array([], dtype=numpy.float64)
910
+ sources = []
911
+ if max_values_to_read > 0:
912
+ t_cat = t_cat[:max_values_to_read]
913
+ v_cat = v_cat[:max_values_to_read]
914
+ sources = sources[:max_values_to_read]
915
+ results.append(((t_cat, v_cat), sources))
916
+
917
+ if len(parameters) == 1:
918
+ return results[0]
919
+ return results
920
+
852
921
  def _resolve_ifun(self, param, factory):
853
922
  """Resolve interpolating function factory for a parameter."""
854
923
  if factory is None:
@@ -17,6 +17,7 @@ DBD_ERROR_INVALID_ENCODING = 10
17
17
  DBD_ERROR_INVALID_FILE_CRITERION_SPECIFIED = 11
18
18
  DBD_ERROR_NO_DATA_TO_INTERPOLATE = 12
19
19
  DBD_ERROR_NO_DATA = 13
20
+ DBD_ERROR_READ_ERROR = 14
20
21
 
21
22
 
22
23
  class DbdError(Exception):
@@ -54,6 +55,8 @@ class DbdError(Exception):
54
55
  mesg = "One or more parameters that are to be interpolated, does/do not have any data."
55
56
  elif self.value == DBD_ERROR_NO_DATA:
56
57
  mesg = "One or more parameters do not have any data."
58
+ elif self.value == DBD_ERROR_READ_ERROR:
59
+ mesg = "Error reading DBD file."
57
60
  else:
58
61
  mesg = f"Undefined error. ({self.value})"
59
62
  if self.mesg:
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
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
File without changes
File without changes
File without changes
File without changes
File without changes