This commit is contained in:
Dion Moult
2026-07-26 18:03:09 +10:00
parent 7aa967b01a
commit 291d7d8441
72 changed files with 477 additions and 377 deletions
+1 -6
View File
@@ -206,12 +206,7 @@ class CostSchedulesData:
data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(unit)
if quantity.is_a("IfcPhysicalSimpleQuantity"):
measure_class = (
quantity.declaration
.as_entity()
.attribute_by_index(3)
.type_of_attribute()
.declared_type()
.name()
quantity.declaration.as_entity().attribute_by_index(3).type_of_attribute().declared_type().name()
)
if "Count" in measure_class:
data["UnitSymbol"] = "U"
@@ -1057,7 +1057,9 @@ class CreateDrawing(bpy.types.Operator):
# Specifically for PLAN_VIEW and REFLECTED_PLAN_VIEW, any Plan context is also prioritised.
contexts = self.get_linework_contexts(ifc, target_view)
self.serialize_contexts_elements(ifc, tree, contexts, "body", drawing_elements, target_view, link_matrix)
self.serialize_contexts_elements(ifc, tree, contexts, "annotation", drawing_elements, target_view, link_matrix)
self.serialize_contexts_elements(
ifc, tree, contexts, "annotation", drawing_elements, target_view, link_matrix
)
if tool.Ifc.get() == ifc and self.camera_element not in drawing_elements:
with profile("Camera element"):
+2 -2
View File
@@ -308,9 +308,9 @@ def add_drawing(
group = ifc.run("group.add_group")
ifc.run("group.edit_group", group=group, attributes={"Name": drawing_name, "ObjectType": "DRAWING"})
ifc.run("group.assign_group", group=group, products=[element])
ifc.run("group.assign_group", group=drawings_parent_group, products=[group])
collector.assign(camera)
pset = ifc.run("pset.add_pset", product=element, name="EPset_Drawing")
if drawing.get_unit_system() == "METRIC":
@@ -109,4 +109,5 @@ class BlenderImporter:
print("Done creating geometry")
return results
BlenderImporter().execute()
@@ -146,7 +146,9 @@ def test_fit_flow_segments_with_single_segment_dispatches_obstruction():
mep.tool.Model, "get_flow_segment_profile", return_value=segment_profile
), patch.object(mep.MEPAddObstruction, "_execute", return_value=None) as obstruction, patch.object(
mep.MEPAddBend, "_execute", return_value=None
) as bend, patch.object(mep.MEPAddTransition, "_execute", return_value=None) as transition:
) as bend, patch.object(
mep.MEPAddTransition, "_execute", return_value=None
) as transition:
mep.FitFlowSegments._execute(op, context=context)
assert obstruction.call_count == 1
@@ -178,7 +180,9 @@ def test_fit_flow_segments_refuses_mixed_pipe_and_duct():
mep.tool.Model, "get_flow_segment_profile", return_value=profile
), patch.object(mep.MEPAddObstruction, "_execute", return_value=None) as obstruction, patch.object(
mep.MEPAddBend, "_execute", return_value=None
) as bend, patch.object(mep.MEPAddTransition, "_execute", return_value=None) as transition:
) as bend, patch.object(
mep.MEPAddTransition, "_execute", return_value=None
) as transition:
mep.FitFlowSegments._execute(op, context=context)
obstruction.assert_not_called()
@@ -173,8 +173,9 @@ def test_gizmo_group_class_wiring(gizmo_cls_name, bl_idname, is_element_predicat
predicate = getattr(tool.Parametric, is_element_predicate)
fake_element = Mock()
fake_element.is_a.return_value = True
with patch.object(tool.Parametric, is_element_predicate, side_effect=predicate) as p, patch.object(
tool.System, "has_parametric_body", return_value=True
with (
patch.object(tool.Parametric, is_element_predicate, side_effect=predicate) as p,
patch.object(tool.System, "has_parametric_body", return_value=True),
):
cls.is_element_type(fake_element)
assert p.called, f"{gizmo_cls_name}.is_element_type did not delegate to Parametric.{is_element_predicate}"
@@ -139,6 +139,5 @@ def test_every_cancel_ops_entry_has_a_real_preview_propertygroup() -> None:
orphaned = [attr for attr, _op in preview_base.PREVIEW_CANCEL_OPS if attr not in declared_attrs]
assert not orphaned, (
"PREVIEW_CANCEL_OPS contains entries whose PointerProperty child no longer "
f"exists on {UMBRELLA_CLASS}. Drop the stale tuple(s):\n "
+ "\n ".join(orphaned)
f"exists on {UMBRELLA_CLASS}. Drop the stale tuple(s):\n " + "\n ".join(orphaned)
)
+4 -6
View File
@@ -29,11 +29,11 @@ import zipfile
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent.parent
DIST_DIR = PROJECT_ROOT / "dist"
TARGET_DIR = PROJECT_ROOT / "target" / "release"
DIST_DIR = PROJECT_ROOT / "dist"
TARGET_DIR = PROJECT_ROOT / "target" / "release"
CONNECTOR_FOLDER_NAME = "autodesk"
BINARY_NAME = "bonsaiviewer-autodesk"
BINARY_NAME = "bonsaiviewer-autodesk"
def _platform_tag() -> str:
@@ -73,9 +73,7 @@ def main() -> None:
bin_src = TARGET_DIR / _binary_name_for_host()
if not bin_src.exists():
raise FileNotFoundError(
f"cargo build did not produce expected binary at {bin_src}"
)
raise FileNotFoundError(f"cargo build did not produce expected binary at {bin_src}")
bundle_dir = DIST_DIR / CONNECTOR_FOLDER_NAME
bundle_dir.mkdir(parents=True)
+5 -3
View File
@@ -57,7 +57,8 @@ class CsvHeader(TypedDict):
# Formula
Formula: NotRequired[str]
#QuantityClass: NotRequired[str]
# QuantityClass: NotRequired[str]
# Currently we assume that if column is not part of the main header,
# then it is a cost value category. So here we list any additional column
@@ -97,7 +98,8 @@ class CostItem(TypedDict):
Query: Union[str, None]
Formula: Union[str, None]
#QuantityClass: Union[str, None]
# QuantityClass: Union[str, None]
class Csv2Ifc:
# Inputs.
@@ -420,7 +422,7 @@ class Csv2Ifc:
products=results,
formula=cost_item["Formula"],
ifc_class=ifc_quantity_class,
)
)
self.create_cost_items(cost_item["children"], cost_item["ifc"])
+1 -6
View File
@@ -168,12 +168,7 @@ class ifc5D2json:
data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(unit)
if quantity.is_a("IfcPhysicalSimpleQuantity"):
measure_class = (
quantity.declaration
.as_entity()
.attribute_by_index(3)
.type_of_attribute()
.declared_type()
.name()
quantity.declaration.as_entity().attribute_by_index(3).type_of_attribute().declared_type().name()
)
if "Count" in measure_class:
data["UnitSymbol"] = "U"
@@ -107,6 +107,7 @@ else:
def optional_logger_args(logger: ifcopenshell_wrapper.logger | None) -> tuple[logger] | tuple[()]:
return (logger,) if logger is not None else ()
# explicitly specify available imported symbols
# (it's a requirement for a typed library)
__all__ = [
@@ -87,9 +87,7 @@ def create(
_create_geometric_representation(file, alignment)
referent_name = ifcopenshell.util.alignment.station_as_string(file, start_station)
referent = ifcopenshell.api.alignment.add_stationing_referent(
file, referent_name, alignment, 0.0, start_station
)
referent = ifcopenshell.api.alignment.add_stationing_referent(file, referent_name, alignment, 0.0, start_station)
for layout in alignment_layouts:
_add_zero_length_segment(file, layout)
@@ -73,7 +73,10 @@ def distance_along_from_station(file: ifcopenshell.file, alignment: entity_insta
return station - start_station
stations = [
(_distance_along_of_referent(referent), ifcopenshell.util.element.get_pset(referent, name="Pset_Stationing", prop="Station"))
(
_distance_along_of_referent(referent),
ifcopenshell.util.element.get_pset(referent, name="Pset_Stationing", prop="Station"),
)
for referent in referent_nest.RelatedObjects
]
stations.sort(key=lambda entry: entry[0])
@@ -161,7 +161,18 @@ keywords = list(filter(operator.attrgetter("is_keyword"), terminals))
# terminals is identity-ordered (no __eq__/__hash__), so sort for determinism
keywords.sort(key=lambda x: repr(x))
negated_keywords = map(lambda s: "~%s" % s, keywords)
no_action = {"letter", "digit", "digits", "real_literal", "integer_literal", "string_literal", "simple_string_literal", "letter", "not_quote", "not_paren_star_quote_special"}
no_action = {
"letter",
"digit",
"digits",
"real_literal",
"integer_literal",
"string_literal",
"simple_string_literal",
"letter",
"not_quote",
"not_paren_star_quote_special",
}
while True:
emitted_in_loop = set()
@@ -197,7 +208,9 @@ for id in sorted(to_emit):
elif id in to_original_text:
stmt = "(original_text_for%s).add_parse_action(token_map(str.lower))" % stmt
if id not in no_action and not isinstance(expr.contents, Keyword):
children = list(map(operator.attrgetter('contents'), reduce(lambda x, y: x | y, (find_bytype(e, Keyword) for e in [expr]))))
children = list(
map(operator.attrgetter("contents"), reduce(lambda x, y: x | y, (find_bytype(e, Keyword) for e in [expr])))
)
has_duplicates = len(children) > len(set(children))
node_type = "ListNode" if ("ZeroOrMore" in stmt or has_duplicates) else "Node"
action = ".set_parse_action(%s)" % (
@@ -246,6 +259,4 @@ if __name__ == "__main__":
mdl = importlib.import_module(output)
mdl.Generator(m).emit()
sys.stdout.write(m.schema.name)
"""
% ("\n ".join(statements))
)
""" % ("\n ".join(statements)))
@@ -1,15 +1,16 @@
import sys, fileinput
if sys.platform == "win32" and not hasattr(sys.stdout, 'buffer'):
if sys.platform == "win32" and not hasattr(sys.stdout, "buffer"):
import os, msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
files = sys.argv[1:]
if files[0] == '-o':
b = open(files[1], 'wb')
if files[0] == "-o":
b = open(files[1], "wb")
files = files[2:]
else:
b = getattr(sys.stdout, 'buffer', sys.stdout)
b = getattr(sys.stdout, "buffer", sys.stdout)
for line in fileinput.input(files=files, mode='rb'):
for line in fileinput.input(files=files, mode="rb"):
b.write(line)
@@ -27,7 +27,7 @@ def indent(n, s):
else:
strs = s
splitted = itertools.chain.from_iterable(map(functools.partial(str.split, sep="\n"), map(str, strs)))
return "\n".join(" "*n + l for l in splitted)
return "\n".join(" " * n + l for l in splitted)
class Base:
@@ -26,6 +26,7 @@ import documentation
from collections import defaultdict
class Header(codegen.Base):
def __init__(self, mapping):
declarations = []
@@ -41,7 +42,12 @@ class Header(codegen.Base):
% dict({"documentation": templates.multi_line_comment(documentation.description(kwargs["name"]))}, **kwargs)
)
forward_names = list(mapping.schema.entities.keys()) + list(mapping.schema.simpletypes.keys()) + list(mapping.schema.selects.keys()) + list(mapping.schema.enumerations.keys())
forward_names = (
list(mapping.schema.entities.keys())
+ list(mapping.schema.simpletypes.keys())
+ list(mapping.schema.selects.keys())
+ list(mapping.schema.enumerations.keys())
)
forward_definitions = "".join(["class %s; " % n for n in forward_names])
select_super_types = defaultdict(list)
@@ -57,11 +63,14 @@ class Header(codegen.Base):
yield x
if mapping.schema.is_select(x):
yield from visit_select(mapping.schema.selects[x])
write(templates.select,
name=name,
template_items="\n".join(templates.select_list_item % {'item_name': nm} for nm in visit_select(type)),
cast_functions="\n".join(templates.select_cast_function % {'name': name, 'item_name': nm} for nm in visit_select(type)),
write(
templates.select,
name=name,
template_items="\n".join(templates.select_list_item % {"item_name": nm} for nm in visit_select(type)),
cast_functions="\n".join(
templates.select_cast_function % {"name": name, "item_name": nm} for nm in visit_select(type)
),
)
def get_select_super_types(nm, bases=[]):
@@ -115,10 +124,15 @@ class Header(codegen.Base):
# with the v1 data model we're back to exactly one supertype, no more virtual inheritance to handle selects
assert len(superclasses) == 1
superclass_statement = superclasses[0]
superclass_2 = superclass_statement.split('::')[-1]
superclass_2 = superclass_statement.split("::")[-1]
write(
templates.simpletype, name=name, type=type_str, attr_type=attr_type, superclass=superclass_statement, superclass_2=superclass_2
templates.simpletype,
name=name,
type=type_str,
attr_type=attr_type,
superclass=superclass_statement,
superclass_2=superclass_2,
)
class_definitions = []
@@ -145,7 +159,7 @@ class Header(codegen.Base):
if mapping.make_argument_type(attr) != "ifcopenshell::Argument_UNKNOWN":
attr_lines.append("%s %s() const;" % (type_str, attr.name))
attr_lines.append("void set%s(const %s& v);" % (attr.name, type_str))
if type_str == 'std::optional< std::string >':
if type_str == "std::optional< std::string >":
# because a 2-step char[] -> std::string -> optional<string> is not allowed
# attr_lines.append("void set%s(const %s& v);" % (attr.name, 'std::string'))
pass
@@ -182,7 +196,7 @@ class Header(codegen.Base):
supertypes = list(map(case_normalize, supertypes))
assert len(supertypes) == 1
superclass = supertypes[0]
superclass_2 = superclass.split('::')[-1]
superclass_2 = superclass.split("::")[-1]
argument_count = mapping.argument_count(type)
@@ -67,7 +67,7 @@ class Implementation(codegen.Base):
templates.enum_from_string_stmt % dict(context, **locals()) for value in enum.values
),
)
for name, enum in mapping.schema.selects.items():
write(
templates.select_function,
@@ -107,21 +107,18 @@ class Implementation(codegen.Base):
return templates.get_attr_stmt_nested_array
elif arg["is_templated_list"] and not (simple or express):
return templates.get_attr_stmt_array
elif arg["argument_type_enum"] == 'ifcopenshell::Argument_ENTITY_INSTANCE':
elif arg["argument_type_enum"] == "ifcopenshell::Argument_ENTITY_INSTANCE":
return templates.get_attr_stmt_entity
else:
return templates.get_attr_stmt
null_check = ""
if arg["is_optional"]:
attr_check = (
"if(get_attribute_value(%d).isNull()) { return %%s; }"
% (arg["index"] - 1,)
)
attr_check = "if(get_attribute_value(%d).isNull()) { return %%s; }" % (arg["index"] - 1,)
if "std::optional" in arg["full_type"]:
null_check = attr_check % "std::nullopt"
else:
null_check = attr_check % (arg['full_type'] + "{}")
null_check = attr_check % (arg["full_type"] + "{}")
tmpl = find_template(arg)
write_attr(
@@ -154,7 +151,7 @@ class Implementation(codegen.Base):
return templates.set_attr_stmt_nested_array
elif arg["is_templated_list"] and not (simple or express):
return templates.set_attr_stmt_array
elif arg["argument_type_enum"] == 'ifcopenshell::Argument_ENTITY_INSTANCE':
elif arg["argument_type_enum"] == "ifcopenshell::Argument_ENTITY_INSTANCE":
return templates.set_attr_instance
else:
return templates.set_attr_stmt
@@ -175,7 +172,9 @@ class Implementation(codegen.Base):
"non_optional_type": arg["non_optional_type"].replace("::Value", ""),
"star_if_optional": "*" if "std::optional" in arg["full_type"] else "",
"check_optional_set_begin": "if (v) {" if "std::optional" in arg["full_type"] else "",
"check_optional_set_else": "} else {" if "std::optional" in arg["full_type"] else "if constexpr (false)",
"check_optional_set_else": (
"} else {" if "std::optional" in arg["full_type"] else "if constexpr (false)"
),
"check_optional_set_end": "}" if "std::optional" in arg["full_type"] else "",
},
)
@@ -190,11 +189,15 @@ class Implementation(codegen.Base):
tmpl = (
templates.constructor_stmt_array
if arg["is_templated_list"]
else templates.constructor_stmt_enum
if arg["is_enum"]
else templates.constructor_stmt_instance
if arg["full_type"].endswith('*')
else templates.constructor_stmt
else (
templates.constructor_stmt_enum
if arg["is_enum"]
else (
templates.constructor_stmt_instance
if arg["full_type"].endswith("*")
else templates.constructor_stmt
)
)
)
impl = tmpl % {
"name": deref_name,
@@ -236,11 +239,7 @@ class Implementation(codegen.Base):
for i in type.inverse
]
superclass = (
"%s(e)" % type.supertypes[0]
if len(type.supertypes) == 1
else "express::Entity(e)"
)
superclass = "%s(e)" % type.supertypes[0] if len(type.supertypes) == 1 else "express::Entity(e)"
superclass_num_attrs = (
"%s(const std::weak_ptr<instance_data>&(in_memory_attribute_storage(%%d)))" % type.supertypes[0]
@@ -371,7 +370,17 @@ class Implementation(codegen.Base):
# ("const std::weak_ptr<instance_data>& e",),
# "",
# ),
("", "", initializer, "", ("%s v" % type_str,), ("set_attribute_value(0, %s(v));" % ("cast_vector<express::Base>" if mapping.is_templated_list(type) else ""))),
(
"",
"",
initializer,
"",
("%s v" % type_str,),
(
"set_attribute_value(0, %s(v));"
% ("cast_vector<express::Base>" if mapping.is_templated_list(type) else "")
),
),
# ("v", "", constructor, "", ("%s v" % type_str,), ""),
("", "", templates.cast_function, type_str, (), simpletype_impl_cast),
),
@@ -23,6 +23,7 @@ import operator
import collections
import bootstrap
class Node:
def __init__(self, s, loc, tokens, rule=None):
self.rule = rule or (type(self).__name__)
@@ -58,15 +59,15 @@ class ListNode:
rules_as_list = set()
for t in self.tokens:
r = getattr(t, 'rule', None)
r = getattr(t, "rule", None)
if r:
rules_as_list.add(r)
self.dict_tokens[r].append(t)
for r, t in tokens.asDict().items():
if r not in rules_as_list:
self.dict_tokens[r].append(t)
self.flat = sum([getattr(t, "flat", [t]) for t in self.tokens], [])
def __repr__(self):
@@ -74,7 +75,7 @@ class ListNode:
def __iter__(self):
return iter(self.tokens)
# Somehow indexing messes up the pyparsing results, so instead of x[0] use list(x)[0]
# def __getitem__(self, i):
# return self.tokens[i]
@@ -110,7 +111,7 @@ def format_clause(exp):
return "".join(whitespace(term) for term in exp.flat)
class TypeDeclaration(Node):
class TypeDeclaration(Node):
name = property(lambda self: self.type_id[0])
utype = property(lambda self: self.underlying_type.any().any())
type = property(lambda self: self.utype[0] if isinstance(self.utype, list) else self.utype)
@@ -245,7 +246,8 @@ class NamedType(Node):
def do_try(fn):
try:
return fn()
except: pass
except:
pass
def get_rule_id(x):
@@ -255,8 +257,14 @@ def get_rule_id(x):
if matches:
return matches[0]
rule_dependencies = {
k: list(map(operator.attrgetter('contents'), bootstrap.reduce(lambda x, y: x | y, (bootstrap.find_bytype(e, bootstrap.Keyword) for e in [v])))) \
k: list(
map(
operator.attrgetter("contents"),
bootstrap.reduce(lambda x, y: x | y, (bootstrap.find_bytype(e, bootstrap.Keyword) for e in [v])),
)
)
for k, v in bootstrap.express
}
@@ -264,16 +272,17 @@ all_rules = [k for k, e in bootstrap.express]
rule_definitions = {k: v for k, v in bootstrap.express}
def to_tree(x, key=None):
def prune(di):
# translate class names back to grammar rules if nested actions are encountered
di = {get_rule_id(k) or k: v for k, v in di.items()}
def replace_synonyms(x):
for y in x:
yield y
if False: # y in di:
if False: # y in di:
# production element from grammar is found in parsed data,
# return that.
@@ -292,19 +301,21 @@ def to_tree(x, key=None):
yield S
# Do this recursively
yield from replace_synonyms([S])
# is this a concatenation with zero or more synonyms? then also processs that
# @todo catches:
# - simple_expression = term { add_like_op term } .
# but should probably also work on
# - a = b { b }
# in which case the second Concat would be eliminated
elif isinstance(rule, bootstrap.Concat) and \
len(rule.contents) == 2 and \
is_synonym(rule.contents[0]) and \
isinstance(rule.contents[1].contents, bootstrap.Repeated) and \
isinstance(rule.contents[1].contents.contents[0], bootstrap.Concat) and \
str(rule.contents[1].contents.contents[0].contents[1]) == str(rule.contents[0]):
elif (
isinstance(rule, bootstrap.Concat)
and len(rule.contents) == 2
and is_synonym(rule.contents[0])
and isinstance(rule.contents[1].contents, bootstrap.Repeated)
and isinstance(rule.contents[1].contents.contents[0], bootstrap.Concat)
and str(rule.contents[1].contents.contents[0].contents[1]) == str(rule.contents[0])
):
S = is_synonym(rule.contents[0])
yield S
# Do this recursively
@@ -315,13 +326,13 @@ def to_tree(x, key=None):
if key == "aggregation_types":
# hack hack hack apparently the parser can't distinguish these
subrules += list(replace_synonyms(rule_dependencies["general_aggregation_types"]))
if rule_dependencies[key] and not subrules:
# sometimes an intermediate production rule is missing
# from the pyparsing output, e.g from parameter to simple_expression
# directly. Recover from this.
subrules = sum(map(rule_dependencies.__getitem__, rule_dependencies[key]), [])
if not isinstance(rule_definitions[key], bootstrap.Union):
# Filter out terminals when not a union. E.g no
# reason to retain TYPE, END_TYPE, but operators
@@ -331,7 +342,7 @@ def to_tree(x, key=None):
vs = list(di.values())
return {k: v for k, v in di.items() if k in subrules or (k == key and len(vs) == 1 and vs[0] not in all_rules)}
def simplify(di):
if isinstance(di, list):
if set(map(type, di)) == {str} and set(map(len, di)) == {1}:
@@ -343,11 +354,11 @@ def to_tree(x, key=None):
return {k: simplify(v) for k, v in di.items()}
else:
return di
if isinstance(x, ListNode):
d = to_tree(x.dict_tokens, key=get_rule_id(x) or key)
if key == 'if_stmt':
if key == "if_stmt":
# The definition of if statement if (roughy):
# 'if' expr 'then' stmt+ 'else' stmt+
# this causes stmt to be joined under the same
@@ -355,39 +366,41 @@ def to_tree(x, key=None):
# `else_stmt` that collects the second group
# of stmts.
statements = x.dict_tokens['stmt']
statements = x.dict_tokens["stmt"]
else_index = None
if_nesting = 0
for i, tk in enumerate(x.flat):
if tk == 'if': if_nesting += 1
if tk == 'end_if': if_nesting -= 1
if tk == 'else' and if_nesting == 1:
for i, tk in enumerate(x.flat):
if tk == "if":
if_nesting += 1
if tk == "end_if":
if_nesting -= 1
if tk == "else" and if_nesting == 1:
else_index = i
if else_index:
indices = []
for s in statements:
for i in range(max(indices, default=0), len(x.flat)):
if x.flat[i:i+len(s.flat)] == s.flat:
if x.flat[i : i + len(s.flat)] == s.flat:
indices.append(i)
break
assert len(indices) == len(statements)
before_else = [i < else_index for i in indices]
else_stmt = [st for b, st in zip(before_else, d['stmt']) if not b]
d['stmt'] = [st for b, st in zip(before_else, d['stmt']) if b]
else_stmt = [st for b, st in zip(before_else, d["stmt"]) if not b]
d["stmt"] = [st for b, st in zip(before_else, d["stmt"]) if b]
if else_stmt:
d['else_stmt'] = else_stmt
if key == 'formal_parameter':
d["else_stmt"] = else_stmt
if key == "formal_parameter":
# Not so pretty hack to fix the overwriting of simple_id-like
# ast nodes. The full solution would probably to register parse
# actions. And directly reassign.
pid = d['parameter_id'][0][0]
d['parameter_id'][0] = x.flat[:x.flat.index(pid)+1:2]
pid = d["parameter_id"][0][0]
d["parameter_id"][0] = x.flat[: x.flat.index(pid) + 1 : 2]
if key is None:
return {get_rule_id(x): d}
@@ -400,7 +413,10 @@ def to_tree(x, key=None):
elif isinstance(x, dict):
# d = {k: to_tree(v, key=k) for k, v in x.items()}
# not fully understood, but when finding specific node Types and production rules, prioritize the former
d = {get_rule_id(k) or k: to_tree(v, key=k) for k, v in sorted(x.items(), key=lambda p: get_rule_id(p[0]) is not None)}
d = {
get_rule_id(k) or k: to_tree(v, key=k)
for k, v in sorted(x.items(), key=lambda p: get_rule_id(p[0]) is not None)
}
return simplify(prune(d))
elif isinstance(x, list):
return [to_tree(v, key=key) for v in x]
@@ -459,7 +475,8 @@ class SuperTypeExpression(Node):
else:
constraint = self.supertype_rule[0]
return [
list(list(s)[0])[0].simple_id for s in list(list(list(constraint.subtype_constraint[0].supertype_expression[0])[0])[0].one_of[0])[2::2]
list(list(s)[0])[0].simple_id
for s in list(list(list(constraint.subtype_constraint[0].supertype_expression[0])[0])[0].one_of[0])[2::2]
]
sub_types = property(get_sub_types)
@@ -576,10 +593,11 @@ class ProcedureDeclaration(ListNode):
@property
def name(self):
return self.flat[1]
class FunctionDeclaration(ProcedureDeclaration):
pass
class RuleDeclaration(ProcedureDeclaration):
pass
@@ -695,6 +695,7 @@ codegen_rule("MOD", lambda context: "%")
codegen_rule("TRUE", lambda context: "True")
codegen_rule("FALSE", lambda context: "False")
def _dotted_name(node: ast.AST):
"""Return dotted name for Name/Attribute chains, else None."""
if isinstance(node, ast.Name):
@@ -704,6 +705,7 @@ def _dotted_name(node: ast.AST):
return f"{base}.{node.attr}" if base else node.attr
return None
class AttributeGetattrTransformer(ast.NodeTransformer):
def visit_Attribute(self, node):
parents = []
@@ -720,7 +722,7 @@ class AttributeGetattrTransformer(ast.NodeTransformer):
if isinstance(node.ctx, ast.Store):
return node
if _dotted_name(node) in ('ifcopenshell.create_entity', 'str.lower'):
if _dotted_name(node) in ("ifcopenshell.create_entity", "str.lower"):
return node
if node.attr.startswith("__"):
@@ -87,14 +87,8 @@ class Schema:
sort = lambda d: OrderedCaseInsensitiveDict(sorted(d))
declarations = [
d.any()[0]
for d in schema_declarations
if d.rule == "declaration"
] + [
d
for d in schema_declarations
if d.rule == "RuleDeclaration"
declarations = [d.any()[0] for d in schema_declarations if d.rule == "declaration"] + [
d for d in schema_declarations if d.rule == "RuleDeclaration"
]
self.types = sort([(t.name, t) for t in declarations if isinstance(t, nodes.TypeDeclaration)])
@@ -102,8 +96,12 @@ class Schema:
self.rules = sort([(t.name, t) for t in declarations if isinstance(t, nodes.RuleDeclaration)])
self.functions = sort([(t.name, t) for t in declarations if isinstance(t, nodes.FunctionDeclaration)])
self.keys = list(self.types.keys()) + list(self.entities.keys()) + list(self.rules.keys()) + list(self.functions.keys())
self.all_declarations = {k: v for d in (self.types, self.entities, self.rules, self.functions) for k, v in d.items()}
self.keys = (
list(self.types.keys()) + list(self.entities.keys()) + list(self.rules.keys()) + list(self.functions.keys())
)
self.all_declarations = {
k: v for d in (self.types, self.entities, self.rules, self.functions) for k, v in d.items()
}
of_type = lambda *types: sort(
[(a, b.type) for a, b in self.types.items() if any(isinstance(b.type, ty) for ty in types)]
@@ -110,9 +110,7 @@ class LateBoundSchemaInstantiator:
self.declarations[str(name)].set_subtypes([self.declarations[str(v)] for v in tys])
def finalize(self, can_be_instantiated_set, override_schema_name=None):
self.schema = w.schema_definition(
override_schema_name or self.schema_name, list(self.declarations.values())
)
self.schema = w.schema_definition(override_schema_name or self.schema_name, list(self.declarations.values()))
def disown(self):
for elem in self.cache + list(self.declarations.values()):
@@ -123,6 +121,7 @@ class string_pool:
def __init__(self, fn):
self.di = {}
self.fn = fn
def append(self, v):
def _():
if i := self.di.get(v):
@@ -131,7 +130,9 @@ class string_pool:
i = len(self.di)
self.di[v] = i
return i
return self.fn(_())
def __iter__(self):
return iter(self.di.keys())
@@ -146,9 +147,9 @@ class EarlyBoundCodeWriter:
"",
'#include "../../ifcparse/schema.h"',
'#include "../../ifcparse/schemas/%(schema_name_title)s.h"' % self.__dict__,
'#include <string>',
"#include <string>",
"",
'using namespace std::string_literals;',
"using namespace std::string_literals;",
"using namespace ifcopenshell;",
"",
]
@@ -180,18 +181,18 @@ class EarlyBoundCodeWriter:
# self.statements.append("{factory_placeholder}")
# self.statements.append(
# """
# #if defined(__clang__)
# __attribute__((optnone))
# #elif defined(__GNUC__) || defined(__GNUG__)
# #pragma GCC push_options
# #pragma GCC optimize ("O0")
# #elif defined(_MSC_VER)
# #pragma optimize("", off)
# #endif
# """
# )
# self.statements.append(
# """
# #if defined(__clang__)
# __attribute__((optnone))
# #elif defined(__GNUC__) || defined(__GNUG__)
# #pragma GCC push_options
# #pragma GCC optimize ("O0")
# #elif defined(_MSC_VER)
# #pragma optimize("", off)
# #endif
# """
# )
self.statements.append("ifcopenshell::schema_definition* %s_populate_schema() {" % self.schema_name.upper())
self.statements.append("{string_pool_placeholder}")
@@ -200,7 +201,7 @@ class EarlyBoundCodeWriter:
index_in_schema = self.names.index(name)
ref = self.strings.append(name)
self.statements.append(
' %(schema_name)s_types[%(index_in_schema)d] = new type_declaration(%(ref)s, %(index_in_schema)d, %(declared_type)s);'
" %(schema_name)s_types[%(index_in_schema)d] = new type_declaration(%(ref)s, %(index_in_schema)d, %(declared_type)s);"
% locals()
)
@@ -210,7 +211,7 @@ class EarlyBoundCodeWriter:
ref = self.strings.append(name)
items = ",".join(self.strings.append(v) for v in enum.values)
self.statements.append(
' %(schema_name)s_types[%(index_in_schema)d] = new enumeration_type(%(ref)s, %(index_in_schema)d, {%(items)s});'
" %(schema_name)s_types[%(index_in_schema)d] = new enumeration_type(%(ref)s, %(index_in_schema)d, {%(items)s});"
% locals()
)
@@ -218,10 +219,14 @@ class EarlyBoundCodeWriter:
schema_name = self.schema_name.upper()
index_in_schema = self.names.index(name)
ref = self.strings.append(name)
supertype = "0" if len(type.supertypes) == 0 else "%s_types[%d]" % (self.schema_name, self.names.index(type.supertypes[0]))
supertype = (
"0"
if len(type.supertypes) == 0
else "%s_types[%d]" % (self.schema_name, self.names.index(type.supertypes[0]))
)
is_abstract = "true" if type.abstract else "false"
self.statements.append(
' %(schema_name)s_types[%(index_in_schema)d] = new entity(%(ref)s, %(is_abstract)s, %(index_in_schema)d, (entity*) %(supertype)s);'
" %(schema_name)s_types[%(index_in_schema)d] = new entity(%(ref)s, %(is_abstract)s, %(index_in_schema)d, (entity*) %(supertype)s);"
% locals()
)
@@ -233,73 +238,86 @@ class EarlyBoundCodeWriter:
map(lambda v: "%s_types[%d]" % (self.schema_name, self.names.index(v)), sorted(map(str, type.values)))
)
self.statements.append(
' %(schema_name)s_types[%(index_in_schema)d] = new select_type(%(ref)s, %(index_in_schema)d, {%(items)s});'
" %(schema_name)s_types[%(index_in_schema)d] = new select_type(%(ref)s, %(index_in_schema)d, {%(items)s});"
% locals()
)
def entity_attributes(self, name, attribute_definitions, is_derived):
schema_name = self.schema_name.upper()
index_in_schema = self.names.index(name)
def _():
index_in_schema = self.names.index(name)
schema_name = self.schema_name
for attr_name, decl_type, optional in attribute_definitions:
attr_name_ref = self.strings.append(attr_name)
optional_cpp = str(optional).lower()
yield 'new attribute(%(attr_name_ref)s, %(decl_type)s, %(optional_cpp)s)' % locals()
yield "new attribute(%(attr_name_ref)s, %(decl_type)s, %(optional_cpp)s)" % locals()
attributes = ",".join(_())
derived = ",".join(map(lambda b: str(b).lower(), is_derived))
self.statements.append(" ((entity*)%(schema_name)s_types[%(index_in_schema)d])->set_attributes({%(attributes)s}, {%(derived)s});" % locals())
self.statements.append(
" ((entity*)%(schema_name)s_types[%(index_in_schema)d])->set_attributes({%(attributes)s}, {%(derived)s});"
% locals()
)
def inverse_attributes(self, name, inv_attrs):
schema_name = self.schema_name.upper()
index_in_schema = self.names.index(name)
def _():
schema_name = self.schema_name
index_in_schema = self.names.index(name)
for attr_name, aggr_type, bound1, bound2, entity_ref, attribute_entity, attribute_entity_index in inv_attrs:
attr_name_ref = self.strings.append(attr_name)
opposite_index_in_schema = self.names.index(entity_ref)
opposite1 = '%(schema_name)s_types[%(opposite_index_in_schema)d]' % locals()
opposite1 = "%(schema_name)s_types[%(opposite_index_in_schema)d]" % locals()
opposite_index_in_schema = self.names.index(attribute_entity)
opposite2 = '%(schema_name)s_types[%(opposite_index_in_schema)d]' % locals()
yield 'new inverse_attribute(%(attr_name_ref)s, inverse_attribute::%(aggr_type)s_type, %(bound1)d, %(bound2)d, ((entity*) %(opposite1)s), ((entity*) %(opposite2)s)->attributes()[%(attribute_entity_index)d])' % locals()
opposite2 = "%(schema_name)s_types[%(opposite_index_in_schema)d]" % locals()
yield "new inverse_attribute(%(attr_name_ref)s, inverse_attribute::%(aggr_type)s_type, %(bound1)d, %(bound2)d, ((entity*) %(opposite1)s), ((entity*) %(opposite2)s)->attributes()[%(attribute_entity_index)d])" % locals()
attributes = ",".join(_())
self.statements.append(" ((entity*) %(schema_name)s_types[%(index_in_schema)d])->set_inverse_attributes({%(attributes)s});" % locals())
self.statements.append(
" ((entity*) %(schema_name)s_types[%(index_in_schema)d])->set_inverse_attributes({%(attributes)s});"
% locals()
)
def entity_subtypes(self, name, tys):
schema_name = self.schema_name.upper()
index_in_schema = self.names.index(name)
subtypes = ",".join(map(lambda t: ("((entity*) %%(schema_name)s_types[%d])" % self.names.index(t)), tys)) % locals()
self.statements.append(" ((entity*) %(schema_name)s_types[%(index_in_schema)d])->set_subtypes({%(subtypes)s});" % locals())
subtypes = (
",".join(map(lambda t: ("((entity*) %%(schema_name)s_types[%d])" % self.names.index(t)), tys)) % locals()
)
self.statements.append(
" ((entity*) %(schema_name)s_types[%(index_in_schema)d])->set_subtypes({%(subtypes)s});" % locals()
)
def finalize(self, can_be_instantiated_set):
schema_name = self.schema_name.upper()
schema_name_title = self.schema_name.capitalize()
def _():
schema_name = self.schema_name.upper()
schema_name_title = self.schema_name.capitalize()
for type_name in self.names:
index_in_schema = self.names.index(type_name)
yield "%(schema_name)s_types[%(index_in_schema)d]" % locals()
declarations = ",".join(_())
schema_name_ref = self.strings.append(schema_name)
self.statements.append(
' return new schema_definition(%(schema_name_ref)s, {%(declarations)s});'
% locals()
)
self.statements.append("}");
self.statements.append(" return new schema_definition(%(schema_name_ref)s, {%(declarations)s});" % locals())
self.statements.append("}")
# self.statements.append(
# """
# #if defined(__clang__)
# #elif defined(__GNUC__) || defined(__GNUG__)
# #pragma GCC pop_options
# #elif defined(_MSC_VER)
# #pragma optimize("", on)
# #endif
# """
# )
# self.statements.append(
# """
# #if defined(__clang__)
# #elif defined(__GNUC__) || defined(__GNUG__)
# #pragma GCC pop_options
# #elif defined(_MSC_VER)
# #pragma optimize("", on)
# #endif
# """
# )
self.statements.extend(
(
@@ -353,12 +371,9 @@ class EarlyBoundCodeWriter:
# )
""
self.statements[self.statements.index("{string_pool_placeholder}")] = (
"""
self.statements[self.statements.index("{string_pool_placeholder}")] = """
const std::string strings[] = {%s};
"""
% ",".join(map(lambda s: '"%s"s' % s, self.strings))
)
""" % ",".join(map(lambda s: '"%s"s' % s, self.strings))
def __str__(self):
return "\n".join(self.statements)
@@ -380,16 +395,19 @@ class SchemaClass(codegen.Base):
def wrapper(*args, **kwargs):
schema_name_upper = mapping.schema.name.upper()
declared_type = fn(*args, **kwargs)
if 'simple_type' in declared_type:
if "simple_type" in declared_type:
pass
else:
match = re.search(r'\((\w+?_[\w+]+?_\w+?)\)', declared_type)
match = re.search(r"\((\w+?_[\w+]+?_\w+?)\)", declared_type)
if match:
old_decl = match.group(1)
name = old_decl.lower().replace(schema_name.lower() + '_', '').replace('_type', '')
name = old_decl.lower().replace(schema_name.lower() + "_", "").replace("_type", "")
idx = [n.lower() for n in x.names].index(name)
declared_type = declared_type.replace(old_decl, '%(schema_name_upper)s_types[%(idx)d]' % locals())
declared_type = declared_type.replace(
old_decl, "%(schema_name_upper)s_types[%(idx)d]" % locals()
)
return declared_type
return wrapper if code == EarlyBoundCodeWriter else fn
@transform_to_indexed
@@ -129,14 +129,16 @@ simpletype_impl_is_without_supertype = "return v == %(class_name)s_type;"
simpletype_impl_type = "return *((ifcopenshell::type_declaration*)%(schema_name_upper)s_types[%(index_in_schema)d]);"
simpletype_impl_class = "return *((ifcopenshell::type_declaration*)%(schema_name_upper)s_types[%(index_in_schema)d]);"
simpletype_impl_explicit_constructor = "data_ = e;"
simpletype_impl_constructor = (
"data_ = new const std::weak_ptr<instance_data>&(%(schema_name_upper)s_types[%(index_in_schema)d]); set_attribute_value(0, v);"
)
simpletype_impl_constructor = "data_ = new const std::weak_ptr<instance_data>&(%(schema_name_upper)s_types[%(index_in_schema)d]); set_attribute_value(0, v);"
simpletype_impl_constructor_templated = "data_ = new const std::weak_ptr<instance_data>&(%(schema_name_upper)s_types[%(index_in_schema)d]); set_attribute_value(0, cast_vector<express::Base>(v));"
simpletype_impl_cast = "return get_attribute_value(0);"
simpletype_impl_cast_templated = "std::vector<express::Base> es = get_attribute_value(0); return cast_vector<%(underlying_type)s>(es);"
simpletype_impl_cast_templated = (
"std::vector<express::Base> es = get_attribute_value(0); return cast_vector<%(underlying_type)s>(es);"
)
simpletype_impl_declaration = "return *((ifcopenshell::type_declaration*)%(schema_name_upper)s_types[%(index_in_schema)d]);"
simpletype_impl_declaration = (
"return *((ifcopenshell::type_declaration*)%(schema_name_upper)s_types[%(index_in_schema)d]);"
)
select = """%(documentation)s
class IFC_SCHEMA_API %(name)s : public express::Select {
@@ -226,7 +228,7 @@ const ifcopenshell::entity& %(schema_name)s::%(name)s::Class() { return *((ifcop
%(schema_name)s::%(name)s %(schema_name)s::%(name)s::initialize(%(constructor_arguments)s) { %(constructor_implementation)s; return *this; }
"""
# data_ = e;
# data_ = e;
# data_ = new const std::weak_ptr<instance_data>&(%(schema_name_upper)s_types[%(index_in_schema)d]);
optional_attribute_description = "/// Whether the optional attribute %s is defined for this %s"
@@ -234,9 +236,7 @@ optional_attribute_description = "/// Whether the optional attribute %s is defin
function = "%(return_type)s %(schema_name)s::%(class_name)s::%(name)s(%(arguments)s) { %(body)s }"
const_function = "%(return_type)s %(schema_name)s::%(class_name)s::%(name)s(%(arguments)s) const { %(body)s }"
constructor = "%(schema_name)s::%(class_name)s::%(class_name)s(%(arguments)s) { %(body)s }"
initialize_single_initlist = (
"%(schema_name)s::%(class_name)s %(schema_name)s::%(class_name)s::initialize(%(arguments)s) { %(body)s; return *this; }"
)
initialize_single_initlist = "%(schema_name)s::%(class_name)s %(schema_name)s::%(class_name)s::initialize(%(arguments)s) { %(body)s; return *this; }"
cast_function = "%(schema_name)s::%(class_name)s::operator %(return_type)s() const { %(body)s }"
array_type = "std::vector< %(instance_type)s > /*[%(lower)s:%(upper)s]*/"
@@ -258,41 +258,25 @@ optional_attr_stmt = "return !get_attribute_value(%(index)d).isNull();"
get_attr_stmt = "%(null_check)s %(non_optional_type)s v = get_attribute_value(%(index)d); return v;"
get_attr_stmt_enum = "%(null_check)s return %(non_optional_type)s::FromString(get_attribute_value(%(index)d));"
get_attr_stmt_entity = "%(null_check)s return ((express::Base)(get_attribute_value(%(index)d))).as<%(non_optional_type_no_pointer)s>();"
get_attr_stmt_entity = (
"%(null_check)s return ((express::Base)(get_attribute_value(%(index)d))).as<%(non_optional_type_no_pointer)s>();"
)
get_attr_stmt_array = "%(null_check)s std::vector<express::Base> es = get_attribute_value(%(index)d); return cast_vector<%(list_instance_type)s>(es);"
get_attr_stmt_nested_array = "%(null_check)s std::vector<std::vector<express::Base>> es = get_attribute_value(%(index)d); return cast_vector<%(list_instance_type)s>(es);"
get_inverse = "return cast_vector<%(type)s>(file()->get_inverse(data()->id(), %(schema_name_upper)s_types[%(type_index)d], %(index)d));"
set_attr_stmt = (
"%(check_optional_set_begin)sset_attribute_value(%(index)d, %(star_if_optional)sv);%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
)
set_attr_instance = (
"%(check_optional_set_begin)sset_attribute_value(%(index)d, v);%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
)
set_attr_stmt_enum = "%(check_optional_set_begin)sset_attribute_value(%(index)d, enumeration_reference(&%(non_optional_type)s::Class(), (size_t) %(star_if_optional)sv));%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
set_attr_stmt_array = (
"%(check_optional_set_begin)sset_attribute_value(%(index)d, cast_vector<express::Base>(%(star_if_optional)sv));%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
)
set_attr_stmt_nested_array = (
"%(check_optional_set_begin)sset_attribute_value(%(index)d, cast_vector<express::Base>(%(star_if_optional)sv));%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
)
set_attr_stmt = "%(check_optional_set_begin)sset_attribute_value(%(index)d, %(star_if_optional)sv);%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
set_attr_instance = "%(check_optional_set_begin)sset_attribute_value(%(index)d, v);%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
set_attr_stmt_enum = "%(check_optional_set_begin)sset_attribute_value(%(index)d, enumeration_reference(&%(non_optional_type)s::Class(), (size_t) %(star_if_optional)sv));%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
set_attr_stmt_array = "%(check_optional_set_begin)sset_attribute_value(%(index)d, cast_vector<express::Base>(%(star_if_optional)sv));%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
set_attr_stmt_nested_array = "%(check_optional_set_begin)sset_attribute_value(%(index)d, cast_vector<express::Base>(%(star_if_optional)sv));%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
constructor_stmt = (
"set_attribute_value(%(index)d, (%(name)s));"
)
constructor_stmt_enum = (
"set_attribute_value(%(index)d, (enumeration_reference(&%(type)s::Class(),(size_t)%(name)s)));"
)
constructor_stmt_array = (
"set_attribute_value(%(index)d, cast_vector<express::Base>(%(name)s));"
)
constructor_stmt_derived = (
""
)
constructor_stmt_instance = (
"set_attribute_value(%(index)d, %(name)s);"
)
constructor_stmt = "set_attribute_value(%(index)d, (%(name)s));"
constructor_stmt_enum = "set_attribute_value(%(index)d, (enumeration_reference(&%(type)s::Class(),(size_t)%(name)s)));"
constructor_stmt_array = "set_attribute_value(%(index)d, cast_vector<express::Base>(%(name)s));"
constructor_stmt_derived = ""
constructor_stmt_instance = "set_attribute_value(%(index)d, %(name)s);"
constructor_stmt_optional = " if (%(name)s) {%(stmt)s }"
@@ -301,5 +285,3 @@ inverse_implementation = ' inverse_map[Type::%(type)s].insert(std::make_pair(
def multi_line_comment(li):
return ("/// %s" % ("\n/// ".join(li))) if len(li) else ""
@@ -145,8 +145,7 @@ class configuration:
config.set(
"snippets",
"print all wall ids",
self.config_encode(
"""
self.config_encode("""
###########################################################################
# A simple script that iterates over all walls in the current model #
# and prints their Globally unique IDs (GUIDS) to the console window #
@@ -154,15 +153,13 @@ class configuration:
for wall in model.by_type("IfcWall"):
print ("wall with global id: "+str(wall.GlobalId))
""".lstrip()
),
""".lstrip()),
)
config.set(
"snippets",
"print properties of current selection",
self.config_encode(
"""
self.config_encode("""
###########################################################################
# A simple script that iterates over all IfcPropertySets of the currently #
# selected object and prints them to the console #
@@ -180,8 +177,7 @@ if selection:
for prop in relDefinesByProperties.RelatingPropertyDefinition.HasProperties:
print ("{:<20} :{}".format(prop.Name,prop.NominalValue.wrappedValue))
print ("\\n")
""".lstrip()
),
""".lstrip()),
)
with open(conf_file, "w") as configfile:
config.write(configfile)
@@ -547,9 +547,20 @@ def create_shape(
return wrap_shape_creation(
settings,
(
ifcopenshell_wrapper.create_shape(settings, inst, repr, geometry_library, *ifcopenshell.optional_logger_args(logger),)
ifcopenshell_wrapper.create_shape(
settings,
inst,
repr,
geometry_library,
*ifcopenshell.optional_logger_args(logger),
)
if repr
else ifcopenshell_wrapper.create_shape(settings, inst, geometry_library, *ifcopenshell.optional_logger_args(logger),)
else ifcopenshell_wrapper.create_shape(
settings,
inst,
geometry_library,
*ifcopenshell.optional_logger_args(logger),
)
),
)
@@ -330,7 +330,6 @@ class Iterator:
def unit_magnitude(self): ...
def unit_name(self): ...
class OpaqueCoordinate_3:
def __init__(self, *args): ...
def get(self, i): ...
@@ -755,13 +754,10 @@ class entity_instance(entity_instance_mixin):
def declaration(self) -> declaration: ...
@property
def file(self) -> file: ...
def get_argument(self, *args: int | str) -> Any: ...
def get_argument_index(self, a: str) -> int: ...
def attribute_name(self, i: int) -> str: ...
def attribute_type(
self, *args: int | str
) -> Literal[
def attribute_type(self, *args: int | str) -> Literal[
"NULL",
"DERIVED",
"INT",
@@ -915,7 +911,6 @@ class file(file_mixin):
def good(self): ...
@property
def header(self) -> spf_header: ...
def ifcroot_type(self) -> entity: ...
def initialize(self, *args): ...
def key_value_store_iter(self, prefix): ...
@@ -1619,9 +1614,15 @@ def set_plugin_search_paths(paths: Sequence[str]) -> None: ...
def clear_plugin_search_paths() -> None: ...
def clear_schemas(): ...
def construct_iterator(geometry_library, settings, file, num_threads, logger=None): ...
def construct_iterator_with_include_exclude(geometry_library, settings, file, elems, include, num_threads, logger=None): ...
def construct_iterator_with_include_exclude_globalid(geometry_library, settings, file, elems, include, num_threads, logger=None): ...
def construct_iterator_with_include_exclude_id(geometry_library, settings, file, elems, include, num_threads, logger=None): ...
def construct_iterator_with_include_exclude(
geometry_library, settings, file, elems, include, num_threads, logger=None
): ...
def construct_iterator_with_include_exclude_globalid(
geometry_library, settings, file, elems, include, num_threads, logger=None
): ...
def construct_iterator_with_include_exclude_id(
geometry_library, settings, file, elems, include, num_threads, logger=None
): ...
def convert_loop_to_function_item(loop): ...
def create_box(*args): ...
def create_epeck(*args): ...
+1 -1
View File
@@ -83,7 +83,7 @@ class sqlite(file):
if not Path(filepath).exists():
raise FileNotFoundError(f"File doesn't exist: {filepath}")
# See ifcopenshell.file.file_mixin.post_init()
# history, future and transaction are stored in a list so that they
# can easily be shared among file instances that are the same C++
@@ -355,8 +355,7 @@ def get_cost_rate(
class CostValueUnserialiser:
def parse(self, formula: str):
l = lark.Lark(
"""start: formula
l = lark.Lark("""start: formula
formula: operand (operator operand)*
operand: value | category "(" formula ")"
value: NUMBER?
@@ -393,8 +392,7 @@ class CostValueUnserialiser:
NEWLINE: (CR? LF)+
%ignore WS // Disregard spaces in text
"""
)
""")
start = l.parse(formula)
return self.get_formula(start.children[0])
@@ -40,8 +40,7 @@ import ifcopenshell.util.shape_builder
import ifcopenshell.util.system
import ifcopenshell.util.unit
filter_elements_grammar = lark.Lark(
"""start: filter_group
filter_elements_grammar = lark.Lark("""start: filter_group
filter_group: facet_list ("+" facet_list)* "+"?
facet_list: facet ("," facet)*
@@ -114,11 +113,9 @@ filter_elements_grammar = lark.Lark(
%ignore WS // Disregard spaces in text
%ignore COMMENT // Allow /* ... */ block comments to toggle parts of a query
"""
)
""")
get_element_grammar = lark.Lark(
"""start: keys
get_element_grammar = lark.Lark("""start: keys
keys: key ("." key)*
key: quoted_string | regex_string | unquoted_string
@@ -133,11 +130,9 @@ get_element_grammar = lark.Lark(
WS: /[ \\t\\f\\r\\n]/+
%ignore WS // Disregard spaces in text
"""
)
""")
format_grammar = lark.Lark(
"""start: expression
format_grammar = lark.Lark("""start: expression
?expression: add_sub
?add_sub: mul_div
@@ -196,8 +191,7 @@ format_grammar = lark.Lark(
NEWLINE: (CR? LF)+
%ignore WS // Disregard spaces in text
"""
)
""")
class FormatTransformer(lark.Transformer):
@@ -24,7 +24,6 @@ import ifcopenshell.api.context
import ifcopenshell.api.unit
from ifcopenshell.api.alignment._add_segment_to_layout import _add_segment_to_layout
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
@@ -24,7 +24,6 @@ import ifcopenshell.api.context
import ifcopenshell.api.unit
import ifcopenshell.util.element
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
@@ -23,7 +23,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
@@ -23,7 +23,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3_ADD2")
IFC4X3_AVAILABLE = True
@@ -25,7 +25,6 @@ import ifcopenshell.api.unit
import ifcopenshell.util
import ifcopenshell.util.unit
try:
ifcopenshell.file(schema="IFC4X3_ADD2")
IFC4X3_AVAILABLE = True
@@ -22,7 +22,6 @@ import pytest
import ifcopenshell.api.alignment
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3_ADD2")
IFC4X3_AVAILABLE = True
@@ -23,7 +23,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
@@ -24,7 +24,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3_ADD2")
IFC4X3_AVAILABLE = True
@@ -22,7 +22,6 @@ import pytest
import ifcopenshell.api.alignment
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3_ADD2")
IFC4X3_AVAILABLE = True
@@ -22,7 +22,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
@@ -23,7 +23,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3_ADD2")
IFC4X3_AVAILABLE = True
@@ -23,7 +23,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
@@ -22,7 +22,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
@@ -22,7 +22,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
@@ -22,7 +22,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
@@ -23,7 +23,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
@@ -29,6 +29,7 @@ try:
except RuntimeError:
IFC4X3_AVAILABLE = False
def _BlossCurve_100_0_300_1000_1_Meter(file):
design_parameters = file.createIfcAlignmentCantSegment(
StartDistAlong=0.0,
@@ -33,6 +33,7 @@ try:
except RuntimeError:
IFC4X3_AVAILABLE = False
def _BlossCurve_100_0_300_1000_1_Meter(file):
design_parameters = file.createIfcAlignmentHorizontalSegment(
StartPoint=file.createIfcCartesianPoint((0.0, 0.0)),
@@ -32,6 +32,7 @@ try:
except RuntimeError:
IFC4X3_AVAILABLE = False
def _CircularArc_100_0_10_0_0_0_0_5_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
@@ -23,7 +23,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
@@ -22,7 +22,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
@@ -31,6 +31,7 @@ try:
except RuntimeError:
IFC4X3_AVAILABLE = False
def _test1():
file = ifcopenshell.file(schema="IFC4X3")
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(), Name="Test")
@@ -22,7 +22,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
@@ -23,7 +23,6 @@ import ifcopenshell.api.alignment
import ifcopenshell.api.context
import ifcopenshell.api.unit
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
@@ -22,7 +22,6 @@ import ifcopenshell.api.aggregate
import ifcopenshell.api.cogo
import ifcopenshell.api.context
try:
ifcopenshell.file(schema="IFC4X3_ADD2")
IFC4X3_AVAILABLE = True
@@ -22,7 +22,6 @@ import ifcopenshell.api.aggregate
import ifcopenshell.api.cogo
import ifcopenshell.api.context
try:
ifcopenshell.file(schema="IFC4X3_ADD2")
IFC4X3_AVAILABLE = True
@@ -22,7 +22,6 @@ import ifcopenshell.api.aggregate
import ifcopenshell.api.cogo
import ifcopenshell.api.context
try:
ifcopenshell.file(schema="IFC4X3_ADD2")
IFC4X3_AVAILABLE = True
@@ -20,6 +20,7 @@ import ifcopenshell
import pytest
import test.bootstrap
class TestGetInfo2(test.bootstrap.IFC4):
def test_instance_attribute(self):
brep = self.file.create_entity("IfcFacetedBrep")
@@ -65,25 +66,27 @@ class TestGetInfo2(test.bootstrap.IFC4):
"type": "IfcFacetedBrep",
}
def test_equality():
f = ifcopenshell.file()
g = ifcopenshell.file()
f.createIfcCartesianPoint((0., 0.))
g.createIfcCartesianPoint((0., 0.))
f.createIfcCartesianPoint((0.0, 0.0))
g.createIfcCartesianPoint((0.0, 0.0))
assert f[1] == g[1]
g[1].Coordinates = (1., 0.)
g[1].Coordinates = (1.0, 0.0)
assert f[1] != g[1]
def test_setting_logical():
f = ifcopenshell.file()
inst = f.createIfcPresentationLayerWithStyle(LayerOn="UNKNOWN")
assert inst.LayerOn == "UNKNOWN"
assert '.U.' in str(inst)
assert ".U." in str(inst)
with pytest.raises(Exception):
inst.LayerOn = "SOME_OTHER_STRING"
inst.LayerOn = False
assert inst.LayerOn is False
assert '.F.' in str(inst)
assert ".F." in str(inst)
inst.LayerOn = True
assert inst.LayerOn is True
assert '.T.' in str(inst)
assert ".T." in str(inst)
+6 -5
View File
@@ -21,13 +21,13 @@ import pytest
import ifcopenshell
import test.bootstrap
try:
ifcopenshell.file(schema="IFC4X3")
IFC4X3_AVAILABLE = True
except RuntimeError:
IFC4X3_AVAILABLE = False
class TestTransaction(test.bootstrap.IFC4):
def test_that_nothing_happens_without_a_transaction(self):
wall = self.file.createIfcWall()
@@ -296,9 +296,10 @@ class TestFile(test.bootstrap.IFC4):
g.assign_header_from(f)
assert g.header.file_name.name == "test"
@pytest.mark.skipif(not IFC4X3_AVAILABLE, reason="IFC4X3 not available")
def test_schema_identifier():
f = ifcopenshell.file(schema='IFC4X3')
assert f.schema_identifier == 'IFC4X3_ADD2'
assert f.schema == 'IFC4X3'
assert f.schema_version == (4,3,2,0)
f = ifcopenshell.file(schema="IFC4X3")
assert f.schema_identifier == "IFC4X3_ADD2"
assert f.schema == "IFC4X3"
assert f.schema_version == (4, 3, 2, 0)
@@ -1,5 +1,6 @@
import ifcopenshell
def test_skip_over_non_entity_instance():
data = """
ISO-10303-21;
+2 -1
View File
@@ -8,6 +8,7 @@ import tabulate
import ifcopenshell.express.rule_executor
import ifcopenshell.validate
@pytest.mark.parametrize(
"filename",
[
@@ -45,4 +46,4 @@ def test_file(filename):
if __name__ == "__main__":
pytest.main(["-sx", __file__, '--import-mode=importlib'])
pytest.main(["-sx", __file__, "--import-mode=importlib"])
@@ -9,19 +9,20 @@ import ifcopenshell.util.shape
from pathlib import Path
repo_root = Path(__file__).resolve().parent.parent.parent.parent
test_files = repo_root / 'test' / 'input' / 'tests'
test_files = repo_root / "test" / "input" / "tests"
settings = ifcopenshell.geom.settings()
testdata = list(csv.reader((test_files / 'data.csv').open(newline='')))[1:]
testdata = list(csv.reader((test_files / "data.csv").open(newline="")))[1:]
print(testdata)
@pytest.mark.parametrize("fn,area,volume", testdata)
def test_conversion(fn, area, volume):
f = ifcopenshell.open(test_files / fn)
elem = next(inst for inst in f.by_type('IfcElement') if not inst.is_a('IfcOpeningElement'))
for kernel in ('manifold', 'opencascade', 'cgal'):
elem = next(inst for inst in f.by_type("IfcElement") if not inst.is_a("IfcOpeningElement"))
for kernel in ("manifold", "opencascade", "cgal"):
shp = ifcopenshell.geom.create_shape(settings, elem, geometry_library=kernel)
if area:
assert pytest.approx(float(area), rel=0.05) == ifcopenshell.util.shape.get_area(shp.geometry)
@@ -22,7 +22,6 @@ import ifcopenshell
import ifcopenshell.api.unit
import ifcopenshell.util.alignment as sta
try:
ifcopenshell.file(schema="IFC4X3_ADD2")
IFC4X3_AVAILABLE = True
@@ -111,7 +111,7 @@ class Patcher(ifcpatch.BasePatcher):
if element.is_a("IfcProject"):
proj = self.new.add(element)
for ctx in element.RepresentationContexts or ():
for coop in getattr(ctx, 'HasCoordinateOperation', ()):
for coop in getattr(ctx, "HasCoordinateOperation", ()):
self.new.add(coop)
return proj
return ifcopenshell.api.project.append_asset(
@@ -33,9 +33,7 @@ class TestDowngradeIndexedPolyCurve(test.bootstrap.IFC4):
Points=point_list,
Segments=segments,
)
self.file.create_entity(
"IfcArbitraryClosedProfileDef", ProfileType="AREA", OuterCurve=curve
)
self.file.create_entity("IfcArbitraryClosedProfileDef", ProfileType="AREA", OuterCurve=curve)
return curve
def test_run_without_segments(self):
@@ -80,9 +78,7 @@ class TestDowngradeIndexedPolyCurve(test.bootstrap.IFC4):
Points=point_list,
Segments=[self.file.createIfcLineIndex((1, 2, 3, 4, 1))],
)
self.file.create_entity(
"IfcArbitraryClosedProfileDef", ProfileType="AREA", OuterCurve=curve
)
self.file.create_entity("IfcArbitraryClosedProfileDef", ProfileType="AREA", OuterCurve=curve)
ifcpatch.execute(
{"input": "input.ifc", "file": self.file, "recipe": "DowngradeIndexedPolyCurve", "arguments": []}
)
@@ -110,9 +106,7 @@ class TestDowngradeIndexedPolyCurve(test.bootstrap.IFC4):
self.file.createIfcLineIndex((3, 4)),
],
)
self.file.create_entity(
"IfcArbitraryClosedProfileDef", ProfileType="AREA", OuterCurve=curve
)
self.file.create_entity("IfcArbitraryClosedProfileDef", ProfileType="AREA", OuterCurve=curve)
ifcpatch.execute(
{"input": "input.ifc", "file": self.file, "recipe": "DowngradeIndexedPolyCurve", "arguments": []}
)
+1 -3
View File
@@ -701,9 +701,7 @@ class Property(Facet):
if isinstance(self.baseName, str):
prop = pset_props.get(self.baseName)
if prop == "UNKNOWN" and next(
p
for p in self.get_properties(inst.file.by_id(pset_props["id"]))
if p.Name == self.baseName
p for p in self.get_properties(inst.file.by_id(pset_props["id"])) if p.Name == self.baseName
).NominalValue.is_a("IfcLogical"):
pass
elif prop is not None and prop != "":
+29 -20
View File
@@ -39,9 +39,9 @@ BAKE = HERE / "../../build-viewer/ifcviewer/sidecar_bake"
# (class, name, footprint w x d in m, height in m, placement x/y/z in m)
ELEMENTS = [
("IfcSlab", "Slab", (6.0, 6.0), 0.2, (-3.0, -3.0, 0.0)),
("IfcWall", "Wall", (5.0, 0.3), 3.0, (-2.5, -2.5, 0.2)),
("IfcBeam", "Beam", (0.3, 5.0), 0.3, (2.0, -2.5, 3.2)),
("IfcSlab", "Slab", (6.0, 6.0), 0.2, (-3.0, -3.0, 0.0)),
("IfcWall", "Wall", (5.0, 0.3), 3.0, (-2.5, -2.5, 0.2)),
("IfcBeam", "Beam", (0.3, 5.0), 0.3, (2.0, -2.5, 3.2)),
]
@@ -51,8 +51,8 @@ def build_ifc(path: Path) -> None:
ifcopenshell.api.unit.assign_unit(f, length={"is_metric": True, "raw": "METERS"})
body = ifcopenshell.api.context.add_context(f, context_type="Model")
body = ifcopenshell.api.context.add_context(
f, context_type="Model", context_identifier="Body",
target_view="MODEL_VIEW", parent=body)
f, context_type="Model", context_identifier="Body", target_view="MODEL_VIEW", parent=body
)
site = ifcopenshell.api.root.create_entity(f, ifc_class="IfcSite", name="Site")
storey = ifcopenshell.api.root.create_entity(f, ifc_class="IfcBuildingStorey", name="Ground floor")
@@ -61,30 +61,39 @@ def build_ifc(path: Path) -> None:
for ifc_class, name, (w, d), height, (x, y, z) in ELEMENTS:
element = ifcopenshell.api.root.create_entity(f, ifc_class=ifc_class, name=name)
ifcopenshell.api.spatial.assign_container(
f, products=[element], relating_structure=storey)
ifcopenshell.api.spatial.assign_container(f, products=[element], relating_structure=storey)
# A rectangular profile extruded up — enough to be a recognisable,
# distinctly-placed solid without dragging in a whole modelling stack.
profile = f.create_entity(
"IfcRectangleProfileDef", ProfileType="AREA", XDim=w, YDim=d,
"IfcRectangleProfileDef",
ProfileType="AREA",
XDim=w,
YDim=d,
Position=f.create_entity(
"IfcAxis2Placement2D",
Location=f.create_entity("IfcCartesianPoint", Coordinates=(w / 2, d / 2))))
"IfcAxis2Placement2D", Location=f.create_entity("IfcCartesianPoint", Coordinates=(w / 2, d / 2))
),
)
solid = f.create_entity(
"IfcExtrudedAreaSolid", SweptArea=profile, Depth=height,
"IfcExtrudedAreaSolid",
SweptArea=profile,
Depth=height,
Position=f.create_entity(
"IfcAxis2Placement3D",
Location=f.create_entity("IfcCartesianPoint", Coordinates=(0.0, 0.0, 0.0))),
ExtrudedDirection=f.create_entity("IfcDirection", DirectionRatios=(0.0, 0.0, 1.0)))
"IfcAxis2Placement3D", Location=f.create_entity("IfcCartesianPoint", Coordinates=(0.0, 0.0, 0.0))
),
ExtrudedDirection=f.create_entity("IfcDirection", DirectionRatios=(0.0, 0.0, 1.0)),
)
representation = f.create_entity(
"IfcShapeRepresentation", ContextOfItems=body, RepresentationIdentifier="Body",
RepresentationType="SweptSolid", Items=[solid])
ifcopenshell.api.geometry.assign_representation(
f, product=element, representation=representation)
"IfcShapeRepresentation",
ContextOfItems=body,
RepresentationIdentifier="Body",
RepresentationType="SweptSolid",
Items=[solid],
)
ifcopenshell.api.geometry.assign_representation(f, product=element, representation=representation)
ifcopenshell.api.geometry.edit_object_placement(
f, product=element,
matrix=ifcopenshell.util.placement.a2p((x, y, z), (0.0, 0.0, 1.0), (1.0, 0.0, 0.0)))
f, product=element, matrix=ifcopenshell.util.placement.a2p((x, y, z), (0.0, 0.0, 1.0), (1.0, 0.0, 0.0))
)
f.write(str(path))
+20 -6
View File
@@ -168,7 +168,9 @@ def _is_in_allowed_headers(cursor, allowed_headers: set[Path]) -> bool:
def _is_in_allowed_namespace(cpp_name: str, config: WrapperConfig) -> bool:
if not config.allowed_namespaces:
return True
return any(cpp_name == namespace or cpp_name.startswith(f"{namespace}::") for namespace in config.allowed_namespaces)
return any(
cpp_name == namespace or cpp_name.startswith(f"{namespace}::") for namespace in config.allowed_namespaces
)
def _matches_ignore(cpp_name: str, ignored: list[str]) -> bool:
@@ -328,7 +330,7 @@ def _python_default_value(
if adapter == "integer":
return cpp_value if cpp_value.lstrip("-").isdigit() else None
if adapter == "string":
return cpp_value if cpp_value.startswith(("\"", "'")) else None
return cpp_value if cpp_value.startswith(('"', "'")) else None
if is_enum_adapter(adapter):
enum_name = enum_py_names.get(adapter.split(":", 1)[1])
if enum_name is None:
@@ -393,9 +395,17 @@ def _finalize_overload_names(callables: list[CallableModel]) -> None:
for index, callable_model in enumerate(group, start=1):
parameter_suffix = "_".join(parameter.name for parameter in callable_model.parameters)
if callable_model.kind == "constructor":
callable_model.py_name = f"{callable_model.py_name}_{parameter_suffix}" if parameter_suffix else f"{callable_model.py_name}_overload_{index}"
callable_model.py_name = (
f"{callable_model.py_name}_{parameter_suffix}"
if parameter_suffix
else f"{callable_model.py_name}_overload_{index}"
)
else:
callable_model.py_name = f"{callable_model.py_name}_with_{parameter_suffix}" if parameter_suffix else f"{callable_model.py_name}_overload_{index}"
callable_model.py_name = (
f"{callable_model.py_name}_with_{parameter_suffix}"
if parameter_suffix
else f"{callable_model.py_name}_overload_{index}"
)
callable_model.c_name = normalize_identifier(callable_model.py_name)
@@ -473,7 +483,9 @@ def _discover_methods(
qualified_name = f"{owner.cpp_name}::{child.spelling}"
if _matches_ignore(qualified_name, config.ignore.methods):
continue
return_adapter = _resolve_return_adapter(child.result_type.spelling, scalar_adapters, enum_cursors, class_models_by_cpp)
return_adapter = _resolve_return_adapter(
child.result_type.spelling, scalar_adapters, enum_cursors, class_models_by_cpp
)
if return_adapter is None:
continue
parameters = _build_parameter_models(child, config, scalar_adapters, enum_cursors)
@@ -535,7 +547,9 @@ def build_module_model(config: WrapperConfig) -> ModuleModel:
for normalized_cpp_name, cursor in class_cursors.items():
owner = class_models_by_cpp[normalized_cpp_name]
owner.callables.extend(_discover_constructors(cursor, owner, config, scalar_adapters, enum_cursors))
owner.callables.extend(_discover_methods(cursor, owner, config, scalar_adapters, enum_cursors, class_models_by_cpp))
owner.callables.extend(
_discover_methods(cursor, owner, config, scalar_adapters, enum_cursors, class_models_by_cpp)
)
owner.callables = _deduplicate_callables(owner.callables)
_finalize_overload_names(owner.callables)
+1 -5
View File
@@ -126,11 +126,7 @@ def resolve_cpp_type_key(cpp_type: str, candidates: set[str]) -> str | None:
if canonical in candidates:
return canonical
leaf = strip_pointer(canonical).rsplit("::", 1)[-1]
matches = [
candidate
for candidate in candidates
if strip_pointer(candidate).rsplit("::", 1)[-1] == leaf
]
matches = [candidate for candidate in candidates if strip_pointer(candidate).rsplit("::", 1)[-1] == leaf]
if len(matches) == 1:
return matches[0]
return None
+39 -17
View File
@@ -173,7 +173,7 @@ def _class_or_enum_cpp_name(adapter: str, model: ModuleModel) -> str:
def _cpp_argument(parameter: ParameterModel, model: ModuleModel) -> str:
if parameter.adapter == "string":
return f"std::string({parameter.name} ? {parameter.name} : \"\")"
return f'std::string({parameter.name} ? {parameter.name} : "")'
if is_enum_adapter(parameter.adapter):
return f"static_cast<{_class_or_enum_cpp_name(parameter.adapter, model)}>({parameter.name})"
if is_handle_adapter(parameter.adapter):
@@ -315,8 +315,7 @@ def emit_c_api_header(model: ModuleModel) -> str:
for variant in _all_variants(model):
return_type = _return_c_type(variant.callable.return_adapter, model)
parameters = ", ".join(
f"{_parameter_c_type(parameter, model)} {parameter.name}"
for parameter in variant.parameters
f"{_parameter_c_type(parameter, model)} {parameter.name}" for parameter in variant.parameters
)
if variant.callable.kind == "method":
self_type = f"{_class_c_type(variant.owner, model)}* handle"
@@ -327,11 +326,15 @@ def emit_c_api_header(model: ModuleModel) -> str:
for class_model in sequence_targets:
list_prefix = f"{model.c_prefix}_{_class_c_identifier(class_model, model)}_list"
lines.append(f"int {list_prefix}_size(const {_list_c_type(class_model, model)}* handle);")
lines.append(f"{_class_c_type(class_model, model)}* {list_prefix}_get(const {_list_c_type(class_model, model)}* handle, int index);")
lines.append(
f"{_class_c_type(class_model, model)}* {list_prefix}_get(const {_list_c_type(class_model, model)}* handle, int index);"
)
lines.append(f"void {list_prefix}_free({_list_c_type(class_model, model)}* handle);")
lines.append("")
for class_model in model.classes:
lines.append(f"void {model.c_prefix}_{_class_c_identifier(class_model, model)}_free({_class_c_type(class_model, model)}* handle);")
lines.append(
f"void {model.c_prefix}_{_class_c_identifier(class_model, model)}_free({_class_c_type(class_model, model)}* handle);"
)
lines.extend(
[
"",
@@ -419,8 +422,7 @@ def emit_c_api_implementation(model: ModuleModel) -> str:
for variant in _all_variants(model):
return_type = _return_c_type(variant.callable.return_adapter, model)
parameter_list = ", ".join(
f"{_parameter_c_type(parameter, model)} {parameter.name}"
for parameter in variant.parameters
f"{_parameter_c_type(parameter, model)} {parameter.name}" for parameter in variant.parameters
)
if variant.callable.kind == "method":
self_type = f"{_class_c_type(variant.owner, model)}* handle"
@@ -435,21 +437,31 @@ def emit_c_api_implementation(model: ModuleModel) -> str:
for parameter in variant.parameters:
if is_handle_adapter(parameter.adapter):
lines.append(f" if ({parameter.name} == nullptr) {{")
lines.append(f' throw std::runtime_error("Null handle parameter received for {parameter.name}");')
lines.append(
f' throw std::runtime_error("Null handle parameter received for {parameter.name}");'
)
lines.append(" }")
call_expression = _call_expression(variant, model)
if variant.callable.kind == "constructor":
lines.append(f" auto constructed_value = {call_expression};")
if variant.owner.handle_kind == "shared_ptr":
lines.append(f" return new {_class_c_type(variant.owner, model)}{{ std::move(constructed_value) }};")
lines.append(
f" return new {_class_c_type(variant.owner, model)}{{ std::move(constructed_value) }};"
)
elif variant.owner.owner_cpp_name is not None:
lines.append(f" return new {_class_c_type(variant.owner, model)}{{ {{}}, std::move(constructed_value) }};")
lines.append(
f" return new {_class_c_type(variant.owner, model)}{{ {{}}, std::move(constructed_value) }};"
)
else:
lines.append(f" return new {_class_c_type(variant.owner, model)}{{ std::move(constructed_value) }};")
lines.append(
f" return new {_class_c_type(variant.owner, model)}{{ std::move(constructed_value) }};"
)
elif variant.callable.return_adapter == "string":
lines.append(f" auto result = {call_expression};")
lines.append(" return duplicate_string(result);")
elif variant.callable.return_adapter in {"integer", "bool", "void"} or is_enum_adapter(variant.callable.return_adapter):
elif variant.callable.return_adapter in {"integer", "bool", "void"} or is_enum_adapter(
variant.callable.return_adapter
):
if variant.callable.return_adapter == "void":
lines.append(f" {call_expression};")
lines.append(" return;")
@@ -503,11 +515,15 @@ def emit_c_api_implementation(model: ModuleModel) -> str:
]
)
if class_model.handle_kind == "shared_ptr":
lines.append(f" auto item_value = std::make_shared<{class_model.cpp_name}>(handle->value.at(static_cast<size_t>(index)));")
lines.append(
f" auto item_value = std::make_shared<{class_model.cpp_name}>(handle->value.at(static_cast<size_t>(index)));"
)
lines.append(f" return new {_class_c_type(class_model, model)}{{ std::move(item_value) }};")
elif class_model.owner_cpp_name is not None:
lines.append(f" auto item_value = handle->value.at(static_cast<size_t>(index));")
lines.append(f" return new {_class_c_type(class_model, model)}{{ handle->owner, std::move(item_value) }};")
lines.append(
f" return new {_class_c_type(class_model, model)}{{ handle->owner, std::move(item_value) }};"
)
else:
lines.append(f" auto item_value = handle->value.at(static_cast<size_t>(index));")
lines.append(f" return new {_class_c_type(class_model, model)}{{ std::move(item_value) }};")
@@ -526,7 +542,9 @@ def emit_c_api_implementation(model: ModuleModel) -> str:
]
)
for class_model in model.classes:
lines.append(f"void {model.c_prefix}_{_class_c_identifier(class_model, model)}_free({_class_c_type(class_model, model)}* handle) {{")
lines.append(
f"void {model.c_prefix}_{_class_c_identifier(class_model, model)}_free({_class_c_type(class_model, model)}* handle) {{"
)
lines.append(" delete handle;")
lines.append("}")
lines.append("")
@@ -706,7 +724,9 @@ def emit_python_extension(model: ModuleModel) -> str:
lines.append(f" {list_prefix}_free(result);")
lines.append(" return values;")
else:
raise RuntimeError(f"Unsupported return adapter in Python extension emitter: {variant.callable.return_adapter}")
raise RuntimeError(
f"Unsupported return adapter in Python extension emitter: {variant.callable.return_adapter}"
)
lines.append("}")
lines.append("")
lines.extend(["static PyMethodDef MODULE_METHODS[] = {"])
@@ -847,7 +867,9 @@ def emit_python_facade(model: ModuleModel) -> str:
lines.append(" self._handle = handle")
lines.append("")
for callable_model in class_model.callables:
parameters = ", ".join(_python_parameter_signature(parameter, model) for parameter in callable_model.parameters)
parameters = ", ".join(
_python_parameter_signature(parameter, model) for parameter in callable_model.parameters
)
full_variant = _full_variant(class_model, callable_model)
call_arguments = ", ".join(_python_native_argument(parameter) for parameter in callable_model.parameters)
return_annotation = _python_type_for_return(callable_model.return_adapter, model)
+1 -5
View File
@@ -27,11 +27,7 @@ def _existing_directories(paths: list[Path]) -> list[str]:
def _discover_headers(src_ifcparse: Path) -> list[str]:
return [
str(path.resolve())
for path in sorted(src_ifcparse.glob("*.h"))
if path.parent.name != "schemas"
]
return [str(path.resolve()) for path in sorted(src_ifcparse.glob("*.h")) if path.parent.name != "schemas"]
def _discover_boost_include_dirs() -> list[Path]:
@@ -13,6 +13,7 @@ class FileType(IntEnum):
FT_UNKNOWN = _native.FT_UNKNOWN
FT_AUTODETECT = _native.FT_AUTODETECT
class exception:
__slots__ = ("_handle",)
@@ -23,6 +24,7 @@ class exception:
def with_message(message: str) -> exception:
return exception(_native.exception_new_with_message(message))
class attribute_out_of_range_exception:
__slots__ = ("_handle",)
@@ -33,6 +35,7 @@ class attribute_out_of_range_exception:
def with_message(message: str) -> attribute_out_of_range_exception:
return attribute_out_of_range_exception(_native.attribute_out_of_range_exception_new_with_message(message))
class invalid_token_exception:
__slots__ = ("_handle",)
@@ -40,8 +43,15 @@ class invalid_token_exception:
self._handle = handle
@staticmethod
def with_token_start_token_string_expected_type(token_start: int, token_string: str, expected_type: str) -> invalid_token_exception:
return invalid_token_exception(_native.invalid_token_exception_new_with_token_start_token_string_expected_type(token_start, token_string, expected_type))
def with_token_start_token_string_expected_type(
token_start: int, token_string: str, expected_type: str
) -> invalid_token_exception:
return invalid_token_exception(
_native.invalid_token_exception_new_with_token_start_token_string_expected_type(
token_start, token_string, expected_type
)
)
class parameter_type:
__slots__ = ("_handle",)
@@ -61,6 +71,7 @@ class parameter_type:
def is_(self, arg0: str) -> bool:
return _native.parameter_type_is(self._handle, arg0)
class named_type:
__slots__ = ("_handle",)
@@ -76,6 +87,7 @@ class named_type:
def is_(self, name: str) -> bool:
return _native.named_type_is(self._handle, name)
class simple_type:
__slots__ = ("_handle",)
@@ -85,6 +97,7 @@ class simple_type:
def as_simple_type(self) -> simple_type:
return simple_type(_native.simple_type_as_simple_type(self._handle))
class aggregation_type:
__slots__ = ("_handle",)
@@ -103,6 +116,7 @@ class aggregation_type:
def as_aggregation_type(self) -> aggregation_type:
return aggregation_type(_native.aggregation_type_as_aggregation_type(self._handle))
class declaration:
__slots__ = ("_handle",)
@@ -143,6 +157,7 @@ class declaration:
def schema(self) -> schema_definition:
return schema_definition(_native.declaration_schema(self._handle))
class type_declaration:
__slots__ = ("_handle",)
@@ -155,6 +170,7 @@ class type_declaration:
def as_type_declaration(self) -> type_declaration:
return type_declaration(_native.type_declaration_as_type_declaration(self._handle))
class select_type:
__slots__ = ("_handle",)
@@ -167,6 +183,7 @@ class select_type:
def as_select_type(self) -> select_type:
return select_type(_native.select_type_as_select_type(self._handle))
class enumeration_type:
__slots__ = ("_handle",)
@@ -179,6 +196,7 @@ class enumeration_type:
def as_enumeration_type(self) -> enumeration_type:
return enumeration_type(_native.enumeration_type_as_enumeration_type(self._handle))
class attribute:
__slots__ = ("_handle",)
@@ -194,6 +212,7 @@ class attribute:
def optional(self) -> bool:
return _native.attribute_optional(self._handle)
class inverse_attribute:
__slots__ = ("_handle",)
@@ -215,6 +234,7 @@ class inverse_attribute:
def attribute_reference(self) -> attribute:
return attribute(_native.inverse_attribute_attribute_reference(self._handle))
class entity:
__slots__ = ("_handle",)
@@ -248,6 +268,7 @@ class entity:
def as_entity(self) -> entity:
return entity(_native.entity_as_entity(self._handle))
class schema_definition:
__slots__ = ("_handle",)
@@ -258,7 +279,9 @@ class schema_definition:
return declaration(_native.schema_definition_declaration_by_name_with_name(self._handle, name))
def declaration_by_name_with_declaration_index(self, declaration_index: int) -> declaration:
return declaration(_native.schema_definition_declaration_by_name_with_declaration_index(self._handle, declaration_index))
return declaration(
_native.schema_definition_declaration_by_name_with_declaration_index(self._handle, declaration_index)
)
def declarations(self) -> list[declaration]:
return [declaration(item) for item in _native.schema_definition_declarations(self._handle)]
@@ -278,6 +301,7 @@ class schema_definition:
def name(self) -> str:
return _native.schema_definition_name(self._handle)
class Base:
__slots__ = ("_handle",)
@@ -301,6 +325,7 @@ class Base:
def id(self) -> int:
return _native.base_id(self._handle)
class Entity:
__slots__ = ("_handle",)
@@ -314,6 +339,7 @@ class Entity:
def get_inverse(self, attribute_name: str) -> list[Entity]:
return [Entity(item) for item in _native.entity_get_inverse(self._handle, attribute_name)]
class Select:
__slots__ = ("_handle",)
@@ -327,6 +353,7 @@ class Select:
def concrete(self) -> Base:
return Base(_native.select_concrete(self._handle))
class DeclaredType:
__slots__ = ("_handle",)
@@ -337,6 +364,7 @@ class DeclaredType:
def create() -> DeclaredType:
return DeclaredType(_native.declared_type_new())
class full_buffer_impl:
__slots__ = ("_handle",)
@@ -365,6 +393,7 @@ class full_buffer_impl:
_native.full_buffer_impl_drop_pages(self._handle, up_to_position)
return None
class paged_file_impl:
__slots__ = ("_handle",)
@@ -373,7 +402,9 @@ class paged_file_impl:
@staticmethod
def with_path_page_size_page_capacity(path: str, page_size: int, page_capacity: int) -> paged_file_impl:
return paged_file_impl(_native.paged_file_impl_new_with_path_page_size_page_capacity(path, page_size, page_capacity))
return paged_file_impl(
_native.paged_file_impl_new_with_path_page_size_page_capacity(path, page_size, page_capacity)
)
def size(self) -> int:
return _native.paged_file_impl_size(self._handle)
@@ -389,6 +420,7 @@ class paged_file_impl:
_native.paged_file_impl_drop_pages(self._handle, up_to_position)
return None
class pushed_sequential_impl:
__slots__ = ("_handle",)
@@ -409,6 +441,7 @@ class pushed_sequential_impl:
_native.pushed_sequential_impl_drop_pages(self._handle, up_to_position)
return None
class character_encoder:
__slots__ = ("_handle",)
@@ -419,6 +452,7 @@ class character_encoder:
def with_input(input: str) -> character_encoder:
return character_encoder(_native.character_encoder_new_with_input(input))
class file_open_status:
__slots__ = ("_handle",)
@@ -427,6 +461,7 @@ class file_open_status:
pass
class spf_header:
__slots__ = ("_handle",)
@@ -435,6 +470,7 @@ class spf_header:
pass
class file:
__slots__ = ("_handle",)
@@ -508,6 +544,7 @@ class file:
_native.file_reset_identity_cache(self._handle)
return None
class global_id:
__slots__ = ("_handle",)