xarray-ms 0.3.8__tar.gz → 0.5.0__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 (67) hide show
  1. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/.github/workflows/ci.yml +3 -3
  2. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/.github/workflows/pre-commit.yml +1 -1
  3. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/PKG-INFO +1 -1
  4. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/doc/source/changelog.rst +14 -0
  5. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/doc/source/conf.py +1 -1
  6. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/doc/source/install.rst +16 -28
  7. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/pyproject.toml +2 -2
  8. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/backend/msv2/factories/correlated.py +2 -2
  9. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/backend/msv2/measures_adapters.py +36 -33
  10. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/backend/msv2/measures_encoders.py +2 -17
  11. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/errors.py +1 -1
  12. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/.github/ISSUE_TEMPLATE.md +0 -0
  13. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  14. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/.github/dependabot.yml +0 -0
  15. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/.github/workflows/readthedocs.yml +0 -0
  16. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/.gitignore +0 -0
  17. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/.pre-commit-config.yaml +0 -0
  18. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/.readthedocs.yaml +0 -0
  19. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/LICENSE +0 -0
  20. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/README.rst +0 -0
  21. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/doc/Makefile +0 -0
  22. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/doc/make.bat +0 -0
  23. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/doc/source/api.rst +0 -0
  24. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/doc/source/index.rst +0 -0
  25. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/doc/source/introduction.rst +0 -0
  26. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/doc/source/links.rst +0 -0
  27. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/doc/source/partitioning.rst +0 -0
  28. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/doc/source/roadmap.rst +0 -0
  29. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/doc/source/tutorial.rst +0 -0
  30. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/hello.txt +0 -0
  31. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/__init__.py +0 -0
  32. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/conftest.py +0 -0
  33. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/msv4_test_corpus/__init__.py +0 -0
  34. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/msv4_test_corpus/conftest.py +0 -0
  35. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/msv4_test_corpus/test_msv_corpus.py +0 -0
  36. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/test_antenna.py +0 -0
  37. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/test_backend.py +0 -0
  38. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/test_basic.py +0 -0
  39. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/test_field_and_source.py +0 -0
  40. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/test_github.py +0 -0
  41. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/test_imputation.py +0 -0
  42. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/test_measures.py +0 -0
  43. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/test_multiton.py +0 -0
  44. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/test_read.py +0 -0
  45. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/test_structure.py +0 -0
  46. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/test_utils.py +0 -0
  47. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/tests/test_zarr_roundtrip.py +0 -0
  48. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/__init__.py +0 -0
  49. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/backend/msv2/array.py +0 -0
  50. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/backend/msv2/entrypoint.py +0 -0
  51. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/backend/msv2/entrypoint_utils.py +0 -0
  52. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/backend/msv2/factories/__init__.py +0 -0
  53. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/backend/msv2/factories/antenna.py +0 -0
  54. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/backend/msv2/factories/core.py +0 -0
  55. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/backend/msv2/factories/field_and_source.py +0 -0
  56. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/backend/msv2/imputation.py +0 -0
  57. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/backend/msv2/partition.py +0 -0
  58. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/backend/msv2/structure.py +0 -0
  59. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/backend/msv2/table_utils.py +0 -0
  60. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/casa_types.py +0 -0
  61. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/msv4_types.py +0 -0
  62. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/multiton.py +0 -0
  63. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/query.py +0 -0
  64. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/testing/__init__.py +0 -0
  65. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/testing/simulator.py +0 -0
  66. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/testing/utils.py +0 -0
  67. {xarray_ms-0.3.8 → xarray_ms-0.5.0}/xarray_ms/utils.py +0 -0
@@ -74,7 +74,7 @@ jobs:
74
74
  python-version: ${{ matrix.python-version }}
75
75
 
76
76
  - name: Checkout source
77
- uses: actions/checkout@v5
77
+ uses: actions/checkout@v6
78
78
  with:
79
79
  fetch-depth: 1
80
80
 
@@ -83,7 +83,7 @@ jobs:
83
83
 
84
84
  - name: Load cached MSv4 Test Corpus
85
85
  id: load-cached-msv4-test-corpus
