From c2a05ec8075dec5369f89250af2bab1e491a2c01 Mon Sep 17 00:00:00 2001 From: jffmichi <> Date: Tue, 20 May 2025 01:58:32 +0200 Subject: [PATCH 1/6] CAM: fix refactored postprocessors crashing on blank lines --- src/Mod/CAM/Path/Post/UtilsParse.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mod/CAM/Path/Post/UtilsParse.py b/src/Mod/CAM/Path/Post/UtilsParse.py index ec2808b706..7a09a70ae9 100644 --- a/src/Mod/CAM/Path/Post/UtilsParse.py +++ b/src/Mod/CAM/Path/Post/UtilsParse.py @@ -720,11 +720,12 @@ def parse_a_path(values: Values, gcode: Gcode, pathobj) -> None: command_line = [] # Modify the command name if necessary - if command[0] == "(": + if command.startswith("("): if not values["OUTPUT_COMMENTS"]: continue if values["COMMENT_SYMBOL"] != "(" and len(command) > 2: command = create_comment(values, command[1:-1]) + cmd = check_for_an_adaptive_op(values, command, command_line, adaptive_op_variables) if cmd: command = cmd From 70f3c7c38770d7e6982586d956e8e5ac8a37b452 Mon Sep 17 00:00:00 2001 From: jffmichi <> Date: Tue, 20 May 2025 02:37:00 +0200 Subject: [PATCH 2/6] CAM: add configuration value to suppress blank lines in refactored postprocessors --- .../CAM/CAMTests/TestRefactoredTestPost.py | 36 +++++++++++++++++++ src/Mod/CAM/Path/Post/UtilsArguments.py | 4 +++ src/Mod/CAM/Path/Post/UtilsParse.py | 5 +++ 3 files changed, 45 insertions(+) diff --git a/src/Mod/CAM/CAMTests/TestRefactoredTestPost.py b/src/Mod/CAM/CAMTests/TestRefactoredTestPost.py index 58b05f44a6..a074abb58d 100644 --- a/src/Mod/CAM/CAMTests/TestRefactoredTestPost.py +++ b/src/Mod/CAM/CAMTests/TestRefactoredTestPost.py @@ -667,6 +667,42 @@ G54 ############################################################################# + def test00191(self): + """Make sure postprocessor doesn't crash on blank lines""" + + path = [ + Path.Command("G0 X1"), + Path.Command(""), + Path.Command("G0 X2"), + ] + + self.post.values["OUTPUT_BLANK_LINES"] = True + self.multi_compare( + path, + """G90 +G21 +G54 +G0 X1.000 + +G0 X2.000 +""", + "", + ) + + self.post.values["OUTPUT_BLANK_LINES"] = False + self.multi_compare( + path, + """G90 +G21 +G54 +G0 X1.000 +G0 X2.000 +""", + "", + ) + + ############################################################################# + def test00200(self): """Test Outputting visible arguments. diff --git a/src/Mod/CAM/Path/Post/UtilsArguments.py b/src/Mod/CAM/Path/Post/UtilsArguments.py index 7896d0a16d..f4ebd00517 100644 --- a/src/Mod/CAM/Path/Post/UtilsArguments.py +++ b/src/Mod/CAM/Path/Post/UtilsArguments.py @@ -478,6 +478,10 @@ def init_shared_values(values: Values) -> None: # values["OUTPUT_COMMENTS"] = True # + # If True output blank lines. If False blank lines are suppressed. + # + values["OUTPUT_BLANK_LINES"] = True + # # if False duplicate axis values or feeds are suppressed # if they are the same as the previous line. # diff --git a/src/Mod/CAM/Path/Post/UtilsParse.py b/src/Mod/CAM/Path/Post/UtilsParse.py index 7a09a70ae9..85cbed4cd4 100644 --- a/src/Mod/CAM/Path/Post/UtilsParse.py +++ b/src/Mod/CAM/Path/Post/UtilsParse.py @@ -719,6 +719,11 @@ def parse_a_path(values: Values, gcode: Gcode, pathobj) -> None: command = c.Name command_line = [] + # Skip blank lines if requested + if not command: + if not values["OUTPUT_BLANK_LINES"]: + continue + # Modify the command name if necessary if command.startswith("("): if not values["OUTPUT_COMMENTS"]: From 7b58dd29777a8acab154f41abba0d1f975a6046d Mon Sep 17 00:00:00 2001 From: jffmichi <> Date: Tue, 20 May 2025 03:28:36 +0200 Subject: [PATCH 3/6] CAM: fix Custom operation UI panel dropping trailing blank lines --- src/Mod/CAM/Path/Op/Gui/Custom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/CAM/Path/Op/Gui/Custom.py b/src/Mod/CAM/Path/Op/Gui/Custom.py index fa88d57278..35f93160ba 100644 --- a/src/Mod/CAM/Path/Op/Gui/Custom.py +++ b/src/Mod/CAM/Path/Op/Gui/Custom.py @@ -61,7 +61,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage): return signals def setGCode(self): - self.obj.Gcode = self.form.txtGCode.toPlainText().splitlines() + self.obj.Gcode = self.form.txtGCode.toPlainText().split("\n") Command = PathOpGui.SetupOperation( From a59fc30d6ca2b7165d4e24b64943e4d9b9a4450f Mon Sep 17 00:00:00 2001 From: jffmichi <> Date: Tue, 20 May 2025 05:00:06 +0200 Subject: [PATCH 4/6] CAM: fix some non-refactored postprocessors crashing on blank lines --- src/Mod/CAM/Path/Post/scripts/KineticNCBeamicon2_post.py | 2 +- src/Mod/CAM/Path/Post/scripts/centroid_post.py | 2 +- src/Mod/CAM/Path/Post/scripts/dynapath_4060_post.py | 2 +- src/Mod/CAM/Path/Post/scripts/fablin_post.py | 2 +- src/Mod/CAM/Path/Post/scripts/fangling_post.py | 2 +- src/Mod/CAM/Path/Post/scripts/fanuc_post.py | 2 +- src/Mod/CAM/Path/Post/scripts/jtech_post.py | 2 +- src/Mod/CAM/Path/Post/scripts/linuxcnc_post.py | 2 +- src/Mod/CAM/Path/Post/scripts/mach3_mach4_post.py | 2 +- src/Mod/CAM/Path/Post/scripts/opensbp_post.py | 2 +- src/Mod/CAM/Path/Post/scripts/philips_post.py | 2 +- src/Mod/CAM/Path/Post/scripts/uccnc_post.py | 2 +- src/Mod/CAM/Path/Post/scripts/wedm_post.py | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Mod/CAM/Path/Post/scripts/KineticNCBeamicon2_post.py b/src/Mod/CAM/Path/Post/scripts/KineticNCBeamicon2_post.py index 3008d6e032..d3334aeff6 100644 --- a/src/Mod/CAM/Path/Post/scripts/KineticNCBeamicon2_post.py +++ b/src/Mod/CAM/Path/Post/scripts/KineticNCBeamicon2_post.py @@ -344,7 +344,7 @@ def parse(pathobj): if command == lastcommand: outstring.pop(0) - if c.Name[0] == "(" and not OUTPUT_COMMENTS: # command is a comment + if c.Name.startswith("(") and not OUTPUT_COMMENTS: # command is a comment continue # Now add the remaining parameters in order diff --git a/src/Mod/CAM/Path/Post/scripts/centroid_post.py b/src/Mod/CAM/Path/Post/scripts/centroid_post.py index 49c58d1137..8bf2660401 100644 --- a/src/Mod/CAM/Path/Post/scripts/centroid_post.py +++ b/src/Mod/CAM/Path/Post/scripts/centroid_post.py @@ -282,7 +282,7 @@ def parse(pathobj): commandlist = [] # list of elements in the command, code and params. command = c.Name # command M or G code or comment string - if command[0] == "(": + if command.startswith("("): command = PostUtils.fcoms(command, COMMENT) commandlist.append(command) diff --git a/src/Mod/CAM/Path/Post/scripts/dynapath_4060_post.py b/src/Mod/CAM/Path/Post/scripts/dynapath_4060_post.py index f7861567f3..ebfb2025fd 100644 --- a/src/Mod/CAM/Path/Post/scripts/dynapath_4060_post.py +++ b/src/Mod/CAM/Path/Post/scripts/dynapath_4060_post.py @@ -401,7 +401,7 @@ def parse(pathobj): if command == lastcommand: outstring.pop(0) - if c.Name[0] == "(" and not OUTPUT_COMMENTS: # command is a comment + if c.Name.startswith("(") and not OUTPUT_COMMENTS: # command is a comment continue # Now add the remaining parameters in order diff --git a/src/Mod/CAM/Path/Post/scripts/fablin_post.py b/src/Mod/CAM/Path/Post/scripts/fablin_post.py index 73c4e640e3..165fe4df51 100644 --- a/src/Mod/CAM/Path/Post/scripts/fablin_post.py +++ b/src/Mod/CAM/Path/Post/scripts/fablin_post.py @@ -251,7 +251,7 @@ def parse(pathobj): command = c.Name # fablin does not support parenthesis syntax, so removing that (pocket) in the agnostic gcode - if command[0] == "(": + if command.startswith("("): if not OUTPUT_COMMENTS: pass else: diff --git a/src/Mod/CAM/Path/Post/scripts/fangling_post.py b/src/Mod/CAM/Path/Post/scripts/fangling_post.py index c6938c66b5..8d2a50c237 100644 --- a/src/Mod/CAM/Path/Post/scripts/fangling_post.py +++ b/src/Mod/CAM/Path/Post/scripts/fangling_post.py @@ -411,7 +411,7 @@ def parse(pathobj): if command == lastcommand: outstring.pop(0) - if c.Name[0] == "(" and not OUTPUT_COMMENTS: # command is a comment + if c.Name.startswith("(") and not OUTPUT_COMMENTS: # command is a comment continue # Now add the remaining parameters in order diff --git a/src/Mod/CAM/Path/Post/scripts/fanuc_post.py b/src/Mod/CAM/Path/Post/scripts/fanuc_post.py index 4487f70457..e6b51e2a80 100644 --- a/src/Mod/CAM/Path/Post/scripts/fanuc_post.py +++ b/src/Mod/CAM/Path/Post/scripts/fanuc_post.py @@ -504,7 +504,7 @@ def parse(pathobj): if command == "G80" and lastcommand == nextcommand: continue - if c.Name[0] == "(" and not OUTPUT_COMMENTS: # command is a comment + if c.Name.startswith("(") and not OUTPUT_COMMENTS: # command is a comment continue # Now add the remaining parameters in order diff --git a/src/Mod/CAM/Path/Post/scripts/jtech_post.py b/src/Mod/CAM/Path/Post/scripts/jtech_post.py index 35e12487ea..3fd943a108 100644 --- a/src/Mod/CAM/Path/Post/scripts/jtech_post.py +++ b/src/Mod/CAM/Path/Post/scripts/jtech_post.py @@ -313,7 +313,7 @@ def parse(pathobj): if command == lastcommand: outstring.pop(0) - if c.Name[0] == "(" and not OUTPUT_COMMENTS: # command is a comment + if c.Name.startswith("(") and not OUTPUT_COMMENTS: # command is a comment continue # Now add the remaining parameters in order diff --git a/src/Mod/CAM/Path/Post/scripts/linuxcnc_post.py b/src/Mod/CAM/Path/Post/scripts/linuxcnc_post.py index 5a0e676936..84f4d32551 100644 --- a/src/Mod/CAM/Path/Post/scripts/linuxcnc_post.py +++ b/src/Mod/CAM/Path/Post/scripts/linuxcnc_post.py @@ -355,7 +355,7 @@ def parse(pathobj): if command == lastcommand: outstring.pop(0) - if c.Name[0] == "(" and not OUTPUT_COMMENTS: # command is a comment + if c.Name.startswith("(") and not OUTPUT_COMMENTS: # command is a comment continue # Now add the remaining parameters in order diff --git a/src/Mod/CAM/Path/Post/scripts/mach3_mach4_post.py b/src/Mod/CAM/Path/Post/scripts/mach3_mach4_post.py index a450895333..7a8909ed09 100644 --- a/src/Mod/CAM/Path/Post/scripts/mach3_mach4_post.py +++ b/src/Mod/CAM/Path/Post/scripts/mach3_mach4_post.py @@ -387,7 +387,7 @@ def parse(pathobj): if command == lastcommand: outstring.pop(0) - if c.Name[0] == "(" and not OUTPUT_COMMENTS: # command is a comment + if c.Name.startswith("(") and not OUTPUT_COMMENTS: # command is a comment continue # Now add the remaining parameters in order diff --git a/src/Mod/CAM/Path/Post/scripts/opensbp_post.py b/src/Mod/CAM/Path/Post/scripts/opensbp_post.py index 45fa861a23..7fac68914d 100644 --- a/src/Mod/CAM/Path/Post/scripts/opensbp_post.py +++ b/src/Mod/CAM/Path/Post/scripts/opensbp_post.py @@ -359,7 +359,7 @@ def parse(pathobj): output += scommands[command](c) if c.Parameters: CurrentState.update(c.Parameters) - elif command[0] == "(": + elif command.startswith("("): output += "' " + command + "\n" else: print("I don't know what the hell the command: ", end="") diff --git a/src/Mod/CAM/Path/Post/scripts/philips_post.py b/src/Mod/CAM/Path/Post/scripts/philips_post.py index 9a67cb7957..3389302605 100644 --- a/src/Mod/CAM/Path/Post/scripts/philips_post.py +++ b/src/Mod/CAM/Path/Post/scripts/philips_post.py @@ -412,7 +412,7 @@ def export(objectslist, filename, argstring): command = command.replace("G0", "G") # normalize: G01 -> G1 if command != UNITS or UNITS_INCLUDED: - if command[0] == "(": + if command.startswith("("): command = PostUtils.fcoms(command, COMMENT) # the mapping is done for output only! For internal things we # still use the old value. diff --git a/src/Mod/CAM/Path/Post/scripts/uccnc_post.py b/src/Mod/CAM/Path/Post/scripts/uccnc_post.py index b44a77c506..2ee54ecd0e 100644 --- a/src/Mod/CAM/Path/Post/scripts/uccnc_post.py +++ b/src/Mod/CAM/Path/Post/scripts/uccnc_post.py @@ -599,7 +599,7 @@ def parse(pathobj): if command == lastcommand: commandlist.pop(0) - if c.Name[0] == "(" and not OUTPUT_COMMENTS: # command is a comment + if c.Name.startswith("(") and not OUTPUT_COMMENTS: # command is a comment continue # Now add the remaining parameters in order diff --git a/src/Mod/CAM/Path/Post/scripts/wedm_post.py b/src/Mod/CAM/Path/Post/scripts/wedm_post.py index 1b9396f8b9..fe3e134f7e 100644 --- a/src/Mod/CAM/Path/Post/scripts/wedm_post.py +++ b/src/Mod/CAM/Path/Post/scripts/wedm_post.py @@ -456,7 +456,7 @@ def parse(pathobj): if command == lastcommand: outstring.pop(0) - if command[0] == "(": # command is a comment + if command.startswith("("): # command is a comment if OUTPUT_COMMENTS: # Edit comment with COMMENT_CHAR outstring.insert(0, COMMENT_CHAR) else: From 08cba3fa4555872eb71cf3ceebead68e2b9fb1a8 Mon Sep 17 00:00:00 2001 From: jffmichi <> Date: Tue, 20 May 2025 05:01:46 +0200 Subject: [PATCH 5/6] CAM: fix fablin postprocessor always writing to "-" instead of specified file --- src/Mod/CAM/Path/Post/scripts/fablin_post.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Mod/CAM/Path/Post/scripts/fablin_post.py b/src/Mod/CAM/Path/Post/scripts/fablin_post.py index 165fe4df51..87388d9f11 100644 --- a/src/Mod/CAM/Path/Post/scripts/fablin_post.py +++ b/src/Mod/CAM/Path/Post/scripts/fablin_post.py @@ -199,9 +199,12 @@ def export(objectslist, filename, argstring): print("done postprocessing.") - gfile = pyopen(filename, "w") - gfile.write(final) - gfile.close() + if not filename == "-": + gfile = pyopen(filename, "w") + gfile.write(final) + gfile.close() + + return final def linenumber(): From 09e356cec67eea0fb84fe71f889ae30511c596ca Mon Sep 17 00:00:00 2001 From: jffmichi <> Date: Tue, 20 May 2025 05:04:03 +0200 Subject: [PATCH 6/6] CAM: fix philips postprocessor always writing to "-" instead of specified file and not processing arguments --- src/Mod/CAM/Path/Post/scripts/philips_post.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/Mod/CAM/Path/Post/scripts/philips_post.py b/src/Mod/CAM/Path/Post/scripts/philips_post.py index 3389302605..373c2f3475 100644 --- a/src/Mod/CAM/Path/Post/scripts/philips_post.py +++ b/src/Mod/CAM/Path/Post/scripts/philips_post.py @@ -352,6 +352,7 @@ def linenumberify(GCodeString): def export(objectslist, filename, argstring): + processArguments(argstring) global UNITS global linenr @@ -584,8 +585,16 @@ def export(objectslist, filename, argstring): lastcommand = c.Name gcode = gcode.replace("_", "-") gcode += linenumberify(GCODE_FOOTER) - if SHOW_EDITOR: - PostUtils.editor(gcode) - gfile = pyopen(filename, "w") - gfile.write(gcode) - gfile.close() + + # show the gCode result dialog + if FreeCAD.GuiUp and SHOW_EDITOR: + final = PostUtils.editor(gcode) + else: + final = gcode + + if not filename == "-": + gfile = pyopen(filename, "w") + gfile.write(final) + gfile.close() + + return final