diff --git a/flatdata-generator/flatdata/generator/engine.py b/flatdata-generator/flatdata/generator/engine.py index 76d892ce..bf6a6d9e 100644 --- a/flatdata-generator/flatdata/generator/engine.py +++ b/flatdata-generator/flatdata/generator/engine.py @@ -7,6 +7,7 @@ from flatdata.generator.tree.builder import build_ast from flatdata.generator.tree.nodes.trivial.namespace import Namespace +from flatdata.generator.tree.nodes.node import Node from .generators.cpp import CppGenerator from .generators.dot import DotGenerator @@ -69,7 +70,7 @@ def render_python_module(self, module_name=None, archive_name=None, root_namespa if specified, archive type is returned along with the model :param root_namespace: Root namespace to pick in case of multiple top level namespaces. """ - root_namespace = self._find_root_namespace(self.tree, root_namespace) + root_namespace = self._find_root_namespace(self.tree, archive_name, root_namespace) module_code = self.render("py") module = types.ModuleType(module_name if module_name is not None else root_namespace.name) #pylint: disable=exec-used @@ -90,7 +91,7 @@ def _create_generator(cls, name): return generator_type() @staticmethod - def _find_root_namespace(tree, root_namespace=None): + def _find_root_namespace(tree, archive_name, root_namespace=None): root_children = tree.root.children root_namespaces = [ child for child in root_children @@ -103,6 +104,13 @@ def _find_root_namespace(tree, root_namespace=None): if namespace.name == root_namespace: return namespace raise RuntimeError("Invalid root namespace provided. Could not find root namespace in archive.") + elif archive_name: + for namespace in root_namespaces: + archive_path = namespace.name + Node.PATH_SEPARATOR + archive_name + archive_node = namespace.get(archive_path) + if archive_node is not None: + return namespace + raise RuntimeError("Archive direct parent namespace is not a root namespace.") elif len(root_namespaces) > 1: raise RuntimeError("Ambiguous root namespace. Could not find root archive.") diff --git a/flatdata-generator/flatdata/generator/tree/syntax_tree.py b/flatdata-generator/flatdata/generator/tree/syntax_tree.py index 4369110f..51172057 100644 --- a/flatdata-generator/flatdata/generator/tree/syntax_tree.py +++ b/flatdata-generator/flatdata/generator/tree/syntax_tree.py @@ -39,6 +39,12 @@ def find(self, path): """ return self._root.find(path) + def get(self, path, default=None): + """ + Returns the node like find() does, but allows default value specification. + """ + return self._root.get(path, default) + def subtree(self, path): """ Returns subtree of the given tree as a SyntaxTree diff --git a/flatdata-py/tests/test_backward_compatibility.py b/flatdata-py/tests/test_backward_compatibility.py index 7fffe87c..a1c5ee42 100644 --- a/flatdata-py/tests/test_backward_compatibility.py +++ b/flatdata-py/tests/test_backward_compatibility.py @@ -29,9 +29,25 @@ def test_instance_reading(): check_signed_struct(archive.resource[0]) -def test_multi_namespace_instance_reading(): +def test_multi_namespace_instance_reading_implicit(): + root_namespace = None + archive_name = "Archive" + module, archive_type = Engine(MULTI_NAMESPACE_TEST_SCHEMA).render_python_module(None, archive_name, root_namespace) + valid_data = { + "Archive.archive": ARCHIVE_SIGNATURE_PAYLOAD, + "Archive.archive.schema": module.backward_compatibility_Archive.schema().encode(), + "resource": RESOURCE_PAYLOAD, + "resource.schema": module.backward_compatibility_Archive.resource_schema('resource').encode() + } + archive = module.backward_compatibility_Archive(DictResourceStorage(valid_data)) + check_signed_struct(archive.resource) + check_signed_struct(archive.resource[0]) + + +def test_multi_namespace_instance_reading_explicit(): root_namespace = "backward_compatibility" - module = Engine(MULTI_NAMESPACE_TEST_SCHEMA).render_python_module(None, None, root_namespace) + archive_name = None + module = Engine(MULTI_NAMESPACE_TEST_SCHEMA).render_python_module(None, archive_name, root_namespace) valid_data = { "Archive.archive": ARCHIVE_SIGNATURE_PAYLOAD, "Archive.archive.schema": module.backward_compatibility_Archive.schema().encode(),