86
- uses: actions/cache@v4
86
+ uses: actions/cache@v5
87
87
  with:
88
88
  key: msv4-test-corpus-${{ hashFiles('metadata.json')}}
89
89
  path: ~/.cache/xarray-ms/msv4-test-data
@@ -123,7 +123,7 @@ jobs:
123
123
  python-version: 3.11
124
124
 
125
125
  - name: Checkout source
126
- uses: actions/checkout@v5
126
+ uses: actions/checkout@v6
127
127
  with:
128
128
  fetch-depth: 1
129
129
 
@@ -6,7 +6,7 @@ jobs:
6
6
  pre-commit:
7
7
  runs-on: ubuntu-latest
8
8
  steps:
9
- - uses: actions/checkout@v5
9
+ - uses: actions/checkout@v6
10
10
  with:
11
11
  fetch-depth: 1
12
12
  - uses: actions/setup-python@v6
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xarray-ms
3
- Version: 0.3.8
3
+ Version: 0.5.0
4
4
  Summary: xarray MSv4 views over MSv2 Measurement Sets
5
5
  Author-email: Simon Perkins <simon.perkins@gmail.com>
6
6
  License-File: LICENSE
@@ -3,6 +3,20 @@
3
3
  Changelog
4
4
  =========
5
5
 
6
+ 0.5.0 (02-03-2026)
7
+ ------------------
8
+ * Fix ``VisibilityCoder`` typo (:pr:`145`)
9
+ * Raise an exception if no MSv4 Frame Type is available in ``EpochCoder.decode`` (:pr:`145`)
10
+ * Replace an assert with an ``InvalidMeasurementSet`` exception if the
11
+ number of ``TabRefTypes`` doesn't match the ``TabRefCodes`` (:pr:`145`)
12
+ * Guard frame inference in a dictionary with a KeyError (:pr:`145`)
13
+
14
+ 0.3.9 (18-02-2026)
15
+ ------------------
16
+ * Define and use an ``OnMissingLiteralType`` (:pr:`144`)
17
+ * Correct exception name from ComplexMeasuremetSet to ComplexMeasurementSet (:pr:`143`)
18
+ * Remove poetry-specific installation documentation (:pr:`140`)
19
+
6
20
  0.3.8 (17-10-2025)
7
21
  ------------------
8
22
  * Synchronise with v4.0.0 schema version (:pr:`139`)
@@ -11,7 +11,7 @@
11
11
  project = "xarray-ms"
12
12
  copyright = "2024 - 2025 NRF (SARAO) and Rhodes University (RATT) Centre"
13
13
  author = "Simon Perkins"
14
- release = "0.3.8"
14
+ release = "0.5.0"
15
15
 
16
16
  # -- General configuration ---------------------------------------------------
17
17
  # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
@@ -16,40 +16,31 @@ they must be installed separately.
16
16
  Development
17
17
  ===========
18
18
 
19
- Firstly, install Python `Poetry <poetry_>`_.
20
-
21
- .. _poetry: https://python-poetry.org/
22
-
23
- Then, the following commands will install the required dependencies,
24
- optional testing dependencies, documentation and development dependencies
25
- in a suitable virtual environment:
19
+ Create a virtual environment and install with the dev, doc and testing
20
+ dependencies:
26
21
 
27
22
  .. code-block:: bash
28
23
 
29
- $ cd /code/arcae
30
- $ poetry env use 3.11
31
- $ poetry install -E testing --with doc --with dev
32
- $ poetry run pre-commit install
33
- $ poetry shell
24
+
25
+ $ virtualenv -p python3.12 /tmp/xms
26
+ $ source xms/bin/activate
27
+ (xms) $ pip install -e .[dev,doc,testing]
34
28
 
35
29
  The pre-commit hooks can be manually executed as follows:
36
30
 
37
31
  .. code-block:: bash
38
32
 
39
- $ poetry run pre-commit run -a
40
-
33
+ (xms) $ pre-commit run -a
41
34
 
42
35
  Test Suite
43
36
  ----------
44
37
 
