Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions astropy/units/function/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ def __pow__(self, power):
def __pos__(self):
return self._copy()

def to_string(self, format="generic"):
def to_string(self, format="generic", **kwargs):
"""
Output the unit in the given format as a string.

Expand All @@ -391,23 +391,51 @@ def to_string(self, format="generic"):
The name of a format or a formatter object. If not
provided, defaults to the generic format.
"""
if format not in ("generic", "unscaled", "latex", "latex_inline"):
supported_formats = (
"generic",
"unscaled",
"latex",
"latex_inline",
"unicode",
"console",
)
if format not in supported_formats:
raise ValueError(
f"Function units cannot be written in {format} "
"format. Only 'generic', 'unscaled', 'latex' and "
"'latex_inline' are supported."
f"format. Only {', '.join(supported_formats)} are supported."
)
self_str = self.function_unit.to_string(format)
pu_str = self.physical_unit.to_string(format)
self_str = self.function_unit.to_string(format, **kwargs)
pu_str = self.physical_unit.to_string(format, **kwargs)
if pu_str == "":
pu_str = "1"
if format.startswith("latex"):
# need to strip leading and trailing "$"
self_str += rf"$\mathrm{{\left( {pu_str[1:-1]} \right)}}$"
else:
self_str += f"({pu_str})"
pu_lines = pu_str.splitlines()
if len(pu_lines) == 1:
self_str += f"({pu_str})"
else:
# If the physical unit is formatted into a multiline
Comment thread
olebole marked this conversation as resolved.
Resolved
# string, the lines need to be adjusted so that the
# functional string is aligned with the fraction line
# (second one), and all other lines are indented
# accordingly.
f = f"{{0:^{len(self_str)+1}s}}{{1:s}}"
lines = [
f.format("", pu_lines[0]),
f.format(f"{self_str}(", f"{pu_lines[1]})"),
] + [f.format("", line) for line in pu_lines[2:]]
self_str = "\n".join(lines)
return self_str

def __format__(self, format_spec):
"""Try to format units using a formatter."""
try:
return self.to_string(format=format_spec)
except ValueError:
return format(str(self), format_spec)

def __str__(self):
"""Return string representation for unit."""
self_str = str(self.function_unit)
Expand Down
30 changes: 30 additions & 0 deletions astropy/units/tests/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -818,3 +818,33 @@ def test_celsius_fits():
assert u.Unit("deg C kg-1", format="fits") == u.C * u.deg / u.kg
assert u.Unit("Celsius kg-1", format="fits") == u.deg_C / u.kg
assert u.deg_C.to_string("fits") == "Celsius"


@pytest.mark.parametrize(
"format_spec, string",
[
("generic", "dB(1 / m)"),
("unscaled", "dB(1 / m)"),
("latex", r"$\mathrm{dB}$$\mathrm{\left( \mathrm{\frac{1}{m}} \right)}$"),
("latex_inline", r"$\mathrm{dB}$$\mathrm{\left( \mathrm{m^{-1}} \right)}$"),
("console", "dB(m^-1)"),
("unicode", "dB(m⁻¹)"),
],
)
def test_function_format_styles(format_spec, string):
dbunit = u.decibel(u.m**-1)
assert dbunit.to_string(format_spec) == string
assert f"{dbunit:{format_spec}}" == string


@pytest.mark.parametrize(
"format_spec, inline, string",
[
("console", False, " 1\ndB( -)\n m"),
("unicode", False, " 1\ndB( ─)\n m"),
("latex", True, r"$\mathrm{dB}$$\mathrm{\left( \mathrm{m^{-1}} \right)}$"),
],
)
def test_function_format_styles_inline(format_spec, inline, string):
dbunit = u.decibel(u.m**-1)
assert dbunit.to_string(format_spec, inline=inline) == string
2 changes: 2 additions & 0 deletions docs/changes/units/14407.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Allow "console" and "unicode" formats for conversion to string of
function units.