From 0944f8a7cbce31fd512ae5f078a99d96e194b3e3 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 1 Nov 2024 13:50:56 +0500 Subject: [PATCH] Fix unsafe enum items #5673 --- src/bonsai/bonsai/bim/module/bcf/prop.py | 9 +++--- src/bonsai/bonsai/bim/module/brick/prop.py | 25 ++++++++------- src/bonsai/bonsai/bim/module/gis/prop.py | 5 +-- src/bonsai/bonsai/bim/module/light/prop.py | 8 +++-- src/bonsai/bonsai/bim/module/qto/prop.py | 12 +++---- src/bonsai/bonsai/bim/module/sequence/data.py | 31 +++++++++++++++++-- src/bonsai/bonsai/bim/module/sequence/prop.py | 29 ++++++----------- 7 files changed, 68 insertions(+), 51 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/bcf/prop.py b/src/bonsai/bonsai/bim/module/bcf/prop.py index 17316e7cef..ef681ace10 100644 --- a/src/bonsai/bonsai/bim/module/bcf/prop.py +++ b/src/bonsai/bonsai/bim/module/bcf/prop.py @@ -184,20 +184,19 @@ class BcfTopic(PropertyGroup): is_editable: BoolProperty(name="Edit Topic Attributes", default=False, update=updateBcfTopicIsEditable) -# TODO: unsafe? def get_related_topics(self: "BCFProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]: + global RELATED_TOPICS_ENUM_ITEMS props = self active_topic = props.active_topic active_related_topics = active_topic.related_topics.keys() - enum_items = [] - i = 0 + RELATED_TOPICS_ENUM_ITEMS = [] for t in props.topics: if t.name == active_topic.name: continue if t.name in active_related_topics: continue - enum_items.append((t.name, t.title, t.description)) - return enum_items + RELATED_TOPICS_ENUM_ITEMS.append((t.name, t.title, t.description)) + return RELATED_TOPICS_ENUM_ITEMS class BCFProperties(PropertyGroup): diff --git a/src/bonsai/bonsai/bim/module/brick/prop.py b/src/bonsai/bonsai/bim/module/brick/prop.py index 8982c144a2..1a226fd1a0 100644 --- a/src/bonsai/bonsai/bim/module/brick/prop.py +++ b/src/bonsai/bonsai/bim/module/brick/prop.py @@ -45,30 +45,33 @@ def get_libraries(self, context): return BrickschemaReferencesData.data["libraries"] -# TODO: unsafe? def get_namespaces(self, context): - return [(uri, f"{alias}: {uri}", "") for alias, uri in BrickStore.namespaces] + global NAMESPACES_ENUM_ITEMS + NAMESPACES_ENUM_ITEMS = [(uri, f"{alias}: {uri}", "") for alias, uri in BrickStore.namespaces] + return NAMESPACES_ENUM_ITEMS -# TODO: unsafe? def get_brick_entity_classes(self, context): + global ENTITY_CLASSES_ENUM_ITEMS entity = self.brick_entity_create_type - return [(uri, uri.split("#")[-1], "") for uri in BrickStore.entity_classes[entity]] + ENTITY_CLASSES_ENUM_ITEMS = [(uri, uri.split("#")[-1], "") for uri in BrickStore.entity_classes[entity]] + return ENTITY_CLASSES_ENUM_ITEMS -# TODO: unsafe? def get_brick_roots(self, context): - return [(root, root, "") for root in BrickStore.root_classes] + global BRICK_ROOTS_ENUM_ITEMS + BRICK_ROOTS_ENUM_ITEMS = [(root, root, "") for root in BrickStore.root_classes] + return BRICK_ROOTS_ENUM_ITEMS -# TODO: unsafe? def get_brick_relations(self, context): - relations = [(uri, uri.split("#")[-1], "") for uri in BrickStore.relationships] + global BRICK_RELATIONS_ENUM_ITEMS + BRICK_RELATIONS_ENUM_ITEMS = [(uri, uri.split("#")[-1], "") for uri in BrickStore.relationships] for relation in BrickschemaData.data["active_relations"]: if relation["predicate_name"] == "label": - return relations - relations.append(("http://www.w3.org/2000/01/rdf-schema#label", "label", "")) - return relations + return BRICK_RELATIONS_ENUM_ITEMS + BRICK_RELATIONS_ENUM_ITEMS.append(("http://www.w3.org/2000/01/rdf-schema#label", "label", "")) + return BRICK_RELATIONS_ENUM_ITEMS def update_view(self, context): diff --git a/src/bonsai/bonsai/bim/module/gis/prop.py b/src/bonsai/bonsai/bim/module/gis/prop.py index 7e83b5a33d..bbf12aeb07 100644 --- a/src/bonsai/bonsai/bim/module/gis/prop.py +++ b/src/bonsai/bonsai/bim/module/gis/prop.py @@ -22,9 +22,10 @@ from bonsai.bim.prop import StrProperty class BIMCityJsonProperties(PropertyGroup): - # TODO: unsafe? def get_lods(self, context): - return [(item.name, "LOD" + item.name, "Level of Detail " + item.name) for item in self.lods] + global LODS_ENUM_ITEMS + LODS_ENUM_ITEMS = [(item.name, "LOD" + item.name, "Level of Detail " + item.name) for item in self.lods] + return LODS_ENUM_ITEMS # TODO: instead of subtype it would be nice to have a helper operator that allows filtered file browsing input: StringProperty(name="CityJSON Input", default="", subtype="FILE_PATH") diff --git a/src/bonsai/bonsai/bim/module/light/prop.py b/src/bonsai/bonsai/bim/module/light/prop.py index 4864f8ca30..90a27c0a5c 100644 --- a/src/bonsai/bonsai/bim/module/light/prop.py +++ b/src/bonsai/bonsai/bim/module/light/prop.py @@ -270,11 +270,13 @@ class RadianceExporterProperties(PropertyGroup): items=categories, name="Category", description="Material category", update=update_material_mapping ) - # TODO: unsafe? def get_subcategories(self, context): + global SUBCATEGORIES_ENUM_ITEMS if self.category in spectraldb: - return [(k, k, "") for k in spectraldb[self.category].keys()] - return [] + SUBCATEGORIES_ENUM_ITEMS = [(k, k, "") for k in spectraldb[self.category].keys()] + else: + SUBCATEGORIES_ENUM_ITEMS = [] + return SUBCATEGORIES_ENUM_ITEMS subcategory: bpy.props.EnumProperty( items=get_subcategories, name="Subcategory", description="Material subcategory", update=update_material_mapping diff --git a/src/bonsai/bonsai/bim/module/qto/prop.py b/src/bonsai/bonsai/bim/module/qto/prop.py index 28cc13a9cc..cdd52ed414 100644 --- a/src/bonsai/bonsai/bim/module/qto/prop.py +++ b/src/bonsai/bonsai/bim/module/qto/prop.py @@ -32,7 +32,6 @@ from bpy.props import ( ) -# TODO: unsafe? def get_qto_rule(self, context): results = [] for rule_id, rule in ifc5d.qto.rules.items(): @@ -40,7 +39,6 @@ def get_qto_rule(self, context): return results -# TODO: unsafe? def get_calculator(self, context): results = [] for name, calculator in ifc5d.qto.calculators.items(): @@ -48,18 +46,18 @@ def get_calculator(self, context): return results -# TODO: unsafe? def get_calculator_function(self, context): + global CALCULATOR_FUNCTION_ENUM_ITEMS calculator = ifc5d.qto.calculators[self.calculator] - results = [] + CALCULATOR_FUNCTION_ENUM_ITEMS = [] previous_measure = None for function_id, function in calculator.functions.items(): measure = function.measure.split("Measure")[0][3:] if previous_measure is not None and measure != previous_measure: - results.append(None) - results.append((function_id, f"{measure}: {function.name}", function.description)) + CALCULATOR_FUNCTION_ENUM_ITEMS.append(None) + CALCULATOR_FUNCTION_ENUM_ITEMS.append((function_id, f"{measure}: {function.name}", function.description)) previous_measure = measure - return results + return CALCULATOR_FUNCTION_ENUM_ITEMS class BIMQtoProperties(PropertyGroup): diff --git a/src/bonsai/bonsai/bim/module/sequence/data.py b/src/bonsai/bonsai/bim/module/sequence/data.py index 7e46621ee0..ca4e76aa5f 100644 --- a/src/bonsai/bonsai/bim/module/sequence/data.py +++ b/src/bonsai/bonsai/bim/module/sequence/data.py @@ -19,8 +19,11 @@ import bpy import bonsai.tool as tool import ifcopenshell -import ifcopenshell.util.date as dateutil +import ifcopenshell.util.attribute +import ifcopenshell.util.date +from ifcopenshell.util.doc import get_predefined_type_doc import json +from typing import Any def refresh(): @@ -32,7 +35,7 @@ def refresh(): class SequenceData: - data = {} + data: dict[str, Any] = {} is_loaded = False @classmethod @@ -41,6 +44,7 @@ class SequenceData: "has_work_plans": cls.has_work_plans(), "has_work_schedules": cls.has_work_schedules(), "has_work_calendars": cls.has_work_calendars(), + "schedule_predefined_types_enum": cls.schedule_predefined_types_enum(), } cls.load_work_plans() cls.load_work_schedules() @@ -88,6 +92,7 @@ class SequenceData: @classmethod def load_work_schedules(cls): cls.data["work_schedules"] = {} + cls.data["work_schedules_enum"] = [] for work_schedule in tool.Ifc.get().by_type("IfcWorkSchedule"): data = work_schedule.get_info() if not data["Name"]: @@ -106,12 +111,14 @@ class SequenceData: if obj.is_a("IfcTask"): data["RelatedObjects"].append(obj.id()) cls.data["work_schedules"][work_schedule.id()] = data + cls.data["work_schedules_enum"].append((str(work_schedule.id()), data["Name"], "")) cls.data["number_of_work_schedules_loaded"] = cls.number_of_work_schedules_loaded() @classmethod def load_work_calendars(cls): cls.data["work_calendars"] = {} + cls.data["work_calendars_enum"] = [] for work_calendar in tool.Ifc.get().by_type("IfcWorkCalendar"): data = work_calendar.get_info() del data["OwnerHistory"] @@ -120,6 +127,7 @@ class SequenceData: data["WorkingTimes"] = [t.id() for t in work_calendar.WorkingTimes or []] data["ExceptionTimes"] = [t.id() for t in work_calendar.ExceptionTimes or []] cls.data["work_calendars"][work_calendar.id()] = data + cls.data["work_calendars_enum"].append((str(work_calendar.id()), data["Name"], "")) cls.data["number_of_work_calendars_loaded"] = len(cls.data["work_calendars"].keys()) @@ -234,6 +242,23 @@ class SequenceData: data["NestingIndex"] = rel.RelatedObjects.index(task) cls.data["tasks"][task.id()] = data + @classmethod + def schedule_predefined_types_enum(cls) -> list[tuple[str, str, str]]: + results: list[tuple[str, str, str]] = [] + declaration = tool.Ifc().schema().declaration_by_name("IfcWorkSchedule") + version = tool.Ifc.get_schema() + for attribute in declaration.attributes(): + if attribute.name() == "PredefinedType": + results.extend( + [ + (e, e, get_predefined_type_doc(version, "IfcWorkSchedule", e)) + for e in ifcopenshell.util.attribute.get_enum_items(attribute) + if e != "BASELINE" + ] + ) + break + return results + class WorkScheduleData: data = {} @@ -268,7 +293,7 @@ class WorkScheduleData: { "id": work_schedule.id(), "name": work_schedule.Name or "Unnamed", - "date": str(dateutil.ifc2datetime(work_schedule.CreationDate)), + "date": str(ifcopenshell.util.date.ifc2datetime(work_schedule.CreationDate)), } ) return results diff --git a/src/bonsai/bonsai/bim/module/sequence/prop.py b/src/bonsai/bonsai/bim/module/sequence/prop.py index cbbb4f5ad8..6d2866ae8d 100644 --- a/src/bonsai/bonsai/bim/module/sequence/prop.py +++ b/src/bonsai/bonsai/bim/module/sequence/prop.py @@ -21,7 +21,6 @@ import isodate import ifcopenshell.api import ifcopenshell.util.attribute import ifcopenshell.util.date -from ifcopenshell.util.doc import get_predefined_type_doc import bonsai.tool as tool import bonsai.core.sequence as core from bonsai.bim.ifc import IfcStore @@ -82,13 +81,15 @@ def getTaskTimeColumns(self, context): def getWorkSchedules(self, context): - # TODO: unsafe? - return [(str(k), v["Name"], "") for k, v in SequenceData.data["work_schedules"].items()] + if not SequenceData.is_loaded: + SequenceData.load() + return SequenceData.data["work_schedules_enum"] def getWorkCalendars(self, context): - # TODO: unsafe? - return [(str(k), v["Name"], "") for k, v in SequenceData.data["work_calendars"].items()] + if not SequenceData.is_loaded: + SequenceData.load() + return SequenceData.data["work_calendars_enum"] def update_active_task_index(self, context): @@ -231,22 +232,10 @@ def updateTaskDuration(self, context): tool.Sequence.refresh_task_resources() -# TODO: unsafe? def get_schedule_predefined_types(self, context): - results = [] - declaration = tool.Ifc().schema().declaration_by_name("IfcWorkSchedule") - version = tool.Ifc.get_schema() - for attribute in declaration.attributes(): - if attribute.name() == "PredefinedType": - results.extend( - [ - (e, e, get_predefined_type_doc(version, "IfcWorkSchedule", e)) - for e in attribute.type_of_attribute().declared_type().enumeration_items() - if e != "BASELINE" - ] - ) - break - return results + if not SequenceData.is_loaded: + SequenceData.load() + return SequenceData.data["schedule_predefined_types_enum"] def update_visualisation_start(self, context):