Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAINT/TST: update tests to use pytest #477

Merged
merged 14 commits into from
Mar 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ include = */pywt/*
omit =
*/version.py
*/pywt/tests/*
*/pywt/_doc_utils.py*
*/pywt/data/create_dat.py
*.pxd
stringsource
Expand Down
11 changes: 7 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ before_install:
- pip install $NUMPYSPEC
- pip install $MATPLOTLIBSPEC
- pip install $CYTHONSPEC
- pip install nose coverage codecov futures
- pip install pytest pytest-cov coverage codecov futures
- set -o pipefail
- if [ "${USE_WHEEL}" == "1" ]; then pip install wheel; fi
- |
Expand All @@ -72,23 +72,26 @@ script:
pip wheel . -v
pip install PyWavelets*.whl -v
pushd demo
nosetests pywt
pytest --pyargs pywt
python ../pywt/tests/test_doc.py
popd
elif [ "${USE_SDIST}" == "1" ]; then
python setup.py sdist
# Move out of source directory to avoid finding local pywt
pushd dist
pip install PyWavelets* -v
nosetests pywt
pytest --pyargs pywt
python ../pywt/tests/test_doc.py
popd
elif [ "${REFGUIDE_CHECK}" == "1" ]; then
pip install -e . -v
python util/refguide_check.py --doctests
else
CFLAGS="--coverage" python setup.py build --build-lib build/lib/ --build-temp build/tmp/
nosetests build/lib/ --tests pywt/tests
CFLAGS="--coverage" pip install -e . -v
pushd demo
pytest --pyargs pywt --cov=pywt
popd
fi

after_success:
Expand Down
14 changes: 13 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Copyright (c) 2006-2012 Filip Wasilewski <http://en.ig.ma/>
Copyright (c) 2012-2017 The PyWavelets Developers <https://github.com/PyWavelets/pywt>
Copyright (c) 2012-2019 The PyWavelets Developers <https://github.com/PyWavelets/pywt>

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
Expand All @@ -18,3 +18,15 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


The PyWavelets repository and source distributions bundle some code that is
adapted from compatibly licensed projects. We list these here.

Name: NumPy
Files: pywt/_pytesttester.py
License: 3-clause BSD

