Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pint-to-ucum conversion #11

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
63 changes: 50 additions & 13 deletions src/ucumvert/ucum_pint.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import logging
from pathlib import Path

import pint
from lark import Transformer
from lark.exceptions import VisitError
from pint import (
Expand Down Expand Up @@ -342,6 +343,10 @@ def find_matching_pint_definitions(report_file: Path | None = None) -> None:
logger.info("Created mapping report: %s", report_file)


class PintUcumError(Exception):
pass


class PintUcumRegistry(UnitRegistry):
def _after_init(self) -> None:
"""This is called after all __init__"""
Expand All @@ -357,7 +362,7 @@ def _after_init(self) -> None:
self._ucum_parser = get_ucum_parser()
self._from_ucum_transformer = UcumToPintTransformer().transform

def from_ucum(self, ucum_code):
def from_ucum(self, ucum_code) -> pint.Quantity:
"""Transform an ucum_code to a pint unit.

Parameters
Expand All @@ -368,20 +373,52 @@ def from_ucum(self, ucum_code):
parsed_data = self._ucum_parser.parse(ucum_code)
return self._from_ucum_transformer(parsed_data)

def to_ucum(self, units) -> str:
"""Return corresponding UCUM code for pint unit container.

Parameters
----------
ucum_code :
Ucum code as string.
"""
# TODO: create mapping (at runtime?) from pint to ucum
pint_to_ucum_mapping = {"kilogram": "kg", "meter": "m", "second": "s"}

units_container = units._units # noqa: SLF001
ucum_code = []
for unit, exponent in units_container.items():
try:
ucum_unit_code = pint_to_ucum_mapping[unit]
except KeyError:
error_message = f"pint unit '{unit}' has no corresponding UCUM code."
raise PintUcumError(error_message) from None
ucum_code.append(
f"{ucum_unit_code}" + (f"{exponent}" if exponent != 1 else "")
)

# breakpoint()
ucum_str = ".".join(ucum_code)
print(f"{units!r} --> {ucum_str}")
return ucum_str


def run_examples(): # pragma: no cover
test_ucum_units = [
# "Cel",
# "/s2",
# r"m.s{s_ann}",
"[arb'U]",
]
parser = get_ucum_parser()
for unit in test_ucum_units:
print("parsing ucum code:", unit)
parsed_data = parser.parse(unit)
q = UcumToPintTransformer().transform(parsed_data)
print(f"Pint {q!r}")
# test_ucum_units = [
# # "Cel",
# # "/s2",
# # r"m.s{s_ann}",
# "[arb'U]",
# ]
# parser = get_ucum_parser()
# for unit in test_ucum_units:
# print("parsing ucum code:", unit)
# parsed_data = parser.parse(unit)
# q = UcumToPintTransformer().transform(parsed_data)
# print(f"Pint {q!r}")
ureg = PintUcumRegistry()
q = 3.5 * ureg.from_ucum("kg/m3")
print(f"IN: {q!r}")
ureg.to_ucum(q.units)


if __name__ == "__main__":
Expand Down
Loading