Replacing a Gtk MenuItem with another - python

A part of my selection menu is a 'recents' menu, consisting of the 5 most recently selected menuitems. So whenever the user selects an item from the menu, it should update this part of the menu.
In order to do this, I need to replace those menu items with new ones. But apparently just keeping a reference to them and pointing it at a new object is not enough. The menu is not rebuilt on the fly.
Code:
def rebuild_recents_menu(self):
counter = 0
for item in self._build_recents_menu():
self.recent_group['base_group'][counter] = item
counter += 1
GLib.idle_add(self.asset_menu.show_all) # self.assets_menu is a reference to the menu to which the submenu is attached
def _build_recents_menu(self):
recent_group = {
'base_group': [],
'subgroup_quotes': [],
'subgroup_exchanges': []
}
for i in range(0,5):
if i > len(self.coin.settings.get('recent'))-1:
base_item = self.create_base_item(None, recent_group, hidden = True)
else:
base = self.coin.settings.get('recent')[i]
base_item = self.create_base_item(base, recent_group)
yield base_item
self.recent_group = recent_group
def create_base_item(self, base, group, hidden = False):
if hidden:
base_item = Gtk.RadioMenuItem.new_with_label(group.get('base_group'), 'hidden')
base_item.hide()
else:
base_item = Gtk.RadioMenuItem.new_with_label(group.get('base_group'), base)
base_item.set_submenu(self._menu_quotes(base, group.get('subgroup_quotes'), group.get('subgroup_exchanges')))
group.get('base_group').append(base_item)
if self.exchange.asset_pair.get('base') == base:
base_item.set_active(True)
base_item.connect('toggled', self._handle_toggle, base)
return base_item

Related

TypeError: list_content() missing 1 required positional argument: 'key'

I have a python problem that creates a box and puts items in the box and with the help of the list command I can see what's in my box. One example of the execution may go as:
next command> newbox bedroom-box-05
next command> add bedroom-box-05 pillow 3
next command> list bedroom-box-05
Box "bedroom-box-05" contains 3 items.
3 pillow
There are some issues with class MovingBox() as I cannot change the main functions.
class MovingBox():
"""A class for keeping track of the contents ofa moving box. """
def __init__(self,*args):
self = dict()
def add_item(self,key,value =[]):
setattr(self,key,value)
self.add_item=value
def list_content(self,key,value =[]):
setattr(self, key, value)
self.list_content = value
key1 = Keys() # parens
key1.list_content(value)
DON'T CHANGE ANYTHING AFTER THIS LINE
def convert_str_to_int(word):
"""
Converts the parameter string *word* in to an integer value.
"""
try:
result = int(word)
except ValueError:
return None
return result
def newbox(all_boxes, list_of_additional_info):
if len(list_of_additional_info) != 1:
print("Error: wrong number of initial data: can't create a new box.")
return
box_name = list_of_additional_info[0]
all_boxes[box_name] = MovingBox(box_name)
def add_to_box(all_boxes, list_of_additional_info):
if len(list_of_additional_info) != 3:
print("Error: wrong number of elements: can't add into a box.")
return
box_name, item_name, item_count = list_of_additional_info
item_count = convert_str_to_int(item_count)
if item_count is None:
print("Error: not a number: can't add to a box.")
return
if box_name not in all_boxes:
print("Error: box does not exist: can't add to a box.")
return
all_boxes[box_name].add_item(item_name, item_count)
def list_box_content(all_boxes, list_of_additional_info):
"""Displays the contents of a single box in *all_boxes* """
if len(list_of_additional_info) != 1:
print("Error: wrong number of elements: can't list contents.")
return
box_name = list_of_additional_info[0]
if box_name not in all_boxes:
print("Error: box does not exist: can't list content.")
return
all_boxes[box_name].list_content()
def main():
boxes = {}
while True:
command_line = input("next command> ").strip()
if command_line == "":
break
command_words = command_line.split()
first_word = command_words[0]
list_of_other_words = command_words[1:]
if first_word == "quit":
break
elif first_word == "newbox":
newbox(boxes, list_of_other_words)
elif first_word == "add":
add_to_box(boxes, list_of_other_words)
elif first_word == "list":
list_box_content(boxes, list_of_other_words)
if __name__ == "__main__":
main()
Based on the way this class is being used in the code that you're not supposed to change, I don't think you've understood what the MovingBox is supposed to contain/model. Here are examples of how MovingBox is being used:
MovingBox(box_name)
# creates a box named box_name
all_boxes[box_name].add_item(item_name, item_count)
# increments the count of item_name by item_count
all_boxes[box_name].list_content()
# lists the content of the box
The immediate error you're hitting is that list_content isn't supposed to take a parameter, but the larger problem is that what you've tried to implement doesn't match up at all with what the rest of the code is trying to do -- e.g. your implementation of add_item seems to be trying to add a unique item with an arbitrary value (that defaults to [], which has its own problems), when the calling code is actually providing a count of a type of item.
Since MovingBox is seemingly supposed to just be a counter with a custom interface, I'd implement it as a wrapper around collections.Counter:
from collections import Counter
class MovingBox():
"""A class for keeping track of the contents of a moving box. """
def __init__(self, name: str):
self.name = name
self.contents = Counter()
def add_item(self, name: str, count: int) -> None:
self.contents[name] += count
def list_content(self) -> None:
total = sum(self.contents.values())
print(f'Box "{self.name}" contains {total} items.')
for name, count in self.contents.items():
print(f'{count} {name}')
>>> box = MovingBox("a box")
>>> box.add_item("pillow", 3)
>>> box.list_content()
Box "a box" contains 3 items.
3 pillow

