Imported Upstream version 44.1.0 upstream/44.1.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 29 Dec 2020 22:04:48 +0000 (07:04 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 29 Dec 2020 22:04:48 +0000 (07:04 +0900)
25 files changed:
.bumpversion.cfg
.travis.yml
CHANGES.rst
appveyor.yml
azure-pipelines.yml [new file with mode: 0644]
docs/conf.py
docs/developer-guide.txt
docs/releases.txt
setup.cfg
setuptools/build_meta.py
setuptools/command/build_ext.py
setuptools/command/develop.py
setuptools/command/easy_install.py
setuptools/command/egg_info.py
setuptools/command/sdist.py
setuptools/command/test.py
setuptools/command/upload_docs.py
setuptools/dist.py
setuptools/tests/test_build_meta.py
setuptools/tests/test_develop.py
setuptools/tests/test_sdist.py
setuptools/tests/test_setopt.py
tools/finalize.py [new file with mode: 0644]
tools/tox_pip.py
tox.ini

index e1bfa89..c8c9f54 100644 (file)
@@ -1,7 +1,6 @@
 [bumpversion]
-current_version = 44.0.0
+current_version = 44.1.0
 commit = True
 tag = True
 
 [bumpversion:file:setup.cfg]
-
index 501a0b6..3ce1bf0 100644 (file)
@@ -27,6 +27,9 @@ jobs:
     if: tag IS present
     script: tox -e release
     after_success: skip
+  allow_failures:
+  # suppress failures due to pypa/setuptools#2000
+  - python: pypy3
 
 cache: pip
 
@@ -41,8 +44,6 @@ install:
 - pip freeze --all
 - env
 
-# update egg_info based on setup.py in checkout
-- python bootstrap.py
 - "! grep pyc setuptools.egg-info/SOURCES.txt"
 
 script:
index 109a3f4..83cd8c7 100644 (file)
@@ -1,3 +1,11 @@
+v44.1.0
+-------
+
+* #1704: Set sys.argv[0] in setup script run by build_meta.__legacy__
+* #1959: Fix for Python 4: replace unsafe six.PY3 with six.PY2
+* #1994: Fixed a bug in the "setuptools.finalize_distribution_options" hook that lead to ignoring the order attribute of entry points managed by this hook.
+
+
 v44.0.0
 -------
 
index 0881806..02fe1ee 100644 (file)
@@ -28,7 +28,6 @@ test_script:
   - python -m pip install --disable-pip-version-check --upgrade pip setuptools wheel
   - pip install --upgrade tox tox-venv virtualenv
   - pip freeze --all
-  - python bootstrap.py
   - tox -- --cov
 
 after_test:
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
new file mode 100644 (file)
index 0000000..3e80bf4
--- /dev/null
@@ -0,0 +1,71 @@
+# Create the project in Azure with:
+# az devops project create --name $name --organization https://dev.azure.com/$org/ --visibility public
+# then configure the pipelines (through web UI)
+
+trigger:
+  branches:
+    include:
+    - '*'
+  tags:
+    include:
+    - '*'
+
+pool:
+  vmimage: 'Ubuntu-18.04'
+
+variables:
+- group: Azure secrets
+
+stages:
+- stage: Test
+  jobs:
+
+  - job: 'Test'
+    strategy:
+      matrix:
+        Python36:
+          python.version: '3.6'
+        Python38:
+          python.version: '3.8'
+      maxParallel: 4
+
+    steps:
+    - task: UsePythonVersion@0
+      inputs:
+        versionSpec: '$(python.version)'
+        architecture: 'x64'
+
+    - script: python -m pip install tox
+      displayName: 'Install tox'
+
+    - script: |
+        tox -- --junit-xml=test-results.xml
+      displayName: 'run tests'
+
+    - task: PublishTestResults@2
+      inputs:
+        testResultsFiles: '**/test-results.xml'
+        testRunTitle: 'Python $(python.version)'
+      condition: succeededOrFailed()
+
+- stage: Publish
+  dependsOn: Test
+  jobs:
+  - job: 'Publish'
+
+    steps:
+    - task: UsePythonVersion@0
+      inputs:
+        versionSpec: '3.8'
+        architecture: 'x64'
+
+    - script: python -m pip install tox
+      displayName: 'Install tox'
+
+    - script: |
+        tox -e release
+      env:
+        TWINE_PASSWORD: $(PyPI-token)
+      displayName: 'publish to PyPI'
+
+  condition: contains(variables['Build.SourceBranch'], 'tags')
index cbd19fb..6f6ae13 100644 (file)
@@ -26,7 +26,7 @@ import os
 # hack to run the bootstrap script so that jaraco.packaging.sphinx
 # can invoke setup.py
 'READTHEDOCS' in os.environ and subprocess.check_call(
-    [sys.executable, 'bootstrap.py'],
+    [sys.executable, '-m', 'bootstrap'],
     cwd=os.path.join(os.path.dirname(__file__), os.path.pardir),
 )
 
index d145fba..0b4ae4d 100644 (file)
@@ -104,12 +104,8 @@ from the command line after pushing a new branch.
 Testing
 -------
 
-The primary tests are run using tox. To run the tests, first create the metadata
-needed to run the tests::
-
-    $ python bootstrap.py
-
-Then make sure you have tox installed, and invoke it::
+The primary tests are run using tox.  Make sure you have tox installed,
+and invoke it::
 
     $ tox
 
index 98ba39e..35b415c 100644 (file)
@@ -3,39 +3,13 @@ Release Process
 ===============
 
 In order to allow for rapid, predictable releases, Setuptools uses a
-mechanical technique for releases, enacted by Travis following a
-successful build of a tagged release per
-`PyPI deployment <https://docs.travis-ci.com/user/deployment/pypi>`_.
-
-Prior to cutting a release, please use `towncrier`_ to update
-``CHANGES.rst`` to summarize the changes since the last release.
-To update the changelog:
-
-1. Install towncrier via ``pip install towncrier`` if not already installed.
-2. Preview the new ``CHANGES.rst`` entry by running
-   ``towncrier --draft --version {new.version.number}`` (enter the desired
-   version number for the next release).  If any changes are needed, make
-   them and generate a new preview until the output is acceptable.  Run
-   ``git add`` for any modified files.
-3. Run ``towncrier --version {new.version.number}`` to stage the changelog
-   updates in git.
-4. Verify that there are no remaining ``changelog.d/*.rst`` files.  If a
-   file was named incorrectly, it may be ignored by towncrier.
-5. Review the updated ``CHANGES.rst`` file.  If any changes are needed,
-   make the edits and stage them via ``git add CHANGES.rst``.
-
-Once the changelog edits are staged and ready to commit, cut a release by
-installing and running ``bump2version --allow-dirty {part}`` where ``part``
-is major, minor, or patch based on the scope of the changes in the
-release. Then, push the commits to the master branch::
-
-    $ git push origin master
-    $ git push --tags
-
-If tests pass, the release will be uploaded to PyPI (from the Python 3.6
-tests).
-
-.. _towncrier: https://pypi.org/project/towncrier/
+mechanical technique for releases, enacted on tagged commits by
+continuous integration.
+
+To finalize a release, run ``tox -e finalize``, review, then push
+the changes.
+
+If tests pass, the release will be uploaded to PyPI.
 
 Release Frequency
 -----------------
index ecef860..cb5ae73 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -19,7 +19,7 @@ universal = 1
 
 [metadata]
 name = setuptools
-version = 44.0.0
+version = 44.1.0
 description = Easily download, build, install, upgrade, and uninstall Python packages
 author = Python Packaging Authority
 author_email = distutils-sig@python.org
index 10c4b52..eb9e815 100644 (file)
@@ -232,6 +232,12 @@ class _BuildMetaLegacyBackend(_BuildMetaBackend):
         if script_dir not in sys.path:
             sys.path.insert(0, script_dir)
 
+        # Some setup.py scripts (e.g. in pygame and numpy) use sys.argv[0] to
+        # get the directory of the source code. They expect it to refer to the
+        # setup.py script.
+        sys_argv_0 = sys.argv[0]
+        sys.argv[0] = setup_script
+
         try:
             super(_BuildMetaLegacyBackend,
                   self).run_setup(setup_script=setup_script)
@@ -242,6 +248,7 @@ class _BuildMetaLegacyBackend(_BuildMetaBackend):
             # the original path so that the path manipulation does not persist
             # within the hook after run_setup is called.
             sys.path[:] = sys_path
+            sys.argv[0] = sys_argv_0
 
 # The primary backend
 _BACKEND = _BuildMetaBackend()
index daa8e4f..1b51e04 100644 (file)
@@ -113,7 +113,7 @@ class build_ext(_build_ext):
         if fullname in self.ext_map:
             ext = self.ext_map[fullname]
             use_abi3 = (
-                six.PY3
+                not six.PY2
                 and getattr(ext, 'py_limited_api')
                 and get_abi3_suffix()
             )
index 009e4f9..b561924 100644 (file)
@@ -108,7 +108,7 @@ class develop(namespaces.DevelopInstaller, easy_install):
         return path_to_setup
 
     def install_for_development(self):
-        if six.PY3 and getattr(self.distribution, 'use_2to3', False):
+        if not six.PY2 and getattr(self.distribution, 'use_2to3', False):
             # If we run 2to3 we can not do this inplace:
 
             # Ensure metadata is up-to-date
index 09066f8..426301d 100644 (file)
@@ -1567,7 +1567,7 @@ def get_exe_prefixes(exe_filename):
                 continue
             if parts[0].upper() in ('PURELIB', 'PLATLIB'):
                 contents = z.read(name)
-                if six.PY3:
+                if not six.PY2:
                     contents = contents.decode()
                 for pth in yield_lines(contents):
                     pth = pth.strip().replace('\\', '/')
index 5d8f451..a5c5a2f 100644 (file)
@@ -266,7 +266,7 @@ class egg_info(InfoCommon, Command):
         to the file.
         """
         log.info("writing %s to %s", what, filename)
-        if six.PY3:
+        if not six.PY2:
             data = data.encode("utf-8")
         if not self.dry_run:
             f = open(filename, 'wb')
index a851453..8c3438e 100644 (file)
@@ -207,7 +207,7 @@ class sdist(sdist_add_defaults, orig.sdist):
         manifest = open(self.manifest, 'rb')
         for line in manifest:
             # The manifest must contain UTF-8. See #303.
-            if six.PY3:
+            if not six.PY2:
                 try:
                     line = line.decode('UTF-8')
                 except UnicodeDecodeError:
index c148b38..f6470e9 100644 (file)
@@ -129,7 +129,7 @@ class test(Command):
 
     @contextlib.contextmanager
     def project_on_sys_path(self, include_dists=[]):
-        with_2to3 = six.PY3 and getattr(self.distribution, 'use_2to3', False)
+        with_2to3 = not six.PY2 and getattr(self.distribution, 'use_2to3', False)
 
         if with_2to3:
             # If we run 2to3 we can not do this inplace:
@@ -240,7 +240,7 @@ class test(Command):
         # Purge modules under test from sys.modules. The test loader will
         # re-import them from the build location. Required when 2to3 is used
         # with namespace packages.
-        if six.PY3 and getattr(self.distribution, 'use_2to3', False):
+        if not six.PY2 and getattr(self.distribution, 'use_2to3', False):
             module = self.test_suite.split('.')[0]
             if module in _namespace_packages:
                 del_modules = []
index 07aa564..130a0cb 100644 (file)
@@ -24,7 +24,7 @@ from .upload import upload
 
 
 def _encode(s):
-    errors = 'surrogateescape' if six.PY3 else 'strict'
+    errors = 'strict' if six.PY2 else 'surrogateescape'
     return s.encode('utf-8', errors)
 
 
@@ -153,7 +153,7 @@ class upload_docs(upload):
         # set up the authentication
         credentials = _encode(self.username + ':' + self.password)
         credentials = standard_b64encode(credentials)
-        if six.PY3:
+        if not six.PY2:
             credentials = credentials.decode('ascii')
         auth = "Basic " + credentials
 
index 1ba262e..f6453a0 100644 (file)
@@ -571,7 +571,7 @@ class Distribution(_Distribution):
         from setuptools.extern.six.moves.configparser import ConfigParser
 
         # Ignore install directory options if we have a venv
-        if six.PY3 and sys.prefix != sys.base_prefix:
+        if not six.PY2 and sys.prefix != sys.base_prefix:
             ignore_options = [
                 'install-base', 'install-platbase', 'install-lib',
                 'install-platlib', 'install-purelib', 'install-headers',
@@ -593,7 +593,7 @@ class Distribution(_Distribution):
             with io.open(filename, encoding='utf-8') as reader:
                 if DEBUG:
                     self.announce("  reading {filename}".format(**locals()))
-                (parser.read_file if six.PY3 else parser.readfp)(reader)
+                (parser.readfp if six.PY2 else parser.read_file)(reader)
             for section in parser.sections():
                 options = parser.options(section)
                 opt_dict = self.get_option_dict(section)
@@ -636,7 +636,7 @@ class Distribution(_Distribution):
 
         Ref #1653
         """
-        if six.PY3:
+        if not six.PY2:
             return val
         try:
             return val.encode()
@@ -731,13 +731,13 @@ class Distribution(_Distribution):
         to influence the order of execution. Smaller numbers
         go first and the default is 0.
         """
-        hook_key = 'setuptools.finalize_distribution_options'
+        group = 'setuptools.finalize_distribution_options'
 
         def by_order(hook):
             return getattr(hook, 'order', 0)
-        eps = pkg_resources.iter_entry_points(hook_key)
+        eps = map(lambda e: e.load(), pkg_resources.iter_entry_points(group))
         for ep in sorted(eps, key=by_order):
-            ep.load()(self)
+            ep(self)
 
     def _finalize_setup_keywords(self):
         for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
index 326b4f5..d68444f 100644 (file)
@@ -406,6 +406,28 @@ class TestBuildMetaBackend:
 
         assert expected == sorted(actual)
 
+    _sys_argv_0_passthrough = {
+        'setup.py': DALS("""
+            import os
+            import sys
+
+            __import__('setuptools').setup(
+                name='foo',
+                version='0.0.0',
+            )
+
+            sys_argv = os.path.abspath(sys.argv[0])
+            file_path = os.path.abspath('setup.py')
+            assert sys_argv == file_path
+            """)
+    }
+
+    def test_sys_argv_passthrough(self, tmpdir_cwd):
+        build_files(self._sys_argv_0_passthrough)
+        build_backend = self.get_build_backend()
+        with pytest.raises(AssertionError):
+            build_backend.build_sdist("temp")
+
 
 class TestBuildMetaLegacyBackend(TestBuildMetaBackend):
     backend_name = 'setuptools.build_meta:__legacy__'
@@ -417,3 +439,9 @@ class TestBuildMetaLegacyBackend(TestBuildMetaBackend):
 
         build_backend = self.get_build_backend()
         build_backend.build_sdist("temp")
+
+    def test_sys_argv_passthrough(self, tmpdir_cwd):
+        build_files(self._sys_argv_0_passthrough)
+
+        build_backend = self.get_build_backend()
+        build_backend.build_sdist("temp")
index 00d4bd9..792975f 100644 (file)
@@ -95,7 +95,7 @@ class TestDevelop:
         with io.open(fn) as init_file:
             init = init_file.read().strip()
 
-        expected = 'print("foo")' if six.PY3 else 'print "foo"'
+        expected = 'print "foo"' if six.PY2 else 'print("foo")'
         assert init == expected
 
     def test_console_scripts(self, tmpdir):
@@ -161,7 +161,7 @@ class TestNamespaces:
         reason="https://github.com/pypa/setuptools/issues/851",
     )
     @pytest.mark.skipif(
-        platform.python_implementation() == 'PyPy' and six.PY3,
+        platform.python_implementation() == 'PyPy' and not six.PY2,
         reason="https://github.com/pypa/setuptools/issues/1202",
     )
     def test_namespace_package_importable(self, tmpdir):
index 8538dd2..0bea53d 100644 (file)
@@ -51,7 +51,7 @@ def quiet():
 
 # Convert to POSIX path
 def posix(path):
-    if six.PY3 and not isinstance(path, str):
+    if not six.PY2 and not isinstance(path, str):
         return path.replace(os.sep.encode('ascii'), b'/')
     else:
         return path.replace(os.sep, '/')
@@ -329,7 +329,7 @@ class TestSdistTest:
             cmd.read_manifest()
 
         # The filelist should contain the UTF-8 filename
-        if six.PY3:
+        if not six.PY2:
             filename = filename.decode('utf-8')
         assert filename in cmd.filelist.files
 
@@ -383,7 +383,7 @@ class TestSdistTest:
         if sys.platform == 'darwin':
             filename = decompose(filename)
 
-        if six.PY3:
+        if not six.PY2:
             fs_enc = sys.getfilesystemencoding()
 
             if sys.platform == 'win32':
@@ -425,7 +425,19 @@ class TestSdistTest:
         with quiet():
             cmd.run()
 
-        if six.PY3:
+        if six.PY2:
+            # Under Python 2 there seems to be no decoded string in the
+            # filelist.  However, due to decode and encoding of the
+            # file name to get utf-8 Manifest the latin1 maybe excluded
+            try:
+                # fs_enc should match how one is expect the decoding to
+                # be proformed for the manifest output.
+                fs_enc = sys.getfilesystemencoding()
+                filename.decode(fs_enc)
+                assert filename in cmd.filelist.files
+            except UnicodeDecodeError:
+                filename not in cmd.filelist.files
+        else:
             # not all windows systems have a default FS encoding of cp1252
             if sys.platform == 'win32':
                 # Latin-1 is similar to Windows-1252 however
@@ -440,18 +452,6 @@ class TestSdistTest:
                 # The Latin-1 filename should have been skipped
                 filename = filename.decode('latin-1')
                 filename not in cmd.filelist.files
-        else:
-            # Under Python 2 there seems to be no decoded string in the
-            # filelist.  However, due to decode and encoding of the
-            # file name to get utf-8 Manifest the latin1 maybe excluded
-            try:
-                # fs_enc should match how one is expect the decoding to
-                # be proformed for the manifest output.
-                fs_enc = sys.getfilesystemencoding()
-                filename.decode(fs_enc)
-                assert filename in cmd.filelist.files
-            except UnicodeDecodeError:
-                filename not in cmd.filelist.files
 
     def test_pyproject_toml_in_sdist(self, tmpdir):
         """
index 3fb04fb..1b03895 100644 (file)
@@ -15,7 +15,7 @@ class TestEdit:
     def parse_config(filename):
         parser = configparser.ConfigParser()
         with io.open(filename, encoding='utf-8') as reader:
-            (parser.read_file if six.PY3 else parser.readfp)(reader)
+            (parser.readfp if six.PY2 else parser.read_file)(reader)
         return parser
 
     @staticmethod
diff --git a/tools/finalize.py b/tools/finalize.py
new file mode 100644 (file)
index 0000000..3b66341
--- /dev/null
@@ -0,0 +1,59 @@
+"""
+Finalize the repo for a release. Invokes towncrier and bumpversion.
+"""
+
+__requires__ = ['bump2version', 'towncrier']
+
+
+import subprocess
+import pathlib
+import re
+import sys
+
+
+def release_kind():
+    """
+    Determine which release to make based on the files in the
+    changelog.
+    """
+    # use min here as 'major' < 'minor' < 'patch'
+    return min(
+        'major' if 'breaking' in file.name else
+        'minor' if 'change' in file.name else
+        'patch'
+        for file in pathlib.Path('changelog.d').iterdir()
+    )
+
+
+bump_version_command = [
+    sys.executable,
+    '-m', 'bumpversion',
+    release_kind(),
+]
+
+
+def get_version():
+    cmd = bump_version_command + ['--dry-run', '--verbose']
+    out = subprocess.check_output(cmd, text=True)
+    return re.search('^new_version=(.*)', out, re.MULTILINE).group(1)
+
+
+def update_changelog():
+    cmd = [
+        sys.executable, '-m',
+        'towncrier',
+        '--version', get_version(),
+        '--yes',
+    ]
+    subprocess.check_call(cmd)
+
+
+def bump_version():
+    cmd = bump_version_command + ['--allow-dirty']
+    subprocess.check_call(cmd)
+
+
+if __name__ == '__main__':
+    print("Cutting release at", get_version())
+    update_changelog()
+    bump_version()
index 63518f9..ba77663 100644 (file)
@@ -1,31 +1,31 @@
-import os
-import shutil
 import subprocess
 import sys
-from glob import glob
 
-VIRTUAL_ENV = os.environ['VIRTUAL_ENV']
-TOX_PIP_DIR = os.path.join(VIRTUAL_ENV, 'pip')
+
+def remove_setuptools():
+    """
+    Remove setuptools from the current environment.
+    """
+    print("Removing setuptools")
+    cmd = [sys.executable, '-m', 'pip', 'uninstall', '-y', 'setuptools']
+    # set cwd to something other than '.' to avoid detecting
+    # '.' as the installed package.
+    subprocess.check_call(cmd, cwd='.tox')
+
+
+def bootstrap():
+    print("Running bootstrap")
+    cmd = [sys.executable, '-m', 'bootstrap']
+    subprocess.check_call(cmd)
 
 
 def pip(args):
-    # First things first, get a recent (stable) version of pip.
-    if not os.path.exists(TOX_PIP_DIR):
-        subprocess.check_call([sys.executable, '-m', 'pip',
-                               '--disable-pip-version-check',
-                               'install', '-t', TOX_PIP_DIR,
-                               'pip'])
-        shutil.rmtree(glob(os.path.join(TOX_PIP_DIR, 'pip-*.dist-info'))[0])
-    # And use that version.
-    pypath = os.environ.get('PYTHONPATH')
-    pypath = pypath.split(os.pathsep) if pypath is not None else []
-    pypath.insert(0, TOX_PIP_DIR)
-    os.environ['PYTHONPATH'] = os.pathsep.join(pypath)
-    # Fix call for setuptools editable install.
-    for n, a in enumerate(args):
-        if a == '.':
-            args[n] = os.getcwd()
-    subprocess.check_call([sys.executable, '-m', 'pip'] + args, cwd=TOX_PIP_DIR)
+    if '.' in args:
+        remove_setuptools()
+        bootstrap()
+
+    cmd = [sys.executable, '-m', 'pip'] + args
+    subprocess.check_call(cmd)
 
 
 if __name__ == '__main__':
diff --git a/tox.ini b/tox.ini
index 6a1af56..3fc6a56 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -1,20 +1,22 @@
-# Note: Run "python bootstrap.py" before running Tox, to generate metadata.
-#
 # To run Tox against all supported Python interpreters, you can set:
 #
 # export TOXENV='py27,py3{5,6,7,8},pypy,pypy3'
 
 [tox]
 envlist=python
+minversion = 3.2
+requires =
+       tox-pip-version >= 0.0.6
+       # workaround for #1998
+       virtualenv < 20
 
 [helpers]
-# Wrapper for calls to pip that make sure the version being used is a
-# up-to-date, and to prevent the current working directory from being
-# added to `sys.path`.
+# Custom pip behavior
 pip = python {toxinidir}/tools/tox_pip.py
 
 [testenv]
 deps=-r{toxinidir}/tests/requirements.txt
+pip_version = pip
 install_command = {[helpers]pip} install {opts} {packages}
 list_dependencies_command = {[helpers]pip} freeze --all
 setenv=COVERAGE_FILE={toxworkdir}/.coverage.{envname}
@@ -45,7 +47,7 @@ commands=codecov -X gcov --file {toxworkdir}/coverage.xml
 deps = -r{toxinidir}/docs/requirements.txt
 skip_install=True
 commands =
-    python {toxinidir}/bootstrap.py
+    python -m bootstrap
     sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/build/html
     sphinx-build -W -b man -d {envtmpdir}/doctrees docs docs/build/man
 
@@ -56,6 +58,14 @@ source=
 omit=
        */_vendor/*
 
+[testenv:finalize]
+skip_install = True
+deps =
+       towncrier
+       bump2version
+commands =
+       python tools/finalize.py
+
 [testenv:release]
 skip_install = True
 deps =