From dbe9f85c7d8f760756ebf8129195470700e63e3d Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Mon, 7 Nov 2016 04:33:46 -0800 Subject: [PATCH 1/2] Drop support for Python 2.6 * Drop unittest2 requirement * Use set literals * Use dict/set comprehension * Use str.format() automatic numbering --- .travis.yml | 7 ++----- PIL/BmpImagePlugin.py | 2 +- PIL/IcoImagePlugin.py | 2 +- PIL/JpegImagePlugin.py | 4 ++-- PIL/TiffImagePlugin.py | 16 ++++++---------- PIL/TiffTags.py | 14 +++++++------- Tests/README.rst | 4 ---- Tests/helper.py | 6 +----- Tests/test_file_libtiff.py | 6 +++--- Tests/test_file_tiff_metadata.py | 2 +- Tests/test_image_getim.py | 9 +-------- Tests/test_image_resample.py | 6 +++--- Tests/test_image_resize.py | 6 +++--- Tests/test_image_toqimage.py | 2 +- Tests/test_image_toqpixmap.py | 2 +- Tests/test_imagewin_pointers.py | 6 +----- _imaging.c | 4 ---- docs/installation.rst | 4 +++- py3.h | 2 +- setup.py | 3 +-- tox.ini | 2 +- winbuild/build.py | 3 --- winbuild/get_pythons.py | 2 +- 23 files changed, 41 insertions(+), 73 deletions(-) diff --git a/.travis.yml b/.travis.yml index 15bec68cc..e5d5a6b4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,6 @@ python: - "pypy3" - 3.5 - 2.7 - - 2.6 - "2.7_with_system_site_packages" # For PyQt4 - 3.2 - 3.3 @@ -24,10 +23,8 @@ install: - "travis_retry pip install cffi" - "travis_retry pip install nose" - "travis_retry pip install check-manifest" - # Pyroma tests sometimes hang on PyPy and Python 2.6; skip for those - - if [ $TRAVIS_PYTHON_VERSION != "pypy" && $TRAVIS_PYTHON_VERSION != "2.6" ]; then travis_retry pip install pyroma; fi - - - if [ "$TRAVIS_PYTHON_VERSION" == "2.6" ]; then travis_retry pip install unittest2; fi + # Pyroma tests sometimes hang on PyPy; skip + - if [ $TRAVIS_PYTHON_VERSION != "pypy" ]; then travis_retry pip install pyroma; fi # Coverage 4.0 doesn't support Python 3.2 - if [ "$TRAVIS_PYTHON_VERSION" == "3.2" ]; then travis_retry pip install coverage==3.7.1; fi diff --git a/PIL/BmpImagePlugin.py b/PIL/BmpImagePlugin.py index a922d8ff8..b04981af9 100644 --- a/PIL/BmpImagePlugin.py +++ b/PIL/BmpImagePlugin.py @@ -73,7 +73,7 @@ class BmpImageFile(ImageFile.ImageFile): read, seek = self.fp.read, self.fp.seek if header: seek(header) - file_info = dict() + file_info = {} file_info['header_size'] = i32(read(4)) # read bmp header size @offset 14 (this is part of the header size) file_info['direction'] = -1 # --------------------- If requested, read header at a specific position diff --git a/PIL/IcoImagePlugin.py b/PIL/IcoImagePlugin.py index a01aed376..b278a85bf 100644 --- a/PIL/IcoImagePlugin.py +++ b/PIL/IcoImagePlugin.py @@ -139,7 +139,7 @@ class IcoFile(object): """ Get a list of all available icon sizes and color depths. """ - return set((h['width'], h['height']) for h in self.entry) + return {(h['width'], h['height']) for h in self.entry} def getimage(self, size, bpp=False): """ diff --git a/PIL/JpegImagePlugin.py b/PIL/JpegImagePlugin.py index 6d4e588c0..92316a65a 100644 --- a/PIL/JpegImagePlugin.py +++ b/PIL/JpegImagePlugin.py @@ -408,7 +408,7 @@ def _fixup_dict(src_dict): except: pass return value - return dict((k, _fixup(v)) for k, v in src_dict.items()) + return {k: _fixup(v) for k, v in src_dict.items()} def _getexif(self): @@ -488,7 +488,7 @@ def _getmp(self): rawmpentries = mp[0xB002] for entrynum in range(0, quant): unpackedentry = unpack_from( - '{0}LLLHH'.format(endianness), rawmpentries, entrynum * 16) + '{}LLLHH'.format(endianness), rawmpentries, entrynum * 16) labels = ('Attribute', 'Size', 'DataOffset', 'EntryNo1', 'EntryNo2') mpentry = dict(zip(labels, unpackedentry)) diff --git a/PIL/TiffImagePlugin.py b/PIL/TiffImagePlugin.py index d442c3766..f1860e4aa 100644 --- a/PIL/TiffImagePlugin.py +++ b/PIL/TiffImagePlugin.py @@ -132,7 +132,7 @@ COMPRESSION_INFO = { 34677: "tiff_sgilog24", } -COMPRESSION_INFO_REV = dict((v, k) for (k, v) in COMPRESSION_INFO.items()) +COMPRESSION_INFO_REV = {v: k for k, v in COMPRESSION_INFO.items()} OPEN_INFO = { # (ByteOrder, PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample, @@ -294,11 +294,7 @@ class IFDRational(Rational): return elif denominator == 1: - if sys.hexversion < 0x2070000 and isinstance(value, float): - # python 2.6 is different. - self._val = Fraction.from_float(value) - else: - self._val = Fraction(value) + self._val = Fraction(value) else: self._val = Fraction(value, denominator) @@ -592,7 +588,7 @@ class ImageFileDirectory_v2(collections.MutableMapping): TYPES[idx] = name size = struct.calcsize("=" + fmt) _load_dispatch[idx] = size, lambda self, data, legacy_api=True: ( - self._unpack("{0}{1}".format(len(data) // size, fmt), data)) + self._unpack("{}{}".format(len(data) // size, fmt), data)) _write_dispatch[idx] = lambda self, *values: ( b"".join(self._pack(fmt, value) for value in values)) @@ -624,7 +620,7 @@ class ImageFileDirectory_v2(collections.MutableMapping): @_register_loader(5, 8) def load_rational(self, data, legacy_api=True): - vals = self._unpack("{0}L".format(len(data) // 4), data) + vals = self._unpack("{}L".format(len(data) // 4), data) combine = lambda a, b: (a, b) if legacy_api else IFDRational(a, b) return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2])) @@ -644,7 +640,7 @@ class ImageFileDirectory_v2(collections.MutableMapping): @_register_loader(10, 8) def load_signed_rational(self, data, legacy_api=True): - vals = self._unpack("{0}l".format(len(data) // 4), data) + vals = self._unpack("{}l".format(len(data) // 4), data) combine = lambda a, b: (a, b) if legacy_api else IFDRational(a, b) return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2])) @@ -1518,7 +1514,7 @@ class AppendingTiffWriter: # JPEGQTables = 519 # JPEGDCTables = 520 # JPEGACTables = 521 - Tags = set((273, 288, 324, 519, 520, 521)) + Tags = {273, 288, 324, 519, 520, 521} def __init__(self, fn, new=False): if hasattr(fn, 'read'): diff --git a/PIL/TiffTags.py b/PIL/TiffTags.py index edb28b9ec..6644b237e 100644 --- a/PIL/TiffTags.py +++ b/PIL/TiffTags.py @@ -418,13 +418,13 @@ TYPES = {} # some of these are not in our TAGS_V2 dict and were included from tiff.h -LIBTIFF_CORE = set([255, 256, 257, 258, 259, 262, 263, 266, 274, 277, - 278, 280, 281, 340, 341, 282, 283, 284, 286, 287, - 296, 297, 321, 320, 338, 32995, 322, 323, 32998, - 32996, 339, 32997, 330, 531, 530, 301, 532, 333, - # as above - 269 # this has been in our tests forever, and works - ]) +LIBTIFF_CORE = {255, 256, 257, 258, 259, 262, 263, 266, 274, 277, + 278, 280, 281, 340, 341, 282, 283, 284, 286, 287, + 296, 297, 321, 320, 338, 32995, 322, 323, 32998, + 32996, 339, 32997, 330, 531, 530, 301, 532, 333, + # as above + 269 # this has been in our tests forever, and works + } LIBTIFF_CORE.remove(320) # Array of short, crashes LIBTIFF_CORE.remove(301) # Array of short, crashes diff --git a/Tests/README.rst b/Tests/README.rst index a7212cb3d..0985e0f26 100644 --- a/Tests/README.rst +++ b/Tests/README.rst @@ -10,10 +10,6 @@ Install:: pip install coverage nose -If you're using Python 2.6, there's one additional dependency:: - - pip install unittest2 - Execution --------- diff --git a/Tests/helper.py b/Tests/helper.py index 5cfd7678f..7b8bdcce4 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -5,11 +5,7 @@ from __future__ import print_function import sys import tempfile import os - -if sys.version_info[:2] <= (2, 6): - import unittest2 as unittest -else: - import unittest +import unittest class PillowTestCase(unittest.TestCase): diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 6e40d4b37..2d1b33154 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -180,9 +180,9 @@ class TestFileLibTiff(LibTiffTestCase): # Get the list of the ones that we should be able to write - core_items = dict((tag, info) for tag, info in [(s, TiffTags.lookup(s)) for s - in TiffTags.LIBTIFF_CORE] - if info.type is not None) + core_items = {tag: info for tag, info in ((s, TiffTags.lookup(s)) for s + in TiffTags.LIBTIFF_CORE) + if info.type is not None} # Exclude ones that have special meaning # that we're already testing them diff --git a/Tests/test_file_tiff_metadata.py b/Tests/test_file_tiff_metadata.py index 7af03a675..c75487f9b 100644 --- a/Tests/test_file_tiff_metadata.py +++ b/Tests/test_file_tiff_metadata.py @@ -8,7 +8,7 @@ from helper import unittest, PillowTestCase, hopper from PIL import Image, TiffImagePlugin, TiffTags from PIL.TiffImagePlugin import _limit_rational, IFDRational -tag_ids = dict((info.name, info.value) for info in TiffTags.TAGS_V2.values()) +tag_ids = {info.name: info.value for info in TiffTags.TAGS_V2.values()} class TestFileTiffMetadata(PillowTestCase): diff --git a/Tests/test_image_getim.py b/Tests/test_image_getim.py index c67118b58..bc562de5a 100644 --- a/Tests/test_image_getim.py +++ b/Tests/test_image_getim.py @@ -1,5 +1,4 @@ from helper import unittest, PillowTestCase, hopper, py3 -import sys class TestImageGetIm(PillowTestCase): @@ -11,13 +10,7 @@ class TestImageGetIm(PillowTestCase): if py3: self.assertIn("PyCapsule", type_repr) - if sys.hexversion < 0x2070000: - # py2.6 x64, windows - target_types = (int, long) - else: - target_types = (int) - - self.assertIsInstance(im.im.id, target_types) + self.assertIsInstance(im.im.id, int) if __name__ == '__main__': diff --git a/Tests/test_image_resample.py b/Tests/test_image_resample.py index 6fcdd84b9..1336c1009 100644 --- a/Tests/test_image_resample.py +++ b/Tests/test_image_resample.py @@ -232,10 +232,10 @@ class CoreResampleAlphaCorrectTest(PillowTestCase): def run_levels_case(self, i): px = i.load() for y in range(i.size[1]): - used_colors = set(px[x, y][0] for x in range(i.size[0])) + used_colors = {px[x, y][0] for x in range(i.size[0])} self.assertEqual(256, len(used_colors), 'All colors should present in resized image. ' - 'Only {0} on {1} line.'.format(len(used_colors), y)) + 'Only {} on {} line.'.format(len(used_colors), y)) @unittest.skip("current implementation isn't precise enough") def test_levels_rgba(self): @@ -270,7 +270,7 @@ class CoreResampleAlphaCorrectTest(PillowTestCase): for y in range(i.size[1]): for x in range(i.size[0]): if px[x, y][-1] != 0 and px[x, y][:-1] != clean_pixel: - message = 'pixel at ({0}, {1}) is differ:\n{2}\n{3}'\ + message = 'pixel at ({}, {}) is differ:\n{}\n{}'\ .format(x, y, px[x, y], clean_pixel) self.assertEqual(px[x, y][:3], clean_pixel, message) diff --git a/Tests/test_image_resize.py b/Tests/test_image_resize.py index 73f8091ed..e0af7bb6b 100644 --- a/Tests/test_image_resize.py +++ b/Tests/test_image_resize.py @@ -69,10 +69,10 @@ class TestImagingCoreResize(PillowTestCase): for f in [Image.LINEAR, Image.BOX, Image.BILINEAR, Image.HAMMING, Image.BICUBIC, Image.LANCZOS]: # samples resized with current filter - references = dict( - (name, self.resize(ch, (4, 4), f)) + references = { + name: self.resize(ch, (4, 4), f) for name, ch in samples.items() - ) + } for mode, channels_set in [ ('RGB', ('blank', 'filled', 'dirty')), diff --git a/Tests/test_image_toqimage.py b/Tests/test_image_toqimage.py index ccab08799..4a318c5c4 100644 --- a/Tests/test_image_toqimage.py +++ b/Tests/test_image_toqimage.py @@ -29,7 +29,7 @@ class TestToQImage(PillowQtTestCase, PillowTestCase): self.assertFalse(data.isNull()) # Test saving the file - tempfile = self.tempfile('temp_{0}.png'.format(mode)) + tempfile = self.tempfile('temp_{}.png'.format(mode)) data.save(tempfile) diff --git a/Tests/test_image_toqpixmap.py b/Tests/test_image_toqpixmap.py index 0bed9c747..c6555d7ff 100644 --- a/Tests/test_image_toqpixmap.py +++ b/Tests/test_image_toqpixmap.py @@ -19,7 +19,7 @@ class TestToQPixmap(PillowQPixmapTestCase, PillowTestCase): self.assertFalse(data.isNull()) # Test saving the file - tempfile = self.tempfile('temp_{0}.png'.format(mode)) + tempfile = self.tempfile('temp_{}.png'.format(mode)) data.save(tempfile) diff --git a/Tests/test_imagewin_pointers.py b/Tests/test_imagewin_pointers.py index f37c67eac..7178d8cb8 100644 --- a/Tests/test_imagewin_pointers.py +++ b/Tests/test_imagewin_pointers.py @@ -75,11 +75,7 @@ if sys.platform.startswith('win32'): memcpy(bp, ctypes.byref(bf), ctypes.sizeof(bf)) memcpy(bp + ctypes.sizeof(bf), ctypes.byref(bi), bi.biSize) memcpy(bp + bf.bfOffBits, pixels, bi.biSizeImage) - try: - return bytearray(buf) - except ValueError: - # py2.6 - return buffer(buf)[:] + return bytearray(buf) class TestImageWinPointers(PillowTestCase): def test_pointer(self): diff --git a/_imaging.c b/_imaging.c index 3c109b88c..e2320d862 100644 --- a/_imaging.c +++ b/_imaging.c @@ -3073,11 +3073,7 @@ _getattr_id(ImagingObject* self, void* closure) static PyObject* _getattr_ptr(ImagingObject* self, void* closure) { -#if PY_VERSION_HEX >= 0x02070000 return PyCapsule_New(self->image, IMAGING_MAGIC, NULL); -#else - return PyCObject_FromVoidPtrAndDesc(self->image, IMAGING_MAGIC, NULL); -#endif } static PyObject* diff --git a/docs/installation.rst b/docs/installation.rst index 2ada37c03..4cccf303e 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -15,7 +15,9 @@ Notes .. note:: Pillow < 2.0.0 supports Python versions 2.4, 2.5, 2.6, 2.7. -.. note:: Pillow >= 2.0.0 supports Python versions 2.6, 2.7, 3.2, 3.3, 3.4, 3.5 +.. note:: Pillow >= 2.0.0 < 3.5.0 supports Python versions 2.6, 2.7, 3.2, 3.3, 3.4, 3.5 + +.. note:: Pillow >= 3.5.0 supports Python versions 2.7, 3.2, 3.3, 3.4, 3.5 Basic Installation ------------------ diff --git a/py3.h b/py3.h index a2a1e264f..310583845 100644 --- a/py3.h +++ b/py3.h @@ -1,5 +1,5 @@ /* - Python3 definition file to consistently map the code to Python 2.6 or + Python3 definition file to consistently map the code to Python 2 or Python 3. PyInt and PyLong were merged into PyLong in Python 3, so all PyInt functions diff --git a/setup.py b/setup.py index 553494afb..dbb9e046c 100644 --- a/setup.py +++ b/setup.py @@ -147,7 +147,7 @@ class pil_build_ext(build_ext): features = ['zlib', 'jpeg', 'tiff', 'freetype', 'lcms', 'webp', 'webpmux', 'jpeg2000', 'imagequant'] - required = set(['jpeg', 'zlib']) + required = {'jpeg', 'zlib'} def __init__(self): for f in self.features: @@ -770,7 +770,6 @@ try: "Topic :: Multimedia :: Graphics :: Graphics Conversion", "Topic :: Multimedia :: Graphics :: Viewers", "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", diff --git a/tox.ini b/tox.ini index 507af757a..809183b9a 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ # and then run "tox" from this directory. [tox] -envlist = py26, py27, py32, py33, py34, py35 +envlist = py27, py32, py33, py34, py35 [testenv] commands = diff --git a/winbuild/build.py b/winbuild/build.py index aacf13174..487977adb 100644 --- a/winbuild/build.py +++ b/winbuild/build.py @@ -18,9 +18,6 @@ def setup_vms(): % (py, arch, VIRT_BASE, py, arch)) ret.append("%s%s%s\Scripts\pip.exe install nose" % (VIRT_BASE, py, arch)) - if py == '26': - ret.append("%s%s%s\Scripts\pip.exe install unittest2" % - (VIRT_BASE, py, arch)) return "\n".join(ret) diff --git a/winbuild/get_pythons.py b/winbuild/get_pythons.py index 57c866daa..5abd836fb 100644 --- a/winbuild/get_pythons.py +++ b/winbuild/get_pythons.py @@ -2,7 +2,7 @@ from fetch import fetch import os if __name__ == '__main__': - for version in ['2.6.6', '2.7.10', '3.2.5', '3.3.5', '3.4.3']: + for version in ['2.7.10', '3.2.5', '3.3.5', '3.4.3']: for platform in ['', '.amd64']: for extension in ['', '.asc']: fetch('https://www.python.org/ftp/python/%s/python-%s%s.msi%s' From 85cf6d31401cc1763c0f5405663054a09071385d Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Mon, 7 Nov 2016 04:35:23 -0800 Subject: [PATCH 2/2] Drop support for Python 3.2 --- .travis.yml | 5 +---- docs/installation.rst | 2 +- setup.py | 16 +--------------- tox.ini | 2 +- winbuild/build.rst | 2 +- winbuild/get_pythons.py | 2 +- 6 files changed, 6 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index e5d5a6b4d..952714b5f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,6 @@ python: - 3.5 - 2.7 - "2.7_with_system_site_packages" # For PyQt4 - - 3.2 - 3.3 - 3.4 - nightly @@ -26,9 +25,7 @@ install: # Pyroma tests sometimes hang on PyPy; skip - if [ $TRAVIS_PYTHON_VERSION != "pypy" ]; then travis_retry pip install pyroma; fi - # Coverage 4.0 doesn't support Python 3.2 - - if [ "$TRAVIS_PYTHON_VERSION" == "3.2" ]; then travis_retry pip install coverage==3.7.1; fi - - if [ "$TRAVIS_PYTHON_VERSION" != "3.2" ]; then travis_retry pip install coverage; fi + - "travis_retry pip install coverage" # docs only on python 2.7 - if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then travis_retry pip install -r requirements.txt ; fi diff --git a/docs/installation.rst b/docs/installation.rst index 4cccf303e..2724886bb 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -17,7 +17,7 @@ Notes .. note:: Pillow >= 2.0.0 < 3.5.0 supports Python versions 2.6, 2.7, 3.2, 3.3, 3.4, 3.5 -.. note:: Pillow >= 3.5.0 supports Python versions 2.7, 3.2, 3.3, 3.4, 3.5 +.. note:: Pillow >= 3.5.0 supports Python versions 2.7, 3.3, 3.4, 3.5 Basic Installation ------------------ diff --git a/setup.py b/setup.py index dbb9e046c..808ec728a 100644 --- a/setup.py +++ b/setup.py @@ -74,20 +74,7 @@ def _find_include_file(self, include): def _find_library_file(self, library): - # Fix for 3.2.x <3.2.4, 3.3.0, shared lib extension is the python shared - # lib extension, not the system shared lib extension: e.g. .cpython-33.so - # vs .so. See Python bug http://bugs.python.org/16754 - if 'cpython' in self.compiler.shared_lib_extension: - _dbg('stripping cpython from shared library extension %s', - self.compiler.shared_lib_extension) - existing = self.compiler.shared_lib_extension - self.compiler.shared_lib_extension = "." + existing.split('.')[-1] - ret = self.compiler.find_library_file(self.compiler.library_dirs, - library) - self.compiler.shared_lib_extension = existing - else: - ret = self.compiler.find_library_file(self.compiler.library_dirs, - library) + ret = self.compiler.find_library_file(self.compiler.library_dirs, library) if ret: _dbg('Found library %s at %s', (library, ret)) else: @@ -772,7 +759,6 @@ try: "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", diff --git a/tox.ini b/tox.ini index 809183b9a..4d63febd0 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ # and then run "tox" from this directory. [tox] -envlist = py27, py32, py33, py34, py35 +envlist = py27, py33, py34, py35 [testenv] commands = diff --git a/winbuild/build.rst b/winbuild/build.rst index e4c2293a9..86c4cf4c7 100644 --- a/winbuild/build.rst +++ b/winbuild/build.rst @@ -31,7 +31,7 @@ The build routines expect Python to be installed at C:\PythonXX for Download Python 3.4, install it, and add it to the path. This is the Python that we will use to bootstrap the build process. (The download -routines are using 3.2+ features, and installing 3.4 gives us pip and +routines are using 3 features, and installing 3.4 gives us pip and virtualenv as well, reducing the number of packages that we need to install.) diff --git a/winbuild/get_pythons.py b/winbuild/get_pythons.py index 5abd836fb..481283df3 100644 --- a/winbuild/get_pythons.py +++ b/winbuild/get_pythons.py @@ -2,7 +2,7 @@ from fetch import fetch import os if __name__ == '__main__': - for version in ['2.7.10', '3.2.5', '3.3.5', '3.4.3']: + for version in ['2.7.10', '3.3.5', '3.4.3']: for platform in ['', '.amd64']: for extension in ['', '.asc']: fetch('https://www.python.org/ftp/python/%s/python-%s%s.msi%s'