[tor-commits] [sbws/master] fix: Move to declarative setup.cfg

juga at torproject.org juga at torproject.org
Thu Mar 18 08:11:40 UTC 2021


commit 7d26503cb32668c107bef3bae8389170c8ded14b
Author: juga0 <juga at riseup.net>
Date:   Tue Mar 16 14:28:09 2021 +0000

    fix: Move to declarative setup.cfg
    
    Also:
    - Update versioneer
    - And include other source distribution files in MANIFEST.in
    - Add project URLs
    - Add formatter and linter dependencies and configurations.
    - tox: Remove travis, fix python environments
    - tox: Remove extra coverage options and add them in .coveragerc.
---
 .coveragerc              |   1 +
 .gitattributes           |   1 +
 MANIFEST.in              |   8 +--
 pyproject.toml           |  24 +++++++
 sbws/_version.py         |  25 ++++---
 setup.cfg                |  93 ++++++++++++++++++++++++--
 setup.py                 |  86 ++----------------------
 tests/integration/run.sh |   3 +-
 tox.ini                  |  88 +++++++++++++-----------
 versioneer.py            | 169 ++++++++++++++++++++++++++++-------------------
 10 files changed, 289 insertions(+), 209 deletions(-)

diff --git a/.coveragerc b/.coveragerc
index c6303ca..ed599ae 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,2 +1,3 @@
 [run]
 omit = */__init__.py
+source = sbws
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..cc47975
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+sbws/_version.py export-subst
diff --git a/MANIFEST.in b/MANIFEST.in
index 793621e..a5058d4 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,8 +1,8 @@
 include *.md
 include *.rst
-include *.ini
-recursive-include docs *
-prune docs/build
+recursive-include docs Makefile make.bat
+recursive-include sbws *.ini
 recursive-include tests *
 recursive-exclude **/__pycache__ *
-include versioneer.py
+recursive-exclude * *.py[co]
+prune docs/build
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..f790796
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,24 @@
+
+[tool.black]
+line-length = 79
+target-version = ['py36', 'py37', 'py38']
+exclude = '''
+/(
+  docs
+  | .*__init__\.py
+  | .*_version\.py
+)/
+'''
+
+
+[tool.isort]
+line_length = 79
+# Compatibility with black
+# profile = black  # does not seem to work
+multi_line_output = 3
+include_trailing_comma = true
+force_grid_wrap = 0
+use_parentheses = true
+ensure_newline_before_comments = true
+src_paths = "sbws,tests"
+skip = "versioneer.py,docs,sbws/_version.py,sbws/__init__.py"
diff --git a/sbws/_version.py b/sbws/_version.py
index e1de1ad..cbf260a 100644
--- a/sbws/_version.py
+++ b/sbws/_version.py
@@ -6,7 +6,7 @@
 # that just contains the computed version number.
 
 # This file is released into the public domain. Generated by
-# versioneer-0.18 (https://github.com/warner/python-versioneer)
+# versioneer-0.19 (https://github.com/python-versioneer/python-versioneer)
 
 """Git implementation of _version.py."""
 
@@ -57,7 +57,7 @@ HANDLERS = {}
 
 
 def register_vcs_handler(vcs, method):  # decorator
-    """Decorator to mark a method as the handler for a particular VCS."""
+    """Create decorator to mark a method as the handler of a VCS."""
     def decorate(f):
         """Store f in HANDLERS[vcs][method]."""
         if vcs not in HANDLERS:
@@ -93,9 +93,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
         if verbose:
             print("unable to find command, tried %s" % (commands,))
         return None, None
-    stdout = p.communicate()[0].strip()
-    if sys.version_info[0] >= 3:
-        stdout = stdout.decode()
+    stdout = p.communicate()[0].strip().decode()
     if p.returncode != 0:
         if verbose:
             print("unable to run %s (error)" % dispcmd)
@@ -165,6 +163,10 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose):
         raise NotThisMethod("no keywords at all, weird")
     date = keywords.get("date")
     if date is not None:
+        # Use only the last line.  Previous lines may contain GPG signature
+        # information.
+        date = date.splitlines()[-1]
+
         # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant
         # datestamp. However we prefer "%ci" (which expands to an "ISO-8601
         # -like" string, which we must then edit to make compliant), because
@@ -300,6 +302,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
     # commit date: see ISO-8601 comment in git_versions_from_keywords()
     date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"],
                        cwd=root)[0].strip()
+    # Use only the last line.  Previous lines may contain GPG signature
+    # information.
+    date = date.splitlines()[-1]
     pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
 
     return pieces
@@ -338,18 +343,18 @@ def render_pep440(pieces):
 
 
 def render_pep440_pre(pieces):
-    """TAG[.post.devDISTANCE] -- No -dirty.
+    """TAG[.post0.devDISTANCE] -- No -dirty.
 
     Exceptions:
-    1: no tags. 0.post.devDISTANCE
+    1: no tags. 0.post0.devDISTANCE
     """
     if pieces["closest-tag"]:
         rendered = pieces["closest-tag"]
         if pieces["distance"]:
-            rendered += ".post.dev%d" % pieces["distance"]
+            rendered += ".post0.dev%d" % pieces["distance"]
     else:
         # exception #1
-        rendered = "0.post.dev%d" % pieces["distance"]
+        rendered = "0.post0.dev%d" % pieces["distance"]
     return rendered
 
 
@@ -385,7 +390,7 @@ def render_pep440_old(pieces):
 
     The ".dev0" means dirty.
 
-    Eexceptions:
+    Exceptions:
     1: no tags. 0.postDISTANCE[.dev0]
     """
     if pieces["closest-tag"]:
diff --git a/setup.cfg b/setup.cfg
index fd6b30c..578a389 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,3 +1,92 @@
+[metadata]
+name = sbws
+description = Simple Bandwidth Scanner
+author = Matt Traudt, juga
+author_email = {pastly, juga}@torproject.org
+license = CC0
+url = gitlab.torproject.org/tpo/network-health/sbws
+keywords = tor onion bandwidth measurements scanner relay circuit
+classifiers =
+    Development Status :: 4 - Beta
+    Environment :: Console
+    Intended Audience :: Developers
+    Intended Audience :: System Administrators
+    License :: OSI Approved :: MIT License
+    Natural Language :: English
+    Operating System :: POSIX :: Linux
+    Programming Language :: Python :: 3
+    Programming Language :: Python :: 3.6
+    Programming Language :: Python :: 3.7
+    Programming Language :: Python :: 3.8
+    Programming Language :: Python :: 3.9
+long_description = file: README.md
+license_files = LICENSE.md
+project_urls =
+    Documentation = sbws.readthedocs.org
+    Source = gitlab.torproject.org/tpo/network-health/sbws
+    Tracker = gitlab.torproject.org/tpo/network-health/sbws/-/issues
+
+[options]
+packages = find:
+include_package_data = True
+# See stable releases at https://www.python.org/downloads/
+python_requires = >= 3.6
+install_requires =
+    stem >= 1.7.0
+    ; # Now versioneer is also needed as dependency
+    versioneer
+    requests[socks]
+
+[options.extras_require]
+test =
+  black
+  coverage
+  flake8
+  flake8-docstrings
+  freezegun
+  isort
+  ; pylint  ; when we ever fix all the errors it throughs
+  pytest
+  tox
+  sphinx
+doc =
+  sphinx
+  pylint
+  recommonmark
+dev =
+  flake8
+  flake8-docstrings
+  isort
+  vulture
+
+[options.entry_points]
+console_scripts =
+    sbws = sbws.sbws:main
+
+[tool:pytest]
+log_cli=true
+log_cli_level=DEBUG
+
+[flake8]
+max-line-length = 79
+# D103 Missing docstring
+# D400: First line should end with a period (not 't')
+# D401: First line should be in imperative mood
+# Compatibility with black
+# W503 line break before binary operator
+# E203 whitespace before ':'
+extend-ignore = E203, W503, D1, D2, D4
+exclude = docs/*,sbws/_version.py,sbws/__init__.py,versioneer.py
+
+[coverage:run]
+# Do not give error on empty __init__ files
+omit = */__init__.py
+source = sbws
+
+[aliases]
+# Define setup.py command aliases here
+test = pytest
+
 # See the docstring in versioneer.py for instructions. Note that you must
 # re-run 'versioneer.py setup' after changing this section, and commit the
 # resulting files.
@@ -15,7 +104,3 @@ versionfile_build = sbws/_version.py
 tag_prefix = v
 # String at the start of all unpacked tarball filenames.
 parentdir_prefix = sbws-
-
-[tool:pytest]
-log_cli=true
-log_cli_level=DEBUG
diff --git a/setup.py b/setup.py
index 10ff1fd..9ea4303 100755
--- a/setup.py
+++ b/setup.py
@@ -1,85 +1,7 @@
-#!/usr/bin/env python3
-# Always prefer setuptools over distutils
-from setuptools import setup, find_packages
-# To use a consistent encoding
-from codecs import open
-import os
-# To generate the version at build time based on
-# git describe --tags --dirty --always
+"""The setup script."""
+import setuptools
 import versioneer
 
-
-here = os.path.abspath(os.path.dirname(__file__))
-
-
-def long_description():
-    with open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
-        return f.read()
-
-
-def get_package_data():
-    # Example that grabs all *.ini files in the cwd and all files in foo/bar
-    # other_files = ['*.ini']
-    # for r, _, fs in os.walk(os.path.join(here, 'foo', 'bar')):
-    #     for f in fs:
-    #         other_files.append(os.path.join(r, f))
-    # return other_files
-    return [
-        'config.default.ini',
-        'config.log.default.ini',
-    ]
-
-
-def get_data_files():
-    pass
-
-
-setup(
-    name='sbws',
-    version=versioneer.get_version(),
-    cmdclass=versioneer.get_cmdclass(),
-    description='Simple Bandwidth Scanner',
-    long_description=long_description(),
-    long_description_content_type="text/markdown",
-    author='Matt Traudt, juga',
-    author_email='{pastly, juga}@torproject.org',
-    license='CC0',
-    url="https://gitweb.torproject.org/sbws.git",
-    classifiers=[
-        'Development Status :: 4 - Beta',
-        "Environment :: Console",
-        'Intended Audience :: Developers',
-        'Intended Audience :: System Administrators',
-        'Operating System :: OS Independent',
-        'Programming Language :: Python :: 3',
-        'Programming Language :: Python :: 3.6',
-        'Programming Language :: Python :: 3.7',
-        'Programming Language :: Python :: 3.8',
-        'Programming Language :: Python :: 3.9',
-        'Topic :: System :: Networking',
-    ],
-    packages=find_packages(),
-    include_package_data=True,
-    package_data={
-        'sbws': get_package_data(),
-    },
-    data_files=get_data_files(),
-    keywords='tor onion bandwidth measurements scanner relay circuit',
-    python_requires='>=3.5',
-    entry_points={
-        'console_scripts': [
-            'sbws = sbws.sbws:main',
-        ]
-    },
-    install_requires=[
-        'stem>=1.7.0',
-        'requests[socks]',
-    ],
-    extras_require={
-        # vulture: find unused code
-        'dev': ['flake8', 'vulture'],
-        'test': ['tox', 'pytest', 'coverage', 'freezegun'],
-        # recommonmark: to make sphinx render markdown
-        'doc': ['sphinx', 'recommonmark', 'pylint'],
-    },
+setuptools.setup(
+    version=versioneer.get_version(), cmdclass=versioneer.get_cmdclass()
 )
diff --git a/tests/integration/run.sh b/tests/integration/run.sh
index 70ee5f2..90a5322 100755
--- a/tests/integration/run.sh
+++ b/tests/integration/run.sh
@@ -12,6 +12,7 @@ wget -O/dev/null http://127.0.0.1:28888/sbws.bin
 sbws -c tests/integration/sbws_testnet.ini scanner
 sbws -c tests/integration/sbws_testnet.ini generate
 # Run integration tests
-coverage run -a --rcfile=.coveragerc --source=sbws -m pytest -s tests/integration -vv
+python -m coverage run --append --module pytest -svv tests/integration
+
 sbws -c tests/integration/sbws_testnet.ini cleanup
 tests/integration/stop_chutney.sh
diff --git a/tox.ini b/tox.ini
index bb66836..5c6e2a2 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,27 +1,29 @@
 [tox]
 skip_missing_interpreters = True
-envlist = py{36, 37, 38, 39, 310}, inst, setup, integration, lint, stats, doc
+envlist =
+    py{36, 37, 38, 39, 310}
+    inst,
+    setup,
+    black,
+    isort,
+    flake8,
+    doc,
+    stats
 
-[travis]
-python =
-    3.6: py36, inst, setup, unit, integration, lint, doc
-    3.7: py37, inst, setup, unit, integration, lint, doc
-    3.8: py38, inst, setup, unit, integration, lint, doc
-    3.9: py39, inst, setup, unit, integration, lint, doc
-    nightly: pynightly, inst, setup, unit, integration, lint, doc
 
-; [testenv]
-# install_command can be removed when --process-dependency-links is not
-# needed anymore, and this section commented
-# install_command = pip install {opts} {packages}
+[testenv]
+; Installing with deps errors with versioneer
+; deps = .[test]
+skip_install = True
+commands =
+    pip install .[test]
+    ; Use python -m to use the binary from the virtualenv if it is also
+    ; installed in the system. Do not use {envbindir} since it would require
+    ; to install it in tox virtualenv
+    python -m coverage run --append --module pytest -svv tests/unit
 
 # test that it can be installed with custom commands and clean env
 [testenv:inst]
-skip_install = True
-commands =
-    # this will fail until --process-dependency-links is not needed
-    # it needs to be commented since error code will be still 1
-    - pip install .
 ignore_errors = True
 recreate = True
 
@@ -32,42 +34,48 @@ skip_install = True
 commands = python setup.py install
 recreate = True
 
-[testenv]
-deps = .[test]
-commands =
-    coverage run -a --rcfile={toxinidir}/.coveragerc --source=sbws -m pytest \
-        -s {toxinidir}/tests/unit -vv
-
 [testenv:integration]
 ignore_errors = True
 deps = .[test]
 whitelist_externals =
     bash
 commands =
-    # For some reason .[test] is not copying config.* files
-    pip install .
     bash -c tests/integration/run.sh {envtmpdir}/chutney
 
-[testenv:lint]
+[testenv:black]
+skip_install = True
+deps =
+  black
+commands =
+  black --check --diff sbws tests
+
+[testenv:isort]
+skip_install = True
+deps =
+  isort
+commands =
+  isort --check-only --diff sbws tests
+
+[testenv:flake8]
 skip_install = True
-deps = .[dev]
-commands = flake8 sbws scripts tests
+deps = flake8-docstrings
+commands =
+  flake8 sbws tests
 
 [testenv:clean]
 skip_install = True
-changedir={toxinidir}
 deps = coverage
-command = coverage erase
+changedir = {toxinidir}
+commands = python -m coverage erase
 
 [testenv:stats]
 skip_install = True
-changedir={toxinidir}
-deps = .[test]
+deps = coverage
 commands=
-    # nothing to combine while not using several python versions
-    # coverage combine
-    coverage report
-    coverage html
+    ; nothing to combine while not using several python versions
+    ; python -m coverage combine
+    python -m coverage report
+    python -m coverage html
 
 [testenv:doc]
 deps = .[doc]
@@ -75,11 +83,11 @@ whitelist_externals = make
 changedir = docs
 commands =
     make html
-    # this requires build the pdf images
-    # make latexpdf
-    make man
+    ; this requires build the pdf images
+    ; make latexpdf
+    ; make man
 
-# this requires Internet, it should not be in envlist
+; this requires Internet, it should not be in envlist
 [testenv:doclinks]
 deps = .[doc]
 whitelist_externals = make
diff --git a/versioneer.py b/versioneer.py
index 64fea1c..1040c21 100644
--- a/versioneer.py
+++ b/versioneer.py
@@ -1,5 +1,5 @@
 
-# Version: 0.18
+# Version: 0.19
 
 """The Versioneer - like a rocketeer, but for versions.
 
@@ -7,16 +7,12 @@ The Versioneer
 ==============
 
 * like a rocketeer, but for versions!
-* https://github.com/warner/python-versioneer
+* https://github.com/python-versioneer/python-versioneer
 * Brian Warner
 * License: Public Domain
-* Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6, and pypy
-* [![Latest Version]
-(https://pypip.in/version/versioneer/badge.svg?style=flat)
-](https://pypi.python.org/pypi/versioneer/)
-* [![Build Status]
-(https://travis-ci.org/warner/python-versioneer.png?branch=master)
-](https://travis-ci.org/warner/python-versioneer)
+* Compatible with: Python 3.6, 3.7, 3.8, 3.9 and pypy3
+* [![Latest Version][pypi-image]][pypi-url]
+* [![Build Status][travis-image]][travis-url]
 
 This is a tool for managing a recorded version number in distutils-based
 python projects. The goal is to remove the tedious and error-prone "update
@@ -27,9 +23,10 @@ system, and maybe making new tarballs.
 
 ## Quick Install
 
-* `pip install versioneer` to somewhere to your $PATH
-* add a `[versioneer]` section to your setup.cfg (see below)
+* `pip install versioneer` to somewhere in your $PATH
+* add a `[versioneer]` section to your setup.cfg (see [Install](INSTALL.md))
 * run `versioneer install` in your source tree, commit the results
+* Verify version information with `python setup.py version`
 
 ## Version Identifiers
 
@@ -61,7 +58,7 @@ version 1.3). Many VCS systems can report a description that captures this,
 for example `git describe --tags --dirty --always` reports things like
 "0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the
 0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has
-uncommitted changes.
+uncommitted changes).
 
 The version identifier is used for multiple purposes:
 
@@ -166,7 +163,7 @@ which may help identify what went wrong).
 
 Some situations are known to cause problems for Versioneer. This details the
 most significant ones. More can be found on Github
-[issues page](https://github.com/warner/python-versioneer/issues).
+[issues page](https://github.com/python-versioneer/python-versioneer/issues).
 
 ### Subprojects
 
@@ -180,7 +177,7 @@ two common reasons why `setup.py` might not be in the root:
   `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI
   distributions (and upload multiple independently-installable tarballs).
 * Source trees whose main purpose is to contain a C library, but which also
-  provide bindings to Python (and perhaps other langauges) in subdirectories.
+  provide bindings to Python (and perhaps other languages) in subdirectories.
 
 Versioneer will look for `.git` in parent directories, and most operations
 should get the right version string. However `pip` and `setuptools` have bugs
@@ -194,9 +191,9 @@ work too.
 Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in
 some later version.
 
-[Bug #38](https://github.com/warner/python-versioneer/issues/38) is tracking
+[Bug #38](https://github.com/python-versioneer/python-versioneer/issues/38) is tracking
 this issue. The discussion in
-[PR #61](https://github.com/warner/python-versioneer/pull/61) describes the
+[PR #61](https://github.com/python-versioneer/python-versioneer/pull/61) describes the
 issue from the Versioneer side in more detail.
 [pip PR#3176](https://github.com/pypa/pip/pull/3176) and
 [pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve
@@ -224,22 +221,10 @@ regenerated while a different version is checked out. Many setup.py commands
 cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into
 a different virtualenv), so this can be surprising.
 
-[Bug #83](https://github.com/warner/python-versioneer/issues/83) describes
+[Bug #83](https://github.com/python-versioneer/python-versioneer/issues/83) describes
 this one, but upgrading to a newer version of setuptools should probably
 resolve it.
 
-### Unicode version strings
-
-While Versioneer works (and is continually tested) with both Python 2 and
-Python 3, it is not entirely consistent with bytes-vs-unicode distinctions.
-Newer releases probably generate unicode version strings on py2. It's not
-clear that this is wrong, but it may be surprising for applications when then
-write these strings to a network connection or include them in bytes-oriented
-APIs like cryptographic checksums.
-
-[Bug #71](https://github.com/warner/python-versioneer/issues/71) investigates
-this question.
-
 
 ## Updating Versioneer
 
@@ -265,6 +250,12 @@ installation by editing setup.py . Alternatively, it might go the other
 direction and include code from all supported VCS systems, reducing the
 number of intermediate scripts.
 
+## Similar projects
+
+* [setuptools_scm](https://github.com/pypa/setuptools_scm/) - a non-vendored build-time
+  dependency
+* [minver](https://github.com/jbweston/miniver) - a lightweight reimplementation of
+  versioneer
 
 ## License
 
@@ -274,13 +265,15 @@ Specifically, both are released under the Creative Commons "Public Domain
 Dedication" license (CC0-1.0), as described in
 https://creativecommons.org/publicdomain/zero/1.0/ .
 
+[pypi-image]: https://img.shields.io/pypi/v/versioneer.svg
+[pypi-url]: https://pypi.python.org/pypi/versioneer/
+[travis-image]:
+https://img.shields.io/travis/com/python-versioneer/python-versioneer.svg
+[travis-url]: https://travis-ci.com/github/python-versioneer/python-versioneer
+
 """
 
-from __future__ import print_function
-try:
-    import configparser
-except ImportError:
-    import ConfigParser as configparser
+import configparser
 import errno
 import json
 import os
@@ -339,9 +332,9 @@ def get_config_from_root(root):
     # configparser.NoOptionError (if it lacks "VCS="). See the docstring at
     # the top of versioneer.py for instructions on writing your setup.cfg .
     setup_cfg = os.path.join(root, "setup.cfg")
-    parser = configparser.SafeConfigParser()
+    parser = configparser.ConfigParser()
     with open(setup_cfg, "r") as f:
-        parser.readfp(f)
+        parser.read_file(f)
     VCS = parser.get("versioneer", "VCS")  # mandatory
 
     def get(parser, name):
@@ -371,7 +364,7 @@ HANDLERS = {}
 
 
 def register_vcs_handler(vcs, method):  # decorator
-    """Decorator to mark a method as the handler for a particular VCS."""
+    """Create decorator to mark a method as the handler of a VCS."""
     def decorate(f):
         """Store f in HANDLERS[vcs][method]."""
         if vcs not in HANDLERS:
@@ -407,9 +400,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
         if verbose:
             print("unable to find command, tried %s" % (commands,))
         return None, None
-    stdout = p.communicate()[0].strip()
-    if sys.version_info[0] >= 3:
-        stdout = stdout.decode()
+    stdout = p.communicate()[0].strip().decode()
     if p.returncode != 0:
         if verbose:
             print("unable to run %s (error)" % dispcmd)
@@ -418,7 +409,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
     return stdout, p.returncode
 
 
-LONG_VERSION_PY['git'] = '''
+LONG_VERSION_PY['git'] = r'''
 # This file helps to compute a version number in source trees obtained from
 # git-archive tarball (such as those provided by githubs download-from-tag
 # feature). Distribution tarballs (built by setup.py sdist) and build
@@ -426,7 +417,7 @@ LONG_VERSION_PY['git'] = '''
 # that just contains the computed version number.
 
 # This file is released into the public domain. Generated by
-# versioneer-0.18 (https://github.com/warner/python-versioneer)
+# versioneer-0.19 (https://github.com/python-versioneer/python-versioneer)
 
 """Git implementation of _version.py."""
 
@@ -477,7 +468,7 @@ HANDLERS = {}
 
 
 def register_vcs_handler(vcs, method):  # decorator
-    """Decorator to mark a method as the handler for a particular VCS."""
+    """Create decorator to mark a method as the handler of a VCS."""
     def decorate(f):
         """Store f in HANDLERS[vcs][method]."""
         if vcs not in HANDLERS:
@@ -513,9 +504,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
         if verbose:
             print("unable to find command, tried %%s" %% (commands,))
         return None, None
-    stdout = p.communicate()[0].strip()
-    if sys.version_info[0] >= 3:
-        stdout = stdout.decode()
+    stdout = p.communicate()[0].strip().decode()
     if p.returncode != 0:
         if verbose:
             print("unable to run %%s (error)" %% dispcmd)
@@ -585,6 +574,10 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose):
         raise NotThisMethod("no keywords at all, weird")
     date = keywords.get("date")
     if date is not None:
+        # Use only the last line.  Previous lines may contain GPG signature
+        # information.
+        date = date.splitlines()[-1]
+
         # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant
         # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601
         # -like" string, which we must then edit to make compliant), because
@@ -720,6 +713,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
     # commit date: see ISO-8601 comment in git_versions_from_keywords()
     date = run_command(GITS, ["show", "-s", "--format=%%ci", "HEAD"],
                        cwd=root)[0].strip()
+    # Use only the last line.  Previous lines may contain GPG signature
+    # information.
+    date = date.splitlines()[-1]
     pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
 
     return pieces
@@ -758,18 +754,18 @@ def render_pep440(pieces):
 
 
 def render_pep440_pre(pieces):
-    """TAG[.post.devDISTANCE] -- No -dirty.
+    """TAG[.post0.devDISTANCE] -- No -dirty.
 
     Exceptions:
-    1: no tags. 0.post.devDISTANCE
+    1: no tags. 0.post0.devDISTANCE
     """
     if pieces["closest-tag"]:
         rendered = pieces["closest-tag"]
         if pieces["distance"]:
-            rendered += ".post.dev%%d" %% pieces["distance"]
+            rendered += ".post0.dev%%d" %% pieces["distance"]
     else:
         # exception #1
-        rendered = "0.post.dev%%d" %% pieces["distance"]
+        rendered = "0.post0.dev%%d" %% pieces["distance"]
     return rendered
 
 
@@ -805,7 +801,7 @@ def render_pep440_old(pieces):
 
     The ".dev0" means dirty.
 
-    Eexceptions:
+    Exceptions:
     1: no tags. 0.postDISTANCE[.dev0]
     """
     if pieces["closest-tag"]:
@@ -977,6 +973,10 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose):
         raise NotThisMethod("no keywords at all, weird")
     date = keywords.get("date")
     if date is not None:
+        # Use only the last line.  Previous lines may contain GPG signature
+        # information.
+        date = date.splitlines()[-1]
+
         # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant
         # datestamp. However we prefer "%ci" (which expands to an "ISO-8601
         # -like" string, which we must then edit to make compliant), because
@@ -1112,6 +1112,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
     # commit date: see ISO-8601 comment in git_versions_from_keywords()
     date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"],
                        cwd=root)[0].strip()
+    # Use only the last line.  Previous lines may contain GPG signature
+    # information.
+    date = date.splitlines()[-1]
     pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
 
     return pieces
@@ -1181,7 +1184,7 @@ def versions_from_parentdir(parentdir_prefix, root, verbose):
 
 
 SHORT_VERSION_PY = """
-# This file was generated by 'versioneer.py' (0.18) from
+# This file was generated by 'versioneer.py' (0.19) from
 # revision-control system data, or from the parent directory name of an
 # unpacked source archive. Distribution tarballs contain a pre-generated copy
 # of this file.
@@ -1259,18 +1262,18 @@ def render_pep440(pieces):
 
 
 def render_pep440_pre(pieces):
-    """TAG[.post.devDISTANCE] -- No -dirty.
+    """TAG[.post0.devDISTANCE] -- No -dirty.
 
     Exceptions:
-    1: no tags. 0.post.devDISTANCE
+    1: no tags. 0.post0.devDISTANCE
     """
     if pieces["closest-tag"]:
         rendered = pieces["closest-tag"]
         if pieces["distance"]:
-            rendered += ".post.dev%d" % pieces["distance"]
+            rendered += ".post0.dev%d" % pieces["distance"]
     else:
         # exception #1
-        rendered = "0.post.dev%d" % pieces["distance"]
+        rendered = "0.post0.dev%d" % pieces["distance"]
     return rendered
 
 
@@ -1306,7 +1309,7 @@ def render_pep440_old(pieces):
 
     The ".dev0" means dirty.
 
-    Eexceptions:
+    Exceptions:
     1: no tags. 0.postDISTANCE[.dev0]
     """
     if pieces["closest-tag"]:
@@ -1480,8 +1483,12 @@ def get_version():
     return get_versions()["version"]
 
 
-def get_cmdclass():
-    """Get the custom setuptools/distutils subclasses used by Versioneer."""
+def get_cmdclass(cmdclass=None):
+    """Get the custom setuptools/distutils subclasses used by Versioneer.
+
+    If the package uses a different cmdclass (e.g. one from numpy), it
+    should be provide as an argument.
+    """
     if "versioneer" in sys.modules:
         del sys.modules["versioneer"]
         # this fixes the "python setup.py develop" case (also 'install' and
@@ -1495,9 +1502,9 @@ def get_cmdclass():
         # parent is protected against the child's "import versioneer". By
         # removing ourselves from sys.modules here, before the child build
         # happens, we protect the child from the parent's versioneer too.
-        # Also see https://github.com/warner/python-versioneer/issues/52
+        # Also see https://github.com/python-versioneer/python-versioneer/issues/52
 
-    cmds = {}
+    cmds = {} if cmdclass is None else cmdclass.copy()
 
     # we add "version" to both distutils and setuptools
     from distutils.core import Command
@@ -1539,7 +1546,9 @@ def get_cmdclass():
     #  setup.py egg_info -> ?
 
     # we override different "build_py" commands for both environments
-    if "setuptools" in sys.modules:
+    if 'build_py' in cmds:
+        _build_py = cmds['build_py']
+    elif "setuptools" in sys.modules:
         from setuptools.command.build_py import build_py as _build_py
     else:
         from distutils.command.build_py import build_py as _build_py
@@ -1559,6 +1568,31 @@ def get_cmdclass():
                 write_to_version_file(target_versionfile, versions)
     cmds["build_py"] = cmd_build_py
 
+    if "setuptools" in sys.modules:
+        from setuptools.command.build_ext import build_ext as _build_ext
+    else:
+        from distutils.command.build_ext import build_ext as _build_ext
+
+    class cmd_build_ext(_build_ext):
+        def run(self):
+            root = get_root()
+            cfg = get_config_from_root(root)
+            versions = get_versions()
+            _build_ext.run(self)
+            if self.inplace:
+                # build_ext --inplace will only build extensions in
+                # build/lib<..> dir with no _version.py to write to.
+                # As in place builds will already have a _version.py
+                # in the module dir, we do not need to write one.
+                return
+            # now locate _version.py in the new build/ directory and replace
+            # it with an updated value
+            target_versionfile = os.path.join(self.build_lib,
+                                              cfg.versionfile_source)
+            print("UPDATING %s" % target_versionfile)
+            write_to_version_file(target_versionfile, versions)
+    cmds["build_ext"] = cmd_build_ext
+
     if "cx_Freeze" in sys.modules:  # cx_freeze enabled?
         from cx_Freeze.dist import build_exe as _build_exe
         # nczeczulin reports that py2exe won't like the pep440-style string
@@ -1592,10 +1626,7 @@ def get_cmdclass():
         del cmds["build_py"]
 
     if 'py2exe' in sys.modules:  # py2exe enabled?
-        try:
-            from py2exe.distutils_buildexe import py2exe as _py2exe  # py3
-        except ImportError:
-            from py2exe.build_exe import py2exe as _py2exe  # py2
+        from py2exe.distutils_buildexe import py2exe as _py2exe
 
         class cmd_py2exe(_py2exe):
             def run(self):
@@ -1620,7 +1651,9 @@ def get_cmdclass():
         cmds["py2exe"] = cmd_py2exe
 
     # we override different "sdist" commands for both environments
-    if "setuptools" in sys.modules:
+    if 'sdist' in cmds:
+        _sdist = cmds['sdist']
+    elif "setuptools" in sys.modules:
         from setuptools.command.sdist import sdist as _sdist
     else:
         from distutils.command.sdist import sdist as _sdist
@@ -1695,7 +1728,7 @@ del get_versions
 
 
 def do_setup():
-    """Main VCS-independent setup function for installing Versioneer."""
+    """Do main VCS-independent setup function for installing Versioneer."""
     root = get_root()
     try:
         cfg = get_config_from_root(root)





More information about the tor-commits mailing list