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