aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libbe/bug.py168
-rw-r--r--libbe/bugdir.py84
-rw-r--r--libbe/comment.py187
-rw-r--r--libbe/util/id.py28
4 files changed, 171 insertions, 296 deletions
diff --git a/libbe/bug.py b/libbe/bug.py
index 5755b63..1f96779 100644
--- a/libbe/bug.py
+++ b/libbe/bug.py
@@ -237,35 +237,25 @@ class Bug(settings_object.SavedSettingsObject):
@doc_property(doc="The trunk of the comment tree. We use a dummy root comment by default, because there can be several comment threads rooted on the same parent bug. To simplify comment interaction, we condense these threads into a single thread with a Comment dummy root.")
def comment_root(): return {}
- def _get_storage(self):
- if hasattr(self.bugdir, "storage"):
- return self.bugdir.storage
-
- @Property
- @cached_property(generator=_get_storage)
- @local_property("storage")
- @doc_property(doc="A revision control system instance.")
- def storage(): return {}
-
def __init__(self, bugdir=None, uuid=None, from_storage=False,
load_comments=False, summary=None):
settings_object.SavedSettingsObject.__init__(self)
self.bugdir = bugdir
+ self.storage = None
self.uuid = uuid
+ self.id = libbe.util.id.ID(self, 'bug')
if from_storage == False:
if uuid == None:
self.uuid = libbe.util.id.uuid_gen()
self.settings = {}
self._setup_saved_settings()
- if self.storage != None and self.storage.is_writeable():
- self.storage.writeable = False
- set_writeable = True
- else:
- set_writeable = False
self.time = int(time.time()) # only save to second precision
self.summary = summary
- if set_writeable == True:
- self.storage.writeable = True
+ dummy = self.comment_root
+ if self.bugdir != None:
+ self.storage = self.bugdir.storage
+ if from_storage == False:
+ if self.storage != None and self.storage.is_writeable():
self.save()
def __repr__(self):
@@ -287,20 +277,47 @@ class Bug(settings_object.SavedSettingsObject):
return str(value)
return value
- def xml(self, indent=0, shortname=None, show_comments=False):
- if shortname == None:
- if self.bugdir == None:
- shortname = self.uuid
+ def string(self, shortlist=False, show_comments=False):
+ if shortlist == False:
+ if self.time == None:
+ timestring = ""
else:
- shortname = self.bugdir.bug_shortname(self)
+ htime = utility.handy_time(self.time)
+ timestring = "%s (%s)" % (htime, self.time_string)
+ info = [("ID", self.uuid),
+ ("Short name", self.id.user()),
+ ("Severity", self.severity),
+ ("Status", self.status),
+ ("Assigned", self._setting_attr_string("assigned")),
+ ("Reporter", self._setting_attr_string("reporter")),
+ ("Creator", self._setting_attr_string("creator")),
+ ("Created", timestring)]
+ longest_key_len = max([len(k) for k,v in info])
+ infolines = [" %*s : %s\n" %(longest_key_len,k,v) for k,v in info]
+ bugout = "".join(infolines) + "%s" % self.summary.rstrip('\n')
+ else:
+ statuschar = self.status[0]
+ severitychar = self.severity[0]
+ chars = "%c%c" % (statuschar, severitychar)
+ bugout = "%s:%s: %s" % (self.id.user(),chars,self.summary.rstrip('\n'))
+
+ if show_comments == True:
+ # take advantage of the string_thread(auto_name_map=True)
+ # SIDE-EFFECT of sorting by comment time.
+ comout = self.comment_root.string_thread(flatten=False)
+ output = bugout + '\n' + comout.rstrip('\n')
+ else :
+ output = bugout
+ return output
+ def xml(self, indent=0, show_comments=False):
if self.time == None:
timestring = ""
else:
timestring = utility.time_to_str(self.time)
info = [('uuid', self.uuid),
- ('short-name', shortname),
+ ('short-name', self.id.user()),
('severity', self.severity),
('status', self.status),
('assigned', self.assigned),
@@ -315,9 +332,7 @@ class Bug(settings_object.SavedSettingsObject):
for estr in self.extra_strings:
lines.append(' <extra-string>%s</extra-string>' % estr)
if show_comments == True:
- comout = self.comment_root.xml_thread(indent=indent+2,
- auto_name_map=True,
- bug_shortname=shortname)
+ comout = self.comment_root.xml_thread(indent=indent+2)
if len(comout) > 0:
lines.append(comout)
lines.append('</bug>')
@@ -335,16 +350,16 @@ class Bug(settings_object.SavedSettingsObject):
>>> commA = bugA.comment_root.new_reply(body='comment A')
>>> commB = bugA.comment_root.new_reply(body='comment B')
>>> commC = commA.new_reply(body='comment C')
- >>> xml = bugA.xml(shortname="bug-1", show_comments=True)
+ >>> xml = bugA.xml(show_comments=True)
>>> bugB = Bug()
>>> bugB.from_xml(xml, verbose=True)
- >>> bugB.xml(shortname="bug-1", show_comments=True) == xml
+ >>> bugB.xml(show_comments=True) == xml
False
>>> bugB.uuid = bugB.alt_id
>>> for comm in bugB.comments():
... comm.uuid = comm.alt_id
... comm.alt_id = None
- >>> bugB.xml(shortname="bug-1", show_comments=True) == xml
+ >>> bugB.xml(show_comments=True) == xml
True
>>> bugB.explicit_attrs # doctest: +NORMALIZE_WHITESPACE
['severity', 'status', 'creator', 'created', 'summary']
@@ -414,10 +429,10 @@ class Bug(settings_object.SavedSettingsObject):
>>> commC.uuid = 'commC'
>>> commC.in_reply_to = commA.uuid
>>> bugA.add_comment(commC)
- >>> print bugA.xml(shortname="bug-1", show_comments=True) # doctest: +ELLIPSIS
+ >>> print bugA.xml(show_comments=True) # doctest: +ELLIPSIS
<bug>
<uuid>0123</uuid>
- <short-name>bug-1</short-name>
+ <short-name>/012</short-name>
<severity>minor</severity>
<status>open</status>
<creator>Jack</creator>
@@ -425,7 +440,7 @@ class Bug(settings_object.SavedSettingsObject):
<summary>Need to test Bug.add_comment()</summary>
<comment>
<uuid>commA</uuid>
- <short-name>bug-1:1</short-name>
+ <short-name>/012/commA</short-name>
<author></author>
<date>...</date>
<content-type>text/plain</content-type>
@@ -433,7 +448,7 @@ class Bug(settings_object.SavedSettingsObject):
</comment>
<comment>
<uuid>commC</uuid>
- <short-name>bug-1:2</short-name>
+ <short-name>/012/commC</short-name>
<in-reply-to>commA</in-reply-to>
<author></author>
<date>...</date>
@@ -442,7 +457,7 @@ class Bug(settings_object.SavedSettingsObject):
</comment>
<comment>
<uuid>commB</uuid>
- <short-name>bug-1:3</short-name>
+ <short-name>/012/commB</short-name>
<author></author>
<date>...</date>
<content-type>text/plain</content-type>
@@ -546,7 +561,7 @@ class Bug(settings_object.SavedSettingsObject):
>>> print bugA.xml(show_comments=True) # doctest: +ELLIPSIS
<bug>
<uuid>0123</uuid>
- <short-name>0123</short-name>
+ <short-name>/012</short-name>
<severity>minor</severity>
<status>open</status>
<creator>John</creator>
@@ -557,7 +572,7 @@ class Bug(settings_object.SavedSettingsObject):
<extra-string>TAG: very helpful</extra-string>
<comment>
<uuid>uuid-commA</uuid>
- <short-name>0123:1</short-name>
+ <short-name>/012/uuid-commA</short-name>
<author></author>
<date>...</date>
<content-type>text/plain</content-type>
@@ -565,7 +580,7 @@ class Bug(settings_object.SavedSettingsObject):
</comment>
<comment>
<uuid>uuid-commB</uuid>
- <short-name>0123:2</short-name>
+ <short-name>/012/uuid-commB</short-name>
<author></author>
<date>...</date>
<content-type>text/plain</content-type>
@@ -603,6 +618,7 @@ class Bug(settings_object.SavedSettingsObject):
if accept_comments == True:
o_comm_copy = copy.copy(o_comm)
o_comm_copy.bug = self
+ o_comm_copy.id = libbe.util.id.ID(o_comm_copy, 'comment')
self.comment_root.add_reply(o_comm_copy)
elif change_exception == True:
raise ValueError, \
@@ -613,63 +629,18 @@ class Bug(settings_object.SavedSettingsObject):
accept_extra_strings=accept_extra_strings,
change_exception=change_exception)
- def string(self, shortlist=False, show_comments=False):
- if self.bugdir == None:
- shortname = self.uuid
- else:
- shortname = self.bugdir.bug_shortname(self)
- if shortlist == False:
- if self.time == None:
- timestring = ""
- else:
- htime = utility.handy_time(self.time)
- timestring = "%s (%s)" % (htime, self.time_string)
- info = [("ID", self.uuid),
- ("Short name", shortname),
- ("Severity", self.severity),
- ("Status", self.status),
- ("Assigned", self._setting_attr_string("assigned")),
- ("Reporter", self._setting_attr_string("reporter")),
- ("Creator", self._setting_attr_string("creator")),
- ("Created", timestring)]
- longest_key_len = max([len(k) for k,v in info])
- infolines = [" %*s : %s\n" %(longest_key_len,k,v) for k,v in info]
- bugout = "".join(infolines) + "%s" % self.summary.rstrip('\n')
- else:
- statuschar = self.status[0]
- severitychar = self.severity[0]
- chars = "%c%c" % (statuschar, severitychar)
- bugout = "%s:%s: %s" % (shortname,chars,self.summary.rstrip('\n'))
-
- if show_comments == True:
- # take advantage of the string_thread(auto_name_map=True)
- # SIDE-EFFECT of sorting by comment time.
- comout = self.comment_root.string_thread(flatten=False,
- auto_name_map=True,
- bug_shortname=shortname)
- output = bugout + '\n' + comout.rstrip('\n')
- else :
- output = bugout
- return output
-
# methods for saving/loading/acessing settings and properties.
- def id(self, *args):
- assert len(args) <= 1, str(args)
- if len(args) == 1:
- assert args[0] in ["values"], str(args)
- return libbe.util.id.bug_id(self, *args)
-
def load_settings(self, settings_mapfile=None):
if settings_mapfile == None:
settings_mapfile = \
- self.storage.get(self.id("values"), default="\n")
+ self.storage.get(self.id.storage("values"), default="\n")
self.settings = mapfile.parse(settings_mapfile)
self._setup_saved_settings()
def save_settings(self):
mf = mapfile.generate(self._get_saved_settings())
- self.storage.set(self.id("values"), mf)
+ self.storage.set(self.id.storage("values"), mf)
def save(self):
"""
@@ -683,11 +654,11 @@ class Bug(settings_object.SavedSettingsObject):
"""
assert self.storage != None, "Can't save without storage"
if self.bugdir != None:
- parent = self.bugdir.id()
+ parent = self.bugdir.id.storage()
else:
parent = None
- self.storage.add(self.id(), parent=parent)
- self.storage.add(self.id('values'), parent=self.id())
+ self.storage.add(self.id.storage(), parent=parent)
+ self.storage.add(self.id.storage('values'), parent=self.id.storage())
self.save_settings()
if len(self.comment_root) > 0:
comment.save_comments(self)
@@ -707,10 +678,14 @@ class Bug(settings_object.SavedSettingsObject):
self.storage.writeable = w
def remove(self):
- self.storage.recursive_remove(self.id())
+ self.storage.recursive_remove(self.id.storage())
# methods for managing comments
+ def uuids(self):
+ for comment in self.comments():
+ yield comment.uuid
+
def comments(self):
for comment in self.comment_root.traverse():
yield comment
@@ -719,20 +694,15 @@ class Bug(settings_object.SavedSettingsObject):
comm = self.comment_root.new_reply(body=body)
return comm
- def comment_from_shortname(self, shortname, *args, **kwargs):
- return self.comment_root.comment_from_shortname(shortname,
- *args, **kwargs)
-
def comment_from_uuid(self, uuid, *args, **kwargs):
return self.comment_root.comment_from_uuid(uuid, *args, **kwargs)
- def comment_shortnames(self, shortname=None):
- """
- SIDE-EFFECT : Comment.comment_shortnames will sort the comment
- tree by comment.time
- """
- for id, comment in self.comment_root.comment_shortnames(shortname):
- yield (id, comment)
+ # methods for id generation
+
+ def sibling_uuids(self):
+ if self.bugdir != None:
+ return self.bugdir.uuids()
+ return []
# The general rule for bug sorting is that "more important" bugs are
diff --git a/libbe/bugdir.py b/libbe/bugdir.py
index 02ff96f..39eface 100644
--- a/libbe/bugdir.py
+++ b/libbe/bugdir.py
@@ -173,6 +173,7 @@ class BugDir (list, settings_object.SavedSettingsObject):
list.__init__(self)
settings_object.SavedSettingsObject.__init__(self)
self.storage = storage
+ self.id = libbe.util.id.ID(self, 'bugdir')
if from_storage == True:
self.load_settings()
else:
@@ -185,16 +186,10 @@ class BugDir (list, settings_object.SavedSettingsObject):
# methods for saving/loading/accessing settings and properties.
- def id(self, *args):
- assert len(args) <= 1, str(args)
- if len(args) == 1:
- assert args[0] in ['settings'], str(args)
- return libbe.util.id.bugdir_id(self, *args)
-
def load_settings(self, settings_mapfile=None):
if settings_mapfile == None:
settings_mapfile = \
- self.storage.get(self.id('settings'), default='\n')
+ self.storage.get(self.id.storage('settings'), default='\n')
self.settings = mapfile.parse(settings_mapfile)
self._setup_saved_settings()
self._setup_user_id(self.user_id)
@@ -204,7 +199,7 @@ class BugDir (list, settings_object.SavedSettingsObject):
def save_settings(self):
mf = mapfile.generate(self._get_saved_settings())
- self.storage.set(self.id('settings'), mf)
+ self.storage.set(self.id.storage('settings'), mf)
def load_all_bugs(self):
"""
@@ -224,9 +219,8 @@ class BugDir (list, settings_object.SavedSettingsObject):
happen, so calling this method will just waste time (unless
something else has been messing with your stored files).
"""
- self.uuid = 'BD'
- self.storage.add(self.id())
- self.storage.add(self.id('settings'), parent=self.id())
+ self.storage.add(self.id.storage())
+ self.storage.add(self.id.storage('settings'), parent=self.id.storage())
self.save_settings()
for bug in self:
bug.save()
@@ -241,10 +235,11 @@ class BugDir (list, settings_object.SavedSettingsObject):
yield bug.uuid
if self.storage != None and self.storage.is_readable():
# and the ones that are still just in storage
- for id in self.storage.children(self.id()):
- parsed = libbe.util.id.parse_id(id)
- if parsed['type'] == 'bug' and parsed['bug'] not in uuids:
- yield parsed['bug']
+ child_uuids = libbe.util.id.child_uuids(
+ self.storage.children(self.id.storage()))
+ for id in child_uuids:
+ if id not in uuids:
+ yield id
def _clear_bugs(self):
while len(self) > 0:
@@ -258,7 +253,8 @@ class BugDir (list, settings_object.SavedSettingsObject):
return bg
def new_bug(self, summary=None, _uuid=None):
- bg = bug.Bug(bugdir=self, uuid=_uuid, summary=summary)
+ bg = bug.Bug(bugdir=self, uuid=_uuid, summary=summary,
+ from_storage=False)
self.append(bg)
self._bug_map_gen()
return bg
@@ -268,45 +264,6 @@ class BugDir (list, settings_object.SavedSettingsObject):
if self.storage.is_writeable():
bug.remove()
- def bug_shortname(self, bug):
- """
- Generate short names from uuids. Picks the minimum number of
- characters (>=3) from the beginning of the uuid such that the
- short names are unique.
-
- Obviously, as the number of bugs in the database grows, these
- short names will cease to be unique. The complete uuid should be
- used for long term reference.
- """
- chars = 3
- for uuid in self._bug_map.keys():
- if bug.uuid == uuid:
- continue
- while (bug.uuid[:chars] == uuid[:chars]):
- chars+=1
- return bug.uuid[:chars]
-
- def bug_from_shortname(self, shortname):
- """
- >>> bd = SimpleBugDir(memory=True)
- >>> bug_a = bd.bug_from_shortname('a')
- >>> print type(bug_a)
- <class 'libbe.bug.Bug'>
- >>> print bug_a
- a:om: Bug A
- >>> bd.cleanup()
- """
- matches = []
- self._bug_map_gen()
- for uuid in self._bug_map.keys():
- if uuid.startswith(shortname):
- matches.append(uuid)
- if len(matches) > 1:
- raise MultipleBugMatches(shortname, matches)
- if len(matches) == 1:
- return self.bug_from_uuid(matches[0])
- raise NoBugMatches(shortname)
-
def bug_from_uuid(self, uuid):
if not self.has_bug(uuid):
raise KeyError("No bug matches %s\n bug map: %s\n root: %s" \
@@ -322,6 +279,11 @@ class BugDir (list, settings_object.SavedSettingsObject):
return False
return True
+ # methods for id generation
+
+ def sibling_uuids(self):
+ return []
+
# methods for managing duplicate BugDirs
def duplicate_bugdir(self, revision):
@@ -344,7 +306,7 @@ class BugDir (list, settings_object.SavedSettingsObject):
if parsed['type'] == 'bugdir':
assert parsed['remaining'] == ['settings'], parsed['remaining']
dbd._settings = copy.copy(self._settings)
- mf = self.storage.get(self.id('settings'), default='\n',
+ mf = self.storage.get(self.id.storage('settings'), default='\n',
revision=revision)
dbd.load_settings(mf)
else:
@@ -357,7 +319,7 @@ class BugDir (list, settings_object.SavedSettingsObject):
dbd._bug_map[parsed['bug']] = bug
if parsed['type'] == 'bug':
assert parsed['remaining'] == ['values'], parsed['remaining']
- mf = self.storage.get(self.id('values'), default='\n',
+ mf = self.storage.get(self.id.storage('values'), default='\n',
revision=revision)
bug.load_settings(mf)
elif parsed['type'] == 'comment':
@@ -366,11 +328,11 @@ class BugDir (list, settings_object.SavedSettingsObject):
bug.comment_root = copy.deepcopy(bug.comment_root)
comment = bug.comment_from_uuid(parsed['comment'])
if parsed['remaining'] == ['values']:
- mf = self.storage.get(self.id('values'), default='\n',
+ mf = self.storage.get(self.id.storage('values'), default='\n',
revision=revision)
comment.load_settings(mf)
else:
- body = self.storage.get(self.id('body'), default='\n',
+ body = self.storage.get(self.id.storage('body'), default='\n',
revision=revision)
comment.body = body
else:
@@ -552,6 +514,8 @@ if libbe.TESTING == True:
self.storage.disconnect() # flush
self.storage.connect()
bugdir._clear_bugs()
+ uuids = sorted(bugdir.uuids())
+ self.failUnless(uuids == ['a', 'b'], uuids)
uuids = sorted([bug.uuid for bug in bugdir])
self.failUnless(uuids == [], uuids)
bugdir.load_all_bugs()
@@ -570,6 +534,8 @@ if libbe.TESTING == True:
uuids = sorted([bug.uuid for bug in bugdir])
self.failUnless(uuids == ['a', 'b'], uuids)
bugdir._clear_bugs()
+ uuids = sorted(bugdir.uuids())
+ self.failUnless(uuids == [], uuids)
uuids = sorted([bug.uuid for bug in bugdir])
self.failUnless(uuids == [], uuids)
bugdir.cleanup()
diff --git a/libbe/comment.py b/libbe/comment.py
index f5a6309..ebfde23 100644
--- a/libbe/comment.py
+++ b/libbe/comment.py
@@ -73,10 +73,8 @@ def load_comments(bug, load_full=False):
from disk *now*, rather than waiting and lazy loading as required.
"""
uuids = []
- for id in bug.storage.children():
- parsed = libbe.util.id.parse_id(id)
- if parsed['type'] == 'comment':
- uuids.append(parsed['comment'])
+ for id in libbe.util.id.child_uuids(bug.storage.children()):
+ uuids.append(id)
comments = []
for uuid in uuids:
comm = Comment(bug, uuid, from_storage=True)
@@ -157,14 +155,14 @@ class Comment(Tree, settings_object.SavedSettingsObject):
def _get_comment_body(self):
if self.storage != None and self.storage.is_readable() \
and self.uuid != INVALID_UUID:
- return self.storage.get(self.id("body"),
+ return self.storage.get(self.id.storage("body"),
decode=self.content_type.startswith("text/"))
def _set_comment_body(self, old=None, new=None, force=False):
assert self.uuid != INVALID_UUID, self
if (self.storage != None and self.storage.writeable == True) \
or force==True:
assert new != None, "Can't save empty comment"
- self.storage.set(self.id("body"), new)
+ self.storage.set(self.id.storage("body"), new)
@Property
@change_hook_property(hook=_set_comment_body)
@@ -173,16 +171,6 @@ class Comment(Tree, settings_object.SavedSettingsObject):
@doc_property(doc="The meat of the comment")
def body(): return {}
- def _get_storage(self):
- if hasattr(self.bug, "storage"):
- return self.bug.storage
-
- @Property
- @cached_property(generator=_get_storage)
- @local_property("storage")
- @doc_property(doc="A revision control system instance.")
- def storage(): return {}
-
def _extra_strings_check_fn(value):
return utility.iterable_full_of_strings(value, \
alternative=settings_object.EMPTY)
@@ -214,22 +202,21 @@ class Comment(Tree, settings_object.SavedSettingsObject):
Tree.__init__(self)
settings_object.SavedSettingsObject.__init__(self)
self.bug = bug
+ self.storage = None
self.uuid = uuid
+ self.id = libbe.util.id.ID(self, 'comment')
if from_storage == False:
if uuid == None:
self.uuid = libbe.util.id.uuid_gen()
self.settings = {}
self._setup_saved_settings()
- if self.storage != None and self.storage.is_writeable():
- self.storage.writeable = False
- set_writeable = True
- else:
- set_writeable = False
self.time = int(time.time()) # only save to second precision
self.in_reply_to = in_reply_to
self.body = body
- if set_writeable == True:
- self.storage.writeable = True
+ if self.bug != None:
+ self.storage = self.bug.storage
+ if from_storage == False:
+ if self.storage != None and self.storage.is_writeable():
self.save()
def __cmp__(self, other):
@@ -243,7 +230,7 @@ class Comment(Tree, settings_object.SavedSettingsObject):
>>> comm.author = "Jane Doe <jdoe@example.com>"
>>> print comm
--------- Comment ---------
- Name: com-1
+ Name: //com
From: Jane Doe <jdoe@example.com>
Date: Thu, 20 Nov 2008 15:55:11 +0000
<BLANKLINE>
@@ -268,15 +255,15 @@ class Comment(Tree, settings_object.SavedSettingsObject):
return str(value)
return value
- def xml(self, indent=0, shortname=None):
+ def xml(self, indent=0):
"""
>>> comm = Comment(bug=None, body="Some\\ninsightful\\nremarks\\n")
>>> comm.uuid = "0123"
>>> comm.date = "Thu, 01 Jan 1970 00:00:00 +0000"
- >>> print comm.xml(indent=2, shortname="com-1")
+ >>> print comm.xml(indent=2)
<comment>
<uuid>0123</uuid>
- <short-name>com-1</short-name>
+ <short-name>//012</short-name>
<author></author>
<date>Thu, 01 Jan 1970 00:00:00 +0000</date>
<content-type>text/plain</content-type>
@@ -285,8 +272,6 @@ class Comment(Tree, settings_object.SavedSettingsObject):
remarks</body>
</comment>
"""
- if shortname == None:
- shortname = self.uuid
if self.content_type.startswith('text/'):
body = (self.body or '').rstrip('\n')
else:
@@ -297,7 +282,7 @@ class Comment(Tree, settings_object.SavedSettingsObject):
body = base64.encodestring(self.body or '')
info = [('uuid', self.uuid),
('alt-id', self.alt_id),
- ('short-name', shortname),
+ ('short-name', self.id.user()),
('in-reply-to', self.in_reply_to),
('author', self._setting_attr_string('author')),
('date', self.date),
@@ -323,16 +308,16 @@ class Comment(Tree, settings_object.SavedSettingsObject):
>>> commA.date = "Thu, 01 Jan 1970 00:00:00 +0000"
>>> commA.author = u'Fran\xe7ois'
>>> commA.extra_strings += ['TAG: very helpful']
- >>> xml = commA.xml(shortname="com-1")
+ >>> xml = commA.xml()
>>> commB = Comment()
>>> commB.from_xml(xml, verbose=True)
>>> commB.explicit_attrs
['author', 'date', 'content_type', 'body', 'alt_id']
- >>> commB.xml(shortname="com-1") == xml
+ >>> commB.xml() == xml
False
>>> commB.uuid = commB.alt_id
>>> commB.alt_id = None
- >>> commB.xml(shortname="com-1") == xml
+ >>> commB.xml() == xml
True
"""
if type(xml_string) == types.UnicodeType:
@@ -426,7 +411,7 @@ class Comment(Tree, settings_object.SavedSettingsObject):
>>> print commA.xml()
<comment>
<uuid>0123</uuid>
- <short-name>0123</short-name>
+ <short-name>//012</short-name>
<author>John</author>
<date>Thu, 01 Jan 1970 00:00:00 +0000</date>
<content-type>text/plain</content-type>
@@ -457,13 +442,14 @@ class Comment(Tree, settings_object.SavedSettingsObject):
'Merge would add extra string "%s" to comment %s' \
% (estr, self.uuid)
- def string(self, indent=0, shortname=None):
+ def string(self, indent=0):
"""
>>> comm = Comment(bug=None, body="Some\\ninsightful\\nremarks\\n")
+ >>> comm.uuid = 'abcdef'
>>> comm.date = "Thu, 01 Jan 1970 00:00:00 +0000"
- >>> print comm.string(indent=2, shortname="com-1")
+ >>> print comm.string(indent=2)
--------- Comment ---------
- Name: com-1
+ Name: //abc
From:
Date: Thu, 01 Jan 1970 00:00:00 +0000
<BLANKLINE>
@@ -471,11 +457,9 @@ class Comment(Tree, settings_object.SavedSettingsObject):
insightful
remarks
"""
- if shortname == None:
- shortname = self.uuid
lines = []
lines.append("--------- Comment ---------")
- lines.append("Name: %s" % shortname)
+ lines.append("Name: %s" % self.id.user())
lines.append("From: %s" % (self._setting_attr_string("author")))
lines.append("Date: %s" % self.date)
lines.append("")
@@ -488,9 +472,8 @@ class Comment(Tree, settings_object.SavedSettingsObject):
sep = '\n' + istring
return istring + sep.join(lines).rstrip('\n')
- def string_thread(self, string_method_name="string", name_map={},
- indent=0, flatten=True,
- auto_name_map=False, bug_shortname=None):
+ def string_thread(self, string_method_name="string",
+ indent=0, flatten=True):
"""
Return a string displaying a thread of comments.
bug_shortname is only used if auto_name_map == True.
@@ -522,94 +505,77 @@ class Comment(Tree, settings_object.SavedSettingsObject):
>>> a.sort(key=lambda comm : comm.time)
>>> print a.string_thread(flatten=True)
--------- Comment ---------
- Name: a
+ Name: //a
From:
Date: Thu, 20 Nov 2008 01:00:00 +0000
<BLANKLINE>
Insightful remarks
--------- Comment ---------
- Name: b
+ Name: //b
From:
Date: Thu, 20 Nov 2008 02:00:00 +0000
<BLANKLINE>
Critique original comment
--------- Comment ---------
- Name: c
+ Name: //c
From:
Date: Thu, 20 Nov 2008 03:00:00 +0000
<BLANKLINE>
Begin flamewar :p
--------- Comment ---------
- Name: d
+ Name: //d
From:
Date: Thu, 20 Nov 2008 04:00:00 +0000
<BLANKLINE>
Useful examples
- >>> print a.string_thread(auto_name_map=True, bug_shortname="bug-1")
+ >>> print a.string_thread()
--------- Comment ---------
- Name: bug-1:1
+ Name: //a
From:
Date: Thu, 20 Nov 2008 01:00:00 +0000
<BLANKLINE>
Insightful remarks
--------- Comment ---------
- Name: bug-1:2
+ Name: //b
From:
Date: Thu, 20 Nov 2008 02:00:00 +0000
<BLANKLINE>
Critique original comment
--------- Comment ---------
- Name: bug-1:3
+ Name: //c
From:
Date: Thu, 20 Nov 2008 03:00:00 +0000
<BLANKLINE>
Begin flamewar :p
--------- Comment ---------
- Name: bug-1:4
+ Name: //d
From:
Date: Thu, 20 Nov 2008 04:00:00 +0000
<BLANKLINE>
Useful examples
"""
- if auto_name_map == True:
- name_map = {}
- for shortname,comment in self.comment_shortnames(bug_shortname):
- name_map[comment.uuid] = shortname
stringlist = []
for depth,comment in self.thread(flatten=flatten):
ind = 2*depth+indent
- if comment.uuid in name_map:
- sname = name_map[comment.uuid]
- else:
- sname = None
string_fn = getattr(comment, string_method_name)
- stringlist.append(string_fn(indent=ind, shortname=sname))
+ stringlist.append(string_fn(indent=ind))
return '\n'.join(stringlist)
- def xml_thread(self, name_map={}, indent=0,
- auto_name_map=False, bug_shortname=None):
- return self.string_thread(string_method_name="xml", name_map=name_map,
- indent=indent, auto_name_map=auto_name_map,
- bug_shortname=bug_shortname)
+ def xml_thread(self, indent=0):
+ return self.string_thread(string_method_name="xml", indent=indent)
# methods for saving/loading/acessing settings and properties.
- def id(self, *args):
- assert len(args) <= 1, str(args)
- if len(args) == 1:
- assert args[0] in ["values", "body"], str(args)
- return libbe.util.id.comment_id(self, *args)
-
def load_settings(self, settings_mapfile=None):
if settings_mapfile == None:
settings_mapfile = \
- self.storage.get(self.id("values"), default="\n")
+ self.storage.get(self.id.storage("values"), default="\n")
self.settings = mapfile.parse(settings_mapfile)
self._setup_saved_settings()
def save_settings(self):
mf = mapfile.generate(self._get_saved_settings())
- self.storage.set(self.id("values"), mf)
+ self.storage.set(self.id.storage("values"), mf)
def save(self):
"""
@@ -625,12 +591,12 @@ class Comment(Tree, settings_object.SavedSettingsObject):
assert self.storage != None, "Can't save without storage"
assert self.body != None, "Can't save blank comment"
if self.bug != None:
- parent = self.bug.id()
+ parent = self.bug.id.storage()
else:
parent = None
- self.storage.add(self.id(), parent=parent)
- self.storage.add(self.id('values'), parent=self.id())
- self.storage.add(self.id('body'), parent=self.id())
+ self.storage.add(self.id.storage(), parent=parent)
+ self.storage.add(self.id.storage('values'), parent=self.id.storage())
+ self.storage.add(self.id.storage('body'), parent=self.id.storage())
self.save_settings()
self._set_comment_body(new=self.body, force=True)
@@ -638,7 +604,7 @@ class Comment(Tree, settings_object.SavedSettingsObject):
for comment in self:
comment.remove()
if self.uuid != INVALID_UUID:
- self.storage.recursive_remove(self.id())
+ self.storage.recursive_remove(self.id.storage())
def add_reply(self, reply, allow_time_inversion=False):
if self.uuid != INVALID_UUID:
@@ -661,62 +627,9 @@ class Comment(Tree, settings_object.SavedSettingsObject):
self.add_reply(reply)
return reply
- def comment_shortnames(self, bug_shortname=None):
- """
- Iterate through (id, comment) pairs, in time order.
- (This is a user-friendly id, not the comment uuid).
-
- SIDE-EFFECT : will sort the comment tree by comment.time
-
- >>> a = Comment(bug=None, uuid="a")
- >>> b = a.new_reply()
- >>> b.uuid = "b"
- >>> c = b.new_reply()
- >>> c.uuid = "c"
- >>> d = a.new_reply()
- >>> d.uuid = "d"
- >>> for id,name in a.comment_shortnames("bug-1"):
- ... print id, name.uuid
- bug-1:1 a
- bug-1:2 b
- bug-1:3 c
- bug-1:4 d
- >>> for id,name in a.comment_shortnames():
- ... print id, name.uuid
- :1 a
- :2 b
- :3 c
- :4 d
- """
- if bug_shortname == None:
- bug_shortname = ""
- self.sort(key=lambda comm : comm.time)
- for num,comment in enumerate(self.traverse()):
- yield ("%s:%d" % (bug_shortname, num+1), comment)
-
- def comment_from_shortname(self, comment_shortname, *args, **kwargs):
- """
- Use a comment shortname to look up a comment.
- >>> a = Comment(bug=None, uuid="a")
- >>> b = a.new_reply()
- >>> b.uuid = "b"
- >>> c = b.new_reply()
- >>> c.uuid = "c"
- >>> d = a.new_reply()
- >>> d.uuid = "d"
- >>> comm = a.comment_from_shortname("bug-1:3", bug_shortname="bug-1")
- >>> id(comm) == id(c)
- True
- """
- for cur_name, comment in self.comment_shortnames(*args, **kwargs):
- if comment_shortname == cur_name:
- return comment
- raise InvalidShortname(comment_shortname,
- list(self.comment_shortnames(*args, **kwargs)))
-
def comment_from_uuid(self, uuid, match_alt_id=True):
"""
- Use a comment shortname to look up a comment.
+ Use a uuid to look up a comment.
>>> a = Comment(bug=None, uuid="a")
>>> b = a.new_reply()
>>> b.uuid = "b"
@@ -744,6 +657,14 @@ class Comment(Tree, settings_object.SavedSettingsObject):
return comment
raise KeyError(uuid)
+ # methods for id generation
+
+ def sibling_uuids(self):
+ if self.bug != None:
+ return self.bug.uuids()
+ return []
+
+
def cmp_attr(comment_1, comment_2, attr, invert=False):
"""
Compare a general attribute between two comments using the conventional
diff --git a/libbe/util/id.py b/libbe/util/id.py
index d443706..ab62359 100644
--- a/libbe/util/id.py
+++ b/libbe/util/id.py
@@ -137,7 +137,7 @@ class ID (object):
referenced object. It would be hard to find bug 'XYZ' if
that's all you knew. Much easier with 'ABC/XYZ', where ABC
is the bugdir. Each project can publish a list of bugdir-id
-x - to - location mappings, e.g.
+ - to - location mappings, e.g.
ABC...(full uuid)...DEF https://server.com/projectX/be/
which is easier than publishing all-object-ids-to-location
mappings.
@@ -169,9 +169,9 @@ x - to - location mappings, e.g.
self._object = object
self._type = type
assert self._type in HIERARCHY, self._type
- self.uuid = self._object.uuid
def storage(self, *args):
+ import libbe.comment
return _assemble(self._object.uuid, *args)
def _ancestors(self):
@@ -182,7 +182,7 @@ x - to - location mappings, e.g.
o = self._object
for i in range(index, 0, -1):
parent_name = HIERARCHY[i-1]
- o = getattr(o, parent_name)
+ o = getattr(o, parent_name, None)
ret.insert(0, o)
return ret
@@ -190,8 +190,26 @@ x - to - location mappings, e.g.
return _assemble(*[o.uuid for o in self._ancestors()])
def user(self):
- return _assemble(*[_truncate(o.uuid, o.sibling_uuids())
- for o in self._ancestors()])
+ ids = []
+ for o in self._ancestors():
+ if o == None:
+ ids.append(None)
+ else:
+ ids.append(_truncate(o.uuid, o.sibling_uuids()))
+ return _assemble(*ids)
+
+def child_uuids(child_storage_ids):
+ """
+ Extract uuid children from other children generated by the
+ ID.storage() method.
+ >>> list(child_uuids(['abc123/values', '123abc', '123def']))
+ ['123abc', '123def']
+ """
+ for id in child_storage_ids:
+ fields = libbe.util.id._split(id)
+ if len(fields) == 1:
+ yield fields[0]
+
def parse_user(id):
"""