From c68b0c728021c996aa694a1e0151170fe558dcde Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Wed, 18 Jun 2025 11:37:20 +0500 Subject: [PATCH] typing --- src/bonsai/bonsai/bim/module/cost/data.py | 6 +- .../bonsai/bim/module/debug/operator.py | 2 +- .../bonsai/bim/module/georeference/data.py | 3 +- src/bonsai/bonsai/bim/module/model/data.py | 3 +- src/bonsai/bonsai/bim/module/profile/data.py | 3 +- .../bonsai/bim/module/pset_template/data.py | 4 +- src/bonsai/bonsai/bim/module/root/data.py | 6 +- src/bonsai/bonsai/bim/module/sequence/data.py | 9 +- .../bonsai/bim/module/structural/data.py | 6 +- src/bonsai/bonsai/bim/module/style/data.py | 9 +- src/bonsai/bonsai/bim/module/style/prop.py | 1 + src/bonsai/bonsai/bim/module/system/data.py | 3 +- src/bonsai/bonsai/bim/module/unit/data.py | 8 +- src/bonsai/bonsai/core/material.py | 36 ++++---- src/bonsai/bonsai/core/resource.py | 84 ++++++++++--------- src/bonsai/bonsai/tool/drawing.py | 9 +- src/bonsai/bonsai/tool/geometry.py | 2 + src/bonsai/bonsai/tool/structural.py | 3 +- src/bonsai/test/tool/test_debug.py | 3 +- .../ifcopenshell/ifcopenshell_wrapper.pyi | 2 +- .../api/cost/test_add_cost_item_quantity.py | 3 +- .../resource/test_add_resource_quantity.py | 6 +- .../test/util/test_system.py | 3 +- .../test/util/test_unit.py | 3 +- src/ifctester/ifctester/ids.py | 14 ++-- 25 files changed, 137 insertions(+), 94 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/cost/data.py b/src/bonsai/bonsai/bim/module/cost/data.py index 59443d5783..7d631eaf40 100644 --- a/src/bonsai/bonsai/bim/module/cost/data.py +++ b/src/bonsai/bonsai/bim/module/cost/data.py @@ -300,10 +300,8 @@ class CostSchedulesData: @classmethod def quantity_types(cls) -> list[tuple[str, str, str]]: - return [ - (t.name(), t.name(), "") - for t in tool.Ifc.schema().declaration_by_name("IfcPhysicalSimpleQuantity").subtypes() - ] + assert (entity := tool.Ifc.schema().declaration_by_name("IfcPhysicalSimpleQuantity").as_entity()) + return [(t.name(), t.name(), "") for t in entity.subtypes()] @classmethod def get_cost_schedule_types(cls) -> list[tuple[str, str, str]]: diff --git a/src/bonsai/bonsai/bim/module/debug/operator.py b/src/bonsai/bonsai/bim/module/debug/operator.py index 24a2cf5968..3388d7e469 100644 --- a/src/bonsai/bonsai/bim/module/debug/operator.py +++ b/src/bonsai/bonsai/bim/module/debug/operator.py @@ -918,7 +918,7 @@ class DebugActiveDrawing(bpy.types.Operator): original_exclude = ifcopenshell.util.element.get_pset(drawing, "EPset_Drawing", "Exclude") pset = tool.Pset.get_element_pset(drawing, "EPset_Drawing") - def drawing_fails_to_load(chunk_to_include: set) -> bool: + def drawing_fails_to_load(chunk_to_include: set[ifcopenshell.entity_instance]) -> bool: current_elements = all_elements - chunk_to_include excluded_guids = ", ".join([e.GlobalId for e in current_elements if hasattr(e, "GlobalId")]) new_exclude = "" if not original_exclude else f"{original_exclude}, " diff --git a/src/bonsai/bonsai/bim/module/georeference/data.py b/src/bonsai/bonsai/bim/module/georeference/data.py index b64ef55c39..059368abc7 100644 --- a/src/bonsai/bonsai/bim/module/georeference/data.py +++ b/src/bonsai/bonsai/bim/module/georeference/data.py @@ -54,7 +54,8 @@ class GeoreferenceData: def coordinate_operation_class(cls): if tool.Ifc.get_schema() == "IFC2X3": return [] - declaration = tool.Ifc.schema().declaration_by_name("IfcCoordinateOperation") + declaration = tool.Ifc.schema().declaration_by_name("IfcCoordinateOperation").as_entity() + assert declaration declarations = ifcopenshell.util.schema.get_subtypes(declaration) names = [d.name() for d in declarations] version = tool.Ifc.get_schema() diff --git a/src/bonsai/bonsai/bim/module/model/data.py b/src/bonsai/bonsai/bim/module/model/data.py index 3af67e4990..2c96e42925 100644 --- a/src/bonsai/bonsai/bim/module/model/data.py +++ b/src/bonsai/bonsai/bim/module/model/data.py @@ -99,7 +99,8 @@ class AuthoringData: @classmethod def boundary_class(cls): - declaration = tool.Ifc.schema().declaration_by_name("IfcRelSpaceBoundary") + declaration = tool.Ifc.schema().declaration_by_name("IfcRelSpaceBoundary").as_entity() + assert declaration declarations = ifcopenshell.util.schema.get_subtypes(declaration) names = [d.name() for d in declarations] version = tool.Ifc.get_schema() diff --git a/src/bonsai/bonsai/bim/module/profile/data.py b/src/bonsai/bonsai/bim/module/profile/data.py index cc28d8b008..eb21a72f25 100644 --- a/src/bonsai/bonsai/bim/module/profile/data.py +++ b/src/bonsai/bonsai/bim/module/profile/data.py @@ -96,9 +96,10 @@ class ProfileData: @classmethod def profile_def_classes_enum(cls) -> list[tuple[str, str, str]]: version = tool.Ifc.get_schema() + assert (entity := tool.Ifc.schema().declaration_by_name("IfcProfileDef").as_entity()) return [ (t.name(), t.name(), ifcopenshell.util.doc.get_entity_doc(version, t.name()).get("description", "")) - for t in tool.Ifc.schema().declaration_by_name("IfcProfileDef").subtypes() + for t in entity.subtypes() ] @classmethod diff --git a/src/bonsai/bonsai/bim/module/pset_template/data.py b/src/bonsai/bonsai/bim/module/pset_template/data.py index 8eae1fdc42..84d65f25f1 100644 --- a/src/bonsai/bonsai/bim/module/pset_template/data.py +++ b/src/bonsai/bonsai/bim/module/pset_template/data.py @@ -98,7 +98,9 @@ class PsetTemplatesData: pset_type = next(iter(pset_types)) if len(pset_types) == 1 else None schema = ifcopenshell.schema_by_name(ifc_file.schema) - attribute = schema.declaration_by_name("IfcSimplePropertyTemplate").attributes()[0] + entity = schema.declaration_by_name("IfcSimplePropertyTemplate").as_entity() + assert entity + attribute = entity.attributes()[0] enum_items = [ a for a in ifcopenshell.util.attribute.get_enum_items(attribute) diff --git a/src/bonsai/bonsai/bim/module/root/data.py b/src/bonsai/bonsai/bim/module/root/data.py index 271d966e3c..34fc15b0e4 100644 --- a/src/bonsai/bonsai/bim/module/root/data.py +++ b/src/bonsai/bonsai/bim/module/root/data.py @@ -70,9 +70,9 @@ class IfcClassData: if tool.Ifc.get_schema() in ("IFC2X3", "IFC4"): names.extend(("IfcDoorStyle", "IfcWindowStyle")) if ifc_product == "IfcElement": - feature_elements = ifcopenshell.util.schema.get_subtypes( - tool.Ifc.schema().declaration_by_name("IfcFeatureElement") - ) + entity = tool.Ifc.schema().declaration_by_name("IfcFeatureElement").as_entity() + assert entity + feature_elements = ifcopenshell.util.schema.get_subtypes(entity) for feature_element in feature_elements: names.remove(feature_element.name()) version = tool.Ifc.get_schema() diff --git a/src/bonsai/bonsai/bim/module/sequence/data.py b/src/bonsai/bonsai/bim/module/sequence/data.py index 512056f1b3..6fdb0add3f 100644 --- a/src/bonsai/bonsai/bim/module/sequence/data.py +++ b/src/bonsai/bonsai/bim/module/sequence/data.py @@ -247,7 +247,8 @@ class SequenceData: @classmethod def schedule_predefined_types_enum(cls) -> list[tuple[str, str, str]]: results: list[tuple[str, str, str]] = [] - declaration = tool.Ifc().schema().declaration_by_name("IfcWorkSchedule") + declaration = tool.Ifc().schema().declaration_by_name("IfcWorkSchedule").as_entity() + assert declaration version = tool.Ifc.get_schema() for attribute in declaration.attributes(): if attribute.name() == "PredefinedType": @@ -265,7 +266,8 @@ class SequenceData: def task_columns_enum(cls) -> list[tuple[str, str, str]]: schema = tool.Ifc.schema() taskcolumns_enum = [] - for a in schema.declaration_by_name("IfcTask").all_attributes(): + assert (entity := schema.declaration_by_name("IfcTask").as_entity()) + for a in entity.all_attributes(): if (primitive_type := ifcopenshell.util.attribute.get_primitive_type(a)) not in ( "string", "float", @@ -281,7 +283,8 @@ class SequenceData: def task_time_columns_enum(cls) -> list[tuple[str, str, str]]: schema = tool.Ifc.schema() tasktimecolumns_enum = [] - for a in schema.declaration_by_name("IfcTaskTime").all_attributes(): + assert (entity := schema.declaration_by_name("IfcTaskTime").as_entity()) + for a in entity.all_attributes(): if (primitive_type := ifcopenshell.util.attribute.get_primitive_type(a)) not in ( "string", "float", diff --git a/src/bonsai/bonsai/bim/module/structural/data.py b/src/bonsai/bonsai/bim/module/structural/data.py index d2cf1f3fbd..f3215ddff3 100644 --- a/src/bonsai/bonsai/bim/module/structural/data.py +++ b/src/bonsai/bonsai/bim/module/structural/data.py @@ -290,7 +290,8 @@ class StructuralLoadsData: @classmethod def structural_load_types(cls): - declaration = tool.Ifc.schema().declaration_by_name("IfcStructuralLoadStatic") + declaration = tool.Ifc.schema().declaration_by_name("IfcStructuralLoadStatic").as_entity() + assert declaration version = tool.Ifc.get_schema() return [ (d.name(), d.name(), ifcopenshell.util.doc.get_entity_doc(version, d.name()).get("description", "")) @@ -321,7 +322,8 @@ class BoundaryConditionsData: @classmethod def boundary_condition_types(cls): - declaration = tool.Ifc.schema().declaration_by_name("IfcBoundaryCondition") + declaration = tool.Ifc.schema().declaration_by_name("IfcBoundaryCondition").as_entity() + assert declaration version = tool.Ifc.get_schema() return [ (d.name(), d.name(), ifcopenshell.util.doc.get_entity_doc(version, d.name()).get("description", "")) diff --git a/src/bonsai/bonsai/bim/module/style/data.py b/src/bonsai/bonsai/bim/module/style/data.py index 09cb5447b1..83e453d7a5 100644 --- a/src/bonsai/bonsai/bim/module/style/data.py +++ b/src/bonsai/bonsai/bim/module/style/data.py @@ -44,12 +44,14 @@ class StylesData: @classmethod def reflectance_methods(cls): - declaration = tool.Ifc.schema().declaration_by_name("IfcReflectanceMethodEnum") + declaration = tool.Ifc.schema().declaration_by_name("IfcReflectanceMethodEnum").as_enumeration_type() + assert declaration return [(i, i, "") for i in declaration.enumeration_items()] @classmethod def style_types(cls): - declaration = tool.Ifc.schema().declaration_by_name("IfcPresentationStyle") + declaration = tool.Ifc.schema().declaration_by_name("IfcPresentationStyle").as_entity() + assert declaration declarations = ifcopenshell.util.schema.get_subtypes(declaration) version = tool.Ifc.get_schema() return [ @@ -66,7 +68,8 @@ class StylesData: @classmethod def get_presentation_style_declarations(cls): - declaration = tool.Ifc.schema().declaration_by_name("IfcPresentationStyle") + declaration = tool.Ifc.schema().declaration_by_name("IfcPresentationStyle").as_entity() + assert declaration return ifcopenshell.util.schema.get_subtypes(declaration) diff --git a/src/bonsai/bonsai/bim/module/style/prop.py b/src/bonsai/bonsai/bim/module/style/prop.py index 7daf36f0c4..11dcf72f92 100644 --- a/src/bonsai/bonsai/bim/module/style/prop.py +++ b/src/bonsai/bonsai/bim/module/style/prop.py @@ -153,6 +153,7 @@ class ColourRgb(PropertyGroup): color_name: StringProperty(name="Color Name") if TYPE_CHECKING: + name: str color_value: tuple[float, float, float] color_name: str diff --git a/src/bonsai/bonsai/bim/module/system/data.py b/src/bonsai/bonsai/bim/module/system/data.py index d630f14af1..19a77e425d 100644 --- a/src/bonsai/bonsai/bim/module/system/data.py +++ b/src/bonsai/bonsai/bim/module/system/data.py @@ -50,7 +50,8 @@ class SystemData: @classmethod def system_class(cls): - declaration = tool.Ifc.schema().declaration_by_name("IfcSystem") + declaration = tool.Ifc.schema().declaration_by_name("IfcSystem").as_entity() + assert declaration declarations = ifcopenshell.util.schema.get_subtypes(declaration) version = tool.Ifc.get_schema() diff --git a/src/bonsai/bonsai/bim/module/unit/data.py b/src/bonsai/bonsai/bim/module/unit/data.py index 32cdf97223..bae735245b 100644 --- a/src/bonsai/bonsai/bim/module/unit/data.py +++ b/src/bonsai/bonsai/bim/module/unit/data.py @@ -62,7 +62,8 @@ class UnitsData: @classmethod def unit_classes(cls): - declarations = ifcopenshell.util.schema.get_subtypes(tool.Ifc.schema().declaration_by_name("IfcNamedUnit")) + assert (entity := tool.Ifc.schema().declaration_by_name("IfcNamedUnit").as_entity()) + declarations = ifcopenshell.util.schema.get_subtypes(entity) version = tool.Ifc.get_schema() results = [ (c, c, get_entity_doc(version, c).get("description", "")) for c in sorted([d.name() for d in declarations]) @@ -81,9 +82,8 @@ class UnitsData: @classmethod def named_unit_types(cls): - values = ifcopenshell.util.attribute.get_enum_items( - tool.Ifc.schema().declaration_by_name("IfcNamedUnit").all_attributes()[1] - ) + assert (entity := tool.Ifc.schema().declaration_by_name("IfcNamedUnit").as_entity()) + values = ifcopenshell.util.attribute.get_enum_items(entity.all_attributes()[1]) return [(c, c, "") for c in sorted(values)] @classmethod diff --git a/src/bonsai/bonsai/core/material.py b/src/bonsai/bonsai/core/material.py index fcec980206..25a1df3e89 100644 --- a/src/bonsai/bonsai/core/material.py +++ b/src/bonsai/bonsai/core/material.py @@ -26,8 +26,8 @@ if TYPE_CHECKING: def add_material( - ifc: tool.Ifc, - material: tool.Material, + ifc: type[tool.Ifc], + material: type[tool.Material], name: str, category: Optional[str] = None, description: Optional[str] = None, @@ -38,7 +38,7 @@ def add_material( return ifc_material -def add_material_set(ifc: tool.Ifc, material: tool.Material, set_type: str) -> ifcopenshell.entity_instance: +def add_material_set(ifc: type[tool.Ifc], material: type[tool.Material], set_type: str) -> ifcopenshell.entity_instance: ifc_material = ifc.run("material.add_material_set", name="Unnamed", set_type=set_type) material.ensure_new_material_set_is_valid(ifc_material) if material.is_editing_materials(): @@ -46,7 +46,9 @@ def add_material_set(ifc: tool.Ifc, material: tool.Material, set_type: str) -> i return ifc_material -def remove_material(ifc: tool.Ifc, material_tool: tool.Material, material: ifcopenshell.entity_instance) -> bool: +def remove_material( + ifc: type[tool.Ifc], material_tool: type[tool.Material], material: ifcopenshell.entity_instance +) -> bool: """Remove an IFC material. Return True if deletion succeeded,\n @@ -60,33 +62,37 @@ def remove_material(ifc: tool.Ifc, material_tool: tool.Material, material: ifcop return True -def remove_material_set(ifc: tool.Ifc, material_tool: tool.Material, material: ifcopenshell.entity_instance) -> None: +def remove_material_set( + ifc: type[tool.Ifc], material_tool: type[tool.Material], material: ifcopenshell.entity_instance +) -> None: ifc.run("material.remove_material_set", material=material) if material_tool.is_editing_materials(): material_tool.import_material_definitions(material_tool.get_active_material_type()) -def load_materials(material: tool.Material, material_type: str) -> None: +def load_materials(material: type[tool.Material], material_type: str) -> None: material.import_material_definitions(material_type) material.enable_editing_materials() -def disable_editing_materials(material: tool.Material) -> None: +def disable_editing_materials(material: type[tool.Material]) -> None: material.disable_editing_materials() def select_by_material( - material_tool: tool.Material, spatial: tool.Spatial, material: ifcopenshell.entity_instance + material_tool: type[tool.Material], spatial: type[tool.Spatial], material: ifcopenshell.entity_instance ) -> None: spatial.select_products(material_tool.get_elements_by_material(material)) -def enable_editing_material(material_tool: tool.Material, material: ifcopenshell.entity_instance) -> None: +def enable_editing_material(material_tool: type[tool.Material], material: ifcopenshell.entity_instance) -> None: material_tool.load_material_attributes(material) material_tool.enable_editing_material(material) -def edit_material(ifc: tool.Ifc, material_tool: tool.Material, material: ifcopenshell.entity_instance) -> None: +def edit_material( + ifc: type[tool.Ifc], material_tool: type[tool.Material], material: ifcopenshell.entity_instance +) -> None: attributes = material_tool.get_material_attributes() ifc.run("material.edit_material", material=material, attributes=attributes) material_tool.disable_editing_material() @@ -95,13 +101,13 @@ def edit_material(ifc: tool.Ifc, material_tool: tool.Material, material: ifcopen material_tool.enable_editing_materials() -def disable_editing_material(material_tool: tool.Material) -> None: +def disable_editing_material(material_tool: type[tool.Material]) -> None: material_tool.disable_editing_material() def assign_material( - ifc: tool.Ifc, - material_tool: tool.Material, + ifc: type[tool.Ifc], + material_tool: type[tool.Material], material_type: Union[str, None], objects: list[bpy.types.Object], material: Optional[ifcopenshell.entity_instance] = None, @@ -131,7 +137,7 @@ def assign_material( material_tool.ensure_material_assigned(elements=[element], material_type=material_type, material=material) -def unassign_material(ifc: tool.Ifc, material_tool: tool.Material, objects: list[bpy.types.Object]) -> None: +def unassign_material(ifc: type[tool.Ifc], material_tool: type[tool.Material], objects: list[bpy.types.Object]) -> None: for obj in objects: element = ifc.get_entity(obj) if not element: @@ -158,7 +164,7 @@ def unassign_material(ifc: tool.Ifc, material_tool: tool.Material, objects: list def patch_non_parametric_mep_segment( - ifc: tool.Ifc, material_tool: tool.Material, profile_tool: tool.Profile, obj: bpy.types.Object + ifc: type[tool.Ifc], material_tool: type[tool.Material], profile_tool: type[tool.Profile], obj: bpy.types.Object ) -> None: element = ifc.get_entity(obj) if not element: diff --git a/src/bonsai/bonsai/core/resource.py b/src/bonsai/bonsai/core/resource.py index 9729fbd84f..a3423c98db 100644 --- a/src/bonsai/bonsai/core/resource.py +++ b/src/bonsai/bonsai/core/resource.py @@ -28,13 +28,13 @@ if TYPE_CHECKING: import bonsai.tool as tool -def load_resources(resource: tool.Resource) -> None: +def load_resources(resource: type[tool.Resource]) -> None: resource.load_resources() def add_resource( - tool_ifc: tool.Ifc, - resource_tool: tool.Resource, + tool_ifc: type[tool.Ifc], + resource_tool: type[tool.Resource], ifc_class, parent_resource: Optional[ifcopenshell.entity_instance] = None, ) -> None: @@ -42,33 +42,37 @@ def add_resource( resource_tool.load_resources() -def disable_editing_resource(resource_tool: tool.Resource) -> None: +def disable_editing_resource(resource_tool: type[tool.Resource]) -> None: resource_tool.disable_editing_resource() -def disable_resource_editing_ui(resource_tool: tool.Resource) -> None: +def disable_resource_editing_ui(resource_tool: type[tool.Resource]) -> None: resource_tool.disable_resource_editing_ui() -def enable_editing_resource(resource_tool: tool.Resource, resource) -> None: +def enable_editing_resource(resource_tool: type[tool.Resource], resource) -> None: resource_tool.enable_editing_resource(resource) resource_tool.load_resource_attributes(resource) -def edit_resource(ifc: tool.Ifc, resource_tool: tool.Resource, resource: ifcopenshell.entity_instance) -> None: +def edit_resource( + ifc: type[tool.Ifc], resource_tool: type[tool.Resource], resource: ifcopenshell.entity_instance +) -> None: attributes = resource_tool.get_resource_attributes() ifc.run("resource.edit_resource", resource=resource, attributes=attributes) resource_tool.load_resource_properties() resource_tool.disable_editing_resource() -def remove_resource(ifc: tool.Ifc, resource_tool: tool.Resource, resource: ifcopenshell.entity_instance) -> None: +def remove_resource( + ifc: type[tool.Ifc], resource_tool: type[tool.Resource], resource: ifcopenshell.entity_instance +) -> None: ifc.run("resource.remove_resource", resource=resource) resource_tool.load_resources() def enable_editing_resource_time( - ifc_tool, resource_tool: tool.Resource, resource: ifcopenshell.entity_instance + ifc_tool, resource_tool: type[tool.Resource], resource: ifcopenshell.entity_instance ) -> None: resource_time = resource_tool.get_resource_time(resource) if resource_time is None: @@ -78,19 +82,19 @@ def enable_editing_resource_time( def edit_resource_time( - ifc: tool.Ifc, resource_tool: tool.Resource, resource_time: ifcopenshell.entity_instance + ifc: type[tool.Ifc], resource_tool: type[tool.Resource], resource_time: ifcopenshell.entity_instance ) -> None: attributes = resource_tool.get_resource_time_attributes() ifc.run("resource.edit_resource_time", resource_time=resource_time, attributes=attributes) resource_tool.disable_editing_resource() -def disable_editing_resource_time(resource_tool: tool.Resource) -> None: +def disable_editing_resource_time(resource_tool: type[tool.Resource]) -> None: resource_tool.disable_editing_resource() def calculate_resource_work( - ifc: tool.Ifc, resource_tool: tool.Resource, resource: ifcopenshell.entity_instance + ifc: type[tool.Ifc], resource_tool: type[tool.Resource], resource: ifcopenshell.entity_instance ) -> None: if resource_tool.get_task_assignments(resource): ifc.run("resource.calculate_resource_work", resource=resource) @@ -101,28 +105,30 @@ def calculate_resource_work( resource_tool.load_resources() -def enable_editing_resource_costs(resource_tool: tool.Resource, resource: ifcopenshell.entity_instance) -> None: +def enable_editing_resource_costs(resource_tool: type[tool.Resource], resource: ifcopenshell.entity_instance) -> None: resource_tool.enable_editing_resource_costs(resource) resource_tool.disable_editing_resource_cost_value() -def disable_editing_resource_cost_value(resource_tool: tool.Resource) -> None: +def disable_editing_resource_cost_value(resource_tool: type[tool.Resource]) -> None: resource_tool.disable_editing_resource_cost_value() -def enable_editing_resource_cost_value(resource_tool: tool.Resource, cost_value: ifcopenshell.entity_instance) -> None: +def enable_editing_resource_cost_value( + resource_tool: type[tool.Resource], cost_value: ifcopenshell.entity_instance +) -> None: resource_tool.enable_editing_cost_value_attributes(cost_value) resource_tool.load_cost_value_attributes(cost_value) def enable_editing_resource_cost_value_formula( - resource_tool: tool.Resource, cost_value: ifcopenshell.entity_instance + resource_tool: type[tool.Resource], cost_value: ifcopenshell.entity_instance ) -> None: resource_tool.enable_editing_resource_cost_value_formula(cost_value) def edit_resource_cost_value_formula( - ifc: tool.Ifc, resource_tool: tool.Resource, cost_value: ifcopenshell.entity_instance + ifc: type[tool.Ifc], resource_tool: type[tool.Resource], cost_value: ifcopenshell.entity_instance ) -> None: formula = resource_tool.get_resource_cost_value_formula() ifc.run("cost.edit_cost_value_formula", cost_value=cost_value, formula=formula) @@ -130,65 +136,67 @@ def edit_resource_cost_value_formula( def edit_resource_cost_value( - ifc: tool.Ifc, resource_tool: tool.Resource, cost_value: ifcopenshell.entity_instance + ifc: type[tool.Ifc], resource_tool: type[tool.Resource], cost_value: ifcopenshell.entity_instance ) -> None: attributes = resource_tool.get_resource_cost_value_attributes() ifc.run("cost.edit_cost_value", cost_value=cost_value, attributes=attributes) resource_tool.disable_editing_resource_cost_value() -def enable_editing_resource_base_quantity(resource_tool: tool.Resource, resource: ifcopenshell.entity_instance) -> None: +def enable_editing_resource_base_quantity( + resource_tool: type[tool.Resource], resource: ifcopenshell.entity_instance +) -> None: resource_tool.enable_editing_resource_base_quantity(resource) -def add_resource_quantity(ifc: tool.Ifc, ifc_class: str, resource: ifcopenshell.entity_instance) -> None: +def add_resource_quantity(ifc: type[tool.Ifc], ifc_class: str, resource: ifcopenshell.entity_instance) -> None: ifc.run("resource.add_resource_quantity", resource=resource, ifc_class=ifc_class) -def remove_resource_quantity(ifc: tool.Ifc, resource: ifcopenshell.entity_instance) -> None: +def remove_resource_quantity(ifc: type[tool.Ifc], resource: ifcopenshell.entity_instance) -> None: ifc.run("resource.remove_resource_quantity", resource=resource) def enable_editing_resource_quantity( - resource_tool: tool.Resource, resource_quantity: ifcopenshell.entity_instance + resource_tool: type[tool.Resource], resource_quantity: ifcopenshell.entity_instance ) -> None: resource_tool.enable_editing_resource_quantity(resource_quantity) -def disable_editing_resource_quantity(resource_tool: tool.Resource) -> None: +def disable_editing_resource_quantity(resource_tool: type[tool.Resource]) -> None: resource_tool.disable_editing_resource_quantity() def edit_resource_quantity( - resource_tool: tool.Resource, ifc: tool.Ifc, physical_quantity: ifcopenshell.entity_instance + resource_tool: type[tool.Resource], ifc: type[tool.Ifc], physical_quantity: ifcopenshell.entity_instance ) -> None: attributes = resource_tool.get_resource_quantity_attributes() ifc.run("resource.edit_resource_quantity", physical_quantity=physical_quantity, attributes=attributes) resource_tool.disable_editing_resource_quantity() -def import_resources(resource_tool: tool.Resource, file_path: str) -> None: +def import_resources(resource_tool: type[tool.Resource], file_path: str) -> None: resource_tool.import_resources(file_path) resource_tool.load_resources() -def export_resources(resource_tool: tool.Resource, file_path: str) -> None: +def export_resources(resource_tool: type[tool.Resource], file_path: str) -> None: resource_tool.export_resources(file_path) -def expand_resource(resource_tool: tool.Resource, resource: ifcopenshell.entity_instance) -> None: +def expand_resource(resource_tool: type[tool.Resource], resource: ifcopenshell.entity_instance) -> None: resource_tool.expand_resource(resource) resource_tool.load_resources() -def contract_resource(resource_tool: tool.Resource, resource: ifcopenshell.entity_instance) -> None: +def contract_resource(resource_tool: type[tool.Resource], resource: ifcopenshell.entity_instance) -> None: resource_tool.contract_resource(resource) resource_tool.load_resources() def assign_resource( - ifc: tool.Ifc, - spatial: tool.Spatial, + ifc: type[tool.Ifc], + spatial: type[tool.Spatial], resource: ifcopenshell.entity_instance, products: Optional[Iterable[ifcopenshell.entity_instance]] = None, ) -> None: @@ -199,8 +207,8 @@ def assign_resource( def unassign_resource( - ifc: tool.Ifc, - spatial: tool.Spatial, + ifc: type[tool.Ifc], + spatial: type[tool.Spatial], resource: ifcopenshell.entity_instance, products: Optional[Iterable[ifcopenshell.entity_instance]] = None, ) -> None: @@ -210,7 +218,7 @@ def unassign_resource( ifc.run("resource.unassign_resource", relating_resource=resource, related_object=product) -def edit_productivity_pset(ifc: tool.Ifc, resource_tool: tool.Resource) -> None: +def edit_productivity_pset(ifc: type[tool.Ifc], resource_tool: type[tool.Resource]) -> None: resource = resource_tool.get_highlighted_resource() if resource is None: return @@ -223,7 +231,7 @@ def edit_productivity_pset(ifc: tool.Ifc, resource_tool: tool.Resource) -> None: def add_usage_constraint( - ifc: tool.Ifc, resource_tool: tool.Resource, resource: ifcopenshell.entity_instance, reference_path: str + ifc: type[tool.Ifc], resource_tool: type[tool.Resource], resource: ifcopenshell.entity_instance, reference_path: str ) -> None: metric = resource_tool.has_metric_constraint(resource, "Usage") if metric: @@ -245,7 +253,7 @@ def add_usage_constraint( def remove_usage_constraint( - ifc: tool.Ifc, resource_tool: tool.Resource, resource: ifcopenshell.entity_instance, reference_path: str + ifc: type[tool.Ifc], resource_tool: type[tool.Resource], resource: ifcopenshell.entity_instance, reference_path: str ) -> None: constraints = resource_tool.get_constraints(resource) for constraint in constraints: @@ -258,16 +266,16 @@ def remove_usage_constraint( ifc.run("constraint.remove_constraint", constraint=constraint) -def go_to_resource(resource_tool: tool.Resource, resource: ifcopenshell.entity_instance) -> None: +def go_to_resource(resource_tool: type[tool.Resource], resource: ifcopenshell.entity_instance) -> None: resource_tool.go_to_resource(resource) def calculate_resource_usage( - ifc: tool.Resource, resource_tool: tool.Resource, resource: ifcopenshell.entity_instance + ifc: type[tool.Resource], resource_tool: type[tool.Resource], resource: ifcopenshell.entity_instance ) -> None: ifc.run("resource.calculate_resource_usage", resource=resource) resource_tool.load_resources() -def calculate_resource_quantity(resource_tool: tool.Resource, resource: ifcopenshell.entity_instance) -> None: +def calculate_resource_quantity(resource_tool: type[tool.Resource], resource: ifcopenshell.entity_instance) -> None: resource_tool.calculate_resource_quantity(resource) diff --git a/src/bonsai/bonsai/tool/drawing.py b/src/bonsai/bonsai/tool/drawing.py index a8d4c90382..04f5e8c06e 100644 --- a/src/bonsai/bonsai/tool/drawing.py +++ b/src/bonsai/bonsai/tool/drawing.py @@ -206,16 +206,19 @@ class Drawing(bonsai.core.tool.Drawing): if not related_object: related_object = bpy.context.active_object - related_entity = tool.Ifc.get_entity(related_object) - if not related_entity: + + if not related_object or not (related_entity := tool.Ifc.get_entity(related_object)): return obj_entity = tool.Ifc.get_entity(obj) + assert obj_entity assign_product = False if object_type == "STAIR_ARROW": if related_entity.is_a("IfcStairFlight"): stair, arrow = related_object, obj + assert isinstance(stair.data, bpy.types.Mesh) + assert isinstance(arrow.data, bpy.types.Mesh) # place the arrow # NOTE: may not work correctly in EDIT mode @@ -239,6 +242,8 @@ class Drawing(bonsai.core.tool.Drawing): elif object_type == "REVISION_CLOUD": revised_object, cloud = related_object, obj + assert isinstance(revised_object.data, bpy.types.Mesh) + assert isinstance(obj.data, bpy.types.Mesh) verts = [np.array(revised_object.matrix_world @ v.co) for v in revised_object.data.vertices] verts = [(np.around(v[[0, 1]], decimals=3)).tolist() for v in verts] diff --git a/src/bonsai/bonsai/tool/geometry.py b/src/bonsai/bonsai/tool/geometry.py index 90a12250cd..50cc8ed80b 100644 --- a/src/bonsai/bonsai/tool/geometry.py +++ b/src/bonsai/bonsai/tool/geometry.py @@ -1469,11 +1469,13 @@ class Geometry(bonsai.core.tool.Geometry): ifc_file = tool.Ifc.get() # as shape aspect might have multiple representations # it's easier to find it from the item + representation = None for inverse in ifc_file.get_inverse(representation_items[0]): if inverse.is_a("IfcShapeRepresentation") and shape_aspect in inverse.OfShapeAspect: representation = inverse break + assert representation # removing last item would make representation invalid if len(representation.Items) == len(representation_items): # removing last representation would make shape aspect invalid. diff --git a/src/bonsai/bonsai/tool/structural.py b/src/bonsai/bonsai/tool/structural.py index 68ff8448f9..b7bf23b481 100644 --- a/src/bonsai/bonsai/tool/structural.py +++ b/src/bonsai/bonsai/tool/structural.py @@ -146,7 +146,8 @@ class Structural(bonsai.core.tool.Structural): props = cls.get_structural_props() props.structural_analysis_model_attributes.clear() schema = tool.Ifc.schema() - for attribute in schema.declaration_by_name("IfcStructuralAnalysisModel").all_attributes(): + assert (entity := schema.declaration_by_name("IfcStructuralAnalysisModel").as_entity()) + for attribute in entity.all_attributes(): data_type = str(attribute.type_of_attribute) if " bool: ... + def _is(self, *args: Union[str, declaration]) -> bool: ... def as_entity(self) -> Union[entity, None]: ... def as_enumeration_type(self) -> Union[enumeration_type, None]: ... def as_select_type(self) -> Union[select_type, None]: ... diff --git a/src/ifcopenshell-python/test/api/cost/test_add_cost_item_quantity.py b/src/ifcopenshell-python/test/api/cost/test_add_cost_item_quantity.py index e61a4dc2c5..c954ec169d 100644 --- a/src/ifcopenshell-python/test/api/cost/test_add_cost_item_quantity.py +++ b/src/ifcopenshell-python/test/api/cost/test_add_cost_item_quantity.py @@ -25,7 +25,8 @@ import ifcopenshell.api.control class TestAddCostItemQuantity(test.bootstrap.IFC4): def test_run(self): schema = ifcopenshell.schema_by_name(self.file.schema) - quantity_types = [t.name() for t in schema.declaration_by_name("IfcPhysicalSimpleQuantity").subtypes()] + assert (entity := schema.declaration_by_name("IfcPhysicalSimpleQuantity").as_entity()) + quantity_types = [t.name() for t in entity.subtypes()] schedule = ifcopenshell.api.cost.add_cost_schedule(self.file) item = ifcopenshell.api.cost.add_cost_item(self.file, cost_schedule=schedule) wall = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall") diff --git a/src/ifcopenshell-python/test/api/resource/test_add_resource_quantity.py b/src/ifcopenshell-python/test/api/resource/test_add_resource_quantity.py index e843e5828b..c9e20e7a49 100644 --- a/src/ifcopenshell-python/test/api/resource/test_add_resource_quantity.py +++ b/src/ifcopenshell-python/test/api/resource/test_add_resource_quantity.py @@ -26,8 +26,10 @@ import ifcopenshell.util.resource class TestAddResourceQuantity(test.bootstrap.IFC4): def test_run(self): schema = ifcopenshell.schema_by_name(self.file.schema) - quantity_types = [t.name() for t in schema.declaration_by_name("IfcPhysicalSimpleQuantity").subtypes()] - resource_types = [t.name() for t in schema.declaration_by_name("IfcConstructionResource").subtypes()] + assert (quantity_entity := schema.declaration_by_name("IfcPhysicalSimpleQuantity").as_entity()) + quantity_types = [t.name() for t in quantity_entity.subtypes()] + assert (resource_entity := schema.declaration_by_name("IfcConstructionResource").as_entity()) + resource_types = [t.name() for t in resource_entity.subtypes()] self.file.create_entity("IfcProject") # add_resource diff --git a/src/ifcopenshell-python/test/util/test_system.py b/src/ifcopenshell-python/test/util/test_system.py index 892d9e2fdf..3e8c6d0159 100644 --- a/src/ifcopenshell-python/test/util/test_system.py +++ b/src/ifcopenshell-python/test/util/test_system.py @@ -31,7 +31,8 @@ class TestValidateGroupTypes: ifcsystem_classes = set() for schema_name in get_args(ifcopenshell.util.schema.IFC_SCHEMA): schema = ifcopenshell.schema_by_name(schema_name) - declaration = schema.declaration_by_name("IfcSystem") + declaration = schema.declaration_by_name("IfcSystem").as_entity() + assert declaration declarations = ifcopenshell.util.schema.get_subtypes(declaration) ifcsystem_classes.update(d.name() for d in declarations) diff --git a/src/ifcopenshell-python/test/util/test_unit.py b/src/ifcopenshell-python/test/util/test_unit.py index b5f1fc537e..e0d304888b 100644 --- a/src/ifcopenshell-python/test/util/test_unit.py +++ b/src/ifcopenshell-python/test/util/test_unit.py @@ -227,7 +227,8 @@ class TestFormatLength(test.bootstrap.IFC4): class TestIsAttrType(test.bootstrap.IFC4): def test_run(self): schema = ifcopenshell.schema_by_name("IFC4") - declaration = schema.declaration_by_name("IfcPropertySingleValue") + declaration = schema.declaration_by_name("IfcPropertySingleValue").as_entity() + assert declaration nominal_value = declaration.attribute_by_index(2).type_of_attribute() assert subject.is_attr_type(nominal_value, "IfcValue") assert subject.is_attr_type(nominal_value, "IfcLengthMeasure") diff --git a/src/ifctester/ifctester/ids.py b/src/ifctester/ifctester/ids.py index 3014d3e5ef..7e02151a23 100644 --- a/src/ifctester/ifctester/ids.py +++ b/src/ifctester/ifctester/ids.py @@ -38,7 +38,7 @@ from .facet import ( Cardinality, FacetFailure, ) -from typing import Optional, Union +from typing import Optional, Union, Any cwd = os.path.dirname(os.path.realpath(__file__)) schema = None @@ -83,6 +83,8 @@ def get_schema(): class Ids: + info: dict[str, Any] + def __init__( self, title: Optional[str] = "Untitled", @@ -119,12 +121,12 @@ class Ids: if milestone: self.info["milestone"] = milestone - def asdict(self): - info = {} + def asdict(self) -> dict[str, Any]: + info: dict[str, Any] = {} for attr in ["title", "copyright", "version", "description", "author", "date", "purpose", "milestone"]: if attr in self.info: info[attr] = self.info[attr] - ids_dict = { + ids_dict: dict[str, Any] = { "@xmlns": "http://standards.buildingsmart.org/IDS", "@xmlns:xs": "http://www.w3.org/2001/XMLSchema", "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", @@ -202,8 +204,8 @@ class Specification: self.status = None self.is_ifc_version = None - def asdict(self): - results = { + def asdict(self) -> dict[str, Any]: + results: dict[str, Any] = { "@name": self.name, "@ifcVersion": self.ifcVersion, "applicability": {},