Skip to content

Commit

Permalink
Fix parsing of ucum unit with prefixes
Browse files Browse the repository at this point in the history
This also fixes an undesired fixture modification in one test.
  • Loading branch information
dalito committed Sep 10, 2024
1 parent 67f4b5b commit 4d81399
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 5 deletions.
7 changes: 6 additions & 1 deletion src/ucumvert/ucum_pint.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,12 @@ def component(self, args):
def simple_unit(self, args):
# print("DBGsu>", repr(args), len(args))
if len(args) == 2: # prefix is present # noqa: PLR2004
return self.ureg(args[0] + args[1])
# Work around a pint bug: parsing of abbreviated custom unit with prefix
# that could be a unit (k,m,M) does not detect the prefix but 2 units.
# e.g. m[IU] --> <Quantity(1, 'meter * [IU]')> instead of <Quantity(1, 'milli[IU]')>
# Therefore, this fails (pint 0.23):
# return self.ureg(args[0] + args[1])
return self.ureg(args[0] + str(self.ureg(args[1]).units))

# Substitute UCUM atoms that cannot be defined in pint as units or aliases.
return self.ureg(MAPPINGS_UCUM_TO_PINT.get(args[0], args[0]))
Expand Down
23 changes: 19 additions & 4 deletions tests/test_ucum_pint.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from pathlib import Path

import pytest
from lark import LarkError
from pint import UnitRegistry
Expand All @@ -12,8 +14,6 @@
from ucumvert.ucum_pint import find_ucum_codes_that_need_mapping
from ucumvert.xml_util import get_metric_units, get_non_metric_units

ureg = UnitRegistry()


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


def test_ucum_to_pint(ucum_parser, ureg_std):
expected_quantity = ureg("kilogram")
expected_quantity = ureg_std("kilogram")
parsed_data = ucum_parser.parse("kg")
result = UcumToPintTransformer(ureg=ureg_std).transform(parsed_data)
assert result == expected_quantity
Expand Down Expand Up @@ -99,7 +99,11 @@ def test_ucum_all_unit_atoms_pint_vs_str(
assert ureg_ucumvert(result_str) == expected_quantity


def test_ucum_preprocessor(ureg_ucumvert):
def test_ucum_preprocessor():
# Don't use ureg_ucumvert from fixture here, because we want to modify it.
defdir = Path(__file__).resolve().parents[1] / "src" / "ucumvert"
ureg_ucumvert = UnitRegistry()
ureg_ucumvert.load_definitions(defdir / "pint_ucum_defs.txt")
expected = ureg_ucumvert("m*kg")
ureg_ucumvert.preprocessors.append(ucum_preprocessor)
assert ureg_ucumvert("m.kg") == expected
Expand All @@ -111,3 +115,14 @@ def test_ucum_unitregistry():
ureg = PintUcumRegistry()
assert ureg.from_ucum("m.kg") == ureg("m*kg")
assert ureg.from_ucum("Cel") == ureg("degC")


def test_prefix_with_unit_that_is_also_a_prefix_issue24(ucum_parser, ureg_ucumvert):
parsed_data = ucum_parser.parse("m[IU]/L")

expected_quantity = ureg_ucumvert("milliinternational_unit/liter")
assert expected_quantity == UcumToPintTransformer().transform(parsed_data)
assert expected_quantity == 10**-3 * ureg_ucumvert("[IU]/L")

result_str = UcumToPintStrTransformer().transform(parsed_data)
assert result_str == "(((m[IU]) / (L)))"

0 comments on commit 4d81399

Please sign in to comment.