diff options
author | Hernan <hernan.grecco@gmail.com> | 2022-04-04 16:15:53 -0300 |
---|---|---|
committer | Hernan <hernan.grecco@gmail.com> | 2022-04-04 16:15:53 -0300 |
commit | c6c0050e186f6152266e13563b0e5d3a91f938af (patch) | |
tree | 992e2a74907d43c7f38a37cffade91594052faac | |
parent | 8a6842d968f32683049304da3ec52d29d59ad3ad (diff) | |
download | pint-c6c0050e186f6152266e13563b0e5d3a91f938af.tar.gz |
Provide a method to iter the definitions in the order they appear,
recursing the imported files.
Close #1498
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | pint/parser.py | 28 | ||||
-rw-r--r-- | pint/registry.py | 21 | ||||
-rw-r--r-- | pint/testsuite/test_issues.py | 40 |
4 files changed, 79 insertions, 13 deletions
@@ -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 |