From 15ceaf6a62805d3571e6286611699c5333d2289c Mon Sep 17 00:00:00 2001 From: mohapatr3 Date: Sun, 26 Oct 2025 02:40:33 +0530 Subject: [PATCH] root namespace in inspector args Signed-off-by: mohapatr3 --- flatdata-generator/flatdata/generator/engine.py | 15 +++++++++++---- flatdata-py/flatdata/lib/inspector.py | 12 ++++++++---- flatdata-py/tests/common.py | 17 +++++++++++++++++ .../tests/test_backward_compatibility.py | 14 ++++++++++++++ 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/flatdata-generator/flatdata/generator/engine.py b/flatdata-generator/flatdata/generator/engine.py index d568f03a..76d892ce 100644 --- a/flatdata-generator/flatdata/generator/engine.py +++ b/flatdata-generator/flatdata/generator/engine.py @@ -1,5 +1,5 @@ ''' - Copyright (c) 2017 HERE Europe B.V. + Copyright (c) 2025 HERE Europe B.V. See the LICENSE file in the root of this project for license details. ''' @@ -61,14 +61,15 @@ def render(self, generator_name): output_content = generator.render(self.tree) return output_content - def render_python_module(self, module_name=None, archive_name=None): + def render_python_module(self, module_name=None, archive_name=None, root_namespace=None): """ Render python module. :param module_name: Module name to use. If none, root namespace name is used. :param archive_name: Archive name to lookup, 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 = self._find_root_namespace(self.tree, 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 @@ -89,7 +90,7 @@ def _create_generator(cls, name): return generator_type() @staticmethod - def _find_root_namespace(tree): + def _find_root_namespace(tree, root_namespace=None): root_children = tree.root.children root_namespaces = [ child for child in root_children @@ -97,6 +98,12 @@ def _find_root_namespace(tree): ] if not root_namespaces: raise RuntimeError("No root namespace found.") + elif root_namespace: + for namespace in root_namespaces: + if namespace.name == root_namespace: + return namespace + raise RuntimeError("Invalid root namespace provided. Could not find root namespace in archive.") elif len(root_namespaces) > 1: raise RuntimeError("Ambiguous root namespace. Could not find root archive.") + return root_namespaces[0] diff --git a/flatdata-py/flatdata/lib/inspector.py b/flatdata-py/flatdata/lib/inspector.py index 5bfdfdc2..21dabd74 100755 --- a/flatdata-py/flatdata/lib/inspector.py +++ b/flatdata-py/flatdata/lib/inspector.py @@ -1,5 +1,5 @@ ''' - Copyright (c) 2017 HERE Europe B.V. + Copyright (c) 2025 HERE Europe B.V. See the LICENSE file in the root of this project for license details. ''' @@ -29,7 +29,7 @@ """ -def open_archive(path, archive=None, module_name=None): +def open_archive(path, archive=None, module_name=None, root_namespace=None): """ Opens archive at a given path. Archive schema is read and python bindings are generated on the fly. @@ -38,6 +38,7 @@ def open_archive(path, archive=None, module_name=None): :param archive: Archive name to open (in case multiple archives reside in one directory) if None, will be implied. If cannot be implied, RuntimeError is raised. :param module_name: Module name to create. If None, will match the highest-level namespace. + :param root_namespace: Root namespace to pick in case of multiple top level namespaces. :return: tuple archive, module """ if not os.path.exists(path): @@ -73,7 +74,8 @@ def open_archive(path, archive=None, module_name=None): try: module, archive_type = \ Engine(schema.read().decode()).render_python_module(module_name=module_name, - archive_name=archive_name) + archive_name=archive_name, + root_namespace=root_namespace) except FlatdataSyntaxError as err: raise RuntimeError("Error reading schema: %s " % err) @@ -87,12 +89,14 @@ def main(): help="Path to archive") parser.add_argument("-a", "--archive", type=str, dest="archive", required=False, default=None, help="Name of the archive") + parser.add_argument("-n", "--namespace", type=str, dest="namespace", required=False, default=None, + help="Root namespace to pick in case of multiple top level namespaces") parser.add_argument("--non-interactive", type=str, dest="non_interactive", required=False, default=None, help="Python code to execute in non-interactive mode") args = parser.parse_args() - archive, _ = open_archive(args.path, args.archive) + archive, _ = open_archive(args.path, args.archive, None, args.namespace) pd.set_option('display.max_rows', 30) pd.set_option('expand_frame_repr', False) diff --git a/flatdata-py/tests/common.py b/flatdata-py/tests/common.py index a03bf1c9..c6df91ab 100644 --- a/flatdata-py/tests/common.py +++ b/flatdata-py/tests/common.py @@ -29,6 +29,23 @@ ) +MULTI_NAMESPACE_TEST_SCHEMA = """ +namespace backward_compatibility { + struct SignedStruct { + a : i16 : 5; + b : u32 : 32; + c : i32 : 7; + d : u32 : 32; + } + archive Archive { + resource: SignedStruct; + } +} +namespace second { +} +""" + + VECTOR_TEST_SCHEMA = """ namespace backward_compatibility { diff --git a/flatdata-py/tests/test_backward_compatibility.py b/flatdata-py/tests/test_backward_compatibility.py index 269960a3..7fffe87c 100644 --- a/flatdata-py/tests/test_backward_compatibility.py +++ b/flatdata-py/tests/test_backward_compatibility.py @@ -29,6 +29,20 @@ def test_instance_reading(): check_signed_struct(archive.resource[0]) +def test_multi_namespace_instance_reading(): + root_namespace = "backward_compatibility" + module = Engine(MULTI_NAMESPACE_TEST_SCHEMA).render_python_module(None, None, 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_vector_reading(): module = Engine(VECTOR_TEST_SCHEMA).render_python_module() valid_data = {