From 91d8911e4addd5558b1e5d1415b5b2a46d173452 Mon Sep 17 00:00:00 2001 From: Claire Waters Date: Fri, 28 Aug 2026 13:29:39 -0500 Subject: [PATCH 1/4] FEAT: convert uncertianty fields to SI in kimunits --- kim_tools/kimunits.py | 58 +++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/kim_tools/kimunits.py b/kim_tools/kimunits.py index 841768e..dbe20d5 100644 --- a/kim_tools/kimunits.py +++ b/kim_tools/kimunits.py @@ -160,33 +160,43 @@ def convert_inner(x, fit=None): def add_si_units(doc, convert=convert): - """Given a document, add all of the appropriate si-units fields""" - if isinstance(doc, dict): + """ Given a document, add all of the appropriate si-units fields """ + + # dict specifying which SI keys correspond with which source keys + corresponding_keys = {"source-value":"si-value", + "source-std-uncert-value":"si-std-uncert-value", + "source-expand-uncert-value":"si-expand-uncert-value", + "source-asym-std-uncert-neg":"si-asym-std-uncert-neg", + "source-asym-std-uncert-pos":"si-asym-std-uncert-pos", + "source-asym-expand-uncert-neg":"si-asym-expand-uncert-neg", + "source-asym-expand-uncert-pos":"si-asym-expand-uncert-pos"} + + + if isinstance(doc,dict): # check for a source-unit to defined a value with units - if "source-unit" in doc: - # we've found a place to add - assert "source-value" in doc, "Badly formed doc" - o_value = doc.get("source-value", None) - o_unit = doc.get("source-unit", None) - - if o_value is None: - raise UnitConversion("No source-value provided") - if o_unit is None: - raise UnitConversion("No source-unit provided") - - # convert the units and insert - value, unit = convert_list(o_value, o_unit, convert=convert) - si_dict = {"si-unit": unit, "si-value": value} - doc = doc.copy() - doc.update(si_dict) - return doc + if 'source-unit' in doc: + #we've found a place to add + assert 'source-value' in doc, "Badly formed doc" + # search for any convertable source values or uncertanties + for source_key in corresponding_keys.keys(): + o_value = doc.get(source_key, None) + o_unit = doc.get("source-unit", None) + + # convertable value or uncertianty found + if o_value is not None: + # convert the units and insert + value, unit = convert_list(o_value, o_unit, convert=convert) + # look up the corresponding SI key for the converted value + converted_key = corresponding_keys[source_key] + si_dict = {"si-unit": unit, converted_key: value } + doc = doc.copy() + doc.update(si_dict) + return doc else: # recurse - return type(doc)( - (key, add_si_units(value)) for key, value in list(doc.items()) - ) + return type(doc)( (key, add_si_units(value)) for key,value in doc.items() ) - elif isinstance(doc, (list, tuple)): - return type(doc)(add_si_units(x) for x in doc) + elif isinstance(doc, (list,tuple)): + return type(doc)( add_si_units(x) for x in doc ) return doc From c7148b8963d57aa539c24c080db4ebead9e035c2 Mon Sep 17 00:00:00 2001 From: Claire Waters Date: Fri, 28 Aug 2026 13:51:17 -0500 Subject: [PATCH 2/4] ENH: add test for add_si_units --- tests/test_units.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_units.py b/tests/test_units.py index f3ae5b2..ad6ec2b 100644 --- a/tests/test_units.py +++ b/tests/test_units.py @@ -1,6 +1,6 @@ import numpy as np -from kim_tools.kimunits import convert_list, convert_units +from kim_tools.kimunits import convert_list, convert_units, add_si_units def test_units() -> None: @@ -9,3 +9,6 @@ def test_units() -> None: assert one_kilogram[1] == "kg" assert np.isclose(convert_units(0, "tempC", "tempF", suppress_unit=True), 32) assert np.allclose(convert_list([1000, 1000], "g")[0], [1, 1]) + assert np.isclose( + add_si_units({"source-value": 1000, "source-unit": "mm"})["si-value"], 1.0 + ) \ No newline at end of file From 3115e2d97572b244fcf60cffb15254c858ae2ffa Mon Sep 17 00:00:00 2001 From: Claire Waters Date: Sat, 29 Aug 2026 00:00:32 +0000 Subject: [PATCH 3/4] STY: run pre-commit --- kim_tools/kimunits.py | 39 ++++++++++++++++++++------------------- tests/test_units.py | 4 ++-- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/kim_tools/kimunits.py b/kim_tools/kimunits.py index dbe20d5..ece4941 100644 --- a/kim_tools/kimunits.py +++ b/kim_tools/kimunits.py @@ -160,27 +160,28 @@ def convert_inner(x, fit=None): def add_si_units(doc, convert=convert): - """ Given a document, add all of the appropriate si-units fields """ + """Given a document, add all of the appropriate si-units fields""" # dict specifying which SI keys correspond with which source keys - corresponding_keys = {"source-value":"si-value", - "source-std-uncert-value":"si-std-uncert-value", - "source-expand-uncert-value":"si-expand-uncert-value", - "source-asym-std-uncert-neg":"si-asym-std-uncert-neg", - "source-asym-std-uncert-pos":"si-asym-std-uncert-pos", - "source-asym-expand-uncert-neg":"si-asym-expand-uncert-neg", - "source-asym-expand-uncert-pos":"si-asym-expand-uncert-pos"} - - - if isinstance(doc,dict): + corresponding_keys = { + "source-value": "si-value", + "source-std-uncert-value": "si-std-uncert-value", + "source-expand-uncert-value": "si-expand-uncert-value", + "source-asym-std-uncert-neg": "si-asym-std-uncert-neg", + "source-asym-std-uncert-pos": "si-asym-std-uncert-pos", + "source-asym-expand-uncert-neg": "si-asym-expand-uncert-neg", + "source-asym-expand-uncert-pos": "si-asym-expand-uncert-pos", + } + + if isinstance(doc, dict): # check for a source-unit to defined a value with units - if 'source-unit' in doc: - #we've found a place to add - assert 'source-value' in doc, "Badly formed doc" + if "source-unit" in doc: + # we've found a place to add + assert "source-value" in doc, "Badly formed doc" # search for any convertable source values or uncertanties for source_key in corresponding_keys.keys(): o_value = doc.get(source_key, None) - o_unit = doc.get("source-unit", None) + o_unit = doc.get("source-unit", None) # convertable value or uncertianty found if o_value is not None: @@ -188,15 +189,15 @@ def add_si_units(doc, convert=convert): value, unit = convert_list(o_value, o_unit, convert=convert) # look up the corresponding SI key for the converted value converted_key = corresponding_keys[source_key] - si_dict = {"si-unit": unit, converted_key: value } + si_dict = {"si-unit": unit, converted_key: value} doc = doc.copy() doc.update(si_dict) return doc else: # recurse - return type(doc)( (key, add_si_units(value)) for key,value in doc.items() ) + return type(doc)((key, add_si_units(value)) for key, value in doc.items()) - elif isinstance(doc, (list,tuple)): - return type(doc)( add_si_units(x) for x in doc ) + elif isinstance(doc, (list, tuple)): + return type(doc)(add_si_units(x) for x in doc) return doc diff --git a/tests/test_units.py b/tests/test_units.py index ad6ec2b..aacc8cc 100644 --- a/tests/test_units.py +++ b/tests/test_units.py @@ -1,6 +1,6 @@ import numpy as np -from kim_tools.kimunits import convert_list, convert_units, add_si_units +from kim_tools.kimunits import add_si_units, convert_list, convert_units def test_units() -> None: @@ -11,4 +11,4 @@ def test_units() -> None: assert np.allclose(convert_list([1000, 1000], "g")[0], [1, 1]) assert np.isclose( add_si_units({"source-value": 1000, "source-unit": "mm"})["si-value"], 1.0 - ) \ No newline at end of file + ) From 0f9ffcdc60d8a5fb4efc1c2fe0d5fb7e816dc015 Mon Sep 17 00:00:00 2001 From: Claire Waters Date: Mon, 31 Aug 2026 16:28:49 +0000 Subject: [PATCH 4/4] BUG: don't exit conversion loop prematurely add test for multiple SI key conversions --- kim_tools/kimunits.py | 6 +++--- tests/test_units.py | 11 ++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/kim_tools/kimunits.py b/kim_tools/kimunits.py index ece4941..aaf6a96 100644 --- a/kim_tools/kimunits.py +++ b/kim_tools/kimunits.py @@ -179,6 +179,7 @@ def add_si_units(doc, convert=convert): # we've found a place to add assert "source-value" in doc, "Badly formed doc" # search for any convertable source values or uncertanties + output = doc.copy() for source_key in corresponding_keys.keys(): o_value = doc.get(source_key, None) o_unit = doc.get("source-unit", None) @@ -190,9 +191,8 @@ def add_si_units(doc, convert=convert): # look up the corresponding SI key for the converted value converted_key = corresponding_keys[source_key] si_dict = {"si-unit": unit, converted_key: value} - doc = doc.copy() - doc.update(si_dict) - return doc + output.update(si_dict) + return output else: # recurse return type(doc)((key, add_si_units(value)) for key, value in doc.items()) diff --git a/tests/test_units.py b/tests/test_units.py index aacc8cc..336675e 100644 --- a/tests/test_units.py +++ b/tests/test_units.py @@ -10,5 +10,14 @@ def test_units() -> None: assert np.isclose(convert_units(0, "tempC", "tempF", suppress_unit=True), 32) assert np.allclose(convert_list([1000, 1000], "g")[0], [1, 1]) assert np.isclose( - add_si_units({"source-value": 1000, "source-unit": "mm"})["si-value"], 1.0 + add_si_units( + {"source-value": 1000, "source-unit": "mm", "source-std-uncert-value": 1} + )["si-value"], + 1.0, + ) + assert np.isclose( + add_si_units( + {"source-value": 1000, "source-unit": "mm", "source-std-uncert-value": 1} + )["si-std-uncert-value"], + 0.001, )