ifcedit: fix Optional[entity_instance] coercion crash on native JSON values

coerce_value assumed value_str was always a CLI string, but ifcmcp
passes JSON-decoded native types (int, None) straight through. Guard
the Union/Optional "none" check so it only calls .lower() on strings,
and handle native None explicitly.
This commit is contained in:
Bruno Postle
2026-07-13 08:55:43 +01:00
parent ab15750747
commit 65695fb878
2 changed files with 13 additions and 1 deletions
+3 -1
View File
@@ -60,9 +60,11 @@ def coerce_value(
# Union / Optional
if origin is typing.Union:
non_none_types = [a for a in args if a is not type(None)]
if value_str.lower() == "none":
if isinstance(value_str, str) and value_str.lower() == "none":
if type(None) in args:
return None
if value_str is None and type(None) in args:
return None
# Try each non-None type in order
for t in non_none_types:
try:
+10
View File
@@ -57,6 +57,16 @@ class TestOptionalCoercion:
def test_optional_int(self):
assert coerce_value("42", Optional[int]) == 42
def test_optional_entity_native_int(self, model):
# MCP callers pass JSON-decoded native types (int), not CLI strings.
wall = model.by_type("IfcWall")[0]
result = coerce_value(wall.id(), Optional[ifcopenshell.entity_instance], model)
assert result == wall
def test_optional_entity_native_none(self, model):
# JSON null decodes to Python None, not the string "none".
assert coerce_value(None, Optional[ifcopenshell.entity_instance], model) is None
class TestUnionCoercion:
def test_union_str_int(self):