Skip to content

Commit f14930e

Browse files
committed
Drop support for Python 2.6, removing lots of compatibility code for a leaner, cleaner codebase. Fixes #878.
1 parent ac99976 commit f14930e

24 files changed

+44
-170
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
language: python
22
python:
3-
- 2.6
43
- 2.7
54
- 3.3
65
- 3.4

CHANGES.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
v31.0.0
2+
-------
3+
4+
* #878: Drop support for Python 2.6. Python 2.6 users should
5+
rely on 'setuptools < 31dev'.
6+
17
v30.3.0
28
-------
39

README.rst

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ The recommended way to bootstrap setuptools on any system is to download
1717
operating systems have different recommended techniques to accomplish this
1818
basic routine, so below are some examples to get you started.
1919

20-
Setuptools requires Python 2.6 or later. To install setuptools
21-
on Python 2.4 or Python 2.5, use the `bootstrap script for Setuptools 1.x
22-
<https://github.com/raw/pypa/setuptools/bootstrap-py24/ez_setup.py>`_.
20+
Setuptools requires Python 3.3 or later (or Python 2.7).
2321

2422
The link provided to ez_setup.py is a bookmark to bootstrap script for the
2523
latest known stable release.

docs/easy_install.txt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Please see the `setuptools PyPI page <https://pypi.python.org/pypi/setuptools>`_
3535
for download links and basic installation instructions for each of the
3636
supported platforms.
3737

38-
You will need at least Python 2.6. An ``easy_install`` script will be
38+
You will need at least Python 3.3 or 2.7. An ``easy_install`` script will be
3939
installed in the normal location for Python scripts on your platform.
4040

4141
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
305305
directory (by default in the Python installation directory). It is recommended
306306
for EasyInstall that you ensure this directory is in the PATH environment
307307
variable. The easiest way to ensure the Scripts directory is in the PATH is
308-
to run ``Tools\Scripts\win_add2path.py`` from the Python directory (requires
309-
Python 2.6 or later).
308+
to run ``Tools\Scripts\win_add2path.py`` from the Python directory.
310309

311310
Note that instead of changing your ``PATH`` to include the Python scripts
312311
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]_.
987986

988987
`Use "virtualenv"`_
989988

