-# Copyright (C) 2008-2010 Gianluca Montecchi <gian@grys.it>
+# Copyright (C) 2008-2012 Chris Ball <cjb@laptop.org>
+# Gianluca Montecchi <gian@grys.it>
+# Niall Douglas (s_sourceforge@nedprod.com) <spam@spamtrap.com>
# Thomas Habets <thomas@habets.pp.se>
-# W. Trevor King <wking@drexel.edu>
+# W. Trevor King <wking@tremily.us>
#
# This file is part of Bugs Everywhere.
#
-# Bugs Everywhere is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation, either version 2 of the License, or (at your
-# option) any later version.
+# Bugs Everywhere is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 2 of the License, or (at your option) any
+# later version.
#
# Bugs Everywhere is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
#
-# You should have received a copy of the GNU General Public License
-# along with Bugs Everywhere. If not, see <http://www.gnu.org/licenses/>.
+# You should have received a copy of the GNU General Public License along with
+# Bugs Everywhere. If not, see <http://www.gnu.org/licenses/>.
-"""Define the :class:`Comment` class for representing bug comments.
+"""Define :py:class:`Comment` for representing bug comments.
"""
import base64
import doctest
-class InvalidShortname(KeyError):
- def __init__(self, shortname, shortnames):
- msg = "Invalid shortname %s\n%s" % (shortname, shortnames)
- KeyError.__init__(self, msg)
- self.shortname = shortname
- self.shortnames = shortnames
-
class MissingReference(ValueError):
def __init__(self, comment):
msg = "Missing reference to %s" % (comment.in_reply_to)
self.reference = comment.in_reply_to
self.comment = comment
-class DiskAccessRequired (Exception):
- def __init__(self, goal):
- msg = "Cannot %s without accessing the disk" % goal
- Exception.__init__(self, msg)
-
INVALID_UUID = "!!~~\n INVALID-UUID \n~~!!"
def load_comments(bug, load_full=False):
def save_comments(bug):
for comment in bug.comment_root.traverse():
+ comment.bug = bug
+ comment.storage = bug.storage
comment.save()
class Comment (Tree, settings_object.SavedSettingsObject):
- """Comments are a notes that attach to :class:`~libbe.bug.Bug`\s in
+ """Comments are a notes that attach to :py:class:`~libbe.bug.Bug`\s in
threaded trees. In mailing-list terms, a comment is analogous to
a single part of an email.
assert self.uuid != INVALID_UUID, self
if self.content_type.startswith('text/') \
and self.bug != None and self.bug.bugdir != None:
- new = libbe.util.id.short_to_long_text([self.bug.bugdir], new)
+ new = libbe.util.id.short_to_long_text(
+ {self.bug.bugdir.uuid: self.bug.bugdir}, new)
if (self.storage != None and self.storage.writeable == True) \
or force==True:
assert new != None, "Can't save empty comment"
if ``from_storage==False`` (the default). When
``from_storage==True``, they are loaded from the bug database.
``content_type`` decides if the body should be run through
- :func:`util.id.short_to_long_text` before saving. See
- :meth:`_set_comment_body` for details.
+ :py:func:`util.id.short_to_long_text` before saving. See
+ :py:meth:`_set_comment_body` for details.
``in_reply_to`` should be the uuid string of the parent comment.
"""
sep = '\n' + istring
return istring + sep.join(lines).rstrip('\n')
- def from_xml(self, xml_string, verbose=True):
+ def from_xml(self, xml_string, preserve_uuids=False, verbose=True):
u"""
Note: If alt-id is not given, translates any <uuid> fields to
<alt-id> fields.
>>> commB.alt_id = None
>>> commB.xml() == xml
True
+ >>> commC = Comment()
+ >>> commC.from_xml(xml, preserve_uuids=True)
+ >>> commC.uuid == commA.uuid
+ True
"""
if type(xml_string) == types.UnicodeType:
xml_string = xml_string.strip().encode('unicode_escape')
text = settings_object.EMPTY
else:
text = xml.sax.saxutils.unescape(child.text)
- text = text.decode('unicode_escape').strip()
- if child.tag == 'uuid':
+ if not isinstance(text, unicode):
+ text = text.decode('unicode_escape')
+ text = text.strip()
+ if child.tag == 'uuid' and not preserve_uuids:
uuid = text
continue # don't set the comment's uuid tag.
elif child.tag == 'body':
<extra-string>TAG: very helpful</extra-string>
</comment>
"""
- for attr in other.explicit_attrs:
- old = getattr(self, attr)
- new = getattr(other, attr)
- if old != new:
- if accept_changes == True:
- setattr(self, attr, new)
- elif change_exception == True:
- raise ValueError, \
- 'Merge would change %s "%s"->"%s" for comment %s' \
- % (attr, old, new, self.uuid)
+ if hasattr(other, 'explicit_attrs'):
+ for attr in other.explicit_attrs:
+ old = getattr(self, attr)
+ new = getattr(other, attr)
+ if old != new:
+ if accept_changes:
+ setattr(self, attr, new)
+ elif change_exception:
+ raise ValueError(
+ ('Merge would change {} "{}"->"{}" for comment {}'
+ ).format(attr, old, new, self.uuid))
if self.alt_id == self.uuid:
self.alt_id = None
for estr in other.extra_strings:
if self.content_type.startswith("text/"):
body = (self.body or "")
if self.bug != None and self.bug.bugdir != None:
- body = libbe.util.id.long_to_short_text([self.bug.bugdir], body)
+ body = libbe.util.id.long_to_short_text(
+ {self.bug.bugdir.uuid: self.bug.bugdir}, body)
lines.extend(body.splitlines())
else:
lines.append("Content type %s not printable. Try XML output instead" % self.content_type)
if self.uuid == INVALID_UUID:
return
if settings_mapfile == None:
- settings_mapfile = \
- self.storage.get(self.id.storage("values"), default="\n")
+ settings_mapfile = self.storage.get(
+ self.id.storage('values'), '{}\n')
try:
settings = mapfile.parse(settings_mapfile)
except mapfile.InvalidMapfileContents, e: