0

code below creates a layout and displays some text in the layout. Next the layout is displayed on the console screen using raw display module from urwid library. However running the code fails as a global variable ui, declared in main, is not recognised in another function.

Error code on running is :
Traceback (most recent call last):
File "./yamlUrwidUIPhase6.py", line 97, in <module>
main() File "./yamlUrwidUIPhase6.py", line 90, in main
form = FormDisplay() File "./yamlUrwidUIPhase6.py", line 23, in __init__
palette = ui.register_palette([
NameError: global name 'ui' is not defined

The code :

import sys  
sys.path.append('./lib')  
import os  
from pprint import pprint  
import random  
import urwid  
global ui

class FormDisplay(object):

    def __init__(self):
        self.ui = urwid.raw_display.Screen()
        palette = ui.register_palette([
            ('Field', 'dark green, bold', 'black'), # information fields, Search: etc.
            ('Info', 'dark green', 'black'), # information in fields
            ('Bg', 'black', 'black'), # screen background
            ('InfoFooterText', 'white', 'dark blue'), # footer text
            ('InfoFooterHotkey', 'dark cyan, bold', 'dark blue'), # hotkeys in footer text
            ('InfoFooter', 'black', 'dark blue'),  # footer background
            ('InfoHeaderText', 'white, bold', 'dark blue'), # header text
            ('InfoHeader', 'black', 'dark blue'), # header background
            ('BigText', RandomColor(), 'black'), # main menu banner text
            ('GeneralInfo', 'brown', 'black'), # main menu text
            ('LastModifiedField', 'dark cyan, bold', 'black'), # Last modified:
            ('LastModifiedDate', 'dark cyan', 'black'), # info in Last modified:
            ('PopupMessageText', 'black', 'dark cyan'), # popup message text
            ('PopupMessageBg', 'black', 'dark cyan'), # popup message background
            ('SearchBoxHeaderText', 'light gray, bold', 'dark cyan'), # field names in the search box
            ('SearchBoxHeaderBg', 'black', 'dark cyan'), # field name background in the search box
            ('OnFocusBg', 'white', 'dark magenta') # background when a widget is focused
           ])
        urwid.set_encoding('utf8')

    def main(self):
        #self.view = ui.run_wrapper(formLayout)
        self.view = formLayout()
        self.ui.start()
        self.loop = urwid.MainLoop(self.view, self.palette, unhandled_input=self.unhandled_input)
        self.loop.run()

    def unhandled_input(self, key):
        if key == 'f8':
          quit()
          return


def formLayout():
    text1 = urwid.Text("Urwid 3DS Application program - F8 exits.")
    text2 = urwid.Text("One mission accomplished")

    textH = urwid.Text("topmost Pile text")
    cols = urwid.Columns([text1,text2])
    pile = urwid.Pile([textH,cols])
    fill = urwid.Filler(pile)

    textT  = urwid.Text("Display") 

    textSH = urwid.Text("Pile text in Frame")
    textF = urwid.Text("Good progress !")

    frame = urwid.Frame(fill,header=urwid.Pile([textT,textSH]),footer=textF)
    dim = ui.get_cols_rows()

    ui.draw_screen(dim, frame.render(dim, True))
    return

def RandomColor():
    '''Pick a random color for the main menu text'''
    listOfColors = ['dark red', 'dark green', 'brown', 'dark blue',
                    'dark magenta', 'dark cyan', 'light gray',
                    'dark gray', 'light red', 'light green', 'yellow',
                    'light blue', 'light magenta', 'light cyan', 'default']
    color = listOfColors[random.randint(0, 14)]
    return color

def main():
    form = FormDisplay()
    form.main()

########################################
##### MAIN ENTRY POINT
########################################
if __name__ == '__main__':
    main()

I don't want to change the function formLayout as I intend to add more to this basic code framework, where in another function will be added that repeatedly calls formLayout to keep updating the screen based on reading values from a yml file.

tauseef_CuriousGuy
  • 770
  • 1
  • 12
  • 28
  • Please note the changes I've made in the original thread http://stackoverflow.com/questions/17898314/main-function-call-fails-in-python/17901023 , moreover could you post the code that throws the stack trace. – Ketouem Jul 27 '13 at 21:31
  • You also need a declaration of `ui` outside of any function or class for the `global ui` declarations to be effective. – Jonathan Jul 27 '13 at 21:34
  • @Jonathan I put the global ui right after the imports but still doesn't work. Should I start a new question with my current code and the error message ? because i can't figure out how to put properly indented code in commments boxes here. – tauseef_CuriousGuy Jul 27 '13 at 21:52
  • @Ketouem I moved the code here, let's discuss it here. incorporated your changes in code. new trace for the error message printed. still doesn't work – tauseef_CuriousGuy Jul 27 '13 at 22:03
  • @Jonathan updated code (above) to make global ui come right after the imports. still doesn't work. latest stack trace given. – tauseef_CuriousGuy Jul 27 '13 at 22:04
  • you don't need to make a global variable. Just put self.palette = self.ui.register_palette – Ketouem Jul 27 '13 at 22:06
  • @Ketouem deleted the global ui declaration. made the change self.palette = self.ui.register_palette . The error now comes from the function formLayout() : NameError: global name 'ui' is not defined in the function formLayout() I was wondering after your suggestions as to how formLayout() will recognise ui when now its not even declared globally but nonetheless used in the same way as I did earlier. – tauseef_CuriousGuy Jul 27 '13 at 22:15
  • @tauseef_india: The problem now is that you're trying to do some things with `ui` from methods of the `FormDisplay` class and other things from standalone functions. Why don't you make all those functions methods of the class? – BrenBarn Jul 27 '13 at 22:16
  • Why don't you put the formLayout function inside the class hence you could call self.ui. Or if you don't wan't to put it inside the class, edit the function to make it accept a parameter and pass it and instance of the above class ( formLayout(formdisplay_instance) ) – Ketouem Jul 27 '13 at 22:18
  • I agree with that having formLayout function part of the FormDisplay class will save me from the trouble of having a global accessible nature of ui. But I prefer having it in this way because of further things that I wanted to build on this code. See here : [http://stackoverflow.com/questions/17846930/required-widgets-for-displaying-a-1d-console-application] – tauseef_CuriousGuy Jul 27 '13 at 22:38
  • So my idea is to use the FormDisplay class to get a handle on a global variable ui referring to the console screen. Meanwhile other standalone functions, more will be added subsequently, can also use this handle to modify the console screen. But I appreciate your suggestions. :-) – tauseef_CuriousGuy Jul 27 '13 at 22:39
  • The yml file that describes my console screen is here : [http://stackoverflow.com/questions/17816756/checking-for-any-string-literal-in-an-ordered-dictionary] – tauseef_CuriousGuy Jul 27 '13 at 22:57

2 Answers2

1

Writing global ui in main does nothing except make it so that main itself can write to a global variable called ui. If you want to write to that global variable from other functions (like your __init__), you need to include a global declaration there too. Every function where you want to assign to a global variable has to have its own global declaration.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • my main intention behind using global ui is because i want a handle to the console screen ( represented here by the raw display module provided by urwid). so that i can write several functions for creating a top level box widget and then for adding further sub widgets to the box widget whereby i can write/modify to the screen. If I have a global ui declaration for each function then will the function call reflect changes in the global console screen ? – tauseef_CuriousGuy Jul 27 '13 at 21:16
  • @tauseef_india: Yes, if you use `global ui` in each function that uses `ui`, at least all those functions will be able to write to that variable. I don't know how `uiwid` works so I can't say whether that means it will actually work and do what you want it to do, but at least you won't have these `name not defined` issues. – BrenBarn Jul 27 '13 at 21:27
  • declared global ui in each of the functions that used ui, still doesn't work :-( – tauseef_CuriousGuy Jul 27 '13 at 21:38
  • it showed similar error message as given in stack trace above. i tried to incorporate Jonathan's suggestion in the other answer above, but that doesn't work also. – tauseef_CuriousGuy Jul 27 '13 at 22:07
  • now there is an attribute error with changed code. new question at [http://stackoverflow.com/questions/17908588/attributeerror-while-trying-to-create-a-console-screen-using-urwid] – tauseef_CuriousGuy Jul 28 '13 at 14:02
0

okay, thanks to people for various suggestions that helped me learn about the global scoping. I followed the answer by Jeff Shannon here : Using global variables in a function other than the one that created them seem to be able to get rid of the name scoping error caused by using global ui. here is what i did i used ui=urwid.raw_display.Screen() right after the imports and then declared global ui in the functions that used it. But now I get a different kind of error. Think it best to start a new question with the error now obtained.

Community
  • 1
  • 1
tauseef_CuriousGuy
  • 770
  • 1
  • 12
  • 28