From 2f867266d4b47cc8ca0c7ccb3768d240e5096f11 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Tue, 17 Nov 2009 08:43:44 -0500 Subject: Don't attempt to convert unicode objects to strings in *._setting_attr_string() --- libbe/bug.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index fd30ff7..6633ab7 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -267,7 +267,9 @@ class Bug(settings_object.SavedSettingsObject): value = getattr(self, setting) if value == None: return "" - return str(value) + if type(value) not in types.StringTypes: + return str(value) + return value def xml(self, show_comments=False): if self.bugdir == None: -- cgit From 4c6a1e6439293c7e584aef4fda0da1a3968fe7c9 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 19 Nov 2009 17:00:02 -0500 Subject: Ran the new update_copyright.py --- libbe/bug.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 6633ab7..48f8358 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -1,4 +1,4 @@ -# Copyright (C) 2008-2009 Chris Ball +# Copyright (C) 2008-2009 Gianluca Montecchi # Thomas Habets # W. Trevor King # -- cgit From 75fedab07f9e566ca1c984051d7deece4d910e2c Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 20 Nov 2009 17:09:08 -0500 Subject: Added Bug.from_xml() + some .from_xml() fixups. Moved comment.InvalidXML to utility.InvalidXML, so that bug and comment can share it. Added docstring explaining the __init__ arguments. Added indent and shortname options to Bug.xml() to match Comment.xml(). Added .extra_strings export to Comment.xml(). Converted Bug.xml() from string addition to list joining, which avoids a bunch of memory allocation/deallocation. Assorted " -> ' replacements. Elaborated doctests to check UTF-8, extra_strings, ... Added new comparison cmp_extra_strings for both bug. and comment.DEFAULT_CMP_FULL_CMP_LIST. --- libbe/bug.py | 112 +++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 89 insertions(+), 23 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 48f8358..fecb9b7 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -25,6 +25,10 @@ import os.path import errno import time import types +try: # import core module, Python >= 2.5 + from xml.etree import ElementTree +except ImportError: # look for non-core module + from elementtree import ElementTree import xml.sax.saxutils import doctest @@ -271,40 +275,100 @@ class Bug(settings_object.SavedSettingsObject): return str(value) return value - def xml(self, show_comments=False): - if self.bugdir == None: - shortname = self.uuid - else: - shortname = self.bugdir.bug_shortname(self) + def xml(self, indent=0, shortname=None, show_comments=False): + if shortname == None: + if self.bugdir == None: + shortname = self.uuid + else: + shortname = self.bugdir.bug_shortname(self) if self.time == None: timestring = "" else: timestring = utility.time_to_str(self.time) - info = [("uuid", self.uuid), - ("short-name", shortname), - ("severity", self.severity), - ("status", self.status), - ("assigned", self.assigned), - ("target", self.target), - ("reporter", self.reporter), - ("creator", self.creator), - ("created", timestring), - ("summary", self.summary)] - ret = '\n' + info = [('uuid', self.uuid), + ('short-name', shortname), + ('severity', self.severity), + ('status', self.status), + ('assigned', self.assigned), + ('target', self.target), + ('reporter', self.reporter), + ('creator', self.creator), + ('created', timestring), + ('summary', self.summary)] + lines = [''] for (k,v) in info: if v is not None: - ret += ' <%s>%s\n' % (k,xml.sax.saxutils.escape(v),k) + lines.append(' <%s>%s' % (k,xml.sax.saxutils.escape(v),k)) for estr in self.extra_strings: - ret += ' %s\n' % estr + lines.append(' %s\n' % estr) if show_comments == True: - comout = self.comment_root.xml_thread(auto_name_map=True, + comout = self.comment_root.xml_thread(indent=indent+2, + auto_name_map=True, bug_shortname=shortname) if len(comout) > 0: - ret += comout+'\n' - ret += '' - return ret + lines.append(comout) + lines.append('') + istring = ' '*indent + sep = '\n' + istring + return istring + sep.join(lines).rstrip('\n') + + def from_xml(self, xml_string, verbose=True): + """ + Note: If a bug uuid is given, set .alt_id to it's value. + >>> bugA = Bug(uuid="0123", summary="Need to test Bug.from_xml()") + >>> bugA.date = "Thu, 01 Jan 1970 00:00:00 +0000" + >>> bugA.creator = u'Fran\xe7ois' + >>> bugA.extra_strings += ['TAG: very helpful'] + >>> 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") + >>> bugB = Bug() + >>> bugB.from_xml(xml, verbose=True) + >>> bugB.xml(shortname="bug-1") == xml + False + >>> bugB.uuid = bugB.alt_id + >>> bugB.xml(shortname="bug-1") == xml + True + """ + if type(xml_string) == types.UnicodeType: + xml_string = xml_string.strip().encode('unicode_escape') + bug = ElementTree.XML(xml_string) + if bug.tag != 'bug': + raise utility.InvalidXML( \ + 'bug', bug, 'root element must be ') + tags=['uuid','short-name','severity','status','assigned','target', + 'reporter', 'creator', 'created', 'summary', 'extra-string', + 'comment'] + uuid = None + estrs = [] + for child in bug.getchildren(): + if child.tag == 'short-name': + pass + elif child.tag in tags: + if child.text == None or len(child.text) == 0: + text = settings_object.EMPTY + else: + text = xml.sax.saxutils.unescape(child.text) + text = text.decode('unicode_escape').strip() + if child.tag == "uuid": + uuid = text + continue # don't set the bug's uuid tag. + if child.tag == 'extra-string': + estrs.append(text) + continue # don't set the bug's extra_string yet. + else: + attr_name = child.tag.replace('-','_') + setattr(self, attr_name, text) + elif verbose == True: + print >> sys.stderr, "Ignoring unknown tag %s in %s" \ + % (child.tag, comment.tag) + if uuid not in [None, self.uuid]: + if not hasattr(self, 'alt_id') or self.alt_id == None: + self.alt_id = uuid + self.extra_strings = estrs def string(self, shortlist=False, show_comments=False): if self.bugdir == None: @@ -525,6 +589,7 @@ cmp_assigned = lambda bug_1, bug_2 : cmp_attr(bug_1, bug_2, "assigned") cmp_target = lambda bug_1, bug_2 : cmp_attr(bug_1, bug_2, "target") cmp_reporter = lambda bug_1, bug_2 : cmp_attr(bug_1, bug_2, "reporter") cmp_summary = lambda bug_1, bug_2 : cmp_attr(bug_1, bug_2, "summary") +cmp_extra_strings = lambda bug_1, bug_2 : cmp_attr(bug_1, bug_2, "extra_strings") # chronological rankings (newer < older) cmp_time = lambda bug_1, bug_2 : cmp_attr(bug_1, bug_2, "time", invert=True) @@ -547,7 +612,8 @@ def cmp_comments(bug_1, bug_2): DEFAULT_CMP_FULL_CMP_LIST = \ (cmp_status, cmp_severity, cmp_assigned, cmp_time, cmp_creator, - cmp_reporter, cmp_target, cmp_comments, cmp_summary, cmp_uuid) + cmp_reporter, cmp_target, cmp_comments, cmp_summary, cmp_uuid, + cmp_extra_strings) class BugCompoundComparator (object): def __init__(self, cmp_list=DEFAULT_CMP_FULL_CMP_LIST): -- cgit From 3e050db00d2ffa2c011efc4d9b47d8edeac5c43c Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sat, 28 Nov 2009 07:41:13 -0500 Subject: Added Bug.merge() and Comment.merge(). Added *.explicit_attrs list creation to Bug and Comment.from_xml(). Added match_alt_id keyword argumennt to .comment_from_uuid(). Removed extra enline following '' tag in Bug and Comment.xml(). --- libbe/bug.py | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 110 insertions(+), 9 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index fecb9b7..23d5488 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -20,6 +20,7 @@ Define the Bug class for representing bugs. """ +import copy import os import os.path import errno @@ -302,7 +303,7 @@ class Bug(settings_object.SavedSettingsObject): if v is not None: lines.append(' <%s>%s' % (k,xml.sax.saxutils.escape(v),k)) for estr in self.extra_strings: - lines.append(' %s\n' % estr) + lines.append(' %s' % estr) if show_comments == True: comout = self.comment_root.xml_thread(indent=indent+2, auto_name_map=True, @@ -332,6 +333,8 @@ class Bug(settings_object.SavedSettingsObject): >>> bugB.uuid = bugB.alt_id >>> bugB.xml(shortname="bug-1") == xml True + >>> bugB.explicit_attrs # doctest: +NORMALIZE_WHITESPACE + ['uuid', 'severity', 'status', 'creator', 'created', 'summary'] """ if type(xml_string) == types.UnicodeType: xml_string = xml_string.strip().encode('unicode_escape') @@ -340,8 +343,9 @@ class Bug(settings_object.SavedSettingsObject): raise utility.InvalidXML( \ 'bug', bug, 'root element must be ') tags=['uuid','short-name','severity','status','assigned','target', - 'reporter', 'creator', 'created', 'summary', 'extra-string', + 'reporter', 'creator','created','summary','extra-string', 'comment'] + self.explicit_attrs = [] uuid = None estrs = [] for child in bug.getchildren(): @@ -353,23 +357,120 @@ class Bug(settings_object.SavedSettingsObject): else: text = xml.sax.saxutils.unescape(child.text) text = text.decode('unicode_escape').strip() - if child.tag == "uuid": + if child.tag == 'uuid': uuid = text continue # don't set the bug's uuid tag. - if child.tag == 'extra-string': + elif child.tag == 'extra-string': estrs.append(text) continue # don't set the bug's extra_string yet. - else: - attr_name = child.tag.replace('-','_') + attr_name = child.tag.replace('-','_') + self.explicit_attrs.append(attr_name) setattr(self, attr_name, text) elif verbose == True: print >> sys.stderr, "Ignoring unknown tag %s in %s" \ % (child.tag, comment.tag) - if uuid not in [None, self.uuid]: + if uuid != self.uuid: if not hasattr(self, 'alt_id') or self.alt_id == None: self.alt_id = uuid self.extra_strings = estrs + def merge(self, other, allow_changes=True, allow_new_comments=True): + """ + Merge info from other into this bug. Overrides any attributes + in self that are listed in other.explicit_attrs. + >>> bugA = Bug(uuid='0123', summary='Need to test Bug.merge()') + >>> bugA.date = 'Thu, 01 Jan 1970 00:00:00 +0000' + >>> bugA.creator = 'Frank' + >>> bugA.extra_strings += ['TAG: very helpful'] + >>> bugA.extra_strings += ['TAG: favorite'] + >>> commA = bugA.comment_root.new_reply(body='comment A') + >>> commA.uuid = 'uuid-commA' + >>> bugB = Bug(uuid='3210', summary='More tests for Bug.merge()') + >>> bugB.date = 'Fri, 02 Jan 1970 00:00:00 +0000' + >>> bugB.creator = 'John' + >>> bugB.explicit_attrs = ['creator', 'summary'] + >>> bugB.extra_strings += ['TAG: very helpful'] + >>> bugB.extra_strings += ['TAG: useful'] + >>> commB = bugB.comment_root.new_reply(body='comment B') + >>> commB.uuid = 'uuid-commB' + >>> bugA.merge(bugB, allow_changes=False) + Traceback (most recent call last): + ... + ValueError: Merge would change creator "Frank"->"John" for bug 0123 + >>> bugA.merge(bugB, allow_new_comments=False) + Traceback (most recent call last): + ... + ValueError: Merge would add comment uuid-commB (alt: None) to bug 0123 + >>> bugA.merge(bugB) + >>> print bugA.xml(show_comments=True) # doctest: +ELLIPSIS + + 0123 + 0123 + minor + open + John + ... + More tests for Bug.merge() + TAG: favorite + TAG: useful + TAG: very helpful + + uuid-commA + 0123:1 + + ... + text/plain + comment A + + + uuid-commB + 0123:2 + + ... + text/plain + comment B + + + """ + for attr in other.explicit_attrs: + old = getattr(self, attr) + new = getattr(other, attr) + if old != new: + if allow_changes == True: + setattr(self, attr, new) + else: + raise ValueError, \ + 'Merge would change %s "%s"->"%s" for bug %s' \ + % (attr, old, new, self.uuid) + if allow_changes == False and len(other.extra_strings) > 0: + raise ValueError, \ + 'Merge would change extra_strings for bug %s' % self.uuid + for estr in other.extra_strings: + if not estr in self.extra_strings: + self.extra_strings.append(estr) + import sys + for o_comm in other.comments(): + s_comm = None + try: + s_comm = self.comment_root.comment_from_uuid(o_comm.uuid) + except KeyError, e: + try: + s_comm = self.comment_root.comment_from_uuid(o_comm.alt_id) + except KeyError, e: + pass + if s_comm == None: + if allow_new_comments == False: + raise ValueError, \ + 'Merge would add comment %s (alt: %s) to bug %s' \ + % (o_comm.uuid, o_comm.alt_id, self.uuid) + o_comm_copy = copy.copy(o_comm) + o_comm_copy.bug = self + print >> sys.stderr, "add comment %s" % o_comm.uuid + self.comment_root.add_reply(o_comm_copy) + else: + print >> sys.stderr, "merge comment %s into %s" % (o_comm.uuid, s_comm.uuid) + s_comm.merge(o_comm, allow_changes=allow_changes) + def string(self, shortlist=False, show_comments=False): if self.bugdir == None: shortname = self.uuid @@ -493,8 +594,8 @@ class Bug(settings_object.SavedSettingsObject): return self.comment_root.comment_from_shortname(shortname, *args, **kwargs) - def comment_from_uuid(self, uuid): - return self.comment_root.comment_from_uuid(uuid) + def comment_from_uuid(self, uuid, *args, **kwargs): + return self.comment_root.comment_from_uuid(uuid, *args, **kwargs) def comment_shortnames(self, shortname=None): """ -- cgit From 832843d26eed9023f4cf4fc431527c63ca1d533d Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sat, 28 Nov 2009 22:07:16 -0500 Subject: Added comment import to Bug.from_xml(). This is a pretty critical feature, dunno how I missed it before. I also added a little check to both Bug and Comment.from_xml() so that xml_string can take an ElementTree Element as well as the usual raw string/unicode. This avoids repeated string <-> Element conversions. Added Bug.add_comment() which handles the addition of a Comment instance, matching .in_reply_to, checking .uuid uniqueness, etc. --- libbe/bug.py | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 9 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 23d5488..5f2cf54 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -325,32 +325,44 @@ 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") + >>> xml = bugA.xml(shortname="bug-1", show_comments=True) >>> bugB = Bug() >>> bugB.from_xml(xml, verbose=True) - >>> bugB.xml(shortname="bug-1") == xml + >>> bugB.xml(shortname="bug-1", show_comments=True) == xml False >>> bugB.uuid = bugB.alt_id - >>> bugB.xml(shortname="bug-1") == xml + >>> for comm in bugB.comments(): + ... comm.uuid = comm.alt_id + ... comm.alt_id = None + >>> bugB.xml(shortname="bug-1", show_comments=True) == xml True >>> bugB.explicit_attrs # doctest: +NORMALIZE_WHITESPACE - ['uuid', 'severity', 'status', 'creator', 'created', 'summary'] + ['severity', 'status', 'creator', 'created', 'summary'] + >>> len(list(bugB.comments())) + 3 """ if type(xml_string) == types.UnicodeType: xml_string = xml_string.strip().encode('unicode_escape') - bug = ElementTree.XML(xml_string) + if hasattr(xml_string, 'getchildren'): # already an ElementTree Element + bug = xml_string + else: + bug = ElementTree.XML(xml_string) if bug.tag != 'bug': raise utility.InvalidXML( \ 'bug', bug, 'root element must be ') tags=['uuid','short-name','severity','status','assigned','target', - 'reporter', 'creator','created','summary','extra-string', - 'comment'] + 'reporter', 'creator','created','summary','extra-string'] self.explicit_attrs = [] uuid = None estrs = [] for child in bug.getchildren(): if child.tag == 'short-name': pass + elif child.tag == 'comment': + comm = comment.Comment(bug=self) + comm.from_xml(child) + self.add_comment(comm) + continue elif child.tag in tags: if child.text == None or len(child.text) == 0: text = settings_object.EMPTY @@ -374,6 +386,75 @@ class Bug(settings_object.SavedSettingsObject): self.alt_id = uuid self.extra_strings = estrs + def add_comment(self, new_comment): + """ + Add a comment too the current bug, under the parent specified + by comment.in_reply_to. + Note: If a bug uuid is given, set .alt_id to it's value. + >>> bugA = Bug(uuid='0123', summary='Need to test Bug.add_comment()') + >>> bugA.creator = 'Jack' + >>> commA = bugA.comment_root.new_reply(body='comment A') + >>> commA.uuid = 'commA' + >>> commB = comment.Comment(body='comment B') + >>> commB.uuid = 'commB' + >>> bugA.add_comment(commB) + >>> commC = comment.Comment(body='comment C') + >>> commC.uuid = 'commC' + >>> commC.in_reply_to = commA.uuid + >>> bugA.add_comment(commC) + >>> print bugA.xml(shortname="bug-1", show_comments=True) # doctest: +ELLIPSIS + + 0123 + bug-1 + minor + open + Jack + ... + Need to test Bug.add_comment() + + commA + bug-1:1 + + ... + text/plain + comment A + + + commC + bug-1:2 + commA + + ... + text/plain + comment C + + + commB + bug-1:3 + + ... + text/plain + comment B + + + """ + uuid_map = {} + for c in self.comments(): + uuid_map[c.uuid] = c + if c.alt_id != None: + uuid_map[c.alt_id] = c + assert new_comment.uuid not in uuid_map + if new_comment.alt_id != None: + assert new_comment.alt_id not in uuid_map + if new_comment.in_reply_to == comment.INVALID_UUID: + new_comment.in_reply_to = None + if new_comment.in_reply_to == None: + parent = self.comment_root + else: + parent = uuid_map[new_comment.in_reply_to] + new_comment.bug = self + parent.append(new_comment) + def merge(self, other, allow_changes=True, allow_new_comments=True): """ Merge info from other into this bug. Overrides any attributes @@ -450,14 +531,13 @@ class Bug(settings_object.SavedSettingsObject): self.extra_strings.append(estr) import sys for o_comm in other.comments(): - s_comm = None try: s_comm = self.comment_root.comment_from_uuid(o_comm.uuid) except KeyError, e: try: s_comm = self.comment_root.comment_from_uuid(o_comm.alt_id) except KeyError, e: - pass + s_comm = None if s_comm == None: if allow_new_comments == False: raise ValueError, \ -- cgit From 759c69d8c8a4bbd7ba9c42bb3a813cd0d06a52b7 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sun, 29 Nov 2009 03:19:30 -0500 Subject: Moved comment.list_to_root() to Bug.add_comments() with some cleanups. This makes Bug.add_comment simpler. Also makes Bug.from_xml() more robust, since it no longer depends on the order in which the XML file lists the comments. The previous Bug.from_xml() would have choked on B A A because when B was being added, the referenced A hadn't yet been noticed. --- libbe/bug.py | 59 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 17 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 5f2cf54..d3dbe2d 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -228,7 +228,7 @@ class Bug(settings_object.SavedSettingsObject): @Property @cached_property(generator=_get_comment_root) @local_property("comment_root") - @doc_property(doc="The trunk of the comment tree") + @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_vcs(self): @@ -355,13 +355,14 @@ class Bug(settings_object.SavedSettingsObject): self.explicit_attrs = [] uuid = None estrs = [] + comments = [] for child in bug.getchildren(): if child.tag == 'short-name': pass elif child.tag == 'comment': comm = comment.Comment(bug=self) comm.from_xml(child) - self.add_comment(comm) + comments.append(comm) continue elif child.tag in tags: if child.text == None or len(child.text) == 0: @@ -385,8 +386,9 @@ class Bug(settings_object.SavedSettingsObject): if not hasattr(self, 'alt_id') or self.alt_id == None: self.alt_id = uuid self.extra_strings = estrs + self.add_comments(comments) - def add_comment(self, new_comment): + def add_comment(self, comment, *args, **kwargs): """ Add a comment too the current bug, under the parent specified by comment.in_reply_to. @@ -438,22 +440,47 @@ class Bug(settings_object.SavedSettingsObject): """ + self.add_comments([comment], **kwargs) + + def add_comments(self, comments, default_parent=None, + ignore_missing_references=False): + """ + Convert a raw list of comments to single root comment. If a + comment does not specify a parent with .in_reply_to, the + parent defaults to .comment_root, but you can specify another + default parent via default_parent. + """ uuid_map = {} - for c in self.comments(): + if default_parent == None: + default_parent = self.comment_root + for c in list(self.comments()) + comments: + assert c.uuid != None + assert c.uuid not in uuid_map uuid_map[c.uuid] = c if c.alt_id != None: uuid_map[c.alt_id] = c - assert new_comment.uuid not in uuid_map - if new_comment.alt_id != None: - assert new_comment.alt_id not in uuid_map - if new_comment.in_reply_to == comment.INVALID_UUID: - new_comment.in_reply_to = None - if new_comment.in_reply_to == None: - parent = self.comment_root - else: - parent = uuid_map[new_comment.in_reply_to] - new_comment.bug = self - parent.append(new_comment) + uuid_map[None] = self.comment_root + if default_parent != self.comment_root: + assert default_parent.uuid in uuid_map, default_parent + for c in comments: + if c.in_reply_to == None \ + and default_parent.uuid != comment.INVALID_UUID: + c.in_reply_to = default_parent.uuid + elif c.in_reply_to == comment.INVALID_UUID: + c.in_reply_to = None + try: + parent = uuid_map[c.in_reply_to] + except KeyError: + if ignore_missing_references == True: + print >> sys.stderr, \ + "Ignoring missing reference to %s" % c.in_reply_to + parent = default_parent + if parent.uuid != comment.INVALID_UUID: + c.in_reply_to = parent.uuid + else: + raise comment.MissingReference(c) + c.bug = self + parent.append(c) def merge(self, other, allow_changes=True, allow_new_comments=True): """ @@ -545,10 +572,8 @@ class Bug(settings_object.SavedSettingsObject): % (o_comm.uuid, o_comm.alt_id, self.uuid) o_comm_copy = copy.copy(o_comm) o_comm_copy.bug = self - print >> sys.stderr, "add comment %s" % o_comm.uuid self.comment_root.add_reply(o_comm_copy) else: - print >> sys.stderr, "merge comment %s into %s" % (o_comm.uuid, s_comm.uuid) s_comm.merge(o_comm, allow_changes=allow_changes) def string(self, shortlist=False, show_comments=False): -- cgit From 19cea054def7997bb13ecc77269b7b612f658d16 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 30 Nov 2009 06:05:03 -0500 Subject: Changed Bug and Comment.merge() kwargs. The old allow_changes and allow_new_comments didn't have separate handling for extra_strings, like import_xml will need. It also didn't have a way to specify what to do if an illegal change occurs. Sometimes you'll want to raise an exception, but sometimes you'll want to ?silently? ignore the change. --- libbe/bug.py | 58 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 16 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index d3dbe2d..897d841 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -482,7 +482,9 @@ class Bug(settings_object.SavedSettingsObject): c.bug = self parent.append(c) - def merge(self, other, allow_changes=True, allow_new_comments=True): + def merge(self, other, accept_changes=True, + accept_extra_strings=True, accept_comments=True, + change_exception=False): """ Merge info from other into this bug. Overrides any attributes in self that are listed in other.explicit_attrs. @@ -501,15 +503,35 @@ class Bug(settings_object.SavedSettingsObject): >>> bugB.extra_strings += ['TAG: useful'] >>> commB = bugB.comment_root.new_reply(body='comment B') >>> commB.uuid = 'uuid-commB' - >>> bugA.merge(bugB, allow_changes=False) + >>> bugA.merge(bugB, accept_changes=False, accept_extra_strings=False, + ... accept_comments=False, change_exception=False) + >>> print bugA.creator + Frank + >>> bugA.merge(bugB, accept_changes=False, accept_extra_strings=False, + ... accept_comments=False, change_exception=True) Traceback (most recent call last): ... ValueError: Merge would change creator "Frank"->"John" for bug 0123 - >>> bugA.merge(bugB, allow_new_comments=False) + >>> print bugA.creator + Frank + >>> bugA.merge(bugB, accept_changes=True, accept_extra_strings=False, + ... accept_comments=False, change_exception=True) + Traceback (most recent call last): + ... + ValueError: Merge would add extra string "TAG: useful" for bug 0123 + >>> print bugA.creator + John + >>> print bugA.extra_strings + ['TAG: favorite', 'TAG: very helpful'] + >>> bugA.merge(bugB, accept_changes=True, accept_extra_strings=True, + ... accept_comments=False, change_exception=True) Traceback (most recent call last): ... ValueError: Merge would add comment uuid-commB (alt: None) to bug 0123 - >>> bugA.merge(bugB) + >>> print bugA.extra_strings + ['TAG: favorite', 'TAG: useful', 'TAG: very helpful'] + >>> bugA.merge(bugB, accept_changes=True, accept_extra_strings=True, + ... accept_comments=True, change_exception=True) >>> print bugA.xml(show_comments=True) # doctest: +ELLIPSIS 0123 @@ -544,19 +566,20 @@ class Bug(settings_object.SavedSettingsObject): old = getattr(self, attr) new = getattr(other, attr) if old != new: - if allow_changes == True: + if accept_changes == True: setattr(self, attr, new) - else: + elif change_exception == True: raise ValueError, \ 'Merge would change %s "%s"->"%s" for bug %s' \ % (attr, old, new, self.uuid) - if allow_changes == False and len(other.extra_strings) > 0: - raise ValueError, \ - 'Merge would change extra_strings for bug %s' % self.uuid for estr in other.extra_strings: if not estr in self.extra_strings: - self.extra_strings.append(estr) - import sys + if accept_extra_strings == True: + self.extra_strings.append(estr) + elif change_exception == True: + raise ValueError, \ + 'Merge would add extra string "%s" for bug %s' \ + % (estr, self.uuid) for o_comm in other.comments(): try: s_comm = self.comment_root.comment_from_uuid(o_comm.uuid) @@ -566,15 +589,18 @@ class Bug(settings_object.SavedSettingsObject): except KeyError, e: s_comm = None if s_comm == None: - if allow_new_comments == False: + if accept_comments == True: + o_comm_copy = copy.copy(o_comm) + o_comm_copy.bug = self + self.comment_root.add_reply(o_comm_copy) + elif change_exception == True: raise ValueError, \ 'Merge would add comment %s (alt: %s) to bug %s' \ % (o_comm.uuid, o_comm.alt_id, self.uuid) - o_comm_copy = copy.copy(o_comm) - o_comm_copy.bug = self - self.comment_root.add_reply(o_comm_copy) else: - s_comm.merge(o_comm, allow_changes=allow_changes) + s_comm.merge(o_comm, accept_changes=accept_changes, + accept_extra_strings=accept_extra_strings, + change_exception=change_exception) def string(self, shortlist=False, show_comments=False): if self.bugdir == None: -- cgit From 2ba535acb1f03fb7d1bdb57e4173d55661d300da Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 3 Dec 2009 21:19:54 -0500 Subject: Added libbe.TESTING (defaults to False). This flag allows us to skip unittest and testsuite declaration if we woln't need them. It speeds up simple be calls a suprising amount. With Testing=True (the old behavior): wking@thor:be.wtk$ time ./be > /dev/null real 0m0.393s user 0m0.340s sys 0m0.048s With TESTING=False (the new behavior): be.wtk$ time ./be > /dev/null real 0m0.216s user 0m0.152s sys 0m0.064s This adjustment was inspired by Jakub Wilk's Debian bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=559295 --- libbe/bug.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 897d841..1a190c3 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -31,8 +31,8 @@ try: # import core module, Python >= 2.5 except ImportError: # look for non-core module from elementtree import ElementTree import xml.sax.saxutils -import doctest +import libbe from beuuid import uuid_gen from properties import Property, doc_property, local_property, \ defaulting_property, checked_property, cached_property, \ @@ -41,6 +41,8 @@ import settings_object import mapfile import comment import utility +if libbe.TESTING == True: + import doctest class DiskAccessRequired (Exception): @@ -877,4 +879,5 @@ def cmp_last_modified(bug_1, bug_2): return -cmp(val_1, val_2) -suite = doctest.DocTestSuite() +if libbe.TESTING == True: + suite = doctest.DocTestSuite() -- cgit From 01db171aafdd01f184f707ba23c1484692a4a45b Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sat, 5 Dec 2009 18:25:03 -0500 Subject: This addresses the following portion of 22b:7: * Targeting normal bugs With "be depend". I think we should remove the "target" field from bugs, and move target dependencies over into the "be depend" framework. * be target list Would become "be list --severity target". A target "severity" would keep target bugs distinct from other bug/issue types. --- libbe/bug.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 1a190c3..ed1bbd2 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -56,6 +56,7 @@ class DiskAccessRequired (Exception): # in order of increasing severity. (name, description) pairs severity_def = ( + ("target", "The issue is a target or milestone, not a bug."), ("wishlist","A feature that could improve usefulness, but not a bug."), ("minor","The standard bug level."), ("serious","A bug that requires workarounds."), @@ -173,10 +174,6 @@ class Bug(settings_object.SavedSettingsObject): def active(self): return self.status in active_status_values - @_versioned_property(name="target", - doc="The deadline for fixing this bug") - def target(): return {} - @_versioned_property(name="creator", doc="The user who entered the bug into the system") def creator(): return {} -- cgit From 117425d1243a553b4566a4ff855a9d5db6b61348 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sat, 5 Dec 2009 19:46:11 -0500 Subject: Remove some more Bug.target references from libbe/bug.py --- libbe/bug.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index ed1bbd2..06c2cc5 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -292,7 +292,6 @@ class Bug(settings_object.SavedSettingsObject): ('severity', self.severity), ('status', self.status), ('assigned', self.assigned), - ('target', self.target), ('reporter', self.reporter), ('creator', self.creator), ('created', timestring), @@ -349,7 +348,7 @@ class Bug(settings_object.SavedSettingsObject): if bug.tag != 'bug': raise utility.InvalidXML( \ 'bug', bug, 'root element must be ') - tags=['uuid','short-name','severity','status','assigned','target', + tags=['uuid','short-name','severity','status','assigned', 'reporter', 'creator','created','summary','extra-string'] self.explicit_attrs = [] uuid = None @@ -617,7 +616,6 @@ class Bug(settings_object.SavedSettingsObject): ("Severity", self.severity), ("Status", self.status), ("Assigned", self._setting_attr_string("assigned")), - ("Target", self._setting_attr_string("target")), ("Reporter", self._setting_attr_string("reporter")), ("Creator", self._setting_attr_string("creator")), ("Created", timestring)] @@ -817,7 +815,6 @@ def cmp_attr(bug_1, bug_2, attr, invert=False): cmp_uuid = lambda bug_1, bug_2 : cmp_attr(bug_1, bug_2, "uuid") cmp_creator = lambda bug_1, bug_2 : cmp_attr(bug_1, bug_2, "creator") cmp_assigned = lambda bug_1, bug_2 : cmp_attr(bug_1, bug_2, "assigned") -cmp_target = lambda bug_1, bug_2 : cmp_attr(bug_1, bug_2, "target") cmp_reporter = lambda bug_1, bug_2 : cmp_attr(bug_1, bug_2, "reporter") cmp_summary = lambda bug_1, bug_2 : cmp_attr(bug_1, bug_2, "summary") cmp_extra_strings = lambda bug_1, bug_2 : cmp_attr(bug_1, bug_2, "extra_strings") @@ -843,8 +840,7 @@ def cmp_comments(bug_1, bug_2): DEFAULT_CMP_FULL_CMP_LIST = \ (cmp_status, cmp_severity, cmp_assigned, cmp_time, cmp_creator, - cmp_reporter, cmp_target, cmp_comments, cmp_summary, cmp_uuid, - cmp_extra_strings) + cmp_reporter, cmp_comments, cmp_summary, cmp_uuid, cmp_extra_strings) class BugCompoundComparator (object): def __init__(self, cmp_list=DEFAULT_CMP_FULL_CMP_LIST): -- cgit From 7a8b1223fac612ef8b3dffd0e4c6832a97aa222d Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Tue, 8 Dec 2009 04:33:49 -0500 Subject: Transitioned bug.py to new storage format. --- libbe/bug.py | 107 +++++++++++++++++++++++++---------------------------------- 1 file changed, 46 insertions(+), 61 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 06c2cc5..1aa34fd 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -33,14 +33,15 @@ except ImportError: # look for non-core module import xml.sax.saxutils import libbe -from beuuid import uuid_gen -from properties import Property, doc_property, local_property, \ +import libbe.util.id +from libbe.storage.properties import Property, doc_property, local_property, \ defaulting_property, checked_property, cached_property, \ primed_property, change_hook_property, settings_property -import settings_object -import mapfile -import comment -import utility +import libbe.storage.settings_object as settings_object +import libbe.storage.util.mapfile as mapfile +import libbe.comment as comment +import libbe.util.utility as utility + if libbe.TESTING == True: import doctest @@ -174,8 +175,14 @@ class Bug(settings_object.SavedSettingsObject): def active(self): return self.status in active_status_values + def _get_user_id(self): + if self.bugdir != None: + return self.bugdir.get_user_id() + return None + @_versioned_property(name="creator", - doc="The user who entered the bug into the system") + doc="The user who entered the bug into the system", + generator=_get_user_id) def creator(): return {} @_versioned_property(name="reporter", @@ -219,7 +226,7 @@ class Bug(settings_object.SavedSettingsObject): def summary(): return {} def _get_comment_root(self, load_full=False): - if self.sync_with_disk: + if self.storage != None and self.storage.is_readable(): return comment.loadComments(self, load_full=load_full) else: return comment.Comment(self, uuid=comment.INVALID_UUID) @@ -230,30 +237,27 @@ 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_vcs(self): - if hasattr(self.bugdir, "vcs"): - return self.bugdir.vcs + def _get_storage(self): + if hasattr(self.bugdir, "storage"): + return self.bugdir.storage @Property - @cached_property(generator=_get_vcs) - @local_property("vcs") + @cached_property(generator=_get_storage) + @local_property("storage") @doc_property(doc="A revision control system instance.") - def vcs(): return {} + def storage(): return {} def __init__(self, bugdir=None, uuid=None, from_disk=False, load_comments=False, summary=None): settings_object.SavedSettingsObject.__init__(self) self.bugdir = bugdir self.uuid = uuid - if from_disk == True: - self.sync_with_disk = True - else: - self.sync_with_disk = False + if from_disk == False: if uuid == None: - self.uuid = uuid_gen() + self.uuid = libbe.util.id.uuid_gen() + self.settings = {} + self._setup_saved_settings() self.time = int(time.time()) # only save to second precision - if self.vcs != None: - self.creator = self.vcs.get_user_id() self.summary = summary def __repr__(self): @@ -641,72 +645,53 @@ class Bug(settings_object.SavedSettingsObject): # methods for saving/loading/acessing settings and properties. - def get_path(self, *args): - dir = os.path.join(self.bugdir.get_path("bugs"), self.uuid) - if len(args) == 0: - return dir - assert args[0] in ["values", "comments"], str(args) - return os.path.join(dir, *args) - - def set_sync_with_disk(self, value): - self.sync_with_disk = value - for comment in self.comments(): - comment.set_sync_with_disk(value) + def id(self, *args): + assert len(args) <= 1, str(args) + assert args[0] in ["values"], str(args) + return libbe.util.id.comment_id(self, args) def load_settings(self): - if self.sync_with_disk == False: - raise DiskAccessRequired("load settings") - self.settings = mapfile.map_load(self.vcs, self.get_path("values")) + mf = self.storage.get(self.id("values"), default="\n") + self.settings = mapfile.parse(mf) self._setup_saved_settings() def save_settings(self): - if self.sync_with_disk == False: - raise DiskAccessRequired("save settings") - assert self.summary != None, "Can't save blank bug" - self.vcs.mkdir(self.get_path()) - path = self.get_path("values") - mapfile.map_save(self.vcs, path, self._get_saved_settings()) + mf = mapfile.generate(self._get_saved_settings()) + self.storage.set(self.id("values"), mf) def save(self): """ Save any loaded contents to disk. Because of lazy loading of comments, this is actually not too inefficient. - However, if self.sync_with_disk = True, then any changes are - automatically written to disk as soon as they happen, so - calling this method will just waste time (unless something - else has been messing with your on-disk files). + However, if self.storage.is_writeable() == True, then any + changes are automatically written to storage as soon as they + happen, so calling this method will just waste time (unless + something else has been messing with your stored files). """ - sync_with_disk = self.sync_with_disk - if sync_with_disk == False: - self.set_sync_with_disk(True) + assert self.storage != None, "Can't save without storage" + self.storage.add(self.id()) + self.storage.add(self.id('values')) self.save_settings() if len(self.comment_root) > 0: comment.saveComments(self) - if sync_with_disk == False: - self.set_sync_with_disk(False) def load_comments(self, load_full=True): - if self.sync_with_disk == False: - raise DiskAccessRequired("load comments") if load_full == True: # Force a complete load of the whole comment tree self.comment_root = self._get_comment_root(load_full=True) else: # Setup for fresh lazy-loading. Clear _comment_root, so - # _get_comment_root returns a fresh version. Turn of - # syncing temporarily so we don't write our blank comment + # next _get_comment_root returns a fresh version. Turn of + # writing temporarily so we don't write our blank comment # tree to disk. - self.sync_with_disk = False + w = self.storage.writeable + self.storage.writeable = False self.comment_root = None - self.sync_with_disk = True + self.storage.writeable = w def remove(self): - if self.sync_with_disk == False: - raise DiskAccessRequired("remove") - self.comment_root.remove() - path = self.get_path() - self.vcs.recursive_remove(path) + self.storage.recursive_remove(self.id()) # methods for managing comments -- cgit From 44b4e3f8b6405d0e1e0ebf6cb526ab62cdbbdb25 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Tue, 8 Dec 2009 08:54:50 -0500 Subject: Transitioned bugdir.py to new storage format. --- libbe/bug.py | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 1aa34fd..7bb52bc 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -177,7 +177,7 @@ class Bug(settings_object.SavedSettingsObject): def _get_user_id(self): if self.bugdir != None: - return self.bugdir.get_user_id() + return self.bugdir._get_user_id() return None @_versioned_property(name="creator", @@ -227,7 +227,7 @@ class Bug(settings_object.SavedSettingsObject): def _get_comment_root(self, load_full=False): if self.storage != None and self.storage.is_readable(): - return comment.loadComments(self, load_full=load_full) + return comment.load_comments(self, load_full=load_full) else: return comment.Comment(self, uuid=comment.INVALID_UUID) @@ -247,18 +247,26 @@ class Bug(settings_object.SavedSettingsObject): @doc_property(doc="A revision control system instance.") def storage(): return {} - def __init__(self, bugdir=None, uuid=None, from_disk=False, + def __init__(self, bugdir=None, uuid=None, from_storage=False, load_comments=False, summary=None): settings_object.SavedSettingsObject.__init__(self) self.bugdir = bugdir self.uuid = uuid - if from_disk == False: + 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 + self.save() def __repr__(self): return "Bug(uuid=%r)" % self.uuid @@ -462,8 +470,9 @@ class Bug(settings_object.SavedSettingsObject): if c.alt_id != None: uuid_map[c.alt_id] = c uuid_map[None] = self.comment_root + uuid_map[comment.INVALID_UUID] = self.comment_root if default_parent != self.comment_root: - assert default_parent.uuid in uuid_map, default_parent + assert default_parent.uuid in uuid_map, default_parent.uuid for c in comments: if c.in_reply_to == None \ and default_parent.uuid != comment.INVALID_UUID: @@ -647,12 +656,15 @@ class Bug(settings_object.SavedSettingsObject): def id(self, *args): assert len(args) <= 1, str(args) - assert args[0] in ["values"], str(args) - return libbe.util.id.comment_id(self, args) - - def load_settings(self): - mf = self.storage.get(self.id("values"), default="\n") - self.settings = mapfile.parse(mf) + 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.settings = mapfile.parse(settings_mapfile) self._setup_saved_settings() def save_settings(self): @@ -661,8 +673,8 @@ class Bug(settings_object.SavedSettingsObject): def save(self): """ - Save any loaded contents to disk. Because of lazy loading of - comments, this is actually not too inefficient. + Save any loaded contents to storage. Because of lazy loading + of comments, this is actually not too inefficient. However, if self.storage.is_writeable() == True, then any changes are automatically written to storage as soon as they @@ -670,11 +682,15 @@ class Bug(settings_object.SavedSettingsObject): something else has been messing with your stored files). """ assert self.storage != None, "Can't save without storage" - self.storage.add(self.id()) - self.storage.add(self.id('values')) + if self.bugdir != None: + parent = self.bugdir.id() + else: + parent = None + self.storage.add(self.id(), parent=parent) + self.storage.add(self.id('values'), parent=self.id()) self.save_settings() if len(self.comment_root) > 0: - comment.saveComments(self) + comment.save_comments(self) def load_comments(self, load_full=True): if load_full == True: -- cgit From 79154201c1c012063aa3fe1881ff06a3f239fdc5 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Tue, 8 Dec 2009 09:01:26 -0500 Subject: Moved properties.py and settings_object.py to libbe/storage/util/ --- libbe/bug.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 7bb52bc..84eb1ed 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -34,8 +34,8 @@ import xml.sax.saxutils import libbe import libbe.util.id -from libbe.storage.properties import Property, doc_property, local_property, \ - defaulting_property, checked_property, cached_property, \ +from libbe.storage.util.properties import Property, doc_property, + local_property, defaulting_property, checked_property, cached_property, \ primed_property, change_hook_property, settings_property import libbe.storage.settings_object as settings_object import libbe.storage.util.mapfile as mapfile -- cgit From 3e6096fb5bcb9c9e8a50faa76461da96d145ca8f Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Tue, 8 Dec 2009 20:02:34 -0500 Subject: Reworked test.py to handle deeper directory structure --- libbe/bug.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 84eb1ed..5755b63 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -34,7 +34,7 @@ import xml.sax.saxutils import libbe import libbe.util.id -from libbe.storage.util.properties import Property, doc_property, +from libbe.storage.util.properties import Property, doc_property, \ local_property, defaulting_property, checked_property, cached_property, \ primed_property, change_hook_property, settings_property import libbe.storage.settings_object as settings_object -- cgit From a153347564e4c6baa0388fda05530f5548d16ac5 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 10 Dec 2009 19:31:47 -0500 Subject: Moved bugdir, bug, and comment over to new id implementation. --- libbe/bug.py | 168 ++++++++++++++++++++++++----------------------------------- 1 file changed, 69 insertions(+), 99 deletions(-) (limited to 'libbe/bug.py') 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(' %s' % 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('') @@ -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 0123 - bug-1 + /012 minor open Jack @@ -425,7 +440,7 @@ class Bug(settings_object.SavedSettingsObject): Need to test Bug.add_comment() commA - bug-1:1 + /012/commA ... text/plain @@ -433,7 +448,7 @@ class Bug(settings_object.SavedSettingsObject): commC - bug-1:2 + /012/commC commA ... @@ -442,7 +457,7 @@ class Bug(settings_object.SavedSettingsObject): commB - bug-1:3 + /012/commB ... text/plain @@ -546,7 +561,7 @@ class Bug(settings_object.SavedSettingsObject): >>> print bugA.xml(show_comments=True) # doctest: +ELLIPSIS 0123 - 0123 + /012 minor open John @@ -557,7 +572,7 @@ class Bug(settings_object.SavedSettingsObject): TAG: very helpful uuid-commA - 0123:1 + /012/uuid-commA ... text/plain @@ -565,7 +580,7 @@ class Bug(settings_object.SavedSettingsObject): uuid-commB - 0123:2 + /012/uuid-commB ... text/plain @@ -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 -- cgit From dff6bd9bf89ca80e2265696a478e540476718c9c Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sat, 12 Dec 2009 20:57:59 -0500 Subject: Moved be to libbe.ui.command_line and transitioned to Command format. --- libbe/bug.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 1f96779..d62de49 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -37,7 +37,7 @@ import libbe.util.id from libbe.storage.util.properties import Property, doc_property, \ local_property, defaulting_property, checked_property, cached_property, \ primed_property, change_hook_property, settings_property -import libbe.storage.settings_object as settings_object +import libbe.storage.util.settings_object as settings_object import libbe.storage.util.mapfile as mapfile import libbe.comment as comment import libbe.util.utility as utility -- cgit From 4d057dab603f42ec40b911dbee6792dcf107bd14 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sun, 13 Dec 2009 06:19:23 -0500 Subject: Converted libbe.storage.vcs.base to new Storage format. --- libbe/bug.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index d62de49..29d95f5 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -657,8 +657,9 @@ class Bug(settings_object.SavedSettingsObject): parent = self.bugdir.id.storage() else: parent = None - 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(), parent=parent, directory=True) + self.storage.add(self.id.storage('values'), parent=self.id.storage(), + directory=False) self.save_settings() if len(self.comment_root) > 0: comment.save_comments(self) -- cgit From 19fe0817ba7c2cd04caea3adfa82d4490288a548 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 14 Dec 2009 07:37:51 -0500 Subject: Transitioned comment to Command format --- libbe/bug.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 29d95f5..6c5f958 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -175,14 +175,8 @@ class Bug(settings_object.SavedSettingsObject): def active(self): return self.status in active_status_values - def _get_user_id(self): - if self.bugdir != None: - return self.bugdir._get_user_id() - return None - @_versioned_property(name="creator", - doc="The user who entered the bug into the system", - generator=_get_user_id) + doc="The user who entered the bug into the system") def creator(): return {} @_versioned_property(name="reporter", -- cgit From 0f87a22c20a019f49455005542d4c60216ce39d2 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 14 Dec 2009 20:13:30 -0500 Subject: Transitioned merge to Command-format --- libbe/bug.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 6c5f958..da9a1a2 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -296,8 +296,7 @@ class Bug(settings_object.SavedSettingsObject): 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. + self.comment_root.sort(cmp=libbe.comment.cmp_time, reverse=True) comout = self.comment_root.string_thread(flatten=False) output = bugout + '\n' + comout.rstrip('\n') else : -- cgit From 89b7a1411e4658e831f5d635534b24355dbb941d Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Tue, 15 Dec 2009 06:44:20 -0500 Subject: Fixed libbe.command.diff + ugly BugDir.duplicate_bugdir implementation duplicate_bugdir() works, but for the vcs backends, it could require shelling out for _every_ file read. This could, and probably will, be horribly slow. Still it works ;). I'm not sure what a better implementation would be. The old implementation checked out the entire earlier state into a temporary directory pros: single shell out, simple upgrade implementation cons: wouldn't work well for HTTP backens I think a good solution would run along the lines of the currently commented out code in duplicate_bugdir(), where a VersionedStorage.changed_since(revision) call would give you a list of changed files. diff could work off of that directly, without the need to generate a whole duplicate bugdir. I'm stuck on how to handle upgrades though... Also removed trailing whitespace from all python files. --- libbe/bug.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index da9a1a2..6ab4d78 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -24,6 +24,7 @@ import copy import os import os.path import errno +import sys import time import types try: # import core module, Python >= 2.5 @@ -170,7 +171,7 @@ class Bug(settings_object.SavedSettingsObject): check_fn=lambda s: s in status_values, require_save=True) def status(): return {} - + @property def active(self): return self.status in active_status_values @@ -249,7 +250,7 @@ class Bug(settings_object.SavedSettingsObject): if self.bugdir != None: self.storage = self.bugdir.storage if from_storage == False: - if self.storage != None and self.storage.is_writeable(): + if self.storage != None and self.storage.is_writeable(): self.save() def __repr__(self): @@ -294,7 +295,7 @@ class Bug(settings_object.SavedSettingsObject): 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: self.comment_root.sort(cmp=libbe.comment.cmp_time, reverse=True) comout = self.comment_root.string_thread(flatten=False) @@ -398,7 +399,7 @@ class Bug(settings_object.SavedSettingsObject): self.explicit_attrs.append(attr_name) setattr(self, attr_name, text) elif verbose == True: - print >> sys.stderr, "Ignoring unknown tag %s in %s" \ + print >> sys.stderr, 'Ignoring unknown tag %s in %s' \ % (child.tag, comment.tag) if uuid != self.uuid: if not hasattr(self, 'alt_id') or self.alt_id == None: @@ -492,7 +493,7 @@ class Bug(settings_object.SavedSettingsObject): except KeyError: if ignore_missing_references == True: print >> sys.stderr, \ - "Ignoring missing reference to %s" % c.in_reply_to + 'Ignoring missing reference to %s' % c.in_reply_to parent = default_parent if parent.uuid != comment.INVALID_UUID: c.in_reply_to = parent.uuid @@ -628,7 +629,11 @@ class Bug(settings_object.SavedSettingsObject): if settings_mapfile == None: settings_mapfile = \ self.storage.get(self.id.storage("values"), default="\n") - self.settings = mapfile.parse(settings_mapfile) + try: + self.settings = mapfile.parse(settings_mapfile) + except mapfile.InvalidMapfileContents, e: + raise Exception('Invalid settings file for bug %s\n' + '(BE version missmatch?)' % self.id.user()) self._setup_saved_settings() def save_settings(self): @@ -639,7 +644,7 @@ class Bug(settings_object.SavedSettingsObject): """ Save any loaded contents to storage. Because of lazy loading of comments, this is actually not too inefficient. - + However, if self.storage.is_writeable() == True, then any changes are automatically written to storage as soon as they happen, so calling this method will just waste time (unless @@ -666,14 +671,14 @@ class Bug(settings_object.SavedSettingsObject): # next _get_comment_root returns a fresh version. Turn of # writing temporarily so we don't write our blank comment # tree to disk. - w = self.storage.writeable + w = self.storage.writeable self.storage.writeable = False self.comment_root = None self.storage.writeable = w def remove(self): self.storage.recursive_remove(self.id.storage()) - + # methods for managing comments def uuids(self): @@ -770,7 +775,7 @@ def cmp_attr(bug_1, bug_2, attr, invert=False): val_2 = getattr(bug_2, attr) if val_1 == None: val_1 = None if val_2 == None: val_2 = None - + if invert == True : return -cmp(val_1, val_2) else : @@ -816,7 +821,7 @@ class BugCompoundComparator (object): if val != 0 : return val return 0 - + cmp_full = BugCompoundComparator() -- cgit From 214c4317bb90684dcfdab4d2402daa66fbad2e77 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sun, 27 Dec 2009 15:58:29 -0500 Subject: Fixed libbe.storage.util.upgrade Note that it only upgrades on-disk versions, so you can't use a non-VCS storage backend whose version isn't your command's current storage version. See #bea/110/bd1# for reasoning. To see the on-disk storage version, look at .be/version To see your command's supported storage version, look at be --full-version I added test_upgrade.sh to exercise the upgrade mechanism on BE's own repository. --- libbe/bug.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 6ab4d78..1186ad4 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -628,7 +628,7 @@ class Bug(settings_object.SavedSettingsObject): def load_settings(self, settings_mapfile=None): if settings_mapfile == None: settings_mapfile = \ - self.storage.get(self.id.storage("values"), default="\n") + self.storage.get(self.id.storage('values'), default='\n') try: self.settings = mapfile.parse(settings_mapfile) except mapfile.InvalidMapfileContents, e: @@ -638,7 +638,7 @@ class Bug(settings_object.SavedSettingsObject): def save_settings(self): mf = mapfile.generate(self._get_saved_settings()) - self.storage.set(self.id.storage("values"), mf) + self.storage.set(self.id.storage('values'), mf) def save(self): """ -- cgit From 292f341109b31c16213146f9184d0b93a425f316 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 28 Dec 2009 07:10:47 -0500 Subject: Add most comments with ignore_missing_references=True. --- libbe/bug.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 1186ad4..66ba579 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -405,7 +405,7 @@ class Bug(settings_object.SavedSettingsObject): if not hasattr(self, 'alt_id') or self.alt_id == None: self.alt_id = uuid self.extra_strings = estrs - self.add_comments(comments) + self.add_comments(comments, ignore_missing_references=True) def add_comment(self, comment, *args, **kwargs): """ -- cgit From 4d4283ecd654f1efb058cd7f7dba6be88b70ee92 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 1 Jan 2010 08:11:08 -0500 Subject: Updated copyright information --- libbe/bug.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 66ba579..7e9999e 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -1,4 +1,4 @@ -# Copyright (C) 2008-2009 Gianluca Montecchi +# Copyright (C) 2008-2010 Gianluca Montecchi # Thomas Habets # W. Trevor King # -- cgit From bda68bb5d93f4b608fb1dd17c5a0cf1bb406daf9 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 22 Jan 2010 11:30:26 -0500 Subject: Reworked settings_object module, but command.init tests still fail: $ python test.py libbe.command.init Doctest: libbe.command.init.Init ... FAIL ... ----------------------- File ".../libbe/command/init.py", line 47, in libbe.command.init.Init Failed example: ui.run(cmd) Exception raised: Traceback (most recent call last): ... File "/tmp/be.wtk/libbe/command/init.py", line 97, in _run bd = libbe.bugdir.BugDir(storage, from_storage=False) File "/tmp/be.wtk/libbe/bugdir.py", line 185, in __init__ self.save() File "/tmp/be.wtk/libbe/bugdir.py", line 228, in save self.save_settings() File "/tmp/be.wtk/libbe/bugdir.py", line 204, in save_settings mf = mapfile.generate(self._get_saved_settings()) File "/tmp/be.wtk/libbe/storage/util/settings_object.py", line 230, in _get_saved_settings self, self._setting_name_to_attr_name(k)) File "/tmp/be.wtk/libbe/storage/util/properties.py", line 194, in _fget value = fget(self) File "/tmp/be.wtk/libbe/storage/util/properties.py", line 329, in _fget primer(self) File "/tmp/be.wtk/libbe/storage/util/settings_object.py", line 69, in prop_load_settings self.load_settings() File "/tmp/be.wtk/libbe/bugdir.py", line 194, in load_settings self.settings = mapfile.parse(settings_mapfile) File "/tmp/be.wtk/libbe/storage/util/mapfile.py", line 123, in parse c = yaml.load(contents) ... File "/usr/lib/python2.6/site-packages/yaml/reader.py", line 213, in update_raw data = self.stream.read(size) AttributeError: 'NoneType' object has no attribute 'read' ... --- libbe/bug.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 7e9999e..275a826 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -242,8 +242,6 @@ class Bug(settings_object.SavedSettingsObject): if from_storage == False: if uuid == None: self.uuid = libbe.util.id.uuid_gen() - self.settings = {} - self._setup_saved_settings() self.time = int(time.time()) # only save to second precision self.summary = summary dummy = self.comment_root -- cgit From 331a641325daf3b067ecde2a51b5308c9287444e Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 22 Jan 2010 20:38:57 -0500 Subject: Move BugDir, Bug, and Comment to new _setup_saved_settings --- libbe/bug.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 275a826..0b40921 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -121,7 +121,7 @@ def load_status(active_status_def, inactive_status_def): load_status(active_status_def, inactive_status_def) -class Bug(settings_object.SavedSettingsObject): +class Bug (settings_object.SavedSettingsObject): """ >>> b = Bug() >>> print b.status @@ -628,11 +628,11 @@ class Bug(settings_object.SavedSettingsObject): settings_mapfile = \ self.storage.get(self.id.storage('values'), default='\n') try: - self.settings = mapfile.parse(settings_mapfile) + settings = mapfile.parse(settings_mapfile) except mapfile.InvalidMapfileContents, e: raise Exception('Invalid settings file for bug %s\n' '(BE version missmatch?)' % self.id.user()) - self._setup_saved_settings() + self._setup_saved_settings(settings) def save_settings(self): mf = mapfile.generate(self._get_saved_settings()) -- cgit From 668be5b01d9ad47f4f9714bfe8deee377341eb35 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sat, 6 Feb 2010 13:09:24 -0500 Subject: Added libbe.bug to the Sphinx documentation --- libbe/bug.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index 0b40921..a4b569f 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -16,8 +16,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -""" -Define the Bug class for representing bugs. +"""Define the Bug class for representing bugs. """ import copy @@ -122,7 +121,9 @@ load_status(active_status_def, inactive_status_def) class Bug (settings_object.SavedSettingsObject): - """ + """A bug (or issue) is a place to store attributes and attach + comments. In mailing-list terms, a bug is analogous to a thread. + >>> b = Bug() >>> print b.status open @@ -132,6 +133,7 @@ class Bug (settings_object.SavedSettingsObject): There are two formats for time, int and string. Setting either one will adjust the other appropriately. The string form is the one stored in the bug's settings file on disk. + >>> print type(b.time) >>> print type(b.time_string) @@ -333,7 +335,7 @@ class Bug (settings_object.SavedSettingsObject): return istring + sep.join(lines).rstrip('\n') def from_xml(self, xml_string, verbose=True): - """ + u""" Note: If a bug uuid is given, set .alt_id to it's value. >>> bugA = Bug(uuid="0123", summary="Need to test Bug.from_xml()") >>> bugA.date = "Thu, 01 Jan 1970 00:00:00 +0000" @@ -410,6 +412,7 @@ class Bug (settings_object.SavedSettingsObject): Add a comment too the current bug, under the parent specified by comment.in_reply_to. Note: If a bug uuid is given, set .alt_id to it's value. + >>> bugA = Bug(uuid='0123', summary='Need to test Bug.add_comment()') >>> bugA.creator = 'Jack' >>> commA = bugA.comment_root.new_reply(body='comment A') @@ -506,6 +509,7 @@ class Bug (settings_object.SavedSettingsObject): """ Merge info from other into this bug. Overrides any attributes in self that are listed in other.explicit_attrs. + >>> bugA = Bug(uuid='0123', summary='Need to test Bug.merge()') >>> bugA.date = 'Thu, 01 Jan 1970 00:00:00 +0000' >>> bugA.creator = 'Frank' -- cgit From 4c71190ebafd7ce198a5c0047588c4b2f7e5ef58 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sat, 6 Feb 2010 13:44:05 -0500 Subject: Added bugdir and comment modules to Sphinx docs --- libbe/bug.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index a4b569f..dd68518 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -16,7 +16,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -"""Define the Bug class for representing bugs. +"""Define the :class:`Bug` class for representing bugs. """ import copy @@ -122,7 +122,9 @@ load_status(active_status_def, inactive_status_def) class Bug (settings_object.SavedSettingsObject): """A bug (or issue) is a place to store attributes and attach - comments. In mailing-list terms, a bug is analogous to a thread. + :class:`libbe.comment.Comment`\s. In mailing-list terms, a bug is + analogous to a thread. Bugs are normally stored in + :class:`libbe.bugdir.BugDir`\s. >>> b = Bug() >>> print b.status @@ -716,6 +718,7 @@ def cmp_severity(bug_1, bug_2): """ Compare the severity levels of two bugs, with more severe bugs comparing as less. + >>> bugA = Bug() >>> bugB = Bug() >>> bugA.severity = bugB.severity = "wishlist" @@ -734,8 +737,9 @@ def cmp_severity(bug_1, bug_2): def cmp_status(bug_1, bug_2): """ - Compare the status levels of two bugs, with more 'open' bugs + Compare the status levels of two bugs, with more "open" bugs comparing as less. + >>> bugA = Bug() >>> bugB = Bug() >>> bugA.status = bugB.status = "open" @@ -755,9 +759,10 @@ def cmp_status(bug_1, bug_2): def cmp_attr(bug_1, bug_2, attr, invert=False): """ - Compare a general attribute between two bugs using the conventional - comparison rule for that attribute type. If invert == True, sort - *against* that convention. + Compare a general attribute between two bugs using the + conventional comparison rule for that attribute type. If + ``invert==True``, sort *against* that convention. + >>> attr="severity" >>> bugA = Bug() >>> bugB = Bug() -- cgit From 413626d3b77e9bf89389a272ed489da29f3d9877 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sat, 6 Feb 2010 16:53:57 -0500 Subject: Use numpydoc and generate-libbe-txt.py to autogenerate API documentation --- libbe/bug.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libbe/bug.py') diff --git a/libbe/bug.py b/libbe/bug.py index dd68518..8bf32dd 100644 --- a/libbe/bug.py +++ b/libbe/bug.py @@ -122,9 +122,9 @@ load_status(active_status_def, inactive_status_def) class Bug (settings_object.SavedSettingsObject): """A bug (or issue) is a place to store attributes and attach - :class:`libbe.comment.Comment`\s. In mailing-list terms, a bug is + :class:`~libbe.comment.Comment`\s. In mailing-list terms, a bug is analogous to a thread. Bugs are normally stored in - :class:`libbe.bugdir.BugDir`\s. + :class:`~libbe.bugdir.BugDir`\s. >>> b = Bug() >>> print b.status -- cgit