From 9acc09c4a06a452da7156eea26d7722a599892ae Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 23 Oct 2023 10:29:07 -0400 Subject: [PATCH 01/28] Initial restructuring --- pyproject.toml | 16 +++++++++++----- __init__.py => src/cq_cli/__init__.py | 0 cq-cli.py => src/cq_cli/cq_cli.py | 0 {cqcodecs => src/cq_cli/cqcodecs}/__init__.py | 0 .../cq_cli/cqcodecs}/codec_helpers.py | 0 .../cq_cli/cqcodecs}/cq_codec_gltf.py | 0 .../cq_cli/cqcodecs}/cq_codec_step.py | 0 .../cq_cli/cqcodecs}/cq_codec_stl.py | 0 .../cq_cli/cqcodecs}/cq_codec_svg.py | 0 .../cq_cli/cqcodecs}/cq_codec_threejs.py | 0 {cqcodecs => src/cq_cli/cqcodecs}/loader.py | 0 11 files changed, 11 insertions(+), 5 deletions(-) rename __init__.py => src/cq_cli/__init__.py (100%) rename cq-cli.py => src/cq_cli/cq_cli.py (100%) rename {cqcodecs => src/cq_cli/cqcodecs}/__init__.py (100%) rename {cqcodecs => src/cq_cli/cqcodecs}/codec_helpers.py (100%) rename {cqcodecs => src/cq_cli/cqcodecs}/cq_codec_gltf.py (100%) rename {cqcodecs => src/cq_cli/cqcodecs}/cq_codec_step.py (100%) rename {cqcodecs => src/cq_cli/cqcodecs}/cq_codec_stl.py (100%) rename {cqcodecs => src/cq_cli/cqcodecs}/cq_codec_svg.py (100%) rename {cqcodecs => src/cq_cli/cqcodecs}/cq_codec_threejs.py (100%) rename {cqcodecs => src/cq_cli/cqcodecs}/loader.py (100%) diff --git a/pyproject.toml b/pyproject.toml index a733bcb..02e8527 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,11 @@ [build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" [project] -name = "cq-cli" -version = "2.1.0" -license = "Apache-2.0" +name = "cq_cli" +version = "2.3.0" +license = {file = "LICENSE"} authors = [ { name="Jeremy Wright" }, ] @@ -20,6 +20,12 @@ dependencies = [ 'cadquery >= 2.3.1', ] +[project.optional-dependencies] +dev = [ + "black==19.10b0", + "click==8.0.4" +] + [project.urls] "Homepage" = "https://github.com/CadQuery/cq-cli" "Bug Tracker" = "https://github.com/CadQuery/cq-cli/issues" diff --git a/__init__.py b/src/cq_cli/__init__.py similarity index 100% rename from __init__.py rename to src/cq_cli/__init__.py diff --git a/cq-cli.py b/src/cq_cli/cq_cli.py similarity index 100% rename from cq-cli.py rename to src/cq_cli/cq_cli.py diff --git a/cqcodecs/__init__.py b/src/cq_cli/cqcodecs/__init__.py similarity index 100% rename from cqcodecs/__init__.py rename to src/cq_cli/cqcodecs/__init__.py diff --git a/cqcodecs/codec_helpers.py b/src/cq_cli/cqcodecs/codec_helpers.py similarity index 100% rename from cqcodecs/codec_helpers.py rename to src/cq_cli/cqcodecs/codec_helpers.py diff --git a/cqcodecs/cq_codec_gltf.py b/src/cq_cli/cqcodecs/cq_codec_gltf.py similarity index 100% rename from cqcodecs/cq_codec_gltf.py rename to src/cq_cli/cqcodecs/cq_codec_gltf.py diff --git a/cqcodecs/cq_codec_step.py b/src/cq_cli/cqcodecs/cq_codec_step.py similarity index 100% rename from cqcodecs/cq_codec_step.py rename to src/cq_cli/cqcodecs/cq_codec_step.py diff --git a/cqcodecs/cq_codec_stl.py b/src/cq_cli/cqcodecs/cq_codec_stl.py similarity index 100% rename from cqcodecs/cq_codec_stl.py rename to src/cq_cli/cqcodecs/cq_codec_stl.py diff --git a/cqcodecs/cq_codec_svg.py b/src/cq_cli/cqcodecs/cq_codec_svg.py similarity index 100% rename from cqcodecs/cq_codec_svg.py rename to src/cq_cli/cqcodecs/cq_codec_svg.py diff --git a/cqcodecs/cq_codec_threejs.py b/src/cq_cli/cqcodecs/cq_codec_threejs.py similarity index 100% rename from cqcodecs/cq_codec_threejs.py rename to src/cq_cli/cqcodecs/cq_codec_threejs.py diff --git a/cqcodecs/loader.py b/src/cq_cli/cqcodecs/loader.py similarity index 100% rename from cqcodecs/loader.py rename to src/cq_cli/cqcodecs/loader.py From 109f14f67ae50068954ab66822a862edf0bdde34 Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 23 Oct 2023 10:30:04 -0400 Subject: [PATCH 02/28] Black formatting pass --- src/cq_cli/cq_cli.py | 146 +++++++++++++++------- src/cq_cli/cqcodecs/codec_helpers.py | 7 +- src/cq_cli/cqcodecs/cq_codec_gltf.py | 9 +- src/cq_cli/cqcodecs/cq_codec_step.py | 7 +- src/cq_cli/cqcodecs/cq_codec_stl.py | 7 +- src/cq_cli/cqcodecs/cq_codec_svg.py | 12 +- src/cq_cli/cqcodecs/cq_codec_threejs.py | 7 +- src/cq_cli/cqcodecs/loader.py | 5 +- tests/test_cli.py | 154 ++++++++++++++++++++---- tests/test_gltf_codec.py | 7 +- tests/test_helpers.py | 11 +- tests/test_step_codec.py | 3 +- tests/test_stl_codec.py | 19 ++- tests/test_svg_codec.py | 17 ++- tests/test_threejs_codec.py | 9 +- tests/testdata/cube.py | 2 +- tests/testdata/cube_assy.py | 2 +- tests/testdata/cube_params.py | 2 +- tests/testdata/impossible_cube.py | 2 +- tests/testdata/sphere.py | 2 +- 20 files changed, 321 insertions(+), 109 deletions(-) diff --git a/src/cq_cli/cq_cli.py b/src/cq_cli/cq_cli.py index c76e20c..aa7e02e 100755 --- a/src/cq_cli/cq_cli.py +++ b/src/cq_cli/cq_cli.py @@ -9,11 +9,12 @@ import json from cqcodecs import loader + def build_and_parse(script_str, params, errfile): """ 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 + # 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 cqModel = cqgi.parse(script_str) @@ -22,7 +23,7 @@ def build_and_parse(script_str, params, errfile): # Handle the case of the build not being successful, otherwise pass the codec the build result if not build_result.success: # Re-throw the exception so that it will be caught and formatted correctly - raise(build_result.exception) + raise (build_result.exception) else: return build_result except Exception: @@ -30,7 +31,7 @@ def build_and_parse(script_str, params, errfile): # If there was an error file specified write to that, otherwise send it to stderr if errfile != None: - with open(errfile, 'w') as file: + with open(errfile, "w") as file: file.write(str(out_tb)) else: print(str(out_tb), file=sys.stderr) @@ -41,6 +42,7 @@ def build_and_parse(script_str, params, errfile): # Return None here to prevent a failed build from slipping through return None + def get_script_from_infile(infile, outfile, errfile): """ Gets the CadQuery script from the infile location. @@ -58,7 +60,7 @@ def get_script_from_infile(infile, outfile, errfile): if errfile == None: print("infile does not exist.", file=sys.stderr) else: - with open(errfile, 'w') as file: + with open(errfile, "w") as file: file.write("Argument error: infile does not exist.") return None @@ -68,7 +70,7 @@ def get_script_from_infile(infile, outfile, errfile): # Grab the string from stdin script_str = sys.stdin.read() else: - with open(infile, 'r') as file: + with open(infile, "r") as file: script_str = file.read() return script_str @@ -96,7 +98,7 @@ def get_params_from_file(param_json_path, errfile): # Make sure that the file exists if os.path.isfile(param_json_path): # Read the contents of the file - with open(param_json_path, 'r') as file: + with open(param_json_path, "r") as file: params_json = file.read() param_dict_array = json.loads(params_json) @@ -112,10 +114,15 @@ def get_params_from_file(param_json_path, errfile): param_dict[key] = param_dict_array[key] else: if errfile == None: - print("Parameter file does not exist, default parameters will be used. ", file=sys.stderr) + print( + "Parameter file does not exist, default parameters will be used. ", + file=sys.stderr, + ) else: - with open(errfile, 'w') as file: - file.write("Argument error: Parameter file does not exist, default parameters will be used.") + with open(errfile, "w") as file: + file.write( + "Argument error: Parameter file does not exist, default parameters will be used." + ) return param_dict @@ -131,21 +138,52 @@ def main(): loaded_codecs = loader.load_codecs() # Parse the command line arguments - parser = argparse.ArgumentParser(description='Command line utility for converting CadQuery script output to various other output formats.') - parser.add_argument('--codec', help='The codec to use when converting the CadQuery output. Must match the name of a codec file in the cqcodecs directory.') - parser.add_argument('--getparams', help='Analyzes the script and returns a JSON string with the parameter information.') - parser.add_argument('--infile', help='The input CadQuery script to convert.') - parser.add_argument('--outfile', help='File to write the converted CadQuery output to. Prints to stdout if not specified.') - parser.add_argument('--errfile', help='File to write any errors to. Prints to stderr if not specified.') - parser.add_argument('--params', help='A colon and semicolon delimited string (no spaces) of key/value pairs representing variables and their values in the CadQuery script. i.e. var1:10.0;var2:4.0;') - parser.add_argument('--outputopts', dest='opts', help='A colon and semicolon delimited string (no spaces) of key/value pairs representing options to pass to the selected codec. i.e. width:100;height:200;') - parser.add_argument('--validate', help='Setting to true forces the CLI to only parse and validate the script and not produce converted output.') + parser = argparse.ArgumentParser( + description="Command line utility for converting CadQuery script output to various other output formats." + ) + parser.add_argument( + "--codec", + help="The codec to use when converting the CadQuery output. Must match the name of a codec file in the cqcodecs directory.", + ) + parser.add_argument( + "--getparams", + help="Analyzes the script and returns a JSON string with the parameter information.", + ) + parser.add_argument("--infile", help="The input CadQuery script to convert.") + parser.add_argument( + "--outfile", + help="File to write the converted CadQuery output to. Prints to stdout if not specified.", + ) + parser.add_argument( + "--errfile", + help="File to write any errors to. Prints to stderr if not specified.", + ) + parser.add_argument( + "--params", + help="A colon and semicolon delimited string (no spaces) of key/value pairs representing variables and their values in the CadQuery script. i.e. var1:10.0;var2:4.0;", + ) + parser.add_argument( + "--outputopts", + dest="opts", + help="A colon and semicolon delimited string (no spaces) of key/value pairs representing options to pass to the selected codec. i.e. width:100;height:200;", + ) + parser.add_argument( + "--validate", + help="Setting to true forces the CLI to only parse and validate the script and not produce converted output.", + ) args = parser.parse_args() # Make sure that the user has at least specified the validate or codec arguments - if args.validate == None and args.infile == None and args.codec == None and args.outfile == None: - print("Please specify at least the validate option plus an infile, or an infile and an outfile or a codec.") + if ( + args.validate == None + and args.infile == None + and args.codec == None + and args.outfile == None + ): + print( + "Please specify at least the validate option plus an infile, or an infile and an outfile or a codec." + ) parser.print_help(sys.stderr) sys.exit(2) @@ -167,9 +205,10 @@ def main(): # Validation handling # # If the user wants to validate, do that and exit - if args.validate == 'true': + if args.validate == "true": script_str = get_script_from_infile(args.infile, outfile, errfile) - if script_str == None: sys.exit(1) + if script_str == None: + sys.exit(1) # Set the PYTHONPATH variable to the current directory to allow module loading set_pythonpath_for_infile(args.infile) @@ -180,10 +219,10 @@ def main(): if build_result != None and build_result.success: # Let the user know that the validation was a success if outfile != None: - with open(outfile, 'w') as file: - file.write('validation_success') + with open(outfile, "w") as file: + file.write("validation_success") else: - print('validation_success') + print("validation_success") return 0 @@ -198,7 +237,8 @@ def main(): # Load the script string script_str = get_script_from_infile(args.infile, outfile, errfile) - if script_str == None: sys.exit(1) + if script_str == None: + sys.exit(1) # Set the PYTHONPATH variable to the current directory to allow module loading set_pythonpath_for_infile(args.infile) @@ -249,10 +289,10 @@ def main(): params.append(new_dict) # Write the converted output to the appropriate place based on the command line arguments - if args.getparams == 'true': + if args.getparams == "true": print(json.dumps(params)) else: - with open(args.getparams, 'w') as file: + with open(args.getparams, "w") as file: file.write(json.dumps(params)) # Check to see if the user only cared about getting the params @@ -268,24 +308,26 @@ def main(): # Attempt to auto-detect the codec if the user has not set the option if args.outfile != None and args.codec == None: # Determine the codec from the file extension - codec_temp = args.outfile.split('.')[-1] + codec_temp = args.outfile.split(".")[-1] if codec_temp != None: codec_temp = "cq_codec_" + codec_temp if codec_temp in loaded_codecs: codec = codec_temp # If the user has not supplied a codec, they need to be validating the script - if (codec == None and args.outfile == None) and (args.validate == None or args.validate == 'false'): + if (codec == None and args.outfile == None) and ( + args.validate == None or args.validate == "false" + ): print("Please specify a valid codec. You have the following to choose from:") for key in loaded_codecs: - print(key.replace('cq_codec_', '')) + print(key.replace("cq_codec_", "")) sys.exit(3) # If the codec is None at this point, the user specified an invalid codec if codec == None: print("Please specify a valid codec. You have the following to choose from:") for key in loaded_codecs: - print(key.replace('cq_codec_', '')) + print(key.replace("cq_codec_", "")) sys.exit(3) for key in loaded_codecs: @@ -300,7 +342,8 @@ def main(): # Grab the script input from a file path or stdin script_str = get_script_from_infile(infile, outfile, errfile) - if script_str == None: sys.exit(1) + if script_str == None: + sys.exit(1) # Set the PYTHONPATH variable to the current directory to allow module loading set_pythonpath_for_infile(args.infile) @@ -311,7 +354,13 @@ def main(): # Check whether any parameters were passed if args.params != None: # We have been passed a directory - if args.params.startswith('/') or args.params.startswith('.') or args.params.startswith('..') or args.params.startswith('~') or args.params[1] == ':': + if ( + args.params.startswith("/") + or args.params.startswith(".") + or args.params.startswith("..") + or args.params.startswith("~") + or args.params[1] == ":" + ): # Load the parameters dictionary from the file file_params = get_params_from_file(args.params, errfile) @@ -323,9 +372,9 @@ def main(): params = json.loads(args.params) else: # Convert the string of parameters into a params dictionary - groups = args.params.split(';') + groups = args.params.split(";") for group in groups: - param_parts = group.split(':') + param_parts = group.split(":") # Protect against a trailing semi-colon if len(param_parts) == 2: params[param_parts[0]] = param_parts[1] @@ -336,9 +385,9 @@ def main(): # Check whether any output options were passed if args.opts != None: # Convert the string of options into a output_opts dictionary - groups = args.opts.split(';') + groups = args.opts.split(";") for group in groups: - opt_parts = group.split(':') + opt_parts = group.split(":") # Protect against a trailing semi-colon if len(opt_parts) == 2: op1 = opt_parts[1] @@ -347,7 +396,12 @@ def main(): if op1 == "True" or op1 == "False": op = opt_parts[1] == "True" elif op1[:1] == "(": - op = tuple(map(float, opt_parts[1].replace("(", "").replace(")", "").split(','))) + op = tuple( + map( + float, + opt_parts[1].replace("(", "").replace(")", "").split(","), + ) + ) elif "." in op1: op = float(opt_parts[1]) else: @@ -370,7 +424,7 @@ def main(): if errfile == None: print("build_and_parse error: " + str(err), file=sys.stderr) else: - with open(errfile, 'w') as file: + with open(errfile, "w") as file: file.write(err) sys.exit(100) @@ -389,13 +443,16 @@ def main(): print(converted) else: if isinstance(converted, str): - with open(outfile, 'w') as file: + with open(outfile, "w") as file: file.write(converted) elif isinstance(converted, (bytes, bytearray)): - with open(outfile, 'wb') as file: + with open(outfile, "wb") as file: file.write(converted) else: - raise TypeError("Expected converted output to be str, bytes, or bytearray. Got '%s'" % type(converted).__name__) + raise TypeError( + "Expected converted output to be str, bytes, or bytearray. Got '%s'" + % type(converted).__name__ + ) except Exception: out_tb = traceback.format_exc() @@ -404,10 +461,11 @@ def main(): if errfile == None: print("Conversion codec error: " + str(out_tb), file=sys.stderr) else: - with open(errfile, 'w') as file: + with open(errfile, "w") as file: file.write(str(out_tb)) sys.exit(200) + if __name__ == "__main__": main() diff --git a/src/cq_cli/cqcodecs/codec_helpers.py b/src/cq_cli/cqcodecs/codec_helpers.py index e4c3311..8cfc228 100644 --- a/src/cq_cli/cqcodecs/codec_helpers.py +++ b/src/cq_cli/cqcodecs/codec_helpers.py @@ -1,9 +1,10 @@ -from contextlib import contextmanager,redirect_stderr,redirect_stdout +from contextlib import contextmanager, redirect_stderr, redirect_stdout from os import devnull + @contextmanager def suppress_stdout_stderr(): """A context manager that redirects stdout and stderr to devnull""" - with open(devnull, 'w') as fnull: + with open(devnull, "w") as fnull: with redirect_stderr(fnull) as err, redirect_stdout(fnull) as out: - yield (err, out) \ No newline at end of file + yield (err, out) diff --git a/src/cq_cli/cqcodecs/cq_codec_gltf.py b/src/cq_cli/cqcodecs/cq_codec_gltf.py index dc17a68..827a195 100644 --- a/src/cq_cli/cqcodecs/cq_codec_gltf.py +++ b/src/cq_cli/cqcodecs/cq_codec_gltf.py @@ -3,6 +3,7 @@ import cadquery as cq import cqcodecs.codec_helpers as helpers + def convert(build_result, output_file=None, error_file=None, output_opts=None): # Create a temporary file to put the STL output into temp_dir = tempfile.gettempdir() @@ -15,10 +16,12 @@ def convert(build_result, output_file=None, error_file=None, output_opts=None): if type(build_result.first_result.shape).__name__ == "Assembly": build_result.first_result.shape.save(temp_file, binary=False) else: - raise ValueError("GLTF export is only available for CadQuery assemblies at this time") + raise ValueError( + "GLTF export is only available for CadQuery assemblies at this time" + ) # Read the GLTF output back in - with open(temp_file, 'r') as file: + with open(temp_file, "r") as file: gltf_str = file.read() - return gltf_str \ No newline at end of file + return gltf_str diff --git a/src/cq_cli/cqcodecs/cq_codec_step.py b/src/cq_cli/cqcodecs/cq_codec_step.py index 6bdec53..4968ed8 100644 --- a/src/cq_cli/cqcodecs/cq_codec_step.py +++ b/src/cq_cli/cqcodecs/cq_codec_step.py @@ -3,6 +3,7 @@ import cadquery as cq import cqcodecs.codec_helpers as helpers + def convert(build_result, output_file=None, error_file=None, output_opts=None): # Create a temporary file to put the STL output into temp_dir = tempfile.gettempdir() @@ -11,10 +12,12 @@ def convert(build_result, output_file=None, error_file=None, output_opts=None): # The exporters will add extra output that we do not want, so suppress it with helpers.suppress_stdout_stderr(): # Put the STEP output into the temp file - exporters.export(build_result.results[0].shape, temp_file, exporters.ExportTypes.STEP) + exporters.export( + build_result.results[0].shape, temp_file, exporters.ExportTypes.STEP + ) # Read the STEP output back in - with open(temp_file, 'r') as file: + with open(temp_file, "r") as file: step_str = file.read() return step_str diff --git a/src/cq_cli/cqcodecs/cq_codec_stl.py b/src/cq_cli/cqcodecs/cq_codec_stl.py index 126ed1c..9eb55e6 100644 --- a/src/cq_cli/cqcodecs/cq_codec_stl.py +++ b/src/cq_cli/cqcodecs/cq_codec_stl.py @@ -3,6 +3,7 @@ import cadquery as cq import cqcodecs.codec_helpers as helpers + def convert(build_result, output_file=None, error_file=None, output_opts=None): # Create a temporary file to put the STL output into temp_dir = tempfile.gettempdir() @@ -20,10 +21,12 @@ def convert(build_result, output_file=None, error_file=None, output_opts=None): # The exporters will add extra output that we do not want, so suppress it with helpers.suppress_stdout_stderr(): # Put the STL output into the temp file - build_result.results[0].shape.val().exportStl(temp_file, linearDeflection, angularDeflection, True) + build_result.results[0].shape.val().exportStl( + temp_file, linearDeflection, angularDeflection, True + ) # Read the STL output back in - with open(temp_file, 'r') as file: + with open(temp_file, "r") as file: stl_str = file.read() return stl_str diff --git a/src/cq_cli/cqcodecs/cq_codec_svg.py b/src/cq_cli/cqcodecs/cq_codec_svg.py index cf9a5e5..a3d6e99 100644 --- a/src/cq_cli/cqcodecs/cq_codec_svg.py +++ b/src/cq_cli/cqcodecs/cq_codec_svg.py @@ -3,6 +3,7 @@ import cadquery as cq import cqcodecs.codec_helpers as helpers + def convert(build_result, output_file=None, error_file=None, output_opts=None): # Create a temporary file to put the STL output into temp_dir = tempfile.gettempdir() @@ -11,10 +12,15 @@ def convert(build_result, output_file=None, error_file=None, output_opts=None): # The exporters will add extra output that we do not want, so suppress it with helpers.suppress_stdout_stderr(): # Put the STEP output into the temp file - exporters.export(build_result.results[0].shape, temp_file, exporters.ExportTypes.SVG, opt=output_opts) + exporters.export( + build_result.results[0].shape, + temp_file, + exporters.ExportTypes.SVG, + opt=output_opts, + ) # Read the STEP output back in - with open(temp_file, 'r') as file: + with open(temp_file, "r") as file: step_str = file.read() - return step_str \ No newline at end of file + return step_str diff --git a/src/cq_cli/cqcodecs/cq_codec_threejs.py b/src/cq_cli/cqcodecs/cq_codec_threejs.py index c547d27..88aacbc 100644 --- a/src/cq_cli/cqcodecs/cq_codec_threejs.py +++ b/src/cq_cli/cqcodecs/cq_codec_threejs.py @@ -3,6 +3,7 @@ import cadquery as cq import cqcodecs.codec_helpers as helpers + def convert(build_result, output_file=None, error_file=None, output_opts=None): # Create a temporary file to put the STL output into temp_dir = tempfile.gettempdir() @@ -11,10 +12,12 @@ def convert(build_result, output_file=None, error_file=None, output_opts=None): # The exporters will add extra output that we do not want, so suppress it with helpers.suppress_stdout_stderr(): # Put the STEP output into the temp file - exporters.export(build_result.results[0].shape, temp_file, exporters.ExportTypes.TJS) + exporters.export( + build_result.results[0].shape, temp_file, exporters.ExportTypes.TJS + ) # Read the STEP output back in - with open(temp_file, 'r') as file: + with open(temp_file, "r") as file: tjs_str = file.read() return tjs_str diff --git a/src/cq_cli/cqcodecs/loader.py b/src/cq_cli/cqcodecs/loader.py index feb5942..a98605b 100644 --- a/src/cq_cli/cqcodecs/loader.py +++ b/src/cq_cli/cqcodecs/loader.py @@ -2,12 +2,13 @@ import importlib import pkgutil + def load_codecs(): cq_codecs = {} # Search all of the modules in the current directory to find codecs for finder, name, ispkg in pkgutil.iter_modules([os.path.dirname(__file__)]): - if name.startswith('cq_codec_'): + if name.startswith("cq_codec_"): cq_codecs[name] = importlib.import_module("cqcodecs." + name) - return cq_codecs \ No newline at end of file + return cq_codecs diff --git a/tests/test_cli.py b/tests/test_cli.py index baebc26..af181e8 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -3,6 +3,7 @@ import tests.test_helpers as helpers import json + def test_no_cli_arguments(): """ Runs the CLI with no arguments, which you should not do unless you want the usage message. @@ -10,7 +11,12 @@ def test_no_cli_arguments(): command = ["python", "cq-cli.py"] out, err, exitcode = helpers.cli_call(command) - assert out.decode().split('\n')[0].startswith("Please specify at least the validate option") + assert ( + out.decode() + .split("\n")[0] + .startswith("Please specify at least the validate option") + ) + def test_codec_and_infile_arguments_file_nonexistent(): """ @@ -23,6 +29,7 @@ def test_codec_and_infile_arguments_file_nonexistent(): assert err.decode().startswith("infile does not exist.") + def test_codec_and_infile_arguments(): """ Test the CLI with only the codec and infile set, with a file that exists. @@ -32,7 +39,8 @@ def test_codec_and_infile_arguments(): command = ["python", "cq-cli.py", "--codec", "step", "--infile", test_file] out, err, exitcode = helpers.cli_call(command) - assert out.decode().split('\n')[0].replace('\r', '') == "ISO-10303-21;" + assert out.decode().split("\n")[0].replace("\r", "") == "ISO-10303-21;" + def test_codec_infile_and_outfile_arguments(): """ @@ -44,15 +52,25 @@ def test_codec_infile_and_outfile_arguments(): temp_dir = tempfile.gettempdir() temp_file = os.path.join(temp_dir, "temp_test_4.step") - command = ["python", "cq-cli.py", "--codec", "step", "--infile", test_file, '--outfile', temp_file] + command = [ + "python", + "cq-cli.py", + "--codec", + "step", + "--infile", + test_file, + "--outfile", + temp_file, + ] out, err, exitcode = helpers.cli_call(command) # Read the STEP output back from the outfile - with open(temp_file, 'r') as file: + with open(temp_file, "r") as file: step_str = file.read() assert step_str.startswith("ISO-10303-21;") + def test_codec_infile_outfile_errfile_arguments(): """ Tests the CLI with the codec, infile, outfile and errfile parameters set. @@ -65,11 +83,22 @@ def test_codec_infile_outfile_errfile_arguments(): temp_file = os.path.join(temp_dir, "temp_test_5.step") err_file = os.path.join(temp_dir, "temp_test_5_error.txt") - command = ["python", "cq-cli.py", "--codec", "step", "--infile", test_file, '--outfile', temp_file, '--errfile', err_file] + command = [ + "python", + "cq-cli.py", + "--codec", + "step", + "--infile", + test_file, + "--outfile", + temp_file, + "--errfile", + err_file, + ] out, err, exitcode = helpers.cli_call(command) # Read the error back from the errfile - with open(err_file, 'r') as file: + with open(err_file, "r") as file: err_str = file.read() assert err_str == "Argument error: infile does not exist." @@ -86,11 +115,22 @@ def test_parameter_file(): temp_dir = tempfile.gettempdir() temp_file = os.path.join(temp_dir, "temp_test_6.step") - command = ["python", "cq-cli.py", "--codec", "step", "--infile", test_file, '--outfile', temp_file, '--params', params_file] + command = [ + "python", + "cq-cli.py", + "--codec", + "step", + "--infile", + test_file, + "--outfile", + temp_file, + "--params", + params_file, + ] out, err, exitcode = helpers.cli_call(command) # Read the STEP output back from the outfile - with open(temp_file, 'r') as file: + with open(temp_file, "r") as file: step_str = file.read() assert step_str.startswith("ISO-10303-21;") @@ -106,11 +146,22 @@ def test_parameter_json_string(): temp_dir = tempfile.gettempdir() temp_file = os.path.join(temp_dir, "temp_test_7.step") - command = ["python", "cq-cli.py", "--codec", "step", "--infile", test_file, '--outfile', temp_file, '--params', "{\"width\":10}"] + command = [ + "python", + "cq-cli.py", + "--codec", + "step", + "--infile", + test_file, + "--outfile", + temp_file, + "--params", + '{"width":10}', + ] out, err, exitcode = helpers.cli_call(command) # Read the STEP output back from the outfile - with open(temp_file, 'r') as file: + with open(temp_file, "r") as file: step_str = file.read() assert step_str.startswith("ISO-10303-21;") @@ -126,11 +177,22 @@ def test_parameter_delimited_string(): temp_dir = tempfile.gettempdir() temp_file = os.path.join(temp_dir, "temp_test_8.step") - command = ["python", "cq-cli.py", "--codec", "step", "--infile", test_file, '--outfile', temp_file, '--params', "width:10;"] + command = [ + "python", + "cq-cli.py", + "--codec", + "step", + "--infile", + test_file, + "--outfile", + temp_file, + "--params", + "width:10;", + ] out, err, exitcode = helpers.cli_call(command) # Read the STEP output back from the outfile - with open(temp_file, 'r') as file: + with open(temp_file, "r") as file: step_str = file.read() assert step_str.startswith("ISO-10303-21;") @@ -180,21 +242,39 @@ def test_parameter_file_input_output(): out, err, exitcode = helpers.cli_call(command) # Run the script with baseline parameters - command2 = ["python", "cq-cli.py", "--codec", "stl", "--infile", test_file, '--params', temp_file] + command2 = [ + "python", + "cq-cli.py", + "--codec", + "stl", + "--infile", + test_file, + "--params", + temp_file, + ] out2, err2, exitcode2 = helpers.cli_call(command2) assert err2.decode() == "" # Modify the parameters file - with open(temp_file, 'r') as file: + with open(temp_file, "r") as file: json_str = file.read() json_dict = json.loads(json_str) - json_dict[0]['initial'] = 10 + json_dict[0]["initial"] = 10 with open(temp_file, "w") as file: file.writelines(json.dumps(json_dict)) # Run the command with the new parameters - command3 = ["python", "cq-cli.py", "--codec", "stl", "--infile", test_file, '--params', temp_file] + command3 = [ + "python", + "cq-cli.py", + "--codec", + "stl", + "--infile", + test_file, + "--params", + temp_file, + ] out3, err3, exitcode3 = helpers.cli_call(command3) # Make sure that the file output changed @@ -223,28 +303,50 @@ def test_params_stl_output(): file.writelines(json.dumps(params_json)) # Execute the script with the current parameters and save the new parameter metadata to the customizer file - command = ["python", "cq-cli.py", "--codec", "stl", "--infile", test_file, '--outfile', output_file_path, "--params", params_json_file_path, "--getparams", customizer_file_path ] + command = [ + "python", + "cq-cli.py", + "--codec", + "stl", + "--infile", + test_file, + "--outfile", + output_file_path, + "--params", + params_json_file_path, + "--getparams", + customizer_file_path, + ] out, err, exitcode = helpers.cli_call(command) # Make sure there was no error assert err.decode() == "" # Make sure that the customizer.json file exists and has what we expect in it - with open(customizer_file_path, 'r') as file2: + with open(customizer_file_path, "r") as file2: json_str = file2.read() json_dict = json.loads(json_str) - assert json_dict[0]['initial'] == 1 - assert json_dict[1]['initial'] == "cube" - assert json_dict[2]['initial'] == True + assert json_dict[0]["initial"] == 1 + assert json_dict[1]["initial"] == "cube" + assert json_dict[2]["initial"] == True # Write an STL using the default parameters so that we can compare it to what was generated with customized parameters - command = ["python", "cq-cli.py", "--codec", "stl", "--infile", test_file, '--outfile', default_output_file_path ] + command = [ + "python", + "cq-cli.py", + "--codec", + "stl", + "--infile", + test_file, + "--outfile", + default_output_file_path, + ] out2, err2, exitcode2 = helpers.cli_call(command) # Compare the two files to make sure they are different - with open(output_file_path, 'r') as file3: + with open(output_file_path, "r") as file3: stl_output_with_params = file3.read() - with open(default_output_file_path, 'r') as file4: + with open(default_output_file_path, "r") as file4: default_stl = file4.read() assert stl_output_with_params != default_stl @@ -256,7 +358,7 @@ def test_exit_codes(): """ # Test to make sure we get the correct exit code when no parameters are specified - command = ["python", "cq-cli.py" ] + command = ["python", "cq-cli.py"] out, err, exitcode = helpers.cli_call(command) # Make sure that we got exit code 2 @@ -266,7 +368,7 @@ def test_exit_codes(): test_input_file = helpers.get_test_file_location("impossible_cube.py") # Execute the script with the current parameters and save the new parameter metadata to the customizer file - command = ["python", "cq-cli.py", "--codec", "step", "--infile", test_input_file ] + command = ["python", "cq-cli.py", "--codec", "step", "--infile", test_input_file] out, err, exitcode = helpers.cli_call(command) # Make sure that we got exit code 100 for a failed model build diff --git a/tests/test_gltf_codec.py b/tests/test_gltf_codec.py index 53da3da..75dae84 100644 --- a/tests/test_gltf_codec.py +++ b/tests/test_gltf_codec.py @@ -1,7 +1,10 @@ import pytest import tests.test_helpers as helpers -@pytest.mark.skip(reason="Waiting on #1414 on the CadQuery repo to be merged to finish this") + +@pytest.mark.skip( + reason="Waiting on #1414 on the CadQuery repo to be merged to finish this" +) def test_gltf_codec(): """ Basic test of the GLTF codec plugin. @@ -11,4 +14,4 @@ def test_gltf_codec(): command = ["python", "cq-cli.py", "--codec", "gltf", "--infile", test_file] out, err, exitcode = helpers.cli_call(command) - assert out.decode().split('\n')[0].replace('\r', '').startswith("{\"accessors\":") + assert out.decode().split("\n")[0].replace("\r", "").startswith('{"accessors":') diff --git a/tests/test_helpers.py b/tests/test_helpers.py index f1592a0..631aa04 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -1,6 +1,7 @@ import os import subprocess + def get_test_file_location(file_name): """ Combines the testdata directory path with a filename for a test. @@ -9,13 +10,11 @@ def get_test_file_location(file_name): return os.path.join(test_data_dir, file_name) + def cli_call(command): """ Makes the operating system process calls to test the CLI properly. """ - proc = subprocess.Popen(command, - stdout = subprocess.PIPE, - stderr = subprocess.PIPE, - ) - out,err = proc.communicate() - return out, err, proc.returncode \ No newline at end of file + proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,) + out, err = proc.communicate() + return out, err, proc.returncode diff --git a/tests/test_step_codec.py b/tests/test_step_codec.py index 8f349bd..98bf283 100644 --- a/tests/test_step_codec.py +++ b/tests/test_step_codec.py @@ -1,5 +1,6 @@ import tests.test_helpers as helpers + def test_step_codec(): """ Basic test of the STEP codec plugin. @@ -9,4 +10,4 @@ def test_step_codec(): command = ["python", "cq-cli.py", "--codec", "step", "--infile", test_file] out, err, exitcode = helpers.cli_call(command) - assert out.decode().split('\n')[0].replace('\r', '') == "ISO-10303-21;" \ No newline at end of file + assert out.decode().split("\n")[0].replace("\r", "") == "ISO-10303-21;" diff --git a/tests/test_stl_codec.py b/tests/test_stl_codec.py index 945c51c..9892015 100644 --- a/tests/test_stl_codec.py +++ b/tests/test_stl_codec.py @@ -1,6 +1,7 @@ import os import tests.test_helpers as helpers + def test_stl_codec(): """ Basic test of the STL codec plugin. @@ -10,7 +11,8 @@ def test_stl_codec(): command = ["python", "cq-cli.py", "--codec", "stl", "--infile", test_file] out, err, exitcode = helpers.cli_call(command) - assert out.decode().split('\n')[0].replace('\r', '') == "solid " + assert out.decode().split("\n")[0].replace("\r", "") == "solid " + def test_stl_codec_quality(): """ @@ -22,13 +24,22 @@ def test_stl_codec_quality(): out, err, exitcode = helpers.cli_call(command) # Keep track of the number of lines for each STL as an approximate measure of quality - high_detail = len(out.decode().split('\n')) + high_detail = len(out.decode().split("\n")) # Attempt to adjust the quality of the resulting STL - command2 = ["python", "cq-cli.py", "--codec", "stl", "--infile", test_file, "--outputopts", "linearDeflection:0.3;angularDeflection:0.3"] + command2 = [ + "python", + "cq-cli.py", + "--codec", + "stl", + "--infile", + test_file, + "--outputopts", + "linearDeflection:0.3;angularDeflection:0.3", + ] out2, err2, exitcode2 = helpers.cli_call(command2) # Keep track of the number of lines in the STL as an approximate measure of quality - low_detail = len(out2.decode().split('\n')) + low_detail = len(out2.decode().split("\n")) assert low_detail < high_detail diff --git a/tests/test_svg_codec.py b/tests/test_svg_codec.py index c8cbc16..a857329 100644 --- a/tests/test_svg_codec.py +++ b/tests/test_svg_codec.py @@ -1,12 +1,25 @@ import tests.test_helpers as helpers + def test_svg_codec(): """ Basic test of the SVG codec plugin. """ test_file = helpers.get_test_file_location("cube.py") - command = ["python", "cq-cli.py", "--codec", "svg", "--infile", test_file, "--outputopts", "width:100;height:100;marginLeft:12;marginTop:12;showAxes:False;projectionDir:(0.5,0.5,0.5);strokeWidth:0.25;strokeColor:(255,0,0);hiddenColor:(0,0,255);showHidden:True;"] + command = [ + "python", + "cq-cli.py", + "--codec", + "svg", + "--infile", + test_file, + "--outputopts", + "width:100;height:100;marginLeft:12;marginTop:12;showAxes:False;projectionDir:(0.5,0.5,0.5);strokeWidth:0.25;strokeColor:(255,0,0);hiddenColor:(0,0,255);showHidden:True;", + ] out, err, exitcode = helpers.cli_call(command) - assert out.decode().split('\n')[0].replace('\r', '') == "" \ No newline at end of file + assert ( + out.decode().split("\n")[0].replace("\r", "") + == '' + ) diff --git a/tests/test_threejs_codec.py b/tests/test_threejs_codec.py index 470176a..f8671ae 100644 --- a/tests/test_threejs_codec.py +++ b/tests/test_threejs_codec.py @@ -1,5 +1,6 @@ import tests.test_helpers as helpers + def test_threejs_codec(): """ Basic test of the TJS (Three.js) codec plugin. @@ -10,5 +11,9 @@ def test_threejs_codec(): out, err, exitcode = helpers.cli_call(command) print("Output New: " + str(out.decode())) print("Error: " + str(err)) - assert out.decode().split('\n')[5].replace('\r', '') == ' "vertices" : 24,' - assert out.decode().split('\n')[6].replace('\r', '') == ' "faces" : 12,' + assert ( + out.decode().split("\n")[5].replace("\r", "") == ' "vertices" : 24,' + ) + assert ( + out.decode().split("\n")[6].replace("\r", "") == ' "faces" : 12,' + ) diff --git a/tests/testdata/cube.py b/tests/testdata/cube.py index 776ac40..1dee3c5 100644 --- a/tests/testdata/cube.py +++ b/tests/testdata/cube.py @@ -2,4 +2,4 @@ cube = cq.Workplane().box(1, 1, 1) -show_object(cube) \ No newline at end of file +show_object(cube) diff --git a/tests/testdata/cube_assy.py b/tests/testdata/cube_assy.py index 28f8d89..4cf3273 100644 --- a/tests/testdata/cube_assy.py +++ b/tests/testdata/cube_assy.py @@ -4,4 +4,4 @@ assy.add(cq.Workplane().box(10, 10, 10)) assy.add(cq.Workplane().box(10, 10, 10), loc=cq.Location((5, 5, 0))) -show_object(assy) \ No newline at end of file +show_object(assy) diff --git a/tests/testdata/cube_params.py b/tests/testdata/cube_params.py index 13db639..da4f29d 100644 --- a/tests/testdata/cube_params.py +++ b/tests/testdata/cube_params.py @@ -6,4 +6,4 @@ cube = cq.Workplane().box(width, width, width, centered).tag(tag_name) -show_object(cube) \ No newline at end of file +show_object(cube) diff --git a/tests/testdata/impossible_cube.py b/tests/testdata/impossible_cube.py index 6a2f612..f1a3ee2 100644 --- a/tests/testdata/impossible_cube.py +++ b/tests/testdata/impossible_cube.py @@ -2,4 +2,4 @@ box = cq.Workplane().box(10, 10, 10).edges().fillet(400.0) -show_object(box) \ No newline at end of file +show_object(box) diff --git a/tests/testdata/sphere.py b/tests/testdata/sphere.py index e892f42..16cba21 100644 --- a/tests/testdata/sphere.py +++ b/tests/testdata/sphere.py @@ -2,4 +2,4 @@ sphere = cq.Workplane().sphere(1) -show_object(sphere) \ No newline at end of file +show_object(sphere) From db3c1ba9551b692285142991ab35c4f50452cc0d Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 23 Oct 2023 10:52:24 -0400 Subject: [PATCH 03/28] Trying to consolidate testing config into one file --- .github/workflows/check-commit-actions.yml | 2 +- .github/workflows/check-pr-actions.yml | 2 +- .github/workflows/tests.yml | 26 ++++++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/check-commit-actions.yml b/.github/workflows/check-commit-actions.yml index 59ca701..af20cef 100644 --- a/.github/workflows/check-commit-actions.yml +++ b/.github/workflows/check-commit-actions.yml @@ -2,7 +2,7 @@ name: tests on: push: branches: - - main + - dev paths-ignore: - 'README.md' - 'LICENSE' diff --git a/.github/workflows/check-pr-actions.yml b/.github/workflows/check-pr-actions.yml index 4ac2a43..e155f40 100644 --- a/.github/workflows/check-pr-actions.yml +++ b/.github/workflows/check-pr-actions.yml @@ -2,7 +2,7 @@ name: check-pr-commit on: pull_request: branches: - - main + - dev paths-ignore: - 'README.md' - 'LICENSE' diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..b58d52b --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,26 @@ +name: tests +on: + push: + branches: + - main + pull_request: + branches: + - main +jobs: + run-pytest-linux: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10"] + steps: + - uses: actions/checkout@v2 + - name: Install CadQuery and pytest + shell: bash --login {0} + run: | + pip install -e . + pip install pytest + - name: Run tests + shell: bash --login {0} + run: | + pytest -v + \ No newline at end of file From 7e2f15f3a57077c6a0d9f2a2060432511b13bbcb Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 23 Oct 2023 10:56:16 -0400 Subject: [PATCH 04/28] Added lint check to CI --- .github/workflows/lint.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..7aebd33 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,25 @@ +name: lint +on: + push: + branches: + - main + pull_request: + branches: + - main +jobs: + run-black-linux: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10"] + steps: + - uses: actions/checkout@v2 + - name: Install CadQuery and pytest + shell: bash --login {0} + run: | + pip install -e . + pip install -e .[dev] + - name: Run tests + shell: bash --login {0} + run: | + black --diff --check . From 3f8922cfea6841a7ebc5b2b5e2b143f44e49e3b8 Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 23 Oct 2023 11:02:38 -0400 Subject: [PATCH 05/28] Trying a newer version of setuptools that supports editable installs --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 02e8527..55a385c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=61.0"] +requires = ["setuptools>=64.0"] build-backend = "setuptools.build_meta" [project] From 6e6f222c124e73e20aedeedff21bfe93350722cd Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 23 Oct 2023 11:04:53 -0400 Subject: [PATCH 06/28] Switching back to hatchling to try to fix editable installs --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 55a385c..d067f17 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] -requires = ["setuptools>=64.0"] -build-backend = "setuptools.build_meta" +requires = ["hatchling"] +build-backend = "hatchling.build" [project] name = "cq_cli" From dc9764812b508e40567e7154127772e1827ed49b Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 23 Oct 2023 11:12:18 -0400 Subject: [PATCH 07/28] Trying to simplify the test config using a matrix --- .github/workflows/tests.yml | 6 ++---- pyproject.toml | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b58d52b..abe1a38 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,15 +12,13 @@ jobs: strategy: matrix: python-version: ["3.10"] + os: [ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v2 - name: Install CadQuery and pytest - shell: bash --login {0} run: | pip install -e . - pip install pytest + pip install -e .[dev] - name: Run tests - shell: bash --login {0} run: | pytest -v - \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index d067f17..62d288c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ dependencies = [ [project.optional-dependencies] dev = [ + "pytest", "black==19.10b0", "click==8.0.4" ] From e6c6b37f8a09b9fd2e424911cbdbcd2d6126a532 Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 23 Oct 2023 11:14:03 -0400 Subject: [PATCH 08/28] Fixed runs-on --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index abe1a38..815d79c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,11 +8,11 @@ on: - main jobs: run-pytest-linux: - runs-on: ubuntu-latest strategy: matrix: python-version: ["3.10"] os: [ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - name: Install CadQuery and pytest From c258c6200897f4621722ffd4d07d618ac303fe38 Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 23 Oct 2023 11:21:07 -0400 Subject: [PATCH 09/28] Forcing an upgrade of pip --- .github/workflows/lint.yml | 3 ++- .github/workflows/tests.yml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7aebd33..3a47739 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -7,7 +7,7 @@ on: branches: - main jobs: - run-black-linux: + run-black-lint: runs-on: ubuntu-latest strategy: matrix: @@ -17,6 +17,7 @@ jobs: - name: Install CadQuery and pytest shell: bash --login {0} run: | + pip install --upgrade pip pip install -e . pip install -e .[dev] - name: Run tests diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 815d79c..49dd637 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,7 @@ on: branches: - main jobs: - run-pytest-linux: + run-pytest: strategy: matrix: python-version: ["3.10"] @@ -17,6 +17,7 @@ jobs: - uses: actions/checkout@v2 - name: Install CadQuery and pytest run: | + pip install --upgrade pip pip install -e . pip install -e .[dev] - name: Run tests From c2a7b5e2b55d8c7005d545d95b653d11427b2a0f Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 23 Oct 2023 11:26:04 -0400 Subject: [PATCH 10/28] Trying to get jobs to stop being cancelled by the system --- .github/workflows/lint.yml | 1 + .github/workflows/tests.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 3a47739..28a6acb 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -10,6 +10,7 @@ jobs: run-black-lint: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: python-version: ["3.10"] steps: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 49dd637..ecd9030 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,6 +9,7 @@ on: jobs: run-pytest: strategy: + fail-fast: false matrix: python-version: ["3.10"] os: [ubuntu-latest, windows-latest] From 357912b06ffe0c029ca25d4af5340690ba7eb010 Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 23 Oct 2023 12:01:30 -0400 Subject: [PATCH 11/28] Reworked PyInstaller spec file and added MacOS to matrix --- .github/workflows/check-commit-actions.yml | 68 ------------- .github/workflows/check-pr-actions.yml | 69 -------------- .github/workflows/tests.yml | 2 +- pyinstaller.spec | 106 +++++++++++++++++++++ 4 files changed, 107 insertions(+), 138 deletions(-) delete mode 100644 .github/workflows/check-commit-actions.yml delete mode 100644 .github/workflows/check-pr-actions.yml create mode 100644 pyinstaller.spec diff --git a/.github/workflows/check-commit-actions.yml b/.github/workflows/check-commit-actions.yml deleted file mode 100644 index af20cef..0000000 --- a/.github/workflows/check-commit-actions.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: tests -on: - push: - branches: - - dev - paths-ignore: - - 'README.md' - - 'LICENSE' - - 'cq-cli_pyinstaller.spec' - - '.github/workflows/pyinstaller-builds-actions.yml' -jobs: - run-pytest: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10"] - steps: - - uses: actions/checkout@v2 - - name: Install CadQuery and pytest - shell: bash --login {0} - run: | - pip install --upgrade pip - pip install --pre git+https://github.com/CadQuery/cadquery.git - pip install pytest - - name: Run tests - shell: bash --login {0} - run: | - pytest -v - # run-pytest-macos: - # runs-on: macos-latest - # strategy: - # matrix: - # python-version: ["3.10"] - # steps: - # - uses: actions/checkout@v2 - # - uses: conda-incubator/setup-miniconda@v2 - # with: - # miniconda-version: "latest" - # python-version: 3.8 - # activate-environment: test - # - name: Install CadQuery and pytest - # shell: bash --login {0} - # run: | - # conda info - # conda install -c cadquery -c conda-forge cadquery=master ocp=7.5.2 python=3.8 - # conda install -c anaconda pytest - # - name: Run tests - # shell: bash --login {0} - # run: | - # conda info - # pytest -v - run-pytest-win: - runs-on: "windows-latest" - strategy: - matrix: - python-version: ["3.10"] - steps: - - uses: actions/checkout@v2 - - name: Install CadQuery and pytest - shell: pwsh - run: | - pip install --upgrade pip - pip install --pre git+https://github.com/CadQuery/cadquery.git - pip install pytest - - name: Run tests - shell: pwsh - run: | - pytest -v diff --git a/.github/workflows/check-pr-actions.yml b/.github/workflows/check-pr-actions.yml deleted file mode 100644 index e155f40..0000000 --- a/.github/workflows/check-pr-actions.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: check-pr-commit -on: - pull_request: - branches: - - dev - paths-ignore: - - 'README.md' - - 'LICENSE' - - 'cq-cli_pyinstaller.spec' - - '.github/workflows/pyinstaller-builds-actions.yml' -jobs: - run-pytest: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10"] - steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.event.pull_request.head.sha }} - - name: Install CadQuery and pytest - shell: bash --login {0} - run: | - pip install --upgrade pip - pip install --pre git+https://github.com/CadQuery/cadquery.git - pip install pytest - - name: Run tests - shell: bash --login {0} - run: | - pytest -v - # run-pytest-macos: - # runs-on: macos-latest - # strategy: - # matrix: - # python-version: ["3.10"] - # steps: - # - uses: actions/checkout@v2 - # with: - # ref: ${{ github.event.pull_request.head.sha }} - # - name: Install CadQuery and pytest - # shell: bash --login {0} - # run: | - # python3 -m ensurepip - # pip3 install --upgrade pip - # pip3 install --pre git+https://github.com/CadQuery/cadquery.git - # pip3 install pytest - # - name: Run tests - # shell: bash --login {0} - # run: | - # pytest -v - run-pytest-win: - runs-on: "windows-latest" - strategy: - matrix: - python-version: ["3.10"] - steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.event.pull_request.head.sha }} - - name: Install CadQuery and pytest - shell: pwsh - run: | - pip install --upgrade pip - pip install --pre git+https://github.com/CadQuery/cadquery.git - pip install pytest - - name: Run tests - shell: pwsh - run: | - pytest -v diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ecd9030..f262322 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ jobs: fail-fast: false matrix: python-version: ["3.10"] - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 diff --git a/pyinstaller.spec b/pyinstaller.spec new file mode 100644 index 0000000..cda6d99 --- /dev/null +++ b/pyinstaller.spec @@ -0,0 +1,106 @@ +# -*- mode: python ; coding: utf-8 -*- +import sys, site, os +import glob +from path import Path +from PyInstaller.utils.hooks import collect_submodules + +# Whether we are running in onefile or dir mode +onefile_mode = True +if len(sys.argv) == 3: + if sys.argv[2] == 'onefile': + onefile_mode = True + elif sys.argv[2] == 'dir': + onefile_mode = False + +block_cipher = None +# if sys.platform == 'linux': +# occt_dir = os.path.join(Path(sys.prefix), 'share', 'opencascade') +# ocp_path = (os.path.join(HOMEPATH, 'OCP.cpython-38-x86_64-linux-gnu.so'), '.') +# elif sys.platform == 'darwin': +# occt_dir = os.path.join(Path(sys.prefix), 'Library', 'share', 'opencascade') +# ocp_path = (os.path.join(HOMEPATH, 'OCP.cpython-38-darwin.so'), '.') +# elif sys.platform == 'win32': +# occt_dir = os.path.join(Path(sys.prefix), 'Library', 'share', 'opencascade') +# ocp_path = (os.path.join(HOMEPATH, 'OCP.cp38-win_amd64.pyd'), '.') + +# Dynamically find all the modules in the cqcodecs directory +hidden_imports = [] +file_list = glob.glob('.' + os.path.sep + "src" + os.path.sep + "cq_cli" + os.path.sep + 'cqcodecs' + os.path.sep + 'cq_codec_*.py') +for file_path in file_list: + file_name = file_path.split(os.path.sep)[-1] + module_name = file_name.replace(".py", "") + hidden_imports.append("cqcodecs." + module_name) +hidden_imports.append('OCP') +hidden_imports.append('typing_extensions') +hidden_imports.append('pyparsing') +hidden_imports.append('ezdxf') +hidden_imports.append('nptyping') +hidden_imports.append('typish') +hidden_imports.append('numpy.core.dtype') +hidden_imports.append('numpy.core._dtype') +hidden_imports.append('vtkmodules') +hidden_imports.append('vtkmodules.all') + +# numpy hidden imports +hidden_imports_numpy = collect_submodules('numpy') +hidden_imports = hidden_imports + hidden_imports_numpy + +a = Analysis(['src/cq_cli/cq_cli.py'], + pathex=['.'], + #binaries=[ + # ocp_path + #], + datas=[ + (os.path.join(os.path.dirname(os.path.realpath('__file__')), 'src', 'cq_cli', 'cqcodecs'), 'cqcodecs') + ], + hiddenimports=hidden_imports, + hookspath=[], + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False) +pyz = PYZ(a.pure, a.zipped_data, + cipher=block_cipher) + +# Select between onefile and dir mode executables +if onefile_mode: + exe = EXE(pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='cq-cli', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=False, + upx_exclude=[], + runtime_tmpdir=None, + console=True ) +else: + exe = EXE(pyz, + a.scripts, + [], + exclude_binaries=True, + name='cq-cli', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=False, + console=True ) + +exclude = ('libGL','libEGL','libbsd') +a.binaries = TOC([x for x in a.binaries if not x[0].startswith(exclude)]) + +if not onefile_mode: + coll = COLLECT(exe, + a.binaries, + a.zipfiles, + a.datas, + strip=False, + upx=False, + upx_exclude=[], + name='cq-cli') From 1cf3e47877104f8ba264848725115c26c5ecd42c Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 23 Oct 2023 12:05:25 -0400 Subject: [PATCH 12/28] Trying to fix login bug on MacOS runner --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f262322..b5b3b08 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,6 +21,8 @@ jobs: pip install --upgrade pip pip install -e . pip install -e .[dev] + shell: bash {0} - name: Run tests run: | pytest -v + shell: bash {0} From ea5a94bfcddc236976a85d33cb07464004301bf9 Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 23 Oct 2023 12:07:03 -0400 Subject: [PATCH 13/28] Disabling MacOS runner for now --- .github/workflows/tests.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b5b3b08..427c9aa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ jobs: fail-fast: false matrix: python-version: ["3.10"] - os: [ubuntu-latest, windows-latest, macos-latest] + os: [ubuntu-latest, windows-latest] # , macos-latest runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 @@ -21,8 +21,6 @@ jobs: pip install --upgrade pip pip install -e . pip install -e .[dev] - shell: bash {0} - name: Run tests run: | pytest -v - shell: bash {0} From eb5a2da0e148e742702e1da559f24ec870672e4b Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Mon, 23 Oct 2023 16:05:34 -0400 Subject: [PATCH 14/28] Trying again to fix MacOS runner --- .github/workflows/tests.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 427c9aa..83ba2bf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,15 +12,15 @@ jobs: fail-fast: false matrix: python-version: ["3.10"] - os: [ubuntu-latest, windows-latest] # , macos-latest + os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - name: Install CadQuery and pytest run: | - pip install --upgrade pip - pip install -e . - pip install -e .[dev] + pip3 install --upgrade pip + pip3 install -e . + pip3 install -e .[dev] - name: Run tests run: | - pytest -v + python3 -m pytest -v From fdd83140911d2eedf6aa497c587e00846b8761e0 Mon Sep 17 00:00:00 2001 From: Justin Buchanan Date: Mon, 23 Oct 2023 19:37:23 -0700 Subject: [PATCH 15/28] update badge url in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 04bffc0..ede0f56 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # cq-cli -[![tests](https://github.com/CadQuery/cq-cli/actions/workflows/check-commit-actions.yml/badge.svg)](https://github.com/CadQuery/cq-cli/actions) +[![tests](https://github.com/CadQuery/cq-cli/actions/workflows/tests.yml/badge.svg)](https://github.com/CadQuery/cq-cli/actions) ## Contents From 0e407f0fbb2d53acf5f5336e41bc20d5c411cae3 Mon Sep 17 00:00:00 2001 From: Justin Buchanan Date: Mon, 23 Oct 2023 19:40:51 -0700 Subject: [PATCH 16/28] tests: fix path to cq-cli.py and run black formatter --- tests/test_cli.py | 67 ++++++++++++++++++++++++++++--------- tests/test_gltf_codec.py | 9 ++++- tests/test_step_codec.py | 9 ++++- tests/test_stl_codec.py | 20 +++++++++-- tests/test_svg_codec.py | 2 +- tests/test_threejs_codec.py | 9 ++++- 6 files changed, 93 insertions(+), 23 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index af181e8..b487a64 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -8,7 +8,7 @@ def test_no_cli_arguments(): """ Runs the CLI with no arguments, which you should not do unless you want the usage message. """ - command = ["python", "cq-cli.py"] + command = ["python", "src/cq_cli/cq_cli.py"] out, err, exitcode = helpers.cli_call(command) assert ( @@ -24,7 +24,14 @@ def test_codec_and_infile_arguments_file_nonexistent(): """ test_file = helpers.get_test_file_location("noexist.py") - command = ["python", "cq-cli.py", "--codec", "step", "--infile", test_file] + command = [ + "python", + "src/cq_cli/cq_cli.py", + "--codec", + "step", + "--infile", + test_file, + ] out, err, exitcode = helpers.cli_call(command) assert err.decode().startswith("infile does not exist.") @@ -36,7 +43,14 @@ def test_codec_and_infile_arguments(): """ test_file = helpers.get_test_file_location("cube.py") - command = ["python", "cq-cli.py", "--codec", "step", "--infile", test_file] + command = [ + "python", + "src/cq_cli/cq_cli.py", + "--codec", + "step", + "--infile", + test_file, + ] out, err, exitcode = helpers.cli_call(command) assert out.decode().split("\n")[0].replace("\r", "") == "ISO-10303-21;" @@ -54,7 +68,7 @@ def test_codec_infile_and_outfile_arguments(): command = [ "python", - "cq-cli.py", + "src/cq_cli/cq_cli.py", "--codec", "step", "--infile", @@ -85,7 +99,7 @@ def test_codec_infile_outfile_errfile_arguments(): command = [ "python", - "cq-cli.py", + "src/cq_cli/cq_cli.py", "--codec", "step", "--infile", @@ -117,7 +131,7 @@ def test_parameter_file(): command = [ "python", - "cq-cli.py", + "src/cq_cli/cq_cli.py", "--codec", "step", "--infile", @@ -148,7 +162,7 @@ def test_parameter_json_string(): command = [ "python", - "cq-cli.py", + "src/cq_cli/cq_cli.py", "--codec", "step", "--infile", @@ -179,7 +193,7 @@ def test_parameter_delimited_string(): command = [ "python", - "cq-cli.py", + "src/cq_cli/cq_cli.py", "--codec", "step", "--infile", @@ -204,7 +218,14 @@ def test_parameter_analysis(): """ test_file = helpers.get_test_file_location("cube_params.py") - command = ["python", "cq-cli.py", "--getparams", "true", "--infile", test_file] + command = [ + "python", + "src/cq_cli/cq_cli.py", + "--getparams", + "true", + "--infile", + test_file, + ] out, err, exitcode = helpers.cli_call(command) # Grab the JSON output from cq-cli @@ -238,13 +259,20 @@ def test_parameter_file_input_output(): temp_file = os.path.join(temp_dir, "temp_test_9.json") # Save the parameters from the script to a file - command = ["python", "cq-cli.py", "--getparams", temp_file, "--infile", test_file] + command = [ + "python", + "src/cq_cli/cq_cli.py", + "--getparams", + temp_file, + "--infile", + test_file, + ] out, err, exitcode = helpers.cli_call(command) # Run the script with baseline parameters command2 = [ "python", - "cq-cli.py", + "src/cq_cli/cq_cli.py", "--codec", "stl", "--infile", @@ -267,7 +295,7 @@ def test_parameter_file_input_output(): # Run the command with the new parameters command3 = [ "python", - "cq-cli.py", + "src/cq_cli/cq_cli.py", "--codec", "stl", "--infile", @@ -305,7 +333,7 @@ def test_params_stl_output(): # Execute the script with the current parameters and save the new parameter metadata to the customizer file command = [ "python", - "cq-cli.py", + "src/cq_cli/cq_cli.py", "--codec", "stl", "--infile", @@ -333,7 +361,7 @@ def test_params_stl_output(): # Write an STL using the default parameters so that we can compare it to what was generated with customized parameters command = [ "python", - "cq-cli.py", + "src/cq_cli/cq_cli.py", "--codec", "stl", "--infile", @@ -358,7 +386,7 @@ def test_exit_codes(): """ # Test to make sure we get the correct exit code when no parameters are specified - command = ["python", "cq-cli.py"] + command = ["python", "src/cq_cli/cq_cli.py"] out, err, exitcode = helpers.cli_call(command) # Make sure that we got exit code 2 @@ -368,7 +396,14 @@ def test_exit_codes(): test_input_file = helpers.get_test_file_location("impossible_cube.py") # Execute the script with the current parameters and save the new parameter metadata to the customizer file - command = ["python", "cq-cli.py", "--codec", "step", "--infile", test_input_file] + command = [ + "python", + "src/cq_cli/cq_cli.py", + "--codec", + "step", + "--infile", + test_input_file, + ] out, err, exitcode = helpers.cli_call(command) # Make sure that we got exit code 100 for a failed model build diff --git a/tests/test_gltf_codec.py b/tests/test_gltf_codec.py index 75dae84..dd3b8df 100644 --- a/tests/test_gltf_codec.py +++ b/tests/test_gltf_codec.py @@ -11,7 +11,14 @@ def test_gltf_codec(): """ test_file = helpers.get_test_file_location("cube_assy.py") - command = ["python", "cq-cli.py", "--codec", "gltf", "--infile", test_file] + command = [ + "python", + "src/cq_cli/cq_cli.py", + "--codec", + "gltf", + "--infile", + test_file, + ] out, err, exitcode = helpers.cli_call(command) assert out.decode().split("\n")[0].replace("\r", "").startswith('{"accessors":') diff --git a/tests/test_step_codec.py b/tests/test_step_codec.py index 98bf283..e7da516 100644 --- a/tests/test_step_codec.py +++ b/tests/test_step_codec.py @@ -7,7 +7,14 @@ def test_step_codec(): """ test_file = helpers.get_test_file_location("cube.py") - command = ["python", "cq-cli.py", "--codec", "step", "--infile", test_file] + command = [ + "python", + "src/cq_cli/cq_cli.py", + "--codec", + "step", + "--infile", + test_file, + ] out, err, exitcode = helpers.cli_call(command) assert out.decode().split("\n")[0].replace("\r", "") == "ISO-10303-21;" diff --git a/tests/test_stl_codec.py b/tests/test_stl_codec.py index 9892015..ce233c0 100644 --- a/tests/test_stl_codec.py +++ b/tests/test_stl_codec.py @@ -8,7 +8,14 @@ def test_stl_codec(): """ test_file = helpers.get_test_file_location("cube.py") - command = ["python", "cq-cli.py", "--codec", "stl", "--infile", test_file] + command = [ + "python", + "src/cq_cli/cq_cli.py", + "--codec", + "stl", + "--infile", + test_file, + ] out, err, exitcode = helpers.cli_call(command) assert out.decode().split("\n")[0].replace("\r", "") == "solid " @@ -20,7 +27,14 @@ def test_stl_codec_quality(): """ test_file = helpers.get_test_file_location("sphere.py") - command = ["python", "cq-cli.py", "--codec", "stl", "--infile", test_file] + command = [ + "python", + "src/cq_cli/cq_cli.py", + "--codec", + "stl", + "--infile", + test_file, + ] out, err, exitcode = helpers.cli_call(command) # Keep track of the number of lines for each STL as an approximate measure of quality @@ -29,7 +43,7 @@ def test_stl_codec_quality(): # Attempt to adjust the quality of the resulting STL command2 = [ "python", - "cq-cli.py", + "src/cq_cli/cq_cli.py", "--codec", "stl", "--infile", diff --git a/tests/test_svg_codec.py b/tests/test_svg_codec.py index a857329..2321e09 100644 --- a/tests/test_svg_codec.py +++ b/tests/test_svg_codec.py @@ -9,7 +9,7 @@ def test_svg_codec(): command = [ "python", - "cq-cli.py", + "src/cq_cli/cq_cli.py", "--codec", "svg", "--infile", diff --git a/tests/test_threejs_codec.py b/tests/test_threejs_codec.py index f8671ae..77d84ab 100644 --- a/tests/test_threejs_codec.py +++ b/tests/test_threejs_codec.py @@ -7,7 +7,14 @@ def test_threejs_codec(): """ test_file = helpers.get_test_file_location("cube.py") - command = ["python", "cq-cli.py", "--codec", "threejs", "--infile", test_file] + command = [ + "python", + "src/cq_cli/cq_cli.py", + "--codec", + "threejs", + "--infile", + test_file, + ] out, err, exitcode = helpers.cli_call(command) print("Output New: " + str(out.decode())) print("Error: " + str(err)) From e7ddb5df9edadf6047cee3ef38716390f3acfeba Mon Sep 17 00:00:00 2001 From: Justin Buchanan Date: Mon, 23 Oct 2023 20:08:37 -0700 Subject: [PATCH 17/28] tests.yml: apt-get install install libgl1-mesa-glx fixes "libGL.so.1: cannot open shared object file" --- .github/workflows/tests.yml | 3 +++ tests/test_cli.py | 3 +-- tests/test_step_codec.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 83ba2bf..974f8c2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -15,6 +15,9 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} steps: + - name: Install Dependencies (Linux) + run: sudo apt-get update && sudo apt install -y libgl1-mesa-glx + if: matrix.os == 'ubuntu-latest' - uses: actions/checkout@v2 - name: Install CadQuery and pytest run: | diff --git a/tests/test_cli.py b/tests/test_cli.py index b487a64..0d7388b 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -52,8 +52,7 @@ def test_codec_and_infile_arguments(): test_file, ] out, err, exitcode = helpers.cli_call(command) - - assert out.decode().split("\n")[0].replace("\r", "") == "ISO-10303-21;" + assert "ISO-10303-21;" in out.decode() def test_codec_infile_and_outfile_arguments(): diff --git a/tests/test_step_codec.py b/tests/test_step_codec.py index e7da516..478be12 100644 --- a/tests/test_step_codec.py +++ b/tests/test_step_codec.py @@ -17,4 +17,4 @@ def test_step_codec(): ] out, err, exitcode = helpers.cli_call(command) - assert out.decode().split("\n")[0].replace("\r", "") == "ISO-10303-21;" + assert "ISO-10303-21;" in out.decode() From fe6a4fcee7285d29d3b13721a5434500be5d3466 Mon Sep 17 00:00:00 2001 From: Justin Buchanan Date: Mon, 23 Oct 2023 20:59:55 -0700 Subject: [PATCH 18/28] attempt to fix build failure on macOS --- src/cq_cli/cq_cli.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cq_cli/cq_cli.py b/src/cq_cli/cq_cli.py index aa7e02e..08dc107 100755 --- a/src/cq_cli/cq_cli.py +++ b/src/cq_cli/cq_cli.py @@ -1,4 +1,10 @@ #!/usr/bin/env python3 + +# surprisingly, this seems to fix issues on macOS - it shouldn't be necessary +# for any python3 installation, but this program fails to run on macOS without +# this import. +from __future__ import print_function + import os import sys import argparse From 0b2f2a1f62ef00ce0874d3c508e5b9534a48ba3f Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Tue, 24 Oct 2023 08:12:52 -0400 Subject: [PATCH 19/28] Disabled MacOS runner for tests --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 974f8c2..58403d6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ jobs: fail-fast: false matrix: python-version: ["3.10"] - os: [ubuntu-latest, windows-latest, macos-latest] + os: [ubuntu-latest, windows-latest] # , macos-latest runs-on: ${{ matrix.os }} steps: - name: Install Dependencies (Linux) From 74cc929340c7bb67c4a5dc3318ea1c60019b6f3c Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Tue, 24 Oct 2023 10:48:44 -0400 Subject: [PATCH 20/28] Added a new PyInstaller CI config --- .github/workflows/pyinstaller.yml | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/pyinstaller.yml diff --git a/.github/workflows/pyinstaller.yml b/.github/workflows/pyinstaller.yml new file mode 100644 index 0000000..765b59e --- /dev/null +++ b/.github/workflows/pyinstaller.yml @@ -0,0 +1,36 @@ +name: pyinstaller-build +on: + workflow_dispatch: + inputs: + type: + description: 'Whether to build a single file (onefile) or directory (dir) dist' + required: true + default: 'dir' +jobs: + build-linux: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + # - uses: conda-incubator/setup-miniconda@v2 + # with: + # miniconda-version: "latest" + # auto-update-conda: true + # python-version: 3.8 + # activate-environment: test + - name: Install dependencies + run: | + pip install --upgrade pip + pip --version + pip install -e . + pip install pyinstaller + pip install path + - name: Run PyInstaller build + run: | + pyinstaller pyinstaller.spec ${{ github.event.inputs.type }} + - uses: actions/upload-artifact@v2 + with: + name: cq-cli-Linux-x86_64 + path: dist From 87e604e68ae541b83872d9dde32faa7f3aad4b13 Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Tue, 24 Oct 2023 17:26:30 -0400 Subject: [PATCH 21/28] Fixed pyproject.toml to install correctly for all use cases --- pyproject.toml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 62d288c..03f6aca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,9 +17,12 @@ classifiers = [ "Operating System :: OS Independent", ] dependencies = [ - 'cadquery >= 2.3.1', + "cadquery @ git+https://github.com/CadQuery/cadquery.git", ] +[project.scripts] +cq-cli = "cq_cli:main" + [project.optional-dependencies] dev = [ "pytest", @@ -30,3 +33,9 @@ dev = [ [project.urls] "Homepage" = "https://github.com/CadQuery/cq-cli" "Bug Tracker" = "https://github.com/CadQuery/cq-cli/issues" + +[tool.hatch.metadata] +allow-direct-references = true + +[tool.hatch.build.targets.wheel] +packages = ["src/cq_cli/cqcodecs"] From 5c7623677ebb81ee851676fbe3fa35e6c9699b47 Mon Sep 17 00:00:00 2001 From: Justin Buchanan Date: Tue, 24 Oct 2023 20:39:02 -0700 Subject: [PATCH 22/28] adjust import paths and fix entrypoint in pyproject.toml --- pyproject.toml | 4 ++-- src/cq_cli/cqcodecs/cq_codec_gltf.py | 2 +- src/cq_cli/cqcodecs/cq_codec_step.py | 2 +- src/cq_cli/cqcodecs/cq_codec_stl.py | 2 +- src/cq_cli/cqcodecs/cq_codec_svg.py | 2 +- src/cq_cli/cqcodecs/cq_codec_threejs.py | 2 +- src/cq_cli/cqcodecs/loader.py | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 03f6aca..020236a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ dependencies = [ ] [project.scripts] -cq-cli = "cq_cli:main" +cq-cli = "cq_cli.cq_cli:main" [project.optional-dependencies] dev = [ @@ -38,4 +38,4 @@ dev = [ allow-direct-references = true [tool.hatch.build.targets.wheel] -packages = ["src/cq_cli/cqcodecs"] +packages = ["src/cq_cli"] diff --git a/src/cq_cli/cqcodecs/cq_codec_gltf.py b/src/cq_cli/cqcodecs/cq_codec_gltf.py index 827a195..867c737 100644 --- a/src/cq_cli/cqcodecs/cq_codec_gltf.py +++ b/src/cq_cli/cqcodecs/cq_codec_gltf.py @@ -1,7 +1,7 @@ import os, tempfile from cadquery import exporters import cadquery as cq -import cqcodecs.codec_helpers as helpers +import cq_cli.cqcodecs.codec_helpers as helpers def convert(build_result, output_file=None, error_file=None, output_opts=None): diff --git a/src/cq_cli/cqcodecs/cq_codec_step.py b/src/cq_cli/cqcodecs/cq_codec_step.py index 4968ed8..b54fc16 100644 --- a/src/cq_cli/cqcodecs/cq_codec_step.py +++ b/src/cq_cli/cqcodecs/cq_codec_step.py @@ -1,7 +1,7 @@ import os, tempfile from cadquery import exporters import cadquery as cq -import cqcodecs.codec_helpers as helpers +import cq_cli.cqcodecs.codec_helpers as helpers def convert(build_result, output_file=None, error_file=None, output_opts=None): diff --git a/src/cq_cli/cqcodecs/cq_codec_stl.py b/src/cq_cli/cqcodecs/cq_codec_stl.py index 9eb55e6..401ff11 100644 --- a/src/cq_cli/cqcodecs/cq_codec_stl.py +++ b/src/cq_cli/cqcodecs/cq_codec_stl.py @@ -1,7 +1,7 @@ import os, tempfile from cadquery import exporters import cadquery as cq -import cqcodecs.codec_helpers as helpers +import cq_cli.cqcodecs.codec_helpers as helpers def convert(build_result, output_file=None, error_file=None, output_opts=None): diff --git a/src/cq_cli/cqcodecs/cq_codec_svg.py b/src/cq_cli/cqcodecs/cq_codec_svg.py index a3d6e99..e9b84a0 100644 --- a/src/cq_cli/cqcodecs/cq_codec_svg.py +++ b/src/cq_cli/cqcodecs/cq_codec_svg.py @@ -1,7 +1,7 @@ import os, tempfile from cadquery import exporters import cadquery as cq -import cqcodecs.codec_helpers as helpers +import cq_cli.cqcodecs.codec_helpers as helpers def convert(build_result, output_file=None, error_file=None, output_opts=None): diff --git a/src/cq_cli/cqcodecs/cq_codec_threejs.py b/src/cq_cli/cqcodecs/cq_codec_threejs.py index 88aacbc..15c61bd 100644 --- a/src/cq_cli/cqcodecs/cq_codec_threejs.py +++ b/src/cq_cli/cqcodecs/cq_codec_threejs.py @@ -1,7 +1,7 @@ import os, tempfile from cadquery import exporters import cadquery as cq -import cqcodecs.codec_helpers as helpers +import cq_cli.cqcodecs.codec_helpers as helpers def convert(build_result, output_file=None, error_file=None, output_opts=None): diff --git a/src/cq_cli/cqcodecs/loader.py b/src/cq_cli/cqcodecs/loader.py index a98605b..d6d962d 100644 --- a/src/cq_cli/cqcodecs/loader.py +++ b/src/cq_cli/cqcodecs/loader.py @@ -9,6 +9,6 @@ def load_codecs(): # Search all of the modules in the current directory to find codecs for finder, name, ispkg in pkgutil.iter_modules([os.path.dirname(__file__)]): if name.startswith("cq_codec_"): - cq_codecs[name] = importlib.import_module("cqcodecs." + name) + cq_codecs[name] = importlib.import_module("cq_cli.cqcodecs." + name) return cq_codecs From b540ec8f6aa68cf7a18595c1b06cb63ce54bf0a8 Mon Sep 17 00:00:00 2001 From: Justin Buchanan Date: Tue, 24 Oct 2023 20:54:31 -0700 Subject: [PATCH 23/28] rename cq_cli.py->main.py and resolve import issues --- pyproject.toml | 2 +- src/cq_cli/{cq_cli.py => main.py} | 6 +++++- tests/test_cli.py | 32 +++++++++++++++---------------- tests/test_gltf_codec.py | 2 +- tests/test_step_codec.py | 2 +- tests/test_stl_codec.py | 6 +++--- tests/test_svg_codec.py | 2 +- tests/test_threejs_codec.py | 2 +- 8 files changed, 29 insertions(+), 25 deletions(-) rename src/cq_cli/{cq_cli.py => main.py} (99%) diff --git a/pyproject.toml b/pyproject.toml index 020236a..a33d00c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ dependencies = [ ] [project.scripts] -cq-cli = "cq_cli.cq_cli:main" +cq-cli = "cq_cli.main:main" [project.optional-dependencies] dev = [ diff --git a/src/cq_cli/cq_cli.py b/src/cq_cli/main.py similarity index 99% rename from src/cq_cli/cq_cli.py rename to src/cq_cli/main.py index 08dc107..914fbd8 100755 --- a/src/cq_cli/cq_cli.py +++ b/src/cq_cli/main.py @@ -7,13 +7,17 @@ import os import sys + +# Add parent directory to path so that `import cq_cli.* resolves correctly. +sys.path.append(os.path.dirname(__file__) + "/..") + import argparse import cadquery as cq from cadquery import cqgi import fileinput import traceback import json -from cqcodecs import loader +from cq_cli.cqcodecs import loader def build_and_parse(script_str, params, errfile): diff --git a/tests/test_cli.py b/tests/test_cli.py index 0d7388b..75c1a6d 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -8,7 +8,7 @@ def test_no_cli_arguments(): """ Runs the CLI with no arguments, which you should not do unless you want the usage message. """ - command = ["python", "src/cq_cli/cq_cli.py"] + command = ["python", "src/cq_cli/main.py"] out, err, exitcode = helpers.cli_call(command) assert ( @@ -26,7 +26,7 @@ def test_codec_and_infile_arguments_file_nonexistent(): command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "step", "--infile", @@ -45,7 +45,7 @@ def test_codec_and_infile_arguments(): command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "step", "--infile", @@ -67,7 +67,7 @@ def test_codec_infile_and_outfile_arguments(): command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "step", "--infile", @@ -98,7 +98,7 @@ def test_codec_infile_outfile_errfile_arguments(): command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "step", "--infile", @@ -130,7 +130,7 @@ def test_parameter_file(): command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "step", "--infile", @@ -161,7 +161,7 @@ def test_parameter_json_string(): command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "step", "--infile", @@ -192,7 +192,7 @@ def test_parameter_delimited_string(): command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "step", "--infile", @@ -219,7 +219,7 @@ def test_parameter_analysis(): command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--getparams", "true", "--infile", @@ -260,7 +260,7 @@ def test_parameter_file_input_output(): # Save the parameters from the script to a file command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--getparams", temp_file, "--infile", @@ -271,7 +271,7 @@ def test_parameter_file_input_output(): # Run the script with baseline parameters command2 = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "stl", "--infile", @@ -294,7 +294,7 @@ def test_parameter_file_input_output(): # Run the command with the new parameters command3 = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "stl", "--infile", @@ -332,7 +332,7 @@ def test_params_stl_output(): # Execute the script with the current parameters and save the new parameter metadata to the customizer file command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "stl", "--infile", @@ -360,7 +360,7 @@ def test_params_stl_output(): # Write an STL using the default parameters so that we can compare it to what was generated with customized parameters command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "stl", "--infile", @@ -385,7 +385,7 @@ def test_exit_codes(): """ # Test to make sure we get the correct exit code when no parameters are specified - command = ["python", "src/cq_cli/cq_cli.py"] + command = ["python", "src/cq_cli/main.py"] out, err, exitcode = helpers.cli_call(command) # Make sure that we got exit code 2 @@ -397,7 +397,7 @@ def test_exit_codes(): # Execute the script with the current parameters and save the new parameter metadata to the customizer file command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "step", "--infile", diff --git a/tests/test_gltf_codec.py b/tests/test_gltf_codec.py index dd3b8df..94ab256 100644 --- a/tests/test_gltf_codec.py +++ b/tests/test_gltf_codec.py @@ -13,7 +13,7 @@ def test_gltf_codec(): command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "gltf", "--infile", diff --git a/tests/test_step_codec.py b/tests/test_step_codec.py index 478be12..9e3d144 100644 --- a/tests/test_step_codec.py +++ b/tests/test_step_codec.py @@ -9,7 +9,7 @@ def test_step_codec(): command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "step", "--infile", diff --git a/tests/test_stl_codec.py b/tests/test_stl_codec.py index ce233c0..45ceab5 100644 --- a/tests/test_stl_codec.py +++ b/tests/test_stl_codec.py @@ -10,7 +10,7 @@ def test_stl_codec(): command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "stl", "--infile", @@ -29,7 +29,7 @@ def test_stl_codec_quality(): command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "stl", "--infile", @@ -43,7 +43,7 @@ def test_stl_codec_quality(): # Attempt to adjust the quality of the resulting STL command2 = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "stl", "--infile", diff --git a/tests/test_svg_codec.py b/tests/test_svg_codec.py index 2321e09..ade12a6 100644 --- a/tests/test_svg_codec.py +++ b/tests/test_svg_codec.py @@ -9,7 +9,7 @@ def test_svg_codec(): command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "svg", "--infile", diff --git a/tests/test_threejs_codec.py b/tests/test_threejs_codec.py index 77d84ab..373713f 100644 --- a/tests/test_threejs_codec.py +++ b/tests/test_threejs_codec.py @@ -9,7 +9,7 @@ def test_threejs_codec(): command = [ "python", - "src/cq_cli/cq_cli.py", + "src/cq_cli/main.py", "--codec", "threejs", "--infile", From c96482072df46587a0ecc6a2f6201257795bb3cc Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Wed, 25 Oct 2023 08:46:09 -0400 Subject: [PATCH 24/28] Fixed PyInstaller spec for new module naming scheme --- pyinstaller.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyinstaller.spec b/pyinstaller.spec index cda6d99..7e62d14 100644 --- a/pyinstaller.spec +++ b/pyinstaller.spec @@ -45,7 +45,7 @@ hidden_imports.append('vtkmodules.all') hidden_imports_numpy = collect_submodules('numpy') hidden_imports = hidden_imports + hidden_imports_numpy -a = Analysis(['src/cq_cli/cq_cli.py'], +a = Analysis(['src/cq_cli/main.py'], pathex=['.'], #binaries=[ # ocp_path From e19e7c2586c4a9690b740b8b4b0094e5a55e08ae Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Wed, 25 Oct 2023 10:02:32 -0400 Subject: [PATCH 25/28] Added CadQuery dependencies to make sure they get installed even when using pip git install --- pyproject.toml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index a33d00c..c2e118f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,14 @@ classifiers = [ ] dependencies = [ "cadquery @ git+https://github.com/CadQuery/cadquery.git", + "cadquery-ocp>=7.7.0a0,<7.8", + "ezdxf", + "multimethod>=1.7,<2.0", + "nlopt", + "nptyping==2.0.1", + "typish", + "casadi", + "path", ] [project.scripts] From aec0be6902fff97b97bf1a524bd3235723845535 Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Wed, 25 Oct 2023 11:48:18 -0400 Subject: [PATCH 26/28] Re-enabled glTF test --- tests/test_gltf_codec.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/test_gltf_codec.py b/tests/test_gltf_codec.py index 94ab256..f7acc18 100644 --- a/tests/test_gltf_codec.py +++ b/tests/test_gltf_codec.py @@ -2,9 +2,6 @@ import tests.test_helpers as helpers -@pytest.mark.skip( - reason="Waiting on #1414 on the CadQuery repo to be merged to finish this" -) def test_gltf_codec(): """ Basic test of the GLTF codec plugin. From addae4923ee9a22b4a3a734aa68ea7c38c88ebad Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Thu, 26 Oct 2023 08:59:50 -0400 Subject: [PATCH 27/28] Trying without explicit CadQuery dependencies --- pyproject.toml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c2e118f..a33d00c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,14 +18,6 @@ classifiers = [ ] dependencies = [ "cadquery @ git+https://github.com/CadQuery/cadquery.git", - "cadquery-ocp>=7.7.0a0,<7.8", - "ezdxf", - "multimethod>=1.7,<2.0", - "nlopt", - "nptyping==2.0.1", - "typish", - "casadi", - "path", ] [project.scripts] From 4eff749e2ac52c0b5fb6e9ee3a56267c5923529b Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Thu, 26 Oct 2023 09:21:47 -0400 Subject: [PATCH 28/28] Reverting removal of explicit CQ dependencies --- pyproject.toml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index a33d00c..c2e118f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,14 @@ classifiers = [ ] dependencies = [ "cadquery @ git+https://github.com/CadQuery/cadquery.git", + "cadquery-ocp>=7.7.0a0,<7.8", + "ezdxf", + "multimethod>=1.7,<2.0", + "nlopt", + "nptyping==2.0.1", + "typish", + "casadi", + "path", ] [project.scripts]