Skip to content

Commit

Permalink
Drop support for Python 2.6, removing lots of compatibility code for …
Browse files Browse the repository at this point in the history
…a leaner, cleaner codebase. Fixes #878.
  • Loading branch information
jaraco committed Dec 9, 2016
1 parent ac99976 commit 1376909
Show file tree
Hide file tree
Showing 18 changed files with 24 additions and 122 deletions.
1 change: 0 additions & 1 deletion .travis.yml
@@ -1,6 +1,5 @@
language: python
python:
- 2.6
- 2.7
- 3.3
- 3.4
Expand Down
6 changes: 6 additions & 0 deletions CHANGES.rst
@@ -1,3 +1,9 @@
v31.0.0
-------

* #878: Drop support for Python 2.6. Python 2.6 users should
rely on 'setuptools < 31dev'.

v30.3.0
-------

Expand Down
4 changes: 1 addition & 3 deletions README.rst
Expand Up @@ -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.
Expand Down
25 changes: 2 additions & 23 deletions pkg_resources/__init__.py
Expand Up @@ -1611,7 +1611,7 @@ def build(cls, path):
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),
Expand Down Expand Up @@ -1644,26 +1644,6 @@ def load(self, path):
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"""

Expand Down Expand Up @@ -1861,8 +1841,7 @@ def get_metadata(self, name):
return metadata

def _warn_on_replacement(self, metadata):
# Python 2.6 and 3.2 compat for: replacement_char = '�'
replacement_char = b'\xef\xbf\xbd'.decode('utf-8')
replacement_char = '�'
if replacement_char in metadata:
tmpl = "{self.path} could not be properly decoded in UTF-8"
msg = tmpl.format(**locals())
Expand Down
4 changes: 2 additions & 2 deletions pkg_resources/tests/test_resources.py
Expand Up @@ -210,8 +210,8 @@ def test_marker_evaluation_with_extras(self):
# 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]
Expand Down
3 changes: 1 addition & 2 deletions setup.py
Expand Up @@ -145,7 +145,6 @@ def pypi_link(pkg_filename):
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
Expand All @@ -156,7 +155,7 @@ def pypi_link(pkg_filename):
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",
Expand Down
4 changes: 2 additions & 2 deletions setuptools/archive_util.py
Expand Up @@ -8,7 +8,7 @@
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",
Expand Down Expand Up @@ -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

Expand Down
4 changes: 1 addition & 3 deletions setuptools/command/egg_info.py
Expand Up @@ -158,9 +158,7 @@ def save_version_info(self, filename):
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()
Expand Down
7 changes: 3 additions & 4 deletions setuptools/command/test.py
Expand Up @@ -3,6 +3,7 @@
import sys
import contextlib
import itertools
import unittest
from distutils.errors import DistutilsOptionError
from unittest import TestLoader

Expand All @@ -13,7 +14,6 @@
working_set, _namespace_packages,
add_activation_listener, require, EntryPoint)
from setuptools import Command
from setuptools.py31compat import unittest_main


class ScanningLoader(TestLoader):
Expand Down Expand Up @@ -225,12 +225,11 @@ def run_tests(self):
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
Expand Down
2 changes: 1 addition & 1 deletion setuptools/config.py
Expand Up @@ -4,9 +4,9 @@
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


Expand Down
2 changes: 1 addition & 1 deletion setuptools/monkey.py
Expand Up @@ -7,8 +7,8 @@
import platform
import types
import functools
from importlib import import_module

from .py26compat import import_module
from setuptools.extern import six

import setuptools
Expand Down
3 changes: 1 addition & 2 deletions setuptools/package_index.py
Expand Up @@ -27,7 +27,6 @@
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_.]+)$')
Expand Down Expand Up @@ -707,7 +706,7 @@ def _download_to(self, url, filename):
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)
Expand Down
31 changes: 0 additions & 31 deletions setuptools/py26compat.py

This file was deleted.

15 changes: 0 additions & 15 deletions setuptools/py31compat.py
@@ -1,6 +1,3 @@
import sys
import unittest

__all__ = ['get_config_vars', 'get_path']

try:
Expand Down Expand Up @@ -42,15 +39,3 @@ def __exit__(self, exctype, excvalue, exctrace):
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)
4 changes: 0 additions & 4 deletions setuptools/sandbox.py
Expand Up @@ -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')
Expand Down
16 changes: 0 additions & 16 deletions setuptools/tests/py26compat.py

This file was deleted.

7 changes: 3 additions & 4 deletions setuptools/tests/test_easy_install.py
Expand Up @@ -35,7 +35,6 @@
import setuptools.tests.server
import pkg_resources

from .py26compat import tarfile_open
from . import contexts
from .textwrap import DALS

Expand Down Expand Up @@ -428,7 +427,7 @@ def test_setup_requires_override_nspkg(self):
# 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)

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)


Expand Down
8 changes: 0 additions & 8 deletions setuptools/tests/test_egg_info.py
Expand Up @@ -2,7 +2,6 @@
import glob
import re
import stat
import sys

from setuptools.command.egg_info import egg_info, manifest_maker
from setuptools.dist import Distribution
Expand Down Expand Up @@ -63,12 +62,6 @@ def env(self):
})
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
Expand Down Expand Up @@ -104,7 +97,6 @@ def _validate_content_order(content, expected):
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
Expand Down

0 comments on commit 1376909

Please sign in to comment.