From af272ae14b2dd9f93310f287b0af1a116fd3783a Mon Sep 17 00:00:00 2001 From: Justin Buchanan Date: Wed, 12 Mar 2025 12:51:01 -0700 Subject: [PATCH 1/4] feat: set the __file__ variable for scripts loaded from files --- src/cq_cli/main.py | 6 +++++- tests/test_cli.py | 23 +++++++++++++++++++++++ tests/testdata/file_var.py | 11 +++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/testdata/file_var.py diff --git a/src/cq_cli/main.py b/src/cq_cli/main.py index b7b58a0..4eb32c6 100755 --- a/src/cq_cli/main.py +++ b/src/cq_cli/main.py @@ -123,7 +123,11 @@ def get_script_from_infile(infile, outfile, errfile): script_str = infile else: with open(infile, "r") as file: - script_str = file.read() + # prepend an assignment for the __file__ variable so the model + # script knows its path and can potentially load resources relative + # to that path. + script_str = f"__file__ = '{os.path.abspath(infile)}'\n" + script_str += file.read() return script_str diff --git a/tests/test_cli.py b/tests/test_cli.py index 6fb4779..2e93bb9 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -544,3 +544,26 @@ def test_multiple_outfiles(): ] out, err, exitcode = helpers.cli_call(command) assert exitcode == 0 + +def test_file_variable_is_set(): + """ + Tests that cq-cli sets the __file__ variable for the model script. + """ + test_file = helpers.get_test_file_location("file_var.py") + + temp_dir = tempfile.gettempdir() + out_path = os.path.join(temp_dir, "temp_test_file_variable.stl") + + command = [ + "python", + "src/cq_cli/main.py", + "--codec", + "stl", + "--infile", + test_file, + "--outfile", + out_path, + ] + out, err, exitcode = helpers.cli_call(command) + assert exitcode == 0 + assert("__file__=" in out.decode()) diff --git a/tests/testdata/file_var.py b/tests/testdata/file_var.py new file mode 100644 index 0000000..7661ac9 --- /dev/null +++ b/tests/testdata/file_var.py @@ -0,0 +1,11 @@ +import cadquery as cq + +# print info about the __file__ variable to stdout so the test can check it +if '__file__' in locals(): + print(f"__file__={__file__}") +else: + print("__FILE__ not set") + +# render a simple shape so the cq-cli invocation succeeds +b = cq.Workplane("XY").rect(10, 10).extrude(10) +show_object(b) From c436bf791b228e35332f2d716a36e79b18f79dd1 Mon Sep 17 00:00:00 2001 From: Justin Buchanan Date: Wed, 12 Mar 2025 13:04:37 -0700 Subject: [PATCH 2/4] reformat with black --- tests/test_cli.py | 3 ++- tests/testdata/file_var.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 2e93bb9..d7be7e0 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -545,6 +545,7 @@ def test_multiple_outfiles(): out, err, exitcode = helpers.cli_call(command) assert exitcode == 0 + def test_file_variable_is_set(): """ Tests that cq-cli sets the __file__ variable for the model script. @@ -566,4 +567,4 @@ def test_file_variable_is_set(): ] out, err, exitcode = helpers.cli_call(command) assert exitcode == 0 - assert("__file__=" in out.decode()) + assert "__file__=" in out.decode() diff --git a/tests/testdata/file_var.py b/tests/testdata/file_var.py index 7661ac9..e0fef46 100644 --- a/tests/testdata/file_var.py +++ b/tests/testdata/file_var.py @@ -1,7 +1,7 @@ import cadquery as cq # print info about the __file__ variable to stdout so the test can check it -if '__file__' in locals(): +if "__file__" in locals(): print(f"__file__={__file__}") else: print("__FILE__ not set") From f30e5061633ee775def34b0228f1e25c89ae43e1 Mon Sep 17 00:00:00 2001 From: Justin Buchanan Date: Wed, 12 Mar 2025 14:30:31 -0700 Subject: [PATCH 3/4] fix tests --- tests/test_cli.py | 44 +++++++++++++++++++++---------------------- tests/test_helpers.py | 16 +++++++++++++++- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index d7be7e0..047a0f3 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -291,21 +291,20 @@ def test_parameter_analysis(): # Grab the JSON output from cq-cli jsn = json.loads(out.decode()) - - # Check to make sure the first parameter was handled properly - assert jsn[0]["type"] == "number" - assert jsn[0]["name"] == "width" - assert jsn[0]["initial"] == 1 - - # Check to make sure the second parameter was handled properly - assert jsn[1]["type"] == "string" - assert jsn[1]["name"] == "tag_name" - assert jsn[1]["initial"] == "cube" - - # Check to make sure the third parameter was handled properly - assert jsn[2]["type"] == "boolean" - assert jsn[2]["name"] == "centered" - assert jsn[2]["initial"] == True + params_by_name = helpers.params_list_to_dict(jsn) + + # Check to make sure the parameters were handled properly + assert params_by_name["width"] == {"name": "width", "type": "number", "initial": 1} + assert params_by_name["tag_name"] == { + "name": "tag_name", + "type": "string", + "initial": "cube", + } + assert params_by_name["centered"] == { + "name": "centered", + "type": "boolean", + "initial": True, + } def test_parameter_file_input_output(): @@ -348,10 +347,10 @@ def test_parameter_file_input_output(): # Modify the parameters file with open(temp_file, "r") as file: json_str = file.read() - json_dict = json.loads(json_str) - json_dict[0]["initial"] = 10 + json_list = json.loads(json_str) + json_list[1]["initial"] = 10 with open(temp_file, "w") as file: - file.writelines(json.dumps(json_dict)) + file.writelines(json.dumps(json_list)) # Run the command with the new parameters command3 = [ @@ -414,10 +413,11 @@ def test_params_stl_output(): # Make sure that the customizer.json file exists and has what we expect in it 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 + json_list = json.loads(json_str) + params = helpers.params_list_to_dict(json_list) + assert params["width"]["initial"] == 1 + assert params["tag_name"]["initial"] == "cube" + assert params["centered"]["initial"] == True # Write an STL using the default parameters so that we can compare it to what was generated with customized parameters command = [ diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 631aa04..7913cfc 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -15,6 +15,20 @@ 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,) + proc = subprocess.Popen( + command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) out, err = proc.communicate() return out, err, proc.returncode + + +def params_list_to_dict(param_list): + """ + Converts a list of params into a dictionary of those params keyed by name. + """ + d = {} + for entry in param_list: + d[entry["name"]] = entry + return d From 67573dd5d84db986a71ef1c5aeec7554622713d6 Mon Sep 17 00:00:00 2001 From: Justin Buchanan Date: Wed, 12 Mar 2025 14:32:53 -0700 Subject: [PATCH 4/4] make linter happy --- tests/test_helpers.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 7913cfc..f36e590 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -15,11 +15,7 @@ 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, - ) + proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() return out, err, proc.returncode