diff --git a/.gitignore b/.gitignore index aa45f946fa7..242f50845a2 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/install.sh b/.travis/install.sh index 694a460e919..8d5e973fb46 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 coverage pip install olefile +pip install -U pytest +pip install -U pytest-cov pip install pyroma -pip install coverage # docs only on Python 2.7 if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then pip install -r requirements.txt ; fi diff --git a/.travis/script.sh b/.travis/script.sh index e1d52212273..1473ab07925 100755 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -6,8 +6,8 @@ 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 setup.py test pushd /tmp/check-manifest && check-manifest --ignore ".coveragerc,.editorconfig,*.yml,*.yaml,tox.ini" && popd # Docs diff --git a/Makefile b/Makefile index d27afaa0bb3..7d9d3447205 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,7 +78,7 @@ 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 check-manifest @@ -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/Tests/README.rst b/Tests/README.rst index 0985e0f260c..f0118c62941 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 @@ -39,6 +38,3 @@ To run an individual test:: Run all the tests from the root of the Pillow source distribution:: ./test-installed.py - - - diff --git a/Tests/helper.py b/Tests/helper.py index 1375eb7e5dd..609db153623 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -42,8 +42,9 @@ 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) + # proxy = self.currentResult + # ok = (len(proxy.errors) + len(proxy.failures) == 0) + ok = True # TODO pytest if ok: # only clean out tempfiles if test passed @@ -180,7 +181,7 @@ class PillowLeakTestCase(PillowTestCase): # requires unix/osx iterations = 100 # count mem_limit = 512 # k - + def _get_mem_usage(self): """ Gets the RUSAGE memory usage, returns in K. Encapsulates the difference @@ -188,7 +189,7 @@ def _get_mem_usage(self): :returns; memory usage in kilobytes """ - + from resource import getpagesize, getrusage, RUSAGE_SELF mem = getrusage(RUSAGE_SELF).ru_maxrss if sys.platform == 'darwin': @@ -199,7 +200,7 @@ def _get_mem_usage(self): # linux # man 2 getrusage # ru_maxrss (since Linux 2.6.32) - # This is the maximum resident set size used (in kilobytes). + # This is the maximum resident set size used (in kilobytes). return mem # Kb def _test_leak(self, core): diff --git a/appveyor.yml b/appveyor.yml index d966c88ffef..94886c8b62e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -74,8 +74,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/profile-installed.py b/profile-installed.py deleted file mode 100755 index e3a04c21cb8..00000000000 --- 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 213f145ab09..4cb3c090704 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 0c9e0fc1447..4a133839622 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,6 @@ +[aliases] +test=pytest [metadata] license_file = LICENSE +[tool:pytest] +addopts = -vx --cov PIL --cov-report term Tests diff --git a/setup.py b/setup.py index 58a282ac300..1902d937307 100755 --- a/setup.py +++ b/setup.py @@ -59,6 +59,7 @@ class RequiredDependencyException(Exception): pass PLATFORM_MINGW = 'mingw' in ccompiler.get_default_compiler() PLATFORM_PYPY = hasattr(sys, 'pypy_version_info') + def _dbg(s, tp=None): if DEBUG: if tp: @@ -748,6 +749,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, @@ -779,7 +783,8 @@ def debug_build(): include_package_data=True, packages=find_packages(), scripts=glob.glob("Scripts/*.py"), - 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 c5aff1360c4..00000000000 --- 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/winbuild/appveyor_install_msys2_deps.sh b/winbuild/appveyor_install_msys2_deps.sh index 52b81443324..b13dc9e98b0 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 3d6c6e57f54..859a4027787 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'