diff --git a/src/ifcopenshell-python/ifcopenshell/util/data.py b/src/ifcopenshell-python/ifcopenshell/util/data.py index 9f02d973a5..75fae18ed5 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/data.py +++ b/src/ifcopenshell-python/ifcopenshell/util/data.py @@ -66,7 +66,7 @@ class Clipping: raise Exception(f"Unexpected clipping type provided: {raw_data}") def apply( - self, ifc_file: ifcopenshell.file, first_operand: ifcopenshell.entity_instance, unit_scale: float + self, ifc_file: Union[ifcopenshell.file, None], first_operand: ifcopenshell.entity_instance, unit_scale: float ) -> ifcopenshell.entity_instance: """Applies the clipping data as an IfcBooleanClippingResult to an operand @@ -76,6 +76,9 @@ class Clipping: :return: An IfcBooleanClippingResult which uses an IfcHalfSpaceSolid to clip the first operand """ + if not ifc_file: + ifc_file = first_operand.file + location = ifc_file.createIfcCartesianPoint([i / unit_scale for i in self.location]) direction = ifc_file.createIfcDirection(self.normal) diff --git a/src/ifcopenshell-python/ifcopenshell/util/element.py b/src/ifcopenshell-python/ifcopenshell/util/element.py index 9034e382be..e4b6ee951d 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/element.py +++ b/src/ifcopenshell-python/ifcopenshell/util/element.py @@ -689,7 +689,7 @@ def get_styles(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entit # TODO: ifc_file argument is unnecessary for some methods now # since we have entity_instance.file, so we can deprecate it. def get_elements_by_material( - ifc_file: ifcopenshell.file, material: ifcopenshell.entity_instance + ifc_file: Union[ifcopenshell.file, None], material: ifcopenshell.entity_instance ) -> set[ifcopenshell.entity_instance]: """Retrieves the elements related to a material. @@ -707,6 +707,8 @@ def get_elements_by_material( material = file.by_type("IfcMaterial")[0] elements = ifcopenshell.util.element.get_elements_by_material(file, material) """ + if not ifc_file: + ifc_file = material.file results = set() for inverse in ifc_file.get_inverse(material): if inverse.is_a("IfcRelAssociatesMaterial"): @@ -730,7 +732,7 @@ def get_elements_by_material( def get_elements_by_style( - ifc_file: ifcopenshell.file, style: ifcopenshell.entity_instance + ifc_file: Union[ifcopenshell.file, None], style: ifcopenshell.entity_instance ) -> set[ifcopenshell.entity_instance]: """Retrieves the elements whose geometric representation uses a style @@ -745,6 +747,8 @@ def get_elements_by_style( style = file.by_type("IfcSurfaceStyle")[0] elements = ifcopenshell.util.element.get_elements_by_style(file, style) """ + if not ifc_file: + ifc_file = style.file results = set() inverses = list(ifc_file.get_inverse(style)) while inverses: @@ -778,7 +782,7 @@ def get_elements_by_style( def get_elements_by_representation( - ifc_file: ifcopenshell.file, representation: ifcopenshell.entity_instance + ifc_file: Union[ifcopenshell.file, None], representation: ifcopenshell.entity_instance ) -> set[ifcopenshell.entity_instance]: """Gets all elements using a geometric representation @@ -793,6 +797,8 @@ def get_elements_by_representation( representation = file.by_type("IfcShapeRepresentation")[0] elements = ifcopenshell.util.element.get_elements_by_representation(file, representation) """ + if not ifc_file: + ifc_file = representation.file results = set() [results.update(pr.ShapeOfProduct) for pr in representation.OfProductRepresentation] for rep_map in representation.RepresentationMap: @@ -838,7 +844,7 @@ def get_elements_by_profile(profile: ifcopenshell.entity_instance) -> set[ifcope def get_elements_by_layer( - ifc_file: ifcopenshell.file, layer: ifcopenshell.entity_instance + ifc_file: Union[ifcopenshell.file, None], layer: ifcopenshell.entity_instance ) -> set[ifcopenshell.entity_instance]: """Get all the elements that are used by a presentation layer @@ -846,6 +852,8 @@ def get_elements_by_layer( :param layer: The IfcPresentationLayerAssignment layer :return: The elements using the geometric representation """ + if not ifc_file: + ifc_file = layer.file results = set() for item in layer.AssignedItems or []: if item.is_a("IfcShapeRepresentation"): @@ -858,7 +866,7 @@ def get_elements_by_layer( def get_layers( - ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance + ifc_file: Union[ifcopenshell.file, None], element: ifcopenshell.entity_instance ) -> list[ifcopenshell.entity_instance]: """Get the CAD layers that an element is part of @@ -876,6 +884,8 @@ def get_layers( element = ifcopenshell.by_type("IfcWall")[0] layers = ifcopenshell.util.element.get_layers(element) """ + if not ifc_file: + ifc_file = element.file layers = [] representations = [] if representation := getattr(element, "Representation", None): @@ -1352,12 +1362,14 @@ def has_element_reference(value: Any, element: ifcopenshell.entity_instance) -> return value == element -def remove_deep(ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance) -> None: +def remove_deep(ifc_file: Union[ifcopenshell.file, None], element: ifcopenshell.entity_instance) -> None: """Recursively purges a subgraph safely. Do not use, use remove_deep2() instead. """ # @todo maybe some sort of try-finally mechanism. + if not ifc_file: + ifc_file = element.file ifc_file.batch() subgraph = list(ifc_file.traverse(element, breadth_first=True)) subgraph_set = set(subgraph) @@ -1431,7 +1443,7 @@ def unbatch_remove_deep2(ifc_file: ifcopenshell.file) -> ifcopenshell.file: def remove_deep2( - ifc_file: ifcopenshell.file, + ifc_file: Union[ifcopenshell.file, None], element: ifcopenshell.entity_instance, also_consider: list[ifcopenshell.entity_instance] = [], do_not_delete: set[ifcopenshell.entity_instance] = set(), @@ -1468,6 +1480,8 @@ def remove_deep2( :param element: The starting element that defines the subgraph """ # ifc_file.batch() + if not ifc_file: + ifc_file = element.file total_inverses = ifc_file.get_total_inverses(element) if total_inverses > 0: @@ -1527,7 +1541,9 @@ def remove_deep2( # ifc_file.unbatch() -def copy(ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance: +def copy( + ifc_file: Union[ifcopenshell.file, None], element: ifcopenshell.entity_instance +) -> ifcopenshell.entity_instance: """ Copy a single element. Any referenced elements are not copied. @@ -1537,6 +1553,8 @@ def copy(ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance) -> :param element: The IFC element to copy :return: The newly copied element """ + if not ifc_file: + ifc_file = element.file new = ifc_file.create_entity(element.is_a()) for i, attribute in enumerate(element): if attribute is None: @@ -1549,7 +1567,7 @@ def copy(ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance) -> def copy_deep( - ifc_file: ifcopenshell.file, + ifc_file: Union[ifcopenshell.file, None], element: ifcopenshell.entity_instance, exclude: Optional[Sequence[str]] = None, exclude_callback: Optional[Callable[[ifcopenshell.entity_instance], bool]] = None, @@ -1572,6 +1590,8 @@ def copy_deep( be left as None. :return: The newly copied element """ + if not ifc_file: + ifc_file = element.file if copied_entities is None: copied_entities = {} else: diff --git a/src/ifcopenshell-python/ifcopenshell/util/schema.py b/src/ifcopenshell-python/ifcopenshell/util/schema.py index 70eff36eb9..79c8a9c499 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/schema.py +++ b/src/ifcopenshell-python/ifcopenshell/util/schema.py @@ -140,7 +140,7 @@ def get_subtypes( def reassign_class( - ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance, new_class: str + ifc_file: Union[ifcopenshell.file, None], element: ifcopenshell.entity_instance, new_class: str ) -> ifcopenshell.entity_instance: """ Attempts to change the class (entity name) of `element` to `new_class` by @@ -156,6 +156,9 @@ def reassign_class( It's unlikely that this affects real-world usage of this function. """ + if not ifc_file: + ifc_file = element.file + schema: ifcopenshell_wrapper.schema_definition = ifcopenshell_wrapper.schema_by_name(ifc_file.schema) try: declaration = schema.declaration_by_name(new_class) diff --git a/src/ifcopenshell-python/ifcopenshell/util/unit.py b/src/ifcopenshell-python/ifcopenshell/util/unit.py index b1862d3882..78a0117fa5 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/unit.py +++ b/src/ifcopenshell-python/ifcopenshell/util/unit.py @@ -456,7 +456,7 @@ def get_project_unit( def get_property_unit( - prop: ifcopenshell.entity_instance, ifc_file: ifcopenshell.file, use_cache: bool = False + prop: ifcopenshell.entity_instance, ifc_file: Union[ifcopenshell.file, None], use_cache: bool = False ) -> Union[ifcopenshell.entity_instance, None]: """Gets the unit definition of a property or quantity @@ -499,11 +499,13 @@ def get_property_unit( measure_class = value.is_a() if measure_class and (unit_type := get_measure_unit_type(measure_class)): + if not ifc_file: + ifc_file = prop.file return get_project_unit(ifc_file, unit_type, use_cache=use_cache) def get_property_table_unit( - prop: ifcopenshell.entity_instance, ifc_file: ifcopenshell.file, use_cache: bool = False + prop: ifcopenshell.entity_instance, ifc_file: Union[ifcopenshell.file, None], use_cache: bool = False ) -> Dict[str, Union[ifcopenshell.entity_instance, None]]: """ Gets the unit definition of a property table @@ -523,6 +525,8 @@ def get_property_table_unit( If a unit-entity is missing, the value associated to the key is `null`. """ + if not ifc_file: + ifc_file = prop.file defining_unit = None if unit := prop.DefiningUnit: defining_unit = unit