0

I am using python tkinter to make a text editor. I am trying to work out the logic of how to save the file the first time with a dialog box (so you can set the file name), and all the other times without. Here is the code I have so far:

filename = ""
def save():

input_data = textinput.get("1.0", "1000000.0")

try:
    with open(filename, "w") as f:
        f.write(input_data)
        f.close()

except IOError:
    file = filedialog.asksaveasfile(initialdir="/documents", title="Save file", defaultextension=".txt", filetypes=[("HTML files", ".html"), ("All file types", ".*")])
    global filename
    filename = file.name
    file.write(input_data)
    file.close()

input_data is the text field contents, and the save() function is called when they push the save button.

I am trying to make it so the first time when you click save, the filename variable has not been assigned to the file path and name, so it does the IOError, that opens the box and saves the file. It also sets a global filename as seen here: Link. But this error is given: SyntaxError: name 'filename' is used prior to global declaration. It is, but that is what the link said to do. How can I solve this problem? Thanks for any help in advance! xD

Alen
  • 25
  • 1
  • 8
  • Why not have `global filename = '' ` as the first line of the code? And then you won't need to use `global ` keyword in the `except` clause. – NotAName Feb 23 '21 at 23:53
  • Now it is showing this: UnboundLocalError: local variable 'filename' referenced before assignment – Alen Feb 23 '21 at 23:57

1 Answers1

2

A global statement needs to be placed above the first use of a variable, even if that first use is just reading the existing value, not assigning to it.

In your code, you're trying to use filename in your open call, within the with statement. The global statement occurs later, when you're trying to assign to the global filename variable.

The easy fix is to just move the global statement up to the top of the function:

filename = ""
def save():
    global filename                                # move the global statement up here
    input_data = textinput.get("1.0", "1000000.0")

    try:
        with open(filename, "w") as f:             # so it's above this use of filename
            f.write(input_data)
            f.close()
    
    except IOError:
        file = filedialog.asksaveasfile(initialdir="/documents", title="Save file", defaultextension=".txt", filetypes=[("HTML files", ".html"), ("All file types", ".*")])
        filename = file.name                      # not only the assignment down here
        file.write(input_data)
        file.close()

A better approach is probably to not use a global variable at all, and instead use an instance of a class to hold the filename, but that's a more disruptive change.

Blckknght
  • 100,903
  • 11
  • 120
  • 169
  • I am slightly confused. Can you add your solution to my code as an example? – Alen Feb 24 '21 at 00:01
  • I've edited to put the change in context, within the function. Hopefully it will make more sense now, especially with the comments in the code. – Blckknght Feb 24 '21 at 00:13
  • Is there something I am missing? It is giving this error: "NameError: name 'filename' is not defined" But it is! – Alen Feb 24 '21 at 00:33
  • Have you omitted the very first line of the code in your question, where you initialize `filename` outside of the function, with `filename = ""`? – Blckknght Feb 24 '21 at 00:48
  • Yes, I am really sorry, but it is still not working – Alen Feb 24 '21 at 00:54
  • `filename = ""` should not be removed. – acw1668 Feb 24 '21 at 08:38
  • Perhaps I wasn't clear. You *do* need to *keep* that line, you'll get the error if you remove it. I omitted it from my rewrite of the code because it doesn't need to change (originally I was not including the full function in my answer, so adding a copy of the setup initialization code never crossed my mind). – Blckknght Feb 24 '21 at 09:27