Jump to content

What is wrong with the post processing script I made?


T9_AIR

Recommended Posts

Posted · What is wrong with the post processing script I made?

Hi everyone! I am making a post-processing script to add a Klipper macro after every line in the file. Everything works until I try to save the sliced gcode when it gives me this error: 'str' object does not support item assignment. If anyone could explain to me what I messed up in the script, it would be a great help.

 

This is my script: 

from ..Script import Script

class AddLoggingGcode(Script):
    def _init_(self):
        super()._init_()

    def getSettingDataString(self):
        return """{
            "name": "Add logging Gcode",
            "key": "AddLoggingGcode",
            "metadata": {},
            "version": 2,
            "settings": {}
        }"""

    def execute(self, data):
        new_data = []
        for layer in data:
            lines = layer.split("\n")
            for line in lines:
                new_data.append(line + "\nLog_FILE")
        return new_data

 

  • Link to post
    Share on other sites

    Posted · What is wrong with the post processing script I made?

    Runs fine for me ("fine" in that it runs without errors, not that it produces a result worth having). What version of Cura are you using? 5.8 here, but older versions include older Python interpreters which can be more or less forgiving about certain things. And cura.log should include a line saying on what line of the script file the error occurred.

     

     If I had to take a stab in the dark and guess where it might be throwing an error, it would be:

    new_data.append(line + "\nLog_FILE")

    Trying to add a literal to a variable. But as I said, runs fine for me. Although regardless, I'd change it to

    new_data.append(f"{line}\nLog_FILE")

    because f-strings are so much fun. And it's fun to be able to say "f-string" and it has legitimately nothing to do with swear words.

     

    Although your output isn't much good, at least not yet:

    Log_FILE;LAYER:0
    Log_FILEM107
    Log_FILEG0 F9000 X93.719 Y95.223 Z0.2
    Log_FILE;TYPE:SKIRT
    Log_FILEG1 F2400 E0
    Log_FILEG1 F1800 X95.28 Y93.764 E0.07107
    Log_FILEG1 X97.303 Y92.557 E0.14942
    Log_FILEG1 X99.021 Y92.275 E0.20732
    Log_FILEG1 X120.853 Y92.2 E0.93346
    Log_FILEG1 X122.749 Y92.666 E0.9984
    Log_FILEG1 X124.777 Y93.719 E1.0744
    Log_FILEG1 X126.236 Y95.28 E1.14547
    Log_FILEG1 X127.443 Y97.303 E1.22382
    Log_FILEG1 X127.725 Y99.021 E1.28173
    Log_FILEG1 X127.8 Y120.853 E2.00787

     

    BTW:

    def _init_(self):
        super()._init_()

    The dunder method for class initialisation is:

    def __init__(self):
        super().__init__()

    Difference might be a little hard to see... two underscores around the init (or any other dunder methods you want to implement).

  • Link to post
    Share on other sites

    Posted · What is wrong with the post processing script I made?

    As Slashee shows, you are getting a "prefix" on every line but you stated you wanted to add your "log_FILE" between each line.

    The list "new_data" has as many items ("layers") as there are lines in the gcode.  Essentially each line is a separate layer.  That may be causing heartburn in Cura when it gets the "data" back.

    Any post-processor that was to run after that one would be likely generate an error as it isn't getting "data" in a form that it expects.  The Cura preview may not work at all, or it will show just a single layer with the entire print on it.

          

    if the results you want are more like this...

    ;TYPE:SKIRT
    Log_FILE
    G1 F600 Z0.2
    Log_FILE
    G1 F2100 E0
    Log_FILE
    G1 F3000 X94.203 Y93.495 E0.0233

     

    Then you will probably want a "+=" rather than an "append".

  • Link to post
    Share on other sites

    Posted · What is wrong with the post processing script I made?
    1 hour ago, GregValiant said:

    Then you will probably want a "+=" rather than an "append".

    += and append on a list give you the same result (as long as you're not passing it a collection) but append is faster because += creates a new list. Beside the point.

     

    Main problem with the output being the way it is is that you're missing a line break. If you're going to do medium-age-school string concatenation, you need this:

    new_data.append("Log_FILE\n" + line + "\n")

     

    But then you still have a problem since you're processing blank lines (like at the end of an item in data), as well as comments:

    Log_FILE
    G1 E0.0000 F1800 
    Log_FILE
    
    Log_FILE
    G92 E0
    Log_FILE
    G92 E0
    Log_FILE
    G1 F2400 E-0.8
    Log_FILE
    ;LAYER_COUNT:100
    Log_FILE
    
    Log_FILE
    ;LAYER:0
    Log_FILE
    M107
    Log_FILE
    G0 F9000 X93.719 Y95.223 Z0.2
    Log_FILE
    ;TYPE:SKIRT
    Log_FILE
    G1 F2400 E0
    Log_FILE
    G1 F1800 X95.28 Y93.764 E0.07107

     

    So you'd need to filter those out (unless you really want them for some reason):

    if line != ""
        if not line.startswith(";"):
            new_lines.append("Log_FILE\n" + line + "\n")
        else:
            new_lines.append(line + "\n")
    else:
        new_lines.append(line)

     

    And in code that is utterly unreadable and you shouldn't use you can be a smartarse and do this:

    new_data.append(f"{(('Log_FILE' + chr(10)) if line and not line.startswith(';') else '') + line + (chr(10) if line else '')}")

    Seriously though, don't do that one. Was just me having a self-imposed challenge to see if I could do that.

  • Link to post
    Share on other sites

    Posted · What is wrong with the post processing script I made?

    ugh... python 

     

    to bad there's not a real switch but if python version > 3.10

    match line:
    	case (line.startswith(";"): // comment
    		new_lines.append(line + "\n");
    
    	case (line.startswith("\n"): // *nix blank line
    		new_lines.append(line);
    
    	case (line.startswith("\r"): // windows blank line
    		new_lines.append(line);
    
    	case default:				// standard action
    		new_lines.append("Log_FILE\n" + line + "\n")

     

    Maybe I spend to much time in C/C++/perl/Java/bash/csh/ksh land, but that seems much easier to read and clearer even withough comments. Also, since I hate python (WTF does whitespace matter!?!?! is this forking basic?) assume that will need some whitespace adjustment. 

  • Link to post
    Share on other sites

    Posted · What is wrong with the post processing script I made?

    I don't who would really want to skin a cat (or wombat), but there is always more than one way.

     

        def execute(self, data):
            for num, layer in enumerate(data):
                lines = layer.split("\n")
                for index, line in enumerate(lines):
                    if line == "":
                        continue
                    lines[index] += "\nLog_FILE"
                data[num] = "\n".join(lines)
            return data

  • Link to post
    Share on other sites

    Posted · What is wrong with the post processing script I made?
    2 hours ago, jaysenodell said:

    ugh... python 

     

    to bad there's not a real switch but if python version > 3.10

    match line:
    	case (line.startswith(";"): // comment
    		new_lines.append(line + "\n");
    
    	case (line.startswith("\n"): // *nix blank line
    		new_lines.append(line);
    
    	case (line.startswith("\r"): // windows blank line
    		new_lines.append(line);
    
    	case default:				// standard action
    		new_lines.append("Log_FILE\n" + line + "\n")

     

    Maybe I spend to much time in C/C++/perl/Java/bash/csh/ksh land, but that seems much easier to read and clearer even withough comments. Also, since I hate python (WTF does whitespace matter!?!?! is this forking basic?) assume that will need some whitespace adjustment. 

    How is match not a real switch, other than you're protected from fallthrough?

    Anyway, to be harsh, your code is wrong on so many levels that I have to issue a better version of it. I mean, don't get me wrong, your suggestion is terrible to begin with, but you could at least make it remotely valid Python.

    if line:  # Empty strings evaluate to False. And Python comments start with # and go to EOL.
        match line[0]:  # You can't use functions as cases so we're grabbing the first character (which is why we're protecting against empty strings)
            case ";":  # It's a comment
                new_lines.append(line + "\n")
            case "\n":  # It's just a blank line. And we're not reading this from a file! Line endings don't matter! And Python is smart enough to convert them anyway if you are reading them from a file! And a proper Windows newline would be "\r\n" anyway! And I don't think this case would ever match anything because the newlines are likely to be stripped!
                new_lines.append(line)
            case _:  # Yes that's the identifier for the default case
                new_lines.append("Log_FILE\n" + line + "\n")
    else:  # This would be the "empty string" problem I mentioned at the start. Which is entirely possible since str.split("\n") or str.splitlines() will remove a newline character by design or by default respectively.
        new_lines.append("\n")
  • Link to post
    Share on other sites

    Posted · What is wrong with the post processing script I made?
    1 hour ago, GregValiant said:

    I don't who would really want to skin a cat (or wombat), but there is always more than one way.

     

        def execute(self, data):
            for num, layer in enumerate(data):
                lines = layer.split("\n")
                for index, line in enumerate(lines):
                    if line == "":
                        continue
                    lines[index] += "\nLog_FILE"
                data[num] = "\n".join(lines)
            return data

    Because there's plenty of skin on a wombat. Those fat little bastards are pretty solid, as anyone who has hit one while driving down a highway can attest to. And they put up much less of a fight than the cats.

     

    Anyway, I don't know who would really want to beat a dead horse, but that way is far from ideal. You're stripping any blank lines from the code and you're inserting the "Log_FILE" after lines - except blank lines because those won't get anything added to them - which means they could quite easily appear before comments or not appear before actual commands.

  • Link to post
    Share on other sites

    Posted (edited) · What is wrong with the post processing script I made?
    35 minutes ago, Slashee_the_Cow said:

    How is match not a real switch, other than you're protected from fallthrough?

    Anyway, to be harsh, your code is wrong on so many levels that I have to issue a better version of it. I mean, don't get me wrong, your suggestion is terrible to begin with, but you could at least make it remotely valid Python.

    Listen... I'm not saying you're not right, but I'm clearly wrong so there. 

     

    Did I mention ... "ugh... python"?

     

    The auto conversions and "make our own standards" that seem to have crept in with MS adoption of python just make me twitchy for no good reason. Call it grumpy old man syndrome and I'll accept it. Because it's right. I'm sure phython is easier in some context, but I just don't care at some point. 

     

    And for the record, the \r\n should show up as [0][1] respetively in the string hence my \r check OR as ^M if it is the actual ascii CR. At least if python is using standard strings. But maybe python strings are special in using 2 bytes for a single byte comparison. Given my complete avoidence whenever possible, I should probably just crawl back under a my rock and resume my troll duties. 

     

    Passing shot though... command line for perl sould be stupid simple for this. This may need a tweek on the check for null line. Also ... *nix centric because me 😛

    perl -pe 'print "Log_FILE\n" unless ( ($_ > "\n") && (strpos( ";". $_) != 0) );'

     

    Edited by jaysenodell
    had a dup of the original line in the output
  • Link to post
    Share on other sites

    Posted · What is wrong with the post processing script I made?
    12 minutes ago, jaysenodell said:

    And for the record, the \r\n should show up as [0][1] respetively in the string hence my \r check OR as ^M if it is the actual ascii CR. At least if python is using standard strings. But maybe python strings are special in using 2 bytes for a single byte comparison. Given my complete avoidence whenever possible, I should probably just crawl back under a my rock and resume my troll duties. 

     

    Passing shot though... command line for perl sould be stupid simple for this. This may need a tweek on the check for null line. Also ... *nix centric because me 😛

    How Python treats line endings in files is completely irrelevant in this case because the post-processor gets passed a list of strings. No file reading whatsoever. No writing, either, which is why you can just use "\n".

     

    But with text file I/O in Python, unless you explicitly state that you want your newlines to be "\r" or "\r\n", it will implicitly convert a platform's newlines to a simple "\n" when you read it and convert a "\n" to that platform's newline when you write it.

     

    Also you're forgetting that it's probably entirely possible with a regex substitution. And no, I'm not providing an example. I can do regex, but not so well at 12:30 AM.

  • Link to post
    Share on other sites

    Posted · What is wrong with the post processing script I made?
    2 minutes ago, Slashee_the_Cow said:

    Also you're forgetting that it's probably entirely possible with a regex substitution. And no, I'm not providing an example. I can do regex, but not so well at 12:30 AM.

    sed/awk for the win!

     

    I forget that this is "in code" and we are dealing with arrays not files. I need to stay in my lane ad remain a "user" here and stay out of develper... stay out of developer .... STAY OUT OF DEVELOPER!

  • Link to post
    Share on other sites

    Posted · What is wrong with the post processing script I made?
    2 minutes ago, jaysenodell said:

    I forget that this is "in code" and we are dealing with arrays not files.

    Lists. Python has arrays, but you need to import the module manually and they're a lot less flexible. But they use a bit less memory and can be (theoretically) quicker to iterate through or grab individual elements because they're contiguous in memory... but with memory speeds these days, you'd need an extreme example to notice a real world difference in performance.

  • Link to post
    Share on other sites

    Posted · What is wrong with the post processing script I made?

    Poor @T9_AIR.  All this back-and-forth over a 6 line script.

    • Laugh 1
    Link to post
    Share on other sites

    Posted · What is wrong with the post processing script I made?
    3 hours ago, GregValiant said:

    Poor @T9_AIR.  All this back-and-forth over a 6 line script.

    I concur.

    @T9_AIR, we're happy to stop squabbling amongst ourselves about who can produce the most obtuse code that works. If you need more help, just post and we'll be happy to do all we can.

    • Laugh 1
    Link to post
    Share on other sites

    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now
    • Our picks

      • UltiMaker Cura 5.8 Stable released 🎉
        In the Cura 5.8 stable release, everyone can now tune their Z seams to look better than ever. Method series users get access to new material profiles, and the base Method model now has a printer profile, meaning the whole Method series is now supported in Cura!
        • 3 replies
      • Introducing the UltiMaker Factor 4
        We are happy to announce the next evolution in the UltiMaker 3D printer lineup: the UltiMaker Factor 4 industrial-grade 3D printer, designed to take manufacturing to new levels of efficiency and reliability. Factor 4 is an end-to-end 3D printing solution for light industrial applications
          • Thanks
          • Like
        • 3 replies
    ×
    ×
    • Create New...