file and entity - avoid infinite recursion if they fail to initialize

Example of the error:

Traceback (most recent call last):
  File "\test.py", line 133, in <module>
    ifc_file = ifcopenshell.file.from_string(ifc_str)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "\ifcopenshell\file.py", line 648, in from_string
    return file(ifcopenshell_wrapper.read(s))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "\ifcopenshell\file.py", line 264, in __init__
    raise exc(msg)
ifcopenshell.SchemaError: Unsupported schema: IFC2X3
Exception ignored in: <function file.__del__ at 0x00000250896EB740>
Traceback (most recent call last):
  File "\ifcopenshell\file.py", line 282, in __del__
    del file_dict[self.file_pointer()]
                  ^^^^^^^^^^^^^^^^^
  File "\ifcopenshell\file.py", line 424, in __getattr__
    return getattr(self.wrapped_data, attr)
                   ^^^^^^^^^^^^^^^^^
  File "\ifcopenshell\file.py", line 424, in __getattr__
    return getattr(self.wrapped_data, attr)
                   ^^^^^^^^^^^^^^^^^
  File "\ifcopenshell\file.py", line 424, in __getattr__
    return getattr(self.wrapped_data, attr)
                   ^^^^^^^^^^^^^^^^^
  [Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded

Simple way to trigger those recursions was:

import ifcopenshell
ifcopenshell.file(schema="IFC4x3_RC4_43c3555")
ifcopenshell.entity_instance(("IFC4X3", "IfcPresentationStyleAssignment"))
This commit is contained in:
Andrej730
2024-06-12 18:13:49 +05:00
parent d2e7e3daaf
commit 6e1ebb02ac
2 changed files with 12 additions and 1 deletions
@@ -160,7 +160,14 @@ class entity_instance:
instance references prevents file gc, even with all instance
refs deleted. This is a work-around for that.
"""
self.wrapped_data.file = None
# Avoid infinite recursion if entity is failed to initialize
# and wrapped_data is unset. Hacky since we override
# both __dict__ and __dir__.
try:
wrapped_data = super().__getattribute__("wrapped_data")
wrapped_data.file = None
except AttributeError:
return
@property
def file(self):
@@ -277,6 +277,10 @@ class file:
file_dict[self.file_pointer()] = weakref.ref(self)
def __del__(self) -> None:
# Avoid infinite recursion if file is failed to initialize
# and wrapped_data is unset.
if "wrapped_data" not in dir(self):
return
del file_dict[self.file_pointer()]
def set_history_size(self, size: int) -> None: