Source code for versionfinder.versioninfo

"""
versionfinder/versioninfo.py

The latest version of this package is available at:
<https://github.com/jantman/versionfinder>

################################################################################
Copyright 2016 Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>

    This file is part of versionfinder.

    versionfinder is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    versionfinder 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 Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with versionfinder.  If not, see <http://www.gnu.org/licenses/>.

The Copyright and Authors attributions contained herein may not be removed or
otherwise altered, except to add the Author attribution of a contributor to
this work. (Additional Terms pursuant to Section 7b of the GPL v3)
################################################################################
While not legally required, I sincerely request that anyone who finds
bugs please submit them at <https://github.com/jantman/versionfinder> or
to me via email, and that you send any contributions or improvements
either as a pull request on GitHub, or to me via email.
################################################################################

AUTHORS:
Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>
################################################################################
"""


[docs]class VersionInfo(object): """ Class describing :py:class:`~.VersionFinder` result; the discovered information about the version and source of an installed package. """ def __init__(self, pip_version=None, pip_url=None, pip_requirement=None, pkg_resources_version=None, pkg_resources_url=None, git_tag=None, git_commit=None, git_remotes=None, git_is_dirty=None): """ Construct a new VersionInfo object containing the specified version information. :param pip_version: the package version reported by pip :type pip_version: str :param pip_url: pip package "Home-page" metadata value :type pip_url: str :param pip_requirement: the package requirement as installed via pip :type pip_requirement: str :param pkg_resources_version: the package version reported by pkg_resources :type pkg_resources_version: str :param pkg_resources_url: pkg_resources package "Home-page" metadata value :type pkg_resources_url: str :param git_tag: if the package source has a git repository on disk, the tag matching the current commit :type git_tag: str :param git_commit: if the package source has a git repository on disk, the commit SHA that repository is currently at :type git_commit: str :param git_remotes: if the package source has a git repository on disk, a dict of name to URL pairs for each git remote :type git_remotes: dict :param git_is_dirty: if the package source has a git repository on disk, whether or not that repository has uncommitted changes or is behind origin. :type git_is_dirty: bool """ self._pip_version = pip_version self._pip_url = pip_url self._pip_requirement = pip_requirement self._pkg_resources_version = pkg_resources_version self._pkg_resources_url = pkg_resources_url self._git_tag = git_tag self._git_commit = git_commit self._git_remotes = git_remotes self._git_is_dirty = git_is_dirty @property def version(self): """ Return the package/distribution version, from pip if possible or else from pkg_resources, or else None if neither can be found. :return: package/distribution version :rtype: :py:obj:`str` or :py:data:`None` """ if self._pip_version is not None: return self._pip_version return self._pkg_resources_version @property def url(self): """ Return the package/distribution "Home-page", from pip if possible or else from pkg_resources, or else None if neither can be found. :return: package/distribution Home-page/URL :rtype: :py:obj:`str` or :py:data:`None` """ if self._pip_url is not None: return self._pip_url return self._pkg_resources_url @property def pip_version(self): """ Return the pip distribution version, or None if the distribution cannot be found with pip. :return: pip distribution version :rtype: :py:obj:`str` or :py:data:`None` """ return self._pip_version @property def pip_url(self): """ Return the pip distribution "Home-page", or None if the distribution cannot be found with pip. :return: pip distribution Home-page/URL :rtype: :py:obj:`str` or :py:data:`None` """ return self._pip_url @property def pip_requirement(self): """ Return the pip requirement for the current installation of the distribution, or None if the distribution cannot be found with pip. :return: pip requirement string :rtype: :py:obj:`str` or :py:data:`None` """ return self._pip_requirement @property def pkg_resources_version(self): """ Return the pkg_resources distribution version, or None if the distribution cannot be found with pkg_resources. :return: pkg_resources distribution version :rtype: :py:obj:`str` or :py:data:`None` """ return self._pkg_resources_version @property def pkg_resources_url(self): """ Return the pkg_resources distribution "Home-page", or None if the distribution cannot be found with pkg_resources. :return: pkg_resources distribution Home-page/URL :rtype: :py:obj:`str` or :py:data:`None` """ return self._pkg_resources_url @property def git_tag(self): """ Return the name of the git that that the distribution is installed at, or None if there is no tag matching the current commit, or if not installed via git. :return: current git tag :rtype: :py:obj:`str` or :py:data:`None` """ return self._git_tag @property def git_commit(self): """ Return the hex SHA of the current git commit that the distribution is installed at, or None if not installed via git. :return: git commit hex SHA :rtype: :py:obj:`str` or :py:data:`None` """ return self._git_commit @property def git_remotes(self): """ If the distribution is installed via git, return a dict of all remotes configured on the git repository; keys are the remote name and values are the remote's first URL. If not installed via git, return None. :return: dict of git remotes, name (str) to first URL (str) :rtype: :py:obj:`dict` or :py:data:`None` """ return self._git_remotes @property def git_remote(self): """ If the distribution is installed via git, return the first URL of the 'origin' remote if one is configured for the repo, or else the first URL of the lexicographically-first remote, or else None. :return: origin or first remote URL :rtype: :py:obj:`str` or :py:data:`None` """ if self._git_remotes is None or len(self._git_remotes) < 1: return None if 'origin' in self._git_remotes: return self._git_remotes['origin'] k = sorted(self._git_remotes.keys())[0] return self._git_remotes[k] @property def git_is_dirty(self): """ Return True if the distribution is installed via git and has uncommitted changes or untracked files in the repo; Return False if the distribution is installed via git and does not have uncommitted changes or untracked files in the repo; return None if the distribution is not installed via git. :return: whether or not the git repo has uncommitted changes or untracked files :rtype: :py:obj:`bool` or :py:data:`None` """ return self._git_is_dirty @property def git_str(self): """ If the distribution is not installed via git, return an empty string. If the distribution is installed via git and pip recognizes the git source, return the pip requirement string specifying the git URL and commit, with an '*' appended if :py:meth:`~.git_is_dirty` is True. Otherwise, return a string of the form: url@ref[*] Where URL is the remote URL, ref is the tag name if the repo is checked out to a commit that matches a tag or else the commit hex SHA, and '*' is appended if :py:meth:`~.git_is_dirty` is True. :return: description of the git repo remote and state :rtype: str """ dirty = '*' if self._git_is_dirty else '' if 'git' in self._pip_requirement: return self._pip_requirement + dirty if self._git_commit is None and self._git_remotes is None: return '' ref = self._git_tag if self._git_tag is not None else self._git_commit return '%s@%s%s' % (self.git_remote, ref, dirty) @property def short_str(self): """ Return a string of the form "ver <url>" where ver is the distribution version and URL is the distribution Home-Page url, or '' if neither can be found. :return: version and URL :rtype: str """ if self.version is None and self.url is None: return '' return '%s <%s>' % (self.version, self.url) @property def long_str(self): """ Return a long version and installation specifier string of the form: If :py:meth:`~.git_str` == '': SHORT_STR otherwise: SHORT_STR (GIT_STR) Where ``SHORT_STR`` is :py:meth:`~.short_str` and ``GIT_STR`` is :py:meth:`~.git_str`. :return: long version/installation specifier string :rtype: str """ gs = self.git_str if gs == '': return self.short_str return self.short_str + ' (' + gs + ')' @property def as_dict(self): """ Return the constructor arguments as a dictionary (effectively the kwargs to the constructor). :return: dict of constructor arguments :rtype: dict """ return { 'pip_version': self._pip_version, 'pip_url': self._pip_url, 'pip_requirement': self._pip_requirement, 'pkg_resources_version': self._pkg_resources_version, 'pkg_resources_url': self._pkg_resources_url, 'git_tag': self._git_tag, 'git_commit': self._git_commit, 'git_remotes': self._git_remotes, 'git_is_dirty': self._git_is_dirty, } def __repr__(self): """ Return a string representation of the object. :return: representation of the object :rtype: str """ d = self.as_dict p = ', '.join(['%s=%s' % (k, d[k]) for k in sorted(d.keys())]) return 'VersionInfo(%s)' % p def __eq__(self, other): """ :param other: class to compare :type other: VersionInfo :return: whether or not the class' as_dict properties are equal :rtype: bool """ return self.as_dict == other.as_dict