Skip to content

Commit

Permalink
Merge branch 'pr/1712'
Browse files Browse the repository at this point in the history
  • Loading branch information
hgrecco committed Apr 25, 2023
2 parents 5794ffb + 4357104 commit 70e1b25
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ Pint Changelog
- Parse '°' along with previous text, rather than adding a space,
allowing, eg 'Δ°C' as a unit.
(PR #1729)
- Improved escaping of special characters for LaTeX format
(PR #1712)
- Avoid addition of spurious trailing zeros when converting units and non-int-type is
Decimal (PR #1625).
- Implementation for numpy.delete added for Quantity.
Expand All @@ -34,6 +36,7 @@ Pint Changelog
(PR #1722)
- Added Townsend unit
(PR #1738)


### Breaking Changes

Expand Down
19 changes: 18 additions & 1 deletion pint/formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from __future__ import annotations

import functools
import re
import warnings
from typing import Callable, Dict
Expand Down Expand Up @@ -178,10 +179,26 @@ def format_pretty(unit, registry, **options):
)


def latex_escape(string):
"""
Prepend characters that have a special meaning in LaTeX with a backslash.
"""
return functools.reduce(
lambda s, m: re.sub(m[0], m[1], s),
(
(r"[\\]", r"\\textbackslash "),
(r"[~]", r"\\textasciitilde "),
(r"[\^]", r"\\textasciicircum "),
(r"([&%$#_{}])", r"\\\1"),
),
str(string),
)


@register_unit_format("L")
def format_latex(unit, registry, **options):
preprocessed = {
r"\mathrm{{{}}}".format(u.replace("_", r"\_")): p for u, p in unit.items()
r"\mathrm{{{}}}".format(latex_escape(u)): p for u, p in unit.items()
}
formatted = formatter(
preprocessed.items(),
Expand Down
27 changes: 27 additions & 0 deletions pint/testsuite/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,33 @@ def test_unit_formatting(self, subtests):
with subtests.test(spec):
assert spec.format(x) == result

def test_latex_escaping(self, subtests):
ureg = UnitRegistry()
ureg.define(r"percent = 1e-2 = %")
x = ureg.Unit(UnitsContainer(percent=1))
for spec, result in {
"L": r"\mathrm{percent}",
"L~": r"\mathrm{\%}",
"Lx": r"\si[]{\percent}",
"Lx~": r"\si[]{\%}",
}.items():
with subtests.test(spec):
ureg.default_format = spec
assert f"{x}" == result, f"Failed for {spec}, {result}"
# no '#' here as it's a comment char when define()ing new units
ureg.define(r"weirdunit = 1 = \~_^&%$_{}")
x = ureg.Unit(UnitsContainer(weirdunit=1))
for spec, result in {
"L": r"\mathrm{weirdunit}",
"L~": r"\mathrm{\textbackslash \textasciitilde \_\textasciicircum \&\%\$\_\{\}}",
"Lx": r"\si[]{\weirdunit}",
# TODO: Currently makes \si[]{\\~_^&%$_{}} (broken). What do we even want this to be?
# "Lx~": r"\si[]{\textbackslash \textasciitilde \_\textasciicircum \&\%\$\_\{\}}",
}.items():
with subtests.test(spec):
ureg.default_format = spec
assert f"{x}" == result, f"Failed for {spec}, {result}"

def test_unit_default_formatting(self, subtests):
ureg = UnitRegistry()
x = ureg.Unit(UnitsContainer(meter=2, kilogram=1, second=-1))
Expand Down

0 comments on commit 70e1b25

Please sign in to comment.