class ChangeSet(object): """A server-side changeset. This represents information on a server-side changeset, which tracks the information on a commit and modified files for some types of repositories (such as Perforce). Not all data may be provided by the server. Attributes: bugs_closed (list of unicode): A list of bug IDs that were closed by this change. files (list of unicode): A list of filenames added/modified/deleted by the change. pending (bool): Whether or not the change is pending (not yet committed). """ #: The changeset number/ID. changenum = TypedProperty(int) #: The summary of the change. summary = TypedProperty(six.text_type) #: The description of the change. description = TypedProperty(six.text_type) #: Testing information for the change. testing_done = TypedProperty(six.text_type) #: The destination branch. branch = TypedProperty(six.text_type) #: The username of the user who made the change. username = TypedProperty(six.text_type) def __init__(self): """Initialize the changeset.""" self.changenum = None self.summary = '' self.description = '' self.testing_done = '' self.branch = '' self.bugs_closed = [] self.files = [] self.username = '' self.pending = False
class ParsedDiffFile(object): """A parsed file from a diff. This stores information on a single file represented in a diff, including the contents of that file's diff, as parsed by :py:class:`DiffParser` or one of its subclasses. Parsers should set the attributes on this based on the contents of the diff, and should add any data found in the diff. This class is meant to be used internally and by subclasses of :py:class:`DiffParser`. Attributes: binary (bool); Whether this represents a binary file. copied (bool): Whether this represents a file that has been copied. The file may or may not be modified in the process. deleted (bool): Whether this represents a file that has been deleted. delete_count (int): The number of delete (``-``) lines found in the file. insert_count (int): The number of insert (``+``) lines found in the file. is_symlink (bool): Whether this represents a file that is a symbolic link to another file. moved (bool): Whether this represents a file that has been moved/renamed. The file may or may not be modified in the process. parser (DiffParser): The diff parser that parsed this file. skip (bool): Whether this file should be skipped by the parser. If any of the parser methods set this, the file will stop parsing and will be excluded from results. """ #: The parsed original name of the file. #: #: Type: #: bytes orig_filename = TypedProperty(bytes) #: The parsed file details of the original file. #: #: This will usually be a revision. #: #: Type: #: bytes or reviewboard.scmtools.core.Revision orig_file_details = TypedProperty((bytes, Revision)) #: The parsed modified name of the file. #: #: This may be the same as :py:attr:`orig_filename`. #: #: Type: #: bytes modified_filename = TypedProperty(bytes) #: The parsed file details of the modified file. #: #: This will usually be a revision. #: #: Type: #: bytes or reviewboard.scmtools.core.Revision modified_file_details = TypedProperty((bytes, Revision)) #: The parsed value for an Index header. #: #: If present in the diff, this usually contains a filename, but may #: contain other content as well, depending on the variation of the diff #: format. #: #: Type: #: bytes index_header_value = TypedProperty(bytes) #: The parsed original name of the file. #: #: Deprecated: #: 4.0: #: Use :py:attr:`orig_filename` instead. origFile = AliasProperty('orig_filename', convert_to_func=force_bytes, deprecated=True, deprecation_warning=RemovedInReviewBoard50Warning) #: The parsed file details of the original file. #: #: Deprecated: #: 4.0: #: Use :py:attr:`orig_file_details` instead. origInfo = AliasProperty('orig_file_details', convert_to_func=force_bytes, deprecated=True, deprecation_warning=RemovedInReviewBoard50Warning) #: The parsed original name of the file. #: #: Deprecated: #: 4.0: #: Use :py:attr:`modified_filename` instead. newFile = AliasProperty('modified_filename', convert_to_func=force_bytes, deprecated=True, deprecation_warning=RemovedInReviewBoard50Warning) #: The parsed file details of the modified file. #: #: Deprecated: #: 4.0: #: Use :py:attr:`modified_file_details` instead. newInfo = AliasProperty('modified_file_details', convert_to_func=force_bytes, deprecated=True, deprecation_warning=RemovedInReviewBoard50Warning) #: The parsed value for an Index header. #: #: Deprecated: #: 4.0: #: Use :py:attr:`index_header_value` instead. index = AliasProperty('index_header_value', convert_to_func=force_bytes, deprecated=True, deprecation_warning=RemovedInReviewBoard50Warning) def __init__(self, parser=None): """Initialize the parsed file information. Args: parser (reviewboard.diffviewer.parser.DiffParser, optional): The diff parser that parsed this file. """ if parser is None: RemovedInReviewBoard50Warning.warn( 'Diff parsers must pass themselves as a parameter when' 'creating a ParsedDiffFile. This will be mandatory in ' 'Review Board 5.0.') self.parser = parser self.binary = False self.deleted = False self.moved = False self.copied = False self.is_symlink = False self.insert_count = 0 self.delete_count = 0 self.skip = False self._data_io = io.BytesIO() self._data = None self._deprecated_info = {} def __setitem__(self, key, value): """Set information on the parsed file from a diff. This is a legacy implementation used to help diff parsers retain compatibility with the old dictionary-based ways of setting parsed file information. Callers should be updated to set attributes instead. Deprecated: 4.0: This will be removed in Review Board 5.0. Args: key (str): The key to set. value (object): The value to set. """ self._warn_old_usage_deprecation() self._deprecated_info[key] = value setattr(self, key, value) def __getitem__(self, key): """Return information on the parsed file from a diff. This is a legacy implementation used to help diff parsers retain compatibility with the old dictionary-based ways of setting parsed file information. Callers should be updated to access attributes instead. Deprecated: 4.0: This will be removed in Review Board 5.0. Args: key (str): The key to retrieve. Returns: object: The resulting value. Raises: KeyError: The key is invalid. """ self._warn_old_usage_deprecation() return self._deprecated_info[key] def __contains__(self, key): """Return whether an old parsed file key has been explicitly set. This is a legacy implementation used to help diff parsers retain compatibility with the old dictionary-based ways of setting parsed file information. Callers should be updated to check attribute values instead. Deprecated: 4.0: This will be removed in Review Board 5.0. Args: key (str): The key to check. Returns: bool: ``True`` if the key has been explicitly set by a diff parser. ``False`` if it has not. """ self._warn_old_usage_deprecation() return key in self._deprecated_info def set(self, key, value): """Set information on the parsed file from a diff. This is a legacy implementation used to help diff parsers retain compatibility with the old dictionary-based ways of setting parsed file information. Callers should be updated to set attributes instead. Deprecated: 4.0: This will be removed in Review Board 5.0. Args: key (str): The key to set. value (object): The value to set. """ self._warn_old_usage_deprecation() self._deprecated_info[key] = value setattr(self, key, value) def get(self, key, default=None): """Return information on the parsed file from a diff. This is a legacy implementation used to help diff parsers retain compatibility with the old dictionary-based ways of setting parsed file information. Callers should be updated to access attributes instead. Deprecated: 4.0: This will be removed in Review Board 5.0. Args: key (str): The key to retrieve. default (object, optional): The default value to return. Returns: object: The resulting value. """ self._warn_old_usage_deprecation() return self._deprecated_info.get(key, default) def update(self, items): """Update information on the parsed file from a diff. This is a legacy implementation used to help diff parsers retain compatibility with the old dictionary-based ways of setting parsed file information. Callers should be updated to set individual attributes instead. Deprecated: 4.0: This will be removed in Review Board 5.0. Args: items (dict): The keys and values to set. """ self._warn_old_usage_deprecation() for key, value in six.iteritems(items): self._deprecated_info[key] = value setattr(self, key, value) @property def data(self): """The data for this diff. This must be accessed after :py:meth:`finalize` has been called. """ if self._data is None: raise ValueError('ParsedDiffFile.data cannot be accessed until ' 'finalize() is called.') return self._data def finalize(self): """Finalize the parsed diff. This makes the diff data available to consumers and closes the buffer for writing. """ self._data = self._data_io.getvalue() self._data_io.close() def prepend_data(self, data): """Prepend data to the buffer. Args: data (bytes): The data to prepend. """ if data: new_data_io = io.BytesIO() new_data_io.write(data) new_data_io.write(self._data_io.getvalue()) self._data_io.close() self._data_io = new_data_io def append_data(self, data): """Append data to the buffer. Args: data (bytes): The data to append. """ if data: self._data_io.write(data) def _warn_old_usage_deprecation(self): """Warn that a DiffParser is populating information in an old way.""" if self.parser is None: message = ( 'Diff parsers must be updated to populate attributes on a ' 'ParsedDiffFile, instead of setting the information in a ' 'dictionary. This will be required in Review Board 5.0.') else: message = ( '%r must be updated to populate attributes on a ' 'ParsedDiffFile, instead of setting the information in a ' 'dictionary. This will be required in Review Board 5.0.' % type(self.parser)) RemovedInReviewBoard50Warning.warn(message, stacklevel=3)
class Revision(object): """A revision in a diff or repository. This represents a specific revision in a tree, or a specialized indicator that can have special meaning. """ #: The name/ID of the revision. name = TypedProperty(six.text_type, allow_none=False) def __init__(self, name): """Initialize the Revision. Args: name (unicode): The name of the revision. This may be a special name (which should be in all-uppercase) or a revision ID. Raises: TypeError: The provided name was not a Unicode string. """ self.name = name def __bytes__(self): """Return a byte string representation of the revision. This is equivalent to fetching :py:attr:`name` and encoding to UTF-8. Returns: bytes: The name/ID of the revision. """ return self.name.encode('utf-8') def __str__(self): """Return a Unicode string representation of the revision. This is equivalent to fetching :py:attr:`name`. Returns: unicode: The name/ID of the revision. """ return self.name def __eq__(self, other): """Return whether this revision equals another. Args: other (Revision): The revision to compare to. Returns: bool: ``True`` if the two revisions are equal. ``False`` if they are not equal. """ return self.name == force_text(other) def __ne__(self, other): """Return whether this revision is not equal to another. Args: other (Revision): The revision to compare to. Returns: bool: ``True`` if the two revisions are not equal. ``False`` if they are equal. """ return self.name != force_text(other) def __repr__(self): """Return a string representation of this revision. Returns: unicode: The string representation. """ return '<Revision: %s>' % self.name
class Commit(object): """A commit in a repository.""" #: The ID of the commit. #: #: This should be its SHA/revision. id = TypedProperty(six.text_type) #: The name or username of the author who made the commit. author_name = TypedProperty(six.text_type) #: The timestamp of the commit as a string in ISO 8601 format. date = TypedProperty(six.text_type) #: The commit message. message = TypedProperty(six.text_type) #: The contents of the commit's diff. #: #: This may be ``None``, depending on how the commit is fetched. diff = TypedProperty(bytes) #: The ID of the commit's parent. #: #: This should be its SHA/revision. If this is the first commit, this #: should be ``None`` or an empty string. parent = TypedProperty(six.text_type) def __init__(self, author_name='', id='', date='', message='', parent='', diff=None): """Initialize the commit. All arguments are optional, and can be set later. Args: author_name (unicode, optional): The name of the author who made this commit. This should be the full name, if available, but can be the username or other identifier. id (unicode, optional): The ID of the commit. This should be its SHA/revision. date (unicode, optional): The timestamp of the commit as a string in ISO 8601 format. message (unicode, optional): The commit message. parent (unicode, optional): The ID of the commit's parent. This should be its SHA/revision. diff (bytes, optional): The contents of the commit's diff. """ self.author_name = author_name self.id = id self.date = date self.message = message self.parent = parent # This field is only used when we're actually fetching the commit from # the server to create a new review request, and isn't part of the # equality test. self.diff = diff def __eq__(self, other): """Return whether this commit is equal to another commit. Args: other (Commit): The commit to compare to. Returns: bool: ``True`` if the two commits are equal. ``False`` if they are not. """ return (self.author_name == other.author_name and self.id == other.id and self.date == other.date and self.message == other.message and self.parent == other.parent) def __repr__(self): """Return a string representation of this commit. Returns: unicode: The string representation. """ return ('<Commit %r (author=%s; date=%s; parent=%r)>' % (self.id, self.author_name, self.date, self.parent)) def split_message(self): """Return a split version of the commit message. This will separate the commit message into a summary and body, if possible. Returns: tuple: A tuple containing two string items: The summary and the commit message. If the commit message is only a single line, both items in the tuple will be that line. """ message = self.message parts = message.split('\n', 1) summary = parts[0] try: message = parts[1] except IndexError: # If the description is only one line long, pass through--'message' # will still be set to what we got from get_change, and will show # up as being the same thing as the summary. pass return summary, message
class Branch(object): """A branch in a repository. Attributes: default (bool): Whether or not this is the default branch for the repository. One (and only one) branch in a list of returned branches should have this set to ``True``. """ #: The ID of the branch. id = TypedProperty(six.text_type, allow_none=False) #: The latest commit ID on the branch. commit = TypedProperty(six.text_type) #: The name of the branch. name = TypedProperty(six.text_type) def __init__(self, id, name=None, commit='', default=False): """Initialize the branch. Args: id (unicode): The ID of the branch. name (unicode, optional): The name of the branch. If not specified, this will default to the ID. commit (unicode, optional): The latest commit ID on the branch. default (bool, optional): Whether or not this is the default branch for the repository. """ self.id = id self.name = name or self.id self.commit = commit self.default = default def __eq__(self, other): """Return whether this branch is equal to another branch. Args: other (Branch): The branch to compare to. Returns: bool: ``True`` if the two branches are equal. ``False`` if they are not. """ return (self.id == other.id and self.name == other.name and self.commit == other.commit and self.default == other.default) def __repr__(self): """Return a string representation of this branch. Returns: unicode: The string representation. """ return ('<Branch %s (name=%s; commit=%s: default=%r)>' % (self.id, self.name, self.commit, self.default))
class MyObject(object): prop = TypedProperty((int, bool), default=100)
class MyObject(object): prop = TypedProperty((int, bool), allow_none=False)
class MyObject(object): prop = TypedProperty((six.text_type, ))
class MyObject(object): prop = TypedProperty((int, bool))