45
- Run the following command within the arcae source code directory to
46
- execute the test suite
38
+ After creating the virtual environment above, run the following command
39
+ within the xarray-ms source code directory to execute the test suite:
47
40
 
48
41
  .. code-block:: bash
49
42
 
50
- $ cd /code/arcae
51
- $ poetry install -E testing --with dev
52
- $ poetry run py.test -s -vvv tests/
43
+ (xms) $ py.test -s -vvv tests/
53
44
 
54
45
 
55
46
  Documentation
@@ -60,15 +51,8 @@ build the Sphinx documentation
60
51
 
61
52
  .. code-block:: bash
62
53
 
63
- $ cd /code/arcae
64
- $ poetry install --with doc
65
- $ poetry shell
66
- $ cd doc
67
- $ make html
68
-
69
- .. _cubed: https://cubed-dev.github.io/cubed/
70
- .. _dask: https://www.dask.org/
71
- .. _zarr: https://zarr.dev/
54
+ (xms) $ cd doc
55
+ (xms) $ make html
72
56
 
73
57
  Release Process
74
58
  ---------------
@@ -88,3 +72,7 @@ on the ``main`` branch:
88
72
  .. code-block:: bash
89
73
 
90
74
  $ tbump 0.2.0
75
+
76
+ .. _cubed: https://cubed-dev.github.io/cubed/
77
+ .. _dask: https://www.dask.org/
78
+ .. _zarr: https://zarr.dev/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "xarray-ms"
3
- version = "0.3.8"
3
+ version = "0.5.0"
4
4
  description = "xarray MSv4 views over MSv2 Measurement Sets"
5
5
  authors = [{name = "Simon Perkins", email = "simon.perkins@gmail.com"}]
6
6
  readme = "README.rst"
@@ -54,7 +54,7 @@ extend-select = ["I"]
54
54
  # github_url = "https://github.com/<user or organization>/<project>/"
55
55
 
56
56
  [tool.tbump.version]
57
- current = "0.3.8"
57
+ current = "0.5.0"
58
58
 
59
59
  # Example of a semver regexp.
60
60
  # Make sure this matches current_version before
