0

I'm trying to use a global variable. I've declared it as global to begin with and the declare it at such at each mention, but I get a NameError after the first function completes. Here's the code, and I think I've gone stare crazy but I can't seem to find the problem.

def on_servername_insertatcursor(self, widget):
    global output  
    output = StringIO.StringIO()         
    servername = widget.get_text()
    output.write("USHARE_NAME="+servername+'\n')

def on_netif_changed(self, widget):
    netif = widget.get_active_text()
    global output
    output.write("USHARE_IFACE="+netif+'\n')

def on_port_insertatcursor(self, widget):
    global output
    port = widget.get_text()
    output.write("USHARE_PORT="+port+'\n')

def on_telprt_insertatcursor(self, widget):
    global output
    telprt = widget.get_text()
    output.write("USHARE_TELNET_PORT="+telprt+'\n')

def on_dirs_insertatcursor(self, widget):
    global output
    dirs = widget.get_text()
    output.write("USHARE_DIR="+dirs+'\n')

def on_iconv_toggled(self, widget):
    global output
    iconv = widget.get_active()
    if iconv == True:
        output.write("USHARE_OVERRIDE_ICONV_ERR="+"True"+'\n')
    else:
        output.write("USHARE_OVERRIDE_ICONV_ERR="+"False"+'\n')

def on_webif_toggled(self, widget):
    global output
    webif = widget.get_active()
    if webif == True:
        output.write("USHARE_ENABLE_WEB="+"yes"+'\n')
    else:
        output.write("USHARE_ENABLE_WEB="+"no"+'\n')

def on_telif_toggled(self, widget):
    global output
    telif = widget.get_active()
    if telif == True:
        output.write("USHARE_ENABLE_TELNET="+"yes"+'\n')
    else:
        output.write("USHARE_ENABLE_TELNET="+"no"+'\n')

def on_xbox_toggled(self, widget):
    global output
    xbox = widget.get_active()
    if xbox == True:
        output.write("USHARE_ENABLE_XBOX="+"yes"+'\n')
    else:
        output.write("USHARE_ENABLE_XBOX="+"no"+'\n')

def on_dlna_toggled(self, widget):
    global output
    dlna = widget.get_active()
    if dlna == True:
        output.write("USHARE_ENABLE_DLNA="+"yes"+'\n')
    else:
        output.write("USHARE_ENABLE_DLNA="+"no"+'\n')

def on_commit_clicked(self, widget):
    commit = output.getvalue()
    logfile = open('/home/boywithaxe/Desktop/ushare.conf','w')
    logfile.write(commit)

def on_endprogram_clicked(self, widget):
    sys.exit(0)

What's amazing is that when insertatcursor (coming from Gtk.TextBuffer.insert_at_cursor() ) is replace with activate, the code works perfectly, except I don't want to have the user have to press enter after every data input.

EDIT. The Traceback is as follows

Traceback (most recent call last):
File "/home/boywithaxe/Developer/Quickly/broadcast/broadcast/BroadcastWindow.py", line     58, in on_netif_changed
output.write("USHARE_IFACE="+netif+'\n')
NameError: global name 'output' is not defined

Having made the changes suggested by @jdi (Thank you btw, I see the logic behind that), the Traceback I get is as follows:

Traceback (most recent call last):
File "/home/boywithaxe/Developer/Quickly/broadcast/broadcast/BroadcastWindow.py", line 55, in on_netif_changed
OUTPUT.write("USHARE_IFACE="+netif+'\n')
NameError: global name 'OUTPUT' is not defined
Traceback (most recent call last):
File "/home/boywithaxe/Developer/Quickly/broadcast/broadcast/BroadcastWindow.py", line 72, in on_iconv_toggled
OUTPUT.write("USHARE_OVERRIDE_ICONV_ERR="+"True"+'\n')
NameError: global name 'OUTPUT' is not defined
Traceback (most recent call last):
File "/home/boywithaxe/Developer/Quickly/broadcast/broadcast/BroadcastWindow.py", line 79, in on_webif_toggled
OUTPUT.write("USHARE_ENABLE_WEB="+"yes"+'\n')
NameError: global name 'OUTPUT' is not defined
Traceback (most recent call last):
File "/home/boywithaxe/Developer/Quickly/broadcast/broadcast/BroadcastWindow.py", line 86, in on_telif_toggled
OUTPUT.write("USHARE_ENABLE_TELNET="+"yes"+'\n')
NameError: global name 'OUTPUT' is not defined
Traceback (most recent call last):
File "/home/boywithaxe/Developer/Quickly/broadcast/broadcast/BroadcastWindow.py", line 93, in on_xbox_toggled
OUTPUT.write("USHARE_ENABLE_XBOX="+"yes"+'\n')
NameError: global name 'OUTPUT' is not defined
Traceback (most recent call last):
File "/home/boywithaxe/Developer/Quickly/broadcast/broadcast/BroadcastWindow.py", line 100, in on_dlna_toggled
OUTPUT.write("USHARE_ENABLE_DLNA="+"yes"+'\n')
NameError: global name 'OUTPUT' is not defined
Traceback (most recent call last):
File "/home/boywithaxe/Developer/Quickly/broadcast/broadcast/BroadcastWindow.py", line 105, in on_commit_clicked
commit = OUTPUT.getvalue()
NameError: global name 'OUTPUT' is not defined
boywithaxe
  • 286
  • 1
  • 12
  • 2
    Why did you put in so many `global`s? Also, please post the *actual trace of the error* as that will contain the reason. I suspect `on_servername_insertatcursor` wasn't called first.. –  Jun 23 '12 at 23:10
  • 3
    if you never *assign to* output (ie `output = 3`) you *don't* need to make it global. – Hugh Bothwell Jun 23 '12 at 23:12
  • 1
    I don't think you went "stare crazy". I think you went "global crazy" – jdi Jun 23 '12 at 23:12
  • @pst: The reason for all the `global`s is as per [this](http://stackoverflow.com/a/423668/1030495). The traceback has been included in the first post(comments to play well with longer code snippets). – boywithaxe Jun 23 '12 at 23:14
  • 3
    You only need `global` when you are setting the variable. You can read its value and change its attributes without that! – JBernardo Jun 23 '12 at 23:15
  • Did you say `output=None` in the global scope? And did you try it without the `global` keyword in your `on_netif_changed()` ? – jdi Jun 23 '12 at 23:21
  • @jdi: I did, and `on_netif_changed` still calls on output. Also changing `output` in the global scope doesn't change anything in the execution and gives me the same error at the same point. – boywithaxe Jun 23 '12 at 23:29
  • I declare shenanigans. Something else must be going on in the execution order of your code. You can clearly see in my answer that the test example works just fine. – jdi Jun 23 '12 at 23:32
  • @jdi: I fully agree with you, and it seems to be cause by the signals. O_O – boywithaxe Jun 23 '12 at 23:42

3 Answers3

1

Your code example doesn't require a global. Just remove it. The only time you need to use the global keyword in a function is if you are going to assign to it.

OUTPUT = StringIO.StringIO()         

def on_servername_insertatcursor(self, widget):
    servername = widget.get_text()
    OUTPUT.write("USHARE_NAME="+servername+'\n')

def on_netif_changed(self, widget):
    netif = widget.get_active_text()
    OUTPUT.write("USHARE_IFACE="+netif+'\n')

def on_port_insertatcursor(self, widget):
    port = widget.get_text()
    OUTPUT.write("USHARE_PORT="+port+'\n')

def on_telprt_insertatcursor(self, widget):
    telprt = widget.get_text()
    OUTPUT.write("USHARE_TELNET_PORT="+telprt+'\n')

def on_dirs_insertatcursor(self, widget):
    dirs = widget.get_text()
    OUTPUT.write("USHARE_DIR="+dirs+'\n')

def on_iconv_toggled(self, widget):
    iconv = widget.get_active()
    if iconv == True:
        OUTPUT.write("USHARE_OVERRIDE_ICONV_ERR="+"True"+'\n')
    else:
        OUTPUT.write("USHARE_OVERRIDE_ICONV_ERR="+"False"+'\n')

Even if you wanted to be able to reset your StringIO object in a function, it still wouldn't require an assignment or global keyword:

def reset_output(self):
    OUTPUT.seek(0)
    OUTPUT.truncate()

Proof that it works

import StringIO

OUTPUT = StringIO.StringIO()         

def foo():
    OUTPUT.write('foo')

def bar():
    OUTPUT.write('bar')

def print_output():
    print OUTPUT.getvalue()

def reset_output():
    OUTPUT.seek(0)
    OUTPUT.truncate()

if __name__ == "__main__":
    foo()
    bar()
    print_output()
    reset_output()
    print_output()

Output

$ python test.py 
foobar

$
jdi
  • 90,542
  • 19
  • 167
  • 203
  • I had that to begin with, and this gave me the exact same Traceback. This is what led me on trying out `global`s in the first place – boywithaxe Jun 23 '12 at 23:21
  • Your example works perfectly but when applied to my code it doesn't. I'm starting to think that it's the widgets and their respective signals, otherwise why would changing from `insertatcursor` to `activate` on `TextBox` widgets affect the end result. – boywithaxe Jun 23 '12 at 23:41
  • @boywithaxe: Yea I can't be sure without knowing the entire scope of your code. – jdi Jun 23 '12 at 23:43
  • That's the code though, well the manual bit anyway, the rest was generated by Quickly, apart from adding links to objects. – boywithaxe Jun 23 '12 at 23:45
  • @boywithaxe: I don't know enough about GTK to know what happens to the scope of these functions if they are used as "SLOTS". My examples are a general approach to global scope. You may need to pass around a context object. – jdi Jun 23 '12 at 23:52
  • I've asked the question on AskUbuntu as well, I'd be surprised if it were the signals all along, also, this would mean I could drop `global`s altogether, making the code cleared. Thank you for all your help. – boywithaxe Jun 24 '12 at 00:06
  • Marked as answered, your solution works, as the problem is not with the logic but the signals. – boywithaxe Jun 24 '12 at 01:07
  • Sorry that I couldn't figure the rest of it out for ya. Good luck on it though. Update your question with results if you find anything out. – jdi Jun 24 '12 at 02:17
0

Try moving output = StringIO.StringIO() outside and above all the functions in the file.

ChipJust
  • 1,376
  • 12
  • 20
0

Well, the problem with the question is unfortunate indenting :) Looking at PyGTK docs shows that the on_... functions shown are indeed methods of a class, not global functions, so the "global" variable is probably not really global but also a member of the class (just look at the self parameter in method definitions).

I gave a more detailed answer on askubuntu, here's a code snippet which shows what needs to be done:

class MyApp(gtk.Window):

    output = None

    def __init__(...):
        ...
        self.output = StringIO.StringIO()

    def on_servername_insertatcursor(self, widget):    
        servername = widget.get_text()
        self.output.write("USHARE_NAME="+servername+'\n')

    def on_netif_changed(self, widget):
        netif = widget.get_active_text()
        self.output.write("USHARE_IFACE="+netif+'\n')

There's absolutely no PyGTK-specific or signals-specific magic involved :)

Community
  • 1
  • 1
Sergey
  • 11,892
  • 2
  • 41
  • 52