backscattermeter_analyzer 2.2.0__tar.gz → 2.2.1__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 (84) hide show
  1. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/PKG-INFO +1 -1
  2. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/pyproject.toml +1 -1
  3. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/characterize/angle/result.py +73 -0
  4. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/characterize/distance/result.py +49 -1
  5. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/exception/__init__.py +9 -0
  6. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/exception/base.py +5 -0
  7. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/exception/io/__init__.py +7 -0
  8. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/exception/io/base.py +7 -0
  9. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/exception/io/registry/__init__.py +15 -0
  10. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/exception/io/registry/already_defined.py +34 -0
  11. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/exception/io/registry/ambiguous_format.py +22 -0
  12. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/exception/io/registry/base.py +7 -0
  13. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/exception/io/registry/identification.py +23 -0
  14. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/exception/io/registry/not_defined.py +29 -0
  15. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/io/hdf5/__init__.py +11 -0
  16. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/io/hdf5/distance/__init__.py +7 -0
  17. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/io/hdf5/distance/main.py +195 -0
  18. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/io/hdf5/distance/motor.py +214 -0
  19. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/io/hdf5/measurement/__init__.py +1 -3
  20. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/io/hdf5/measurement/main.py +3 -2
  21. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/io/hdf5/result.py +199 -0
  22. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/io/hdf5/utils.py +49 -0
  23. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/io/registry/unified_io_registry_base.py +20 -19
  24. backscattermeter_analyzer-2.2.1/src/backscattermeter_analyzer/utils/distance/connect.py +91 -0
  25. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/distance/distance.py +6 -0
  26. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/distance/motor/state.py +9 -0
  27. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/measurement.py +2 -1
  28. backscattermeter_analyzer-2.2.0/src/backscattermeter_analyzer/characterize/angle/result.py +0 -8
  29. backscattermeter_analyzer-2.2.0/src/backscattermeter_analyzer/io/hdf5/__init__.py +0 -7
  30. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/LICENSE +0 -0
  31. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/README.md +0 -0
  32. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/display.py +0 -0
  33. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/justfile +0 -0
  34. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/mise.toml +0 -0
  35. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/__init__.py +0 -0
  36. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/axis.py +0 -0
  37. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/characterize/__init__.py +0 -0
  38. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/characterize/angle/__init__.py +0 -0
  39. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/characterize/distance/__init__.py +0 -0
  40. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/characterize/distance/ratio.py +0 -0
  41. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/characterize/distance/vector.py +0 -0
  42. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/direction.py +0 -0
  43. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/hardware/__init__.py +0 -0
  44. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/hardware/backscattermeter.py +0 -0
  45. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/hardware/camera/__init__.py +0 -0
  46. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/hardware/motor/__init__.py +0 -0
  47. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/hardware/motor/jump.py +0 -0
  48. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/hardware/motor/path.py +0 -0
  49. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/hardware/motor/step_numbers.py +0 -0
  50. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/hardware/optic/__init__.py +0 -0
  51. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/io/__init__.py +0 -0
  52. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/io/hdf5/measurement/motor.py +0 -0
  53. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/io/registry/__init__.py +0 -0
  54. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/io/registry/default.py +0 -0
  55. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/io/registry/interface/__init__.py +0 -0
  56. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/io/registry/interface/unified_read_write.py +0 -0
  57. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/io/registry/interface/unified_read_write_method.py +0 -0
  58. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/io/registry/unified_input_registry.py +0 -0
  59. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/io/registry/unified_io_registry.py +0 -0
  60. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/io/registry/unified_output_registry.py +0 -0
  61. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/scale.py +0 -0
  62. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/__init__.py +0 -0
  63. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/distance/__init__.py +0 -0
  64. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/distance/motor/__init__.py +0 -0
  65. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/distance/motor/no.py +0 -0
  66. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/distance/motor/yes.py +0 -0
  67. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/distance/state.py +0 -0
  68. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/__init__.py +0 -0
  69. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/angle/__init__.py +0 -0
  70. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/angle/no.py +0 -0
  71. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/angle/state.py +0 -0
  72. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/angle/yes.py +0 -0
  73. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/camera/__init__.py +0 -0
  74. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/camera/no.py +0 -0
  75. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/camera/state.py +0 -0
  76. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/camera/yes.py +0 -0
  77. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/connect.py +0 -0
  78. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/motor/__init__.py +0 -0
  79. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/motor/no.py +0 -0
  80. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/motor/state.py +0 -0
  81. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/motor/yes.py +0 -0
  82. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/measurement/state.py +0 -0
  83. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/src/backscattermeter_analyzer/utils/utils.py +0 -0
  84. {backscattermeter_analyzer-2.2.0 → backscattermeter_analyzer-2.2.1}/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: backscattermeter_analyzer