How to remove an item from the list widget using a button on kivymd

I'm having a problem on how can I remove an item from the list widget using a button and possibly how can I clear the widget after checking all the item.
py.file
class MenuScreen(Screen):
def add_item(self):
global lst
i = 0
if self.ids.inp.text == "":
close_button = MDFlatButton(text="Okay", on_release=self.close_dialog)
self.dialog = MDDialog(title="Invalid", text="No item added",
size_hint=(0.7, 1), buttons=[close_button])
self.dialog.open()
else:
list_items.append(self.ids.inp.text)
self.ids.inp.text = ''
for x in range(len(list_items)):
lst = OneLineAvatarIconListItem(text=list_items[i])
i += 1
self.ids.list.add_widget(lst)
def close_dialog(self, obj):
self.dialog.dismiss()
def remove_item(self):
pass
Example image:
For removing the item that is selected you can use self.ids.list.children to access all the items in your list and simply use remove_widget() to remove that item.And to clear your list after all the items are selected,you can use clear_widgets().

urwid auto completion edit widget or pop_up without focus

I am writing an application in python with urwid.
I need an Edit widget with autocompletion. Haven't seen one in the documentation so I have tried implementing it on my own based on the pop_up example.
However, I am faced with the fact that the pop_up widget has the focus which is a problem because:
The cursor in the edit widget is not visible. When using the left and right arrow keys without counting how often you have pressed them you do not know where the next character will be inserted.
All user input goes to the pop_up widget and not to the PopUpLauncher, although most of the key events are meant for the edit widget. I cannot call Edit.keypress because I don't know the size of the edit widget. Therefore I need to duplicate code from urwid.
How can I set the PopUpLauncher to have the focus?
From there on this answer might be helpful.
A strongly simplified version of my custom widget class:
#!/usr/bin/env python
import urwid
class AutoCompleteEdit(urwid.PopUpLauncher):
CMD_INSERT_SELECTED = "complete"
command_map = urwid.CommandMap()
command_map['tab'] = CMD_INSERT_SELECTED
def __init__(self, get_completions):
self.edit_widget = urwid.Edit()
self.__super.__init__(self.edit_widget)
self.get_completions = get_completions
# ------- user input ------
def keypress(self, size, key):
cmd = self.command_map[key]
if cmd is None:
out = self.__super.keypress(size, key)
self.update_completions()
return out
return self.__super.keypress(size, key)
def forwarded_keypress(self, key):
if self.edit_widget.valid_char(key):
#if (isinstance(key, text_type) and not isinstance(self._caption, text_type)):
# # screen is sending us unicode input, must be using utf-8
# # encoding because that's all we support, so convert it
# # to bytes to match our caption's type
# key = key.encode('utf-8')
self.edit_widget.insert_text(key)
self.update_completions()
return
cmd = self.command_map[key]
if cmd == self.CMD_INSERT_SELECTED:
self.insert_selected()
return
elif cmd == urwid.CURSOR_LEFT:
p = self.edit_widget.edit_pos
if p == 0:
return key
p = urwid.move_prev_char(self.edit_widget.edit_text, 0, p)
self.edit_widget.set_edit_pos(p)
elif cmd == urwid.CURSOR_RIGHT:
p = self.edit_widget.edit_pos
if p >= len(self.edit_widget.edit_text):
return key
p = urwid.move_next_char(self.edit_widget.edit_text, p, len(self.edit_widget.edit_text))
self.edit_widget.set_edit_pos(p)
elif key == "backspace":
self.edit_widget.pref_col_maxcol = None, None
if not self.edit_widget._delete_highlighted():
p = self.edit_widget.edit_pos
if p == 0:
return key
p = urwid.move_prev_char(self.edit_widget.edit_text,0,p)
self.edit_widget.set_edit_text(self.edit_widget.edit_text[:p] + self.edit_widget.edit_text[self.edit_widget.edit_pos:])
self.edit_widget.set_edit_pos(p)
elif key == "delete":
self.edit_widget.pref_col_maxcol = None, None
if not self.edit_widget._delete_highlighted():
p = self.edit_widget.edit_pos
if p >= len(self.edit_widget.edit_text):
return key
p = urwid.move_next_char(self.edit_widget.edit_text,p,len(self.edit_widget.edit_text))
self.edit_widget.set_edit_text(self.edit_widget.edit_text[:self.edit_widget.edit_pos] + self.edit_widget.edit_text[p:])
else:
return key
self.update_completions()
return key
def update_completions(self):
i = self.edit_widget.edit_pos
text = self.edit_widget.edit_text[:i]
prefix, completions = self.get_completions(text)
self.prefix = prefix
self.completions = completions
if not self.completions:
if self.is_open():
self.close_pop_up()
return
if not self.is_open():
self.open_pop_up()
self._pop_up_widget.update_completions(completions)
def insert_selected(self):
text = self._pop_up_widget.get_selected()
i = self.edit_widget.edit_pos - len(self.prefix)
assert i >= 0
text = text[i:]
self.edit_widget.insert_text(text)
self.close_pop_up()
# ------- internal ------
def is_open(self):
return self._pop_up_widget
# ------- implementation of abstract methods ------
def create_pop_up(self):
return PopUpList(self.forwarded_keypress)
def get_pop_up_parameters(self):
height = len(self.completions)
width = max(len(x) for x in self.completions)
return {'left':len(self.prefix), 'top':1, 'overlay_width':width, 'overlay_height':height}
class PopUpList(urwid.WidgetWrap):
ATTR = 'popup-button'
ATTR_FOCUS = 'popup-button-focus'
def __init__(self, keypress_callback):
self.body = urwid.SimpleListWalker([urwid.Text("")])
widget = urwid.ListBox(self.body)
widget = urwid.AttrMap(widget, self.ATTR)
self.__super.__init__(widget)
self.keypress_callback = keypress_callback
def update_completions(self, completions):
self.body.clear()
for x in completions:
widget = ListEntry(x)
widget = urwid.AttrMap(widget, self.ATTR, self.ATTR_FOCUS)
self.body.append(widget)
def get_selected(self):
focus_widget, focus_pos = self.body.get_focus()
return self.body[focus_pos].original_widget.text
def keypress(self, size, key):
key = self.keypress_callback(key)
if key:
return super().keypress(size, key)
class ListEntry(urwid.Text):
#https://stackoverflow.com/a/56759094
_selectable = True
signals = ["click"]
def keypress(self, size, key):
"""
Send 'click' signal on 'activate' command.
"""
if self._command_map[key] != urwid.ACTIVATE:
return key
self._emit('click')
def mouse_event(self, size, event, button, x, y, focus):
"""
Send 'click' signal on button 1 press.
"""
if button != 1 or not urwid.util.is_mouse_press(event):
return False
self._emit('click')
return True
if __name__ == '__main__':
palette = [
('popup-button', 'white', 'dark blue'),
('popup-button-focus', 'white,standout', 'dark blue'),
('error', 'dark red', 'default'),
]
completions = ["hello", "hi", "world", "earth", "universe"]
def get_completions(start):
i = start.rfind(" ")
if i == -1:
prefix = ""
else:
i += 1
prefix = start[:i]
start = start[i:]
return prefix, [word for word in completions if word.startswith(start)]
widget = AutoCompleteEdit(get_completions)
widget = urwid.Filler(widget)
#WARNING: note the pop_ups=True
urwid.MainLoop(widget, palette, pop_ups=True).run()
I have found a solution for the first part of the problem at least (visibility of the cursor): overriding the render method in the AutoCompleteEdit class:
def render(self, size, focus=False):
if self.is_open():
focus = True
return self.__super.render(size, focus)
The second problem, code duplication, still remains.
Actually it's more than just code duplication because some functionality (moving the cursor to the very beginning or the very end) is using the size argument of the keypress method. I don't know the size so I can't just copy it out of there.
So if someone knows a better way I would be grateful.

