diff --git a/.gitignore b/.gitignore index aa45f946f..242f50845 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ __pycache__/ *.so # Distribution / packaging +.eggs/ .Python env/ bin/ @@ -69,3 +70,11 @@ docs/_build/ #OS .DS_Store +# JetBrains +.idea + +# Extra test images installed from pillow-depends/test_images +Tests/images/README.md +Tests/images/msp +Tests/images/picins +Tests/images/sunraster diff --git a/.travis.yml b/.travis.yml index ef7adc63d..d208c4165 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,6 @@ matrix: - python: "2.7_with_system_site_packages" # For PyQt4 - python: '3.5' - python: '3.4' - - python: '3.3' - python: '3.7-dev' - env: DOCKER="alpine" - env: DOCKER="arch" # contains PyQt5 diff --git a/.travis/install.sh b/.travis/install.sh index 64ce477f7..cad0e3c32 100755 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -8,11 +8,12 @@ sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-tk\ libharfbuzz-dev libfribidi-dev pip install cffi -pip install nose pip install check-manifest -pip install olefile -pip install pyroma pip install coverage +pip install olefile +pip install -U pytest +pip install -U pytest-cov +pip install pyroma pip install test-image-results # docs only on Python 2.7 diff --git a/.travis/script.sh b/.travis/script.sh index e1d522122..a67b9da3b 100755 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -6,8 +6,9 @@ coverage erase python setup.py clean CFLAGS="-coverage" python setup.py build_ext --inplace -coverage run --append --include=PIL/* selftest.py -coverage run --append --include=PIL/* -m nose -vx Tests/test_*.py +python selftest.py +python -m pytest -vx --cov PIL --cov-report term Tests + pushd /tmp/check-manifest && check-manifest --ignore ".coveragerc,.editorconfig,*.yml,*.yaml,tox.ini" && popd # Docs diff --git a/CHANGES.rst b/CHANGES.rst index a995616e9..c32cbe826 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,7 +2,7 @@ Changelog (Pillow) ================== -4.4.0 (unreleased) +5.0.0 (unreleased) ------------------ - Dynamically link libraqm #2753 diff --git a/Makefile b/Makefile index d27afaa0b..bdf7ce9b4 100644 --- a/Makefile +++ b/Makefile @@ -15,12 +15,9 @@ co: done coverage: - coverage erase - coverage run --parallel-mode --include=PIL/* selftest.py - nosetests --with-cov --cov='PIL/' --cov-report=html Tests/test_*.py -# Doesn't combine properly before report, writing report instead of displaying invalid report. + python selftest.py + python setup.py test rm -r htmlcov || true - coverage combine coverage report doc: @@ -81,9 +78,9 @@ release-test: $(MAKE) install-req python setup.py develop python selftest.py - nosetests Tests/test_*.py + python -m pytest Tests python setup.py install - python test-installed.py + python -m pytest -qq check-manifest pyroma . viewdoc @@ -92,7 +89,7 @@ sdist: python setup.py sdist --format=gztar test: - python test-installed.py + pytest -qq # https://docs.python.org/2/distutils/packageindex.html#the-pypirc-file upload-test: diff --git a/PIL/version.py b/PIL/version.py index 0718fd601..b89052c73 100644 --- a/PIL/version.py +++ b/PIL/version.py @@ -1,2 +1,2 @@ # Master version for Pillow -__version__ = '4.4.0.dev0' +__version__ = '5.0.0.dev0' diff --git a/Tests/README.rst b/Tests/README.rst index 0985e0f26..44f6f4792 100644 --- a/Tests/README.rst +++ b/Tests/README.rst @@ -8,7 +8,7 @@ Dependencies Install:: - pip install coverage nose + pip install pytest pytest-cov Execution --------- @@ -21,12 +21,11 @@ To run an individual test:: Run all the tests from the root of the Pillow source distribution:: - nosetests -vx Tests/test_*.py + pytest -vx Tests Or with coverage:: - coverage run --append --include=PIL/* -m nose -vx Tests/test_*.py - coverage report + pytest -vx --cov PIL --cov-report term Tests coverage html open htmlcov/index.html @@ -34,11 +33,8 @@ Or with coverage:: To run an individual test:: - ./test-installed.py Tests/test_image.py + pytest -k Tests/test_image.py Run all the tests from the root of the Pillow source distribution:: - ./test-installed.py - - - + pytest diff --git a/Tests/helper.py b/Tests/helper.py index b8b44b6f2..fdeb00c0c 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -63,9 +63,8 @@ class PillowTestCase(unittest.TestCase): def delete_tempfile(self, path): try: ok = self.currentResult.wasSuccessful() - except AttributeError: # for nosetests - proxy = self.currentResult - ok = (len(proxy.errors) + len(proxy.failures) == 0) + except AttributeError: # for pytest + ok = True if ok: # only clean out tempfiles if test passed @@ -210,10 +209,6 @@ class PillowTestCase(unittest.TestCase): if skip: self.skipTest(msg or "Known Bad Test") - def shortDescription(self): - # Prevents `nose -v` printing docstrings - return None - def tempfile(self, template): assert template[:5] in ("temp.", "temp_") fd, path = tempfile.mkstemp(template[4:], template[:4]) @@ -256,8 +251,8 @@ class PillowLeakTestCase(PillowTestCase): # linux # man 2 getrusage # ru_maxrss (since Linux 2.6.32) - # This is the maximum resident set size used (in kilobytes). - return mem # Kb + # This is the maximum resident set size used (in kilobytes). + return mem # Kb def _test_leak(self, core): start_mem = self._get_mem_usage() diff --git a/Tests/test_image_access.py b/Tests/test_image_access.py index 9cb27774d..d0fcea1d4 100644 --- a/Tests/test_image_access.py +++ b/Tests/test_image_access.py @@ -251,7 +251,7 @@ class TestCffi(AccessTest): class TestEmbeddable(unittest.TestCase): @unittest.skipIf(not sys.platform.startswith('win32') or - sys.version_info[:2] in ((3, 3), (3, 4)) or + sys.version_info[:2] == (3, 4) or on_appveyor(), # failing on appveyor when run from # subprocess, not from shell "requires Python 2.7 or >=3.5 for Windows") @@ -293,7 +293,7 @@ int main(int argc, char* argv[]) compiler = ccompiler.new_compiler() compiler.add_include_dir(sysconfig.get_python_inc()) - + libdir = sysconfig.get_config_var('LIBDIR') or sysconfig.get_python_inc().replace('include', 'libs') print (libdir) compiler.add_library_dir(libdir) @@ -302,10 +302,10 @@ int main(int argc, char* argv[]) env = os.environ.copy() env["PATH"] = sys.prefix + ';' + env["PATH"] - + # do not display the Windows Error Reporting dialog ctypes.windll.kernel32.SetErrorMode(0x0002) - + process = subprocess.Popen(['embed_pil.exe'], env=env) process.communicate() self.assertEqual(process.returncode, 0) diff --git a/appveyor.yml b/appveyor.yml index d966c88ff..8e995e601 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -21,8 +21,6 @@ environment: - PYTHON: C:/Python34 - PYTHON: C:/Python27 - PYTHON: C:/Python34-x64 - - PYTHON: C:/Python33 - - PYTHON: C:/Python33-x64 - PYTHON: C:/msys64/mingw32 EXECUTABLE: bin/python3 PIP_DIR: bin @@ -74,8 +72,13 @@ build_script: test_script: - cd c:\pillow -- '%PYTHON%\%PIP_DIR%\pip.exe install nose' -- '%PYTHON%\%EXECUTABLE% test-installed.py -v -s %TEST_OPTIONS%' +- '%PYTHON%\%PIP_DIR%\pip.exe install pytest pytest-cov' +- '%PYTHON%\%EXECUTABLE% -m pytest -vx --cov PIL --cov-report term --cov-report xml Tests' +#- '%PYTHON%\%EXECUTABLE% test-installed.py -v -s %TEST_OPTIONS%' TODO TEST_OPTIONS with pytest? + +after_test: +- pip install codecov +- codecov --file coverage.xml --name %PYTHON% matrix: fast_finish: true diff --git a/docs/installation.rst b/docs/installation.rst index 2d0ad8764..3ed48f413 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -17,7 +17,9 @@ Notes .. note:: Pillow >= 2.0.0 < 4.0.0 supports Python versions 2.6, 2.7, 3.2, 3.3, 3.4, 3.5 -.. note:: Pillow >= 4.0.0 supports Python versions 2.7, 3.3, 3.4, 3.5, 3.6 +.. note:: Pillow >= 4.0.0 < 5.0.0 supports Python versions 2.7, 3.3, 3.4, 3.5, 3.6 + +.. note:: Pillow >= 5.0.0 supports Python versions 2.7, 3.4, 3.5, 3.6 Basic Installation ------------------ @@ -382,16 +384,16 @@ These platforms are built and tested for every change. +----------------------------------+-------------------------------+-----------------------+ | Fedora 26 | 2.7 |x86-64 | +----------------------------------+-------------------------------+-----------------------+ -| Mac OS X 10.10 Yosemite* | 2.7, 3.3, 3.4, 3.5, 3.6 |x86-64 | +| Mac OS X 10.10 Yosemite* | 2.7, 3.4, 3.5, 3.6 |x86-64 | +----------------------------------+-------------------------------+-----------------------+ | Ubuntu Linux 16.04 LTS | 2.7 |x86-64 | +----------------------------------+-------------------------------+-----------------------+ -| Ubuntu Linux 14.04 LTS | 2.7, 3.3, 3.4, 3.5, 3.6, |x86-64 | +| Ubuntu Linux 14.04 LTS | 2.7, 3.4, 3.5, 3.6, |x86-64 | | | pypy, pypy3 | | | | | | | | 2.7 |x86 | +----------------------------------+-------------------------------+-----------------------+ -| Windows Server 2012 R2 | 2.7, 3.3, 3.4 |x86, x86-64 | +| Windows Server 2012 R2 | 2.7, 3.4 |x86, x86-64 | | | | | | | pypy, 3.5/mingw |x86 | +----------------------------------+-------------------------------+-----------------------+ diff --git a/docs/releasenotes/4.4.0.rst b/docs/releasenotes/5.0.0.rst similarity index 64% rename from docs/releasenotes/4.4.0.rst rename to docs/releasenotes/5.0.0.rst index 101a513df..886b673c0 100644 --- a/docs/releasenotes/4.4.0.rst +++ b/docs/releasenotes/5.0.0.rst @@ -1,6 +1,17 @@ -4.4.0 +5.0.0 ----- +Backwards Incompatible Changes +============================== + +Python 3.3 Dropped +^^^^^^^^^^^^^^^^^^ + +Python 3.3 is EOL and no longer supported due to moving testing from nose, +which is deprecated, to pytest, which doesn't support Python 3.3. We will not +be creating binaries, testing, or retaining compatibility with this version. +The final version of Pillow for Python 3.3 is 4.3.0. + API Changes =========== @@ -17,7 +28,6 @@ Further, the vendored version was removed in Pillow 4.0.0 and replaced with a deprecation warning that PIL.OleFileIO would be removed in a future version. This warning has been upgraded to an import error pending future removal. - API Additions ============= diff --git a/docs/releasenotes/index.rst b/docs/releasenotes/index.rst index 27fc61870..0ee853fca 100644 --- a/docs/releasenotes/index.rst +++ b/docs/releasenotes/index.rst @@ -6,7 +6,7 @@ Release Notes .. toctree:: :maxdepth: 2 - 4.4.0 + 5.0.0 4.3.0 4.2.1 4.2.0 diff --git a/mp_compile.py b/mp_compile.py index 59f14a651..5fac2399f 100644 --- a/mp_compile.py +++ b/mp_compile.py @@ -54,19 +54,12 @@ def _mp_compile(self, sources, output_dir=None, macros=None, def install(): - fl_pypy3 = (hasattr(sys, 'pypy_version_info') and - (3, 0) < sys.version_info < (3, 3)) fl_win = sys.platform.startswith('win') fl_cygwin = sys.platform.startswith('cygwin') - if fl_pypy3: - # see https://github.com/travis-ci/travis-ci/issues/3587 - print("Single threaded build for pypy3") - return - if fl_win or fl_cygwin: - # windows barfs on multiprocessing installs - print("Single threaded build for windows") + # Windows barfs on multiprocessing installs + print("Single threaded build for Windows") return if MAX_PROCS != 1: diff --git a/profile-installed.py b/profile-installed.py deleted file mode 100755 index e3a04c21c..000000000 --- a/profile-installed.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python -import os -import sys -import glob - -import profile - -# monkey with the path, removing the local directory but adding the Tests/ -# directory for helper.py and the other local imports there. - -del(sys.path[0]) -sys.path.insert(0, os.path.abspath('./Tests')) - -# if there's no test selected (mostly) choose a working default. -# Something is required, because if we import the tests from the local -# directory, once again, we've got the non-installed PIL in the way -if len(sys.argv) == 1: - sys.argv.extend(glob.glob('Tests/test*.py')) - -# Make sure that nose doesn't muck with our paths. -if ('--no-path-adjustment' not in sys.argv) and ('-P' not in sys.argv): - sys.argv.insert(1, '--no-path-adjustment') - -if __name__ == '__main__': - profile.run("nose.main()", sort=2) diff --git a/requirements.txt b/requirements.txt index 213f145ab..4cb3c0907 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,10 +11,10 @@ docutils jarn.viewdoc Jinja2 MarkupSafe -nose -nose-cov olefile pycodestyle +pytest +pytest-cov pyflakes Pygments pyroma diff --git a/setup.cfg b/setup.cfg index 0c9e0fc14..8032517f6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,6 @@ +[aliases] +test=pytest [metadata] license_file = LICENSE +[tool:pytest] +addopts = -vx Tests diff --git a/setup.py b/setup.py index 9319b7372..5c36302bd 100755 --- a/setup.py +++ b/setup.py @@ -751,6 +751,9 @@ def debug_build(): return hasattr(sys, 'gettotalrefcount') +needs_pytest = {'pytest', 'test', 'ptr'}.intersection(sys.argv) +pytest_runner = ['pytest-runner'] if needs_pytest else [] + try: setup(name=NAME, version=PILLOW_VERSION, @@ -770,19 +773,19 @@ try: "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ], - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*", + python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", cmdclass={"build_ext": pil_build_ext}, ext_modules=[Extension("PIL._imaging", ["_imaging.c"])], include_package_data=True, packages=find_packages(), - test_suite='nose.collector', + setup_requires=pytest_runner, + tests_require=['pytest'], keywords=["Imaging", ], license='Standard PIL License', zip_safe=not (debug_build() or PLATFORM_MINGW), ) diff --git a/test-installed.py b/test-installed.py deleted file mode 100755 index c5aff1360..000000000 --- a/test-installed.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python -import nose -import os -import sys -import glob - -# monkey with the path, removing the local directory but adding the Tests/ -# directory for helper.py and the other local imports there. - -del(sys.path[0]) -sys.path.insert(0, os.path.abspath('./Tests')) - -# if there's no test selected (mostly) choose a working default. -# Something is required, because if we import the tests from the local -# directory, once again, we've got the non-installed PIL in the way -for arg in sys.argv[1:]: - if '.py' in arg: - break -else: - sys.argv.extend(glob.glob('Tests/test*.py')) - -# Make sure that nose doesn't muck with our paths. -if ('--no-path-adjustment' not in sys.argv) and ('-P' not in sys.argv): - sys.argv.insert(1, '--no-path-adjustment') - -if 'NOSE_PROCESSES' not in os.environ: - for arg in sys.argv: - if '--processes' in arg: - break - else: # for - sys.argv.insert(1, '--processes=-1') # -1 == number of cores - sys.argv.insert(1, '--process-timeout=30') - -if __name__ == '__main__': - nose.main() diff --git a/tox.ini b/tox.ini index 84ac7135e..0d2e41765 100644 --- a/tox.ini +++ b/tox.ini @@ -11,4 +11,4 @@ commands = {envpython} setup.py clean {envpython} setup.py build_ext --inplace {envpython} selftest.py - {envpython} test-installed.py --installed + {envpython} -m pytest -qq diff --git a/winbuild/README.md b/winbuild/README.md index 89d60de62..5ecbf18c6 100644 --- a/winbuild/README.md +++ b/winbuild/README.md @@ -1,18 +1,18 @@ Quick README ------------- +------------ -For more extensive info, see the windows build instructions `docs/build.rst`. +For more extensive info, see the Windows build instructions `docs/build.rst`. -* See https://github.com/python-pillow/Pillow/issues/553#issuecomment-37877416 and https://github.com/matplotlib/matplotlib/issues/1717#issuecomment-13343859 +* See https://github.com/python-pillow/Pillow/issues/553#issuecomment-37877416 and https://github.com/matplotlib/matplotlib/issues/1717#issuecomment-13343859 * Works best with Python 3.4, due to virtualenv and pip batteries included. Python3+ required for fetch command. * Check config.py for virtual env paths, suffix for 64-bit releases. Defaults to `x64`, set `X64_EXT` to change. * When running in CI with one Python per invocation, set the `PYTHON` env variable to the Python folder. (e.g. `PYTHON`=`c:\Python27\`) This overrides the matrix in config.py and will just build and test for the specific Python. * `python get_pythons.py` downloads all the Python releases, and their signatures. (Manually) Install in `c:\PythonXX[x64]\`. -* `python build_dep.py` downloads and creates a build script for all the dependencies, in 32 and 64 bit versions, and with both compiler versions. +* `python build_dep.py` downloads and creates a build script for all the dependencies, in 32 and 64-bit versions, and with both compiler versions. * (in powershell) `build_deps.cmd` invokes the dependency build. * `python build.py --clean` makes Pillow for the matrix of Pythons. * `python test.py` runs the tests on Pillow in all the virtual envs. -* Currently working with zlib, libjpeg, freetype, and libtiff on Python 2.7, 3.3, and 3.4, both 32 and 64 bit, on a local win7 pro machine and appveyor.com -* Webp is built, not detected. -* LCMS, OpenJpeg and libimagequant are not building. +* Currently working with zlib, libjpeg, freetype, and libtiff on Python 2.7, and 3.4, both 32 and 64-bit, on a local win7 pro machine and appveyor.com +* WebP is built, not detected. +* LCMS, OpenJPEG and libimagequant are not building. diff --git a/winbuild/appveyor_install_msys2_deps.sh b/winbuild/appveyor_install_msys2_deps.sh index 52b814433..b13dc9e98 100644 --- a/winbuild/appveyor_install_msys2_deps.sh +++ b/winbuild/appveyor_install_msys2_deps.sh @@ -7,5 +7,5 @@ pacman -S --noconfirm mingw32/mingw-w64-i686-python3 \ mingw32/mingw-w64-i686-python2-setuptools \ mingw-w64-i686-libjpeg-turbo -/mingw32/bin/pip install nose olefile -/mingw32/bin/pip3 install nose olefile +/mingw32/bin/pip install pytest pytest-cov olefile +/mingw32/bin/pip3 install pytest pytest-cov olefile diff --git a/winbuild/build.py b/winbuild/build.py index 3d6c6e57f..859a40277 100755 --- a/winbuild/build.py +++ b/winbuild/build.py @@ -16,7 +16,7 @@ def setup_vms(): for arch in ('', X64_EXT): ret.append("virtualenv -p c:/Python%s%s/python.exe --clear %s%s%s" % (py, arch, VIRT_BASE, py, arch)) - ret.append(r"%s%s%s\Scripts\pip.exe install nose" % + ret.append(r"%s%s%s\Scripts\pip.exe install pytest pytest-cov" % (VIRT_BASE, py, arch)) return "\n".join(ret) @@ -76,7 +76,7 @@ def build_one(py_ver, compiler): args['executable'] = "python.exe" if 'EXECUTABLE' in os.environ: args['executable'] = "%EXECUTABLE%" - + args['py_ver'] = py_ver if '34' in py_ver: args['tcl_ver'] = '86' diff --git a/winbuild/get_pythons.py b/winbuild/get_pythons.py index 481283df3..448450afb 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.3.5', '3.4.3']: + for version in ['2.7.10', '3.4.3']: for platform in ['', '.amd64']: for extension in ['', '.asc']: fetch('https://www.python.org/ftp/python/%s/python-%s%s.msi%s'