Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for type annotated parameters #1694

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 47 additions & 1 deletion cadquery/cqgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
The CadQuery Gateway Interface.
Provides classes and tools for executing CadQuery scripts
"""
import sys
import ast
import traceback
import time
Expand Down Expand Up @@ -65,7 +66,9 @@
assignment_finder = ConstantAssignmentFinder(self.metadata)

for node in self.ast_tree.body:
if isinstance(node, ast.Assign):
if isinstance(node, ast.AnnAssign):
assignment_finder.visit_AnnAssign(node)
elif isinstance(node, ast.Assign):
assignment_finder.visit_Assign(node)

def _find_descriptions(self):
Expand Down Expand Up @@ -564,6 +567,31 @@
print("Unable to handle assignment for variable '%s'" % var_name)
pass

def handle_ann_assignment(self, var_name, annotation_id, value_node):
try:
if annotation_id == "int" or annotation_id == "float":
self.cqModel.add_script_parameter(
InputParameter.create(
value_node, var_name, NumberParameterType, value_node.n
)
)
elif annotation_id == "str":
self.cqModel.add_script_parameter(
InputParameter.create(
value_node, var_name, StringParameterType, value_node.s
)
)
elif annotation_id == "bool":
self.cqModel.add_script_parameter(
InputParameter.create(
value_node, var_name, BooleanParameterType, value_node.s
)
)

except:
print("Unable to handle annotated assignment for variable '%s'" % var_name)
pass

Check warning on line 593 in cadquery/cqgi.py

View check run for this annotation

Codecov / codecov/patch

cadquery/cqgi.py#L591-L593

Added lines #L591 - L593 were not covered by tests

def visit_Assign(self, node):

try:
Expand Down Expand Up @@ -595,3 +623,21 @@
print("Unable to handle assignment for node '%s'" % ast.dump(left_side))

return node

def visit_AnnAssign(self, node):
left_side = node.target

# do not handle Attribute or Subscript
if not isinstance(left_side, ast.Name):
return

Check warning on line 632 in cadquery/cqgi.py

View check run for this annotation

Codecov / codecov/patch

cadquery/cqgi.py#L632

Added line #L632 was not covered by tests

annTypes = ["int", "float", "str", "bool"]

if (
hasattr(node, "annotation")
and isinstance(node.annotation, ast.Name)
and node.annotation.id in annTypes
):
self.handle_ann_assignment(left_side.id, node.annotation.id, node.value)

return node
3 changes: 3 additions & 0 deletions partcad.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# This is a PartCAD package.
# See https://partcad.org/ and https://github.com/openvmp/partcad for more information.

name: /pub/examples/script/cadquery
desc: CadQuery examples
url: https://github.com/CadQuery/cadquery
Expand Down
26 changes: 21 additions & 5 deletions tests/test_cqgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
TESTSCRIPT = textwrap.dedent(
"""
height=2.0
width=3.0
width:float=3.0
transparent=False
(a,b) = (1.0,1.0)
o = (2, 2, 0)
foo="bar"
Expand All @@ -29,9 +30,10 @@
"""
height=2.0
width=3.0
transparent:bool=False
(a,b) = (1.0,1.0)
o = (2, 2, 0)
foo="bar"
foo:str="bar"
debug(foo, { "color": 'yellow' } )
result = "%s|%s|%s|%s|%s" % ( str(height) , str(width) , foo , str(a) , str(o) )
show_object(result)
Expand All @@ -45,7 +47,8 @@ def test_parser(self):
model = cqgi.CQModel(TESTSCRIPT)
metadata = model.metadata
self.assertEqual(
set(metadata.parameters.keys()), {"height", "width", "a", "b", "foo", "o"}
set(metadata.parameters.keys()),
{"height", "width", "transparent", "a", "b", "foo", "o"},
)

def test_build_with_debug(self):
Expand Down Expand Up @@ -135,7 +138,7 @@ def test_that_two_results_are_returned(self):
"""
h = 1
show_object(h)
h = 2
h: int = 2
show_object(h)
"""
)
Expand Down Expand Up @@ -166,6 +169,16 @@ def test_that_assigning_string_to_number_fails(self):
result = cqgi.parse(script).build({"h": "a string"})
self.assertTrue(isinstance(result.exception, cqgi.InvalidParameterError))

def test_that_assigning_string_to_annotated_list_fails(self):
script = textwrap.dedent(
"""
h: list[float] = [20.0]
show_object(h)
"""
)
result = cqgi.parse(script).build({"h": "a string"})
self.assertTrue(isinstance(result.exception, cqgi.InvalidParameterError))

def test_that_assigning_unknown_var_fails(self):
script = textwrap.dedent(
"""
Expand Down Expand Up @@ -222,7 +235,10 @@ def test_that_only_top_level_vars_are_detected(self):

def do_stuff():
x = 1
y = 2
y: int = 2
class Foo:
z = 3
zz: int = 4

show_object( "result" )
"""
Expand Down