3131
3232__all__ = ['Message' , 'thread' ]
3333
34+ __version__ = "0.96"
3435
3536#
3637# constants
@@ -61,46 +62,54 @@ def __init__(self, **args):
6162 def __repr__ (self ):
6263 return '<%s %x: %r>' % (self .__class__ .__name__ , id (self ),
6364 dict .__repr__ (self ))
65+
6466 def __hash__ (self ):
6567 """ Make the container hashable. Care must be taken though not to change
66- the container contents after the initialization as otherwise the hash
68+ the container contents after the initialization as otherwise the hash
6769 value will change
68- """
70+ """
6971 return hash (tuple (sorted (self .items ())) + (self .parent ,))
7072
71-
73+ @ property
7274 def is_dummy (self ):
73- """Check if Container has some contents ."""
75+ """Check if the container has some content ."""
7476 return not len (self .keys ())
7577
7678 def add_child (self , child ):
77- """Add a child to `self`.
79+ """Add a child to the container
7880
79- Arguments:
80- child (Container): Child to add.
81+ Parameters
82+ ----------
83+ child : Container
84+ Child to add.
8185 """
8286 if child .parent :
8387 child .parent .remove_child (child )
8488 self .children .append (child )
8589 child .parent = self
8690
8791 def remove_child (self , child ):
88- """Remove a child from `self`.
92+ """Remove a child from the container
8993
90- Arguments:
91- child (Container): Child to remove.
94+ Parameters
95+ ----------
96+ child : Container
97+ Child to remove.
9298 """
9399 self .children .remove (child )
94100 child .parent = None
95101
96102 def has_descendant (self , ctr ):
97- """Check if `ctr` is a descendant of this.
103+ """Check if `ctr` is a descendant of this container .
98104
99- Arguments:
100- ctr (Container): possible descendant container.
105+ Parameters
106+ ----------
107+ ctr : Container
108+ possible descendant container.
101109
102- Returns:
103- True if `ctr` is a descendant of `self`, else False.
110+ Returns
111+ -------
112+ True if `ctr` is a descendant of `self`, else False.
104113 """
105114 # To avoid recursing indefinitely, we'll do a depth-first
106115 # search; 'seen' tracks the containers we've already seen,
@@ -122,26 +131,29 @@ def has_descendant(self, ctr):
122131 return False
123132
124133 @property
125- def size (self ):
126- """Count the number of objects included in the container,
127- including itself"""
134+ def tree_size (self ):
135+ """Recursively count the number of children containers.
136+ The current container is also included in the count.
137+ """
128138
129- return 1 + sum ([child .size for child in self .children ])
139+ return 1 + sum ([child .tree_size for child in self .children ])
130140
131141 @property
132- def depth (self ):
133- """Compute the current container depth """
142+ def current_depth (self ):
143+ """Compute the depth in the hierarchy of the current container"""
134144
135145 if self .parent is None :
136146 return 0
137147 else :
138- return 1 + self .parent .depth
148+ return 1 + self .parent .current_depth
139149
140150 def flatten (self ):
141- """ Return a flatten version of the tree
151+ """ Return a flatten version of the hierarchical tree
142152
143153 Returns
144- list [Containers]: a list of messages
154+ -------
155+ list : Containers
156+ a flat list of containers
145157 """
146158 from itertools import chain
147159
@@ -151,18 +163,20 @@ def flatten(self):
151163
152164 @property
153165 def root (self ):
154- """
155- Get the root container
166+ """ Get the root container
156167
157168 Returns
158- Container: the top most level container
169+ -------
170+ Containe: the top most level container
159171 """
160172
161173 if self .parent is None :
162174 return self
163175 else :
164176 return self .parent .root
165177
178+
179+ class JwzContainer (Container ):
166180 def collapse_empty (self , inplace = True ):
167181 """ Collapse empty top level containers.
168182
@@ -173,7 +187,7 @@ def collapse_empty(self, inplace=True):
173187 container to be used as the root node.
174188
175189 This method removes this empty container and makes the first child
176- to be the root message. The other messages at depth == 1 then become
190+ to be the root message. The other messages at depth == 1 then become
177191 it's children.
178192
179193 Parameters
@@ -186,9 +200,9 @@ def collapse_empty(self, inplace=True):
186200 if not inplace :
187201 raise NotImplementedError
188202
189- if not 'message' in self :
190- raise ValueError (' This method is only valid when used for email threading' )
191-
203+ if 'message' not in self :
204+ raise ValueError (" This method is only valid when used for "
205+ "email threading" )
192206
193207 if self ['message' ] is not None :
194208 # nothing to be done
@@ -212,29 +226,30 @@ def collapse_empty(self, inplace=True):
212226
213227 return new_root
214228
215-
216229 def to_dict (self , include = []):
217230 """ Convert a Container tree to a nested dict
218231 """
219232 if 'message' not in self :
220- raise ValueError ('This method is currently valid with email threading, '
221- 'please overwrite it for other applications' )
233+ raise ValueError ('This method is currently valid with email'
234+ 'threading, please overwrite it for '
235+ 'other applications' )
222236
223237 if self ['message' ] is None :
224- raise ValueError ('Containers with None messages are not supported:! \n ' \
225- ' this: {}' .format (self ))
238+ raise ValueError ('Containers with None messages are not '
239+ 'supported:! \n this: {}' .format (self ))
226240
227- res = {'id' : self ['message' ].message_idx }
241+ res = {'id' : self ['message' ].message_idx }
228242
229243 for key in include :
230- res [key ] = getattr (self ['message' ], key )
244+ res [key ] = getattr (self ['message' ], key )
231245
232246 if self .parent is not None :
233247 if self .parent ['message' ] is not None :
234248 res ['parent' ] = self .parent ['message' ].message_idx
235249 else :
236- raise ValueError ('Containers with None messages are not supported:!\n ' \
237- ' this: {}\n parent: {}' .format (self , self .parent ))
250+ raise ValueError ('Containers with None messages are not '
251+ 'supported:!\n this: {}\n parent: {}'
252+ .format (self , self .parent ))
238253 else :
239254 res ['parent' ] = None
240255
@@ -243,8 +258,6 @@ def to_dict(self, include=[]):
243258 return res
244259
245260
246-
247-
248261class Message (object ):
249262 """Represents a message to be threaded.
250263
@@ -415,7 +428,7 @@ def thread(messages, group_by_subject=True):
415428 if this_container is not None :
416429 this_container ['message' ] = msg
417430 else :
418- this_container = Container (message = None )
431+ this_container = JwzContainer (message = None )
419432 this_container ['message' ] = msg
420433 id_table [msg .message_id ] = this_container
421434
@@ -425,7 +438,7 @@ def thread(messages, group_by_subject=True):
425438 ## print "Processing reference for "+repr(msg.message_id)+": "+repr(ref)
426439 container = id_table .get (ref , None )
427440 if container is None :
428- container = Container (message = None )
441+ container = JwzContainer (message = None )
429442 id_table [ref ] = container
430443
431444 if prev is not None :
@@ -513,11 +526,11 @@ def thread(messages, group_by_subject=True):
513526 if ctr is None or ctr is container :
514527 continue
515528
516- if ctr .is_dummy () and container .is_dummy () :
529+ if ctr .is_dummy and container .is_dummy :
517530 for child in ctr .children :
518531 container .add_child (child )
519- elif ctr .is_dummy () or container .is_dummy () :
520- if ctr .is_dummy () :
532+ elif ctr .is_dummy or container .is_dummy :
533+ if ctr .is_dummy :
521534 ctr .add_child (container )
522535 else :
523536 container .add_child (ctr )
@@ -528,7 +541,7 @@ def thread(messages, group_by_subject=True):
528541 # container has fewer levels of 're:' headers
529542 container .add_child (ctr )
530543 else :
531- new = Container (message = None )
544+ new = JwzContainer (message = None )
532545 new .add_child (ctr )
533546 new .add_child (container )
534547 subject_table [subj ] = new
0 commit comments