diff --git a/src/bonsai/bonsai/bim/helper.py b/src/bonsai/bonsai/bim/helper.py
index 76ec3e70f5..f36b50291c 100644
--- a/src/bonsai/bonsai/bim/helper.py
+++ b/src/bonsai/bonsai/bim/helper.py
@@ -152,7 +152,7 @@ def import_attribute(
if isinstance(data_type, tuple) or data_type == "entity":
callback(attribute.name(), None, data) if callback else None
return
- new = props.add()
+ new: bonsai.bim.prop.Attribute = props.add()
new.name = attribute.name()
new.is_null = data[attribute.name()] is None
new.is_optional = attribute.optional()
diff --git a/src/bonsai/bonsai/bim/module/library/prop.py b/src/bonsai/bonsai/bim/module/library/prop.py
index 27add1795d..d3e00c710c 100644
--- a/src/bonsai/bonsai/bim/module/library/prop.py
+++ b/src/bonsai/bonsai/bim/module/library/prop.py
@@ -42,7 +42,16 @@ class LibraryReference(PropertyGroup):
class BIMLibraryProperties(PropertyGroup):
- editing_mode: StringProperty(name="Editing Mode")
+ editing_mode: EnumProperty(
+ name="Editing Mode",
+ items=(
+ ("-", "-", ""),
+ ("LIBRARY", "LIBRARY", ""),
+ ("REFERENCES", "REFERENCES", ""),
+ ("REFERENCE", "REFERENCE", ""),
+ ),
+ default="-",
+ )
library_attributes: CollectionProperty(name="Library Attributes", type=Attribute)
active_library_id: IntProperty(name="Active Library Id")
reference_attributes: CollectionProperty(name="Library Attributes", type=Attribute)
diff --git a/src/bonsai/bonsai/bim/module/pset/prop.py b/src/bonsai/bonsai/bim/module/pset/prop.py
index fc91cc198e..88491bf32a 100644
--- a/src/bonsai/bonsai/bim/module/pset/prop.py
+++ b/src/bonsai/bonsai/bim/module/pset/prop.py
@@ -38,8 +38,7 @@ from bpy.props import (
FloatVectorProperty,
CollectionProperty,
)
-from typing import Union, Literal
-
+from typing import Union, Literal, TYPE_CHECKING, get_args
psetnames = {}
qtonames = {}
@@ -231,13 +230,18 @@ class IfcPropertyEnumeratedValue(PropertyGroup):
enumerated_values: CollectionProperty(type=Attribute)
+IfcPropertyValueType = Literal["IfcPropertySingleValue", "IfcPropertyEnumeratedValue"]
+
+
class IfcProperty(PropertyGroup):
metadata: PointerProperty(type=Attribute)
- value_type: EnumProperty(
- items=[(v, v, v) for v in ("IfcPropertySingleValue", "IfcPropertyEnumeratedValue")], name="Value Type"
- )
+ value_type: EnumProperty(items=[(v, v, v) for v in get_args(IfcPropertyValueType)], name="Value Type")
enumerated_value: PointerProperty(type=IfcPropertyEnumeratedValue)
+ if TYPE_CHECKING:
+ metadata: Attribute
+ value_type: IfcPropertyValueType
+
class PsetProperties(PropertyGroup):
active_pset_id: IntProperty(name="Active Pset ID")
diff --git a/src/bonsai/bonsai/bim/module/pset/ui.py b/src/bonsai/bonsai/bim/module/pset/ui.py
index 93d087c54e..fe40ab7aeb 100644
--- a/src/bonsai/bonsai/bim/module/pset/ui.py
+++ b/src/bonsai/bonsai/bim/module/pset/ui.py
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see .
+from __future__ import annotations
import bpy
import bonsai.tool as tool
from bpy.types import Panel
@@ -35,21 +36,23 @@ from bonsai.bim.module.pset.data import (
WorkSchedulePsetsData,
)
from bonsai.bim.module.material.data import ObjectMaterialData
-from typing import Any, Optional
+from typing import Any, Optional, TYPE_CHECKING
+from typing_extensions import assert_never
+
+if TYPE_CHECKING:
+ from bonsai.bim.module.pset.prop import IfcProperty
-def draw_property(
- prop: bpy.types.PropertyGroup, layout: bpy.types.UILayout, copy_operator: Optional[str] = None
-) -> None:
+def draw_property(prop: IfcProperty, layout: bpy.types.UILayout, copy_operator: Optional[str] = None) -> None:
if prop.value_type == "IfcPropertySingleValue":
draw_single_property(prop, layout, copy_operator)
elif prop.value_type == "IfcPropertyEnumeratedValue":
draw_enumerated_property(prop, layout, copy_operator)
+ else:
+ assert_never(prop.value_type)
-def draw_single_property(
- prop: bpy.types.PropertyGroup, layout: bpy.types.UILayout, copy_operator: Optional[str] = None
-) -> None:
+def draw_single_property(prop: IfcProperty, layout: bpy.types.UILayout, copy_operator: Optional[str] = None) -> None:
value_name = prop.metadata.get_value_name(display_only=True)
if not value_name:
layout.label(text=prop["Name"])
diff --git a/src/bonsai/bonsai/bim/module/structural/data.py b/src/bonsai/bonsai/bim/module/structural/data.py
index 9a55a826fb..6e4c63b027 100644
--- a/src/bonsai/bonsai/bim/module/structural/data.py
+++ b/src/bonsai/bonsai/bim/module/structural/data.py
@@ -43,8 +43,8 @@ class LoadGroupDecorationData:
cls.is_loaded = True
@classmethod
- def load_groups_to_show(cls):
- ret = []
+ def load_groups_to_show(cls) -> list[tuple[str, str, str]]:
+ ret: list[tuple[str, str, str]] = []
abrv = {
"LOAD_CASE": "L.Case: ",
"LOAD_COMBINATION": "L.Comb: ",
@@ -64,7 +64,7 @@ class LoadGroupDecorationData:
for subgoup in [sg for sg in item if sg.is_a("IfcStructuralLoadGroup")]:
ret.append((str(subgoup.id()), ". " + abrv[subgoup.PredefinedType] + subgoup.Name, ""))
- if props.activity_type == "External Reaction":
+ elif props.activity_type == "External Reaction":
groups = m.HasResults or []
for g in groups:
result_name = g.ResultForLoadGroup.Name or ""
diff --git a/src/bonsai/bonsai/core/library.py b/src/bonsai/bonsai/core/library.py
index be873fb827..3f0e454c94 100644
--- a/src/bonsai/bonsai/core/library.py
+++ b/src/bonsai/bonsai/core/library.py
@@ -16,35 +16,43 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see .
+from __future__ import annotations
+from typing import TYPE_CHECKING, Optional
-def add_library(ifc):
+if TYPE_CHECKING:
+ import bpy
+ import ifcopenshell
+ import bonsai.tool as tool
+
+
+def add_library(ifc: tool.Ifc) -> ifcopenshell.entity_instance:
return ifc.run("library.add_library", name="Unnamed")
-def remove_library(ifc, library=None):
+def remove_library(ifc: tool.Ifc, library: ifcopenshell.entity_instance) -> None:
ifc.run("library.remove_library", library=library)
-def enable_editing_library_references(library_tool, library=None):
+def enable_editing_library_references(library_tool: tool.Library, library: ifcopenshell.entity_instance) -> None:
library_tool.set_editing_mode("REFERENCES")
library_tool.set_active_library(library)
library_tool.import_references(library)
-def disable_editing_library_references(library):
+def disable_editing_library_references(library: tool.Library) -> None:
library.clear_editing_mode()
-def enable_editing_library(library):
+def enable_editing_library(library: tool.Library) -> None:
library.set_editing_mode("LIBRARY")
library.import_library_attributes(library.get_active_library())
-def disable_editing_library(library):
+def disable_editing_library(library: tool.Library) -> None:
library.set_editing_mode("REFERENCES")
-def edit_library(ifc, library):
+def edit_library(ifc: tool.Ifc, library: tool.Library) -> None:
library.set_editing_mode("REFERENCES")
active_library = library.get_active_library()
attributes = library.export_library_attributes()
@@ -52,29 +60,29 @@ def edit_library(ifc, library):
library.import_references(active_library)
-def add_library_reference(ifc, library):
+def add_library_reference(ifc: tool.Ifc, library: tool.Library) -> ifcopenshell.entity_instance:
active_library = library.get_active_library()
reference = ifc.run("library.add_reference", library=active_library)
library.import_references(active_library)
return reference
-def remove_library_reference(ifc, library, reference=None):
+def remove_library_reference(ifc: tool.Ifc, library: tool.Library, reference: ifcopenshell.entity_instance) -> None:
ifc.run("library.remove_reference", reference=reference)
library.import_references(library.get_active_library())
-def enable_editing_library_reference(library, reference=None):
+def enable_editing_library_reference(library: tool.Library, reference: ifcopenshell.entity_instance) -> None:
library.set_editing_mode("REFERENCE")
library.set_active_reference(reference)
library.import_reference_attributes(reference)
-def disable_editing_library_reference(library):
+def disable_editing_library_reference(library: tool.Library) -> None:
library.set_editing_mode("REFERENCES")
-def edit_library_reference(ifc, library):
+def edit_library_reference(ifc: tool.Ifc, library: tool.Library) -> None:
library.set_editing_mode("REFERENCES")
active_reference = library.get_active_reference()
attributes = library.export_reference_attributes()
@@ -82,9 +90,9 @@ def edit_library_reference(ifc, library):
library.import_references(library.get_active_library())
-def assign_library_reference(ifc, obj=None, reference=None):
+def assign_library_reference(ifc: tool.Ifc, obj: bpy.types.Object, reference: ifcopenshell.entity_instance) -> None:
ifc.run("library.assign_reference", products=[ifc.get_entity(obj)], reference=reference)
-def unassign_library_reference(ifc, obj=None, reference=None):
+def unassign_library_reference(ifc: tool.Ifc, obj: bpy.types.Object, reference: ifcopenshell.entity_instance) -> None:
ifc.run("library.unassign_reference", products=[ifc.get_entity(obj)], reference=reference)
diff --git a/src/bonsai/bonsai/core/structural.py b/src/bonsai/bonsai/core/structural.py
index 704e974da9..af092e1034 100644
--- a/src/bonsai/bonsai/core/structural.py
+++ b/src/bonsai/bonsai/core/structural.py
@@ -16,35 +16,48 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see .
+from __future__ import annotations
+from typing import TYPE_CHECKING, Optional, Union
-def add_structural_analysis_model(ifc, structural):
+if TYPE_CHECKING:
+ import bpy
+ import ifcopenshell
+ import bonsai.tool as tool
+
+
+def add_structural_analysis_model(ifc: tool.Ifc, structural: tool.Structural) -> ifcopenshell.entity_instance:
result = ifc.run("structural.add_structural_analysis_model")
structural.load_structural_analysis_models()
structural.ensure_representation_contexts()
return result
-def assign_structural_analysis_model(ifc, structural, product=None, structural_analysis_model=None):
- product = structural.get_product_or_active_object(product)
+def assign_structural_analysis_model(
+ ifc: tool.Ifc,
+ structural: tool.Structural,
+ product: str,
+ structural_analysis_model: Union[int, None],
+) -> None:
+ product_ = structural.get_product_or_active_object(product)
if structural_analysis_model and product:
ifc.run(
"structural.assign_structural_analysis_model",
**{
- "product": ifc.get().by_id(product.BIMObjectProperties.ifc_definition_id),
+ "product": ifc.get().by_id(product_.BIMObjectProperties.ifc_definition_id),
"structural_analysis_model": ifc.get().by_id(structural_analysis_model),
},
)
-def disable_editing_structural_analysis_model(structural):
+def disable_editing_structural_analysis_model(structural: tool.Structural) -> None:
structural.disable_editing_structural_analysis_model()
-def disable_structural_analysis_model_editing_ui(structural):
+def disable_structural_analysis_model_editing_ui(structural: tool.Structural) -> None:
structural.disable_structural_analysis_model_editing_ui()
-def edit_structural_analysis_model(ifc, structural):
+def edit_structural_analysis_model(ifc: tool.Ifc, structural: tool.Structural) -> None:
attributes = structural.get_structural_analysis_model_attributes()
ifc.run(
"structural.edit_structural_analysis_model",
@@ -57,26 +70,28 @@ def edit_structural_analysis_model(ifc, structural):
structural.disable_editing_structural_analysis_model()
-def enable_editing_structural_analysis_model(structural, model=None):
+def enable_editing_structural_analysis_model(structural: tool.Structural, model: Union[int, None]) -> None:
structural.enable_editing_structural_analysis_model(model)
-def enable_structural_analysis_model_editing_ui(structural):
+def enable_structural_analysis_model_editing_ui(structural: tool.Structural) -> None:
structural.enable_structural_analysis_model_editing_ui()
-def load_structural_analysis_model_attributes(structural, model=None):
+def load_structural_analysis_model_attributes(structural: tool.Structural, model: Union[int, None]) -> None:
data = structural.get_ifc_structural_analysis_model_attributes(model)
+ if data is None:
+ return
structural.load_structural_analysis_model_attributes(data)
-def load_structural_analysis_models(structural):
+def load_structural_analysis_models(structural: tool.Structural) -> None:
structural.load_structural_analysis_models()
structural.enable_structural_analysis_model_editing_ui()
# structural.disable_editing_structural_analysis_model()
-def remove_structural_analysis_model(ifc, structural, model=None):
+def remove_structural_analysis_model(ifc: tool.Ifc, structural: tool.Structural, model: int) -> None:
ifc.run(
"structural.remove_structural_analysis_model",
**{"structural_analysis_model": ifc.get().by_id(model)},
@@ -84,13 +99,18 @@ def remove_structural_analysis_model(ifc, structural, model=None):
structural.load_structural_analysis_models()
-def unassign_structural_analysis_model(ifc, structural, product=None, structural_analysis_model=None):
- product = structural.get_product_or_active_object(product)
+def unassign_structural_analysis_model(
+ ifc: tool.Ifc,
+ structural: tool.Structural,
+ product: str,
+ structural_analysis_model: Union[int, None],
+) -> None:
+ product_ = structural.get_product_or_active_object(product)
if structural_analysis_model and product:
ifc.run(
"structural.unassign_structural_analysis_model",
**{
- "product": ifc.get().by_id(product.BIMObjectProperties.ifc_definition_id),
+ "product": ifc.get().by_id(product_.BIMObjectProperties.ifc_definition_id),
"structural_analysis_model": ifc.get().by_id(structural_analysis_model),
},
)
diff --git a/src/bonsai/bonsai/tool/library.py b/src/bonsai/bonsai/tool/library.py
index a3a49df986..9199a4d4e5 100644
--- a/src/bonsai/bonsai/tool/library.py
+++ b/src/bonsai/bonsai/tool/library.py
@@ -16,48 +16,51 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see .
+import ifcopenshell
import bpy
+import bonsai.bim.helper
import bonsai.core.tool
import bonsai.tool as tool
+from typing import Literal, Any, Union
class Library(bonsai.core.tool.Library):
@classmethod
- def clear_editing_mode(cls):
- bpy.context.scene.BIMLibraryProperties.editing_mode = ""
+ def clear_editing_mode(cls) -> None:
+ bpy.context.scene.BIMLibraryProperties.editing_mode = "-"
@classmethod
- def export_library_attributes(cls):
+ def export_library_attributes(cls) -> dict[str, Any]:
props = bpy.context.scene.BIMLibraryProperties
return bonsai.bim.helper.export_attributes(props.library_attributes)
@classmethod
- def export_reference_attributes(cls):
+ def export_reference_attributes(cls) -> dict[str, Any]:
props = bpy.context.scene.BIMLibraryProperties
return bonsai.bim.helper.export_attributes(props.reference_attributes)
@classmethod
- def get_active_library(cls):
+ def get_active_library(cls) -> ifcopenshell.entity_instance:
return tool.Ifc.get().by_id(bpy.context.scene.BIMLibraryProperties.active_library_id)
@classmethod
- def get_active_reference(cls):
+ def get_active_reference(cls) -> ifcopenshell.entity_instance:
return tool.Ifc.get().by_id(bpy.context.scene.BIMLibraryProperties.active_reference_id)
@classmethod
- def import_library_attributes(cls, library):
+ def import_library_attributes(cls, library: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMLibraryProperties
props.library_attributes.clear()
bonsai.bim.helper.import_attributes2(library, props.library_attributes)
@classmethod
- def import_reference_attributes(cls, reference):
+ def import_reference_attributes(cls, reference: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMLibraryProperties
props.reference_attributes.clear()
bonsai.bim.helper.import_attributes2(reference, props.reference_attributes)
@classmethod
- def import_references(cls, library):
+ def import_references(cls, library: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMLibraryProperties
props.references.clear()
if tool.Ifc.get_schema() == "IFC2X3":
@@ -70,13 +73,13 @@ class Library(bonsai.core.tool.Library):
new.name = reference.Name or "Unnamed"
@classmethod
- def set_active_library(cls, library):
+ def set_active_library(cls, library: ifcopenshell.entity_instance) -> None:
bpy.context.scene.BIMLibraryProperties.active_library_id = library.id()
@classmethod
- def set_active_reference(cls, reference):
+ def set_active_reference(cls, reference: ifcopenshell.entity_instance) -> None:
bpy.context.scene.BIMLibraryProperties.active_reference_id = reference.id()
@classmethod
- def set_editing_mode(cls, mode):
+ def set_editing_mode(cls, mode: Literal["LIBRARY", "REFERENCES", "REFERENCE"]) -> None:
bpy.context.scene.BIMLibraryProperties.editing_mode = mode
diff --git a/src/bonsai/bonsai/tool/structural.py b/src/bonsai/bonsai/tool/structural.py
index cb2fabc6e3..7dfa3dbdd0 100644
--- a/src/bonsai/bonsai/tool/structural.py
+++ b/src/bonsai/bonsai/tool/structural.py
@@ -18,38 +18,40 @@
import bpy
import ifcopenshell
+import ifcopenshell.util.representation
import json
import bonsai.bim.helper
import bonsai.core.tool
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore
from pprint import pprint
+from typing import Union, Any
class Structural(bonsai.core.tool.Structural):
@classmethod
- def disable_editing_structural_analysis_model(cls):
+ def disable_editing_structural_analysis_model(cls) -> None:
bpy.context.scene.BIMStructuralProperties.active_structural_analysis_model_id = 0
@classmethod
- def disable_structural_analysis_model_editing_ui(cls):
+ def disable_structural_analysis_model_editing_ui(cls) -> None:
bpy.context.scene.BIMStructuralProperties.is_editing = False
@classmethod
- def enable_editing_structural_analysis_model(cls, model):
+ def enable_editing_structural_analysis_model(cls, model: Union[int, None]) -> None:
if model:
bpy.context.scene.BIMStructuralProperties.active_structural_analysis_model_id = model
@classmethod
- def enable_structural_analysis_model_editing_ui(cls):
+ def enable_structural_analysis_model_editing_ui(cls) -> None:
bpy.context.scene.BIMStructuralProperties.is_editing = True
@classmethod
- def enabled_structural_analysis_model_editing_ui(cls):
+ def enabled_structural_analysis_model_editing_ui(cls) -> bool:
return bpy.context.scene.BIMStructuralProperties.is_editing
@classmethod
- def ensure_representation_contexts(cls):
+ def ensure_representation_contexts(cls) -> None:
model = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model")
if not model:
model = tool.Ifc.run(
@@ -70,13 +72,13 @@ class Structural(bonsai.core.tool.Structural):
)
@classmethod
- def get_active_structural_analysis_model(cls):
+ def get_active_structural_analysis_model(cls) -> ifcopenshell.entity_instance:
props = bpy.context.scene.BIMStructuralProperties
model = tool.Ifc.get().by_id(props.active_structural_analysis_model_id)
return model
@classmethod
- def get_ifc_structural_analysis_model_attributes(cls, model):
+ def get_ifc_structural_analysis_model_attributes(cls, model: Union[int, None]) -> Union[dict[str, Any], None]:
if model:
ifc_model = tool.Ifc.get().by_id(model)
data = ifc_model.get_info()
@@ -100,14 +102,14 @@ class Structural(bonsai.core.tool.Structural):
return data
@classmethod
- def get_ifc_structural_analysis_models(cls):
+ def get_ifc_structural_analysis_models(cls) -> dict[int, dict[str, Union[str, None]]]:
models = {}
for model in tool.Ifc.get().by_type("IfcStructuralAnalysisModel"):
models[model.id()] = {"Name": model.Name}
return models
@classmethod
- def get_product_or_active_object(cls, product):
+ def get_product_or_active_object(cls, product: str) -> Union[bpy.types.Object, None]:
product = bpy.data.objects.get(product) if product else bpy.context.active_object
try:
if product.BIMObjectProperties.ifc_definition_id:
@@ -118,13 +120,13 @@ class Structural(bonsai.core.tool.Structural):
return None
@classmethod
- def get_structural_analysis_model_attributes(cls):
+ def get_structural_analysis_model_attributes(cls) -> dict[str, Any]:
props = bpy.context.scene.BIMStructuralProperties
attributes = bonsai.bim.helper.export_attributes(props.structural_analysis_model_attributes)
return attributes
@classmethod
- def load_structural_analysis_model_attributes(cls, data):
+ def load_structural_analysis_model_attributes(cls, data: dict[str, Any]) -> None:
props = bpy.context.scene.BIMStructuralProperties
props.structural_analysis_model_attributes.clear()
for attribute in IfcStore.get_schema().declaration_by_name("IfcStructuralAnalysisModel").all_attributes():
@@ -145,7 +147,7 @@ class Structural(bonsai.core.tool.Structural):
new.data_type = "string"
@classmethod
- def load_structural_analysis_models(cls):
+ def load_structural_analysis_models(cls) -> None:
models = tool.Structural.get_ifc_structural_analysis_models()
props = bpy.context.scene.BIMStructuralProperties
props.structural_analysis_models.clear()
diff --git a/src/bonsai/test/tool/test_library.py b/src/bonsai/test/tool/test_library.py
index 28bd577c94..5bc941da43 100644
--- a/src/bonsai/test/tool/test_library.py
+++ b/src/bonsai/test/tool/test_library.py
@@ -130,5 +130,5 @@ class TestSetActiveReference(NewFile):
class TestSetEditingMode(NewFile):
def test_run(self):
- subject.set_editing_mode("FOO")
- assert bpy.context.scene.BIMLibraryProperties.editing_mode == "FOO"
+ subject.set_editing_mode("LIBRARY")
+ assert bpy.context.scene.BIMLibraryProperties.editing_mode == "LIBRARY"