diff --git a/src/blenderbim/blenderbim/bim/handler.py b/src/blenderbim/blenderbim/bim/handler.py index 28306671de..9ebe90c5e7 100644 --- a/src/blenderbim/blenderbim/bim/handler.py +++ b/src/blenderbim/blenderbim/bim/handler.py @@ -223,7 +223,7 @@ def redo_post(scene): tool.Ifc.rebuild_element_maps() -def get_application(ifc): +def get_application(ifc: ifcopenshell.file) -> ifcopenshell.entity_instance: # TODO: cache this for even faster application retrieval. It honestly makes a difference on long scripts. version = get_application_version() for element in ifc.by_type("IfcApplication"): @@ -238,7 +238,7 @@ def get_application(ifc): ) -def get_application_version(): +def get_application_version() -> str: return ".".join( [ str(x) diff --git a/src/blenderbim/blenderbim/tool/owner.py b/src/blenderbim/blenderbim/tool/owner.py index bd5f068adc..b805112689 100644 --- a/src/blenderbim/blenderbim/tool/owner.py +++ b/src/blenderbim/blenderbim/tool/owner.py @@ -19,6 +19,8 @@ import bpy import blenderbim.core.tool import blenderbim.tool as tool +import ifcopenshell +from typing import Union class Owner(blenderbim.core.tool.Owner): @@ -27,7 +29,7 @@ class Owner(blenderbim.core.tool.Owner): bpy.context.scene.BIMOwnerProperties.active_user_id = user.id() @classmethod - def get_user(cls): + def get_user(cls) -> Union[ifcopenshell.entity_instance, None]: if bpy.context.scene.BIMOwnerProperties.active_user_id: return tool.Ifc.get().by_id(bpy.context.scene.BIMOwnerProperties.active_user_id) elif tool.Ifc.get_schema() == "IFC2X3": diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/edit_object_placement.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/edit_object_placement.py index 0e71411464..23b07f0c03 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/edit_object_placement.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/edit_object_placement.py @@ -17,20 +17,34 @@ # along with IfcOpenShell. If not, see . import numpy as np +import numpy.typing as npt import ifcopenshell.api import ifcopenshell.util.unit import ifcopenshell.util.element import ifcopenshell.util.placement +from typing import Optional, Union + +NPArrayOfFloats = npt.NDArray[np.float64] class Usecase: - def __init__(self, file, **settings): + def __init__( + self, + file: ifcopenshell.file, + product: ifcopenshell.entity_instance, + matrix: Optional[NPArrayOfFloats] = None, + is_si=True, + should_transform_children=False, + ): self.file = file - self.settings = {"product": None, "matrix": np.eye(4), "is_si": True, "should_transform_children": False} - for key, value in settings.items(): - self.settings[key] = value + self.settings = { + "product": product, + "matrix": matrix if matrix is not None else np.eye(4), + "is_si": is_si, + "should_transform_children": should_transform_children, + } - def execute(self): + def execute(self) -> ifcopenshell.entity_instance: if not hasattr(self.settings["product"], "ObjectPlacement"): return self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file) @@ -69,12 +83,12 @@ class Usecase: return new_placement - def convert_matrix_to_si(self, matrix): + def convert_matrix_to_si(self, matrix: NPArrayOfFloats): matrix[0][3] *= self.unit_scale matrix[1][3] *= self.unit_scale matrix[2][3] *= self.unit_scale - def get_placement_rel_to(self): + def get_placement_rel_to(self) -> Union[ifcopenshell.entity_instance, None]: if getattr(self.settings["product"], "Decomposes", None): relating_object = self.settings["product"].Decomposes[0].RelatingObject return relating_object.ObjectPlacement if hasattr(relating_object, "ObjectPlacement") else None @@ -96,7 +110,7 @@ class Usecase: elif getattr(self.settings["product"], "ContainedInStructure", None): return self.settings["product"].ContainedInStructure[0].RelatingStructure.ObjectPlacement - def get_children_settings(self, placement): + def get_children_settings(self, placement: Union[ifcopenshell.entity_instance, None]) -> list[dict]: if not placement: return [] results = [] @@ -116,7 +130,9 @@ class Usecase: results.append({"product": obj, "matrix": matrix, "is_si": False, "should_transform_children": True}) return results - def get_relative_placement(self, placement_rel_to): + def get_relative_placement( + self, placement_rel_to: Union[ifcopenshell.entity_instance, None] + ) -> ifcopenshell.entity_instance: if placement_rel_to: relating_object_matrix = ifcopenshell.util.placement.get_local_placement(placement_rel_to) relating_object_matrix[0][3] = self.convert_unit_to_si(relating_object_matrix[0][3]) @@ -136,19 +152,21 @@ class Usecase: relative_placement_matrix[:, 0][0:3], ) - def create_ifc_axis_2_placement_3d(self, point, up, forward): + def create_ifc_axis_2_placement_3d( + self, point: NPArrayOfFloats, up: NPArrayOfFloats, forward: NPArrayOfFloats + ) -> ifcopenshell.entity_instance: return self.file.createIfcAxis2Placement3D( self.create_cartesian_point(point), self.file.createIfcDirection(up.tolist()), self.file.createIfcDirection(forward.tolist()), ) - def create_cartesian_point(self, co): + def create_cartesian_point(self, co: NPArrayOfFloats) -> ifcopenshell.entity_instance: co = self.convert_si_to_unit(co) return self.file.createIfcCartesianPoint(co.tolist()) - def convert_si_to_unit(self, co): + def convert_si_to_unit(self, co: NPArrayOfFloats) -> NPArrayOfFloats: return co / self.unit_scale - def convert_unit_to_si(self, co): + def convert_unit_to_si(self, co: NPArrayOfFloats) -> NPArrayOfFloats: return co * self.unit_scale diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_organisation.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_organisation.py index db4121d9cb..0e6f676fbc 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_organisation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_organisation.py @@ -15,10 +15,11 @@ # # You should have received a copy of the GNU Lesser General Public License # along with IfcOpenShell. If not, see . +import ifcopenshell class Usecase: - def __init__(self, file, identification="APTR", name="Aperture Science"): + def __init__(self, file: ifcopenshell.file, identification: str = "APTR", name: str = "Aperture Science"): """Adds a new organisation Organisations are the main way to identify manufacturers, suppliers, and @@ -45,7 +46,7 @@ class Usecase: self.file = file self.settings = {"identification": identification, "name": name} - def execute(self): + def execute(self) -> ifcopenshell.entity_instance: data = {"Name": self.settings["name"]} if self.file.schema == "IFC2X3": data["Id"] = self.settings["identification"] diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_person.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_person.py index 308d771e21..268568c80d 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_person.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_person.py @@ -15,10 +15,17 @@ # # You should have received a copy of the GNU Lesser General Public License # along with IfcOpenShell. If not, see . +import ifcopenshell class Usecase: - def __init__(self, file, identification="HSeldon", family_name="Seldon", given_name="Hari"): + def __init__( + self, + file: ifcopenshell.entity_instance, + identification: str = "HSeldon", + family_name: str = "Seldon", + given_name: str = "Hari", + ): """Adds a new person Persons are used to identify a legal or liable representative of an @@ -48,7 +55,7 @@ class Usecase: "given_name": given_name, } - def execute(self): + def execute(self) ->ifcopenshell.entity_instance: data = {"FamilyName": self.settings["family_name"], "GivenName": self.settings["given_name"]} if self.file.schema == "IFC2X3": data["Id"] = self.settings["identification"] diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_person_and_organisation.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_person_and_organisation.py index 05c137b516..3e0b372690 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_person_and_organisation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_person_and_organisation.py @@ -15,10 +15,16 @@ # # You should have received a copy of the GNU Lesser General Public License # along with IfcOpenShell. If not, see . +import ifcopenshell class Usecase: - def __init__(self, file, person=None, organisation=None): + def __init__( + self, + file: ifcopenshell.entity_instance, + person: ifcopenshell.entity_instance, + organisation: ifcopenshell.entity_instance, + ): """Adds a paired person and organisation A person and an organisation may be paired to create a representative @@ -47,5 +53,5 @@ class Usecase: self.file = file self.settings = {"person": person, "organisation": organisation} - def execute(self): + def execute(self) -> ifcopenshell.entity_instance: return self.file.createIfcPersonAndOrganization(self.settings["person"], self.settings["organisation"]) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/create_owner_history.py b/src/ifcopenshell-python/ifcopenshell/api/owner/create_owner_history.py index 4ae66cb45e..31491feeaa 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/create_owner_history.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/create_owner_history.py @@ -19,10 +19,11 @@ import time import ifcopenshell import ifcopenshell.api.owner.settings +from typing import Union class Usecase: - def __init__(self, file): + def __init__(self, file: ifcopenshell.entity_instance): """Creates a new owner history indicating an element was added Any object in IFC with a unique ID and name (such as physical products, @@ -59,8 +60,9 @@ class Usecase: are writing your own advanced scripts and want to take advantage of the easier ownership tracking. - :return: The newly created IfcOwnerHistory element. - :rtype: ifcopenshell.entity_instance.entity_instance + :return: The newly created IfcOwnerHistory element or `None` if it's + not IFC2X3 and user or application is not found in the current project. + :rtype: Union[ifcopenshell.entity_instance.entity_instance, None] Example: @@ -99,7 +101,7 @@ class Usecase: self.file = file self.settings = {} - def execute(self): + def execute(self) -> Union[ifcopenshell.entity_instance, None]: user = ifcopenshell.api.owner.settings.get_user(self.file) if self.file.schema != "IFC2X3" and not user: return diff --git a/src/ifcopenshell-python/ifcopenshell/api/void/add_opening.py b/src/ifcopenshell-python/ifcopenshell/api/void/add_opening.py index de479a1d39..3a260a08f7 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/void/add_opening.py +++ b/src/ifcopenshell-python/ifcopenshell/api/void/add_opening.py @@ -23,7 +23,9 @@ import ifcopenshell.util.placement class Usecase: - def __init__(self, file, opening=None, element=None): + def __init__( + self, file: ifcopenshell.file, opening: ifcopenshell.entity_instance, element: ifcopenshell.entity_instance + ): """Create an opening in an element It is often necessary to cut out openings in elements like walls and @@ -103,18 +105,18 @@ class Usecase: self.file = file self.settings = {"opening": opening, "element": element} - def execute(self): + def execute(self) -> ifcopenshell.entity_instance: voids_elements = self.settings["opening"].VoidsElements if voids_elements: if voids_elements[0].RelatingBuildingElement == self.settings["element"]: - return + return voids_elements[0] history = voids_elements[0].OwnerHistory self.file.remove(voids_elements[0]) if history: ifcopenshell.util.element.remove_deep2(self.file, history) - self.file.create_entity( + rel = self.file.create_entity( "IfcRelVoidsElement", **{ "GlobalId": ifcopenshell.guid.new(), @@ -133,3 +135,5 @@ class Usecase: matrix=ifcopenshell.util.placement.get_local_placement(self.settings["opening"].ObjectPlacement), is_si=False, ) + + return rel diff --git a/src/ifcopenshell-python/ifcopenshell/api/void/remove_opening.py b/src/ifcopenshell-python/ifcopenshell/api/void/remove_opening.py index 6ed1079b41..3735d2e735 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/void/remove_opening.py +++ b/src/ifcopenshell-python/ifcopenshell/api/void/remove_opening.py @@ -17,10 +17,11 @@ # along with IfcOpenShell. If not, see . import ifcopenshell.api +import ifcopenshell.util.element class Usecase: - def __init__(self, file, opening=None): + def __init__(self, file: ifcopenshell.entity_instance, opening: ifcopenshell.entity_instance): """Remove an opening Fillings are retained as orphans. Voided elements remain. Openings @@ -47,7 +48,7 @@ class Usecase: self.file = file self.settings = {"opening": opening} - def execute(self): + def execute(self) -> None: for rel in self.settings["opening"].VoidsElements: history = rel.OwnerHistory self.file.remove(rel) diff --git a/src/ifcopenshell-python/ifcopenshell/entity_instance.py b/src/ifcopenshell-python/ifcopenshell/entity_instance.py index c6802aa4a3..6fba487e6c 100644 --- a/src/ifcopenshell-python/ifcopenshell/entity_instance.py +++ b/src/ifcopenshell-python/ifcopenshell/entity_instance.py @@ -67,8 +67,9 @@ def set_unsupported_attribute(*args): _method_dict = {} -def register_schema_attributes(schema): +def register_schema_attributes(schema: ifcopenshell_wrapper.schema_definition) -> None: for decl in schema.declarations(): + decl: ifcopenshell_wrapper.declaration if hasattr(decl, "argument_types"): fq_name = ".".join((schema.name(), decl.name()))