mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
ty: detect unresolved references
This commit is contained in:
@@ -159,8 +159,10 @@ def _add_segment_to_curve(
|
||||
else:
|
||||
assert False
|
||||
|
||||
end_point = ...
|
||||
for mapped_segment in mapped_segments:
|
||||
if mapped_segment:
|
||||
end_point = _add_curve_segment_to_composite_curve(file, layout_segment, mapped_segment, curve)
|
||||
|
||||
assert end_point is not ...
|
||||
return end_point
|
||||
|
||||
@@ -308,5 +308,7 @@ def _get_segment_start_point_label(prev_segment: entity_instance, segment: entit
|
||||
label = _cant_callback(prev_segment, segment)
|
||||
else:
|
||||
label = _cant_label(prev_segment, segment)
|
||||
else:
|
||||
assert False, s.DesignParameters
|
||||
|
||||
return label
|
||||
|
||||
@@ -46,6 +46,7 @@ def _create_layout(file: ifcopenshell.file, alignment: entity_instance, points:
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=alignment_layouts, relating_object=alignment)
|
||||
|
||||
start_dist_along = 0.0
|
||||
gradient = None
|
||||
for p1, p2 in zip(points, points[1:]):
|
||||
x1, y1, z1 = p1.Coordinates
|
||||
x2, y2, z2 = p2.Coordinates
|
||||
@@ -100,6 +101,7 @@ def _create_layout(file: ifcopenshell.file, alignment: entity_instance, points:
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[hsegment], relating_object=alignment_layouts[0])
|
||||
|
||||
if include_vertical:
|
||||
assert gradient is not None
|
||||
vsegment = file.createIfcAlignmentSegment(
|
||||
ifcopenshell.guid.new(),
|
||||
DesignParameters=file.createIfcAlignmentVerticalSegment(
|
||||
|
||||
@@ -57,6 +57,7 @@ def create_from_csv(file: ifcopenshell.file, filepath: str) -> entity_instance:
|
||||
:param filepath: path the to CSV file
|
||||
:return: IfcAlignment
|
||||
"""
|
||||
alignment = None
|
||||
with open(filepath, newline="") as csvfile:
|
||||
reader = csv.reader(csvfile)
|
||||
row_count = 0
|
||||
@@ -89,9 +90,14 @@ def create_from_csv(file: ifcopenshell.file, filepath: str) -> entity_instance:
|
||||
)
|
||||
else:
|
||||
# add all subsequent vertical alignments
|
||||
assert alignment is not None
|
||||
vertical_layout = ifcopenshell.api.alignment.add_vertical_layout(file, alignment)
|
||||
ifcopenshell.api.alignment.layout_vertical_alignment_by_pi_method(
|
||||
file, vertical_layout, coordinates, radii
|
||||
)
|
||||
|
||||
if row_count == 0:
|
||||
raise ValueError(f"CSV file '{filepath}' is empty; expected at least one row for the horizontal alignment.")
|
||||
|
||||
assert alignment is not None
|
||||
return alignment
|
||||
|
||||
@@ -182,6 +182,8 @@ class Usecase:
|
||||
if not reference:
|
||||
migrator = ifcopenshell.util.schema.Migrator()
|
||||
|
||||
old_referenced_source = ...
|
||||
existing_classification = None
|
||||
if self.settings["is_lightweight"]:
|
||||
old_referenced_source = self.settings["reference"].ReferencedSource
|
||||
self.settings["reference"].ReferencedSource = None
|
||||
@@ -194,6 +196,7 @@ class Usecase:
|
||||
reference = migrator.migrate(self.settings["reference"], self.file)
|
||||
|
||||
if self.settings["is_lightweight"]:
|
||||
assert old_referenced_source is not ...
|
||||
reference.ReferencedSource = self.settings["classification"]
|
||||
self.settings["reference"].ReferencedSource = old_referenced_source
|
||||
elif existing_classification:
|
||||
|
||||
@@ -88,6 +88,8 @@ def bearing2dd(bearing: str) -> float:
|
||||
elif cY == "S" and cX == "W":
|
||||
angle = 270.0
|
||||
sign = -1.0
|
||||
else:
|
||||
assert False, (cY, cX)
|
||||
|
||||
try:
|
||||
dms = ifcopenshell.util.geolocation.dms2dd(d, m, s, ms)
|
||||
|
||||
@@ -116,6 +116,8 @@ def add_feature(
|
||||
return ifcopenshell.api.aggregate.assign_object(file, [feature], element)
|
||||
rels = feature.AdheresToElement
|
||||
ifc_class = "IfcRelAdheresToElement"
|
||||
else:
|
||||
assert False, feature
|
||||
|
||||
if rels:
|
||||
if rels[0][4] == element:
|
||||
|
||||
@@ -54,6 +54,8 @@ def remove_feature(file: ifcopenshell.file, feature: ifcopenshell.entity_instanc
|
||||
rels = []
|
||||
else:
|
||||
rels = feature.ProjectsElements
|
||||
else:
|
||||
assert False, feature
|
||||
for rel in rels:
|
||||
history = rel.OwnerHistory
|
||||
file.remove(rel)
|
||||
|
||||
@@ -436,6 +436,7 @@ class Usecase:
|
||||
|
||||
def create_curve_bounded_planes(self, is_2d: bool = False) -> list[ifcopenshell.entity_instance]:
|
||||
items = []
|
||||
points = None
|
||||
if self.file.schema != "IFC2X3":
|
||||
points = self.create_cartesian_point_list_from_vertices(self.settings["geometry"].vertices, is_2d=False)
|
||||
for polygon in self.settings["geometry"].polygons:
|
||||
@@ -443,6 +444,7 @@ class Usecase:
|
||||
if self.file.schema == "IFC2X3":
|
||||
curve = self.create_curve_from_polygon_ifc2x3(polygon, is_2d=False)
|
||||
else:
|
||||
assert points is not None
|
||||
curve = self.create_curve_from_polygon(points, polygon, is_2d=False)
|
||||
items.append(self.file.createIfcCurveBoundedPlane(BasisSurface=plane, OuterBoundary=curve))
|
||||
return items
|
||||
@@ -457,12 +459,14 @@ class Usecase:
|
||||
|
||||
def create_annotation_fill_areas(self, is_2d: bool = False) -> list[ifcopenshell.entity_instance]:
|
||||
items = []
|
||||
points = None
|
||||
if self.file.schema != "IFC2X3":
|
||||
points = self.create_cartesian_point_list_from_vertices(self.settings["geometry"].vertices, is_2d=is_2d)
|
||||
for polygon in self.settings["geometry"].polygons:
|
||||
if self.file.schema == "IFC2X3":
|
||||
curve = self.create_curve_from_polygon_ifc2x3(polygon, is_2d=is_2d)
|
||||
else:
|
||||
assert points is not None
|
||||
curve = self.create_curve_from_polygon(points, polygon, is_2d=is_2d)
|
||||
items.append(self.file.createIfcAnnotationFillArea(OuterBoundary=curve))
|
||||
return items
|
||||
@@ -813,17 +817,20 @@ class Usecase:
|
||||
|
||||
def create_triangulated_face_set(self) -> ifcopenshell.entity_instance:
|
||||
ifc_raw_items = [None] * self.settings["total_items"]
|
||||
ifc_raw_uv_items = None
|
||||
if self.settings["should_generate_uvs"]:
|
||||
ifc_raw_uv_items = [None] * self.settings["total_items"]
|
||||
for i, value in enumerate(ifc_raw_items):
|
||||
ifc_raw_items[i] = []
|
||||
if self.settings["should_generate_uvs"]:
|
||||
assert ifc_raw_uv_items is not None
|
||||
ifc_raw_uv_items[i] = []
|
||||
for polygon in self.settings["geometry"].polygons:
|
||||
ifc_raw_items[polygon.material_index % self.settings["total_items"]].append(
|
||||
[v + 1 for v in polygon.vertices]
|
||||
)
|
||||
if self.settings["should_generate_uvs"]:
|
||||
assert ifc_raw_uv_items is not None
|
||||
ifc_raw_uv_items[polygon.material_index % self.settings["total_items"]].append(
|
||||
[uv + 1 for uv in polygon.loop_indices]
|
||||
)
|
||||
@@ -831,6 +838,7 @@ class Usecase:
|
||||
coordinates = self.create_cartesian_point_list_from_vertices(self.settings["geometry"].vertices)
|
||||
|
||||
if self.settings["should_generate_uvs"]:
|
||||
assert ifc_raw_uv_items is not None
|
||||
# Blender supports multiple UV layers. We don't. Too bad.
|
||||
tex_coords = self.file.createIfcTextureVertexList(
|
||||
[tuple(x.uv) for x in self.settings["geometry"].uv_layers[0].data]
|
||||
|
||||
@@ -50,6 +50,12 @@ def disconnect_path(
|
||||
for r in relating_element.ConnectedTo
|
||||
if r.is_a("IfcRelConnectsPathElements") and r.RelatedElement == related_element
|
||||
]
|
||||
else:
|
||||
raise ValueError(
|
||||
"Either provide `element` and `connection_type`, or provide `relating_element` and `related_element`. "
|
||||
f"Got: element={element}, connection_type={connection_type}, "
|
||||
f"relating_element={relating_element}, related_element={related_element}."
|
||||
)
|
||||
|
||||
for connection in set(connections):
|
||||
history = connection.OwnerHistory
|
||||
|
||||
@@ -52,6 +52,7 @@ def edit_true_north(file: ifcopenshell.file, true_north: Optional[Union[tuple[fl
|
||||
# This unsets true north
|
||||
ifcopenshell.api.georeference.edit_true_north(model, true_north=None)
|
||||
"""
|
||||
x, y = None, None
|
||||
if isinstance(true_north, (float, int)):
|
||||
x, y = ifcopenshell.util.geolocation.angle2yaxis(true_north)
|
||||
elif true_north is not None:
|
||||
@@ -73,4 +74,5 @@ def edit_true_north(file: ifcopenshell.file, true_north: Optional[Union[tuple[fl
|
||||
context.TrueNorth = file.create_entity("IfcDirection")
|
||||
else:
|
||||
context.TrueNorth = file.create_entity("IfcDirection")
|
||||
assert x is not None and y is not None
|
||||
context.TrueNorth.DirectionRatios = (x, y)
|
||||
|
||||
@@ -90,6 +90,8 @@ def edit_wcs(
|
||||
point,
|
||||
file.createIfcDirection((xaxis_x, xaxis_y)),
|
||||
)
|
||||
else:
|
||||
assert False, context
|
||||
context.WorldCoordinateSystem = placement
|
||||
if file.get_total_inverses(old_wcs) == 0:
|
||||
ifcopenshell.util.element.remove_deep2(file, old_wcs)
|
||||
|
||||
+2
@@ -61,6 +61,8 @@ def add_structural_boundary_condition(
|
||||
boundary_class = "IfcBoundaryEdgeCondition"
|
||||
elif related_connection.is_a("IfcStructuralSurfaceConnection"):
|
||||
boundary_class = "IfcBoundaryFaceCondition"
|
||||
else:
|
||||
assert False, related_connection
|
||||
|
||||
condition = file.create_entity(boundary_class, Name=name)
|
||||
connection.AppliedCondition = condition
|
||||
|
||||
@@ -126,6 +126,7 @@ class Usecase:
|
||||
use_style_assignment = self.file.schema == "IFC2X3" or self.settings["should_use_presentation_style_assignment"]
|
||||
replace_previous_same_type_style = self.settings["replace_previous_same_type_style"]
|
||||
|
||||
style: ifcopenshell.entity_instance | None = None
|
||||
for element in self.file.traverse(self.settings["shape_representation"]):
|
||||
if not element.is_a("IfcShapeModel"):
|
||||
continue
|
||||
@@ -137,6 +138,7 @@ class Usecase:
|
||||
if self.settings["styles"]:
|
||||
# If there are more items than styles, fallback to using the last style
|
||||
style = self.settings["styles"].pop(0)
|
||||
assert style is not None
|
||||
name = style.Name
|
||||
current_style_type = style.is_a()
|
||||
|
||||
|
||||
@@ -51,7 +51,8 @@ def assign_system(
|
||||
# This duct is part of the system
|
||||
ifcopenshell.api.system.assign_system(model, products=[duct], system=system)
|
||||
"""
|
||||
if not all(ifcopenshell.util.system.is_assignable(failed_product := product, system) for product in products):
|
||||
raise TypeError(f"You cannot assign an {failed_product.is_a()} to an {system.is_a()}")
|
||||
for product in products:
|
||||
if not ifcopenshell.util.system.is_assignable(product, system):
|
||||
raise TypeError(f"You cannot assign an {product.is_a()} to an {system.is_a()}")
|
||||
|
||||
return ifcopenshell.api.group.assign_group(file, products=products, group=system)
|
||||
|
||||
@@ -144,6 +144,8 @@ class Usecase:
|
||||
elif unit_type == "volume":
|
||||
dimensional_exponents = self.file.createIfcDimensionalExponents(3, 0, 0, 0, 0, 0, 0)
|
||||
name_prefix = "cubic"
|
||||
else:
|
||||
assert False, unit_type
|
||||
|
||||
si_unit = self.file.createIfcSIUnit(
|
||||
None,
|
||||
@@ -159,6 +161,8 @@ class Usecase:
|
||||
name = "{}mile".format(name_prefix + " " if name_prefix else "")
|
||||
elif data["raw"] == "THOU":
|
||||
name = "{}thou".format(name_prefix + " " if name_prefix else "")
|
||||
else:
|
||||
assert False, data
|
||||
value_component = self.file.create_entity(
|
||||
"IfcReal", **{"wrappedValue": ifcopenshell.util.unit.si_conversions[name]}
|
||||
)
|
||||
|
||||
@@ -296,6 +296,7 @@ def main(
|
||||
else:
|
||||
num_passes = 0
|
||||
|
||||
g2 = None
|
||||
for iteration in range(num_passes + 1):
|
||||
|
||||
# initialize empty group, note that in the current approach only one
|
||||
@@ -316,6 +317,7 @@ def main(
|
||||
plt.fill(numpy.array(x.boundary).T[0], numpy.array(x.boundary).T[1])
|
||||
"""
|
||||
|
||||
semantics, pairs = None, None
|
||||
if iteration != num_passes:
|
||||
pairs = svgfill_context.get_face_pairs()
|
||||
semantics = [None] * (max(pairs) + 1)
|
||||
@@ -377,6 +379,7 @@ def main(
|
||||
if inside_elements:
|
||||
elements = None
|
||||
if iteration != num_passes:
|
||||
assert semantics is not None
|
||||
semantics[pi] = (inside_elements[0], -1)
|
||||
else:
|
||||
elements = tree.select_ray(pythonize(a), pythonize(b - a))
|
||||
@@ -409,6 +412,7 @@ def main(
|
||||
svg_fill = "rgb(%s)" % ", ".join(str(f * 255.0) for f in clr[0:3])
|
||||
|
||||
if iteration != num_passes:
|
||||
assert semantics is not None
|
||||
semantics[pi] = elements[0]
|
||||
else:
|
||||
svg_fill = "none"
|
||||
@@ -418,6 +422,8 @@ def main(
|
||||
if iteration != num_passes:
|
||||
to_remove = []
|
||||
|
||||
assert pairs is not None
|
||||
assert semantics is not None
|
||||
for he_idx in range(0, len(pairs), 2):
|
||||
# @todo instead of ray_distance, better do (x.point - y.point).dot(x.normal)
|
||||
# to see if they're coplanar, because ray-distance will be different in case
|
||||
@@ -445,6 +451,7 @@ def main(
|
||||
|
||||
# Swap the XML nodes from the files
|
||||
# Remove the original hidden line node we still have in the serializer output
|
||||
assert g2 is not None
|
||||
g1.removeChild(projection)
|
||||
g2.setAttribute("class", "projection")
|
||||
# Find the children of the projection node parent
|
||||
|
||||
@@ -192,7 +192,7 @@ class entity_instance:
|
||||
return
|
||||
|
||||
@property
|
||||
def file(self):
|
||||
def file(self) -> "ifcopenshell.file":
|
||||
# ugh circular imports, name collisions
|
||||
from . import file
|
||||
|
||||
|
||||
@@ -734,6 +734,7 @@ class file:
|
||||
# Don't store these attributes as transactions
|
||||
# as the creation it self is already stored with
|
||||
# it's arguments
|
||||
transaction = None
|
||||
if attrs:
|
||||
transaction = self.transaction
|
||||
self.transaction = None
|
||||
@@ -849,11 +850,13 @@ class file:
|
||||
:returns: An ifcopenshell.entity_instance
|
||||
"""
|
||||
|
||||
max_id = None
|
||||
if self.transaction:
|
||||
max_id = self.wrapped_data.getMaxId()
|
||||
inst.wrapped_data.this.disown()
|
||||
result = entity_instance(self.wrapped_data.add(inst.wrapped_data, -1 if _id is None else _id), self)
|
||||
if self.transaction:
|
||||
assert max_id is not None
|
||||
added_elements = [e for e in self.traverse(result) if e.id() > max_id]
|
||||
[self.transaction.store_create(e) for e in reversed(added_elements)]
|
||||
return result
|
||||
|
||||
@@ -326,10 +326,11 @@ class iterator(ifcopenshell_wrapper.Iterator):
|
||||
if include_or_exclude_type == {"entity_instance"}:
|
||||
include_or_exclude = cast(set[entity_instance], include_or_exclude)
|
||||
|
||||
if not all((last_inst := inst).is_a("IfcProduct") for inst in include_or_exclude):
|
||||
raise ValueError(
|
||||
f"include and exclude need to be an aggregate of IfcProduct. Violating element: '{last_inst}'."
|
||||
)
|
||||
for inst in include_or_exclude:
|
||||
if not inst.is_a("IfcProduct"):
|
||||
raise ValueError(
|
||||
f"include and exclude need to be an aggregate of IfcProduct. Violating element: '{inst}'."
|
||||
)
|
||||
|
||||
initializer = ifcopenshell_wrapper.construct_iterator_with_include_exclude_id
|
||||
|
||||
|
||||
@@ -1070,7 +1070,10 @@ class file:
|
||||
"""
|
||||
...
|
||||
|
||||
def getMaxId(self): ...
|
||||
def getMaxId(self) -> int:
|
||||
"""Get the highest instance id currently in use in the file."""
|
||||
...
|
||||
|
||||
def get_total_inverses_by_id(self, instance_id: int) -> int: ...
|
||||
def getUnit(self, unit_type): ...
|
||||
def get_inverse(self, e: entity_instance) -> tuple[entity_instance, ...]: ...
|
||||
|
||||
@@ -112,6 +112,8 @@ def sum_child_root_elements(root_element: ifcopenshell.entity_instance, category
|
||||
values = new_child_root_element.CostValues
|
||||
elif root_element.is_a("IfcConstructionResource"):
|
||||
values = child_root_element.BaseCosts
|
||||
else:
|
||||
assert False, root_element
|
||||
for child_cost_value in values or []:
|
||||
if category_filter and child_cost_value.Category != category_filter:
|
||||
continue
|
||||
|
||||
@@ -329,6 +329,8 @@ def get_quantity(
|
||||
data["properties"] = get_quantities(quantity.HasQuantities, verbose=verbose)
|
||||
del data["HasQuantities"]
|
||||
result = data
|
||||
else:
|
||||
assert False, quantity
|
||||
if verbose:
|
||||
result = {"id": quantity.id(), "class": quantity.is_a(), "value": result}
|
||||
return result
|
||||
@@ -385,6 +387,7 @@ def get_property(
|
||||
if prop.Name != name:
|
||||
continue
|
||||
is_single_value = False # For now we pass value type only for single values.
|
||||
result_type = None
|
||||
if prop.is_a("IfcPropertySingleValue"):
|
||||
# 2 IfcPropertySingleValue.NominalValue
|
||||
result = v.wrappedValue if (v := prop[2]) else None
|
||||
@@ -407,6 +410,8 @@ def get_property(
|
||||
data["properties"] = get_properties(prop.HasProperties, verbose=verbose)
|
||||
del data["HasProperties"]
|
||||
result = data
|
||||
else:
|
||||
assert False, prop
|
||||
if verbose:
|
||||
result = {"id": prop.id(), "class": prop.is_a(), "value": result}
|
||||
if is_single_value:
|
||||
|
||||
@@ -260,6 +260,8 @@ def get_helmert_transformation_parameters(ifc_file: ifcopenshell.file) -> Option
|
||||
xaa = 1.0
|
||||
xao = 0.0
|
||||
scale = factor_x = factor_y = factor_z = 1
|
||||
else:
|
||||
assert False, conversion
|
||||
|
||||
if not xaa and not xao:
|
||||
xaa = 1.0
|
||||
|
||||
@@ -18,18 +18,16 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
try:
|
||||
from lark import Lark, Transformer
|
||||
from lark.exceptions import UnexpectedCharacters, UnexpectedEOF, UnexpectedToken
|
||||
|
||||
LARK_AVAILABLE = True
|
||||
except ImportError:
|
||||
LARK_AVAILABLE = False
|
||||
|
||||
import importlib.util
|
||||
import re
|
||||
from typing import Union
|
||||
|
||||
LARK_AVAILABLE = importlib.util.find_spec("lark") is not None
|
||||
|
||||
if LARK_AVAILABLE:
|
||||
from lark import Lark, Transformer
|
||||
from lark.exceptions import UnexpectedCharacters, UnexpectedEOF, UnexpectedToken
|
||||
|
||||
mvd_grammar = r"""
|
||||
start: entry+
|
||||
|
||||
@@ -92,9 +90,9 @@ if LARK_AVAILABLE:
|
||||
self.store_text_attribute(args, "options")
|
||||
|
||||
def dynamic_option(self, args):
|
||||
original_keyword = str(args[0])
|
||||
key = original_keyword.lower()
|
||||
try:
|
||||
original_keyword = str(args[0])
|
||||
key = original_keyword.lower()
|
||||
raw_text = args[1].children[0].value
|
||||
parsed_value = parse_semicolon_separated_kv(raw_text)
|
||||
self._dynamic[key] = (parsed_value, original_keyword)
|
||||
|
||||
@@ -89,6 +89,9 @@ def get_axis2placement(placement: ifcopenshell.entity_instance) -> MatrixType:
|
||||
x = np.array((1, 0, 0))
|
||||
o = placement.Location.Coordinates
|
||||
|
||||
else:
|
||||
assert False, placement
|
||||
|
||||
return a2p(o, z, x)
|
||||
|
||||
|
||||
|
||||
@@ -584,6 +584,7 @@ class Migrator:
|
||||
# NOTE: `attribute` is an attribute in new file schema
|
||||
# print("Migrating attribute", element, new_element, attribute.name())
|
||||
old_file = element.wrapped_data.file
|
||||
value = ...
|
||||
if hasattr(element, attribute.name()):
|
||||
value = getattr(element, attribute.name())
|
||||
# print("Attribute names matched", value)
|
||||
@@ -622,9 +623,7 @@ class Migrator:
|
||||
except: # We tried our best
|
||||
return
|
||||
|
||||
try:
|
||||
value
|
||||
except UnboundLocalError:
|
||||
if value is ...:
|
||||
print(
|
||||
f"Couldn't match attribute {attribute.name()} by name to migrate from {element} "
|
||||
f"to {new_element} and there is no special mapping to handle migration "
|
||||
|
||||
@@ -1279,6 +1279,8 @@ class FacetTransformer(lark.Transformer):
|
||||
result = bool(value.match(element_value)) if element_value is not None else False
|
||||
elif value in (None, True, False):
|
||||
result = element_value is value
|
||||
else:
|
||||
assert False, value
|
||||
|
||||
if comparison.startswith("!"):
|
||||
return not result
|
||||
|
||||
@@ -210,6 +210,8 @@ def np_rotation_matrix(
|
||||
matrix = np.array([[cos_theta, 0, sin_theta], [0, 1, 0], [-sin_theta, 0, cos_theta]])
|
||||
elif axis == "Z":
|
||||
matrix = np.array([[cos_theta, -sin_theta, 0], [sin_theta, cos_theta, 0], [0, 0, 1]])
|
||||
else:
|
||||
assert False, axis
|
||||
else:
|
||||
# Assume axis is a vector.
|
||||
axis = axis / np.linalg.norm(axis)
|
||||
|
||||
@@ -320,6 +320,7 @@ def log_internal_cpp_errors(
|
||||
|
||||
if log_content is None:
|
||||
log_content = ifcopenshell.get_log()
|
||||
lines = None
|
||||
msgs = list(map(json.loads, filter(None, log_content.split("\n"))))
|
||||
chr_offsets = [chr_offset_re.findall(m["message"]) for m in msgs]
|
||||
instance_messages = [for_instance_re.findall(m["message"]) for m in msgs]
|
||||
@@ -356,6 +357,7 @@ def log_internal_cpp_errors(
|
||||
except:
|
||||
inst = None
|
||||
else:
|
||||
assert lines is not None
|
||||
inst = next(
|
||||
(
|
||||
l.decode("ascii", errors="ignore").strip()
|
||||
@@ -691,14 +693,16 @@ def validate_ifc_header(
|
||||
if not value:
|
||||
log_error(header_entity, name, index, AGGREGATE_TYPE, "EMPTY LIST")
|
||||
return
|
||||
if not all(isinstance(last_value := v, str) for v in value):
|
||||
log_error(
|
||||
header_entity,
|
||||
name,
|
||||
index,
|
||||
AGGREGATE_TYPE,
|
||||
f"LIST with {type(last_value).__name__} (value: {last_value})",
|
||||
)
|
||||
for v in value:
|
||||
if not isinstance(v, str):
|
||||
log_error(
|
||||
header_entity,
|
||||
name,
|
||||
index,
|
||||
AGGREGATE_TYPE,
|
||||
f"LIST with {type(v).__name__} (value: {v})",
|
||||
)
|
||||
break
|
||||
return
|
||||
|
||||
if not isinstance(value, str):
|
||||
|
||||
@@ -26,6 +26,8 @@ def test_file_gc(args):
|
||||
inst = f.createIfcPerson()
|
||||
elif api in (1, 2):
|
||||
inst = f.createIfcSite()
|
||||
else:
|
||||
assert False, api
|
||||
|
||||
r = weakref.ref(f)
|
||||
|
||||
@@ -68,9 +70,9 @@ def test_file_gc(args):
|
||||
assert r()
|
||||
|
||||
if not file_first:
|
||||
del f
|
||||
del f # ty: ignore[possibly-unresolved-reference]
|
||||
else:
|
||||
del inst
|
||||
del inst # ty: ignore[possibly-unresolved-reference]
|
||||
|
||||
# With both deleted we should have no longer access to the file.
|
||||
assert r() is None
|
||||
|
||||
Reference in New Issue
Block a user