From 05cb06a28ef81fba46d25fd758072a562d516d62 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Thu, 10 Jul 2025 11:30:46 +0500 Subject: [PATCH] typing --- .../bonsai/bim/module/material/operator.py | 10 ++++++++-- .../bonsai/bim/module/structural/operator.py | 6 +++++- src/bonsai/bonsai/tool/context.py | 8 +++++--- src/bonsai/bonsai/tool/cost.py | 19 +++++++++++-------- src/bonsai/bonsai/tool/owner.py | 2 +- .../ifcopenshell/api/cogo/add_survey_point.py | 4 ++-- 6 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/material/operator.py b/src/bonsai/bonsai/bim/module/material/operator.py index 462f6f5911..5053e3a177 100644 --- a/src/bonsai/bonsai/bim/module/material/operator.py +++ b/src/bonsai/bonsai/bim/module/material/operator.py @@ -28,9 +28,12 @@ import bonsai.bim.helper import bonsai.tool as tool import bonsai.core.material as core import bonsai.bim.module.model.profile as model_profile -from typing import Any, Union, TYPE_CHECKING +from typing import Any, Union, TYPE_CHECKING, Literal from bonsai.bim.module.model import wall, slab +if TYPE_CHECKING: + from bonsai.bim.prop import Attribute + class LoadMaterials(bpy.types.Operator): bl_idname = "bim.load_materials" @@ -508,7 +511,9 @@ class EnableEditingAssignedMaterial(bpy.types.Operator): bonsai.bim.helper.import_attributes2(material, props.material_set_attributes) return {"FINISHED"} - def import_attributes(self, name, prop, data): + def import_attributes( + self, name: str, prop: Union["Attribute", None], data: dict[str, Any] + ) -> None | Literal[True]: if name == "CardinalPoint": # TODO: complain to buildingSMART cardinal_point_map = { @@ -532,6 +537,7 @@ class EnableEditingAssignedMaterial(bpy.types.Operator): 18: "right in line with the shear centre", 19: "top in line with the shear centre", } + assert prop prop.data_type = "enum" prop.enum_items = json.dumps(cardinal_point_map) if data[name]: diff --git a/src/bonsai/bonsai/bim/module/structural/operator.py b/src/bonsai/bonsai/bim/module/structural/operator.py index ed9838a263..59168e205d 100644 --- a/src/bonsai/bonsai/bim/module/structural/operator.py +++ b/src/bonsai/bonsai/bim/module/structural/operator.py @@ -30,6 +30,7 @@ import bonsai.tool as tool from math import degrees from mathutils import Vector, Matrix from bonsai.bim.module.structural.decorator import LoadsDecorator +from typing import Literal class ShowLoads(bpy.types.Operator): @@ -40,6 +41,7 @@ class ShowLoads(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} def modal(self, context, event): + assert context.screen if event.type == "F5": LoadsDecorator.update() for area in context.screen.areas: @@ -54,6 +56,7 @@ class ShowLoads(bpy.types.Operator): return {"PASS_THROUGH"} def invoke(self, context, event): + assert context.window and context.window_manager and context.screen collection = bpy.data.collections.get("IfcStructuralItem") if collection is None: self.report({"ERROR"}, "No IfcStructuralItems found.") @@ -87,6 +90,7 @@ class AddStructuralMemberConnection(bpy.types.Operator, tool.Ifc.Operator): props = tool.Structural.get_object_structural_props(obj) file = tool.Ifc.get() related_structural_connection = file.by_id(oprops.ifc_definition_id) + assert props.relating_structural_member relating_structural_member = tool.Ifc.get_entity(props.relating_structural_member) assert relating_structural_member if not relating_structural_member.is_a("IfcStructuralMember"): @@ -613,7 +617,7 @@ class EnableEditingStructuralLoadCase(bpy.types.Operator): ) return {"FINISHED"} - def import_attributes(self, name, prop, data): + def import_attributes(self, name: str, prop: object, data: object) -> None | Literal[False]: if name in ["SelfWeightCoefficients"]: return False diff --git a/src/bonsai/bonsai/tool/context.py b/src/bonsai/bonsai/tool/context.py index 8c44d0ff26..39f795e2f3 100644 --- a/src/bonsai/bonsai/tool/context.py +++ b/src/bonsai/bonsai/tool/context.py @@ -46,7 +46,7 @@ class Context(bonsai.core.tool.Context): props.context_attributes.clear() context = cls.get_context() - def callback(name: str, prop, data) -> Union[bool, None]: + def callback(name: str, prop: Union[Attribute, None], data: dict[str, Any]) -> Union[bool, None]: if context.is_a("IfcGeometricRepresentationSubContext"): if name == "Precision": props.context_attributes.remove(props.context_attributes.find("Precision")) @@ -57,8 +57,9 @@ class Context(bonsai.core.tool.Context): elif name == "TargetScale": props.context_attributes.remove(props.context_attributes.find("TargetScale")) scale_denominator = None - if data.get(name) is not None and data.get(name) != 0: - scale_denominator = 1.0 / data.get(name) + value = data.get(name) + if value not in (None, 0): + scale_denominator = 1.0 / value new_prop = props.context_attributes.add() new_prop.name = "ScaleDenominator" new_prop.data_type = "float" @@ -68,6 +69,7 @@ class Context(bonsai.core.tool.Context): else: # IfcGeometricRepresentationContext # Import precision as a string because Blender has problem displaying 1e-7 and smaller numbers in UI. if name == "Precision": + assert prop prop.data_type = "string" bonsai.bim.helper.import_attributes(context.is_a(), props.context_attributes, context.get_info(), callback) diff --git a/src/bonsai/bonsai/tool/cost.py b/src/bonsai/bonsai/tool/cost.py index 411b0459a2..fee7320503 100644 --- a/src/bonsai/bonsai/tool/cost.py +++ b/src/bonsai/bonsai/tool/cost.py @@ -22,6 +22,7 @@ import bonsai.core.tool import bonsai.tool as tool import ifcopenshell.api import ifcopenshell.api.cost +import ifcopenshell.api.document import ifcopenshell.api.nest import ifcopenshell.util.element import ifcopenshell.util.date @@ -34,6 +35,7 @@ from typing import Optional, Any, Union, Literal, TYPE_CHECKING, assert_never from collections.abc import Generator if TYPE_CHECKING: + from bonsai.bim.prop import Attribute from bonsai.bim.module.cost.prop import BIMCostProperties, CostItemQuantity @@ -415,7 +417,13 @@ class Cost(bonsai.core.tool.Cost): @classmethod def load_cost_item_value_attributes(cls, cost_value: ifcopenshell.entity_instance) -> None: - def import_attributes(name, prop, data, cost_value, is_rates, props_collection): + props = cls.get_cost_props() + props.cost_value_attributes.clear() + props_collection = props.cost_value_attributes + # is_rates = cls.is_active_schedule_of_rates() + is_rates = True # so it is possible to assign a cost item rate that it not only from a Schedule of Rate + + def import_attributes_callback(name: str, prop: Union[Attribute, None], data) -> None | Literal[True]: if name == "AppliedValue": # TODO: for now, only support simple IfcValues (which are effectively IfcMonetaryMeasure) prop = props_collection.add() @@ -452,14 +460,9 @@ class Cost(bonsai.core.tool.Cost): break return True - props = cls.get_cost_props() - props.cost_value_attributes.clear() - # is_rates = cls.is_active_schedule_of_rates() - is_rates = True # so it is possible to assign a cost item rate that it not only from a Schedule of Rate - callback = lambda name, prop, data: import_attributes( - name, prop, data, cost_value, is_rates, props.cost_value_attributes + bonsai.bim.helper.import_attributes2( + cost_value, props.cost_value_attributes, callback=import_attributes_callback ) - bonsai.bim.helper.import_attributes2(cost_value, props.cost_value_attributes, callback=callback) @classmethod def calculate_applied_value( diff --git a/src/bonsai/bonsai/tool/owner.py b/src/bonsai/bonsai/tool/owner.py index f2c7f82672..4f95ff6782 100644 --- a/src/bonsai/bonsai/tool/owner.py +++ b/src/bonsai/bonsai/tool/owner.py @@ -91,7 +91,7 @@ class Owner(bonsai.core.tool.Owner): address = cls.get_address() - def callback(name: str, prop, data: dict[str, Any]) -> None: + def callback(name: str, prop: object, data: dict[str, Any]) -> None: if name in cls.ADDREESS_ATTRIBUTE_TYPES: collection = cls.get_address_collection(name) for line in data[name] or []: diff --git a/src/ifcopenshell-python/ifcopenshell/api/cogo/add_survey_point.py b/src/ifcopenshell-python/ifcopenshell/api/cogo/add_survey_point.py index fee6b377b1..c4a10661d3 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cogo/add_survey_point.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cogo/add_survey_point.py @@ -20,11 +20,11 @@ import ifcopenshell import ifcopenshell.api.spatial import ifcopenshell.util.representation from ifcopenshell import entity_instance -import typing +from typing import Union def add_survey_point( - file: ifcopenshell.file, survey_point: entity_instance, site: entity_instance = None + file: ifcopenshell.file, survey_point: entity_instance, site: Union[entity_instance, None] = None ) -> entity_instance: """ Adds a single survey point to the model based on IFC Concept Template 4.1.7.1.2.5.