3
- Version: 2.2.0
3
+ Version: 2.2.1
4
4
  Summary: Tool to work on the backscattermeter at LAPP
5
5
  Project-URL: Documentation, https://git.linarphy.net/linarphy/backscattermeter_analyzer/wiki
6
6
  Project-URL: Homepage, https://git.linarphy.net/linarphy/backscattermeter_analyzer
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "backscattermeter_analyzer"
3
- version = "2.2.0"
3
+ version = "2.2.1"
4
4
  description = "Tool to work on the backscattermeter at LAPP"
5
5
  authors = [{ name = "linarphy", email = "linarphy@linarphy.net" }]
6
6
  readme = "README.md"
@@ -0,0 +1,73 @@
1
+ """Result class."""
2
+
3
+
4
+ from dataclasses import dataclass
5
+ from typing import TYPE_CHECKING
6
+
7
+ from backscattermeter_analyzer import Direction, Distance
8
+ from backscattermeter_analyzer.characterize.distance import (
9
+ Result as DistanceResult,
10
+ )
11
+ from backscattermeter_analyzer.utils.measurement.angle import (
12
+ WithManualAngle,
13
+ )
14
+ from backscattermeter_analyzer.utils.measurement.motor import (
15
+ WithMotorPath,
16
+ )
17
+
18
+ if TYPE_CHECKING:
19
+ from backscattermeter_analyzer import Axis, Measurement
20
+
21
+
22
+ @dataclass
23
+ class Result:
24
+ """Result of an analysis of an angle measurement."""
25
+
26
+ @staticmethod
27
+ def analyze(*measurements: Measurement) -> Result:
28
+ """
29
+ Link manual angle measurements and motorized angle measurements.
30
+
31
+ Parameters
32
+ ----------
33
+ *measurements: Measurement
34
+ Manuals and Motorized measurements.
35
+
36
+ """
37
+
38
+ dict_manual: dict[tuple[Axis, Direction], list[Distance]] = {}
39
+ motor_measurements: list[DistanceResult] = []
40
+
41
+ for measurement in measurements:
42
+ angle_state = measurement.state.angle
43
+ motor_state = measurement.state.motor
44
+ if isinstance(angle_state, WithManualAngle):
45
+ if isinstance(motor_state, WithMotorPath):
46
+ message = (
47
+ "Cannot have a measurement with a manual "
48
+ "angle and a motor path at the same time"
49
+ )
50
+ raise TypeError(message)
51
+ direction = Direction(angle_state.angle.pdf_mean < 0)
52
+ result = DistanceResult.analyze(measurement)
53
+ if (angle_state.axis, direction) not in dict_manual:
54
+ distances = 0
55
+ dict_manual[(angle_state.axis, direction)] = (
56
+ result.distances
57
+ )
58
+ else:
59
+ dict_manual[(angle_state.axis, direction)].append(
60
+ measurement
61
+ )
62
+ else:
63
+ if not isinstance(motor_state, WithMotorPath):
64
+ message = (
65
+ "Cannot have a measurement with no manual "
66
+ "angle nor motor path."
67
+ )
68
+ raise TypeError(message)
69
+ motor_measurements.append(
70
+ DistanceResult.analyze(measurement)
71
+ )
72
+
73
+ return Result()
@@ -1,13 +1,17 @@
1
1
  """Result class."""
