-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathitem.py
177 lines (145 loc) · 6.4 KB
/
item.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
""" Anything is an Item. Files, folder, tags, urls, pieces of text. """
class ItemError(Exception):
""" Custom error class for Item. For example when adding an item as an descendend of itself. """
class Item(object):
""" Class to represent a taggable item.
The type can be for example TAG, DIR, URL, TXT, CMD.
The name is the name is the value of this itemm
i.e. the tag name, or the url, or the text.
"""
# _instance_count = 0
# def _make_unique_id():
# Item._instance_count += 1
# return Item._instance_count
def __init__(self, uid, typ, url):
self.uid = uid
self.typ = typ
self.url = url
self.parents = None
self.children = None
def __str__(self):
return (self.typ + ': ' + self.url)
def __repr__(self):
return "Item('%(typ)s', '%(url)s')" % ({'typ': self.typ, 'url': self.url})
def __eq__(self, other):
return self.url == other.url
def _add_parent(self, parent):
if self.parents is None:
self.parents = dict()
self.parents.setdefault(parent.uid, parent)
def add_child(self, child):
""" Create the parent child association between this and the given item."""
# Ensure that a child can never occur as its own ancenstor.
for d, level in self.ancestors():
if child == d:
raise ItemError('Given item %s is already a descendent.' % child.url)
if self.children is None:
self.children = dict()
self.children.setdefault(child.uid, child)
child._add_parent(self)
def parent_items(self):
return self.parents if self.parents is None else self.parents.values()
def child_items(self):
return self.children if self.children is None else self.children.values()
def _traverse(self, next_items, func, *func_args):
""" Traverse all the children, or all the parents, depending on the next_items() function.
next_items(item) returns a list of items or None if there are no more."""
items = [(self,0)]
while len(items) > 0:
current, level = items.pop()
func(current, level, *func_args)
next_item_list = next_items(current)
if next_item_list is not None:
level += 1
items.extend([(x,level) for x in next_item_list]) # Extend the list.
# Do something on the way up
def traverse_parents(self, func, *func_args):
self._traverse(Item.parent_items, func, *func_args)
def traverse_children(self, func, *func_args):
self._traverse(Item.child_items, func, *func_args)
def _recurse(self, next_items, func, *func_args):
""" applies func to the given item and to each of those returned by next_items(item).
func takes at least two parameters: item and level.
func_args is a list of additional arguments passed to func. """
level = 0
def recurse(item, level, func, *func_args):
func(item, level, *func_args)
next_item_list = next_items(item)
if next_item_list is not None:
level += 1
for next_item in next_item_list:
recurse(next_item, level, func, *func_args)
# Do something on the way up
recurse(self, level, func, *func_args)
def recurse_parents(self, func, *func_args):
self._recurse(Item.parent_items, func, *func_args)
def recurse_children(self, func, *func_args):
self._recurse(Item.child_items, func, *func_args)
def descendents(self, width_first=True):
""" A generater that returns tuples (item, level) for all descendents of the given item.
The first pair returned is (item,0).
"""
popdex = 0 if width_first else -1
items = [(self,0)]
while len(items) > 0:
current, level = items.pop(popdex)
yield (current, level)
if current.children is not None:
level += 1
items.extend([(child, level) for child in current.children.values()])
def ancestors(self, width_first=True):
""" A generater that returns tuples (item, level) for all ancestors of the given item.
The first pair returned is (item,0).
"""
popdex = 0 if width_first else -1
items = [(self,0)]
while len(items) > 0:
current, level = items.pop(popdex)
yield (current, level)
if current.parents is not None:
level -= 1
items.extend([(child, level) for child in current.parents.values()])
def show_item(item, level, indent):
temp = level * indent
print(temp, str(item), sep='')
def just_print(item, level):
print(item)
def recurse_children(item, func, *func_args):
""" applies func to the given item and to each of its children.
func takes at least two parameters: item and level.
func_args is a list of additional arguments passed to func. """
level = 0
def recurse(item, level, func, *func_args):
func(item, level, *func_args)
if item.children is not None:
level += 1
for child in item.children.values():
recurse(child, level, func, *func_args)
# Do something on the way up
recurse(item, level, func, *func_args)
def traverse_down2(item, func, *func_args):
""" Same as recurse_children, but non-recurseive implementation. Width-first"""
items = [(item,0)]
while len(items) > 0:
current, level = items.pop()
func(current, level, *func_args)
if current.children is not None:
level += 1
items[0:0] = [(child, level) for child in current.children.values()] # Extend at the beginning of the list.
def main():
me = Item(1, 'tag','me')
dad = Item(2, 'tag', 'dad')
mom = Item(3, 'tag', 'mom')
steven = Item(4, 'tag', 'steven')
la = Item(5, 'tag', 'la')
dad.add_child(me)
mom.add_child(me)
dad.add_child(steven)
mom.add_child(steven)
me.add_child(la)
recurse_children(dad, show_item, ' ')
print()
for item, level in descendents(dad, False):
show_item(item, level, ',,,,')
if __name__ == '__main__':
main()