Commit f14930e6 authored by Jason R. Coombs's avatar Jason R. Coombs

Drop support for Python 2.6, removing lots of compatibility code for a leaner,...

Drop support for Python 2.6, removing lots of compatibility code for a leaner, cleaner codebase. Fixes #878.
parent ac999764
language: python
python:
- 2.6
- 2.7
- 3.3
- 3.4
......
v31.0.0
-------
* #878: Drop support for Python 2.6. Python 2.6 users should
rely on 'setuptools < 31dev'.
v30.3.0
-------
......
......@@ -17,9 +17,7 @@ The recommended way to bootstrap setuptools on any system is to download
operating systems have different recommended techniques to accomplish this
basic routine, so below are some examples to get you started.
Setuptools requires Python 2.6 or later. To install setuptools
on Python 2.4 or Python 2.5, use the `bootstrap script for Setuptools 1.x
<https://raw.githubusercontent.com/pypa/setuptools/bootstrap-py24/ez_setup.py>`_.
Setuptools requires Python 3.3 or later (or Python 2.7).
The link provided to ez_setup.py is a bookmark to bootstrap script for the
latest known stable release.
......
......@@ -35,7 +35,7 @@ Please see the `setuptools PyPI page <https://pypi.python.org/pypi/setuptools>`_
for download links and basic installation instructions for each of the
supported platforms.
You will need at least Python 2.6. An ``easy_install`` script will be
You will need at least Python 3.3 or 2.7. An ``easy_install`` script will be
installed in the normal location for Python scripts on your platform.
Note that the instructions on the setuptools PyPI page assume that you are
......@@ -305,8 +305,7 @@ Regardless of the technique used, the script(s) will be installed to a Scripts
directory (by default in the Python installation directory). It is recommended
for EasyInstall that you ensure this directory is in the PATH environment
variable. The easiest way to ensure the Scripts directory is in the PATH is
to run ``Tools\Scripts\win_add2path.py`` from the Python directory (requires
Python 2.6 or later).
to run ``Tools\Scripts\win_add2path.py`` from the Python directory.
Note that instead of changing your ``PATH`` to include the Python scripts
directory, you can also retarget the installation location for scripts so they
......@@ -987,21 +986,20 @@ The following section lists only the easiest and most relevant approaches [1]_.
`Use "virtualenv"`_
.. [1] There are older ways to achieve custom installation using various ``easy_install`` and ``setup.py install`` options, combined with ``PYTHONPATH`` and/or ``PYTHONUSERBASE`` alterations, but all of these are effectively deprecated by the User scheme brought in by `PEP-370`_ in Python 2.6.
.. [1] There are older ways to achieve custom installation using various ``easy_install`` and ``setup.py install`` options, combined with ``PYTHONPATH`` and/or ``PYTHONUSERBASE`` alterations, but all of these are effectively deprecated by the User scheme brought in by `PEP-370`_.
.. _PEP-370: http://www.python.org/dev/peps/pep-0370/
Use the "--user" option
~~~~~~~~~~~~~~~~~~~~~~~
With Python 2.6 came the User scheme for installation, which means that all
python distributions support an alternative install location that is specific to a user [2]_ [3]_.
Python provides a User scheme for installation, which means that all
python distributions support an alternative install location that is specific to a user [3]_.
The Default location for each OS is explained in the python documentation
for the ``site.USER_BASE`` variable. This mode of installation can be turned on by
specifying the ``--user`` option to ``setup.py install`` or ``easy_install``.
This approach serves the need to have a user-specific stash of packages.
.. [2] Prior to Python2.6, Mac OS X offered a form of the User scheme. That is now subsumed into the User scheme introduced in Python 2.6.
.. [3] Prior to the User scheme, there was the Home scheme, which is still available, but requires more effort than the User scheme to get packages recognized.
Use the "--user" option and customize "PYTHONUSERBASE"
......
......@@ -110,7 +110,7 @@ the need to create a directory just to store one file. This option is
other metadata. (In fact, setuptools itself never generates
``.egg-info`` files, either; the support for using files was added so
that the requirement could easily be satisfied by other tools, such
as the distutils in Python 2.5).
as distutils).
In addition to the ``PKG-INFO`` file, an egg's metadata directory may
also include files and directories representing various forms of
......
......@@ -622,8 +622,8 @@ Requirements Parsing
The "markers" in a requirement are used to specify when a requirement
should be installed -- the requirement will be installed if the marker
evaluates as true in the current environment. For example, specifying
``argparse;python_version<"2.7"`` will not install in an Python 2.7 or 3.3
environment, but will in a Python 2.6 environment.
``argparse;python_version<"3.0"`` will not install in an Python 3
environment, but will in a Python 2 environment.
``Requirement`` Methods and Attributes
--------------------------------------
......@@ -1660,19 +1660,7 @@ PEP 302 Utilities
-----------------
``get_importer(path_item)``
Retrieve a PEP 302 "importer" for the given path item (which need not
actually be on ``sys.path``). This routine simulates the PEP 302 protocol
for obtaining an "importer" object. It first checks for an importer for
the path item in ``sys.path_importer_cache``, and if not found it calls
each of the ``sys.path_hooks`` and caches the result if a good importer is
found. If no importer is found, this routine returns an ``ImpWrapper``
instance that wraps the builtin import machinery as a PEP 302-compliant
"importer" object. This ``ImpWrapper`` is *not* cached; instead a new
instance is returned each time.
(Note: When run under Python 2.5, this function is simply an alias for
``pkgutil.get_importer()``, and instead of ``pkg_resources.ImpWrapper``
instances, it may return ``pkgutil.ImpImporter`` instances.)
A deprecated alias for ``pkgutil.get_importer()``
File/Path Utilities
......
......@@ -3,7 +3,7 @@ Building and Distributing Packages with Setuptools
==================================================
``Setuptools`` is a collection of enhancements to the Python ``distutils``
(for Python 2.6 and up) that allow developers to more easily build and
that allow developers to more easily build and
distribute Python packages, especially ones that have dependencies on other
packages.
......
......@@ -1611,7 +1611,7 @@ class ZipManifests(dict):
Use a platform-specific path separator (os.sep) for the path keys
for compatibility with pypy on Windows.
"""
with ContextualZipFile(path) as zfile:
with zipfile.ZipFile(path) as zfile:
items = (
(
name.replace('/', os.sep),
......@@ -1644,26 +1644,6 @@ class MemoizedZipManifests(ZipManifests):
return self[path].manifest
class ContextualZipFile(zipfile.ZipFile):
"""
Supplement ZipFile class to support context manager for Python 2.6
"""
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.close()
def __new__(cls, *args, **kwargs):
"""
Construct a ZipFile or ContextualZipFile as appropriate
"""
if hasattr(zipfile.ZipFile, '__exit__'):
return zipfile.ZipFile(*args, **kwargs)
return super(ContextualZipFile, cls).__new__(cls)
class ZipProvider(EggProvider):
"""Resource support for zips and eggs"""
......@@ -1861,7 +1841,7 @@ class FileMetadata(EmptyProvider):
return metadata
def _warn_on_replacement(self, metadata):
# Python 2.6 and 3.2 compat for: replacement_char = '�'
# Python 2.7 compat for: replacement_char = '�'
replacement_char = b'\xef\xbf\xbd'.decode('utf-8')
if replacement_char in metadata:
tmpl = "{self.path} could not be properly decoded in UTF-8"
......
......@@ -385,10 +385,10 @@ Environment Markers
>>> em("sys_platform=='win32'") == (sys.platform=='win32')
True
>>> em("python_version >= '2.6'")
>>> em("python_version >= '2.7'")
True
>>> em("python_version > '2.5'")
>>> em("python_version > '2.6'")
True
>>> im("implementation_name=='cpython'")
......
......@@ -206,12 +206,10 @@ class TestDistro:
"""Extras are also evaluated as markers at resolution time."""
ad = pkg_resources.Environment([])
ws = WorkingSet([])
# Metadata needs to be native strings due to cStringIO behaviour in
# 2.6, so use str().
Foo = Distribution.from_filename(
"/foo_dir/Foo-1.2.dist-info",
metadata=Metadata(("METADATA", str("Provides-Extra: baz\n"
"Requires-Dist: quux; extra=='baz'")))
metadata=Metadata(("METADATA", "Provides-Extra: baz\n"
"Requires-Dist: quux; extra=='baz'"))
)
ad.add(Foo)
assert list(ws.resolve(parse_requirements("Foo"), ad)) == [Foo]
......@@ -224,12 +222,10 @@ class TestDistro:
"""Extras are also evaluated as markers at resolution time."""
ad = pkg_resources.Environment([])
ws = WorkingSet([])
# Metadata needs to be native strings due to cStringIO behaviour in
# 2.6, so use str().
Foo = Distribution.from_filename(
"/foo_dir/Foo-1.2.dist-info",
metadata=Metadata(("METADATA", str("Provides-Extra: baz-lightyear\n"
"Requires-Dist: quux; extra=='baz-lightyear'")))
metadata=Metadata(("METADATA", "Provides-Extra: baz-lightyear\n"
"Requires-Dist: quux; extra=='baz-lightyear'"))
)
ad.add(Foo)
assert list(ws.resolve(parse_requirements("Foo"), ad)) == [Foo]
......@@ -241,14 +237,12 @@ class TestDistro:
def test_marker_evaluation_with_multiple_extras(self):
ad = pkg_resources.Environment([])
ws = WorkingSet([])
# Metadata needs to be native strings due to cStringIO behaviour in
# 2.6, so use str().
Foo = Distribution.from_filename(
"/foo_dir/Foo-1.2.dist-info",
metadata=Metadata(("METADATA", str("Provides-Extra: baz\n"
metadata=Metadata(("METADATA", "Provides-Extra: baz\n"
"Requires-Dist: quux; extra=='baz'\n"
"Provides-Extra: bar\n"
"Requires-Dist: fred; extra=='bar'\n")))
"Requires-Dist: fred; extra=='bar'\n"))
)
ad.add(Foo)
quux = Distribution.from_filename("/foo_dir/quux-1.0.dist-info")
......@@ -261,22 +255,20 @@ class TestDistro:
def test_marker_evaluation_with_extras_loop(self):
ad = pkg_resources.Environment([])
ws = WorkingSet([])
# Metadata needs to be native strings due to cStringIO behaviour in
# 2.6, so use str().
a = Distribution.from_filename(
"/foo_dir/a-0.2.dist-info",
metadata=Metadata(("METADATA", str("Requires-Dist: c[a]")))
metadata=Metadata(("METADATA", "Requires-Dist: c[a]"))
)
b = Distribution.from_filename(
"/foo_dir/b-0.3.dist-info",
metadata=Metadata(("METADATA", str("Requires-Dist: c[b]")))
metadata=Metadata(("METADATA", "Requires-Dist: c[b]"))
)
c = Distribution.from_filename(
"/foo_dir/c-1.0.dist-info",
metadata=Metadata(("METADATA", str("Provides-Extra: a\n"
metadata=Metadata(("METADATA", "Provides-Extra: a\n"
"Requires-Dist: b;extra=='a'\n"
"Provides-Extra: b\n"
"Requires-Dist: foo;extra=='b'")))
"Requires-Dist: foo;extra=='b'"))
)
foo = Distribution.from_filename("/foo_dir/foo-0.1.dist-info")
for dist in (a, b, c, foo):
......
......@@ -145,7 +145,6 @@ setup_params = dict(
Intended Audience :: Developers
License :: OSI Approved :: MIT License
Operating System :: OS Independent
Programming Language :: Python :: 2.6
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.3
......@@ -156,7 +155,7 @@ setup_params = dict(
Topic :: System :: Systems Administration
Topic :: Utilities
""").strip().splitlines(),
python_requires='>=2.6,!=3.0.*,!=3.1.*,!=3.2.*',
python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*',
extras_require={
"ssl:sys_platform=='win32'": "wincertstore==0.2",
"certs": "certifi==2016.9.26",
......
......@@ -8,7 +8,7 @@ import posixpath
import contextlib
from distutils.errors import DistutilsError
from pkg_resources import ensure_directory, ContextualZipFile
from pkg_resources import ensure_directory
__all__ = [
"unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter",
......@@ -98,7 +98,7 @@ def unpack_zipfile(filename, extract_dir, progress_filter=default_filter):
if not zipfile.is_zipfile(filename):
raise UnrecognizedFormat("%s is not a zip file" % (filename,))
with ContextualZipFile(filename) as z:
with zipfile.ZipFile(filename) as z:
for info in z.infolist():
name = info.filename
......
......@@ -158,9 +158,7 @@ class egg_info(Command):
build tag. Install these keys in a deterministic order
to avoid arbitrary reordering on subsequent builds.
"""
# python 2.6 compatibility
odict = getattr(collections, 'OrderedDict', dict)
egg_info = odict()
egg_info = collections.OrderedDict()
# follow the order these keys would have been added
# when PYTHONHASHSEED=0
egg_info['tag_build'] = self.tags()
......
......@@ -50,13 +50,6 @@ class sdist(sdist_add_defaults, orig.sdist):
for cmd_name in self.get_sub_commands():
self.run_command(cmd_name)
# Call check_metadata only if no 'check' command
# (distutils <= 2.6)
import distutils.command
if 'check' not in distutils.command.__all__:
self.check_metadata()
self.make_distribution()
dist_files = getattr(self.distribution, 'dist_files', [])
......
......@@ -3,6 +3,7 @@ import operator
import sys
import contextlib
import itertools
import unittest
from distutils.errors import DistutilsOptionError
from unittest import TestLoader
......@@ -13,7 +14,6 @@ from pkg_resources import (resource_listdir, resource_exists, normalize_path,
working_set, _namespace_packages,
add_activation_listener, require, EntryPoint)
from setuptools import Command
from setuptools.py31compat import unittest_main
class ScanningLoader(TestLoader):
......@@ -225,12 +225,11 @@ class test(Command):
del_modules.append(name)
list(map(sys.modules.__delitem__, del_modules))
exit_kwarg = {} if sys.version_info < (2, 7) else {"exit": False}
unittest_main(
unittest.main(
None, None, self._argv,
testLoader=self._resolve_as_ep(self.test_loader),
testRunner=self._resolve_as_ep(self.test_runner),
**exit_kwarg
exit=False,
)
@property
......
......@@ -4,9 +4,9 @@ import os
import sys
from collections import defaultdict
from functools import partial
from importlib import import_module
from distutils.errors import DistutilsOptionError, DistutilsFileError
from setuptools.py26compat import import_module
from setuptools.extern.six import string_types
......
......@@ -7,8 +7,8 @@ import distutils.filelist
import platform
import types
import functools
from importlib import import_module
from .py26compat import import_module
from setuptools.extern import six
import setuptools
......
......@@ -27,7 +27,6 @@ from setuptools import ssl_support
from distutils import log
from distutils.errors import DistutilsError
from fnmatch import translate
from setuptools.py26compat import strip_fragment
from setuptools.py27compat import get_all_headers
EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.]+)$')
......@@ -707,7 +706,7 @@ class PackageIndex(Environment):
fp, info = None, None
try:
checker = HashChecker.from_url(url)
fp = self.open_url(strip_fragment(url))
fp = self.open_url(url)
if isinstance(fp, urllib.error.HTTPError):
raise DistutilsError(
"Can't download %s: %s %s" % (url, fp.code, fp.msg)
......
"""
Compatibility Support for Python 2.6 and earlier
"""
import sys
try:
from urllib.parse import splittag
except ImportError:
from urllib import splittag
def strip_fragment(url):
"""
In `Python 8280 <http://bugs.python.org/issue8280>`_, Python 2.7 and
later was patched to disregard the fragment when making URL requests.
Do the same for Python 2.6 and earlier.
"""
url, fragment = splittag(url)
return url
if sys.version_info >= (2, 7):
strip_fragment = lambda x: x
try:
from importlib import import_module
except ImportError:
def import_module(module_name):
return __import__(module_name, fromlist=['__name__'])
import sys
import unittest
__all__ = ['get_config_vars', 'get_path']
try:
......@@ -42,15 +39,3 @@ except ImportError:
except OSError: # removal errors are not the only possible
pass
self.name = None
unittest_main = unittest.main
_PY31 = (3, 1) <= sys.version_info[:2] < (3, 2)
if _PY31:
# on Python 3.1, translate testRunner==None to TextTestRunner
# for compatibility with Python 2.6, 2.7, and 3.2+
def unittest_main(*args, **kwargs):
if 'testRunner' in kwargs and kwargs['testRunner'] is None:
kwargs['testRunner'] = unittest.TextTestRunner
return unittest.main(*args, **kwargs)
......@@ -37,10 +37,6 @@ def _execfile(filename, globals, locals=None):
mode = 'rb'
with open(filename, mode) as stream:
script = stream.read()
# compile() function in Python 2.6 and 3.1 requires LF line endings.
if sys.version_info[:2] < (2, 7) or sys.version_info[:2] >= (3, 0) and sys.version_info[:2] < (3, 2):
script = script.replace(b'\r\n', b'\n')
script = script.replace(b'\r', b'\n')
if locals is None:
locals = globals
code = compile(script, filename, 'exec')
......
import sys
import tarfile
import contextlib
def _tarfile_open_ex(*args, **kwargs):
"""
Extend result as a context manager.
"""
return contextlib.closing(tarfile.open(*args, **kwargs))
if sys.version_info[:2] < (2, 7) or (3, 0) <= sys.version_info[:2] < (3, 2):
tarfile_open = _tarfile_open_ex
else:
tarfile_open = tarfile.open
......@@ -35,7 +35,6 @@ from pkg_resources import Distribution as PRDistribution
import setuptools.tests.server
import pkg_resources
from .py26compat import tarfile_open
from . import contexts
from .textwrap import DALS
......@@ -428,7 +427,7 @@ class TestSetupRequires:
# extracted path to sys.path so foo.bar v0.1 is importable
foobar_1_dir = os.path.join(temp_dir, 'foo.bar-0.1')
os.mkdir(foobar_1_dir)
with tarfile_open(foobar_1_archive) as tf:
with tarfile.open(foobar_1_archive) as tf:
tf.extractall(foobar_1_dir)
sys.path.insert(1, foobar_1_dir)
......@@ -526,7 +525,7 @@ def make_sdist(dist_path, files):
listed in ``files`` as ``(filename, content)`` tuples.
"""
with tarfile_open(dist_path, 'w:gz') as dist:
with tarfile.open(dist_path, 'w:gz') as dist:
for filename, content in files:
file_bytes = io.BytesIO(content.encode('utf-8'))
file_info = tarfile.TarInfo(name=filename)
......@@ -580,7 +579,7 @@ def make_trivial_sdist(dist_path, setup_py):
setup_py_file = tarfile.TarInfo(name='setup.py')
setup_py_bytes = io.BytesIO(setup_py.encode('utf-8'))
setup_py_file.size = len(setup_py_bytes.getvalue())
with tarfile_open(dist_path, 'w:gz') as dist:
with tarfile.open(dist_path, 'w:gz') as dist:
dist.addfile(setup_py_file, fileobj=setup_py_bytes)
......
......@@ -2,7 +2,6 @@ import os
import glob
import re
import stat
import sys
from setuptools.command.egg_info import egg_info, manifest_maker
from setuptools.dist import Distribution
......@@ -63,12 +62,6 @@ class TestEggInfo(object):
})
yield env
dict_order_fails = pytest.mark.skipif(
sys.version_info < (2,7),
reason="Intermittent failures on Python 2.6",
)
@dict_order_fails
def test_egg_info_save_version_info_setup_empty(self, tmpdir_cwd, env):
"""
When the egg_info section is empty or not present, running
......@@ -104,7 +97,6 @@ class TestEggInfo(object):
flags = re.MULTILINE | re.DOTALL
assert re.search(pattern, content, flags)
@dict_order_fails
def test_egg_info_save_version_info_setup_defaults(self, tmpdir_cwd, env):
"""
When running save_version_info on an existing setup.cfg
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment