From 721466c4293c9c7c477792c654554c98684dae29 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Thu, 25 Apr 2024 11:24:42 +0500 Subject: [PATCH] typing --- src/blenderbim/blenderbim/bim/import_ifc.py | 1 + .../bim/module/boundary/operator.py | 1 + .../blenderbim/bim/module/drawing/sheeter.py | 46 +++++++++++-------- src/blenderbim/blenderbim/core/drawing.py | 5 +- src/blenderbim/blenderbim/tool/drawing.py | 2 +- src/blenderbim/test/core/bootstrap.py | 17 +++---- .../api/document/edit_information.py | 11 ++++- .../api/document/edit_reference.py | 11 ++++- src/ifcopenshell-python/ifcopenshell/file.py | 2 +- .../ifcopenshell/util/shape_builder.py | 4 ++ 10 files changed, 66 insertions(+), 34 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index fb7c07d7cd..481e23817e 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -34,6 +34,7 @@ import ifcopenshell.util.element import ifcopenshell.util.geolocation import ifcopenshell.util.placement import ifcopenshell.util.representation +import ifcopenshell.util.shape import blenderbim.tool as tool import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper from itertools import chain, accumulate diff --git a/src/blenderbim/blenderbim/bim/module/boundary/operator.py b/src/blenderbim/blenderbim/bim/module/boundary/operator.py index 6a20852f06..d0b90221f5 100644 --- a/src/blenderbim/blenderbim/bim/module/boundary/operator.py +++ b/src/blenderbim/blenderbim/bim/module/boundary/operator.py @@ -20,6 +20,7 @@ import bpy import bmesh import logging import shapely +import shapely.ops import mathutils import numpy as np import multiprocessing diff --git a/src/blenderbim/blenderbim/bim/module/drawing/sheeter.py b/src/blenderbim/blenderbim/bim/module/drawing/sheeter.py index 55de457f39..45e7d0883c 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/sheeter.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/sheeter.py @@ -41,7 +41,7 @@ class SheetBuilder: self.data_dir = None self.scale = "NTS" - def create(self, layout_path, titleblock_name): + def create(self, layout_path: str, titleblock_name: str) -> None: root = ET.Element("svg") root.attrib["xmlns"] = "http://www.w3.org/2000/svg" root.attrib["xmlns:xlink"] = "http://www.w3.org/1999/xlink" @@ -76,7 +76,12 @@ class SheetBuilder: with open(layout_path, "w") as f: f.write(minidom.parseString(ET.tostring(root)).toprettyxml(indent=" ")) - def add_drawing(self, reference, drawing, sheet): + def add_drawing( + self, + reference: ifcopenshell.entity_instance, + drawing: ifcopenshell.entity_instance, + sheet: ifcopenshell.entity_instance, + ) -> None: filename = drawing.Name layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT") layout_dir = os.path.dirname(layout_path) @@ -131,7 +136,7 @@ class SheetBuilder: ) layout_tree.write(layout_path) - def update_sheet_drawing_sizes(self, sheet): + def update_sheet_drawing_sizes(self, sheet: ifcopenshell.entity_instance) -> None: ET.register_namespace("", "http://www.w3.org/2000/svg") layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT") @@ -171,7 +176,7 @@ class SheetBuilder: layout_tree.write(layout_path) - def remove_drawing(self, reference, sheet): + def remove_drawing(self, reference: ifcopenshell.entity_instance, sheet: ifcopenshell.entity_instance) -> None: ET.register_namespace("", "http://www.w3.org/2000/svg") layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT") @@ -187,7 +192,12 @@ class SheetBuilder: layout_tree.write(layout_path) - def add_document(self, reference, document, sheet): + def add_document( + self, + reference: ifcopenshell.entity_instance, + document: ifcopenshell.entity_instance, + sheet: ifcopenshell.entity_instance, + ) -> None: view_path = tool.Drawing.get_path_with_ext(tool.Drawing.get_document_uri(document), "svg") if not os.path.exists(view_path): tool.Drawing.create_svg_document(document) @@ -224,7 +234,7 @@ class SheetBuilder: ) layout_tree.write(layout_path) - def add_view_title(self, x, y, parent, layout_dir): + def add_view_title(self, x: float, y: float, parent: ET.Element, layout_dir: str) -> None: title_path = os.path.join(layout_dir, "assets", "view-title.svg") os.makedirs(os.path.dirname(title_path), exist_ok=True) if not os.path.exists(title_path): @@ -241,7 +251,7 @@ class SheetBuilder: title.attrib["width"] = str(self.convert_to_mm(title_root.attrib.get("width"))) title.attrib["height"] = str(self.convert_to_mm(title_root.attrib.get("height"))) - def build(self, sheet): + def build(self, sheet: ifcopenshell.entity_instance) -> dict: self.references = {"SHEET": None, "RASTER": []} layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT") @@ -272,7 +282,7 @@ class SheetBuilder: return self.references - def build_titleblock(self, root, sheet): + def build_titleblock(self, root: ET.Element, sheet: ifcopenshell.entity_instance) -> None: titleblock = root.findall('{http://www.w3.org/2000/svg}g[@data-type="titleblock"]')[0] image = titleblock.findall("{http://www.w3.org/2000/svg}image")[0] g = self.parse_embedded_svg(image, sheet.get_info()) @@ -285,7 +295,7 @@ class SheetBuilder: titleblock.append(g) titleblock.remove(image) - def ensure_drawing_unique_styles(self, svg, drawing_id): + def ensure_drawing_unique_styles(self, svg: ET.Element, drawing_id: int) -> ET.Element: """ensures all drawing's classes and ids will be unique for the whole sheet by adding `drawing_id` based prefix """ @@ -313,7 +323,7 @@ class SheetBuilder: brackets_level -= 1 text += l - def replace_urls(text): + def replace_urls(text: str) -> str: """replace urls `url(#marker)` with `url(#prefix-marker)` since `url(#marker.prefix)` doesn't seem to work """ @@ -343,7 +353,7 @@ class SheetBuilder: return svg - def build_drawings(self, root, sheet): + def build_drawings(self, root: ET.Element, sheet: ifcopenshell.entity_instance): for view in root.findall('{http://www.w3.org/2000/svg}g[@data-type="drawing"]'): drawing_id = int(view.attrib["data-id"]) try: @@ -390,7 +400,7 @@ class SheetBuilder: for image in images: view.remove(image) - def build_documents(self, root, sheet): + def build_documents(self, root: ET.Element, sheet: ifcopenshell.entity_instance) -> None: schedules = root.findall('{http://www.w3.org/2000/svg}g[@data-type="schedule"]') references = root.findall('{http://www.w3.org/2000/svg}g[@data-type="reference"]') documents = schedules + references @@ -427,10 +437,10 @@ class SheetBuilder: for image in images: view.remove(image) - def get_href(self, element): - return urllib.parse.unquote(element.attrib.get("{http://www.w3.org/1999/xlink}href")).replace('\\','/') + def get_href(self, element: ET.Element) -> str: + return urllib.parse.unquote(element.attrib.get("{http://www.w3.org/1999/xlink}href")).replace("\\", "/") - def parse_embedded_svg(self, image, data): + def parse_embedded_svg(self, image: ET.Element, data: dict) -> ET.Element: group = ET.Element("g") group.attrib["transform"] = "translate({},{})".format( self.convert_to_mm(image.attrib.get("x")), self.convert_to_mm(image.attrib.get("y")) @@ -466,7 +476,7 @@ class SheetBuilder: group.append(child) return group - def change_titleblock(self, sheet, titleblock_name): + def change_titleblock(self, sheet: ifcopenshell.entity_instance, titleblock_name: str) -> None: ootb_titleblock_path = os.path.join(self.data_dir, "templates", "titleblocks", titleblock_name + ".svg") titleblock_path = tool.Drawing.get_default_titleblock_path(titleblock_name) sheet_path = tool.Drawing.get_document_uri(sheet, "LAYOUT") @@ -499,7 +509,7 @@ class SheetBuilder: sheet_tree.write(sheet_path) - def convert_to_mm(self, value): + def convert_to_mm(self, value: str) -> float: # CSS is what defines these possibilities # https://www.w3.org/TR/SVG/refs.html#ref-css-values-3 # https://www.w3.org/TR/css-values-3/#absolute-lengths @@ -520,5 +530,5 @@ class SheetBuilder: return float(value[0:-2]) * (1 / 96) * 2.54 * 10 return float(value) - def mm_to_px(self, value): + def mm_to_px(self, value: float) -> float: return (value / 25.4) * 96 diff --git a/src/blenderbim/blenderbim/core/drawing.py b/src/blenderbim/blenderbim/core/drawing.py index b2c1b890bf..b61f469bea 100644 --- a/src/blenderbim/blenderbim/core/drawing.py +++ b/src/blenderbim/blenderbim/core/drawing.py @@ -17,6 +17,7 @@ # along with BlenderBIM Add-on. If not, see . from pathlib import Path +import ifcopenshell def enable_editing_text(drawing, obj=None): @@ -66,7 +67,7 @@ def disable_editing_sheets(drawing): drawing.disable_editing_sheets() -def add_sheet(ifc, drawing, titleblock=None): +def add_sheet(ifc, drawing, titleblock: ifcopenshell.entity_instance): sheet = ifc.run("document.add_information") layout = ifc.run("document.add_reference", information=sheet) titleblock_reference = ifc.run("document.add_reference", information=sheet) @@ -117,7 +118,7 @@ def remove_sheet(ifc, drawing, sheet=None): drawing.import_sheets() -def rename_sheet(ifc, drawing, sheet=None, identification=None, name=None): +def rename_sheet(ifc, drawing, sheet: ifcopenshell.entity_instance, identification: str, name: str) -> None: if ifc.get_schema() == "IFC2X3": attributes = {"DocumentId": identification, "Name": name} else: diff --git a/src/blenderbim/blenderbim/tool/drawing.py b/src/blenderbim/blenderbim/tool/drawing.py index 90b6cd211a..b013e62854 100644 --- a/src/blenderbim/blenderbim/tool/drawing.py +++ b/src/blenderbim/blenderbim/tool/drawing.py @@ -240,7 +240,7 @@ class Drawing(blenderbim.core.tool.Drawing): ) @classmethod - def create_svg_sheet(cls, document, titleblock): + def create_svg_sheet(cls, document: ifcopenshell.entity_instance, titleblock: str) -> str: sheet_builder = sheeter.SheetBuilder() sheet_builder.data_dir = bpy.context.scene.BIMProperties.data_dir uri = cls.get_document_uri(document, "LAYOUT") diff --git a/src/blenderbim/test/core/bootstrap.py b/src/blenderbim/test/core/bootstrap.py index 3b48e66c80..6ec9c206ce 100644 --- a/src/blenderbim/test/core/bootstrap.py +++ b/src/blenderbim/test/core/bootstrap.py @@ -19,6 +19,7 @@ import json import pytest import blenderbim.core.tool +from typing import Any, Self, Optional @pytest.fixture @@ -241,12 +242,12 @@ def voider(): class Prophecy: def __init__(self, cls): self.subject = cls - self.predictions = [] - self.calls = [] - self.return_values = {} - self.should_call = None + self.predictions: list[dict] = [] + self.calls: list[dict] = [] + self.return_values: dict[str, Any] = {} + self.should_call: Optional[dict] = None - def __getattr__(self, attr): + def __getattr__(self, attr: str): if not hasattr(self.subject, attr): raise AttributeError(f"Prophecy {self.subject} has no attribute {attr}") @@ -270,12 +271,12 @@ class Prophecy: self.predictions.append({"type": "SHOULD_BE_CALLED", "number": number, "call": self.should_call}) return self - def will_return(self, value): + def will_return(self, value: Any) -> Self: key = json.dumps(self.should_call, sort_keys=True) self.return_values[key] = value return self - def verify(self): + def verify(self) -> None: predicted_calls = [] for prediction in self.predictions: predicted_calls.append(prediction["call"]) @@ -285,7 +286,7 @@ class Prophecy: if call not in predicted_calls: raise Exception(f"Unpredicted call: {call}") - def verify_should_be_called(self, prediction): + def verify_should_be_called(self, prediction: dict) -> None: if prediction["number"]: count = self.calls.count(prediction["call"]) if count != prediction["number"]: diff --git a/src/ifcopenshell-python/ifcopenshell/api/document/edit_information.py b/src/ifcopenshell-python/ifcopenshell/api/document/edit_information.py index 5d2665741b..1d7af0c1b8 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/document/edit_information.py +++ b/src/ifcopenshell-python/ifcopenshell/api/document/edit_information.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 +from typing import Any, Optional class Usecase: - def __init__(self, file, information=None, attributes=None): + def __init__( + self, + file: ifcopenshell.file, + information: ifcopenshell.entity_instance, + attributes: Optional[dict[str, Any]] = None, + ): """Edits the attributes of an IfcDocumentInformation For more information about the attributes and data types of an @@ -44,6 +51,6 @@ class Usecase: self.file = file self.settings = {"information": information, "attributes": attributes or {}} - def execute(self): + def execute(self) -> None: for name, value in self.settings["attributes"].items(): setattr(self.settings["information"], name, value) diff --git a/src/ifcopenshell-python/ifcopenshell/api/document/edit_reference.py b/src/ifcopenshell-python/ifcopenshell/api/document/edit_reference.py index 98d4a0233a..538c8d2854 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/document/edit_reference.py +++ b/src/ifcopenshell-python/ifcopenshell/api/document/edit_reference.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 +from typing import Any, Optional class Usecase: - def __init__(self, file, reference=None, attributes=None): + def __init__( + self, + file: ifcopenshell.file, + reference: ifcopenshell.entity_instance, + attributes: Optional[dict[str, Any]] = None, + ): """Edits the attributes of an IfcDocumentReference For more information about the attributes and data types of an @@ -47,6 +54,6 @@ class Usecase: self.file = file self.settings = {"reference": reference, "attributes": attributes or {}} - def execute(self): + def execute(self) -> None: for name, value in self.settings["attributes"].items(): setattr(self.settings["reference"], name, value) diff --git a/src/ifcopenshell-python/ifcopenshell/file.py b/src/ifcopenshell-python/ifcopenshell/file.py index d5446d731e..e87663612b 100644 --- a/src/ifcopenshell-python/ifcopenshell/file.py +++ b/src/ifcopenshell-python/ifcopenshell/file.py @@ -259,7 +259,7 @@ class file(object): self.history_size = 64 self.history = [] self.future = [] - self.transaction = None + self.transaction: Optional[Transaction] = None import weakref diff --git a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py index dd1104c780..13efca8da5 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py +++ b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py @@ -18,8 +18,12 @@ import numpy as np import collections +import collections.abc import ifcopenshell import ifcopenshell.api +import ifcopenshell.util.element +import ifcopenshell.util.representation +import ifcopenshell.util.unit from math import cos, sin, pi, tan, radians, degrees, atan, sqrt, ceil from typing import List, Tuple, Type, Union from itertools import chain