summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHernan <hernan.grecco@gmail.com>2022-04-04 16:15:53 -0300
committerHernan <hernan.grecco@gmail.com>2022-04-04 16:15:53 -0300
commitc6c0050e186f6152266e13563b0e5d3a91f938af (patch)
tree992e2a74907d43c7f38a37cffade91594052faac
parent8a6842d968f32683049304da3ec52d29d59ad3ad (diff)
downloadpint-c6c0050e186f6152266e13563b0e5d3a91f938af.tar.gz
Provide a method to iter the definitions in the order they appear,
recursing the imported files. Close #1498
-rw-r--r--CHANGES3
-rw-r--r--pint/parser.py28
-rw-r--r--pint/registry.py21
-rw-r--r--pint/testsuite/test_issues.py40
4 files changed, 79 insertions, 13 deletions
diff --git a/CHANGES b/CHANGES
index 053bc1e..3009fbc 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,7 +4,8 @@ Pint Changelog
0.20 (unreleased)
-----------------
-- Nothing changed yet.
+- Provide a method to iter the definitions in the order they appear,
+ recursing the imported files. (Issue #1498)
0.19 (2022-04-04)
diff --git a/pint/parser.py b/pint/parser.py
index 40830d6..c4800a6 100644
--- a/pint/parser.py
+++ b/pint/parser.py
@@ -61,7 +61,33 @@ class DefinitionFile:
class DefinitionFiles(tuple):
"""Wrapper class that allows handling a tuple containing DefinitionFile."""
- pass
+ def _iter_definitions(self, next_file, *pending_files):
+ for lineno, definition in next_file.parsed_lines:
+ if isinstance(definition, ImportDefinition):
+ if not pending_files:
+ raise ValueError(
+ f"No more files while trying to import {definition.path}."
+ )
+
+ if not str(pending_files[0].filename).endswith(definition.path):
+ raise ValueError(
+ "The order of the files do not match. "
+ f"(expected: {definition.path}, "
+ f"found {pending_files[0].path})"
+ )
+
+ yield from self._iter_definitions(*pending_files)
+ else:
+ yield lineno, definition
+
+ def iter_definitions(self):
+ """Iter all definitions in the order they appear,
+ going into the included files.
+
+ Important: This assumes that the order of the imported files
+ is the one that they will appear in the definitions.
+ """
+ yield from self._iter_definitions(*self)
def build_disk_cache_class(non_int_type: type):
diff --git a/pint/registry.py b/pint/registry.py
index 2c5b065..d9b095b 100644
--- a/pint/registry.py
+++ b/pint/registry.py
@@ -637,17 +637,16 @@ class BaseRegistry(metaclass=RegistryMeta):
else:
parsed_files = parser.DefinitionFiles([p.parse_lines(file)])
- for definition_file in parsed_files[::-1]:
- for lineno, definition in definition_file.parsed_lines:
- if definition.__class__ in p.handled_classes:
- continue
- loaderfunc = loaders.get(definition.__class__, None)
- if not loaderfunc:
- raise ValueError(
- f"No loader function defined "
- f"for {definition.__class__.__name__}"
- )
- loaderfunc(definition)
+ for lineno, definition in parsed_files.iter_definitions():
+ if definition.__class__ in p.handled_classes:
+ continue
+ loaderfunc = loaders.get(definition.__class__, None)
+ if not loaderfunc:
+ raise ValueError(
+ f"No loader function defined "
+ f"for {definition.__class__.__name__}"
+ )
+ loaderfunc(definition)
return parsed_files
diff --git a/pint/testsuite/test_issues.py b/pint/testsuite/test_issues.py
index 9d6cb12..1034799 100644
--- a/pint/testsuite/test_issues.py
+++ b/pint/testsuite/test_issues.py
@@ -901,3 +901,43 @@ if np is not None:
type_before = type(q._magnitude)
callable(q)
assert isinstance(q._magnitude, type_before)
+
+ def test_issue1498(tmp_path):
+ def0 = tmp_path / "def0.txt"
+ def1 = tmp_path / "def1.txt"
+ def2 = tmp_path / "def2.txt"
+
+ # A file that defines a new base unit and uses it in a context
+ def0.write_text(
+ """
+ foo = [FOO]
+
+ @context BAR
+ [FOO] -> [mass]: value / foo * 10.0 kg
+ @end
+ """
+ )
+
+ # A file that defines a new base unit, then imports another file…
+ def1.write_text(
+ f"""
+ foo = [FOO]
+
+ @import {str(def2)}
+ """
+ )
+
+ # …that, in turn, uses it in a context
+ def2.write_text(
+ """
+ @context BAR
+ [FOO] -> [mass]: value / foo * 10.0 kg
+ @end
+ """
+ )
+
+ # Succeeds with pint 0.18; fails with pint 0.19
+ ureg1 = UnitRegistry()
+ ureg1.load_definitions(def1) # ← FAILS
+
+ assert 12.0 == ureg1("1.2 foo").to("kg", "BAR").magnitude