summaryrefslogtreecommitdiff
path: root/pint
diff options
context:
space:
mode:
authorHernan Grecco <hgrecco@gmail.com>2023-04-25 01:29:04 -0300
committerHernan Grecco <hgrecco@gmail.com>2023-04-25 01:29:04 -0300
commit70e1b2590bdb7a7e4c0941a0a75c57d78a2ea01b (patch)
tree91e5dee776a45a1ac3b3fb95f1289a61f2135edd /pint
parent5794ffb8ae25e89ec57fa6e1743c6eafe69e4c0c (diff)
parent4357104a645e90b937a54318f4b5574f7282129f (diff)
downloadpint-70e1b2590bdb7a7e4c0941a0a75c57d78a2ea01b.tar.gz
Merge branch 'pr/1712'
Diffstat (limited to 'pint')
-rw-r--r--pint/formatting.py19
-rw-r--r--pint/testsuite/test_unit.py27
2 files changed, 45 insertions, 1 deletions
diff --git a/pint/formatting.py b/pint/formatting.py
index 554b381..f450d5f 100644
--- a/pint/formatting.py
+++ b/pint/formatting.py
@@ -10,6 +10,7 @@
from __future__ import annotations
+import functools
import re
import warnings
from typing import Callable, Dict
@@ -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(),
diff --git a/pint/testsuite/test_unit.py b/pint/testsuite/test_unit.py
index ee1a5ee..98a4fcc 100644
--- a/pint/testsuite/test_unit.py
+++ b/pint/testsuite/test_unit.py
@@ -54,6 +54,33 @@ class TestUnit(QuantityTestCase):
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))