# # Common.py - DITrack common functions # # Copyright (c) 2006-2007 The DITrack Project, www.ditrack.org. # # $Id: Common.py 1913 2007-08-17 20:14:53Z vss $ # $HeadURL: https://127.0.0.1/ditrack/src/tags/0.7/DITrack/Common.py $ # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # import string import re import urllib attachment_id_re = re.compile(r"^{[-_.%a-zA-Z0-9 ]+}$") class Identifier: """ Class representing an identifier (issue, comment or attachment). The following members are available: comment Available only if has_comment_part() returns True. An object of CommentIdentifier type which contains the comment component of the identifier. issue An object of IssueIdentifier containing the issue part of the identifier. """ def __init__(self, str): """ Parses out the identifier STR. Raises ValueError if the parsing fails. """ s = str.strip().split(".") # Attachment names can have '.' inside s = [s[0].upper(), ".".join(s[1:])] if len(s) == 0: raise ValueError, "Blank identifier passed" elif len(s) == 1: self.issue = IssueIdentifier(s[0]) elif len(s) == 2: self.issue = IssueIdentifier(s[0]) if s[1]: if s[1][0] == "{": self.attachment = AttachmentIdentifier(self.issue, s[1]) else: self.comment = CommentIdentifier(self.issue, s[1]) else: raise ValueError, "Can't parse out the identifier" def has_comment_part(self): """ Returns True if the identifier has a comment component. """ return "comment" in self.__dict__ def is_attachment_id(self): """ Returns true if it is an attachment identifier. """ return "attachment" in self.__dict__ class AttachmentIdentifier(Identifier): def __init__(self, issue_id, str): s = str.strip() if attachment_id_re.match(s): self.fname = urllib.unquote(s[1:-1]) else: raise ValueError, "Invalid attachment identifier" class CommentIdentifier(Identifier): def __init__(self, issue_id, str): s = str.strip().upper() if not s: raise ValueError, "Blank string passed as a comment identifier" if s[0] in string.digits: if not issue_id.is_numeric: # Case of 'A.1': we cannot have committed comment to # uncommitted issue. raise ValueError, \ "Numeric comment identifier of a non-numeric issue " \ "identifier" if not s.isdigit(): raise ValueError, "Expected numeric comment identifier" else: # Name if not (s.isalpha() and s.isupper()): raise ValueError, "Expected alphabetic comment identifier" self.id = s class IssueIdentifier(Identifier): def __init__(self, str): s = str.strip().upper() if not s: raise ValueError, "Empty string is not a valid issue id" self.is_numeric = False if s[0] in string.digits: # Numeric id if not s.isdigit(): raise ValueError, "Issue identifier is mixed alphanumeric" if int(s) == 0: raise ValueError, "0 is not a valid issue number" self.id = s self.is_numeric = True else: # Name if not (s.isupper() and s.isalpha()): raise ValueError, "Expected alphabetic issue identifier" self.id = s