Code, using urwid library, below is supposed to display the contents of yml file (as given here) on a console screen (as per the Application Form layout here :
code is :
import sys
sys.path.append('./lib')
import os
from pprint import pprint
import random
import urwid
ui = urwid.raw_display.Screen()
pile = urwid.Pile([])
from collections import OrderedDict
import yaml_ordered_dict
import collections
import yaml
import itertools
import copy
class FormDisplay(object):
def __init__(self):
global ui
#self.ui = urwid.raw_display.Screen()
self.ui = ui
self.palette = self.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):
global ui
#self.view = ui.run_wrapper(formLayout)
#urwid initialisation first or yml readin first. i chose yml reading
yOrDict = yaml_ordered_dict.load('ApplyForm.yml')
yOrDictLevel1 = yOrDict.get('ApplyForm')
self.ui.start()
self.view = formLayout(yOrDictLevel1)
self.loop = urwid.MainLoop(self.view, self.palette)
self.loop.widget = self.view
self.loop.run()
def find_value(needle, container):
# Already found the object. Return.
if isinstance(container, basestring) and needle in container:
return True
values = None
if isinstance(container, dict):
values = container.values()
elif hasattr(container, '__iter__'):
values = container.__iter__()
if values is None:
return False
# Check deeper in the container, if needed.
for val in values:
if find_value(needle, val):
return True
# No match found.
return False
def getChildMap(tmpMap):
tMap = tmpMap
tmpLen = len(tMap)
listOfKeys = tMap.keys()
topKey = listOfKeys[0]
#print('topkey', topKey)
mapObtained = tMap.get(topKey)
#print('getChildMap',mapObtained)
return mapObtained
def getMapForKeyIndex(tmpMap,index):
listOfKeysForMap = tmpMap.keys()
i = index
mapObtained = collections.OrderedDict(itertools.islice(tmpMap.items(), i, i+1))
#print(type(mapObtained))
#print("getMapForKeyIndex: key and map",i,mapObtained)
return mapObtained
def checkValOfKey(key,tmpMap):
tMap = tmpMap
for k, v in tMap.items():
if k == key :
tVal = tMap[key]
#print('checkValOfKey:tVal',tVal)
return tVal
def removeTopItem(tmpMap):
tMap = tmpMap
listOfKeys = tMap.keys()
topKey = listOfKeys[0]
del tMap[topKey]
return tMap
def createBlock(mapToWorkWith) :
global pile
#pile = urwid.Pile([])
tmapToWorkWith = copy.deepcopy(mapToWorkWith)
tmapToWorkWith = getChildMap(tmapToWorkWith)
#print('createBlock: tmapToWorkWith', tmapToWorkWith)
reducedMapToCarry = copy.deepcopy(tmapToWorkWith)
listOfKeys = tmapToWorkWith.keys()
#if blockPresentAsValueInMap(tmapToWorkWith) == True :
if checkValOfKey('$type',tmapToWorkWith) == 'Block' :
#create a block nd pile
print('XXXXXXXXcreate block and pile listXXXXXXXX')
#pile = urwid.Pile([])
keytoBeginPile = 2
#if displayPresentAsKeyInMap(tmapToWorkWith) == True :
#if checkContainmentOfKeyInMap('$display',(tmapToWorkWith)) :
reducedMapToCarry = removeTopItem(reducedMapToCarry)
reducedMapToCarry = removeTopItem(reducedMapToCarry)
if (tmapToWorkWith.has_key('$display')) == True :
print('display value ',tmapToWorkWith['$display'])
displayText = tmapToWorkWith['$display']
text = urwid.Text(('GeneralInfo', displayText),
align='center')
pile.contents.append(text)
keytoBeginPile +=1
#addDisplayToPile
reducedMapToCarry = removeTopItem(reducedMapToCarry)
for k in range(keytoBeginPile,len(tmapToWorkWith)) :
#//get the value of key at indexkeytoBeginPile in tmapToWorkWith
tmpMap = tmapToWorkWith.get(listOfKeys[k])
if checkValOfKey('$type',tmpMap) != 'Block' :
print('##add to Pile##')
print('display value ',tmpMap['$display'])
displayText = tmpMap['$display']
text = urwid.Text(('GeneralInfo', displayText),
align='center')
#pile.contents.append(text,options='pack')
pile.append(text)
keytoBeginPile +=1
reducedMapToCarry = removeTopItem(reducedMapToCarry)
#print('for Loop traversal: map', reducedMapToCarry)
#mapToPass(pop)
continue
else :
createBlock(reducedMapToCarry)
#return urwid.LineBox(urwid.AttrWrap(urwid.Overlay(urwid.LineBox(urwid.Padding(
# pile, align='center', left=3, right=3)), Banner, 'center', 150, 'middle', None),
# 'GeneralInfo'))
def formLayout(topMap):
global ui
global pile
f3 = open('OrderedMapInFinalApp.yaml',"w")
newMap = topMap #check if needed at all
yaml.dump(newMap, f3)
content = urwid.SimpleListWalker([])
listbox = urwid.ListBox(content)
#orderedMap has come
#read the key value and start for loop
print('lenght of map',len(newMap))
for i in range(len(newMap)):
mapToWorkWith = getMapForKeyIndex(newMap,i)
#print('for loop i nd mapToWorkWith Is',i,mapToWorkWith)
if i == 0 :
if (checkValOfKey('$type',mapToWorkWith) == 'Block') :
print('1st key read')
continue
else :
if (mapToWorkWith.has_key('TITLE') == True):
print('2nd key read')
continue
else :
pile = ([])
createBlock(mapToWorkWith)
#content.append(addBlockToOverallLayout())
content.append(pile)
continue
fill = urwid.Filler(listbox)
frame = urwid.Frame(fill,header=urwid.Pile([textT,textSH]),footer=textF)
dim = ui.get_cols_rows()
#ui is treated as global handle for all functions, either belonging
#to any class or standalone functions such as formLayout
#need to check if screen has been started
if not ui._started:
print("Screen has not been started, so no use of rendering.Thus return :-( ")
return
#ui.draw_screen(dim, listbox.render(dim, True))
return frame
#return listbox
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():
#global ui
form = FormDisplay()
form.main()
########################################
##### MAIN ENTRY POINT
########################################
if __name__ == '__main__':
main()
#
The code use ui to represent the console screen.
I have used a global listbox api that will contain the values, from yml file, whose key is $display. The code fails giving the error below :
Traceback (most recent call last):
File "./yamlUrwidUIPhase8FrameFinalAppC.py", line 308, in <module>
main()
File "./yamlUrwidUIPhase8FrameFinalAppC.py", line 302, in main
form.main()
File "./yamlUrwidUIPhase8FrameFinalAppC.py", line 61, in main
self.loop.run()
File "/home/gehna/urwidWorkInProgress/urwid/main_loop.py", line 272, in run
self.screen.run_wrapper(self._run)
File "/home/gehna/urwidWorkInProgress/urwid/raw_display.py", line 242, in run_wrapper
return fn()
File "/home/gehna/urwidWorkInProgress/urwid/main_loop.py", line 312, in _run
self.draw_screen()
File "/home/gehna/urwidWorkInProgress/urwid/main_loop.py", line 563, in draw_screen
canvas = self._topmost_widget.render(self.screen_size, focus=True)
File "/home/gehna/urwidWorkInProgress/urwid/widget.py", line 141, in cached_render
canv = fn(self, size, focus=focus)
File "/home/gehna/urwidWorkInProgress/urwid/container.py", line 1058, in render
focus and self.focus_part == 'body')
File "/home/gehna/urwidWorkInProgress/urwid/widget.py", line 141, in cached_render
canv = fn(self, size, focus=focus)
File "/home/gehna/urwidWorkInProgress/urwid/decoration.py", line 811, in render
top, bottom = self.filler_values(size, focus)
File "/home/gehna/urwidWorkInProgress/urwid/decoration.py", line 796, in filler_values
height = self._original_widget.rows((maxcol,),focus=focus)
AttributeError: 'ListBox' object has no attribute 'rows'
I checked the parsing section of the code with ddd and pydb debugger and the parsing yml section seems to be okay and the print statements give the values of $display correctly. Is there something wrong with the way I am using ui ? Should I use a draw_screen instead ?
Strange, your code should work as is. I had the same error when creating Frames and giving them the wrong order of arguments, so my best guess is to change this line
to
or
Discard the footer temporarily until you figure out the right order of parameters inside Frame and then put it back.