990-
.. [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.
989+
.. [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`_.
991990

992991
.. _PEP-370: http://www.python.org/dev/peps/pep-0370/
993992

994993

995994
Use the "--user" option
996995
~~~~~~~~~~~~~~~~~~~~~~~
997-
With Python 2.6 came the User scheme for installation, which means that all
998-
python distributions support an alternative install location that is specific to a user [2]_ [3]_.
996+
Python provides a User scheme for installation, which means that all
997+
python distributions support an alternative install location that is specific to a user [3]_.
999998
The Default location for each OS is explained in the python documentation
1000999
for the ``site.USER_BASE`` variable. This mode of installation can be turned on by
10011000
specifying the ``--user`` option to ``setup.py install`` or ``easy_install``.
10021001
This approach serves the need to have a user-specific stash of packages.
10031002

1004-
.. [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.
10051003
.. [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.
10061004

10071005
Use the "--user" option and customize "PYTHONUSERBASE"

docs/formats.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ the need to create a directory just to store one file. This option is
110110
other metadata. (In fact, setuptools itself never generates
111111
``.egg-info`` files, either; the support for using files was added so
112112
that the requirement could easily be satisfied by other tools, such
113-
as the distutils in Python 2.5).
113+
as distutils).
114114

115115
In addition to the ``PKG-INFO`` file, an egg's metadata directory may
116116
also include files and directories representing various forms of

docs/pkg_resources.txt

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -622,8 +622,8 @@ Requirements Parsing
622622
The "markers" in a requirement are used to specify when a requirement
623623
should be installed -- the requirement will be installed if the marker
624624
evaluates as true in the current environment. For example, specifying
625-
``argparse;python_version<"2.7"`` will not install in an Python 2.7 or 3.3
626-
environment, but will in a Python 2.6 environment.
625+
``argparse;python_version<"3.0"`` will not install in an Python 3
626+
environment, but will in a Python 2 environment.
627627

628628
``Requirement`` Methods and Attributes
629629
--------------------------------------
@@ -1660,19 +1660,7 @@ PEP 302 Utilities
16601660
-----------------
16611661

16621662
``get_importer(path_item)``
1663-
Retrieve a PEP 302 "importer" for the given path item (which need not
1664-
actually be on ``sys.path``). This routine simulates the PEP 302 protocol
1665-
for obtaining an "importer" object. It first checks for an importer for
1666-
the path item in ``sys.path_importer_cache``, and if not found it calls
1667-
each of the ``sys.path_hooks`` and caches the result if a good importer is
1668-
found. If no importer is found, this routine returns an ``ImpWrapper``
1669-
instance that wraps the builtin import machinery as a PEP 302-compliant
1670-
"importer" object. This ``ImpWrapper`` is *not* cached; instead a new
1671-
instance is returned each time.
1672-
1673-
(Note: When run under Python 2.5, this function is simply an alias for
1674-
``pkgutil.get_importer()``, and instead of ``pkg_resources.ImpWrapper``
1675-
instances, it may return ``pkgutil.ImpImporter`` instances.)
1663+
A deprecated alias for ``pkgutil.get_importer()``
16761664

16771665

16781666
File/Path Utilities

docs/setuptools.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Building and Distributing Packages with Setuptools
33
==================================================
44

55
``Setuptools`` is a collection of enhancements to the Python ``distutils``
6-
(for Python 2.6 and up) that allow developers to more easily build and
6+
that allow developers to more easily build and
77
distribute Python packages, especially ones that have dependencies on other
88
packages.
99

pkg_resources/__init__.py

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,7 +1611,7 @@ def build(cls, path):
16111611
Use a platform-specific path separator (os.sep) for the path keys
16121612
for compatibility with pypy on Windows.
16131613
"""
1614-
with ContextualZipFile(path) as zfile:
1614+
with zipfile.ZipFile(path) as zfile:
16151615
items = (
16161616
(
16171617
name.replace('/', os.sep),
@@ -1644,26 +1644,6 @@ def load(self, path):
16441644
return self[path].manifest
16451645

16461646

1647-
class ContextualZipFile(zipfile.ZipFile):
1648-
"""
1649-
Supplement ZipFile class to support context manager for Python 2.6
1650-
"""
1651-
1652-
def __enter__(self):
1653-
return self
1654-
1655-
def __exit__(self, type, value, traceback):
1656-
self.close()
1657-
1658-
def __new__(cls, *args, **kwargs):
1659-
"""
1660-
Construct a ZipFile or ContextualZipFile as appropriate
1661-
"""
1662-
if hasattr(zipfile.ZipFile, '__exit__'):
1663-
return zipfile.ZipFile(*args, **kwargs)
1664-
return super(ContextualZipFile, cls).__new__(cls)
1665-
1666-
16671647
class ZipProvider(EggProvider):
16681648
"""Resource support for zips and eggs"""
16691649

@@ -1861,7 +1841,7 @@ def get_metadata(self, name):
18611841
return metadata
18621842

18631843
def _warn_on_replacement(self, metadata):
1864-
# Python 2.6 and 3.2 compat for: replacement_char = '�'
1844+
# Python 2.7 compat for: replacement_char = '�'
18651845
replacement_char = b'\xef\xbf\xbd'.decode('utf-8')
18661846
if replacement_char in metadata:
18671847
tmpl = "{self.path} could not be properly decoded in UTF-8"

pkg_resources/api_tests.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,10 +385,10 @@ Environment Markers
385385
>>> em("sys_platform=='win32'") == (sys.platform=='win32')
386386
True
387387

388-
>>> em("python_version >= '2.6'")
388+
>>> em("python_version >= '2.7'")
389389
True
390390

391-
>>> em("python_version > '2.5'")
391+
>>> em("python_version > '2.6'")
392392
True
393393

394394
>>> im("implementation_name=='cpython'")

pkg_resources/tests/test_resources.py

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,10 @@ def test_marker_evaluation_with_extras(self):
206206
"""Extras are also evaluated as markers at resolution time."""
207207
ad = pkg_resources.Environment([])
208208
ws = WorkingSet([])
209-
# Metadata needs to be native strings due to cStringIO behaviour in
210-
# 2.6, so use str().
211209
Foo = Distribution.from_filename(
212210
"/foo_dir/Foo-1.2.dist-info",
213-
metadata=Metadata(("METADATA", str("Provides-Extra: baz\n"
214-
"Requires-Dist: quux; extra=='baz'")))
211+
metadata=Metadata(("METADATA", "Provides-Extra: baz\n"
212+
"Requires-Dist: quux; extra=='baz'"))
215213
)
216214
ad.add(Foo)
217215
assert list(ws.resolve(parse_requirements("Foo"), ad)) == [Foo]
@@ -224,12 +222,10 @@ def test_marker_evaluation_with_extras_normlized(self):
224222
"""Extras are also evaluated as markers at resolution time."""
225223
ad = pkg_resources.Environment([])
226224
ws = WorkingSet([])
227-
# Metadata needs to be native strings due to cStringIO behaviour in
228-
# 2.6, so use str().
229225
Foo = Distribution.from_filename(
230226
"/foo_dir/Foo-1.2.dist-info",
231-
metadata=Metadata(("METADATA", str("Provides-Extra: baz-lightyear\n"
232-
"Requires-Dist: quux; extra=='baz-lightyear'")))
227+
metadata=Metadata(("METADATA", "Provides-Extra: baz-lightyear\n"
228+
"Requires-Dist: quux; extra=='baz-lightyear'"))
233229
)
234230
ad.add(Foo)
235231
assert list(ws.resolve(parse_requirements("Foo"), ad)) == [Foo]
@@ -241,14 +237,12 @@ def test_marker_evaluation_with_extras_normlized(self):
241237
def test_marker_evaluation_with_multiple_extras(self):
242238
ad = pkg_resources.Environment([])
243239
ws = WorkingSet([])
244-
# Metadata needs to be native strings due to cStringIO behaviour in
245-
# 2.6, so use str().
246240
Foo = Distribution.from_filename(
247241
"/foo_dir/Foo-1.2.dist-info",
248-
metadata=Metadata(("METADATA", str("Provides-Extra: baz\n"
242+
metadata=Metadata(("METADATA", "Provides-Extra: baz\n"
249243
"Requires-Dist: quux; extra=='baz'\n"
250244
"Provides-Extra: bar\n"
251-
"Requires-Dist: fred; extra=='bar'\n")))
245+
"Requires-Dist: fred; extra=='bar'\n"))
252246
)
253247
ad.add(Foo)
254248
quux = Distribution.from_filename("/foo_dir/quux-1.0.dist-info")
@@ -261,22 +255,20 @@ def test_marker_evaluation_with_multiple_extras(self):
261255
def test_marker_evaluation_with_extras_loop(self):
262256
ad = pkg_resources.Environment([])
263257
ws = WorkingSet([])
264-
# Metadata needs to be native strings due to cStringIO behaviour in
265-
# 2.6, so use str().
266258
a = Distribution.from_filename(
267259
"/foo_dir/a-0.2.dist-info",
268-
metadata=Metadata(("METADATA", str("Requires-Dist: c[a]")))
260+
metadata=Metadata(("METADATA", "Requires-Dist: c[a]"))
269261
)
270262
b = Distribution.from_filename(
271263
"/foo_dir/b-0.3.dist-info",
272-
metadata=Metadata(("METADATA", str("Requires-Dist: c[b]")))
264+
metadata=Metadata(("METADATA", "Requires-Dist: c[b]"))
273265
)
274266
c = Distribution.from_filename(
275267
"/foo_dir/c-1.0.dist-info",
276-
metadata=Metadata(("METADATA", str("Provides-Extra: a\n"
268+
metadata=Metadata(("METADATA", "Provides-Extra: a\n"
277269
"Requires-Dist: b;extra=='a'\n"
278270
"Provides-Extra: b\n"
279-
"Requires-Dist: foo;extra=='b'")))
271+
"Requires-Dist: foo;extra=='b'"))
280272
)
281273
foo = Distribution.from_filename("/foo_dir/foo-0.1.dist-info")
282274
for dist in (a, b, c, foo):

setup.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@ def pypi_link(pkg_filename):
145145
Intended Audience :: Developers
146146
License :: OSI Approved :: MIT License
147147
Operating System :: OS Independent
148-
Programming Language :: Python :: 2.6
149148
Programming Language :: Python :: 2.7
150149
Programming Language :: Python :: 3
151150
Programming Language :: Python :: 3.3
@@ -156,7 +155,7 @@ def pypi_link(pkg_filename):
156155
Topic :: System :: Systems Administration
157156
Topic :: Utilities
158157
""").strip().splitlines(),
159-
python_requires='>=2.6,!=3.0.*,!=3.1.*,!=3.2.*',
158+
python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*',
160159
extras_require={
161160
"ssl:sys_platform=='win32'": "wincertstore==0.2",
162161
"certs": "certifi==2016.9.26",

setuptools/archive_util.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import contextlib
99
from distutils.errors import DistutilsError
1010

11-
from pkg_resources import ensure_directory, ContextualZipFile
11+
from pkg_resources import ensure_directory
1212

1313
__all__ = [
1414
"unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter",
@@ -98,7 +98,7 @@ def unpack_zipfile(filename, extract_dir, progress_filter=default_filter):
9898
if not zipfile.is_zipfile(filename):
9999
raise UnrecognizedFormat("%s is not a zip file" % (filename,))
100100

101-
with ContextualZipFile(filename) as z:
101+
with zipfile.ZipFile(filename) as z:
102102
for info in z.infolist():
103103
name = info.filename
104104

setuptools/command/egg_info.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,7 @@ def save_version_info(self, filename):
158158
build tag. Install these keys in a deterministic order
159159
to avoid arbitrary reordering on subsequent builds.
160160
"""
161-
# python 2.6 compatibility
162-
odict = getattr(collections, 'OrderedDict', dict)
163-
egg_info = odict()
161+
egg_info = collections.OrderedDict()
164162
# follow the order these keys would have been added
165163
# when PYTHONHASHSEED=0
166164
egg_info['tag_build'] = self.tags()

setuptools/command/sdist.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,6 @@ def run(self):
5050
for cmd_name in self.get_sub_commands():
5151
self.run_command(cmd_name)
5252

53-
# Call check_metadata only if no 'check' command
54-
# (distutils <= 2.6)
55-
import distutils.command
56-
57-
if 'check' not in distutils.command.__all__:
58-
self.check_metadata()
59-
6053
self.make_distribution()
6154

6255
dist_files = getattr(self.distribution, 'dist_files', [])

setuptools/command/test.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import sys
44
import contextlib
55
import itertools
6+
import unittest
67
from distutils.errors import DistutilsOptionError
78
from unittest import TestLoader
89

@@ -13,7 +14,6 @@
1314
working_set, _namespace_packages,
1415
add_activation_listener, require, EntryPoint)
1516
from setuptools import Command
16-
from setuptools.py31compat import unittest_main
1717

1818

1919
class ScanningLoader(TestLoader):
@@ -225,12 +225,11 @@ def run_tests(self):
225225
del_modules.append(name)
226226
list(map(sys.modules.__delitem__, del_modules))
227227

228-
exit_kwarg = {} if sys.version_info < (2, 7) else {"exit": False}
229-
unittest_main(
228+
unittest.main(
230229
None, None, self._argv,
231230
testLoader=self._resolve_as_ep(self.test_loader),
232231
testRunner=self._resolve_as_ep(self.test_runner),
233-
**exit_kwarg
232+
exit=False,
234233
)
235234

236235
@property

setuptools/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
import sys
55
from collections import defaultdict
66
from functools import partial
7+
from importlib import import_module
78

89
from distutils.errors import DistutilsOptionError, DistutilsFileError
9-
from setuptools.py26compat import import_module
1010
from setuptools.extern.six import string_types
1111

1212

setuptools/monkey.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import platform
88
import types
99
import functools
10+
from importlib import import_module
1011

11-
from .py26compat import import_module
1212
from setuptools.extern import six
1313

1414
import setuptools

setuptools/package_index.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
from distutils import log
2828
from distutils.errors import DistutilsError
2929
from fnmatch import translate
30-
from setuptools.py26compat import strip_fragment
3130
from setuptools.py27compat import get_all_headers
3231

3332
EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.]+)$')
@@ -707,7 +706,7 @@ def _download_to(self, url, filename):
707706
fp, info = None, None
708707
try:
709708
checker = HashChecker.from_url(url)
710-
fp = self.open_url(strip_fragment(url))
709+
fp = self.open_url(url)
711710
if isinstance(fp, urllib.error.HTTPError):
712711
raise DistutilsError(
713712
"Can't download %s: %s %s" % (url, fp.code, fp.msg)

0 commit comments

Comments
 (0)