Name: SciPy
Files: setup.py, util/*
License: 3-clause BSD
8 changes: 5 additions & 3 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ install:
- "util\\appveyor\\build.cmd %PYTHON%\\python.exe -m pip install
numpy --cache-dir c:\\tmp\\pip-cache"
- "util\\appveyor\\build.cmd %PYTHON%\\python.exe -m pip install
Cython nose coverage matplotlib futures --cache-dir c:\\tmp\\pip-cache"
Cython pytest coverage matplotlib futures --cache-dir c:\\tmp\\pip-cache"

test_script:
- "util\\appveyor\\build.cmd %PYTHON%\\python.exe setup.py build --build-lib build\\lib\\"
- "%PYTHON%\\Scripts\\nosetests build\\lib --tests pywt\\tests"
- "util\\appveyor\\build.cmd %PYTHON%\\python.exe -m pip install -e . -v"
- "cd demo"
- "%PYTHON%\\Scripts\\pytest --pyargs pywt"
- "cd .."

after_test:
- "util\\appveyor\\build.cmd %PYTHON%\\python.exe setup.py bdist_wheel"
Expand Down
23 changes: 16 additions & 7 deletions doc/source/dev/testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,22 @@ does not break the build.
Running tests locally
---------------------

Tests are implemented with `nose`_, so use one of:
Tests are implemented with `pytest`_, so use one of:

$ nosetests pywt
$ pytest --pyargs pywt -v

>>> pywt.test() # doctest: +SKIP
There are also older doctests that can be run by performing the following from
the root of the project source.

Note doctests require `Matplotlib`_ in addition to the usual dependencies.
$ python pywt/tests/test_doc.py
$ cd doc
$ make doctest

Additionally the examples in the demo subfolder can be checked by running:

$ python util/refguide_check.py

Note: doctests require `Matplotlib`_ in addition to the usual dependencies.


Running tests with Tox
Expand All @@ -43,6 +52,6 @@ To for example run tests for Python 3.5 and 3.6 use::
For more information see the `Tox`_ documentation.


.. _nose: http://nose.readthedocs.org/en/latest/
.. _Tox: http://tox.testrun.org/
.. _Matplotlib: http://matplotlib.org
.. _pytest: https://pytest.org
.. _Tox: https://tox.readthedocs.io/en/latest/
.. _Matplotlib: https://matplotlib.org
15 changes: 15 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[pytest]
addopts = -l
norecursedirs = doc tools pywt/_extensions
doctest_optionflags = NORMALIZE_WHITESPACE ELLIPSIS ALLOW_UNICODE ALLOW_BYTES

filterwarnings =
error
# Filter out annoying import messages.
ignore:Not importing directory
ignore:numpy.dtype size changed
ignore:numpy.ufunc size changed
ignore::UserWarning:cpuinfo,

env =
PYTHONHASHSEED=0
11 changes: 3 additions & 8 deletions pywt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@

from pywt.version import version as __version__

import numpy as np
if np.lib.NumpyVersion(np.__version__) >= '1.14.0':
from ._utils import is_nose_running
if is_nose_running():
np.set_printoptions(legacy='1.13')

from numpy.testing import Tester
test = Tester().test
from ._pytesttester import PytestTester
test = PytestTester(__name__)
del PytestTester
68 changes: 68 additions & 0 deletions pywt/_pytest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""common test-related code."""
import os
import sys
import multiprocessing
import numpy as np
import pytest


__all__ = ['uses_matlab', # skip if pymatbridge and Matlab unavailable
'uses_futures', # skip if futures unavailable
'uses_pymatbridge', # skip if no PYWT_XSLOW environment variable
'uses_precomputed', # skip if PYWT_XSLOW environment variable found
'matlab_result_dict_cwt', # dict with precomputed Matlab dwt data
'matlab_result_dict_dwt', # dict with precomputed Matlab cwt data
'futures', # the futures module or None
'max_workers', # the number of workers available to futures
'size_set', # the set of Matlab tests to run
]

try:
if sys.version_info[0] == 2:
import futures
else:
from concurrent import futures
max_workers = multiprocessing.cpu_count()
futures_available = True
except ImportError:
futures_available = False
futures = None

# check if pymatbridge + MATLAB tests should be run
matlab_result_dict_dwt = None
matlab_result_dict_cwt = None
matlab_missing = True
use_precomputed = True
size_set = 'reduced'
if 'PYWT_XSLOW' in os.environ:
try:
from pymatbridge import Matlab
mlab = Matlab()
matlab_missing = False
use_precomputed = False
size_set = 'full'
except ImportError:
print("To run Matlab compatibility tests you need to have MathWorks "
"MATLAB, MathWorks Wavelet Toolbox and the pymatbridge Python "
"package installed.")
if use_precomputed:
# load dictionaries of precomputed results
data_dir = os.path.join(os.path.dirname(__file__), 'tests', 'data')
matlab_data_file_cwt = os.path.join(
data_dir, 'cwt_matlabR2015b_result.npz')
matlab_result_dict_cwt = np.load(matlab_data_file_cwt)

matlab_data_file_dwt = os.path.join(
data_dir, 'dwt_matlabR2012a_result.npz')
matlab_result_dict_dwt = np.load(matlab_data_file_dwt)

uses_futures = pytest.mark.skipif(
not futures_available, reason='futures not available')
uses_matlab = pytest.mark.skipif(
matlab_missing, reason='pymatbridge and/or Matlab not available')
uses_pymatbridge = pytest.mark.skipif(
use_precomputed,
reason='PYWT_XSLOW set: skipping tests against precomputed Matlab results')
uses_precomputed = pytest.mark.skipif(
not use_precomputed,
reason='PYWT_XSLOW not set: test against precomputed matlab tests')
164 changes: 164 additions & 0 deletions pywt/_pytesttester.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
"""
Pytest test running.

This module implements the ``test()`` function for NumPy modules. The usual
boiler plate for doing that is to put the following in the module
``__init__.py`` file::

from pywt._pytesttester import PytestTester
test = PytestTester(__name__).test
del PytestTester


Warnings filtering and other runtime settings should be dealt with in the
``pytest.ini`` file in the pywt repo root. The behavior of the test depends on
whether or not that file is found as follows:

* ``pytest.ini`` is present (develop mode)
All warnings except those explicily filtered out are raised as error.
* ``pytest.ini`` is absent (release mode)
DeprecationWarnings and PendingDeprecationWarnings are ignored, other
warnings are passed through.

In practice, tests run from the PyWavelets repo are run in develop mode. That
includes the standard ``python runtests.py`` invocation.

"""
from __future__ import division, absolute_import, print_function

import sys
import os

__all__ = ['PytestTester']


def _show_pywt_info():
import pywt
from pywt._c99_config import _have_c99_complex
print("PyWavelets version %s" % pywt.__version__)
if _have_c99_complex:
print("Compiled with C99 complex support.")
else:
print("Compiled without C99 complex support.")


class PytestTester(object):
"""
Pytest test runner.

This class is made available in ``pywt.testing``, and a test function
is typically added to a package's __init__.py like so::

from pywt.testing import PytestTester
test = PytestTester(__name__).test
del PytestTester

Calling this test function finds and runs all tests associated with the
module and all its sub-modules.

Attributes
----------
module_name : str
Full path to the package to test.

Parameters
----------
module_name : module name
The name of the module to test.

"""
def __init__(self, module_name):
self.module_name = module_name

def __call__(self, label='fast', verbose=1, extra_argv=None,
doctests=False, coverage=False, durations=-1, tests=None):
"""
Run tests for module using pytest.

Parameters
----------
label : {'fast', 'full'}, optional
Identifies the tests to run. When set to 'fast', tests decorated
with `pytest.mark.slow` are skipped, when 'full', the slow marker
is ignored.
verbose : int, optional
Verbosity value for test outputs, in the range 1-3. Default is 1.
extra_argv : list, optional
List with any extra arguments to pass to pytests.
doctests : bool, optional
.. note:: Not supported
coverage : bool, optional
If True, report coverage of NumPy code. Default is False.
Requires installation of (pip) pytest-cov.
durations : int, optional
If < 0, do nothing, If 0, report time of all tests, if > 0,
report the time of the slowest `timer` tests. Default is -1.
tests : test or list of tests
Tests to be executed with pytest '--pyargs'

Returns
-------
result : bool
Return True on success, false otherwise.

Examples
--------
>>> result = np.lib.test() #doctest: +SKIP
...
1023 passed, 2 skipped, 6 deselected, 1 xfailed in 10.39 seconds
>>> result
True

"""
import pytest

module = sys.modules[self.module_name]
module_path = os.path.abspath(module.__path__[0])

# setup the pytest arguments
pytest_args = ["-l"]

# offset verbosity. The "-q" cancels a "-v".
pytest_args += ["-q"]

# Filter out annoying import messages. Want these in both develop and
# release mode.
pytest_args += [
"-W ignore:Not importing directory",
"-W ignore:numpy.dtype size changed",
"-W ignore:numpy.ufunc size changed", ]

if doctests:
raise ValueError("Doctests not supported")

if extra_argv:
pytest_args += list(extra_argv)

if verbose > 1:
pytest_args += ["-" + "v"*(verbose - 1)]

if coverage:
pytest_args += ["--cov=" + module_path]

if label == "fast":
pytest_args += ["-m", "not slow"]
elif label != "full":
pytest_args += ["-m", label]

if durations >= 0:
pytest_args += ["--durations=%s" % durations]

if tests is None:
tests = [self.module_name]

pytest_args += ["--pyargs"] + list(tests)

# run tests.
_show_pywt_info()

try:
code = pytest.main(pytest_args)
except SystemExit as exc:
code = exc.code

return code == 0
Loading