@@ -23,7 +23,7 @@ from xarray_ms.backend.msv2.imputation import (
23
23
  from xarray_ms.backend.msv2.measures_encoders import (
24
24
  MSv2Coder,
25
25
  MSv2CoderFactory,
26
- VisiblityCoder,
26
+ VisibilityCoder,
27
27
  )
28
28
  from xarray_ms.backend.msv2.structure import MSv2StructureFactory, PartitionKeyT
29
29
  from xarray_ms.casa_types import ColumnDesc, Polarisations
@@ -57,7 +57,7 @@ MSV4_to_MSV2_COLUMN_SCHEMAS = {
57
57
  ),
58
58
  "FLAG": MSv2ColumnSchema("FLAG", ("frequency", "polarization"), 1, None),
59
59
  "VISIBILITY": MSv2ColumnSchema(
60
- "DATA", ("frequency", "polarization"), np.nan + np.nan * 1j, VisiblityCoder()
60
+ "DATA", ("frequency", "polarization"), np.nan + np.nan * 1j, VisibilityCoder()
61
61
  ),
62
62
  "WEIGHT_ROW": MSv2ColumnSchema(
63
63
  "WEIGHT",
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import typing
4
4
  from abc import ABC, abstractmethod
5
5
  from dataclasses import dataclass
6
- from typing import TYPE_CHECKING, Any, Dict, Literal, Sequence, overload
6
+ from typing import TYPE_CHECKING, Any, Dict, Literal, Sequence, get_args, overload
7
7
 
8
8
  import numpy as np
9
9
 
@@ -17,7 +17,7 @@ from xarray_ms.casa_types import (
17
17
  UvwMeasures,
18
18
  )
19
19
  from xarray_ms.errors import (
20
- ComplexMeasuremetSet,
20
+ ComplexMeasurementSet,
21
21
  InvalidMeasurementSet,
22
22
  MissingMeasuresInfo,
23
23
  MissingQuantumUnits,
@@ -28,6 +28,8 @@ from xarray_ms.errors import (
28
28
  if TYPE_CHECKING:
29
29
  import pyarrow as pa
30
30
 
31
+ OnMissingType = Literal["none", "raise"]
32
+
31
33
 
32
34
  @dataclass
33
35
  class MeasuresData:
@@ -45,9 +47,9 @@ CASA_MEASURES_MAP = {
45
47
  }
46
48
 
47
49
 
48
- def raise_invalid_on_missing(on_missing: Literal["none", "raise"]):
49
- if on_missing not in {"none", "raise"}:
50
- raise ValueError(f"'on_missing' {on_missing} not in {{'none', 'raise'}}")
50
+ def raise_invalid_on_missing(on_missing: OnMissingType):
51
+ if on_missing not in get_args(OnMissingType):
52
+ raise ValueError(f"'on_missing' {on_missing} not in {get_args(OnMissingType)}")
51
53
 
52
54
 
53
55
  def raise_on_measinfo_indirection(column_name: str, measinfo: Dict[str, Any]):
@@ -57,19 +59,8 @@ def raise_on_measinfo_indirection(column_name: str, measinfo: Dict[str, Any]):
57
59
  i.e. if it has a ``VarRefCol`` for defining a per-row frame or
58
60
  ``RefOff*`` keywords for defining offsets.
59
61
  """
60
-
61
- def check() -> bool:
62
- for k in measinfo:
63
- if "VarRefCol" in k:
64
- return True
65
-
66
- if k.startswith("RefOff"):
67
- return True
68
-
69
- return False
70
-
71
- if check():
72
- raise ComplexMeasuremetSet(
62
+ if any("VarRefCol" in k or k.startswith("RefOff") for k in measinfo):
63
+ raise ComplexMeasurementSet(
73
64
  f"The MEASINFO in column {column_name} {measinfo} "
74
65
  f"contains indirection in the form of `VarRefCol` "
75
66
  f"or `RefCol*` entries. "
@@ -93,7 +84,7 @@ class MeasuresMixin:
93
84
  ) -> Dict[str, Any]: ...
94
85
 
95
86
  def extract_measinfo(
96
- self, column_desc: ColumnDesc, on_missing: Literal["none", "raise"] = "none"
87
+ self, column_desc: ColumnDesc, on_missing: OnMissingType = "none"
97
88
  ) -> Dict[str, Any] | None:
98
89
  """Extracts the MEASINFO keyword from the column descriptor, if present"""
99
90
  try:
@@ -118,7 +109,7 @@ class MeasuresMixin:
118
109
  ) -> str: ...
119
110
 
120
111
  def extract_quantum_unit(
121
- self, column_desc: ColumnDesc, on_missing: Literal["none", "raise"] = "none"
112
+ self, column_desc: ColumnDesc, on_missing: OnMissingType = "none"
122
113
  ) -> str | None:
123
114
  """Attempts to extract a single quantum unit from the keywords
124
115
  of the column descriptor.
@@ -164,7 +155,7 @@ class MeasuresMixin:
164
155
  ) -> str: ...
165
156
 
166
157
  def extract_msv2_type(
167
- self, column_desc: ColumnDesc, on_missing: Literal["none", "raise"] = "none"
158
+ self, column_desc: ColumnDesc, on_missing: OnMissingType = "none"
168
159
  ) -> str | None:
169
160
  """Returns the msv2 measures type, derived from the 'type' keyword
170
161
  in the column descriptor keywords"""
@@ -202,7 +193,7 @@ class MeasuresMixin:
202
193
  ) -> str: ...
203
194
 
204
195
  def extract_msv4_type(
205
- self, column_desc: ColumnDesc, on_missing: Literal["none", "raise"] = "none"
196
+ self, column_desc: ColumnDesc, on_missing: OnMissingType = "none"
206
197
  ) -> str | None:
207
198
  """Returns the msv4 measures type, derived from the 'type' keyword
208
199
  in the column descriptor keywords"""
@@ -249,26 +240,26 @@ class AbstractMeasuresAdapter(ABC):
249
240
  def msv2_frame(self, on_missing: Literal["raise"]) -> str: ...
250
241
 
251
242
  @abstractmethod
252
- def msv2_frame(self, on_missing: Literal["none", "raise"] = "none") -> str | None:
243
+ def msv2_frame(self, on_missing: OnMissingType = "none") -> str | None:
253
244
  """Returns the MSv2 Measures frame.
254
245
 
255
246
  This corresponds to ``MEASINFO['Ref']`` or possibly ``MEASINFO['VarRefCol']``"""
256
247
  raise NotImplementedError
257
248
 
258
249
  @abstractmethod
259
- def msv2_type(self, on_missing: Literal["none", "raise"] = "none") -> str | None:
250
+ def msv2_type(self, on_missing: OnMissingType = "none") -> str | None:
260
251
  """Returns the MSv2 Measures type.
261
252
 
262
253
  This corresponds to ``MEASINFO['type']`` in the column descriptor keywords"""
263
254
  raise NotImplementedError
264
255
 
265
256
  @abstractmethod
266
- def msv4_type(self, on_missing: Literal["none", "raise"] = "none") -> str | None:
257
+ def msv4_type(self, on_missing: OnMissingType = "none") -> str | None:
267
258
  """Return the MSv4 Measures type"""
268
259
  raise NotImplementedError
269
260
 
270
261
  @abstractmethod
271
- def quantum_unit(self, on_missing: Literal["none", "raise"] = "none") -> str | None:
262
+ def quantum_unit(self, on_missing: OnMissingType = "none") -> str | None:
272
263
  """Returns a single unit associated with this measure.
273
264
 
274
265
  This corresponds to ``MEASINFO['QuantumUnits']`` in the
@@ -300,13 +291,13 @@ class ColumnDescMeasuresAdapter(AbstractMeasuresAdapter, MeasuresMixin):
300
291
  def column_name(self) -> str:
301
292
  return self._column_desc.name
302
293
 
303
- def quantum_unit(self, on_missing: Literal["none", "raise"] = "none") -> str | None:
294
+ def quantum_unit(self, on_missing: OnMissingType = "none") -> str | None:
304
295
  return self.extract_quantum_unit(self._column_desc, on_missing=on_missing)
305
296
 
306
- def msv2_type(self, on_missing: Literal["none", "raise"] = "none"):
297
+ def msv2_type(self, on_missing: OnMissingType = "none"):
307
298
  return self.extract_msv2_type(self._column_desc, on_missing=on_missing)
308
299
 
309
- def msv4_type(self, on_missing: Literal["none", "raise"] = "none") -> str | None:
300
+ def msv4_type(self, on_missing: OnMissingType = "none") -> str | None:
310
301
  return self.extract_msv4_type(self._column_desc, on_missing=on_missing)
311
302
 
312
303
  @overload
@@ -315,7 +306,7 @@ class ColumnDescMeasuresAdapter(AbstractMeasuresAdapter, MeasuresMixin):
315
306
  @overload
316
307
  def msv2_frame(self, on_missing: Literal["raise"]) -> str: ...
317
308
 
318
- def msv2_frame(self, on_missing: Literal["none", "raise"] = "none") -> str | None:
309
+ def msv2_frame(self, on_missing: OnMissingType = "none") -> str | None:
319
310
  if (
320
311
  measinfo := self.extract_measinfo(self._column_desc, on_missing=on_missing)
321
312
  ) is None:
@@ -359,7 +350,7 @@ class ArrowTableMeasuresAdapter(ColumnDescMeasuresAdapter, MeasuresMixin):
359
350
  @overload
360
351
  def msv2_frame(self, on_missing: Literal["raise"]) -> str: ...
361
352
 
362
- def msv2_frame(self, on_missing: Literal["none", "raise"] = "none") -> str | None:
353
+ def msv2_frame(self, on_missing: OnMissingType = "none") -> str | None:
363
354
  if (
364
355
  measinfo := self.extract_measinfo(self._column_desc, on_missing=on_missing)
365
356
  ) is None:
@@ -389,7 +380,11 @@ class ArrowTableMeasuresAdapter(ColumnDescMeasuresAdapter, MeasuresMixin):
389
380
  # The measures information may contain it's own reference types and codes
390
381
  if isinstance(tab_ref_types := measinfo.get("TabRefTypes"), Sequence):
391
382
  if isinstance(tab_ref_codes := measinfo.get("TabRefCodes"), Sequence):
392
- assert len(tab_ref_types) == len(tab_ref_codes)
383
+ if len(tab_ref_types) != len(tab_ref_codes):
384
+ raise InvalidMeasurementSet(
385
+ f"TabRefTypes {tab_ref_types} and TabRefCodes {tab_ref_codes} "
386
+ f"have different lengths in {self.column_name} MEASINFO"
387
+ )
393
388
  else:
394
389
  tab_ref_codes = [MeasuresEnum[t].value for t in tab_ref_types]
395
390
 
@@ -399,7 +394,15 @@ class ArrowTableMeasuresAdapter(ColumnDescMeasuresAdapter, MeasuresMixin):
399
394
  code_frame_map = {m.value: m.name for m in MeasuresEnum}
400
395
 
401
396
  # Try and find a unique frame
402
- if len(frames := {code_frame_map[c] for c in var_ref_col}) == 0:
397
+ try:
398
+ frames = {code_frame_map[c] for c in var_ref_col}
399
+ except KeyError as e:
400
+ raise InvalidMeasurementSet(
401
+ f"Code {e.args[0]} in {var_ref_col_name} is not in the "
402
+ f"code frame map {code_frame_map} for column {self.column_name}"
403
+ ) from e
404
+
405
+ if len(frames) == 0:
403
406
  return None
404
407
 
405
408
  if len(frames) > 1:
@@ -107,21 +107,6 @@ class MeasuresCoder(MSv2Coder):
107
107
  self.measures_adapter = measures_adapter
108
108
 
109
109
 
110
- class QuantityCoder(MeasuresCoder):
111
- """Encodes a quantum unit"""
112
-
113
- def encode(self, variable: Variable, name: T_Name = None) -> Variable:
114
- dims, data, attrs, encoding = unpack_for_encoding(variable)
115
- attrs = {k: v for k, v in attrs.items() if k not in {"type", "units"}}
116
- return Variable(dims, data, attrs, encoding, fastpath=True)
117
-
118
- def decode(self, variable: Variable, name: T_Name = None) -> Variable:
119
- dims, data, attrs, encoding = unpack_for_decoding(variable)
120
- attrs["type"] = "quantity"
121
- attrs["units"] = self.measures_adapter.quantum_unit("raise")
122
- return Variable(dims, data, attrs, encoding, fastpath=True)
123
-
124
-
125
110
  class SuppliedAttributesCoder(MSv2Coder):
126
111
  """Adds and removes the supplied attributes during decoding and encoding"""
127
112
 
@@ -149,7 +134,7 @@ class SuppliedQuantityCoder(SuppliedAttributesCoder):
149
134
  super().__init__({"type": "quantity", "units": units})
150
135
 
151
136
 
152
- class VisiblityCoder(SuppliedQuantityCoder):
137
+ class VisibilityCoder(SuppliedQuantityCoder):
153
138
  """Visibility coder"""
154
139
 
155
140
  def __init__(self):
@@ -227,7 +212,7 @@ class EpochCoder(MeasuresCoder):
227
212
 
228
213
  def decode(self, variable: Variable, name: T_Name = None) -> Variable:
229
214
  dims, data, attrs, encoding = unpack_for_decoding(variable)
230
- attrs["type"] = self.measures_adapter.msv4_type()
215
+ attrs["type"] = self.measures_adapter.msv4_type("raise")
231
216
  attrs["units"] = self.measures_adapter.quantum_unit("raise")
232
217
  attrs["format"] = "unix"
233
218
  if (msv2_frame := self.measures_adapter.msv2_frame("raise")) == "UTC":
@@ -39,7 +39,7 @@ class InvalidMeasurementSet(ValueError):
39
39
  """Raised when the Measurement Set is invalid in some way"""
40
40
 
41
41
 
42
- class ComplexMeasuremetSet(ValueError):
42
+ class ComplexMeasurementSet(ValueError):
43
43
  """Raised when complexity in the Measurement Set prevents processing"""
44
44
 
45
45
 
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