From b1f388311cc48ecfb8d25e55d47cbdf50b927d97 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 3 Aug 2026 13:46:58 +0500 Subject: [PATCH] Return support for creating uninitialized files from Python Created a new method to avoid complicating `ifcopenshell.file` ctor signature. --- .../ifcopenshell/__init__.py | 2 +- .../ifcopenshell/ifcopenshell_wrapper.pyi | 23 +++++++++++++++++-- src/ifcwrap/IfcParseWrapper.i | 5 ++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/__init__.py b/src/ifcopenshell-python/ifcopenshell/__init__.py index 9aec42551b..ccf369dff0 100644 --- a/src/ifcopenshell-python/ifcopenshell/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/__init__.py @@ -237,7 +237,7 @@ def open( if readonly: # Temporary conditional see #7131. Remove once newer builds don't segfault on Linux. f = ifcopenshell_wrapper.open(str(path.absolute()), readonly, *optional_logger_args(logger)) elif bypass_types: - f = ifcopenshell_wrapper.file(ifcopenshell_wrapper.uninitialized_tag(), *optional_logger_args(logger)) + f = ifcopenshell_wrapper.file.create_uninitialized(*optional_logger_args(logger)) for ty in bypass_types: f.bypass_type(ty) if mmap: diff --git a/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi b/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi index e390768b60..cd9e0a241d 100644 --- a/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi +++ b/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi @@ -845,6 +845,27 @@ class file(file_mixin): schema_identifier: str | None = None, schema_version: tuple[int, int, int, int] | None = None, ): ... + @staticmethod + def create_uninitialized(logger: logger | None = None) -> file: + """Construct a file with no schema/data yet, to be populated by a later call to ``initialize()``. + + When file is uninitialized, the only two available methods during + this state are ``bypass_type()`` and ``initialize()``. + """ + ... + + def bypass_type(self, type_name: str) -> None: + """Skip loading instances of ``type_name``.""" + ... + # NOTE: inaccurate `*args` - not all args are `str`. + def initialize(self, *args: str) -> bool: + """Parse a file on a ``create_uninitialized()`` instance. + + :param args: ``args[0]`` is a string path to the IFC file. + :return: Whether the file was read and parsed successfully. On failure, check ``good()`` for the specific reason. + """ + ... + def _add(self, entity: entity_instance, id: int = -1) -> entity_instance: ... def add_type_ref(self, new_entity): ... def batch(self) -> None: @@ -873,7 +894,6 @@ class file(file_mixin): def by_id(self, instance_id: int) -> entity_instance: ... def _by_type(self, *args: declaration | str) -> tuple[entity_instance, ...]: ... def _by_type_excl_subtypes(self, *args: declaration | str) -> tuple[entity_instance, ...]: ... - def bypass_type(self, type_name: str) -> None: ... def create(self, *args) -> entity_instance: ... @staticmethod def create_timestamp() -> str: ... @@ -910,7 +930,6 @@ class file(file_mixin): @property def header(self) -> spf_header: ... def ifcroot_type(self) -> entity: ... - def initialize(self, *args): ... def key_value_store_iter(self, prefix): ... def key_value_store_query(self, key): ... def recalculate_id_counter(self): ... diff --git a/src/ifcwrap/IfcParseWrapper.i b/src/ifcwrap/IfcParseWrapper.i index 89bd288ddb..04ac4db0b8 100644 --- a/src/ifcwrap/IfcParseWrapper.i +++ b/src/ifcwrap/IfcParseWrapper.i @@ -260,6 +260,7 @@ private: %} %newobject ifcopenshell::file::key_value_store_iter; +%newobject ifcopenshell::file::create_uninitialized; %extend ifcopenshell::file { /* @@ -274,6 +275,10 @@ private: return new ifcopenshell::file(ifcopenshell::schema_by_name(schema)); } + static ifcopenshell::file* create_uninitialized(logger* logger=nullptr) { + return new ifcopenshell::file(ifcopenshell::uninitialized_tag{}, logger_or_root(logger)); + } + std::vector _get_inverse(const express::Base& e) { if (auto e_ = e.as()) { return cast_vector($self->get_inverse(e_.id(), 0, -1));