Skip to content

Commit

Permalink
Add Tuple support to CQGI (#1373)
Browse files Browse the repository at this point in the history
* Initial draft of Tuple support in CQGI

* Fixed default value for Tuple

* Handle multiple length tuples

* Added a test case for nested tuples

* Added test for invalid parameter type error
  • Loading branch information
jmwright committed Oct 31, 2023
1 parent 8b7189d commit 8a9e5a0
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 10 deletions.
29 changes: 26 additions & 3 deletions cadquery/cqgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ class BooleanParameterType(ParameterType):
pass


class TupleParameterType(ParameterType):
pass


class InputParameter:
"""
Defines a parameter that can be supplied when the model is executed.
Expand Down Expand Up @@ -304,6 +308,15 @@ def set_value(self, new_value):
self.ast_node.value = False
else:
self.ast_node.id = "False"
elif self.varType == TupleParameterType:
self.ast_node.n = new_value

# Build the list of constants to set as the tuple value
constants = []
for nv in new_value:
constants.append(ast.Constant(value=nv))
self.ast_node.elts = constants
ast.fix_missing_locations(self.ast_node)
else:
raise ValueError("Unknown Type of var: ", str(self.varType))

Expand Down Expand Up @@ -478,7 +491,6 @@ def __init__(self, cq_model):

def handle_assignment(self, var_name, value_node):
try:

if type(value_node) == ast.Num:
self.cqModel.add_script_parameter(
InputParameter.create(
Expand All @@ -504,6 +516,17 @@ def handle_assignment(self, var_name, value_node):
value_node, var_name, BooleanParameterType, False
)
)
elif type(value_node) == ast.Tuple:
# Handle multi-length tuples
tup = ()
for entry in value_node.elts:
tup = tup + (entry.value,)

self.cqModel.add_script_parameter(
InputParameter.create(
value_node, var_name, TupleParameterType, tup,
)
)
elif hasattr(ast, "NameConstant") and type(value_node) == ast.NameConstant:
if value_node.value == True:
self.cqModel.add_script_parameter(
Expand All @@ -525,6 +548,7 @@ def handle_assignment(self, var_name, value_node):
str: StringParameterType,
float: NumberParameterType,
int: NumberParameterType,
tuple: TupleParameterType,
}

self.cqModel.add_script_parameter(
Expand Down Expand Up @@ -561,8 +585,7 @@ def visit_Assign(self, node):
self.handle_assignment(left_side.id, node.value)
elif type(node.value) == ast.Tuple:
if isinstance(left_side, ast.Name):
# skip unsupported parameter type
pass
self.handle_assignment(left_side.id, node.value)
else:
# we have a multi-value assignment
for n, v in zip(left_side.elts, node.value.elts):
Expand Down
39 changes: 32 additions & 7 deletions tests/test_cqgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
defining a build_object function to return results
"""

import pytest
from cadquery import cqgi
from tests import BaseTest
import textwrap
Expand All @@ -16,9 +17,10 @@
height=2.0
width=3.0
(a,b) = (1.0,1.0)
o = (2, 2, 0)
foo="bar"
result = "%s|%s|%s|%s" % ( str(height) , str(width) , foo , str(a) )
result = "%s|%s|%s|%s|%s" % ( str(height) , str(width) , foo , str(a) , str(o) )
show_object(result)
"""
)
Expand All @@ -28,9 +30,10 @@
height=2.0
width=3.0
(a,b) = (1.0,1.0)
o = (2, 2, 0)
foo="bar"
debug(foo, { "color": 'yellow' } )
result = "%s|%s|%s|%s" % ( str(height) , str(width) , foo , str(a) )
result = "%s|%s|%s|%s|%s" % ( str(height) , str(width) , foo , str(a) , str(o) )
show_object(result)
debug(height )
"""
Expand All @@ -41,9 +44,8 @@ class TestCQGI(BaseTest):
def test_parser(self):
model = cqgi.CQModel(TESTSCRIPT)
metadata = model.metadata

self.assertEqual(
set(metadata.parameters.keys()), {"height", "width", "a", "b", "foo"}
set(metadata.parameters.keys()), {"height", "width", "a", "b", "foo", "o"}
)

def test_build_with_debug(self):
Expand All @@ -62,12 +64,19 @@ def test_build_with_empty_params(self):

self.assertTrue(result.success)
self.assertTrue(len(result.results) == 1)
self.assertTrue(result.results[0].shape == "2.0|3.0|bar|1.0")
self.assertTrue(result.results[0].shape == "2.0|3.0|bar|1.0|(2, 2, 0)")

def test_build_with_different_params(self):
model = cqgi.CQModel(TESTSCRIPT)
result = model.build({"height": 3.0})
self.assertTrue(result.results[0].shape == "3.0|3.0|bar|1.0")
result = model.build({"height": 3.0, "o": (3, 3)})
print(result.results[0].shape)
self.assertTrue(result.results[0].shape == "3.0|3.0|bar|1.0|(3, 3)")

def test_build_with_nested_tuple_params(self):
model = cqgi.CQModel(TESTSCRIPT)
result = model.build({"height": 3.0, "o": ((2, 2), (3, 3))})
print(result.results[0].shape)
self.assertTrue(result.results[0].shape == "3.0|3.0|bar|1.0|((2, 2), (3, 3))")

def test_describe_parameters(self):
script = textwrap.dedent(
Expand Down Expand Up @@ -222,3 +231,19 @@ def do_stuff():
model = cqgi.parse(script)

self.assertEqual(2, len(model.metadata.parameters))

def test_invalid_parameter_type(self):
"""Contrived test in case a parameter type that is not valid for InputParameter sneaks through."""

# Made up parameter class
class UnknowParameter:
def __init__():
return 1

# Set up the most basic InputParameter object that is possible
p = cqgi.InputParameter()
p.varType = UnknowParameter

# Setting the parameter should throw an unknown parameter type error
with pytest.raises(ValueError) as info:
p.set_value(2)

0 comments on commit 8a9e5a0

Please sign in to comment.