added describe_parameter
This commit is contained in:
@ -44,9 +44,11 @@ class CQModel(object):
|
|||||||
self.ast_tree = ast.parse(script_source, CQSCRIPT)
|
self.ast_tree = ast.parse(script_source, CQSCRIPT)
|
||||||
self.script_source = script_source
|
self.script_source = script_source
|
||||||
self._find_vars()
|
self._find_vars()
|
||||||
|
|
||||||
# TODO: pick up other scirpt metadata:
|
# TODO: pick up other scirpt metadata:
|
||||||
# describe
|
# describe
|
||||||
# pick up validation methods
|
# pick up validation methods
|
||||||
|
self._find_descriptions()
|
||||||
|
|
||||||
def _find_vars(self):
|
def _find_vars(self):
|
||||||
"""
|
"""
|
||||||
@ -65,6 +67,9 @@ class CQModel(object):
|
|||||||
if isinstance(node, ast.Assign):
|
if isinstance(node, ast.Assign):
|
||||||
assignment_finder.visit_Assign(node)
|
assignment_finder.visit_Assign(node)
|
||||||
|
|
||||||
|
def _find_descriptions(self):
|
||||||
|
description_finder = ParameterDescriptionFinder(self.metadata)
|
||||||
|
description_finder.visit(self.ast_tree)
|
||||||
|
|
||||||
def validate(self, params):
|
def validate(self, params):
|
||||||
"""
|
"""
|
||||||
@ -99,6 +104,7 @@ class CQModel(object):
|
|||||||
env = EnvironmentBuilder().with_real_builtins().with_cadquery_objects() \
|
env = EnvironmentBuilder().with_real_builtins().with_cadquery_objects() \
|
||||||
.add_entry("build_object", collector.build_object) \
|
.add_entry("build_object", collector.build_object) \
|
||||||
.add_entry("debug", collector.debug) \
|
.add_entry("debug", collector.debug) \
|
||||||
|
.add_entry("describe_parameter",collector.describe_parameter) \
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
c = compile(self.ast_tree, CQSCRIPT, 'exec')
|
c = compile(self.ast_tree, CQSCRIPT, 'exec')
|
||||||
@ -173,6 +179,11 @@ class ScriptMetadata(object):
|
|||||||
def add_script_parameter(self, p):
|
def add_script_parameter(self, p):
|
||||||
self.parameters[p.name] = p
|
self.parameters[p.name] = p
|
||||||
|
|
||||||
|
def add_parameter_description(self,name,description):
|
||||||
|
print 'Adding Parameter name=%s, desc=%s' % ( name, description )
|
||||||
|
p = self.parameters[name]
|
||||||
|
p.desc = description
|
||||||
|
|
||||||
|
|
||||||
class ParameterType(object):
|
class ParameterType(object):
|
||||||
pass
|
pass
|
||||||
@ -213,19 +224,15 @@ class InputParameter:
|
|||||||
self.varType = None
|
self.varType = None
|
||||||
|
|
||||||
#: help text describing the variable. Only available if the script used describe_parameter()
|
#: help text describing the variable. Only available if the script used describe_parameter()
|
||||||
self.shortDesc = None
|
self.desc = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#: valid values for the variable. Only available if the script used describe_parameter()
|
#: valid values for the variable. Only available if the script used describe_parameter()
|
||||||
self.valid_values = []
|
self.valid_values = []
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.ast_node = None
|
self.ast_node = None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create(ast_node, var_name, var_type, default_value, valid_values=None, short_desc=None):
|
def create(ast_node, var_name, var_type, default_value, valid_values=None, desc=None):
|
||||||
|
|
||||||
if valid_values is None:
|
if valid_values is None:
|
||||||
valid_values = []
|
valid_values = []
|
||||||
@ -234,10 +241,7 @@ class InputParameter:
|
|||||||
p.ast_node = ast_node
|
p.ast_node = ast_node
|
||||||
p.default_value = default_value
|
p.default_value = default_value
|
||||||
p.name = var_name
|
p.name = var_name
|
||||||
if short_desc is None:
|
p.desc = desc
|
||||||
p.shortDesc = var_name
|
|
||||||
else:
|
|
||||||
p.shortDesc = short_desc
|
|
||||||
p.varType = var_type
|
p.varType = var_type
|
||||||
p.valid_values = valid_values
|
p.valid_values = valid_values
|
||||||
return p
|
return p
|
||||||
@ -296,10 +300,9 @@ class ScriptCallback(object):
|
|||||||
"""
|
"""
|
||||||
self.debugObjects.append(DebugObject(obj,args))
|
self.debugObjects.append(DebugObject(obj,args))
|
||||||
|
|
||||||
def describe_parameter(self,var, valid_values, short_desc):
|
def describe_parameter(self,var_data ):
|
||||||
"""
|
"""
|
||||||
Not yet implemented: allows a script to document
|
Do Nothing-- we parsed the ast ahead of exection to get what we need.
|
||||||
extra metadata about the parameters
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -394,6 +397,30 @@ class EnvironmentBuilder(object):
|
|||||||
def build(self):
|
def build(self):
|
||||||
return self.env
|
return self.env
|
||||||
|
|
||||||
|
class ParameterDescriptionFinder(ast.NodeTransformer):
|
||||||
|
"""
|
||||||
|
Visits a parse tree, looking for function calls to describe_parameter(var, description )
|
||||||
|
"""
|
||||||
|
def __init__(self, cq_model):
|
||||||
|
self.cqModel = cq_model
|
||||||
|
|
||||||
|
def visit_Call(self,node):
|
||||||
|
"""
|
||||||
|
Called when we see a function call. Is it describe_parameter?
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if node.func.id == 'describe_parameter':
|
||||||
|
#looks like we have a call to our function.
|
||||||
|
#first parameter is the variable,
|
||||||
|
#second is the description
|
||||||
|
varname = node.args[0].id
|
||||||
|
desc = node.args[1].s
|
||||||
|
self.cqModel.add_parameter_description(varname,desc)
|
||||||
|
|
||||||
|
except:
|
||||||
|
print "Unable to handle function call"
|
||||||
|
pass
|
||||||
|
return node
|
||||||
|
|
||||||
class ConstantAssignmentFinder(ast.NodeTransformer):
|
class ConstantAssignmentFinder(ast.NodeTransformer):
|
||||||
"""
|
"""
|
||||||
@ -404,9 +431,6 @@ class ConstantAssignmentFinder(ast.NodeTransformer):
|
|||||||
self.cqModel = cq_model
|
self.cqModel = cq_model
|
||||||
|
|
||||||
def handle_assignment(self, var_name, value_node):
|
def handle_assignment(self, var_name, value_node):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
if type(value_node) == ast.Num:
|
if type(value_node) == ast.Num:
|
||||||
|
18
doc/cqgi.rst
18
doc/cqgi.rst
@ -70,6 +70,24 @@ run code like this::
|
|||||||
|
|
||||||
The :py:meth:`cadquery.cqgi.parse()` method returns a :py:class:`cadquery.cqgi.CQModel` object.
|
The :py:meth:`cadquery.cqgi.parse()` method returns a :py:class:`cadquery.cqgi.CQModel` object.
|
||||||
|
|
||||||
|
The `metadata`p property of the object contains a `cadquery.cqgi.ScriptMetaData` object, which can be used to discover the
|
||||||
|
user parameters available. This is useful if the execution environment would like to present a GUI to allow the user to change the
|
||||||
|
model parameters. Typically, after collecting new values, the environment will supply them in the build() method.
|
||||||
|
|
||||||
|
This code will return a dictionary of parameter values in the model text SCRIPT::
|
||||||
|
|
||||||
|
parameters = cqgi.parse(SCRIPT).metadata.parameters
|
||||||
|
|
||||||
|
The dictionary you get back is a map where key is the parameter name, and value is an InputParameter object,
|
||||||
|
which has a name, type, and default value.
|
||||||
|
|
||||||
|
The type is an object which extends ParameterType-- you can use this to determine what kind of widget to render ( checkbox for boolean, for example ).
|
||||||
|
|
||||||
|
The parameter object also has a description, valid values, minimum, and maximum values, if the user has provided them using the
|
||||||
|
describe_parameter() method.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Calling :py:meth:`cadquery.cqgi.CQModel.build()` returns a :py:class:`cadquery.cqgi.BuildResult` object,
|
Calling :py:meth:`cadquery.cqgi.CQModel.build()` returns a :py:class:`cadquery.cqgi.BuildResult` object,
|
||||||
,which includes the script execution time, and a success flag.
|
,which includes the script execution time, and a success flag.
|
||||||
|
|
||||||
|
@ -8,11 +8,11 @@ import unittest
|
|||||||
#on py 2.7.x on win
|
#on py 2.7.x on win
|
||||||
suite = unittest.TestSuite()
|
suite = unittest.TestSuite()
|
||||||
|
|
||||||
|
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCQGI.TestCQGI))
|
||||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCadObjects.TestCadObjects))
|
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCadObjects.TestCadObjects))
|
||||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestWorkplanes.TestWorkplanes))
|
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestWorkplanes.TestWorkplanes))
|
||||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCQSelectors.TestCQSelectors))
|
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCQSelectors.TestCQSelectors))
|
||||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCadQuery.TestCadQuery))
|
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCadQuery.TestCadQuery))
|
||||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestExporters.TestExporters))
|
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestExporters.TestExporters))
|
||||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestImporters.TestImporters))
|
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestImporters.TestImporters))
|
||||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCQGI.TestCQGI))
|
|
||||||
unittest.TextTestRunner().run(suite)
|
unittest.TextTestRunner().run(suite)
|
||||||
|
@ -66,6 +66,30 @@ class TestCQGI(BaseTest):
|
|||||||
result = model.build({'height': 3.0})
|
result = model.build({'height': 3.0})
|
||||||
self.assertTrue(result.results[0] == "3.0|3.0|bar|1.0")
|
self.assertTrue(result.results[0] == "3.0|3.0|bar|1.0")
|
||||||
|
|
||||||
|
def test_describe_parameters(self):
|
||||||
|
script = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
a = 2.0
|
||||||
|
describe_parameter(a,'FirstLetter')
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
model = cqgi.CQModel(script)
|
||||||
|
a_param = model.metadata.parameters['a']
|
||||||
|
self.assertTrue(a_param.default_value == 2.0)
|
||||||
|
self.assertTrue(a_param.desc == 'FirstLetter')
|
||||||
|
self.assertTrue(a_param.varType == cqgi.NumberParameterType )
|
||||||
|
|
||||||
|
def test_describe_parameter_invalid_doesnt_fail_script(self):
|
||||||
|
script = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
a = 2.0
|
||||||
|
describe_parameter(a, 2 - 1 )
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
model = cqgi.CQModel(script)
|
||||||
|
a_param = model.metadata.parameters['a']
|
||||||
|
self.assertTrue(a_param.name == 'a' )
|
||||||
|
|
||||||
def test_build_with_exception(self):
|
def test_build_with_exception(self):
|
||||||
badscript = textwrap.dedent(
|
badscript = textwrap.dedent(
|
||||||
"""
|
"""
|
||||||
|
Reference in New Issue
Block a user