xarray-ms 0.5.4__tar.gz → 0.5.5__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.
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/.github/workflows/ci.yml +1 -1
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/.readthedocs.yaml +4 -4
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/PKG-INFO +3 -20
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/doc/source/changelog.rst +10 -1
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/doc/source/conf.py +1 -1
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/doc/source/install.rst +7 -11
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/doc/source/links.rst +1 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/doc/source/partitioning.rst +2 -2
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/doc/source/roadmap.rst +1 -1
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/doc/source/tutorial.rst +1 -1
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/pyproject.toml +6 -6
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/conftest.py +2 -3
- xarray_ms-0.5.5/tests/test_accessors.py +24 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/test_backend.py +0 -12
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/test_structure.py +27 -19
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/backend/msv2/array.py +7 -4
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/backend/msv2/entrypoint.py +11 -21
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/backend/msv2/entrypoint_utils.py +10 -6
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/backend/msv2/factories/core.py +7 -4
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/backend/msv2/factories/correlated.py +13 -9
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/backend/msv2/structure.py +20 -92
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/errors.py +0 -4
- xarray_ms-0.5.4/tests/test_multiton.py +0 -70
- xarray_ms-0.5.4/xarray_ms/multiton.py +0 -73
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/.github/ISSUE_TEMPLATE.md +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/.github/dependabot.yml +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/.github/workflows/pre-commit.yml +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/.github/workflows/readthedocs.yml +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/.gitignore +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/.pre-commit-config.yaml +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/LICENSE +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/README.rst +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/doc/Makefile +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/doc/make.bat +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/doc/source/api.rst +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/doc/source/index.rst +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/doc/source/introduction.rst +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/hello.txt +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/__init__.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/msv4_test_corpus/__init__.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/msv4_test_corpus/conftest.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/msv4_test_corpus/test_msv_corpus.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/test_antenna.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/test_basic.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/test_field_and_source.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/test_github.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/test_imputation.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/test_measures.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/test_read.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/test_table_utils.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/test_utils.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/tests/test_zarr_roundtrip.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/__init__.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/backend/msv2/factories/__init__.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/backend/msv2/factories/antenna.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/backend/msv2/factories/field_and_source.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/backend/msv2/imputation.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/backend/msv2/measures_adapters.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/backend/msv2/measures_encoders.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/backend/msv2/partition.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/backend/msv2/table_utils.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/casa_types.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/msv4_types.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/query.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/testing/__init__.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/testing/simulator.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/testing/utils.py +0 -0
- {xarray_ms-0.5.4 → xarray_ms-0.5.5}/xarray_ms/utils.py +0 -0
|
@@ -1,31 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xarray-ms
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.5
|
|
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
|
|
7
7
|
Requires-Python: >=3.11
|
|
8
|
-
Requires-Dist: arcae<0.6.0,>=0.5.
|
|
9
|
-
Requires-Dist:
|
|
8
|
+
Requires-Dist: arcae<0.6.0,>=0.5.2
|
|
9
|
+
Requires-Dist: rarg-python-patterns>=0.0.3
|
|
10
10
|
Requires-Dist: typing-extensions>=4.12.2
|
|
11
11
|
Requires-Dist: xarray>=2025.0
|
|
12
|
-
Provides-Extra: dev
|
|
13
|
-
Requires-Dist: pre-commit>=3.8.0; extra == 'dev'
|
|
14
|
-
Requires-Dist: tbump>=6.11.0; extra == 'dev'
|
|
15
|
-
Provides-Extra: doc
|
|
16
|
-
Requires-Dist: ipython>=8.27.0; extra == 'doc'
|
|
17
|
-
Requires-Dist: pydata-sphinx-theme>=0.15.4; extra == 'doc'
|
|
18
|
-
Requires-Dist: pygments>=2.18.0; extra == 'doc'
|
|
19
|
-
Requires-Dist: sphinx-copybutton>=0.5.2; extra == 'doc'
|
|
20
|
-
Requires-Dist: sphinx>=8.0.2; extra == 'doc'
|
|
21
|
-
Requires-Dist: sphinxcontrib-spelling; extra == 'doc'
|
|
22
|
-
Provides-Extra: testing
|
|
23
|
-
Requires-Dist: dask>=2024.5.0; extra == 'testing'
|
|
24
|
-
Requires-Dist: distributed>=2024.5.0; extra == 'testing'
|
|
25
|
-
Requires-Dist: platformdirs>=4.3.8; extra == 'testing'
|
|
26
|
-
Requires-Dist: pytest>=8.0.0; extra == 'testing'
|
|
27
|
-
Requires-Dist: xradio>=1.1.2; (python_version >= '3.11' and python_version < '3.14') and extra == 'testing'
|
|
28
|
-
Requires-Dist: zarr<3.0.0,>=2.18.3; extra == 'testing'
|
|
29
12
|
Description-Content-Type: text/x-rst
|
|
30
13
|
|
|
31
14
|
xarray-ms
|
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
Changelog
|
|
4
4
|
=========
|
|
5
5
|
|
|
6
|
+
0.5.5 (12-06-2026)
|
|
7
|
+
------------------
|
|
8
|
+
* Upgrade to arcae 0.5.2 (:pr:`161`)
|
|
9
|
+
* Documentation fixes (:pr:`160`)
|
|
10
|
+
* Replace ``xarray_ms.multiton.Multiton`` with ``rarg-python-patterns.multiton.Multiton`` (:pr:`159`)
|
|
11
|
+
* Move development dependencies in dependency groups (:pr:`158`)
|
|
12
|
+
* Remove ``*kwargs`` from ``MSv2EntryPoint`` methods (:pr:`156`)
|
|
13
|
+
* Revert: Allow unsupported arguments in entrypoint methods (#154) (:pr:`155`)
|
|
14
|
+
|
|
6
15
|
0.5.4 (20-05-2026)
|
|
7
16
|
------------------
|
|
8
17
|
* Allow unsupported arguments in entrypoint methods (:pr:`154`)
|
|
@@ -41,7 +50,7 @@ Changelog
|
|
|
41
50
|
* Synchronise with v4.0.0 schema version (:pr:`139`)
|
|
42
51
|
* Remove ``correlated_xds.scan_number`` coordinate (:pr:`139`)
|
|
43
52
|
* Remove ``correlated_xds.sub_scan_number`` coordinate (:pr:`139`)
|
|
44
|
-
* Add ``
|
|
53
|
+
* Add ``correlated_xds.scan_name`` coordinate (:pr:`139`)
|
|
45
54
|
* Add ``correlated_xds.frequency.spectral_window_intents`` coordinate attribute (:pr:`139`)
|
|
46
55
|
* Remove ``correlated_xds.observation_info["intents"]`` (:pr:`139`)
|
|
47
56
|
* Rename ``correlated_xds.observation_info["project"]`` to ``"project_UID"`` (: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.5.
|
|
14
|
+
release = "0.5.5"
|
|
15
15
|
|
|
16
16
|
# -- General configuration ---------------------------------------------------
|
|
17
17
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
|
@@ -16,31 +16,27 @@ they must be installed separately.
|
|
|
16
16
|
Development
|
|
17
17
|
===========
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
dependencies:
|
|
19
|
+
Install with the dev, doc and testing dependencies using uv_:
|
|
21
20
|
|
|
22
21
|
.. code-block:: bash
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
$ virtualenv -p python3.12 /tmp/xms
|
|
26
|
-
$ source xms/bin/activate
|
|
27
|
-
(xms) $ pip install -e .[dev,doc,testing]
|
|
23
|
+
$ uv sync --group dev --group test --group doc
|
|
28
24
|
|
|
29
25
|
The pre-commit hooks can be manually executed as follows:
|
|
30
26
|
|
|
31
27
|
.. code-block:: bash
|
|
32
28
|
|
|
33
|
-
|
|
29
|
+
$ uv run --dev pre-commit run -a
|
|
34
30
|
|
|
35
31
|
Test Suite
|
|
36
32
|
----------
|
|
37
33
|
|
|
38
|
-
After
|
|
34
|
+
After installing the dependencies above, run the following command
|
|
39
35
|
within the xarray-ms source code directory to execute the test suite:
|
|
40
36
|
|
|
41
37
|
.. code-block:: bash
|
|
42
38
|
|
|
43
|
-
|
|
39
|
+
$ uv run --group test py.test tests/
|
|
44
40
|
|
|
45
41
|
|
|
46
42
|
Documentation
|
|
@@ -51,8 +47,8 @@ build the Sphinx documentation
|
|
|
51
47
|
|
|
52
48
|
.. code-block:: bash
|
|
53
49
|
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
$ cd doc
|
|
51
|
+
$ make html
|
|
56
52
|
|
|
57
53
|
Release Process
|
|
58
54
|
---------------
|
|
@@ -43,7 +43,7 @@ is that it can represent overlapped or disjoint measurements in time and frequen
|
|
|
43
43
|
for one or more baselines.
|
|
44
44
|
However, most observational data is well-behaved:
|
|
45
45
|
Measurements are commonly ordered by ``TIME, ANTENNA1, ANTENNA2``
|
|
46
|
-
and ``CHAN_FREQ`` commonly increases
|
|
46
|
+
and ``CHAN_FREQ`` commonly increases monotonically with
|
|
47
47
|
equidistant values (i.e. ``CHAN_WIDTH`` values are uniform) but this cannot
|
|
48
48
|
always be assumed.
|
|
49
49
|
Any regularity in an MSv2 MS is achieved through convention rather
|
|
@@ -86,7 +86,7 @@ Partitioning in time
|
|
|
86
86
|
Compared to frequency, achieving regularity in time requires more thought
|
|
87
87
|
as it depends on identifying partitions of MSv2 where data:
|
|
88
88
|
|
|
89
|
-
1. contains
|
|
89
|
+
1. contains monotonically increasing ``TIME`` (after ordering).
|
|
90
90
|
2. is dumped with a uniform ``INTERVAL``.
|
|
91
91
|
3. ideally contains no gaps: i.e. ``(TIME - INTERVAL)[1:] == (TIME + INTERVAL)[:-1]``.
|
|
92
92
|
|
|
@@ -18,7 +18,7 @@ In particular, it loads the MSv2 dataset present in the
|
|
|
18
18
|
`Measurement Set v4 test suite <msv4-test-suite_>`_ except for:
|
|
19
19
|
|
|
20
20
|
- ALMA Measurement Sets which sometimes do not correctly link
|
|
21
|
-
the
|
|
21
|
+
the ANTENNA and MAIN table via the FEED table.
|
|
22
22
|
This will need to be addressed heuristically.
|
|
23
23
|
- Single-dish Measurement Sets.
|
|
24
24
|
This is not difficult as it involves loading in
|
|
@@ -55,7 +55,7 @@ with a lazy view over the data.
|
|
|
55
55
|
xarray has extensive functionality for
|
|
56
56
|
`indexing and selecting data <xarray_indexing_and_selecting_>`_.
|
|
57
57
|
|
|
58
|
-
For example, one could select
|
|
58
|
+
For example, one could select some specific dimensions out:
|
|
59
59
|
|
|
60
60
|
.. ipython:: python
|
|
61
61
|
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "xarray-ms"
|
|
3
|
-
version = "0.5.
|
|
3
|
+
version = "0.5.5"
|
|
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"
|
|
7
7
|
requires-python = ">=3.11"
|
|
8
8
|
dependencies = [
|
|
9
9
|
"xarray>=2025.0",
|
|
10
|
-
"
|
|
11
|
-
"arcae>=0.5.1, < 0.6.0",
|
|
10
|
+
"arcae>=0.5.2, < 0.6.0",
|
|
12
11
|
"typing-extensions>=4.12.2",
|
|
12
|
+
"rarg-python-patterns>=0.0.3",
|
|
13
13
|
]
|
|
14
14
|
|
|
15
|
-
[
|
|
16
|
-
|
|
15
|
+
[dependency-groups]
|
|
16
|
+
test = [
|
|
17
17
|
"pytest>=8.0.0",
|
|
18
18
|
"dask>=2024.5.0",
|
|
19
19
|
"distributed>=2024.5.0",
|
|
@@ -55,7 +55,7 @@ extend-select = ["I"]
|
|
|
55
55
|
# github_url = "https://github.com/<user or organization>/<project>/"
|
|
56
56
|
|
|
57
57
|
[tool.tbump.version]
|
|
58
|
-
current = "0.5.
|
|
58
|
+
current = "0.5.5"
|
|
59
59
|
|
|
60
60
|
# Example of a semver regexp.
|
|
61
61
|
# Make sure this matches current_version before
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
import pytest
|
|
3
3
|
from arcae.lib.arrow_tables import Table, ms_descriptor
|
|
4
|
+
from rarg_python_patterns.multiton import Multiton
|
|
4
5
|
|
|
5
|
-
from xarray_ms.backend.msv2.structure import MSv2StructureFactory
|
|
6
|
-
from xarray_ms.multiton import Multiton
|
|
7
6
|
from xarray_ms.testing.simulator import DEFAULT_SIM_PARAMS, MSStructureSimulator
|
|
8
7
|
|
|
9
8
|
MSV4_TEST_CORPUS = "msv4_test_corpus"
|
|
@@ -39,7 +38,7 @@ def pytest_collection_modifyitems(config, items):
|
|
|
39
38
|
def clear_caches():
|
|
40
39
|
yield
|
|
41
40
|
Multiton._INSTANCE_CACHE.clear()
|
|
42
|
-
|
|
41
|
+
Multiton._EXPIRY_HEAP.clear()
|
|
43
42
|
|
|
44
43
|
|
|
45
44
|
@pytest.fixture(scope="session", params=[DEFAULT_SIM_PARAMS])
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import xarray
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@pytest.mark.skip
|
|
6
|
+
@pytest.mark.filterwarnings("ignore:.*?matched multiple partitions")
|
|
7
|
+
@pytest.mark.parametrize(
|
|
8
|
+
"simmed_ms",
|
|
9
|
+
[
|
|
10
|
+
{
|
|
11
|
+
"name": "backend.ms",
|
|
12
|
+
"data_description": [(8, ["XX", "XY", "YX", "YY"]), (4, ["RR", "LL"])],
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
indirect=True,
|
|
16
|
+
)
|
|
17
|
+
def test_accessors(simmed_ms):
|
|
18
|
+
dt = xarray.open_datatree(simmed_ms)
|
|
19
|
+
dt["/backend/partition_000"].attrs["links"] = {
|
|
20
|
+
"antenna": "/backend/partition_000/ANTENNA",
|
|
21
|
+
"weather": "/backend/partition_000/weather_xds",
|
|
22
|
+
}
|
|
23
|
+
# print(dt)
|
|
24
|
+
print(dt["/backend/partition_000"].links.antenna)
|
|
@@ -7,7 +7,6 @@ import xarray.testing as xt
|
|
|
7
7
|
from numpy.testing import assert_array_equal
|
|
8
8
|
|
|
9
9
|
from xarray_ms.backend.msv2.entrypoint import MSv2EntryPoint
|
|
10
|
-
from xarray_ms.errors import IgnoredArgument
|
|
11
10
|
from xarray_ms.testing.utils import id_string, prune_datetime_structures
|
|
12
11
|
|
|
13
12
|
|
|
@@ -238,14 +237,3 @@ def test_open_datatree_chunking(simmed_ms):
|
|
|
238
237
|
}
|
|
239
238
|
|
|
240
239
|
assert ncdt.identical(prune_datetime_structures(dt))
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
@pytest.mark.parametrize(
|
|
244
|
-
"simmed_ms",
|
|
245
|
-
[{"name": "ignored_kwargs.ms"}],
|
|
246
|
-
indirect=True,
|
|
247
|
-
)
|
|
248
|
-
def test_ignored_kwargs_warning(simmed_ms):
|
|
249
|
-
with pytest.warns(IgnoredArgument, match="unsupported_kwarg"):
|
|
250
|
-
dt = xarray.open_datatree(simmed_ms, unsupported_kwarg=True)
|
|
251
|
-
assert isinstance(dt, xarray.DataTree)
|
|
@@ -7,13 +7,15 @@ import pytest
|
|
|
7
7
|
import xarray
|
|
8
8
|
from arcae.lib.arrow_tables import Table
|
|
9
9
|
from numpy.testing import assert_array_equal, assert_equal
|
|
10
|
+
from rarg_python_patterns.multiton import Multiton
|
|
10
11
|
|
|
11
12
|
from xarray_ms.backend.msv2.structure import (
|
|
12
|
-
|
|
13
|
+
MainTableFactory,
|
|
14
|
+
MSv2Structure,
|
|
15
|
+
SubtableFactory,
|
|
13
16
|
TablePartitioner,
|
|
14
17
|
baseline_id,
|
|
15
18
|
)
|
|
16
|
-
from xarray_ms.multiton import Multiton
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
@pytest.mark.parametrize("na", [1, 2, 3, 4, 7])
|
|
@@ -34,20 +36,20 @@ def test_structure_factory(simmed_ms, epoch):
|
|
|
34
36
|
"OBSERVATION_ID",
|
|
35
37
|
"OBS_MODE",
|
|
36
38
|
]
|
|
37
|
-
table_factory = Multiton(Table.from_filename, simmed_ms)
|
|
39
|
+
table_factory: MainTableFactory = Multiton(Table.from_filename, simmed_ms)
|
|
38
40
|
from xarray_ms.backend.msv2.entrypoint_utils import subtable_factory
|
|
39
41
|
|
|
40
|
-
subtables = {
|
|
42
|
+
subtables: dict[str, SubtableFactory] = {
|
|
41
43
|
st: Multiton(subtable_factory, f"{simmed_ms}::{st}")
|
|
42
44
|
for st in ("DATA_DESCRIPTION", "FEED", "FIELD", "STATE")
|
|
43
45
|
}
|
|
44
|
-
structure_factory =
|
|
45
|
-
table_factory, subtables, partition_schema, epoch, True
|
|
46
|
+
structure_factory = Multiton(
|
|
47
|
+
MSv2Structure, table_factory, subtables, partition_schema, epoch, True
|
|
46
48
|
)
|
|
47
49
|
assert pickle.loads(pickle.dumps(structure_factory)) == structure_factory
|
|
48
50
|
|
|
49
|
-
structure_factory2 =
|
|
50
|
-
table_factory, subtables, partition_schema, epoch, True
|
|
51
|
+
structure_factory2 = Multiton(
|
|
52
|
+
MSv2Structure, table_factory, subtables, partition_schema, epoch, True
|
|
51
53
|
)
|
|
52
54
|
assert structure_factory.instance is structure_factory2.instance
|
|
53
55
|
|
|
@@ -114,34 +116,40 @@ def test_table_partitioner():
|
|
|
114
116
|
|
|
115
117
|
def test_epoch(simmed_ms):
|
|
116
118
|
partition_schema = ["FIELD_ID", "DATA_DESC_ID", "OBSERVATION_ID"]
|
|
117
|
-
table_factory = Multiton(Table.from_filename, simmed_ms)
|
|
119
|
+
table_factory: MainTableFactory = Multiton(Table.from_filename, simmed_ms)
|
|
118
120
|
from xarray_ms.backend.msv2.entrypoint_utils import subtable_factory
|
|
119
121
|
|
|
120
|
-
subtables = {
|
|
122
|
+
subtables: dict[str, SubtableFactory] = {
|
|
121
123
|
st: Multiton(subtable_factory, f"{simmed_ms}::{st}")
|
|
122
124
|
for st in ("DATA_DESCRIPTION", "FEED", "FIELD", "STATE")
|
|
123
125
|
}
|
|
124
126
|
|
|
125
|
-
structure_factory =
|
|
126
|
-
table_factory, subtables, partition_schema, "abc", True
|
|
127
|
+
structure_factory = Multiton(
|
|
128
|
+
MSv2Structure, table_factory, subtables, partition_schema, "abc", True
|
|
127
129
|
)
|
|
128
|
-
structure_factory2 =
|
|
129
|
-
table_factory, subtables, partition_schema, "abc", True
|
|
130
|
+
structure_factory2 = Multiton(
|
|
131
|
+
MSv2Structure, table_factory, subtables, partition_schema, "abc", True
|
|
130
132
|
)
|
|
131
133
|
|
|
132
134
|
assert structure_factory.instance is structure_factory2.instance
|
|
133
135
|
|
|
134
|
-
structure_factory3 =
|
|
135
|
-
table_factory, subtables, partition_schema, "def", True
|
|
136
|
+
structure_factory3 = Multiton(
|
|
137
|
+
MSv2Structure, table_factory, subtables, partition_schema, "def", True
|
|
136
138
|
)
|
|
137
139
|
|
|
138
140
|
assert structure_factory.instance is not structure_factory3.instance
|
|
139
141
|
|
|
140
142
|
|
|
141
143
|
def test_msv2_structure_release(simmed_ms):
|
|
142
|
-
|
|
144
|
+
def ncached_structures():
|
|
145
|
+
return sum(
|
|
146
|
+
isinstance(obj, MSv2Structure)
|
|
147
|
+
for obj, _, _, _ in Multiton._INSTANCE_CACHE.values()
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
assert ncached_structures() == 0
|
|
143
151
|
|
|
144
152
|
with xarray.open_datatree(simmed_ms):
|
|
145
|
-
assert
|
|
153
|
+
assert ncached_structures() > 0
|
|
146
154
|
|
|
147
|
-
assert
|
|
155
|
+
assert ncached_structures() == 0
|
|
@@ -15,8 +15,11 @@ from xarray.core.indexing import (
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
16
|
import numpy.typing as npt
|
|
17
17
|
|
|
18
|
-
from xarray_ms.backend.msv2.structure import
|
|
19
|
-
|
|
18
|
+
from xarray_ms.backend.msv2.structure import (
|
|
19
|
+
MainTableFactory,
|
|
20
|
+
MSv2StructureFactory,
|
|
21
|
+
PartitionKeyT,
|
|
22
|
+
)
|
|
20
23
|
|
|
21
24
|
TransformerT = Callable[[npt.NDArray], npt.NDArray]
|
|
22
25
|
|
|
@@ -73,7 +76,7 @@ class MainMSv2Array(MSv2Array):
|
|
|
73
76
|
"_transform",
|
|
74
77
|
)
|
|
75
78
|
|
|
76
|
-
_table_factory:
|
|
79
|
+
_table_factory: MainTableFactory
|
|
77
80
|
_structure_factory: MSv2StructureFactory
|
|
78
81
|
_partition: PartitionKeyT
|
|
79
82
|
_column: str
|
|
@@ -82,7 +85,7 @@ class MainMSv2Array(MSv2Array):
|
|
|
82
85
|
|
|
83
86
|
def __init__(
|
|
84
87
|
self,
|
|
85
|
-
table_factory:
|
|
88
|
+
table_factory: MainTableFactory,
|
|
86
89
|
structure_factory: MSv2StructureFactory,
|
|
87
90
|
partition: PartitionKeyT,
|
|
88
91
|
column: str,
|
|
@@ -25,13 +25,8 @@ from xarray_ms.backend.msv2.structure import (
|
|
|
25
25
|
MSv2Structure,
|
|
26
26
|
MSv2StructureFactory,
|
|
27
27
|
)
|
|
28
|
-
from xarray_ms.errors import
|
|
29
|
-
FrameConversionWarning,
|
|
30
|
-
IgnoredArgument,
|
|
31
|
-
InvalidPartitionKey,
|
|
32
|
-
)
|
|
28
|
+
from xarray_ms.errors import FrameConversionWarning, InvalidPartitionKey
|
|
33
29
|
from xarray_ms.msv4_types import CORRELATED_DATASET_TYPES
|
|
34
|
-
from xarray_ms.multiton import Multiton
|
|
35
30
|
from xarray_ms.utils import format_docstring
|
|
36
31
|
|
|
37
32
|
if TYPE_CHECKING:
|
|
@@ -39,7 +34,12 @@ if TYPE_CHECKING:
|
|
|
39
34
|
|
|
40
35
|
from xarray.backends.common import AbstractDataStore
|
|
41
36
|
|
|
42
|
-
from xarray_ms.backend.msv2.structure import
|
|
37
|
+
from xarray_ms.backend.msv2.structure import (
|
|
38
|
+
DEFAULT_PARTITION_COLUMNS,
|
|
39
|
+
MainTableFactory,
|
|
40
|
+
PartitionKeyT,
|
|
41
|
+
SubtableFactory,
|
|
42
|
+
)
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
def promote_chunks(
|
|
@@ -90,8 +90,8 @@ class MSv2Store(AbstractWritableDataStore):
|
|
|
90
90
|
"_epoch",
|
|
91
91
|
)
|
|
92
92
|
|
|
93
|
-
_table_factory:
|
|
94
|
-
_subtable_factories: Dict[str,
|
|
93
|
+
_table_factory: MainTableFactory
|
|
94
|
+
_subtable_factories: Dict[str, SubtableFactory]
|
|
95
95
|
_structure_factory: MSv2StructureFactory
|
|
96
96
|
_partition_schema: List[str]
|
|
97
97
|
_partition_key: PartitionKeyT
|
|
@@ -102,8 +102,8 @@ class MSv2Store(AbstractWritableDataStore):
|
|
|
102
102
|
|
|
103
103
|
def __init__(
|
|
104
104
|
self,
|
|
105
|
-
table_factory:
|
|
106
|
-
subtable_factories: Dict[str,
|
|
105
|
+
table_factory: MainTableFactory,
|
|
106
|
+
subtable_factories: Dict[str, SubtableFactory],
|
|
107
107
|
structure_factory: MSv2StructureFactory,
|
|
108
108
|
partition_schema: List[str],
|
|
109
109
|
partition_key: PartitionKeyT,
|
|
@@ -314,7 +314,6 @@ class MSv2EntryPoint(BackendEntrypoint):
|
|
|
314
314
|
auto_corrs: bool = False,
|
|
315
315
|
ninstances: int = 8,
|
|
316
316
|
epoch: str | None = None,
|
|
317
|
-
**kwargs,
|
|
318
317
|
) -> DataTree:
|
|
319
318
|
"""Create a :class:`~xarray.core.datatree.DataTree` presenting an MSv4 view
|
|
320
319
|
over multiple partitions of a MSv2 CASA Measurement Set.
|
|
@@ -370,7 +369,6 @@ class MSv2EntryPoint(BackendEntrypoint):
|
|
|
370
369
|
auto_corrs=auto_corrs,
|
|
371
370
|
ninstances=ninstances,
|
|
372
371
|
epoch=epoch,
|
|
373
|
-
**kwargs,
|
|
374
372
|
)
|
|
375
373
|
|
|
376
374
|
dt = DataTree.from_dict(groups_dict)
|
|
@@ -451,18 +449,10 @@ class MSv2EntryPoint(BackendEntrypoint):
|
|
|
451
449
|
ninstances: int = 8,
|
|
452
450
|
epoch: str | None = None,
|
|
453
451
|
structure_factory: MSv2StructureFactory | None = None,
|
|
454
|
-
**kwargs,
|
|
455
452
|
) -> Dict[str, Dataset]:
|
|
456
453
|
"""Create a dictionary of :class:`~xarray.Dataset` presenting an MSv4 view
|
|
457
454
|
over a partition of a MSv2 CASA Measurement Set"""
|
|
458
455
|
|
|
459
|
-
if kwargs:
|
|
460
|
-
warnings.warn(
|
|
461
|
-
f"xarray-ms does not support the following arguments and will ignore them: "
|
|
462
|
-
f"{sorted(kwargs)}",
|
|
463
|
-
IgnoredArgument,
|
|
464
|
-
)
|
|
465
|
-
|
|
466
456
|
if isinstance(filename_or_obj, os.PathLike):
|
|
467
457
|
ms = str(filename_or_obj)
|
|
468
458
|
elif isinstance(filename_or_obj, str):
|
|
@@ -4,12 +4,15 @@ from uuid import uuid4
|
|
|
4
4
|
|
|
5
5
|
import pyarrow as pa
|
|
6
6
|
from arcae.lib.arrow_tables import Table
|
|
7
|
+
from rarg_python_patterns.multiton import Multiton
|
|
7
8
|
|
|
8
9
|
from xarray_ms.backend.msv2.structure import (
|
|
9
10
|
DEFAULT_PARTITION_COLUMNS,
|
|
11
|
+
MainTableFactory,
|
|
12
|
+
MSv2Structure,
|
|
10
13
|
MSv2StructureFactory,
|
|
14
|
+
SubtableFactory,
|
|
11
15
|
)
|
|
12
|
-
from xarray_ms.multiton import Multiton
|
|
13
16
|
|
|
14
17
|
# These tables should always be present on an MS
|
|
15
18
|
DEFAULT_SUBTABLES = [
|
|
@@ -59,8 +62,8 @@ class CommonStoreArgs:
|
|
|
59
62
|
epoch: str
|
|
60
63
|
partition_schema: List[str]
|
|
61
64
|
preferred_chunks: Dict[str, int]
|
|
62
|
-
ms_factory:
|
|
63
|
-
subtable_factories: Dict[str,
|
|
65
|
+
ms_factory: MainTableFactory
|
|
66
|
+
subtable_factories: Dict[str, SubtableFactory]
|
|
64
67
|
structure_factory: MSv2StructureFactory
|
|
65
68
|
|
|
66
69
|
__slots__ = (
|
|
@@ -83,8 +86,8 @@ class CommonStoreArgs:
|
|
|
83
86
|
epoch: str | None = None,
|
|
84
87
|
partition_schema: List[str] | None = None,
|
|
85
88
|
preferred_chunks: Dict[str, int] | None = None,
|
|
86
|
-
ms_factory:
|
|
87
|
-
subtable_factories: Dict[str,
|
|
89
|
+
ms_factory: MainTableFactory | None = None,
|
|
90
|
+
subtable_factories: Dict[str, SubtableFactory] | None = None,
|
|
88
91
|
structure_factory: MSv2StructureFactory | None = None,
|
|
89
92
|
):
|
|
90
93
|
if not os.path.exists(ms):
|
|
@@ -107,7 +110,8 @@ class CommonStoreArgs:
|
|
|
107
110
|
subtable: Multiton(subtable_factory, f"{ms}::{subtable}")
|
|
108
111
|
for subtable in (DEFAULT_SUBTABLES + EXTRA_SUBTABLES)
|
|
109
112
|
}
|
|
110
|
-
self.structure_factory = structure_factory or
|
|
113
|
+
self.structure_factory = structure_factory or Multiton(
|
|
114
|
+
MSv2Structure,
|
|
111
115
|
self.ms_factory,
|
|
112
116
|
self.subtable_factories,
|
|
113
117
|
self.partition_schema,
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
from typing import Dict
|
|
2
2
|
|
|
3
|
-
from xarray_ms.backend.msv2.structure import
|
|
4
|
-
|
|
3
|
+
from xarray_ms.backend.msv2.structure import (
|
|
4
|
+
MSv2StructureFactory,
|
|
5
|
+
PartitionKeyT,
|
|
6
|
+
SubtableFactory,
|
|
7
|
+
)
|
|
5
8
|
|
|
6
9
|
|
|
7
10
|
class DatasetFactory:
|
|
@@ -10,13 +13,13 @@ class DatasetFactory:
|
|
|
10
13
|
|
|
11
14
|
_partition_key: PartitionKeyT
|
|
12
15
|
_structure_factory: MSv2StructureFactory
|
|
13
|
-
_subtable_factories: Dict[str,
|
|
16
|
+
_subtable_factories: Dict[str, SubtableFactory]
|
|
14
17
|
|
|
15
18
|
def __init__(
|
|
16
19
|
self,
|
|
17
20
|
partition_key: PartitionKeyT,
|
|
18
21
|
structure_factory: MSv2StructureFactory,
|
|
19
|
-
subtable_factories: Dict[str,
|
|
22
|
+
subtable_factories: Dict[str, SubtableFactory],
|
|
20
23
|
):
|
|
21
24
|
self._partition_key = partition_key
|
|
22
25
|
self._structure_factory = structure_factory
|
|
@@ -25,7 +25,12 @@ from xarray_ms.backend.msv2.measures_encoders import (
|
|
|
25
25
|
MSv2CoderFactory,
|
|
26
26
|
VisibilityCoder,
|
|
27
27
|
)
|
|
28
|
-
from xarray_ms.backend.msv2.structure import
|
|
28
|
+
from xarray_ms.backend.msv2.structure import (
|
|
29
|
+
MainTableFactory,
|
|
30
|
+
MSv2StructureFactory,
|
|
31
|
+
PartitionKeyT,
|
|
32
|
+
SubtableFactory,
|
|
33
|
+
)
|
|
29
34
|
from xarray_ms.backend.msv2.table_utils import unique_antenna_names
|
|
30
35
|
from xarray_ms.casa_types import ColumnDesc, Polarisations
|
|
31
36
|
from xarray_ms.errors import (
|
|
@@ -35,7 +40,6 @@ from xarray_ms.errors import (
|
|
|
35
40
|
IrregularChannelGridWarning,
|
|
36
41
|
IrregularTimeGridWarning,
|
|
37
42
|
)
|
|
38
|
-
from xarray_ms.multiton import Multiton
|
|
39
43
|
|
|
40
44
|
|
|
41
45
|
@dataclasses.dataclass
|
|
@@ -82,11 +86,11 @@ class CorrelatedFactory(DatasetFactory):
|
|
|
82
86
|
for a partition of the Measurement Set"""
|
|
83
87
|
|
|
84
88
|
_preferred_chunks: Dict[str, int]
|
|
85
|
-
_ms_factory:
|
|
86
|
-
_antenna_factory:
|
|
87
|
-
_spw_factory:
|
|
88
|
-
_pol_factory:
|
|
89
|
-
_obs_factory:
|
|
89
|
+
_ms_factory: MainTableFactory
|
|
90
|
+
_antenna_factory: SubtableFactory
|
|
91
|
+
_spw_factory: SubtableFactory
|
|
92
|
+
_pol_factory: SubtableFactory
|
|
93
|
+
_obs_factory: SubtableFactory
|
|
90
94
|
_main_table_desc: Dict[str, Collection[str]]
|
|
91
95
|
_coder_factory: MSv2CoderFactory
|
|
92
96
|
|
|
@@ -94,8 +98,8 @@ class CorrelatedFactory(DatasetFactory):
|
|
|
94
98
|
self,
|
|
95
99
|
partition_key: PartitionKeyT,
|
|
96
100
|
preferred_chunks: Dict[str, int],
|
|
97
|
-
ms_factory:
|
|
98
|
-
subtable_factories: Dict[str,
|
|
101
|
+
ms_factory: MainTableFactory,
|
|
102
|
+
subtable_factories: Dict[str, SubtableFactory],
|
|
99
103
|
structure_factory: MSv2StructureFactory,
|
|
100
104
|
):
|
|
101
105
|
super().__init__(partition_key, structure_factory, subtable_factories)
|
|
@@ -10,7 +10,6 @@ from functools import partial
|
|
|
10
10
|
from numbers import Integral
|
|
11
11
|
from typing import (
|
|
12
12
|
Any,
|
|
13
|
-
ClassVar,
|
|
14
13
|
Dict,
|
|
15
14
|
Iterator,
|
|
16
15
|
List,
|
|
@@ -19,13 +18,14 @@ from typing import (
|
|
|
19
18
|
Sequence,
|
|
20
19
|
Set,
|
|
21
20
|
Tuple,
|
|
21
|
+
TypeAlias,
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
import numpy as np
|
|
25
25
|
import numpy.typing as npt
|
|
26
26
|
import pyarrow as pa
|
|
27
27
|
from arcae.lib.arrow_tables import Table
|
|
28
|
-
from
|
|
28
|
+
from rarg_python_patterns.multiton import Multiton
|
|
29
29
|
|
|
30
30
|
from xarray_ms.backend.msv2.imputation import (
|
|
31
31
|
maybe_impute_field_table,
|
|
@@ -37,10 +37,18 @@ from xarray_ms.errors import (
|
|
|
37
37
|
InvalidPartitionKey,
|
|
38
38
|
PartitioningError,
|
|
39
39
|
)
|
|
40
|
-
from xarray_ms.multiton import Multiton
|
|
41
40
|
|
|
42
41
|
logger = logging.getLogger(__name__)
|
|
43
42
|
|
|
43
|
+
MainTableFactory: TypeAlias = Multiton[Table]
|
|
44
|
+
"""Multiton producing an arcae main-table :class:`~arcae.lib.arrow_tables.Table`."""
|
|
45
|
+
|
|
46
|
+
SubtableFactory: TypeAlias = Multiton[pa.Table]
|
|
47
|
+
"""Multiton producing a pyarrow :class:`~pyarrow.Table` subtable."""
|
|
48
|
+
|
|
49
|
+
MSv2StructureFactory: TypeAlias = Multiton["MSv2Structure"]
|
|
50
|
+
"""Multiton producing an :class:`MSv2Structure`."""
|
|
51
|
+
|
|
44
52
|
|
|
45
53
|
def nr_of_baselines(na: int, auto_corrs: bool = True) -> int:
|
|
46
54
|
"""Returns the number of baselines, given the number of antenna
|
|
@@ -227,96 +235,14 @@ class PartitionData:
|
|
|
227
235
|
return aids[a1], aids[a2]
|
|
228
236
|
|
|
229
237
|
|
|
230
|
-
def on_get_keep_alive(key, value, exists):
|
|
231
|
-
"""Reinsert to refresh the TTL for the entry on get operations"""
|
|
232
|
-
if exists:
|
|
233
|
-
MSv2StructureFactory._STRUCTURE_CACHE._set(key, value)
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
class MSv2StructureFactory:
|
|
237
|
-
"""Hashable, callable and picklable factory class
|
|
238
|
-
for creating and caching an MSv2Structure"""
|
|
239
|
-
|
|
240
|
-
_ms_factory: Multiton
|
|
241
|
-
_subtable_factories: Dict[str, Multiton]
|
|
242
|
-
_partition_schema: List[str]
|
|
243
|
-
_epoch: str
|
|
244
|
-
_auto_corrs: bool
|
|
245
|
-
_STRUCTURE_CACHE: ClassVar[Cache] = Cache(
|
|
246
|
-
maxsize=100, ttl=5 * 60, on_get=on_get_keep_alive
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
def __init__(
|
|
250
|
-
self,
|
|
251
|
-
ms: Multiton,
|
|
252
|
-
subtables: Dict[str, Multiton],
|
|
253
|
-
partition_schema: List[str],
|
|
254
|
-
epoch: str,
|
|
255
|
-
auto_corrs: bool,
|
|
256
|
-
):
|
|
257
|
-
self._ms_factory = ms
|
|
258
|
-
self._subtable_factories = subtables
|
|
259
|
-
self._partition_schema = partition_schema
|
|
260
|
-
self._epoch = epoch
|
|
261
|
-
self._auto_corrs = auto_corrs
|
|
262
|
-
|
|
263
|
-
def __eq__(self, other: Any) -> bool:
|
|
264
|
-
if not isinstance(other, MSv2StructureFactory):
|
|
265
|
-
return NotImplemented
|
|
266
|
-
|
|
267
|
-
return (
|
|
268
|
-
self._ms_factory == other._ms_factory
|
|
269
|
-
and self._subtable_factories == other._subtable_factories
|
|
270
|
-
and self._partition_schema == other._partition_schema
|
|
271
|
-
and self._epoch == other._epoch
|
|
272
|
-
and self._auto_corrs == other._auto_corrs
|
|
273
|
-
)
|
|
274
|
-
|
|
275
|
-
def __hash__(self):
|
|
276
|
-
return hash(
|
|
277
|
-
(
|
|
278
|
-
self._ms_factory,
|
|
279
|
-
frozenset(self._subtable_factories.items()),
|
|
280
|
-
tuple(self._partition_schema),
|
|
281
|
-
self._epoch,
|
|
282
|
-
self._auto_corrs,
|
|
283
|
-
)
|
|
284
|
-
)
|
|
285
|
-
|
|
286
|
-
def __reduce__(self):
|
|
287
|
-
return (
|
|
288
|
-
MSv2StructureFactory,
|
|
289
|
-
(
|
|
290
|
-
self._ms_factory,
|
|
291
|
-
self._subtable_factories,
|
|
292
|
-
self._partition_schema,
|
|
293
|
-
self._epoch,
|
|
294
|
-
self._auto_corrs,
|
|
295
|
-
),
|
|
296
|
-
)
|
|
297
|
-
|
|
298
|
-
@staticmethod
|
|
299
|
-
def _create_instance(self):
|
|
300
|
-
return MSv2Structure(
|
|
301
|
-
self._ms_factory,
|
|
302
|
-
self._subtable_factories,
|
|
303
|
-
self._partition_schema,
|
|
304
|
-
self._auto_corrs,
|
|
305
|
-
)
|
|
306
|
-
|
|
307
|
-
@property
|
|
308
|
-
def instance(self) -> MSv2Structure:
|
|
309
|
-
return self._STRUCTURE_CACHE.get(self, self._create_instance)
|
|
310
|
-
|
|
311
|
-
def release(self) -> bool:
|
|
312
|
-
return self._STRUCTURE_CACHE.delete(self) > 0
|
|
313
|
-
|
|
314
|
-
|
|
315
238
|
class MSv2Structure(Mapping):
|
|
316
239
|
"""Holds structural information about an MSv2 dataset"""
|
|
317
240
|
|
|
318
|
-
_ms_factory:
|
|
319
|
-
_subtable_factories: Dict[str,
|
|
241
|
+
_ms_factory: MainTableFactory
|
|
242
|
+
_subtable_factories: Dict[str, SubtableFactory]
|
|
243
|
+
# Not used internally, but distinguishes Multiton keys so that
|
|
244
|
+
# different epochs force regeneration of the same structure
|
|
245
|
+
_epoch: str
|
|
320
246
|
_partition_columns: List[str]
|
|
321
247
|
_subtable_partition_columns: List[str]
|
|
322
248
|
_partitions: Mapping[PartitionKeyT, PartitionData]
|
|
@@ -606,9 +532,10 @@ class MSv2Structure(Mapping):
|
|
|
606
532
|
|
|
607
533
|
def __init__(
|
|
608
534
|
self,
|
|
609
|
-
ms:
|
|
610
|
-
subtable_factories: Dict[str,
|
|
535
|
+
ms: MainTableFactory,
|
|
536
|
+
subtable_factories: Dict[str, SubtableFactory],
|
|
611
537
|
partition_schema: List[str],
|
|
538
|
+
epoch: str,
|
|
612
539
|
auto_corrs: bool,
|
|
613
540
|
):
|
|
614
541
|
import time as modtime
|
|
@@ -621,6 +548,7 @@ class MSv2Structure(Mapping):
|
|
|
621
548
|
|
|
622
549
|
self._ms_factory = ms
|
|
623
550
|
self._subtable_factories = subtable_factories
|
|
551
|
+
self._epoch = epoch
|
|
624
552
|
self._partition_columns = partition_columns
|
|
625
553
|
self._subtable_partition_columns = subtable_columns
|
|
626
554
|
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import pickle
|
|
2
|
-
|
|
3
|
-
import xarray
|
|
4
|
-
from arcae.lib.arrow_tables import Table
|
|
5
|
-
|
|
6
|
-
from xarray_ms.multiton import Multiton
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def test_multiton_duplicate_args(simmed_ms):
|
|
10
|
-
"""Tests that when opened with duplicate arguments,
|
|
11
|
-
the same Multiton is returned"""
|
|
12
|
-
|
|
13
|
-
multiton = Multiton(Table.from_filename, simmed_ms, readonly=False)
|
|
14
|
-
data = multiton.instance.getcol("DATA")
|
|
15
|
-
assert data.shape == (30, 8, 4)
|
|
16
|
-
assert set(multiton._INSTANCE_CACHE.keys()) == {multiton}
|
|
17
|
-
|
|
18
|
-
multiton2 = Multiton(Table.from_filename, simmed_ms, readonly=False)
|
|
19
|
-
assert multiton2.instance is multiton.instance
|
|
20
|
-
assert set(multiton._INSTANCE_CACHE.keys()) == {multiton}
|
|
21
|
-
|
|
22
|
-
multiton3 = Multiton(Table.from_filename, simmed_ms)
|
|
23
|
-
assert multiton3.instance is not multiton.instance
|
|
24
|
-
assert multiton3.instance is not multiton2.instance
|
|
25
|
-
assert set(multiton._INSTANCE_CACHE.keys()) == {multiton, multiton3}
|
|
26
|
-
|
|
27
|
-
# Check the positional args passed as kwargs are normalised
|
|
28
|
-
# as positional args
|
|
29
|
-
multiton4 = Multiton(Table.from_filename, filename=simmed_ms, readonly=False)
|
|
30
|
-
assert multiton4.instance is multiton.instance
|
|
31
|
-
assert multiton4.instance is multiton2.instance
|
|
32
|
-
assert multiton4.instance is not multiton3.instance
|
|
33
|
-
assert set(multiton._INSTANCE_CACHE.keys()) == {multiton, multiton3}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def test_multiton_release():
|
|
37
|
-
data = {"closed": False}
|
|
38
|
-
|
|
39
|
-
class A:
|
|
40
|
-
def close(self):
|
|
41
|
-
data["closed"] = True
|
|
42
|
-
|
|
43
|
-
multiton = Multiton(A)
|
|
44
|
-
multiton.instance
|
|
45
|
-
assert set(multiton._INSTANCE_CACHE.keys()) == {multiton}
|
|
46
|
-
multiton.release()
|
|
47
|
-
assert set(multiton._INSTANCE_CACHE.keys()) == set()
|
|
48
|
-
assert data["closed"] is True
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def test_multiton_datatree_release(simmed_ms):
|
|
52
|
-
assert len(Multiton._INSTANCE_CACHE) == 0
|
|
53
|
-
|
|
54
|
-
with xarray.open_datatree(simmed_ms):
|
|
55
|
-
assert len(Multiton._INSTANCE_CACHE) > 0
|
|
56
|
-
|
|
57
|
-
assert len(Multiton._INSTANCE_CACHE) == 0
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def test_multiton_pickling(simmed_ms):
|
|
61
|
-
"""Test that a pickle roundtrip of the Multiton results in the same object"""
|
|
62
|
-
|
|
63
|
-
multiton = Multiton(Table.from_filename, simmed_ms)
|
|
64
|
-
data = multiton.instance.getcol("DATA")
|
|
65
|
-
assert data.shape == (30, 8, 4)
|
|
66
|
-
assert set(multiton._INSTANCE_CACHE.keys()) == {multiton}
|
|
67
|
-
|
|
68
|
-
multiton2 = pickle.loads(pickle.dumps(multiton))
|
|
69
|
-
assert multiton.instance is multiton2.instance
|
|
70
|
-
assert set(multiton._INSTANCE_CACHE.keys()) == {multiton}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import Any, Callable, ClassVar, Mapping, Tuple
|
|
4
|
-
|
|
5
|
-
from cacheout import Cache
|
|
6
|
-
|
|
7
|
-
from xarray_ms.utils import FrozenKey, normalise_args
|
|
8
|
-
|
|
9
|
-
FactoryFunctionT = Callable[..., Any]
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def on_get_keep_alive(key, value, exists):
|
|
13
|
-
"""Re-insert on get to update the TTL"""
|
|
14
|
-
if exists:
|
|
15
|
-
# Re-insert to update the TTL
|
|
16
|
-
Multiton._INSTANCE_CACHE.set(key, value)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def on_instance_delete(key, value, cause):
|
|
20
|
-
"""Invoke any instance close methods on deletion"""
|
|
21
|
-
if hasattr(value, "close") and callable(value.close):
|
|
22
|
-
value.close()
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class Multiton:
|
|
26
|
-
"""Hashable and pickleable factory class
|
|
27
|
-
for creating and caching an object instance"""
|
|
28
|
-
|
|
29
|
-
_INSTANCE_CACHE: ClassVar[Cache] = Cache(
|
|
30
|
-
maxsize=100, ttl=5 * 60, on_get=on_get_keep_alive, on_delete=on_instance_delete
|
|
31
|
-
)
|
|
32
|
-
_factory: FactoryFunctionT
|
|
33
|
-
_args: Tuple[Any, ...]
|
|
34
|
-
_kw: Mapping[str, Any]
|
|
35
|
-
_key: FrozenKey
|
|
36
|
-
|
|
37
|
-
def __init__(self, factory: FactoryFunctionT, *args: Any, **kw: Any):
|
|
38
|
-
self._factory = factory
|
|
39
|
-
self._args, self._kw = normalise_args(factory, args, kw)
|
|
40
|
-
self._key = FrozenKey(factory, *self._args, **self._kw)
|
|
41
|
-
|
|
42
|
-
@staticmethod
|
|
43
|
-
def from_reduce_args(
|
|
44
|
-
factory: FactoryFunctionT, args: Tuple[Any, ...], kw: Mapping[str, Any]
|
|
45
|
-
) -> Multiton:
|
|
46
|
-
return Multiton(factory, *args, **kw)
|
|
47
|
-
|
|
48
|
-
def __reduce__(
|
|
49
|
-
self,
|
|
50
|
-
) -> Tuple[Callable, Tuple[Callable, Tuple[Any, ...], Mapping[str, Any]]]:
|
|
51
|
-
return (self.from_reduce_args, (self._factory, self._args, self._kw))
|
|
52
|
-
|
|
53
|
-
def __hash__(self) -> int:
|
|
54
|
-
return hash(self._key)
|
|
55
|
-
|
|
56
|
-
def __eq__(self, other: Any) -> bool:
|
|
57
|
-
if not isinstance(other, Multiton):
|
|
58
|
-
return NotImplemented
|
|
59
|
-
return self._key == other._key
|
|
60
|
-
|
|
61
|
-
@staticmethod
|
|
62
|
-
def _create_instance(self) -> Any:
|
|
63
|
-
return self._factory(*self._args, **self._kw)
|
|
64
|
-
|
|
65
|
-
@property
|
|
66
|
-
def instance(self) -> Any:
|
|
67
|
-
"""Create the object instance represented by the Multiton,
|
|
68
|
-
or retrieved the cache instance"""
|
|
69
|
-
return self._INSTANCE_CACHE.get(self, self._create_instance)
|
|
70
|
-
|
|
71
|
-
def release(self) -> bool:
|
|
72
|
-
"""Evict any cached instance associated with this Multiton"""
|
|
73
|
-
return self._INSTANCE_CACHE.delete(self) > 0
|
|
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
|
|
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
|