mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
#1807 method mapping proposal
This commit is contained in:
@@ -33,6 +33,51 @@ except ImportError as e:
|
||||
logging = type("logger", (object,), {"exception": staticmethod(lambda s: print(s))})
|
||||
|
||||
|
||||
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
|
||||
# 9 methods. The first will point at
|
||||
# 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 = {}
|
||||
for nm in ifcopenshell_wrapper.schema_names():
|
||||
schema = ifcopenshell_wrapper.schema_by_name(nm)
|
||||
for decl in schema.declarations():
|
||||
if isinstance(decl, ifcopenshell_wrapper.entity):
|
||||
fq_name = ".".join((nm, decl.name()))
|
||||
|
||||
# get type strings as reported by IfcOpenShell C++
|
||||
type_strs = decl.argument_types()
|
||||
|
||||
# convert case for setter function
|
||||
type_strs = [x.title().replace(" ", "") for x in type_strs]
|
||||
|
||||
# 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]
|
||||
|
||||
# prefix to get method names
|
||||
fn_names = ["setArgumentAs" + x for x in type_strs]
|
||||
|
||||
# resolve to actual functions in wrapper
|
||||
functions = [
|
||||
set_derived_atribute if mname == "setArgumentAsDerived" else getattr(ifcopenshell_wrapper.entity_instance, mname) \
|
||||
for mname in fn_names]
|
||||
|
||||
_method_dict[fq_name] = functions
|
||||
|
||||
|
||||
class entity_instance(object):
|
||||
"""This is the base Python class for all IFC objects.
|
||||
|
||||
@@ -52,6 +97,7 @@ class entity_instance(object):
|
||||
if isinstance(e, tuple):
|
||||
e = ifcopenshell_wrapper.new_IfcBaseClass(*e)
|
||||
super(entity_instance, self).__setattr__("wrapped_data", e)
|
||||
super(entity_instance, self).__setattr__("method_list", None)
|
||||
self.wrapped_data.file = file
|
||||
|
||||
def __getattr__(self, name):
|
||||
@@ -65,7 +111,7 @@ class entity_instance(object):
|
||||
return entity_instance.wrap_value(self.wrapped_data.get_inverse(name), self.wrapped_data.file)
|
||||
else:
|
||||
raise AttributeError(
|
||||
"entity instance of type '%s' has no attribute '%s'" % (self.wrapped_data.is_a(), name)
|
||||
"entity instance of type '%s' has no attribute '%s'" % (self.wrapped_data.is_a(True), name)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -129,38 +175,16 @@ class entity_instance(object):
|
||||
if self.wrapped_data.file and self.wrapped_data.file.transaction:
|
||||
self.wrapped_data.file.transaction.store_edit(self, idx, value)
|
||||
|
||||
attr_type = real_attr_type = self.attribute_type(idx).title().replace(" ", "")
|
||||
real_attr_type = real_attr_type.replace("Derived", "None")
|
||||
attr_type = attr_type.replace("Binary", "String")
|
||||
attr_type = attr_type.replace("Enumeration", "String")
|
||||
|
||||
if self.method_list is None:
|
||||
super(entity_instance, self).__setattr__("method_list", _method_dict[self.is_a(True)])
|
||||
|
||||
method = self.method_list[idx]
|
||||
|
||||
if value is None:
|
||||
if attr_type != "Derived":
|
||||
if method is not set_derived_atribute:
|
||||
self.wrapped_data.setArgumentAsNull(idx)
|
||||
else:
|
||||
valid = attr_type != "Derived"
|
||||
if valid:
|
||||
try:
|
||||
if isinstance(value, unicode):
|
||||
value = value.encode("utf-8")
|
||||
except BaseException:
|
||||
pass
|
||||
|
||||
try:
|
||||
if attr_type != "Derived":
|
||||
getattr(self.wrapped_data, "setArgumentAs%s" % attr_type)(
|
||||
idx, entity_instance.unwrap_value(value)
|
||||
)
|
||||
except BaseException as e:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
valid = False
|
||||
|
||||
if not valid:
|
||||
raise ValueError(
|
||||
"Expected %s for attribute %s.%s, got %r"
|
||||
% (real_attr_type, self.is_a(), self.attribute_name(idx), value)
|
||||
)
|
||||
else:
|
||||
self.method_list[idx](self.wrapped_data, idx, entity_instance.unwrap_value(value))
|
||||
|
||||
return value
|
||||
|
||||
|
||||
@@ -134,3 +134,18 @@ const IfcParse::schema_definition* IfcParse::schema_by_name(const std::string& n
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::vector<std::string> IfcParse::schema_names() {
|
||||
// Load schema modules
|
||||
try {
|
||||
IfcParse::schema_by_name("IFC2X3");
|
||||
} catch (IfcParse::IfcException&) {}
|
||||
|
||||
// Populate vector with map keys
|
||||
std::vector<std::string> return_value;
|
||||
for (auto& pair : schemas) {
|
||||
return_value.push_back(pair.first);
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
@@ -448,7 +448,9 @@ namespace IfcParse {
|
||||
|
||||
IFC_PARSE_API const schema_definition* schema_by_name(const std::string&);
|
||||
|
||||
void register_schema(schema_definition*);
|
||||
IFC_PARSE_API std::vector<std::string> schema_names();
|
||||
|
||||
IFC_PARSE_API void register_schema(schema_definition*);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -225,8 +225,12 @@ static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClas
|
||||
return self->declaration().is(s);
|
||||
}
|
||||
|
||||
std::string is_a() const {
|
||||
return self->declaration().name();
|
||||
std::string is_a(bool with_schema=false) const {
|
||||
auto t = self->declaration().name();
|
||||
if (with_schema) {
|
||||
t = self->declaration().schema()->name() + "." + t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
std::pair<IfcUtil::ArgumentType,Argument*> get_argument(unsigned i) {
|
||||
@@ -661,11 +665,12 @@ static IfcUtil::ArgumentType helper_fn_attribute_type(const IfcUtil::IfcBaseClas
|
||||
auto pt = attr->type_of_attribute();
|
||||
if ($self->derived()[i++]) {
|
||||
at = IfcUtil::Argument_DERIVED;
|
||||
}
|
||||
if (pt == 0) {
|
||||
} else if (!pt) {
|
||||
at = IfcUtil::Argument_UNKNOWN;
|
||||
} else {
|
||||
at = IfcUtil::from_parameter_type(pt);
|
||||
}
|
||||
r.push_back(IfcUtil::ArgumentTypeToString(IfcUtil::from_parameter_type(pt)));
|
||||
r.push_back(IfcUtil::ArgumentTypeToString(at));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user