diff --git a/src/cq_cli/main.py b/src/cq_cli/main.py index 914fbd8..64377a3 100755 --- a/src/cq_cli/main.py +++ b/src/cq_cli/main.py @@ -20,13 +20,15 @@ from cq_cli.cqcodecs import loader -def build_and_parse(script_str, params, errfile): +def build_and_parse(script_str, params, errfile, expression): """ Uses CQGI to parse and build a script, substituting in parameters if any were supplied. """ # We need to do a broad try/catch to let the user know if something higher-level fails try: # Do the CQGI handling of the script here and, if successful, pass the build result to the codec + if expression != None: + script_str += "\nshow_object({expr})".format(expr=expression) cqModel = cqgi.parse(script_str) build_result = cqModel.build(params) @@ -181,6 +183,10 @@ def main(): "--validate", help="Setting to true forces the CLI to only parse and validate the script and not produce converted output.", ) + parser.add_argument( + "--expression", + help="A python expression (such as `my_shape(x=5)`) to evaluate and render. This allows rendering different models/parts from the same python file.", + ) args = parser.parse_args() @@ -223,7 +229,7 @@ def main(): # Set the PYTHONPATH variable to the current directory to allow module loading set_pythonpath_for_infile(args.infile) - build_result = build_and_parse(script_str, params, errfile) + build_result = build_and_parse(script_str, params, errfile, args.expression) # Double-check that the build was a success if build_result != None and build_result.success: @@ -424,7 +430,7 @@ def main(): # build_result = None try: - build_result = build_and_parse(script_str, params, errfile) + build_result = build_and_parse(script_str, params, errfile, args.expression) # If None was returned, it means the build failed and the exception has already been reported if build_result == None: diff --git a/tests/test_cli.py b/tests/test_cli.py index 75c1a6d..fe77199 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -407,3 +407,52 @@ def test_exit_codes(): # Make sure that we got exit code 100 for a failed model build assert exitcode == 100 + + +def test_expression_argument(): + """ + Tests the CLI with the the expression argument. + """ + test_file = helpers.get_test_file_location("no_toplevel_objects.py") + + # Get a temporary output file location + temp_dir = tempfile.gettempdir() + temp_file = os.path.join(temp_dir, "temp_test_10.step") + + # Run cq-cli with --expression "cube()" + command = [ + "python", + "src/cq_cli/main.py", + "--codec", + "step", + "--infile", + test_file, + "--outfile", + temp_file, + "--expression", + "cube()", + ] + out, err, exitcode = helpers.cli_call(command) + + # Read the STEP output back from the outfile + with open(temp_file, "r") as file: + step_str = file.read() + + assert step_str.startswith("ISO-10303-21;") + + # Run cq-cli on the same model file, but don't specify an --expression. This + # should fail because the file contains no top-level show_object() calls. + command = [ + "python", + "src/cq_cli/main.py", + "--codec", + "step", + "--infile", + test_file, + "--outfile", + temp_file, + ] + out, err, exitcode = helpers.cli_call(command) + + # cq-cli invocation should fail + assert exitcode == 200 diff --git a/tests/testdata/no_toplevel_objects.py b/tests/testdata/no_toplevel_objects.py new file mode 100644 index 0000000..531e1fd --- /dev/null +++ b/tests/testdata/no_toplevel_objects.py @@ -0,0 +1,8 @@ +import cadquery as cq + +# This test file contains a method for creating a shape, but does not contain +# any top-level `show_object()` calls. + + +def cube(): + return cq.Workplane().box(1, 1, 1)