diff --git a/src/bonsai/bonsai/bim/module/drawing/svgwriter.py b/src/bonsai/bonsai/bim/module/drawing/svgwriter.py index 6f32ea900f..15f9e8c579 100644 --- a/src/bonsai/bonsai/bim/module/drawing/svgwriter.py +++ b/src/bonsai/bonsai/bim/module/drawing/svgwriter.py @@ -25,6 +25,7 @@ import shutil import mathutils import xml.etree.ElementTree as ET import svgwrite +import svgwrite.text import ifcopenshell import ifcopenshell.util.element import ifcopenshell.util.representation @@ -774,7 +775,7 @@ class SvgWriter: "text-anchor": text_anchor, } - def add_fill_bg(self, element, copy=True): + def add_fill_bg(self, element: svgwrite.text.Text, copy: bool = True) -> svgwrite.text.Text: if copy: element = element.copy() if hasattr(element, "xml"): diff --git a/src/bonsai/bonsai/bim/module/resource/ui.py b/src/bonsai/bonsai/bim/module/resource/ui.py index d046277a98..fe5d85acd7 100644 --- a/src/bonsai/bonsai/bim/module/resource/ui.py +++ b/src/bonsai/bonsai/bim/module/resource/ui.py @@ -16,10 +16,12 @@ # You should have received a copy of the GNU General Public License # along with Bonsai. If not, see . +import bpy import bonsai.bim.helper from bpy.types import Panel, UIList from bonsai.bim.ifc import IfcStore from bonsai.bim.module.resource.data import ResourceData +from typing import Any class BIM_PT_resources(Panel): @@ -287,7 +289,7 @@ class BIM_PT_resources(Panel): if self.props.cost_value_editing_type == "ATTRIBUTES": bonsai.bim.helper.draw_attributes(self.props.cost_value_attributes, self.layout.box()) - def draw_readonly_cost_value_ui(self, layout, cost_value): + def draw_readonly_cost_value_ui(self, layout: bpy.types.UILayout, cost_value: dict[str, Any]) -> None: if self.props.active_cost_value_id == cost_value["id"] and self.props.cost_value_editing_type == "FORMULA": layout.prop(self.props, "cost_value_formula", text="") else: @@ -295,7 +297,7 @@ class BIM_PT_resources(Panel): self.draw_cost_value_operator_ui(layout, cost_value["id"], self.props.active_resource_id) - def draw_cost_value_operator_ui(self, layout, cost_value_id, parent_id): + def draw_cost_value_operator_ui(self, layout: bpy.types.UILayout, cost_value_id: int, parent_id: int) -> None: if self.props.active_cost_value_id and self.props.active_cost_value_id == cost_value_id: if self.props.cost_value_editing_type == "ATTRIBUTES": op = layout.operator("bim.edit_resource_cost_value", text="", icon="CHECKMARK") diff --git a/src/ifcopenshell-python/ifcopenshell/util/element.py b/src/ifcopenshell-python/ifcopenshell/util/element.py index 1ff7402051..7c372a734c 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/element.py +++ b/src/ifcopenshell-python/ifcopenshell/util/element.py @@ -53,20 +53,13 @@ def get_pset( occurrence, not the type's pset. :param element: The IFC Element entity - :type element: ifcopenshell.entity_instance :param name: The name of the pset - :type name: str :param prop: The name of the property - :type prop: str,optional :param psets_only: Default as False. Set to true if only property sets are needed. - :type psets_only: bool,optional :param qtos_only: Default as False. Set to true if only quantities are needed. - :type qtos_only: bool,optional :param should_inherit: Default as True. Set to false if you don't want to inherit property sets from the Type. - :type should_inherit: bool,optional :return: A dictionary of property names and values, or a single value if a property is specified. - :rtype: Union[Any, dict[str, Any]] Example: @@ -157,17 +150,11 @@ def get_psets( occurrence, not the type's pset. :param element: The IFC Element entity - :type element: ifcopenshell.entity_instance :param psets_only: Default as False. Set to true if only property sets are needed. - :type psets_only: bool,optional :param qtos_only: Default as False. Set to true if only quantities are needed. - :type qtos_only: bool,optional :param should_inherit: Default as True. Set to false if you don't want to inherit property sets from the Type. - :type should_inherit: bool,optional :param verbose: More detailed prop values, defaults to False. - :type verbose: bool,optional :return: Key, value pair of psets' names and their properties' names & values - :rtype: dict[str, dict[str, Any]] Example: @@ -471,9 +458,7 @@ def get_predefined_type(element: ifcopenshell.entity_instance) -> str: considered first. :param element: The IFC Element entity - :type element: ifcopenshell.entity_instance :return: The predefined type of the element - :rtype: str Example: @@ -503,9 +488,7 @@ def get_type(element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity Note: `get_type(type_element) == type_element`. :param element: The element occurrence (IfcObject) - :type: ifcopenshell.entity_instance :return: The related type element - :rtype: Union[ifcopenshell.entity_instance, None] Example: @@ -533,9 +516,7 @@ def get_types(type: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_in """Get all the occurrences of a type element :param type: The type element - :type type: ifcopenshell.entity_instance :return: A list of occurrences of that type - :rtype: list[ifcopenshell.entity_instance] Example: @@ -588,17 +569,13 @@ def get_material( constituent), or a material set usage. :param element: The element to get the material of. - :type element: ifcopenshell.entity_instance :param should_skip_usage: If set to True, if the material is a material set usage, the material set itself will be returned. Useful if you don't care about occurrence usage parameters. If False, the usage will be returned. - :type should_skip_usage: bool :param should_inherit: If True, any inherited materials from associated types will be considered. - :type should_inherit: bool :return: The associated material of the element or `None`. - :rtype: Union[ifcopenshell.entity_instance, None] Example: @@ -632,11 +609,9 @@ def get_materials( returned as a list. :param element: The element to get the materials of. - :type element: ifcopenshell.entity_instance :param should_inherit: If True, any inherited materials from associated types will be considered. :return: The associated materials of the element. - :rtype: list[ifcopenshell.entity_instance] Example: @@ -658,6 +633,8 @@ def get_materials( return [c.Material for c in material.MaterialConstituents] elif material.is_a("IfcMaterialList"): return list(material.Materials) + else: + assert False, f"Unexpected material type: {material.is_a()}" def get_styles(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]: @@ -666,9 +643,7 @@ def get_styles(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entit Styles may be retreived from the material or the body representation. :param element: The element to get the styles of. - :type element: ifcopenshell.entity_instance :return: A list of surface styles - :rtype: list[ifcopenshell.entity_instance] Example: @@ -749,15 +724,12 @@ def get_elements_by_material( def get_elements_by_style( ifc_file: ifcopenshell.file, style: ifcopenshell.entity_instance -) -> list[ifcopenshell.entity_instance]: +) -> set[ifcopenshell.entity_instance]: """Retrieves the elements whose geometric representation uses a style :param ifc_file: The IFC file - :type ifc_file: ifcopenshell.file :param style: The IfcPresentationStyle entity - :type style: ifcopenshell.entity_instance :return: The elements related to the style - :rtype: list[ifcopenshell.entity_instance] Example: @@ -804,11 +776,8 @@ def get_elements_by_representation( """Gets all elements using a geometric representation :param ifc_file: The IFC file - :type ifc_file: ifcopenshell.file :param representation: The IfcShapeRepresentation representation - :type representation: ifcopenshell.entity_instance :return: The elements using the geometric representation - :rtype: set[ifcopenshell.entity_instance] Example: @@ -834,15 +803,12 @@ def get_elements_by_representation( def get_elements_by_layer( ifc_file: ifcopenshell.file, layer: ifcopenshell.entity_instance -) -> list[ifcopenshell.entity_instance]: +) -> set[ifcopenshell.entity_instance]: """Get all the elements that are used by a presentation layer :param ifc_file: The IFC file - :type ifc_file: ifcopenshell.file :param layer: The IfcPresentationLayerAssignment layer - :type layer: ifcopenshell.entity_instance :return: The elements using the geometric representation - :rtype: list[ifcopenshell.entity_instance] """ results = set() for item in layer.AssignedItems or []: @@ -864,11 +830,8 @@ def get_layers( traditional CAD presentation layer. :param ifc_file: The IFC file object - :type ifc_file: ifcopenshell.file :param element: The IFC element to interrogate - :type element: ifcopenshell.entity_instance :return: A list of IfcPresentationLayerAssignment - :rtype: list[ifcopenshell.entity_instance] Example: @@ -902,18 +865,14 @@ def get_container( Retrieves the spatial structure container of an element. :param element: The IFC element - :type element: ifcopenshell.entity_instance :param should_get_direct: If True, a result is only returned if the element is directly contained in a spatial structure element. If False, an indirect spatial container may be returned, such as if an element is a part of an aggregate, and then if that aggregate is contained in a spatial structure element. - :type should_get_direct: bool :param ifc_class: Optionally filter the type of container you're after. For example, you may be after the storey, not a space. - :type ifc_class: str, optional :return: The direct or indirect container of the element or None. - :rtype: Union[ifcopenshell.entity_instance, None] Example: @@ -958,9 +917,7 @@ def get_referenced_structures(element: ifcopenshell.entity_instance) -> list[ifc as stairs, doors, etc. :param element: The IFC element - :type element: ifcopenshell.entity_instance :return: A list of IfcSpatialElement - :rtype: list[ifcopenshell.entity_instance] Example: @@ -976,9 +933,7 @@ def get_structure_referenced_elements(structure: ifcopenshell.entity_instance) - """Retreives a set of elements referenced by a structure :param structure: IfcSpatialElement - :type element: ifcopenshell.entity_instance :return: A set of referenced elements, IfcSpatialReferenceSelect - :rtype: set[ifcopenshell.entity_instance] Example: @@ -1000,9 +955,7 @@ def get_decomposition(element: ifcopenshell.entity_instance, is_recursive=True) parts of an aggreate, all openings, and all fills of any openings. :param element: The IFC element - :type element: ifcopenshell.entity_instance :return: The decomposition of the element - :rtype: list[ifcopenshell.entity_instance] Example: @@ -1044,9 +997,7 @@ def get_grouped_by(element: ifcopenshell.entity_instance) -> list[ifcopenshell.e """Retrieves all subelements of an element based on the group. :param element: IfcGroup entity - :type element: ifcopenshell.entity_instance :return: All subelements of the group - :rtype: list[ifcopenshell.entity_instance] Example: @@ -1072,7 +1023,6 @@ def get_groups(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entit :param element: The IFC element :return: List of IfcGroups element is assigned to. - :rtype: list[ifcopenshell.entity_instance] Example: @@ -1105,9 +1055,7 @@ def get_parent(element: ifcopenshell.entity_instance) -> Union[ifcopenshell.enti - Voiding: the opening voids another physical element, such as a hole in a wall :param element: Any physical or spatial element in the tree - :type element: ifcopenshell.entity_instance :return: Its parent. This must exist for any valid file, or None if we've reached the IfcProject. - :rtype: Union[ifcopenshell.entity_instance, None] Example: @@ -1131,9 +1079,7 @@ def get_filled_void(element: ifcopenshell.entity_instance) -> Union[ifcopenshell Examples include windows and doors which fill a opening inside a wall. :param element: The building element, typically a window or door - :type element: ifcopenshell.entity_instance :return: The IfcOpeningElement that it is filling - :rtype: Union[ifcopenshell.entity_instance, None] Example: @@ -1152,9 +1098,7 @@ def get_voided_element(element: ifcopenshell.entity_instance) -> Union[ifcopensh For all valid models, this should never return None. :param element: The IfcOpeningElement - :type element: ifcopenshell.entity_instance :return: The building element, such as a wall or slab - :rtype: Union[ifcopenshell.entity_instance, None] Example: @@ -1172,9 +1116,7 @@ def get_aggregate(element: ifcopenshell.entity_instance) -> Union[ifcopenshell.e Retrieves the aggregate parent of an element. :param element: The IFC element - :type element: ifcopenshell.entity_instance :return: The aggregate of the element - :rtype: Union[ifcopenshell.entity_instance, None] Example: @@ -1193,9 +1135,7 @@ def get_nest(element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity Retrieves the nest parent of an element. :param element: The IFC element - :type element: ifcopenshell.entity_instance :return: The nested whole of the element - :rtype: Union[ifcopenshell.entity_instance, None] Example: @@ -1217,9 +1157,7 @@ def get_parts(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entity Retrieves the parts of an element that have an aggregation relationship. :param element: The IFC element - :type element: ifcopenshell.entity_instance :return: The parts of the element - :rtype: list[ifcopenshell.entity_instance] Example: @@ -1239,9 +1177,7 @@ def get_contained(element: ifcopenshell.entity_instance) -> list[ifcopenshell.en Retrieves the contained elements of spatial element. :param element: The IFC element - :type element: ifcopenshell.entity_instance :return: The parts of the element - :rtype: list[ifcopenshell.entity_instance] Example: @@ -1263,9 +1199,7 @@ def get_components(element: ifcopenshell.entity_instance, include_ports=False) - :param element: The IFC element :param include_ports: Default as False. Set to true if you also want to get ports. - :type include_ports: bool,optional :return: The components of the element - :rtype: list[ifcopenshell.entity_instance] Example: @@ -1314,9 +1248,7 @@ def get_referenced_elements(reference: ifcopenshell.entity_instance) -> set[ifco """Get all elements with assigned `reference` :param reference: IfcExternalReference/IfcExternalInformation subtype reference - :type reference: ifcopenshell.entity_instance :return: The elements with assigned `reference` - :rtype: set[ifcopenshell.entity_instance] Example: @@ -1401,8 +1333,6 @@ def batch_remove_deep2(ifc_file: ifcopenshell.file) -> None: on existing variables in memory. :param ifc_file: The IFC file object - :type ifc_file: ifcopenshell.file - :rtype: None Example: @@ -1428,9 +1358,7 @@ def unbatch_remove_deep2(ifc_file: ifcopenshell.file) -> ifcopenshell.file: See documentation for batch_remove_deep2. :param ifc_file: The IFC file object - :type ifc_file: ifcopenshell.file :return: A newly loaded file with the elements removed. - :rtype: ifcopenshell.file """ ifc_string = ifc_file.to_string() lines = iter(ifc_string.split("\n")) @@ -1483,13 +1411,9 @@ def remove_deep2( subgraph but are protected from deletion. :param ifc_file: The IFC file object - :type ifc_file: ifcopenshell.file :param also_consider: elements to also consider as a part of a subgraph - :type also_consider: list[ifcopenshell.entity_instance], optional :param do_not_delete: elements to protect from deletion - :type do_not_delete: list[ifcopenshell.entity_instance], optional :param element: The starting element that defines the subgraph - :type element: ifcopenshell.entity_instance """ # ifc_file.batch() also_considered_inverses = 0 @@ -1554,11 +1478,8 @@ def copy(ifc_file: ifcopenshell.file, element: ifcopenshell.entity_instance) -> GlobalIds are regenerated. :param ifc_file: The IFC file object - :type ifc_file: ifcopenshell.file :param element: The IFC element to copy - :type element: ifcopenshell.entity_instance :return: The newly copied element - :rtype: ifcopenshell.entity_instance """ new = ifc_file.create_entity(element.is_a()) for i, attribute in enumerate(element): @@ -1584,22 +1505,16 @@ def copy_deep( GlobalIds are regenerated. :param ifc_file: The IFC file object - :type ifc_file: ifcopenshell.file :param element: The IFC element to copy - :type element: ifcopenshell.entity_instance :param exclude: An optional list of strings of IFC class names to not copy. If any of the subelement is this class, it will not be copied and the original instance will be referenced. - :type exclude: list[str],optional :param exclude_callback: A callback to determine whether or not to exclude an entity or not. Returns True to exclude and False to exclude. - :type exclude_callback: function,optional :param copied_entities: A dictionary of IDs as keys and entities as values to reuse when coming across the same entity twice. This can typically be left as None. - :type copied_entities: dict[int:ifcopenshell.entity_instance], optional :return: The newly copied element - :rtype: ifcopenshell.entity_instance """ if copied_entities is None: copied_entities = {} @@ -1653,11 +1568,8 @@ def has_property(product: ifcopenshell.entity_instance, property_name: str) -> b Check if a product has a property with a given name. :param product: The IFC product - :type product: ifcopenshell.entity_instance :param property_name: The property name - :type property_name: str :return: True if the product has the property, False otherwise - :rtype: bool Example: diff --git a/src/ifcpatch/ifcpatch/recipes/MergeProjects.py b/src/ifcpatch/ifcpatch/recipes/MergeProjects.py index 96e2d353f6..3dd993f144 100644 --- a/src/ifcpatch/ifcpatch/recipes/MergeProjects.py +++ b/src/ifcpatch/ifcpatch/recipes/MergeProjects.py @@ -27,7 +27,9 @@ from logging import Logger class Patcher: - def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, filepaths: Union[str, ifcopenshell.file]): + def __init__( + self, src: str, file: ifcopenshell.file, logger: Logger, filepaths: list[Union[str, ifcopenshell.file]] + ): """Merge two or more IFC models into one Note that other than combining the two (or more) IfcProject elements into @@ -40,7 +42,7 @@ class Patcher: :param filepaths: The filepath(s) of the second (, third, ...) IFC model to merge into the first. The first model is already specified as the input to IfcPatch. - :type filepaths: Union[str, ifcopenshell.file] + :type filepaths: list[Union[str, ifcopenshell.file]] :filter_glob filepaths: *.ifc;*.ifczip;*.ifcxml Example: @@ -60,10 +62,11 @@ class Patcher: other = filepath else: other = ifcopenshell.open(filepath) + assert isinstance(other, ifcopenshell.file) self.merge(other) - def merge(self, other): + def merge(self, other: ifcopenshell.file) -> None: if (main_unit := self.get_unit_name(self.file)) != self.get_unit_name(other): other = ifcopenshell.util.unit.convert_file_length_units(other, main_unit) @@ -128,7 +131,7 @@ class Patcher: length_unit = ifcopenshell.util.unit.get_project_unit(ifc_file, "LENGTHUNIT") return ifcopenshell.util.unit.get_full_unit_name(length_unit) - def reuse_existing_contexts(self): + def reuse_existing_contexts(self) -> None: to_delete = set() for added_context in self.added_contexts: