geom.settings - add a tooltip for available settings #4832

example - https://i.imgur.com/eTdqv5J.png
added a test so we won't miss if some setting will be added/removed
This commit is contained in:
Andrej730
2024-06-11 11:45:27 +05:00
parent acd4274136
commit f54f45a051
2 changed files with 100 additions and 21 deletions
@@ -27,7 +27,7 @@ from ..entity_instance import entity_instance
from . import has_occ from . import has_occ
from typing import TypeVar, Union, Optional, Generator, Any from typing import TypeVar, Union, Optional, Generator, Any, Literal
T = TypeVar("T") T = TypeVar("T")
ShapeElementType = Union[ ShapeElementType = Union[
@@ -54,17 +54,62 @@ if has_occ:
else: else:
return shape return shape
class missing_setting:
def __repr__(self): return '-'
class settings_mixin: SETTING = Literal[
"mesher-linear-deflection",
"mesher-angular-deflection",
"reorient-shells",
"length-unit",
"angle-unit",
"precision",
"dimensionality",
"layerset-first",
"disable-boolean-result",
"no-wire-intersection-check",
"no-wire-intersection-tolerance",
"precision-factor",
"debug-boolean",
"boolean-attempt-2d",
"weld-vertices",
"use-world-coords",
"use-material-names",
"convert-back-units",
"context-ids",
"context-types",
"context-identifiers",
"iterator-output",
"disable-opening-subtractions",
"apply-default-materials",
"no-normals",
"generate-uvs",
"enable-layerset-slicing",
"element-hierarchy",
"validate",
"edge-arrows",
"building-local-placement",
"site-local-placement",
"force-space-transparency",
"circle-segments",
"keep-bounding-boxes",
"piecewise-step-type",
"piecewise-step-param",
"use-python-opencascade",
]
class missing_setting:
def __repr__(self):
return '-'
class settings_mixin:
""" """
Pythonic interface mixin to the settings modules and Pythonic interface mixin to the settings modules and
to provide an additional setting to enable pythonOCC to provide an additional setting to enable pythonOCC
when available when available
""" """
USE_PYTHON_OPENCASCADE = 'USE_PYTHON_OPENCASCADE' use_python_opencascade = False
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(settings_mixin, self).__init__() super(settings_mixin, self).__init__()
@@ -73,29 +118,33 @@ class settings_mixin:
def __repr__(self): def __repr__(self):
def safe_get(x): def safe_get(x):
try: return self.get_(x) try:
except: return missing_setting() return self.get(x)
except RuntimeError:
return missing_setting()
fmt_pair = lambda x: "%s = %r" % (self.rname(x), safe_get(x)) fmt_pair = lambda x: "%s = %r" % (self.rname(x), safe_get(x))
return "%s(%s)" % ( return "%s(%s)" % (
type(self).__name__, type(self).__name__,
", ".join(map(fmt_pair, self.setting_names())) ", ".join(map(fmt_pair, self.setting_names()))
) )
@staticmethod @staticmethod
def name(k): def name(k: str) -> SETTING:
return k.lower().replace('_', '-') return k.lower().replace("_", "-")
@staticmethod @staticmethod
def rname(k): def rname(k: SETTING) -> str:
return k.upper().replace('-', '_') return k.upper().replace("-", "_")
def set(self, k: str, v: Any) -> None: def set(self, k: SETTING, v: Any) -> None:
""" """
Set value of the setting named `k` to `v`. Set value of the setting named `k` to `v`.
:raises RuntimeError: If there is no setting with name `k`. :raises RuntimeError: If there is no setting with name `k`.
""" """
if k == "USE_PYTHON_OPENCASCADE": k = self.name(k)
if k == "use-python-opencascade":
if not has_occ: if not has_occ:
raise AttributeError("Python OpenCASCADE is not installed") raise AttributeError("Python OpenCASCADE is not installed")
if v: if v:
@@ -104,17 +153,22 @@ class settings_mixin:
self.use_python_opencascade = True self.use_python_opencascade = True
else: else:
self.set_(self.name(k), v) self.set_(self.name(k), v)
def get(self, k: str) -> Any: def get(self, k: SETTING) -> Any:
""" """
Return value of the setting named `k`. Return value of the setting named `k`.
:raises RuntimeError: If there is no setting with name `k`. :raises RuntimeError: If there is no setting with name `k`.
""" """
k = self.name(k)
return self.get_(self.name(k)) if k == "use-python-opencascade":
return self.use_python_opencascade
return self.get_(k)
def __getattr__(self, k): def setting_names(self) -> tuple[SETTING, ...]:
return super().setting_names() + ("use-python-opencascade",)
def __getattr__(self, k: str) -> SETTING:
if k in map(self.rname, self.setting_names()): if k in map(self.rname, self.setting_names()):
return k return k
else: else:
@@ -1,7 +1,32 @@
import pytest
import ifcopenshell import ifcopenshell
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.geom import ifcopenshell.geom
import ifcopenshell.api.owner.settings import ifcopenshell.api.owner.settings
from typing import get_args
class TestGeomSettings:
def test_run(self):
settings = ifcopenshell.geom.settings()
assert set(get_args(ifcopenshell.geom.SETTING)) == set(settings.setting_names())
assert settings.get(settings.USE_PYTHON_OPENCASCADE) is False
assert settings.get("use-python-opencascade") is False
assert "USE_PYTHON_OPENCASCADE = False" in repr(settings)
if ifcopenshell.geom.has_occ:
settings.set("use-python-opencascade", True)
settings.set(settings.USE_PYTHON_OPENCASCADE, True)
assert settings.get(settings.USE_PYTHON_OPENCASCADE) is True
assert "USE_PYTHON_OPENCASCADE = True" in repr(settings)
else:
with pytest.raises(AttributeError):
settings.set("use-python-opencascade", True)
with pytest.raises(AttributeError):
settings.set(settings.USE_PYTHON_OPENCASCADE, True)
assert "USE_PYTHON_OPENCASCADE = False" in repr(settings)
class TestAssignObject: class TestAssignObject:
def test_no_welding_on_distinct_items(self): def test_no_welding_on_distinct_items(self):