2022-01-19 12:18:33 +11:00
|
|
|
# IfcOpenShell - IFC toolkit and geometry engine
|
|
|
|
|
# Copyright (C) 2021 Thomas Krijnen <thomas@aecgeeks.com>
|
|
|
|
|
#
|
|
|
|
|
# This file is part of IfcOpenShell.
|
|
|
|
|
#
|
|
|
|
|
# IfcOpenShell is free software: you can redistribute it and/or modify
|
|
|
|
|
# it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
# (at your option) any later version.
|
|
|
|
|
#
|
|
|
|
|
# IfcOpenShell is distributed in the hope that it will be useful,
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
# GNU Lesser General Public License for more details.
|
|
|
|
|
#
|
|
|
|
|
# You should have received a copy of the GNU Lesser General Public License
|
|
|
|
|
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
2017-11-01 10:41:27 +01:00
|
|
|
|
|
|
|
|
from __future__ import absolute_import
|
|
|
|
|
from __future__ import division
|
2017-03-09 12:04:07 +01:00
|
|
|
from __future__ import print_function
|
2016-06-22 15:03:18 +02:00
|
|
|
|
|
|
|
|
import functools
|
2017-01-04 09:15:52 +01:00
|
|
|
import numbers
|
2016-06-22 15:03:18 +02:00
|
|
|
import itertools
|
|
|
|
|
|
|
|
|
|
from . import ifcopenshell_wrapper
|
|
|
|
|
|
2017-03-09 11:47:54 +01:00
|
|
|
try:
|
|
|
|
|
import logging
|
|
|
|
|
except ImportError as e:
|
2020-11-01 20:08:27 +07:00
|
|
|
logging = type("logger", (object,), {"exception": staticmethod(lambda s: print(s))})
|
2017-03-09 11:47:54 +01:00
|
|
|
|
2017-01-04 09:15:52 +01:00
|
|
|
|
2021-12-02 11:05:36 +01:00
|
|
|
def set_derived_atribute(*args):
|
|
|
|
|
raise TypeError("Unable to set derived attribute")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# For every schema and its entities populate a list
|
|
|
|
|
# of functions for every entity attribute (including
|
|
|
|
|
# inherited attributes) to set that particular
|
|
|
|
|
# attribute by index.
|
|
|
|
|
# For example. IFC2X3.IfcWall with have a list of
|
2022-01-10 15:42:24 +11:00
|
|
|
# 9 methods. The first will point at
|
2021-12-02 11:05:36 +01:00
|
|
|
# ifcopenshell.ifcopenshell_wrapper.entity_instance.setArgumentAsString
|
|
|
|
|
# because the first attribute GlobalId ultimately
|
|
|
|
|
# is of type string.
|
|
|
|
|
# Previously, resolving the appropriate function was
|
|
|
|
|
# done for each invocation of __setitem__. Now this
|
|
|
|
|
# mapping is built once during initialization of the
|
|
|
|
|
# module.
|
|
|
|
|
_method_dict = {}
|
2022-01-12 15:09:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def register_schema_attributes(schema):
|
2021-12-02 11:05:36 +01:00
|
|
|
for decl in schema.declarations():
|
2021-12-02 11:39:28 +01:00
|
|
|
if hasattr(decl, "argument_types"):
|
2022-01-12 15:09:22 +01:00
|
|
|
fq_name = ".".join((schema.name(), decl.name()))
|
2022-01-10 15:42:24 +11:00
|
|
|
|
2021-12-02 11:05:36 +01:00
|
|
|
# get type strings as reported by IfcOpenShell C++
|
|
|
|
|
type_strs = decl.argument_types()
|
2022-01-10 15:42:24 +11:00
|
|
|
|
2021-12-02 11:05:36 +01:00
|
|
|
# convert case for setter function
|
|
|
|
|
type_strs = [x.title().replace(" ", "") for x in type_strs]
|
2022-01-10 15:42:24 +11:00
|
|
|
|
2021-12-02 11:05:36 +01:00
|
|
|
# binary and enumeration are passed from python as string as well
|
|
|
|
|
type_strs = [x.replace("Binary", "String") for x in type_strs]
|
|
|
|
|
type_strs = [x.replace("Enumeration", "String") for x in type_strs]
|
2022-01-10 15:42:24 +11:00
|
|
|
|
2021-12-02 11:05:36 +01:00
|
|
|
# prefix to get method names
|
|
|
|
|
fn_names = ["setArgumentAs" + x for x in type_strs]
|
2022-01-10 15:42:24 +11:00
|
|
|
|
2021-12-02 11:05:36 +01:00
|
|
|
# resolve to actual functions in wrapper
|
|
|
|
|
functions = [
|
2022-01-10 15:42:24 +11:00
|
|
|
set_derived_atribute
|
|
|
|
|
if mname == "setArgumentAsDerived"
|
|
|
|
|
else getattr(ifcopenshell_wrapper.entity_instance, mname)
|
|
|
|
|
for mname in fn_names
|
|
|
|
|
]
|
|
|
|
|
|
2021-12-02 11:05:36 +01:00
|
|
|
_method_dict[fq_name] = functions
|
|
|
|
|
|
|
|
|
|
|
2022-01-12 15:09:22 +01:00
|
|
|
for nm in ifcopenshell_wrapper.schema_names():
|
|
|
|
|
schema = ifcopenshell_wrapper.schema_by_name(nm)
|
|
|
|
|
register_schema_attributes(schema)
|
|
|
|
|
|
|
|
|
|
|
2016-06-22 15:03:18 +02:00
|
|
|
class entity_instance(object):
|
2022-05-09 15:35:52 +10:00
|
|
|
"""Base class for all IFC objects.
|
2017-12-04 09:16:30 -08:00
|
|
|
|
|
|
|
|
An instantiated entity_instance will have methods of Python and the IFC class itself.
|
|
|
|
|
|
2020-04-02 05:53:14 +02:00
|
|
|
Example::
|
2017-12-04 09:16:30 -08:00
|
|
|
|
2020-04-02 05:53:14 +02:00
|
|
|
ifc_file = ifcopenshell.open(file_path)
|
|
|
|
|
products = ifc_file.by_type("IfcProduct")
|
|
|
|
|
print(products[0].__class__)
|
|
|
|
|
>>> <class 'ifcopenshell.entity_instance.entity_instance'>
|
|
|
|
|
print(products[0].Representation)
|
|
|
|
|
>>> #423=IfcProductDefinitionShape($,$,(#409,#421))
|
2017-12-04 09:16:30 -08:00
|
|
|
"""
|
2020-11-01 20:08:27 +07:00
|
|
|
|
2021-07-10 21:43:27 +02:00
|
|
|
def __init__(self, e, file=None):
|
2017-12-31 12:20:13 +01:00
|
|
|
if isinstance(e, tuple):
|
|
|
|
|
e = ifcopenshell_wrapper.new_IfcBaseClass(*e)
|
2020-11-01 20:08:27 +07:00
|
|
|
super(entity_instance, self).__setattr__("wrapped_data", e)
|
2021-12-02 11:05:36 +01:00
|
|
|
super(entity_instance, self).__setattr__("method_list", None)
|
2022-10-04 10:21:45 +02:00
|
|
|
|
|
|
|
|
# Make sure the file is not gc'ed while we have live instances
|
2021-06-30 18:34:12 +10:00
|
|
|
self.wrapped_data.file = file
|
2017-01-04 09:15:52 +01:00
|
|
|
|
2022-10-04 10:21:45 +02:00
|
|
|
def __del__(self):
|
|
|
|
|
"""
|
|
|
|
|
#2471 while the precise chain of action is unclear, creating
|
|
|
|
|
instance references prevents file gc, even with all instance
|
|
|
|
|
refs deleted. This is a work-around for that.
|
|
|
|
|
"""
|
|
|
|
|
self.wrapped_data.file = None
|
|
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
def __getattr__(self, name):
|
|
|
|
|
INVALID, FORWARD, INVERSE = range(3)
|
|
|
|
|
attr_cat = self.wrapped_data.get_attribute_category(name)
|
|
|
|
|
if attr_cat == FORWARD:
|
2017-01-04 09:15:52 +01:00
|
|
|
return entity_instance.wrap_value(
|
2022-10-04 10:21:45 +02:00
|
|
|
self.wrapped_data.get_argument(
|
|
|
|
|
self.wrapped_data.get_argument_index(name)
|
|
|
|
|
),
|
|
|
|
|
self.wrapped_data.file,
|
2020-11-01 20:08:27 +07:00
|
|
|
)
|
2016-07-18 15:53:20 +02:00
|
|
|
elif attr_cat == INVERSE:
|
2022-10-04 10:21:45 +02:00
|
|
|
return entity_instance.wrap_value(
|
|
|
|
|
self.wrapped_data.get_inverse(name), self.wrapped_data.file
|
|
|
|
|
)
|
2017-01-04 09:15:52 +01:00
|
|
|
else:
|
|
|
|
|
raise AttributeError(
|
2022-10-04 10:21:45 +02:00
|
|
|
"entity instance of type '%s' has no attribute '%s'"
|
|
|
|
|
% (self.wrapped_data.is_a(True), name)
|
2020-11-01 20:08:27 +07:00
|
|
|
)
|
2017-01-04 09:15:52 +01:00
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
@staticmethod
|
|
|
|
|
def walk(f, g, value):
|
2017-01-04 09:15:52 +01:00
|
|
|
if isinstance(value, (tuple, list)):
|
|
|
|
|
return tuple(map(functools.partial(entity_instance.walk, f, g), value))
|
|
|
|
|
elif f(value):
|
|
|
|
|
return g(value)
|
|
|
|
|
else:
|
|
|
|
|
return value
|
|
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
@staticmethod
|
2021-06-30 18:34:12 +10:00
|
|
|
def wrap_value(v, file):
|
2020-11-01 20:08:27 +07:00
|
|
|
def wrap(e):
|
2021-06-30 18:34:12 +10:00
|
|
|
return entity_instance(e, file)
|
2017-11-06 09:10:28 +01:00
|
|
|
|
2020-11-01 20:08:27 +07:00
|
|
|
def is_instance(e):
|
|
|
|
|
return isinstance(e, ifcopenshell_wrapper.entity_instance)
|
2017-11-06 11:06:40 +01:00
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
return entity_instance.walk(is_instance, wrap, v)
|
2017-01-04 09:15:52 +01:00
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
@staticmethod
|
|
|
|
|
def unwrap_value(v):
|
2020-11-01 20:08:27 +07:00
|
|
|
def unwrap(e):
|
|
|
|
|
return e.wrapped_data
|
2017-11-06 09:10:28 +01:00
|
|
|
|
2020-11-01 20:08:27 +07:00
|
|
|
def is_instance(e):
|
|
|
|
|
return isinstance(e, entity_instance)
|
2017-11-06 11:06:40 +01:00
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
return entity_instance.walk(is_instance, unwrap, v)
|
2017-01-04 09:15:52 +01:00
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
def attribute_type(self, attr):
|
2020-04-02 05:53:14 +02:00
|
|
|
"""Return the data type of a positional attribute of the element
|
|
|
|
|
|
|
|
|
|
:param attr: The index of the attribute
|
|
|
|
|
:type attr: int
|
|
|
|
|
:rtype: string
|
|
|
|
|
"""
|
2022-10-04 10:21:45 +02:00
|
|
|
attr_idx = (
|
|
|
|
|
attr
|
|
|
|
|
if isinstance(attr, numbers.Integral)
|
|
|
|
|
else self.wrapped_data.get_argument_index(attr)
|
|
|
|
|
)
|
2016-07-18 15:53:20 +02:00
|
|
|
return self.wrapped_data.get_argument_type(attr_idx)
|
2017-01-04 09:15:52 +01:00
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
def attribute_name(self, attr_idx):
|
2020-04-02 05:53:14 +02:00
|
|
|
"""Return the name of a positional attribute of the element
|
|
|
|
|
|
|
|
|
|
:param attr_idx: The index of the attribute
|
|
|
|
|
:type attr_idx: int
|
|
|
|
|
:rtype: string
|
|
|
|
|
"""
|
2016-07-18 15:53:20 +02:00
|
|
|
return self.wrapped_data.get_argument_name(attr_idx)
|
2017-01-04 09:15:52 +01:00
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
def __setattr__(self, key, value):
|
2021-06-30 18:34:12 +10:00
|
|
|
index = self.wrapped_data.get_argument_index(key)
|
|
|
|
|
self[index] = value
|
2017-01-04 09:15:52 +01:00
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
def __getitem__(self, key):
|
2017-08-02 16:05:56 +02:00
|
|
|
if key < 0 or key >= len(self):
|
2022-10-04 10:21:45 +02:00
|
|
|
raise IndexError(
|
|
|
|
|
"Attribute index {} out of range for instance of type {}".format(
|
|
|
|
|
key, self.is_a()
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
return entity_instance.wrap_value(
|
|
|
|
|
self.wrapped_data.get_argument(key), self.wrapped_data.file
|
|
|
|
|
)
|
2017-01-04 09:15:52 +01:00
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
def __setitem__(self, idx, value):
|
2021-07-10 21:43:27 +02:00
|
|
|
if self.wrapped_data.file and self.wrapped_data.file.transaction:
|
2021-07-04 20:22:20 +10:00
|
|
|
self.wrapped_data.file.transaction.store_edit(self, idx, value)
|
|
|
|
|
|
2021-12-02 11:05:36 +01:00
|
|
|
if self.method_list is None:
|
2022-10-04 10:21:45 +02:00
|
|
|
super(entity_instance, self).__setattr__(
|
|
|
|
|
"method_list", _method_dict[self.is_a(True)]
|
|
|
|
|
)
|
2022-01-10 15:42:24 +11:00
|
|
|
|
2021-12-02 11:05:36 +01:00
|
|
|
method = self.method_list[idx]
|
2022-01-10 15:42:24 +11:00
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
if value is None:
|
2021-12-02 11:05:36 +01:00
|
|
|
if method is not set_derived_atribute:
|
2018-11-19 16:38:52 +01:00
|
|
|
self.wrapped_data.setArgumentAsNull(idx)
|
2022-01-10 15:42:24 +11:00
|
|
|
else:
|
2022-10-04 10:21:45 +02:00
|
|
|
self.method_list[idx](
|
|
|
|
|
self.wrapped_data, idx, entity_instance.unwrap_value(value)
|
|
|
|
|
)
|
2018-11-19 16:38:52 +01:00
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
return value
|
2017-01-04 09:15:52 +01:00
|
|
|
|
|
|
|
|
def __len__(self):
|
|
|
|
|
return len(self.wrapped_data)
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
|
return repr(self.wrapped_data)
|
2022-10-08 17:18:47 +02:00
|
|
|
|
|
|
|
|
def to_string(self, valid_spf=True):
|
|
|
|
|
"""Returns a string representation of the current entity instance.
|
|
|
|
|
Equal to str(self) when valid_spf=False. When valid_spf is True
|
|
|
|
|
returns a representation of the string that conforms to valid Step
|
|
|
|
|
Physical File notation. The difference being entity names in upper
|
|
|
|
|
case and string attribute values with unicode values encoded per
|
|
|
|
|
the specific control directives.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
return self.wrapped_data.to_string(valid_spf)
|
2017-01-04 09:15:52 +01:00
|
|
|
|
|
|
|
|
def is_a(self, *args):
|
2020-04-02 06:04:38 +02:00
|
|
|
"""Return the IFC class name of an instance, or checks if an instance belongs to a class.
|
|
|
|
|
|
|
|
|
|
The check will also return true if a parent class name is provided.
|
|
|
|
|
|
|
|
|
|
:param args: If specified, is a case insensitive IFC class name to check
|
|
|
|
|
:type args: string
|
|
|
|
|
:returns: Either the name of the class, or a boolean if it passes the check
|
|
|
|
|
:rtype: string|bool
|
|
|
|
|
|
|
|
|
|
Example::
|
|
|
|
|
|
|
|
|
|
f = ifcopenshell.file()
|
|
|
|
|
f.create_entity('IfcPerson')
|
|
|
|
|
f.is_a()
|
|
|
|
|
>>> 'IfcPerson'
|
|
|
|
|
f.is_a('IfcPerson')
|
|
|
|
|
>>> True
|
|
|
|
|
"""
|
2017-01-04 09:15:52 +01:00
|
|
|
return self.wrapped_data.is_a(*args)
|
|
|
|
|
|
|
|
|
|
def id(self):
|
2020-04-02 05:53:14 +02:00
|
|
|
"""Return the STEP numerical identifier
|
|
|
|
|
|
|
|
|
|
:rtype: int
|
|
|
|
|
"""
|
2017-01-04 09:15:52 +01:00
|
|
|
return self.wrapped_data.id()
|
|
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
def __eq__(self, other):
|
2017-11-06 11:06:40 +01:00
|
|
|
if not isinstance(self, type(other)):
|
2017-11-06 09:10:28 +01:00
|
|
|
return False
|
2022-09-04 14:17:06 +02:00
|
|
|
# Proper entity instances have a stable identity by means of the numeric
|
|
|
|
|
# step id. Selected type instances (such as IfcPropertySingleValue.NominalValue
|
|
|
|
|
# always have id=0, so we compare <type, value, file pointer>
|
|
|
|
|
if self.id():
|
|
|
|
|
return self.wrapped_data == other.wrapped_data
|
|
|
|
|
else:
|
2022-10-04 10:21:45 +02:00
|
|
|
return (self.is_a(), self[0], self.wrapped_data.file_pointer()) == (
|
|
|
|
|
other.is_a(),
|
|
|
|
|
other[0],
|
|
|
|
|
other.wrapped_data.file_pointer(),
|
|
|
|
|
)
|
2017-01-04 09:15:52 +01:00
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
def __hash__(self):
|
2022-09-04 14:17:06 +02:00
|
|
|
# Proper entity instances have a stable identity by means of the numeric
|
|
|
|
|
# step id. Selected type instances (such as IfcPropertySingleValue.NominalValue
|
|
|
|
|
# always have id=0, so we hash <type, value, file pointer>
|
|
|
|
|
if self.id():
|
|
|
|
|
return hash((self.id(), self.wrapped_data.file_pointer()))
|
|
|
|
|
else:
|
|
|
|
|
return hash((self.is_a(), self[0], self.wrapped_data.file_pointer()))
|
2017-01-04 09:15:52 +01:00
|
|
|
|
2016-07-18 15:53:20 +02:00
|
|
|
def __dir__(self):
|
2020-11-01 20:08:27 +07:00
|
|
|
return sorted(
|
|
|
|
|
set(
|
|
|
|
|
itertools.chain(
|
|
|
|
|
dir(type(self)),
|
|
|
|
|
map(str, self.wrapped_data.get_attribute_names()),
|
|
|
|
|
map(str, self.wrapped_data.get_inverse_attribute_names()),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
2017-01-04 09:15:52 +01:00
|
|
|
|
2022-10-04 10:21:45 +02:00
|
|
|
def get_info(
|
|
|
|
|
self, include_identifier=True, recursive=False, return_type=dict, ignore=()
|
|
|
|
|
):
|
2020-04-02 05:53:14 +02:00
|
|
|
"""Return a dictionary of the entity_instance's properties (Python and IFC) and their values.
|
|
|
|
|
|
|
|
|
|
:param include_identifier: Whether or not to include the STEP numerical identifier
|
|
|
|
|
:type include_identifier: bool
|
|
|
|
|
:param recursive: Whether or not to convert referenced IFC elements into dictionaries too. All attributes also apply recursively
|
|
|
|
|
:type recursive: bool
|
|
|
|
|
:param return_type: The return data type to be casted into
|
|
|
|
|
:type return_type: dict|list|other
|
|
|
|
|
:param ignore: A list of attribute names to ignore
|
|
|
|
|
:type ignore: set|list
|
|
|
|
|
:returns: A dictionary of properties and their corresponding values
|
|
|
|
|
:rtype: dict
|
|
|
|
|
|
|
|
|
|
Example::
|
|
|
|
|
|
|
|
|
|
ifc_file = ifcopenshell.open(file_path)
|
|
|
|
|
products = ifc_file.by_type("IfcProduct")
|
|
|
|
|
obj_info = products[0].get_info()
|
|
|
|
|
print(obj_info.keys())
|
|
|
|
|
>>> dict_keys(['Description', 'Name', 'BuildingAddress', 'LongName', 'GlobalId', 'ObjectPlacement', 'OwnerHistory', 'ObjectType',
|
|
|
|
|
>>> ...'ElevationOfTerrain', 'CompositionType', 'id', 'Representation', 'type', 'ElevationOfRefHeight'])
|
2017-12-04 09:16:30 -08:00
|
|
|
"""
|
2020-11-01 20:08:27 +07:00
|
|
|
|
2017-08-04 16:30:43 +02:00
|
|
|
def _():
|
2017-01-01 16:19:39 +01:00
|
|
|
try:
|
2017-08-04 16:30:43 +02:00
|
|
|
if include_identifier:
|
|
|
|
|
yield "id", self.id()
|
|
|
|
|
yield "type", self.is_a()
|
2017-11-06 11:06:40 +01:00
|
|
|
except BaseException:
|
2022-10-04 10:21:45 +02:00
|
|
|
logging.exception(
|
|
|
|
|
"unhandled exception while getting id / type info on {}".format(
|
|
|
|
|
self
|
|
|
|
|
)
|
|
|
|
|
)
|
2017-08-04 16:30:43 +02:00
|
|
|
for i in range(len(self)):
|
|
|
|
|
try:
|
|
|
|
|
if self.wrapped_data.get_attribute_names()[i] in ignore:
|
|
|
|
|
continue
|
|
|
|
|
attr_value = self[i]
|
|
|
|
|
if recursive:
|
2020-11-01 20:08:27 +07:00
|
|
|
|
|
|
|
|
def is_instance(e):
|
|
|
|
|
return isinstance(e, entity_instance)
|
2017-11-06 09:10:28 +01:00
|
|
|
|
2017-08-04 16:30:43 +02:00
|
|
|
def get_info_(inst):
|
|
|
|
|
# for ty in ignore:
|
|
|
|
|
# if inst.is_a(ty):
|
|
|
|
|
# return None
|
2020-11-01 20:08:27 +07:00
|
|
|
return entity_instance.get_info(
|
|
|
|
|
inst,
|
|
|
|
|
include_identifier=include_identifier,
|
|
|
|
|
recursive=recursive,
|
|
|
|
|
return_type=return_type,
|
|
|
|
|
ignore=ignore,
|
|
|
|
|
)
|
2017-11-06 11:06:40 +01:00
|
|
|
|
2022-10-04 10:21:45 +02:00
|
|
|
attr_value = entity_instance.walk(
|
|
|
|
|
is_instance, get_info_, attr_value
|
|
|
|
|
)
|
2017-08-04 16:30:43 +02:00
|
|
|
yield self.attribute_name(i), attr_value
|
2017-11-06 11:06:40 +01:00
|
|
|
except BaseException:
|
2022-10-04 10:21:45 +02:00
|
|
|
logging.exception(
|
|
|
|
|
"unhandled exception occurred setting attribute name for {}".format(
|
|
|
|
|
self
|
|
|
|
|
)
|
|
|
|
|
)
|
2017-11-06 11:06:40 +01:00
|
|
|
|
2017-08-04 16:30:43 +02:00
|
|
|
return return_type(_())
|
2017-01-04 09:15:52 +01:00
|
|
|
|
|
|
|
|
__dict__ = property(get_info)
|
2021-06-30 18:34:12 +10:00
|
|
|
|
2022-10-04 10:21:45 +02:00
|
|
|
def get_info_2(
|
|
|
|
|
self, include_identifier=True, recursive=False, return_type=dict, ignore=()
|
|
|
|
|
):
|
2021-01-10 12:36:47 +01:00
|
|
|
assert include_identifier
|
|
|
|
|
assert recursive
|
|
|
|
|
assert return_type is dict
|
|
|
|
|
assert len(ignore) == 0
|
|
|
|
|
return ifcopenshell_wrapper.get_info_cpp(self.wrapped_data)
|