Python recursive object refrence in Tree datastructure

I am somehow new to python. I needed to use tree to store some data (file paths), The problem is when I generate the tree it seems that all objects after the root reference the same object, although step by step debugging showed the opposite. Here is my (minimized) code:
first the node class:
class PathElement:
Element = ""
IsStatic = True
Children = []
ChildrenCount = 0
def __init__(self, Element, IsStatic=True):
self.Element = Element
self.IsStatic = IsStatic
if not IsStatic:
self.Element = []
def AddChild(self, Child):
print(self, " ", Child)
self.Children.append(Child)
self.ChildrenCount = len(self.Children)
return Child
The Children is list of PathElement nodes. The code that build the tree:
def UnFoldAndCheck(self):
Path = PathElement("root")
Handler = Path
Index = 0
Count = len(self.Path)
while Index < Count:
element = self.Path[Index]
if something:
Child = None
Child = PathElement(element)
Handler.AddChild(Child)
Handler = None #Those added to debug the problem
Handler = Child
elif other_thing:
if condition:
if some_large_condition:
ChildExec = None
ChildExec = PathElement(element, False)
for i in range(0, 5):
ChildExec.Element.append(self.Path[Index + i])
Handler.AddChild(ChildExec)
Handler = None
Handler = ChildExec
Index += 4
elif another_condition:
ChildOp = None
ChildOp = PathElement(element, False)
Handler.AddChild(ChildOp)
Handler = None
Handler = ChildOp
elif some_else_condition:
if condition:
ChildExec = None
ChildExec = PathElement(element, False)
for i in range(0, 3):
ChildExec.Element.append(self.Path[Index + i])
Handler.AddChild(ChildExec)
Handler = None
Handler = ChildExec
Index += 2
elif different_condition:
ChildExec = None
ChildExec = PathElement(element, False)
for i in range(0, 3):
ChildExec.Element.append(self.Path[Index + i])
Handler.AddChild(ChildExec)
Handler = None
Handler = ChildExec
Index += 1
Index += 1
return Path
My problem is that after the tree is built when I use it it will have always same structure:
root -> object with 3 exact nodes -> same object -> same object to infinity
while the expected is:
root -> object -> first children -> second children -> third children -> etc
I'm sure the problem is related to how python handle object references but I can't see where the problem exactly. Any help?
Update:
I reproduced the problem with smaller code (same class PathElement):
from PathElement import PathElement
Path = PathElement("root")
Handler = Path
for i in range(1,6):
Child = PathElement("child"+str(i))
Handler.AddChild(Child)
Handler = Child
Tree = Path
while True:
print(Tree.Element)
if len(Tree.Children) > 0:
Tree = Tree.Children[0]
else:
break
This code will make infinite loop
I guess you come from Java or a similar language. It's important to stick with Python's conventions (Jakob Sachs gave you va link to the Style Guide for Python Code) because that makes your mistakes are easier to identify.
Now, what's wrong here? When you wrote:
class PathElement():
Children = []
Element = ""
IsStatic = True
ChildrenCount = 0
You don't give the initial value of instance fields. You create an initialize class (static) fields. Hence, Children is a static field of the class PathElement. Here's a illustration of that:
class A():
i = []
a = A()
b = A()
a.i.append(1)
b.i.append(2)
assert a.i == b.i == [1,2]
What happens when you try to make read the leftmost part of the tree (child 0, child 0 of child 0, ...)?
while True:
print(Tree.Element)
if len(Tree.Children) > 0:
Tree = Tree.Children[0]
else:
break
Just replace Tree.Children by what it is really: PathElement.Children, that is the static field Children of the class PathElement:
while True:
print(Tree.Element)
if len(PathElement.Children) > 0:
Tree = PathElement.Children[0] # Tree has always the same value.
else:
break
Now, a example of what you can write:
class PathElement:
def __init__(self, element):
self.__element = element
self.__children = []
def add_child(self, child):
self.__children.append(child)
def children(self):
return list(self.__children)
def element(self):
return self.__element
path = ["a", "b", "c", "d", "e", "f"]
root = PathElement("root")
handler = root
while path:
child = PathElement(path.pop(0)) # you can put some conditions here, take more elements of path, ...
handler.add_child(child)
handler = child
def dfs(node):
for c in node.children():
yield c.element()
yield from dfs(c)
print (list(dfs(root)))
# a b c d e f

Creating a tree/deeply nested dict from an indented text file in python

Basically, I want to iterate through a file and put the contents of each line into a deeply nested dict, the structure of which is defined by the amount of whitespace at the start of each line.
Essentially the aim is to take something like this:
a
b
c
d
e
And turn it into something like this:
{"a":{"b":"c","d":"e"}}
Or this:
apple
colours
red
yellow
green
type
granny smith
price
0.10
into this:
{"apple":{"colours":["red","yellow","green"],"type":"granny smith","price":0.10}
So that I can send it to Python's JSON module and make some JSON.
At the moment I'm trying to make a dict and a list in steps like such:
{"a":""} ["a"]
{"a":"b"} ["a"]
{"a":{"b":"c"}} ["a","b"]
{"a":{"b":{"c":"d"}}}} ["a","b","c"]
{"a":{"b":{"c":"d"},"e":""}} ["a","e"]
{"a":{"b":{"c":"d"},"e":"f"}} ["a","e"]
{"a":{"b":{"c":"d"},"e":{"f":"g"}}} ["a","e","f"]
etc.
The list acts like 'breadcrumbs' showing where I last put in a dict.
To do this I need a way to iterate through the list and generate something like dict["a"]["e"]["f"] to get at that last dict. I've had a look at the AutoVivification class that someone has made which looks very useful however I'm really unsure of:
Whether I'm using the right data structure for this (I'm planning to send it to the JSON library to create a JSON object)
How to use AutoVivification in this instance
Whether there's a better way in general to approach this problem.
I came up with the following function but it doesn't work:
def get_nested(dict,array,i):
if i != None:
i += 1
if array[i] in dict:
return get_nested(dict[array[i]],array)
else:
return dict
else:
i = 0
return get_nested(dict[array[i]],array)
Would appreciate help!
(The rest of my extremely incomplete code is here:)
#Import relevant libraries
import codecs
import sys
#Functions
def stripped(str):
if tab_spaced:
return str.lstrip('\t').rstrip('\n\r')
else:
return str.lstrip().rstrip('\n\r')
def current_ws():
if whitespacing == 0 or not tab_spaced:
return len(line) - len(line.lstrip())
if tab_spaced:
return len(line) - len(line.lstrip('\t\n\r'))
def get_nested(adict,anarray,i):
if i != None:
i += 1
if anarray[i] in adict:
return get_nested(adict[anarray[i]],anarray)
else:
return adict
else:
i = 0
return get_nested(adict[anarray[i]],anarray)
#initialise variables
jsondict = {}
unclosed_tags = []
debug = []
vividfilename = 'simple.vivid'
# vividfilename = sys.argv[1]
if len(sys.argv)>2:
jsfilename = sys.argv[2]
else:
jsfilename = vividfilename.split('.')[0] + '.json'
whitespacing = 0
whitespace_array = [0,0]
tab_spaced = False
#open the file
with codecs.open(vividfilename,'rU', "utf-8-sig") as vividfile:
for line in vividfile:
#work out how many whitespaces at start
whitespace_array.append(current_ws())
#For first line with whitespace, work out the whitespacing (eg tab vs 4-space)
if whitespacing == 0 and whitespace_array[-1] > 0:
whitespacing = whitespace_array[-1]
if line[0] == '\t':
tab_spaced = True
#strip out whitespace at start and end
stripped_line = stripped(line)
if whitespace_array[-1] == 0:
jsondict[stripped_line] = ""
unclosed_tags.append(stripped_line)
if whitespace_array[-2] < whitespace_array[-1]:
oldnested = get_nested(jsondict,whitespace_array,None)
print oldnested
# jsondict.pop(unclosed_tags[-1])
# jsondict[unclosed_tags[-1]]={stripped_line:""}
# unclosed_tags.append(stripped_line)
print jsondict
print unclosed_tags
print jsondict
print unclosed_tags
Here is an object oriented approach based on a composite structure of nested Node objects.
Input:
indented_text = \
"""
apple
colours
red
yellow
green
type
granny smith
price
0.10
"""
a Node class
class Node:
def __init__(self, indented_line):
self.children = []
self.level = len(indented_line) - len(indented_line.lstrip())
self.text = indented_line.strip()
def add_children(self, nodes):
childlevel = nodes[0].level
while nodes:
node = nodes.pop(0)
if node.level == childlevel: # add node as a child
self.children.append(node)
elif node.level > childlevel: # add nodes as grandchildren of the last child
nodes.insert(0,node)
self.children[-1].add_children(nodes)
elif node.level <= self.level: # this node is a sibling, no more children
nodes.insert(0,node)
return
def as_dict(self):
if len(self.children) > 1:
return {self.text: [node.as_dict() for node in self.children]}
elif len(self.children) == 1:
return {self.text: self.children[0].as_dict()}
else:
return self.text
To parse the text, first create a root node.
Then, remove empty lines from the text, and create a Node instance for every line, pass this to the add_children method of the root node.
root = Node('root')
root.add_children([Node(line) for line in indented_text.splitlines() if line.strip()])
d = root.as_dict()['root']
print(d)
result:
{'apple': [
{'colours': ['red', 'yellow', 'green']},
{'type': 'granny smith'},
{'price': '0.10'}]
}
I think that it should be possible to do it in one step, where you simply call the constructor of Node once, with the indented text as an argument.
Here is a recursive solution. First, transform the input in the following way.
Input:
person:
address:
street1: 123 Bar St
street2:
city: Madison
state: WI
zip: 55555
web:
email: boo#baz.com
First-step output:
[{'name':'person','value':'','level':0},
{'name':'address','value':'','level':1},
{'name':'street1','value':'123 Bar St','level':2},
{'name':'street2','value':'','level':2},
{'name':'city','value':'Madison','level':2},
{'name':'state','value':'WI','level':2},
{'name':'zip','value':55555,'level':2},
{'name':'web','value':'','level':1},
{'name':'email','value':'boo#baz.com','level':2}]
This is easy to accomplish with split(':') and by counting the number of leading tabs:
def tab_level(astr):
"""Count number of leading tabs in a string
"""
return len(astr)- len(astr.lstrip('\t'))
Then feed the first-step output into the following function:
def ttree_to_json(ttree,level=0):
result = {}
for i in range(0,len(ttree)):
cn = ttree[i]
try:
nn = ttree[i+1]
except:
nn = {'level':-1}
# Edge cases
if cn['level']>level:
continue
if cn['level']<level:
return result
# Recursion
if nn['level']==level:
dict_insert_or_append(result,cn['name'],cn['value'])
elif nn['level']>level:
rr = ttree_to_json(ttree[i+1:], level=nn['level'])
dict_insert_or_append(result,cn['name'],rr)
else:
dict_insert_or_append(result,cn['name'],cn['value'])
return result
return result
where:
def dict_insert_or_append(adict,key,val):
"""Insert a value in dict at key if one does not exist
Otherwise, convert value to list and append
"""
if key in adict:
if type(adict[key]) != list:
adict[key] = [adict[key]]
adict[key].append(val)
else:
adict[key] = val
The following code will take a block-indented file and convert into an XML tree; this:
foo
bar
baz
ban
bal
...becomes:
<cmd>foo</cmd>
<cmd>bar</cmd>
<block>
<name>baz</name>
<cmd>ban</cmd>
<cmd>bal</cmd>
</block>
The basic technique is:
Set indent to 0
For each line, get the indent
If > current, step down and save current block/ident on a stack
If == current, append to current block
If < current, pop from the stack until you get to the matching indent
So:
from lxml import builder
C = builder.ElementMaker()
def indent(line):
strip = line.lstrip()
return len(line) - len(strip), strip
def parse_blockcfg(data):
top = current_block = C.config()
stack = []
current_indent = 0
lines = data.split('\n')
while lines:
line = lines.pop(0)
i, line = indent(line)
if i==current_indent:
pass
elif i > current_indent:
# we've gone down a level, convert the <cmd> to a block
# and then save the current ident and block to the stack
prev.tag = 'block'
prev.append(C.name(prev.text))
prev.text = None
stack.insert(0, (current_indent, current_block))
current_indent = i
current_block = prev
elif i < current_indent:
# we've gone up one or more levels, pop the stack
# until we find out which level and return to it
found = False
while stack:
parent_indent, parent_block = stack.pop(0)
if parent_indent==i:
found = True
break
if not found:
raise Exception('indent not found in parent stack')
current_indent = i
current_block = parent_block
prev = C.cmd(line)
current_block.append(prev)
return top
First of all, don't use array and dict as variable names because they're reserved words in Python and reusing them may end up in all sorts of chaos.
OK so if I get you correctly, you have a tree given in a text file, with parenthood indicated by indentations, and you want to recover the actual tree structure. Right?
Does the following look like a valid outline? Because I have trouble putting your current code into context.
result = {}
last_indentation = 0
for l in f.xreadlines():
(c, i) = parse(l) # create parse to return character and indentation
if i==last_indentation:
# sibling to last
elif i>last_indentation:
# child to last
else:
# end of children, back to a higher level
OK then your list are the current parents, that's in fact right - but I'd keep them pointed to the dictionary you've created, not the literal letter
just starting some stuff here
result = {}
parents = {}
last_indentation = 1 # start with 1 so 0 is the root of tree
parents[0] = result
for l in f.xreadlines():
(c, i) = parse(l) # create parse to return character and indentation
if i==last_indentation:
new_el = {}
parents[i-1][c] = new_el
parents[i] = new_el
elif i>last_indentation:
# child to last
else:
# end of children, back to a higher level

Categories

Resources