Skip to content

Commit 4d81399

Browse files
committed
Fix parsing of ucum unit with prefixes
This also fixes an undesired fixture modification in one test.
1 parent 67f4b5b commit 4d81399

File tree

2 files changed

+25
-5
lines changed

2 files changed

+25
-5
lines changed

src/ucumvert/ucum_pint.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,12 @@ def component(self, args):
152152
def simple_unit(self, args):
153153
# print("DBGsu>", repr(args), len(args))
154154
if len(args) == 2: # prefix is present # noqa: PLR2004
155-
return self.ureg(args[0] + args[1])
155+
# Work around a pint bug: parsing of abbreviated custom unit with prefix
156+
# that could be a unit (k,m,M) does not detect the prefix but 2 units.
157+
# e.g. m[IU] --> <Quantity(1, 'meter * [IU]')> instead of <Quantity(1, 'milli[IU]')>
158+
# Therefore, this fails (pint 0.23):
159+
# return self.ureg(args[0] + args[1])
160+
return self.ureg(args[0] + str(self.ureg(args[1]).units))
156161

157162
# Substitute UCUM atoms that cannot be defined in pint as units or aliases.
158163
return self.ureg(MAPPINGS_UCUM_TO_PINT.get(args[0], args[0]))

tests/test_ucum_pint.py

+19-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from pathlib import Path
2+
13
import pytest
24
from lark import LarkError
35
from pint import UnitRegistry
@@ -12,8 +14,6 @@
1214
from ucumvert.ucum_pint import find_ucum_codes_that_need_mapping
1315
from ucumvert.xml_util import get_metric_units, get_non_metric_units
1416

15-
ureg = UnitRegistry()
16-
1717

1818
def get_unit_atoms():
1919
"""List of all case-sensitive defined UCUM units in ucum-essence.xml"""
@@ -28,7 +28,7 @@ def test_find_ucum_codes_that_need_mapping():
2828

2929

3030
def test_ucum_to_pint(ucum_parser, ureg_std):
31-
expected_quantity = ureg("kilogram")
31+
expected_quantity = ureg_std("kilogram")
3232
parsed_data = ucum_parser.parse("kg")
3333
result = UcumToPintTransformer(ureg=ureg_std).transform(parsed_data)
3434
assert result == expected_quantity
@@ -99,7 +99,11 @@ def test_ucum_all_unit_atoms_pint_vs_str(
9999
assert ureg_ucumvert(result_str) == expected_quantity
100100

101101

102-
def test_ucum_preprocessor(ureg_ucumvert):
102+
def test_ucum_preprocessor():
103+
# Don't use ureg_ucumvert from fixture here, because we want to modify it.
104+
defdir = Path(__file__).resolve().parents[1] / "src" / "ucumvert"
105+
ureg_ucumvert = UnitRegistry()
106+
ureg_ucumvert.load_definitions(defdir / "pint_ucum_defs.txt")
103107
expected = ureg_ucumvert("m*kg")
104108
ureg_ucumvert.preprocessors.append(ucum_preprocessor)
105109
assert ureg_ucumvert("m.kg") == expected
@@ -111,3 +115,14 @@ def test_ucum_unitregistry():
111115
ureg = PintUcumRegistry()
112116
assert ureg.from_ucum("m.kg") == ureg("m*kg")
113117
assert ureg.from_ucum("Cel") == ureg("degC")
118+
119+
120+
def test_prefix_with_unit_that_is_also_a_prefix_issue24(ucum_parser, ureg_ucumvert):
121+
parsed_data = ucum_parser.parse("m[IU]/L")
122+
123+
expected_quantity = ureg_ucumvert("milliinternational_unit/liter")
124+
assert expected_quantity == UcumToPintTransformer().transform(parsed_data)
125+
assert expected_quantity == 10**-3 * ureg_ucumvert("[IU]/L")
126+
127+
result_str = UcumToPintStrTransformer().transform(parsed_data)
128+
assert result_str == "(((m[IU]) / (L)))"

0 commit comments

Comments
 (0)