From 87265d052b5944c76d65aa126d2060b9412723e7 Mon Sep 17 00:00:00 2001 From: Andrej Date: Wed, 4 Jun 2025 19:49:35 +0500 Subject: [PATCH] typing --- src/bonsai/bonsai/bim/import_ifc.py | 4 +- .../bonsai/bim/module/constraint/operator.py | 88 +++++++++++++------ .../bonsai/bim/module/constraint/prop.py | 16 ++++ src/bonsai/bonsai/bim/module/constraint/ui.py | 39 ++++++-- .../bonsai/bim/module/layer/operator.py | 72 ++++++++++----- src/bonsai/bonsai/bim/module/layer/prop.py | 8 ++ src/bonsai/bonsai/bim/module/layer/ui.py | 22 ++++- src/bonsai/bonsai/tool/blender.py | 16 +++- src/bonsai/bonsai/tool/loader.py | 2 +- src/bonsai/bonsai/tool/sequence.py | 3 +- .../ifcopenshell/__init__.py | 4 +- .../ifcopenshell/ifcopenshell_wrapper.pyi | 18 ++-- src/ifcopenshell-python/ifcopenshell/sql.py | 4 +- .../ifcopenshell/util/constraint.py | 6 -- 14 files changed, 212 insertions(+), 90 deletions(-) diff --git a/src/bonsai/bonsai/bim/import_ifc.py b/src/bonsai/bonsai/bim/import_ifc.py index 8747f28891..1332258c12 100644 --- a/src/bonsai/bonsai/bim/import_ifc.py +++ b/src/bonsai/bonsai/bim/import_ifc.py @@ -1033,7 +1033,7 @@ class IfcImporter: element: ifcopenshell.entity_instance, shape: Union[ifcopenshell.geom.ShapeElementType, ifcopenshell.geom.ShapeType], ) -> bpy.types.Curve: - if hasattr(shape, "geometry"): + if isinstance(shape, ifcopenshell.geom.ShapeElementType): geometry = shape.geometry else: geometry = shape @@ -1066,7 +1066,7 @@ class IfcImporter: cartesian_point_offset: Union[npt.NDArray[np.float64], Literal[False]] = None, ) -> Union[bpy.types.Mesh, None]: try: - if hasattr(shape, "geometry"): + if isinstance(shape, ifcopenshell.geom.ShapeElementType): # shape is ShapeElementType geometry = shape.geometry else: diff --git a/src/bonsai/bonsai/bim/module/constraint/operator.py b/src/bonsai/bonsai/bim/module/constraint/operator.py index 4ae0dde395..5b291106f8 100644 --- a/src/bonsai/bonsai/bim/module/constraint/operator.py +++ b/src/bonsai/bonsai/bim/module/constraint/operator.py @@ -17,12 +17,27 @@ # along with Bonsai. If not, see . import bpy -import json import ifcopenshell.api import ifcopenshell.api.constraint -import ifcopenshell.util.attribute import bonsai.bim.helper import bonsai.tool as tool +from typing import TYPE_CHECKING + + +def get_active_object(context: bpy.types.Context, obj_name: str) -> bpy.types.Object: + if obj_name: + obj = bpy.data.objects[obj_name] + else: + assert (obj := context.active_object) + return obj + + +def get_selected_objects(context: bpy.types.Context, obj_name: str) -> list[bpy.types.Object]: + if obj_name: + objs = [bpy.data.objects[obj_name]] + else: + objs = context.selected_objects + return objs class LoadObjectives(bpy.types.Operator): @@ -31,7 +46,7 @@ class LoadObjectives(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - props = context.scene.BIMConstraintProperties + props = tool.Blender.get_constraint_props() props.constraints.clear() for constraint in tool.Ifc.get().by_type("IfcObjective"): new = props.constraints.add() @@ -48,7 +63,8 @@ class DisableConstraintEditingUI(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - context.scene.BIMConstraintProperties.is_editing = "" + props = tool.Blender.get_constraint_props() + props.is_editing = "" bpy.ops.bim.disable_editing_constraint() return {"FINISHED"} @@ -59,8 +75,11 @@ class EnableEditingConstraint(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} constraint: bpy.props.IntProperty() + if TYPE_CHECKING: + constraint: int + def execute(self, context): - props = context.scene.BIMConstraintProperties + props = tool.Blender.get_constraint_props() props.constraint_attributes.clear() bonsai.bim.helper.import_attributes2(tool.Ifc.get().by_id(self.constraint), props.constraint_attributes) props.active_constraint_id = self.constraint @@ -73,7 +92,8 @@ class DisableEditingConstraint(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - context.scene.BIMConstraintProperties.active_constraint_id = 0 + props = tool.Blender.get_constraint_props() + props.active_constraint_id = 0 return {"FINISHED"} @@ -83,7 +103,7 @@ class AddObjective(bpy.types.Operator, tool.Ifc.Operator): bl_options = {"REGISTER", "UNDO"} def _execute(self, context): - result = ifcopenshell.api.run("constraint.add_objective", tool.Ifc.get()) + result = ifcopenshell.api.constraint.add_objective(tool.Ifc.get()) bpy.ops.bim.load_objectives() bpy.ops.bim.enable_editing_constraint(constraint=result.id()) return {"FINISHED"} @@ -95,7 +115,7 @@ class EditObjective(bpy.types.Operator, tool.Ifc.Operator): bl_options = {"REGISTER", "UNDO"} def _execute(self, context): - props = context.scene.BIMConstraintProperties + props = tool.Blender.get_constraint_props() attributes = bonsai.bim.helper.export_attributes(props.constraint_attributes) ifc_file = tool.Ifc.get() ifcopenshell.api.constraint.edit_objective( @@ -113,12 +133,13 @@ class RemoveConstraint(bpy.types.Operator, tool.Ifc.Operator): bl_options = {"REGISTER", "UNDO"} constraint: bpy.props.IntProperty() + if TYPE_CHECKING: + constraint: int + def _execute(self, context): - props = context.scene.BIMConstraintProperties + props = tool.Blender.get_constraint_props() self.file = tool.Ifc.get() - ifcopenshell.api.run( - "constraint.remove_constraint", self.file, **{"constraint": self.file.by_id(self.constraint)} - ) + ifcopenshell.api.constraint.remove_constraint(self.file, constraint=self.file.by_id(self.constraint)) if props.is_editing == "IfcObjective": bpy.ops.bim.load_objectives() return {"FINISHED"} @@ -130,9 +151,12 @@ class EnableAssigningConstraint(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} obj: bpy.props.StringProperty() + if TYPE_CHECKING: + obj: str + def execute(self, context): - obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object - props = obj.BIMObjectConstraintProperties + obj = get_active_object(context, self.obj) + props = tool.Blender.get_object_constraint_props(obj) if props.available_constraint_types == "IfcObjective": bpy.ops.bim.load_objectives() props.is_adding = props.available_constraint_types @@ -145,9 +169,12 @@ class DisableAssigningConstraint(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} obj: bpy.props.StringProperty() + if TYPE_CHECKING: + obj: str + def execute(self, context): - obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object - props = obj.BIMObjectConstraintProperties + obj = get_active_object(context, self.obj) + props = tool.Blender.get_object_constraint_props(obj) props.is_adding = "" return {"FINISHED"} @@ -159,8 +186,13 @@ class AssignConstraint(bpy.types.Operator, tool.Ifc.Operator): obj: bpy.props.StringProperty() constraint: bpy.props.IntProperty() + if TYPE_CHECKING: + obj: str + constraint: int + def _execute(self, context): self.file = tool.Ifc.get() + objs = get_selected_objects(context, self.obj) objs = [bpy.data.objects[self.obj]] if self.obj else context.selected_objects products = [ self.file.by_id(obj_id) @@ -168,13 +200,10 @@ class AssignConstraint(bpy.types.Operator, tool.Ifc.Operator): if (obj_id := tool.Blender.get_object_bim_props(obj).ifc_definition_id) ] if products: - ifcopenshell.api.run( - "constraint.assign_constraint", + ifcopenshell.api.constraint.assign_constraint( self.file, - **{ - "products": products, - "constraint": self.file.by_id(self.constraint), - }, + products=products, + constraint=self.file.by_id(self.constraint), ) return {"FINISHED"} @@ -186,21 +215,22 @@ class UnassignConstraint(bpy.types.Operator, tool.Ifc.Operator): obj: bpy.props.StringProperty() constraint: bpy.props.IntProperty() + if TYPE_CHECKING: + obj: str + constraint: int + def _execute(self, context): self.file = tool.Ifc.get() - objs = [bpy.data.objects[self.obj]] if self.obj else context.selected_objects + objs = get_selected_objects(context, self.obj) products = [ self.file.by_id(obj_id) for obj in objs if (obj_id := tool.Blender.get_object_bim_props(obj).ifc_definition_id) ] if products: - ifcopenshell.api.run( - "constraint.unassign_constraint", + ifcopenshell.api.constraint.unassign_constraint( self.file, - **{ - "products": products, - "constraint": self.file.by_id(self.constraint), - }, + products=products, + constraint=self.file.by_id(self.constraint), ) return {"FINISHED"} diff --git a/src/bonsai/bonsai/bim/module/constraint/prop.py b/src/bonsai/bonsai/bim/module/constraint/prop.py index b773af506a..ec66f78211 100644 --- a/src/bonsai/bonsai/bim/module/constraint/prop.py +++ b/src/bonsai/bonsai/bim/module/constraint/prop.py @@ -32,6 +32,7 @@ from bpy.props import ( FloatVectorProperty, CollectionProperty, ) +from typing import TYPE_CHECKING, Literal def get_available_constraint_types(self, context): @@ -44,6 +45,10 @@ class Constraint(PropertyGroup): name: StringProperty(name="Name") ifc_definition_id: IntProperty(name="IFC Definition ID") + if TYPE_CHECKING: + name: str + ifc_definition_id: int + class BIMConstraintProperties(PropertyGroup): constraint_attributes: CollectionProperty(name="Constraint Attributes", type=Attribute) @@ -52,7 +57,18 @@ class BIMConstraintProperties(PropertyGroup): active_constraint_index: IntProperty(name="Active Constraint Index") is_editing: StringProperty(name="Is Editing") + if TYPE_CHECKING: + constraint_attributes: bpy.types.bpy_prop_collection_idprop[Attribute] + active_constraint_id: int + constraints: bpy.types.bpy_prop_collection_idprop[Constraint] + active_constraint_index: int + is_editing: str + class BIMObjectConstraintProperties(PropertyGroup): is_adding: StringProperty(name="Is Adding") available_constraint_types: EnumProperty(items=get_available_constraint_types, name="Available Constraint Types") + + if TYPE_CHECKING: + is_adding: str + available_constraint_types: Literal["IfcObjective"] diff --git a/src/bonsai/bonsai/bim/module/constraint/ui.py b/src/bonsai/bonsai/bim/module/constraint/ui.py index 3693e9565a..61b335d782 100644 --- a/src/bonsai/bonsai/bim/module/constraint/ui.py +++ b/src/bonsai/bonsai/bim/module/constraint/ui.py @@ -16,10 +16,15 @@ # You should have received a copy of the GNU General Public License # along with Bonsai. If not, see . +from __future__ import annotations import bonsai.tool as tool from bpy.types import Panel, UIList from bonsai.bim.helper import draw_attributes from bonsai.bim.module.constraint.data import ConstraintsData, ObjectConstraintsData +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from bonsai.bim.module.constraint.prop import BIMConstraintProperties, BIMObjectConstraintProperties, Constraint class BIM_PT_constraints(Panel): @@ -39,7 +44,7 @@ class BIM_PT_constraints(Panel): if not ConstraintsData.is_loaded: ConstraintsData.load() - self.props = context.scene.BIMConstraintProperties + self.props = tool.Blender.get_constraint_props() if not self.props.is_editing or self.props.is_editing == "IfcObjective": row = self.layout.row(align=True) @@ -91,8 +96,8 @@ class BIM_PT_object_constraints(Panel): obj = context.active_object assert obj self.oprops = tool.Blender.get_object_bim_props(obj) - self.sprops = context.scene.BIMConstraintProperties - self.props = obj.BIMObjectConstraintProperties + self.sprops = tool.Blender.get_constraint_props() + self.props = tool.Blender.get_object_constraint_props(obj) self.file = tool.Ifc.get() self.draw_add_ui() @@ -131,15 +136,24 @@ class BIM_PT_object_constraints(Panel): class BIM_UL_constraints(UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + def draw_item( + self, + context, + layout, + data: BIMConstraintProperties, + item: Constraint, + icon, + active_data, + active_propname, + ): if item: row = layout.row(align=True) row.label(text=item.name) - if context.scene.BIMConstraintProperties.active_constraint_id == item.ifc_definition_id: - if context.scene.BIMConstraintProperties.is_editing == "IfcObjective": + if data.active_constraint_id == item.ifc_definition_id: + if data.is_editing == "IfcObjective": row.operator("bim.edit_objective", text="", icon="CHECKMARK") row.operator("bim.disable_editing_constraint", text="", icon="CANCEL") - elif context.scene.BIMConstraintProperties.active_constraint_id: + elif data.active_constraint_id: row.operator("bim.remove_constraint", text="", icon="X").constraint = item.ifc_definition_id else: op = row.operator("bim.enable_editing_constraint", text="", icon="GREASEPENCIL") @@ -148,7 +162,16 @@ class BIM_UL_constraints(UIList): class BIM_UL_object_constraints(UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + def draw_item( + self, + context, + layout, + data: BIMObjectConstraintProperties, + item: Constraint, + icon, + active_data, + active_propname, + ): if item: row = layout.row(align=True) row.label(text=item.name) diff --git a/src/bonsai/bonsai/bim/module/layer/operator.py b/src/bonsai/bonsai/bim/module/layer/operator.py index 5480c86034..079c5477f6 100644 --- a/src/bonsai/bonsai/bim/module/layer/operator.py +++ b/src/bonsai/bonsai/bim/module/layer/operator.py @@ -17,13 +17,21 @@ # along with Bonsai. If not, see . import bpy -import json import ifcopenshell.api import ifcopenshell.api.layer import ifcopenshell.util.element -import ifcopenshell.util.attribute import bonsai.bim.helper import bonsai.tool as tool +from typing import TYPE_CHECKING + + +def get_active_mesh(context: bpy.types.Context, mesh_name: str) -> bpy.types.Mesh: + if mesh_name: + item_mesh = bpy.data.meshes[mesh_name] + else: + assert (obj := context.active_object) + assert isinstance(item_mesh := obj.data, bpy.types.Mesh) + return item_mesh class LoadLayers(bpy.types.Operator): @@ -32,10 +40,10 @@ class LoadLayers(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - self.file = tool.Ifc.get() - props = context.scene.BIMLayerProperties + ifc_file = tool.Ifc.get() + props = tool.Layer.get_layer_props() props.layers.clear() - for layer in tool.Ifc.get().by_type("IfcPresentationLayerAssignment"): + for layer in ifc_file.by_type("IfcPresentationLayerAssignment"): new = props.layers.add() new.name = layer.Name or "Unnamed" new.ifc_definition_id = layer.id() @@ -57,7 +65,8 @@ class DisableLayerEditingUI(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - context.scene.BIMLayerProperties.is_editing = False + props = tool.Layer.get_layer_props() + props.is_editing = False return {"FINISHED"} @@ -67,8 +76,11 @@ class EnableEditingLayer(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} layer: bpy.props.IntProperty() + if TYPE_CHECKING: + layer: int + def execute(self, context): - props = context.scene.BIMLayerProperties + props = tool.Layer.get_layer_props() props.layer_attributes.clear() bonsai.bim.helper.import_attributes2(tool.Ifc.get().by_id(self.layer), props.layer_attributes) props.active_layer_id = self.layer @@ -81,7 +93,8 @@ class DisableEditingLayer(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def execute(self, context): - context.scene.BIMLayerProperties.active_layer_id = 0 + props = tool.Layer.get_layer_props() + props.active_layer_id = 0 return {"FINISHED"} @@ -92,7 +105,7 @@ class AddPresentationLayer(bpy.types.Operator, tool.Ifc.Operator): bl_options = {"REGISTER", "UNDO"} def _execute(self, context): - props = context.scene.BIMLayerProperties + props = tool.Layer.get_layer_props() ifc_file = tool.Ifc.get() if props.layer_type == "IfcPresentationLayerWithStyle": layer = ifcopenshell.api.layer.add_layer_with_style(ifc_file) @@ -109,7 +122,7 @@ class EditPresentationLayer(bpy.types.Operator, tool.Ifc.Operator): bl_options = {"REGISTER", "UNDO"} def _execute(self, context): - props = context.scene.BIMLayerProperties + props = tool.Layer.get_layer_props() attributes = bonsai.bim.helper.export_attributes(props.layer_attributes) ifc_file = tool.Ifc.get() ifcopenshell.api.layer.edit_layer(ifc_file, layer=ifc_file.by_id(props.active_layer_id), attributes=attributes) @@ -123,10 +136,12 @@ class RemovePresentationLayer(bpy.types.Operator, tool.Ifc.Operator): bl_options = {"REGISTER", "UNDO"} layer: bpy.props.IntProperty() + if TYPE_CHECKING: + layer: int + def _execute(self, context): - props = context.scene.BIMLayerProperties - self.file = tool.Ifc.get() - ifcopenshell.api.run("layer.remove_layer", self.file, **{"layer": self.file.by_id(self.layer)}) + ifc_file = tool.Ifc.get() + ifcopenshell.api.layer.remove_layer(ifc_file, layer=ifc_file.by_id(self.layer)) bpy.ops.bim.load_layers() return {"FINISHED"} @@ -139,16 +154,17 @@ class AssignPresentationLayer(bpy.types.Operator, tool.Ifc.Operator): item: bpy.props.StringProperty() layer: bpy.props.IntProperty() + if TYPE_CHECKING: + item: str + layer: int + def _execute(self, context): - item = bpy.data.meshes.get(self.item) if self.item else context.active_object.data - self.file = tool.Ifc.get() - ifcopenshell.api.run( - "layer.assign_layer", - self.file, - **{ - "items": [self.file.by_id(tool.Geometry.get_mesh_props(item).ifc_definition_id)], - "layer": self.file.by_id(self.layer), - }, + item = get_active_mesh(context, self.item) + ifc_file = tool.Ifc.get() + ifcopenshell.api.layer.assign_layer( + ifc_file, + items=[ifc_file.by_id(tool.Geometry.get_mesh_props(item).ifc_definition_id)], + layer=ifc_file.by_id(self.layer), ) return {"FINISHED"} @@ -161,8 +177,12 @@ class UnassignPresentationLayer(bpy.types.Operator, tool.Ifc.Operator): item: bpy.props.StringProperty() layer: bpy.props.IntProperty() + if TYPE_CHECKING: + item: str + layer: int + def _execute(self, context): - item = bpy.data.meshes.get(self.item) if self.item else context.active_object.data + item = get_active_mesh(context, self.item) ifc_file = tool.Ifc.get() representation = tool.Geometry.get_data_representation(item) assert representation @@ -176,6 +196,9 @@ class SelectLayerProducts(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} layer: bpy.props.IntProperty() + if TYPE_CHECKING: + layer: int + def execute(self, context): elements = ifcopenshell.util.element.get_elements_by_layer(tool.Ifc.get(), tool.Ifc.get().by_id(self.layer)) for obj in context.visible_objects: @@ -192,6 +215,9 @@ class SelectLayerInLayerUI(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} layer_id: bpy.props.IntProperty() + if TYPE_CHECKING: + layer_id: int + def execute(self, context): props = tool.Layer.get_layer_props() ifc_file = tool.Ifc.get() diff --git a/src/bonsai/bonsai/bim/module/layer/prop.py b/src/bonsai/bonsai/bim/module/layer/prop.py index 6f0dbd7c9c..079ba262de 100644 --- a/src/bonsai/bonsai/bim/module/layer/prop.py +++ b/src/bonsai/bonsai/bim/module/layer/prop.py @@ -59,6 +59,14 @@ class Layer(PropertyGroup): update=lambda self, context: update_layer_property(self, context, property="blocked"), ) + if TYPE_CHECKING: + name: str + ifc_definition_id: int + with_style: bool + on: bool + frozen: bool + blocked: bool + class BIMLayerProperties(PropertyGroup): layer_attributes: CollectionProperty(name="Layer Attributes", type=Attribute) diff --git a/src/bonsai/bonsai/bim/module/layer/ui.py b/src/bonsai/bonsai/bim/module/layer/ui.py index 609cb62815..d7fcdec215 100644 --- a/src/bonsai/bonsai/bim/module/layer/ui.py +++ b/src/bonsai/bonsai/bim/module/layer/ui.py @@ -16,11 +16,16 @@ # You should have received a copy of the GNU General Public License # along with Bonsai. If not, see . +from __future__ import annotations import bpy import bonsai.tool as tool from bpy.types import Panel, UIList, Mesh from bonsai.bim.helper import draw_attributes from bonsai.bim.module.layer.data import LayersData +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from bonsai.bim.module.layer.prop import BIMLayerProperties, Layer class BIM_PT_layers(Panel): @@ -40,7 +45,7 @@ class BIM_PT_layers(Panel): if not LayersData.is_loaded: LayersData.load() - self.props = context.scene.BIMLayerProperties + self.props = tool.Layer.get_layer_props() row = self.layout.row(align=True) row.label(text=f"{LayersData.data['total_layers']} Layers Found", icon="STICKY_UVS_LOC") @@ -71,7 +76,16 @@ class BIM_PT_layers(Panel): class BIM_UL_layers(UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + def draw_item( + self, + context: bpy.types.Context, + layout: bpy.types.UILayout, + data: BIMLayerProperties, + item: Layer, + icon, + active_data, + active_propname, + ): if item: row = layout.row(align=True) row.label(text=item.name) @@ -89,12 +103,12 @@ class BIM_UL_layers(UIList): row.prop(item, "frozen", text="", icon="FREEZE" if item.frozen else "MESH_PLANE", emboss=False) row.prop(item, "blocked", text="", icon="LOCKED" if item.blocked else "UNLOCKED", emboss=False) - if context.scene.BIMLayerProperties.active_layer_id == item.ifc_definition_id: + if data.active_layer_id == item.ifc_definition_id: op = row.operator("bim.select_layer_products", text="", icon="RESTRICT_SELECT_OFF") op.layer = item.ifc_definition_id row.operator("bim.edit_presentation_layer", text="", icon="CHECKMARK") row.operator("bim.disable_editing_layer", text="", icon="CANCEL") - elif context.scene.BIMLayerProperties.active_layer_id: + elif data.active_layer_id: op = row.operator("bim.select_layer_products", text="", icon="RESTRICT_SELECT_OFF") op.layer = item.ifc_definition_id row.operator("bim.remove_presentation_layer", text="", icon="X").layer = item.ifc_definition_id diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index 7ad78d2339..c02a9ce1d8 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -50,6 +50,7 @@ if TYPE_CHECKING: from bonsai.bim.prop import BIMProperties, BIMObjectProperties from bonsai.bim.module.attribute.prop import BIMAttributeProperties from bonsai.bim.module.csv.prop import CsvProperties + from bonsai.bim.module.constraint.prop import BIMConstraintProperties, BIMObjectConstraintProperties from bonsai.bim.module.diff.prop import DiffProperties T = TypeVar("T") @@ -1644,13 +1645,24 @@ class Blender(bonsai.core.tool.Blender): dct = {cls.bl_idname: cls.ifc_element_type for cls in (BimTool.__subclasses__())} return types.MappingProxyType(dct) + @classmethod + def get_object_constraint_props(cls, obj: bpy.types.Object) -> BIMObjectConstraintProperties: + return obj.BIMObjectConstraintProperties + + @classmethod + def get_constraint_props(cls) -> BIMConstraintProperties: + assert (scene := bpy.context.scene) + return scene.BIMConstraintProperties + @classmethod def get_csv_props(cls) -> CsvProperties: - return bpy.context.scene.CsvProperties + assert (scene := bpy.context.scene) + return scene.CsvProperties @classmethod def get_diff_props(cls) -> DiffProperties: - return bpy.context.scene.DiffProperties + assert (scene := bpy.context.scene) + return scene.DiffProperties @classmethod def get_bim_props(cls, scene: Optional[bpy.types.Scene] = None) -> BIMProperties: diff --git a/src/bonsai/bonsai/tool/loader.py b/src/bonsai/bonsai/tool/loader.py index 6f58bbc665..05dbe0b594 100644 --- a/src/bonsai/bonsai/tool/loader.py +++ b/src/bonsai/bonsai/tool/loader.py @@ -101,7 +101,7 @@ class Loader(bonsai.core.tool.Loader): shape: Union[ifcopenshell.geom.ShapeElementType, ifcopenshell.geom.ShapeType], mesh: tool.Geometry.TYPES_WITH_MESH_PROPERTIES, ) -> None: - geometry = shape.geometry if hasattr(shape, "geometry") else shape + geometry = shape.geometry if isinstance(shape, ifcopenshell.geom.ShapeElementType) else shape tool.Geometry.get_mesh_props(mesh).ifc_definition_id = int(geometry.id.split("-")[0]) @classmethod diff --git a/src/bonsai/bonsai/tool/sequence.py b/src/bonsai/bonsai/tool/sequence.py index f89afe3fec..eb8dd03277 100644 --- a/src/bonsai/bonsai/tool/sequence.py +++ b/src/bonsai/bonsai/tool/sequence.py @@ -39,6 +39,7 @@ from dateutil import parser from datetime import datetime from datetime import time as datetime_time from typing import Optional, Any, Union, Literal, TYPE_CHECKING, Iterable +from mathutils import Color if TYPE_CHECKING: import bonsai.bim.prop @@ -1449,7 +1450,7 @@ class Sequence(bonsai.core.tool.Sequence): obj.keyframe_insert(data_path="color", frame=product_frame["COMPLETED"]) @classmethod - def animate_operation(cls, obj, start_frame, product_frame, color): + def animate_operation(cls, obj: bpy.types.Object, start_frame: int, product_frame, color: Color) -> None: if cls.earliest_frame is None or product_frame["STARTED"] < cls.earliest_frame: obj.color = (1.0, 1.0, 1.0, 1) obj.keyframe_insert(data_path="color", frame=start_frame) diff --git a/src/ifcopenshell-python/ifcopenshell/__init__.py b/src/ifcopenshell-python/ifcopenshell/__init__.py index 0942269ceb..97083d0938 100644 --- a/src/ifcopenshell-python/ifcopenshell/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/__init__.py @@ -260,7 +260,7 @@ def schema_by_name( return ifcopenshell_wrapper.schema_by_name(schema) -def guess_format(path: Path) -> Union[str, None]: +def guess_format(path: Path) -> Literal[".ifc", ".ifcZIP", ".ifcXML", ".ifcJSON", ".ifcSQLite", None]: """Guesses the IFC format using file extension IFCs may be serialised as different formats. The most common is a ``.ifc`` @@ -273,8 +273,6 @@ def guess_format(path: Path) -> Union[str, None]: Users generally won't call this function. The :func:`open` function uses this internally to guess the file format. - - :return: Either .ifc, .ifcZIP, .ifcXML, .ifcJSON, .ifcSQLite, or None. """ suffix = path.suffix.lower() if suffix == ".ifc": diff --git a/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi b/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi index 9f8db92bc6..5e631804ae 100644 --- a/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi +++ b/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi @@ -127,7 +127,7 @@ class BRep(Representation): class BRepElement(Element): def calculate_projected_surface_area(self, along_x, along_y, along_z): ... @property - def geometry(self): ... + def geometry(self) -> BRep: ... def geometry_pointer(self): ... @property def surface_area(self): ... @@ -361,7 +361,7 @@ class Serialization(Representation): class SerializedElement(Element): @property - def geometry(self): ... + def geometry(self) -> Serialization: ... class SerializerSettings: def get_(self, name): ... @@ -744,7 +744,7 @@ class ellipse(curve): def matrix(self): ... class entity(declaration): - def all_attributes(self): ... + def all_attributes(self) -> tuple[attribute, ...]: ... def all_inverse_attributes(self): ... def argument_types(self): ... def as_entity(self): ... @@ -1127,10 +1127,10 @@ class revolve(sweep): class schema_definition: def declaration_by_name(self, *args: str) -> declaration: ... def declarations(self) -> tuple[declaration, ...]: ... - def entities(self): ... + def entities(self) -> tuple[entity, ...]: ... def enumeration_types(self): ... def instantiate(self, decl, data): ... - def name(self): ... + def name(self) -> str: ... def select_types(self): ... def type_declarations(self): ... @@ -1446,7 +1446,7 @@ def polygons_to_svg(*args): ... def read(data): ... def register_schema(arg1): ... def schema_by_name(arg1: str) -> schema_definition: ... -def schema_names(): ... +def schema_names() -> tuple[str, ...]: ... def serialise(schema_name, shape_str, advanced): ... def set_feature(x, v): ... def set_log_format_json(): ... @@ -1455,6 +1455,6 @@ def svg_to_line_segments(data, class_name): ... def svg_to_polygons(data, class_name): ... def taxonomy_item_repr(i): ... def tesselate(schema_name, shape_str, d): ... -def turn_off_detailed_logging(): ... -def turn_on_detailed_logging(): ... -def version(): ... +def turn_off_detailed_logging() -> None: ... +def turn_on_detailed_logging() -> None: ... +def version() -> str: ... diff --git a/src/ifcopenshell-python/ifcopenshell/sql.py b/src/ifcopenshell-python/ifcopenshell/sql.py index a77b5a85af..fc7f7f8fa9 100644 --- a/src/ifcopenshell-python/ifcopenshell/sql.py +++ b/src/ifcopenshell-python/ifcopenshell/sql.py @@ -96,9 +96,9 @@ class sqlite(file): self.preprocess_schema() def preprocess_schema(self) -> None: - self.ifc_class_subtypes = {} + self.ifc_class_subtypes: dict[str, Any] = {} self.ifc_class_attributes: dict[str, dict[str, ifcopenshell_wrapper.attribute]] = {} - self.ifc_class_inverse_attributes = {} + self.ifc_class_inverse_attributes: dict[str, Any] = {} self.ifc_class_references = {} self.ifc_class_inverses = {} diff --git a/src/ifcopenshell-python/ifcopenshell/util/constraint.py b/src/ifcopenshell-python/ifcopenshell/util/constraint.py index f4e18d61b3..2c370aa997 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/constraint.py +++ b/src/ifcopenshell-python/ifcopenshell/util/constraint.py @@ -27,9 +27,7 @@ def get_constraints(product: ifcopenshell.entity_instance) -> list[ifcopenshell. Retrieves the constraints assigned to the `product`. :param product: The IFC element. - :type product: ifcopenshell.entity_instance :return: List of assigned constraints. - :rtype: list[ifcopenshell.entity_instance] """ constraints = [] for rel in product.HasAssociations or []: @@ -43,9 +41,7 @@ def get_constrained_elements(constraint: ifcopenshell.entity_instance) -> set[if Retrieves the elements constrained by a `constraint`. :param product: The IFC element. - :type product: ifcopenshell.entity_instance :return: Set of elements constrained by a `constrant`. - :rtype: set[ifcopenshell.entity_instance] """ elements = set() for rel in constraint.file.get_inverse(constraint): @@ -59,9 +55,7 @@ def get_metrics(constraint: ifcopenshell.entity_instance) -> list[ifcopenshell.e Retrieves the list of nested constraints for a IfcObjective `constraint`. :param product: IfcObjective constraint. - :type product: ifcopenshell.entity_instance :return: List of nested constraints. - :rtype: list[ifcopenshell.entity_instance] """ metrics = []