Skip to content

Commit fd63a62

Browse files
authored
Merge pull request #14701 from Mubin17/Issue#12355
#12355 Issue: Register latex to Cosmology.write
2 parents a429c39 + 733510b commit fd63a62

6 files changed

Lines changed: 187 additions & 1 deletion

File tree

‎astropy/cosmology/io/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
"""
66

77
# Import to register with the I/O machinery
8-
from . import cosmology, ecsv, html, mapping, model, row, table, yaml
8+
from . import cosmology, ecsv, html, mapping, model, row, table, yaml, latex

‎astropy/cosmology/io/latex.py‎

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import astropy.units as u
2+
from astropy.cosmology.connect import readwrite_registry
3+
from astropy.cosmology.core import Cosmology
4+
from astropy.cosmology.parameter import Parameter
5+
from astropy.table import QTable
6+
7+
8+
from .table import to_table
9+
10+
_FORMAT_TABLE = {
11+
"H0": "$$H_0$$",
12+
"Om0": "$$\\Omega_{m,0}$$",
13+
"Ode0": "$$\\Omega_{\\Lambda,0}$$",
14+
"Tcmb0": "$$T_{0}$$",
15+
"Neff": "$$N_{eff}$$",
16+
"m_nu": "$$m_{nu}$$",
17+
"Ob0": "$$\\Omega_{b,0}$$",
18+
"w0": "$$w_{0}$$",
19+
"wa": "$$w_{a}$$",
20+
"wz": "$$w_{z}$$",
21+
"wp": "$$w_{p}$$",
22+
"zp": "$$z_{p}$$",
23+
}
24+
25+
26+
def write_latex(
27+
cosmology, file, *, overwrite=False, cls=QTable, latex_names=True, **kwargs
28+
):
29+
r"""Serialize the |Cosmology| into a LaTeX.
30+
31+
Parameters
32+
----------
33+
cosmology : `~astropy.cosmology.Cosmology` subclass instance
34+
file : path-like or file-like
35+
Location to save the serialized cosmology.
36+
37+
overwrite : bool
38+
Whether to overwrite the file, if it exists.
39+
cls : type, optional keyword-only
40+
Astropy :class:`~astropy.table.Table` (sub)class to use when writing.
41+
Default is :class:`~astropy.table.QTable`.
42+
latex_names : bool, optional keyword-only
43+
Whether to use LaTeX names for the parameters. Default is `True`.
44+
**kwargs
45+
Passed to ``cls.write``
46+
47+
Raises
48+
------
49+
TypeError
50+
If kwarg (optional) 'cls' is not a subclass of `astropy.table.Table`
51+
"""
52+
# Check that the format is 'latex' (or not specified)
53+
format = kwargs.pop("format", "latex")
54+
if format != "latex":
55+
raise ValueError(f"format must be 'latex', not {format}")
56+
57+
# Set cosmology_in_meta as false for now since there is no metadata being kept
58+
table = to_table(cosmology, cls=cls, cosmology_in_meta=False)
59+
60+
cosmo_cls = type(cosmology)
61+
for name, col in table.columns.copy().items():
62+
param = getattr(cosmo_cls, name, None)
63+
if not isinstance(param, Parameter) or param.unit in (None, u.one):
64+
continue
65+
# Get column to correct unit
66+
table[name] <<= param.unit
67+
68+
# Convert parameter names to LaTeX format
69+
if latex_names:
70+
new_names = [_FORMAT_TABLE.get(k, k) for k in cosmology.__parameters__]
71+
table.rename_columns(cosmology.__parameters__, new_names)
72+
73+
table.write(file, overwrite=overwrite, format="latex", **kwargs)
74+
75+
76+
# ===================================================================
77+
# Register
78+
79+
readwrite_registry.register_writer("latex", Cosmology, write_latex)
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Licensed under a 3-clause BSD style license - see LICENSE.rst
2+
3+
# THIRD PARTY
4+
import pytest
5+
6+
# LOCAL
7+
from astropy.cosmology.io.latex import _FORMAT_TABLE, write_latex
8+
from astropy.table import QTable, Table
9+
10+
from .base import ReadWriteDirectTestBase, ReadWriteTestMixinBase
11+
12+
13+
class WriteLATEXTestMixin(ReadWriteTestMixinBase):
14+
"""
15+
Tests for a Cosmology[Write] with ``format="latex"``.
16+
This class will not be directly called by :mod:`pytest` since its name does
17+
not begin with ``Test``. To activate the contained tests this class must
18+
be inherited in a subclass. Subclasses must dfine a :func:`pytest.fixture`
19+
``cosmo`` that returns/yields an instance of a |Cosmology|.
20+
See ``TestCosmology`` for an example.
21+
"""
22+
23+
def test_to_latex_failed_cls(self, write, tmp_path):
24+
"""Test failed table type."""
25+
fp = tmp_path / "test_to_latex_failed_cls.tex"
26+
27+
with pytest.raises(TypeError, match="'cls' must be"):
28+
write(fp, format="latex", cls=list)
29+
30+
@pytest.mark.parametrize("tbl_cls", [QTable, Table])
31+
def test_to_latex_cls(self, write, tbl_cls, tmp_path):
32+
fp = tmp_path / "test_to_latex_cls.tex"
33+
write(fp, format="latex", cls=tbl_cls)
34+
35+
def test_latex_columns(self, write, tmp_path):
36+
fp = tmp_path / "test_rename_latex_columns.tex"
37+
write(fp, format="latex", latex_names=True)
38+
tbl = QTable.read(fp)
39+
# asserts each column name has not been reverted yet
40+
# For now, Cosmology class and name are stored in first 2 slots
41+
for column_name in tbl.colnames[2:]:
42+
assert column_name in _FORMAT_TABLE.values()
43+
44+
def test_write_latex_invalid_path(self, write):
45+
"""Test passing an invalid path"""
46+
invalid_fp = ""
47+
with pytest.raises(FileNotFoundError, match="No such file or directory"):
48+
write(invalid_fp, format="latex")
49+
50+
def test_write_latex_false_overwrite(self, write, tmp_path):
51+
"""Test to write a LaTeX file without overwriting an existing file"""
52+
# Test that passing an invalid path to write_latex() raises a IOError
53+
fp = tmp_path / "test_write_latex_false_overwrite.tex"
54+
write(fp, format="latex")
55+
with pytest.raises(OSError, match="overwrite=True"):
56+
write(fp, format="latex", overwrite=False)
57+
58+
59+
class TestReadWriteLaTex(ReadWriteDirectTestBase, WriteLATEXTestMixin):
60+
"""
61+
Directly test ``write_latex``.
62+
These are not public API and are discouraged from use, in favor of
63+
``Cosmology.write(..., format="latex")``, but should be
64+
tested regardless b/c they are used internally.
65+
"""
66+
67+
def setup_class(self):
68+
self.functions = {"write": write_latex}
69+
70+
def test_rename_direct_latex_columns(self, write, tmp_path):
71+
"""Tests renaming columns"""
72+
fp = tmp_path / "test_rename_latex_columns.tex"
73+
write(fp, format="latex", latex_names=True)
74+
tbl = QTable.read(fp)
75+
# asserts each column name has not been reverted yet
76+
for column_name in tbl.colnames[2:]:
77+
# for now, Cosmology as metadata and name is stored in first 2 slots
78+
assert column_name in _FORMAT_TABLE.values()

‎astropy/cosmology/tests/test_connect.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
test_row,
1919
test_table,
2020
test_yaml,
21+
test_latex,
2122
)
2223
from astropy.table import QTable, Row
2324
from astropy.utils.compat.optional_deps import HAS_BS4
@@ -33,6 +34,7 @@
3334
("ascii.ecsv", True, True),
3435
("ascii.html", False, HAS_BS4),
3536
("json", True, True),
37+
("latex", False, True),
3638
}
3739

3840

@@ -55,6 +57,7 @@ class ReadWriteTestMixin(
5557
test_ecsv.ReadWriteECSVTestMixin,
5658
test_html.ReadWriteHTMLTestMixin,
5759
test_json.ReadWriteJSONTestMixin,
60+
test_latex.WriteLATEXTestMixin,
5861
):
5962
"""
6063
Tests for a CosmologyRead/Write on a |Cosmology|.
@@ -75,6 +78,8 @@ def test_readwrite_complete_info(self, cosmo, tmp_path, format, metaio, has_deps
7578
"""
7679
if not has_deps:
7780
pytest.skip("missing a dependency")
81+
if (format, Cosmology) not in readwrite_registry._readers:
82+
pytest.xfail(f"no read method is registered for format {format!r}")
7883

7984
fname = str(tmp_path / f"{cosmo.name}.{format}")
8085
cosmo.write(fname, format=format)
@@ -103,6 +108,8 @@ def test_readwrite_from_subclass_complete_info(
103108
"""
104109
if not has_deps:
105110
pytest.skip("missing a dependency")
111+
if (format, Cosmology) not in readwrite_registry._readers:
112+
pytest.xfail(f"no read method is registered for format {format!r}")
106113

107114
fname = str(tmp_path / f"{cosmo.name}.{format}")
108115
cosmo.write(fname, format=format)
@@ -140,6 +147,8 @@ def cosmo_cls(self, cosmo):
140147
def test_write_methods_have_explicit_kwarg_overwrite(self, format, _, has_deps):
141148
if not has_deps:
142149
pytest.skip("missing a dependency")
150+
if (format, Cosmology) not in readwrite_registry._readers:
151+
pytest.xfail(f"no read method is registered for format {format!r}")
143152

144153
writer = readwrite_registry.get_writer(format, Cosmology)
145154
# test in signature
@@ -156,6 +165,8 @@ def test_readwrite_reader_class_mismatch(
156165
"""Test when the reader class doesn't match the file."""
157166
if not has_deps:
158167
pytest.skip("missing a dependency")
168+
if (format, Cosmology) not in readwrite_registry._readers:
169+
pytest.xfail(f"no read method is registered for format {format!r}")
159170

160171
fname = tmp_path / f"{cosmo.name}.{format}"
161172
cosmo.write(fname, format=format)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added a ``write_latex()`` method for exporting a Cosmology object to a LaTex table.

‎docs/whatsnew/6.0.rst‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ the 5.3 release.
1313
In particular, this release includes:
1414

1515
* :ref:`whatsnew-6.0-geodetic-representation-geometry`
16+
* :ref:`whatsnew-6.0-cosmology-latex-export`
1617

1718
In addition to these major changes, Astropy v6.0 includes a large number of
1819
smaller improvements and bug fixes, which are described in the :ref:`changelog`.
@@ -48,6 +49,22 @@ bodies by subclassing `~astropy.coordinates.BaseGeodeticRepresentation` and defi
4849

4950
See :ref:`astropy-coordinates-create-geodetic` for more details.
5051

52+
53+
.. _whatsnew-6.0-cosmology-latex-export:
54+
55+
Updates to `~astropy.cosmology`
56+
===============================
57+
58+
The :class:`~astropy.cosmology.Cosmology` class in :mod:`~astropy.cosmology` now
59+
supports the latex format in its :attr:`~astropy.cosmology.Cosmology.write()`
60+
method, allowing users to export a cosmology object to a LaTeX table.::
61+
62+
>>> from astropy.cosmology import Planck18
63+
>>> Planck18.write("example_cosmology.tex", format="latex")
64+
65+
This will write the cosmology object to a file in LaTeX format,
66+
with appropriate formatting of units and table alignment.
67+
5168
Full change log
5269
===============
5370

0 commit comments

Comments
 (0)