From 2edfe1e5d8ce2fd4ee58353ea4b1c9fbd38aa69e Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Thu, 17 Jul 2025 14:55:46 +0500 Subject: [PATCH] profile.add_parameterized_profile - add profile_type arg To create more valid profiles by default. Noticed then Bonsai creates new profiles, it doesn't set ProfileType, leading to validation errors. --- src/bonsai/bonsai/tool/profile.py | 1 + .../api/profile/add_parameterized_profile.py | 11 ++++- .../ifcopenshell/util/schema.py | 2 +- .../profile/test_add_parameterized_profile.py | 40 +++++++++++++++++++ 4 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 src/ifcopenshell-python/test/api/profile/test_add_parameterized_profile.py diff --git a/src/bonsai/bonsai/tool/profile.py b/src/bonsai/bonsai/tool/profile.py index 0838ef9a6e..8e467dd182 100644 --- a/src/bonsai/bonsai/tool/profile.py +++ b/src/bonsai/bonsai/tool/profile.py @@ -223,6 +223,7 @@ class Profile(bonsai.core.tool.Profile): """Set default profile attributes to keep profile valid.""" class_match = False si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) + # We're using for-loop as classes may not match exactly. for ifc_class, params in cls.DEFAULT_PROFILE_ATTRS.items(): if profile.is_a(ifc_class): class_match = True diff --git a/src/ifcopenshell-python/ifcopenshell/api/profile/add_parameterized_profile.py b/src/ifcopenshell-python/ifcopenshell/api/profile/add_parameterized_profile.py index 97d8ba3f81..12c57532b0 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/profile/add_parameterized_profile.py +++ b/src/ifcopenshell-python/ifcopenshell/api/profile/add_parameterized_profile.py @@ -16,9 +16,15 @@ # You should have received a copy of the GNU Lesser General Public License # along with IfcOpenShell. If not, see . import ifcopenshell +from typing import Literal -def add_parameterized_profile(file: ifcopenshell.file, ifc_class: str) -> ifcopenshell.entity_instance: +ProfileType = Literal["AREA", "CURVE"] + + +def add_parameterized_profile( + file: ifcopenshell.file, ifc_class: str, profile_type: str = "AREA" +) -> ifcopenshell.entity_instance: """Adds a new parameterised profile IFC offers parameterised profiles for common standardised hot roll @@ -30,6 +36,7 @@ def add_parameterized_profile(file: ifcopenshell.file, ifc_class: str) -> ifcope :param ifc_class: The subclass of IfcParameterizedProfileDef that you'd like to create. + :param profile_type: :return: The newly created element depending on the specified ifc_class. Example: @@ -40,4 +47,4 @@ def add_parameterized_profile(file: ifcopenshell.file, ifc_class: str) -> ifcope ifc_class="IfcCircleProfileDef") circle.Radius = 1. """ - return file.create_entity(ifc_class) + return file.create_entity(ifc_class, ProfileType=profile_type) diff --git a/src/ifcopenshell-python/ifcopenshell/util/schema.py b/src/ifcopenshell-python/ifcopenshell/util/schema.py index 698a3a9987..d3d7b65c6a 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/schema.py +++ b/src/ifcopenshell-python/ifcopenshell/util/schema.py @@ -118,7 +118,7 @@ def get_supertypes( def get_subtypes( declaration: ifcopenshell.ifcopenshell_wrapper.entity, ) -> list[ifcopenshell.ifcopenshell_wrapper.entity]: - """Get a flat list of subtype declarations + """Get a flat list of subtype declarations, recursively. Abstract classes are skipped. diff --git a/src/ifcopenshell-python/test/api/profile/test_add_parameterized_profile.py b/src/ifcopenshell-python/test/api/profile/test_add_parameterized_profile.py new file mode 100644 index 0000000000..8481592643 --- /dev/null +++ b/src/ifcopenshell-python/test/api/profile/test_add_parameterized_profile.py @@ -0,0 +1,40 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2022 Dion Moult +# +# This file is part of IfcOpenShell. +# +# IfcOpenShell is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# IfcOpenShell is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcOpenShell. If not, see . + +import test.bootstrap +import ifcopenshell.api.profile +import ifcopenshell.util.schema + + +class TestAddParametrizedProfileIFC2X3(test.bootstrap.IFC2X3): + def test_run(self): + schema = ifcopenshell.schema_by_name(self.file.schema) + entity = schema.declaration_by_name("IfcParameterizedProfileDef").as_entity() + assert entity + for s in ifcopenshell.util.schema.get_subtypes(entity): + profile = ifcopenshell.api.profile.add_parameterized_profile(self.file, ifc_class=s.name()) + assert profile.is_a() == s.name() + assert profile.ProfileType == "AREA" + + +class TestAddParametrizedProfileIFC4(test.bootstrap.IFC4, TestAddParametrizedProfileIFC2X3): + pass + + +class TestAddParametrizedProfileIFC4X3(test.bootstrap.IFC4, TestAddParametrizedProfileIFC2X3): + pass