diff --git a/src/bonsai/bonsai/bim/ifc.py b/src/bonsai/bonsai/bim/ifc.py
index da67773ace..f652abb487 100644
--- a/src/bonsai/bonsai/bim/ifc.py
+++ b/src/bonsai/bonsai/bim/ifc.py
@@ -140,6 +140,8 @@ class IfcStore:
def update_cache():
if not IfcStore.cache:
return
+ assert IfcStore.cache_path
+ assert IfcStore.file
ifc_key = IfcStore.path + IfcStore.file.wrapped_data.header.file_name.time_stamp
ifc_hash = hashlib.md5(ifc_key.encode("utf-8")).hexdigest()
new_cache_path = os.path.join(bpy.context.scene.BIMProperties.data_dir, "cache", f"{ifc_hash}.h5")
diff --git a/src/bonsai/bonsai/core/debug.py b/src/bonsai/bonsai/core/debug.py
index 94f78d4a9f..ccf569798c 100644
--- a/src/bonsai/bonsai/core/debug.py
+++ b/src/bonsai/bonsai/core/debug.py
@@ -17,15 +17,24 @@
# along with Bonsai. If not, see .
-def parse_express(debug, filename):
+from __future__ import annotations
+from typing import TYPE_CHECKING, Optional
+
+if TYPE_CHECKING:
+ import bpy
+ import ifcopenshell
+ import bonsai.tool as tool
+
+
+def parse_express(debug: tool.Debug, filename: str) -> None:
debug.add_schema_identifier(debug.load_express(filename))
-def purge_hdf5_cache(debug):
+def purge_hdf5_cache(debug: tool.Debug) -> None:
debug.purge_hdf5_cache()
-def purge_unused_elements(ifc, debug, ifc_class):
+def purge_unused_elements(ifc, debug: tool.Debug, ifc_class: str) -> int:
ifc_file = ifc.get()
unused_elements = [i for i in ifc_file.by_type(ifc_class) if ifc_file.get_total_inverses(i) == 0]
unused_elements_amount = len(unused_elements)
diff --git a/src/bonsai/bonsai/core/geometry.py b/src/bonsai/bonsai/core/geometry.py
index 73625af636..7476c56381 100644
--- a/src/bonsai/bonsai/core/geometry.py
+++ b/src/bonsai/bonsai/core/geometry.py
@@ -122,6 +122,7 @@ def switch_representation(
return
entity = ifc.get_entity(obj)
+ assert entity
current_obj_data = geometry.get_object_data(obj)
if not current_obj_data and geometry.is_text_literal(representation):
diff --git a/src/bonsai/bonsai/tool/debug.py b/src/bonsai/bonsai/tool/debug.py
index 17125a2113..41923bd908 100644
--- a/src/bonsai/bonsai/tool/debug.py
+++ b/src/bonsai/bonsai/tool/debug.py
@@ -19,31 +19,37 @@
import os
import bpy
import ifcopenshell.express
+import ifcopenshell.express.schema
+import ifcopenshell.express.schema_class
+import ifcopenshell.util.element
import bonsai.core.tool
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore
+from mathutils import Vector
class Debug(bonsai.core.tool.Debug):
@classmethod
- def add_schema_identifier(cls, schema):
+ def add_schema_identifier(cls, schema: ifcopenshell.express.schema_class.SchemaClass) -> None:
IfcStore.schema_identifiers.append(schema.schema_name)
@classmethod
- def load_express(cls, filename):
+ def load_express(cls, filename: str) -> ifcopenshell.express.schema_class.SchemaClass:
schema = ifcopenshell.express.parse(filename)
ifcopenshell.register_schema(schema)
return schema
@classmethod
- def purge_hdf5_cache(cls):
+ def purge_hdf5_cache(cls) -> None:
cache_dir = os.path.join(bpy.context.scene.BIMProperties.data_dir, "cache")
filelist = [f for f in os.listdir(cache_dir) if f.endswith(".h5")]
for f in filelist:
os.remove(os.path.join(cache_dir, f))
@classmethod
- def debug_geometry(cls, verts=[], edges=[], name="Debug"):
+ def debug_geometry(
+ cls, verts: list[Vector] = [], edges: list[tuple[int, int]] = [], name: str = "Debug"
+ ) -> bpy.types.Object:
mesh = bpy.data.meshes.new("Debug")
mesh.from_pydata(verts, edges, [])
obj = bpy.data.objects.new(name, mesh)
@@ -51,13 +57,13 @@ class Debug(bonsai.core.tool.Debug):
return obj
@classmethod
- def remove_unused_elements(cls, elements):
+ def remove_unused_elements(cls, elements: list[ifcopenshell.entity_instance]) -> None:
ifc_file = tool.Ifc.get()
for element in elements:
ifcopenshell.util.element.remove_deep2(ifc_file, element)
@classmethod
- def print_unused_elements_stats(cls, requested_ifc_class="", ignore_classes=tuple()):
+ def print_unused_elements_stats(cls, requested_ifc_class: str = "", ignore_classes: tuple[str] = tuple()) -> int:
ifc_file = tool.Ifc.get()
# get list of ifc classes used in model
diff --git a/src/bonsai/test/bim/test_feature.py b/src/bonsai/test/bim/test_feature.py
index c0d9438755..0d3194154f 100644
--- a/src/bonsai/test/bim/test_feature.py
+++ b/src/bonsai/test/bim/test_feature.py
@@ -33,7 +33,7 @@ from pytest_bdd import scenarios, given, when, then, parsers
from mathutils import Vector
from math import radians
from pathlib import Path
-from typing import Union
+from typing import Union, Any
scenarios("feature")
@@ -49,18 +49,18 @@ webbrowser.open = lambda x: True
class PanelSpy:
- def __init__(self, panel):
+ def __init__(self, panel: type[bpy.types.Panel]):
self.is_spy_dirty = True
self.panel = panel
def refresh_spy(self):
if self.is_spy_dirty:
self.is_spy_dirty = False
- self.spied_attr = None
- self.spied_labels = []
- self.spied_props = []
- self.spied_operators = []
- self.spied_lists = []
+ self.spied_attr: Union[str, None] = None
+ self.spied_labels: list[str] = []
+ self.spied_props: list[dict[str, Any]] = []
+ self.spied_operators: list[dict[str, Any]] = []
+ self.spied_lists: list[dict[str, Any]] = []
self.panel.draw(self, bpy.context)
def __getattr__(self, attr):
@@ -91,6 +91,7 @@ class PanelSpy:
return self
elif self.spied_attr == "prop":
props, name = args
+ props: bpy.types.bpy_struct
text = kwargs.get("text", props.bl_rna.properties[name].name)
icon = kwargs.get("icon", None)
prop_type = props.bl_rna.properties[name].type
@@ -152,7 +153,7 @@ class TemplateListSpy:
panel_name_cache = {}
-panel_spy = None
+panel_spy: PanelSpy = None
def replace_variables(value):
diff --git a/src/ifcopenshell-python/ifcopenshell/express/__init__.py b/src/ifcopenshell-python/ifcopenshell/express/__init__.py
index d7a0ceebc4..91aa35fd82 100644
--- a/src/ifcopenshell-python/ifcopenshell/express/__init__.py
+++ b/src/ifcopenshell-python/ifcopenshell/express/__init__.py
@@ -16,9 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see .
+from __future__ import annotations
import os
import sys
import subprocess
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ import schema_class
d = os.path.abspath(os.path.dirname(__file__))
sys.path.append(d)
@@ -30,8 +35,9 @@ if not os.path.exists(exp_parser_fn):
subprocess.call([sys.executable, "bootstrap.py"], cwd=d, stdout=f)
-def parse(fn):
+def parse(fn: str) -> schema_class.SchemaClass:
import express_parser
import schema_class
+
mapping = express_parser.parse(fn)
return schema_class.SchemaClass(mapping, schema_class.LateBoundSchemaInstantiator).code