2
2
 
3
3
  from dataclasses import dataclass, field
4
- from typing import TYPE_CHECKING
4
+ from typing import TYPE_CHECKING, Any
5
5
  from uuid import uuid4
6
6
 
7
7
  from astropy.time import TimeDelta
8
8
  from astropy.uncertainty import normal
9
9
  from numpy import mean, std
10
10
 
11
+ from backscattermeter_analyzer.io.registry import (
12
+ UnifiedReadWrite,
13
+ UnifiedReadWriteMethod,
14
+ )
11
15
  from backscattermeter_analyzer.utils.distance import Distance
12
16
  from backscattermeter_analyzer.utils.measurement.motor import (
13
17
  WithMotorPath,
@@ -16,6 +20,46 @@ from backscattermeter_analyzer.utils.measurement.motor import (
16
20
  if TYPE_CHECKING:
17
21
  from backscattermeter_analyzer.utils.measurement import Measurement
18
22
 
23
+ _Base = UnifiedReadWrite["Result"]
24
+
25
+
26
+ class Read(_Base):
27
+ """
28
+ Read and parse a Result.
29
+
30
+ This function provides the Result interface to the
31
+ backscattermeter_analyzer unified I/O layer.
32
+ """
33
+
34
+ def __init__(
35
+ self, instance: Result | None, class_: type[Result]
36
+ ) -> None:
37
+ """Initialize this class."""
38
+ super().__init__(instance, class_, "read")
39
+
40
+ def __call__(self, *args: Any, **kwargs: Any) -> Result:
41
+ """Run the main function."""
42
+ return self._registry.read(self._class_, *args, **kwargs)
43
+
44
+
45
+ class Write(_Base):
46
+ """
47
+ Write a Result object out in the specified format.
48
+
49
+ This function provides the Result interface to the
50
+ backscattermeter_analyzer unified I/O layer.
51
+ """
52
+
53
+ def __init__(
54
+ self, instance: Result | None, class_: type[Result]
55
+ ) -> None:
56
+ """Initialize this class."""
57
+ super().__init__(instance, class_, "write")
58
+
59
+ def __call__(self, *args: Any, **kwargs: Any) -> object | None:
60
+ """Run the main function."""
61
+ return self._registry.write(self._instance, *args, **kwargs)
62
+
19
63
 
20
64
  @dataclass
21
65
  class Result:
@@ -23,8 +67,12 @@ class Result:
23
67
 
24
68
  measurement: Measurement
25
69
  distances: list[Distance]
70
+
26
71
  identifier: str = field(default_factory=lambda: str(uuid4()))
27
72
 
73
+ read = UnifiedReadWriteMethod(Read)
74
+ write = UnifiedReadWriteMethod(Write)
75
+
28
76
  @staticmethod
29
77
  def analyze(measurement: Measurement) -> Result:
30
78
  """Generate a result from a measurement by analysing it."""
@@ -0,0 +1,9 @@
1
+ """Store every exceptions of `backscattermeter_analyzer`."""
2
+
3
+ from .base import BaseError
4
+ from .io import BaseIOError
5
+
6
+ __all__ = [
7
+ "BaseError",
8
+ "BaseIOError",
9
+ ]
@@ -0,0 +1,5 @@
1
+ """Base class."""
2
+
3
+
4
+ class BaseError(Exception):
5
+ """Parent of every exception in `backscattermeter_analyzer`."""
@@ -0,0 +1,7 @@
1
+ """Store exceptions on I/O process."""
2
+
3
+ from .base import BaseIOError
4
+
5
+ __all__ = [
6
+ "BaseIOError",
7
+ ]
@@ -0,0 +1,7 @@
1
+ """BaseIOError class."""
2
+
3
+ from backscattermeter_analyzer.exception.base import BaseError
4
+
5
+
6
+ class BaseIOError(BaseError):
7
+ """Base IO Error."""
@@ -0,0 +1,15 @@
1
+ """Exception about registry registration."""
2
+
3
+ from .already_defined import AlreadyDefinedError
4
+ from .ambiguous_format import AmbiguousFormatError
5
+ from .base import RegistryError
6
+ from .identification import IdentificationError
7
+ from .not_defined import NotDefinedError
8
+
9
+ __all__ = [
10
+ "AlreadyDefinedError",
11
+ "AmbiguousFormatError",
12
+ "IdentificationError",
13
+ "NotDefinedError",
14
+ "RegistryError",
15
+ ]
@@ -0,0 +1,34 @@
1
+ """AlreadyDefinedError class."""
2
+
3
+ from .base import RegistryError
4
+
5
+
6
+ class AlreadyDefinedError(RegistryError):
7
+ """A function that link a format to a class is already defined."""
8
+
9
+ def __init__(
10
+ self, data_format: str, data_class: type, function_type: str
11
+ ) -> None:
12
+ """
13
+ Error initialization.
14
+
15
+ Parameters
16
+ ----------
17
+ data_format: str
18
+ Data format linked to the registry entry.
19
+ data_class: type
20
+ Type linked to the registry entry.
21
+ function_type: str
22
+ Type of the entry (identifier, writer, reader, etc.).
23
+
24
+ Notes
25
+ -----
26
+ data_class - write -> data_format
27
+ data_format - read -> data_class
28
+
29
+ """
30
+ super().__init__(
31
+ f"{function_type.capitalize()} for format `{data_format}`"
32
+ f" and class `{data_class}` is already defined. Use "
33
+ "`force=True` to overwrite and ignore the existing entry."
34
+ )
@@ -0,0 +1,22 @@
1
+ """AmbiguousFormatError class."""
2
+
3
+ from .base import RegistryError
4
+
5
+
6
+ class AmbiguousFormatError(RegistryError):
7
+ """Ambiguous format."""
8
+
9
+ def __init__(self, valid_formats: str) -> None:
10
+ """
11
+ Error initialization.
12
+
13
+ Parameters
14
+ ----------
15
+ valid_formats: str
16
+ Valid formats.
17
+
18
+ """
19
+
20
+ super().__init__(
21
+ f"Format is ambiguous. Options are: {valid_formats}."
22
+ )
@@ -0,0 +1,7 @@
1
+ """RegistryError class."""
2
+
3
+ from backscattermeter_analyzer.exception.io import BaseIOError
4
+
5
+
6
+ class RegistryError(BaseIOError):
7
+ """Error on Unified I/O registry operation."""
@@ -0,0 +1,23 @@
1
+ """IdentificationError class."""
2
+
3
+ from .base import RegistryError
4
+
5
+
6
+ class IdentificationError(RegistryError):
7
+ """Impossible to identify format without explicit format arg."""
8
+
9
+ def __init__(self, format_table: str) -> None:
10
+ """
11
+ Error initialization.
12
+
13
+ Parameters
14
+ ----------
15
+ format_table: str
16
+ Available format table.
17
+
18
+ """
19
+ super().__init__(
20
+ "Format could not be identified based on the file name or "
21
+ "contents, please provide a `format` argument.\n"
22
+ f"The available formats are:\n{format_table}"
23
+ )
@@ -0,0 +1,29 @@
1
+ """NotDefinedError class."""
2
+
3
+ from .base import RegistryError
4
+
5
+
6
+ class NotDefinedError(RegistryError):
7
+ """A function that link a format to a class does not exist."""
8
+
9
+ def __init__(
10
+ self, data_format: str, data_class: type, function_type: str
11
+ ) -> None:
12
+ """
13
+ Error initialization.
14
+
15
+ Parameters
16
+ ----------
17
+ data_format: str
18
+ Data format linked to the non-existing registry entry.
19
+ data_class: type
20
+ Type linked to the non-existing registry entry.
21
+ function_type: str
22
+ Type of the non-existing entry (identifier, writer, reader,
23
+ etc.)
24
+
25
+ """
26
+ super().__init__(
27
+ f"No {function_type} defined for format {data_format} and "
28
+ f"class {data_class}."
29
+ )
@@ -0,0 +1,11 @@
1
+ """Sub-package for writing and parsing hdf5 files."""
2
+
3
+ from .distance import register_distance as register_distance_hdf5
4
+ from .measurement import (
5
+ register_measurement as register_measurement_hdf5,
6
+ )
7
+
8
+ __all__ = [
9
+ "register_distance_hdf5",
10
+ "register_measurement_hdf5",
11
+ ]
@@ -0,0 +1,7 @@
1
+ """Sub-package managing HDF5 conversion of Distance."""
2
+
3
+ from .main import register_distance
4
+
5
+ __all__ = [
6
+ "register_distance",
7
+ ]
@@ -0,0 +1,195 @@
1
+ """Hdf5 conversion for the main metadata of a Distance."""
2
+
3
+ from pathlib import Path
4
+ from typing import TYPE_CHECKING
5
+
6
+ from astropy.uncertainty import Distribution
7
+ from gwpy.detector.channel import Channel
8
+ from h5py import Dataset, File, Group
9
+
10
+ from backscattermeter_analyzer.io.hdf5.utils import (
11
+ dataset_to_distribution,
12
+ distribution_to_dataset,
13
+ get_group,
14
+ is_hdf5,
15
+ )
16
+ from backscattermeter_analyzer.io.registry.default import (
17
+ default_registry,
18
+ )
19
+
20
+ if TYPE_CHECKING:
21
+ from backscattermeter_analyzer.utils import Distance
22
+
23
+
24
+ def _read(input_: Group, path: str | None = None) -> Distance:
25
+ """Read a Distance object from a group, internal function."""
26
+ from backscattermeter_analyzer.utils import (
27
+ Distance,
28
+ )
29
+
30
+ item = get_group(input_, path)
31
+
32
+ group_distance = item.get("distance", default=None)
33
+ if group_distance is None:
34
+ message = f"No `distance` group in {path} from {input_.name}."
35
+ raise ValueError(message)
36
+ if not isinstance(group_distance, Group):
37
+ message = (
38
+ f"`distance` must be a group in {path} from {input_.name}."
39
+ )
40
+ raise TypeError(message)
41
+
42
+ distance: dict[str | Channel, Distribution] = {}
43
+ for dataset_distance in group_distance:
44
+ if not isinstance(group_distance[dataset_distance], Dataset):
45
+ message = (
46
+ f"`{dataset_distance}` is not a dataset in {path} from "
47
+ f"{input_.name}."
48
+ )
49
+ raise TypeError(message)
50
+ distance[dataset_distance] = dataset_to_distribution(
51
+ group_distance[dataset_distance]
52
+ )
53
+
54
+ identifier = item["identifier"]
55
+
56
+ return Distance(distance=distance, identifier=identifier)
57
+
58
+
59
+ def read(input_: Path | Group, path: str | None = None) -> Distance:
60
+ """
61
+ Read a Distance object from an HDF5 component/file.
62
+
63
+ Parameters
64
+ ----------
65
+ input_: Path | Group
66
+ If a Path, the filename to read the distance from.
67
+ If an h5py object, either the file or the group object to read
68
+ the Distance from.
69
+ path: str | None
70
+ The path from which to read the distance inside the HDF5
71
+ file. This should be relative to the input if the input is a
72
+ Group.
73
+
74
+ """
75
+
76
+ if isinstance(input_, Path):
77
+ with File(input_) as file:
78
+ return _read(input_=file, path=path)
79
+
80
+ return _read(input_=input_, path=path)
81
+
82
+
83
+ def _write(
84
+ distance: Distance,
85
+ output: Group,
86
+ path: str | None = None,
87
+ *,
88
+ append: bool = False,
89
+ overwrite: bool = False,
90
+ ) -> None:
91
+ """Write a Distance object to a group, internal function."""
92
+
93
+ if path is not None:
94
+ item = output.get(path, default=None)
95
+ if item is not None and not (append and overwrite):
96
+ message = (
97
+ f"`{path}` already exists in {output.name}, add "
98
+ "`append=True` and `overwrite=True` to proceed anyway."
99
+ )
100
+ raise ValueError(message)
101
+ if item is not None:
102
+ if not isinstance(item, Group):
103
+ message = (
104
+ f"{path} from {output.name} is a {type(item)}"
105
+ ", not a Group."
106
+ )
107
+ raise TypeError(message)
108
+ item.clear()
109
+ else:
110
+ item = output.create_group(name=path)
111
+ else:
112
+ item = output
113
+
114
+ item["identifier"] = distance.identifier
115
+ distance_group = item.create_group("distance")
116
+
117
+ for name, distance_item in distance.distance.items():
118
+ distribution_to_dataset(
119
+ store=distance_group,
120
+ name=str(name),
121
+ distribution=distance_item,
122
+ )
123
+
124
+
125
+ def write(
126
+ distance: Distance,
127
+ output: Path | Group,
128
+ path: str | None = None,
129
+ *,
130
+ append: bool = False,
131
+ overwrite: bool = False,
132
+ ) -> None:
133
+ """
134
+ Write a Distance object to an HDF5 file.
135
+
136
+ Parameters
137
+ ----------
138
+ distance: Distance
139
+ Distance that is to be written to file.
140
+ output: Path | Group
141
+ If a Path, the path of the file to write the distance to. If
142
+ a Group, the group object to write the distance to, depending
143
+ on `path` value.
144
+ path: str | None
145
+ The path to which to write the distance inside the HDF5 file.
146
+ This should be relative to the output Group (or the root Group
147
+ if output is a Path). Default to None.
148
+ append: bool
149
+ Whether to append the distance to an existing HDF5 file.
150
+ Default to False. This can delete a previous distance.
151
+ overwrite: bool
152
+ Whether to overwrite any existing file without warning. Default
153
+ to False. If `append=True` and `overwrite=True`, then only the
154
+ group will be replaced.
155
+
156
+ """
157
+
158
+ if isinstance(output, Path):
159
+ mode = "x"
160
+ if overwrite and not append:
161
+ mode = "w"
162
+ elif append:
163
+ mode = "r+"
164
+
165
+ with File(output, mode=mode) as file:
166
+ return _write(
167
+ distance=distance,
168
+ output=file,
169
+ path=path,
170
+ append=append,
171
+ overwrite=overwrite,
172
+ )
173
+
174
+ return _write(
175
+ distance=distance,
176
+ output=output,
177
+ path=path,
178
+ append=append,
179
+ overwrite=overwrite,
180
+ )
181
+
182
+
183
+ def register_distance() -> None:
184
+ """Register Distance hdf5 conversion in Unified I/O."""
185
+ from backscattermeter_analyzer.utils import (
186
+ Distance,
187
+ )
188
+
189
+ from .motor import register_motor_state
190
+
191
+ register_motor_state()
192
+
193
+ default_registry.register_identifier("hdf5", Distance, is_hdf5)
194
+ default_registry.register_reader("hdf5", Distance, read)
195
+ default_registry.register_writer("hdf5", Distance, write)