From 8f92877fb4ca51023836aa0fd6c9594427fda4ef Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Tue, 2 Jul 2024 11:40:38 +0500 Subject: [PATCH] typing --- .../blenderbim/bim/module/drawing/operator.py | 8 ++-- .../blenderbim/bim/module/project/operator.py | 2 + src/blenderbim/blenderbim/core/geometry.py | 43 ++++++++++++------- src/blenderbim/blenderbim/tool/geometry.py | 1 + src/ifcopenshell-python/ifcopenshell/draw.py | 18 ++++---- .../ifcopenshell/geom/main.py | 2 + 6 files changed, 46 insertions(+), 28 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index aae82ea44a..1c2242dff1 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -46,11 +46,11 @@ import blenderbim.bim.module.drawing.helper as helper import blenderbim.bim.export_ifc from blenderbim.bim.module.drawing.decoration import CutDecorator from blenderbim.bim.module.drawing.data import DecoratorData, DrawingsData -from typing import NamedTuple, List, Union, Optional +from typing import NamedTuple, List, Union, Optional, Literal from lxml import etree from mathutils import Vector, Color, Matrix from timeit import default_timer as timer -from blenderbim.bim.module.drawing.prop import RasterStyleProperty, Literal, RASTER_STYLE_PROPERTIES_EXCLUDE +from blenderbim.bim.module.drawing.prop import RasterStyleProperty, RASTER_STYLE_PROPERTIES_EXCLUDE from blenderbim.bim.ifc import IfcStore from pathlib import Path from bpy_extras.image_utils import load_image @@ -465,12 +465,12 @@ class CreateDrawing(bpy.types.Operator): ifc: ifcopenshell.file, tree: ifcopenshell.geom.tree, contexts: LineworkContexts, - context_type: str, + context_type: Literal["body", "annotation"], drawing_elements: set[ifcopenshell.entity_instance], target_view: str, ) -> None: drawing_elements = drawing_elements.copy() - contexts = getattr(contexts, context_type) + contexts: list[list[int]] = getattr(contexts, context_type) for context in contexts: with profile(f"Processing {context_type} context"): if not context or not drawing_elements: diff --git a/src/blenderbim/blenderbim/bim/module/project/operator.py b/src/blenderbim/blenderbim/bim/module/project/operator.py index ea4aa48ce3..ecd54550d7 100644 --- a/src/blenderbim/blenderbim/bim/module/project/operator.py +++ b/src/blenderbim/blenderbim/bim/module/project/operator.py @@ -33,7 +33,9 @@ import ifcopenshell.util.selector import ifcopenshell.util.geolocation import ifcopenshell.util.representation import ifcopenshell.util.element +import ifcopenshell.util.representation import ifcopenshell.util.shape +import ifcopenshell.util.unit import blenderbim.bim.handler import blenderbim.bim.schema import blenderbim.tool as tool diff --git a/src/blenderbim/blenderbim/core/geometry.py b/src/blenderbim/blenderbim/core/geometry.py index f4af512a26..539e47204c 100644 --- a/src/blenderbim/blenderbim/core/geometry.py +++ b/src/blenderbim/blenderbim/core/geometry.py @@ -17,7 +17,7 @@ # along with BlenderBIM Add-on. If not, see . from __future__ import annotations -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Optional, Sequence if TYPE_CHECKING: import bpy @@ -109,11 +109,9 @@ def switch_representation( ) -> None: """Function can switch to representation that wasn't yet assigned to that object. See #2766. - `should_sync_changes_first` - sync ifc representation with current state of `obj.data`; - - `should_reload` - reload `obj.data` from ifc representation; - - `is_global` - replace mesh data for all users of `obj.data`, not just `obj`; + :param should_sync_changes_first: sync ifc representation with current state of `obj.data` + :param should_reload: reload `obj.data` from ifc representation + :param is_global: replace mesh data for all users of `obj.data`, not just `obj` """ if should_sync_changes_first and geometry.is_edited(obj) and not geometry.is_box_representation(representation): @@ -128,7 +126,7 @@ def switch_representation( if not current_obj_data and geometry.is_text_literal(representation): return - use_immediate_repr = apply_openings and getattr(entity, "HasOpenings", None) + use_immediate_repr = apply_openings and bool(getattr(entity, "HasOpenings", None)) use_immediate_repr = use_immediate_repr or geometry.has_material_style_override(entity) if use_immediate_repr: # if it has openings make sure to switch to element's mapped representation @@ -162,15 +160,20 @@ def switch_representation( geometry.clear_cache(entity) -def get_representation_ifc_parameters(geometry, obj=None, should_sync_changes_first=False): +def get_representation_ifc_parameters( + geometry: tool.Geometry, obj: bpy.types.Object, should_sync_changes_first: bool = False +) -> None: geometry.import_representation_parameters(geometry.get_object_data(obj)) -def remove_representation(ifc, geometry, obj=None, representation=None): +def remove_representation( + ifc: tool.Ifc, geometry: tool.Geometry, obj: bpy.types.Object, representation: ifcopenshell.entity_instance +) -> None: """Consider changing obj representation before using the function, otherwise it will replace object with empty.""" element = ifc.get_entity(obj) + assert element element_type = geometry.get_element_type(element) data = None if element_type and (geometry.is_mapped_representation(representation) or geometry.is_type_product(element)): @@ -196,7 +199,11 @@ def remove_representation(ifc, geometry, obj=None, representation=None): geometry.delete_data(data) -def purge_unused_representations(ifc, geometry): +def purge_unused_representations(ifc: tool.Ifc, geometry: tool.Geometry) -> int: + """Purge representations without inverses. + + :return: A number of purged representations. + """ purged_representations = 0 for representation in geometry.get_model_representations(): if ifc.get().get_total_inverses(representation) == 0: @@ -205,29 +212,35 @@ def purge_unused_representations(ifc, geometry): return purged_representations -def select_connection(geometry, connection=None): +def select_connection(geometry: tool.Geometry, connection: ifcopenshell.entity_instance) -> None: geometry.select_connection(connection) -def remove_connection(geometry, connection=None): +def remove_connection(geometry: tool.Geometry, connection: ifcopenshell.entity_instance) -> None: geometry.remove_connection(connection) -def get_similar_openings(ifc, opening): +def get_similar_openings(ifc: tool.Ifc, opening: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]: model = ifc.get() all_openings = model.by_type("IfcOpeningElement") similar_openings = [o for o in all_openings if o.ObjectPlacement == opening.ObjectPlacement and o != opening] return similar_openings -def get_similar_openings_building_objs(ifc, similar_openings): +def get_similar_openings_building_objs( + ifc: tool.Ifc, similar_openings: list[ifcopenshell.entity_instance] +) -> list[bpy.types.Object]: building_objs = [] for similar_opening in similar_openings: building_objs.append(ifc.get_object(similar_opening.VoidsElements[0].RelatingBuildingElement)) return building_objs -def edit_similar_opening_placement(geometry, opening=None, similar_openings=None): +def edit_similar_opening_placement( + geometry: tool.Geometry, + opening: Optional[ifcopenshell.entity_instance] = None, + similar_openings: Sequence[ifcopenshell.entity_instance] = (), +) -> None: if not opening or not similar_openings: return for similar_opening in similar_openings: diff --git a/src/blenderbim/blenderbim/tool/geometry.py b/src/blenderbim/blenderbim/tool/geometry.py index 7dab0f6609..133b19a757 100644 --- a/src/blenderbim/blenderbim/tool/geometry.py +++ b/src/blenderbim/blenderbim/tool/geometry.py @@ -543,6 +543,7 @@ class Geometry(blenderbim.core.tool.Geometry): logger = logging.getLogger("ImportIFC") ifc_import_settings = blenderbim.bim.import_ifc.IfcImportSettings.factory(bpy.context, None, logger) element = tool.Ifc.get_entity(obj) + assert element # Type checker. settings = ifcopenshell.geom.settings() settings.set("weld-vertices", True) settings.set("apply-default-materials", False) diff --git a/src/ifcopenshell-python/ifcopenshell/draw.py b/src/ifcopenshell-python/ifcopenshell/draw.py index 464d0c00f8..4febc110bc 100644 --- a/src/ifcopenshell-python/ifcopenshell/draw.py +++ b/src/ifcopenshell-python/ifcopenshell/draw.py @@ -27,6 +27,7 @@ import ifcopenshell.geom from xml.dom.minidom import parseString from dataclasses import dataclass, fields +from typing import Callable, Sequence import numpy @@ -64,7 +65,13 @@ class draw_settings: unify_inputs: bool = True -def main(settings, files, iterators=None, merge_projection=True, progress_function=DO_NOTHING): +def main( + settings: draw_settings, + files: list[ifcopenshell.file], + iterators: Sequence[ifcopenshell.geom.iterator] = (), + merge_projection: bool = True, + progress_function: Callable = DO_NOTHING, +): geom_settings = ifcopenshell.geom.settings( # when not doing booleans, proper solids from shells isn't a requirement @@ -97,13 +104,6 @@ def main(settings, files, iterators=None, merge_projection=True, progress_functi for it in iterators: it.set_cache(cache) - def yield_from_iterator(it): - if it.initialize(): - while True: - yield it.get() - if not it.next(): - break - # Initialize serializer buffer = ifcopenshell.geom.serializers.buffer() serialiser_settings = ifcopenshell.geom.serializer_settings() @@ -167,7 +167,7 @@ def main(settings, files, iterators=None, merge_projection=True, progress_functi # Loop over iterators for geometric content for i, it in enumerate(iterators): - for elem in yield_from_iterator(it): + for elem in it: sr.write(elem) if elem.type != "IfcSpace": tree.add_element(elem) diff --git a/src/ifcopenshell-python/ifcopenshell/geom/main.py b/src/ifcopenshell-python/ifcopenshell/geom/main.py index 9bcfe80cf9..fc9430bf8a 100644 --- a/src/ifcopenshell-python/ifcopenshell/geom/main.py +++ b/src/ifcopenshell-python/ifcopenshell/geom/main.py @@ -365,6 +365,8 @@ def create_shape( Note that in Python, you must store a reference to the element returned by this function to prevent garbage collection when you access its children. See #1124. + :raises RuntimeError: If failed to process shape. You can turn detailed logging to get more details. + :return: - `inst` is IfcProduct and `repr` provided / None -> ShapeElementType - `inst` is IfcRepresentation and `repr` is None -> ShapeType