From: Paul Brossier Date: Sat, 17 Nov 2018 15:38:29 +0000 (+0100) Subject: Merge branch 'master' into feature/pytest X-Git-Tag: 0.4.9~71^2~11 X-Git-Url: https://git.aubio.org/?p=aubio.git;a=commitdiff_plain;h=a95b3861bc9d28a6f0b6ba313a29b2cdc3562ecf;hp=2eb52bd821788405d5e380c71249ac91d58d22ed Merge branch 'master' into feature/pytest --- diff --git a/.appveyor.yml b/.appveyor.yml index 9da9024c..10b45fae 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -83,4 +83,4 @@ build_script: test_script: - "python python\\demos\\demo_create_test_sounds.py" - - "nose2 --verbose" + - "pytest --verbose" diff --git a/.circleci/config.yml b/.circleci/config.yml index 81a685e8..eb007381 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,16 +19,16 @@ install-wheel: &install-wheel command: | pip install --user dist/aubio*.whl -test-nose2: &test-nose2 +test-pytest: &test-pytest name: Test python wheel command: | make create_test_sounds - PATH=/home/circleci/.local/bin:$PATH nose2 -v + PATH=/home/circleci/.local/bin:$PATH pytest -v -test-nose2-nosounds: &test-nose2-nosounds +test-pytest-nosounds: &test-pytest-nosounds name: Test python wheel command: | - PATH=/home/circleci/.local/bin:$PATH nose2 -v + PATH=/home/circleci/.local/bin:$PATH pytest -v uninstall-wheel: &uninstall-wheel name: Uninstall python wheel @@ -47,7 +47,7 @@ jobs: - run: *pip-install - run: *build-wheel - run: *install-wheel - - run: *test-nose2 + - run: *test-pytest - run: *uninstall-wheel - store_artifacts: path: dist/ @@ -61,7 +61,7 @@ jobs: - run: *pip-install - run: *build-wheel - run: *install-wheel - - run: *test-nose2 + - run: *test-pytest - run: *uninstall-wheel - store_artifacts: path: dist/ @@ -75,7 +75,7 @@ jobs: - run: *pip-install - run: *build-wheel - run: *install-wheel - - run: *test-nose2 + - run: *test-pytest - run: *uninstall-wheel - store_artifacts: path: dist/ @@ -88,7 +88,7 @@ jobs: - run: *pip-install - run: *build-wheel - run: *install-wheel - - run: *test-nose2-nosounds + - run: *test-pytest-nosounds - run: *uninstall-wheel - store_artifacts: path: dist/ diff --git a/MANIFEST.in b/MANIFEST.in index c16c93aa..4b14a709 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -5,7 +5,6 @@ include waf recursive-include waflib *.py include Makefile wscript */wscript_build include aubio.pc.in -include nose2.cfg include requirements.txt include src/*.c src/*.h include src/*/*.c src/*/*.h @@ -14,7 +13,6 @@ include tests/*.h tests/*/*.c tests/*/*/*.c include python/ext/*.h recursive-include python *.py include python/README.md -include python/tests/run_all_tests include python/tests/eval_pitch include python/tests/*.expected include doc/*.txt doc/*.rst doc/*.cfg doc/Makefile doc/make.bat doc/conf.py diff --git a/Makefile b/Makefile index bfc5bd4e..380d3138 100644 --- a/Makefile +++ b/Makefile @@ -35,8 +35,8 @@ INCLUDEDIR?=$(PREFIX)/include DATAROOTDIR?=$(PREFIX)/share MANDIR?=$(DATAROOTDIR)/man -# default nose2 command -NOSE2?=nose2 -N 4 --verbose +# default python test command +PYTEST?=pytest --verbose SOX=sox @@ -138,9 +138,7 @@ test_python: export LD_LIBRARY_PATH=$(DESTDIR)/$(LIBDIR) test_python: export PYTHONPATH=$(PYDESTDIR)/$(LIBDIR) test_python: local_dylib # run test with installed package - # ./python/tests/run_all_tests --verbose - # run with nose2, multiple processes - $(NOSE2) + $(PYTEST) clean_python: ./setup.py clean @@ -247,7 +245,7 @@ coverage: force_uninstall_python deps_python \ clean_python clean distclean build local_dylib lcov --capture --no-external --directory . --output-file build/coverage_lib.info pip install -v -e . - coverage run `which nose2` + coverage run `which pytest` lcov --capture --no-external --directory . --output-file build/coverage_python.info lcov -a build/coverage_python.info -a build/coverage_lib.info -o build/coverage.info diff --git a/doc/python_module.rst b/doc/python_module.rst index cb4d595e..8c3c3776 100644 --- a/doc/python_module.rst +++ b/doc/python_module.rst @@ -67,8 +67,14 @@ The command line `aubio` is also installed: Python tests ------------ -A number of `python tests`_ are provided. To run them, use -``python/tests/run_all_tests``. +A number of python tests are provided. To run them, use [pytest] from the +aubio source tree: -.. _demo_filter.py: https://github.com/aubio/aubio/blob/master/python/demos/demo_filter.py -.. _python tests: https://github.com/aubio/aubio/blob/master/python/tests + $ cd aubio + $ pytest + +Each test script can also be called individually. For instance: + + $ ./python/tests/test_note2midi.py -v + +[pytest]: https://pytest.org diff --git a/nose2.cfg b/nose2.cfg deleted file mode 100644 index d1be6d8f..00000000 --- a/nose2.cfg +++ /dev/null @@ -1,6 +0,0 @@ -[unittest] -start-dir = python/tests/ -plugins = nose2.plugins.mp - -[multiprocess] -always-on = false diff --git a/python/README.md b/python/README.md index dbb8ff37..7e2e7836 100644 --- a/python/README.md +++ b/python/README.md @@ -35,17 +35,18 @@ sounds. Testing the Python module ------------------------- -Python tests are in `python/tests` and use the [nose2 python package][nose2]. +Python tests are in `python/tests` and use [pytest]. -To run the all the python tests, use the script: +To run the all the python tests: - $ ./python/tests/run_all_tests + $ cd aubio + $ pytest Each test script can also be called one at a time. For instance: - $ ./python/tests/test_note2midi.py -v + $ pytest -v python/tests/test_note2midi.py -[nose2]: https://github.com/nose-devs/nose2 +[pytest]: https://pytest.org Install in a virtualenv ----------------------- diff --git a/python/tests/__init__.py b/python/tests/__init__.py deleted file mode 100644 index 8b137891..00000000 --- a/python/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/python/tests/_tools.py b/python/tests/_tools.py new file mode 100644 index 00000000..41216563 --- /dev/null +++ b/python/tests/_tools.py @@ -0,0 +1,41 @@ +""" +This file imports test methods from different testing modules, in this +order: + + - try importing 'pytest' + - if it fails, fallback to 'numpy.testing' + +Nose2 support was removed because of lacking assertWarns on py2.7. + +""" + +import sys + +_has_pytest = False + +# check if we have pytest +try: + import pytest + parametrize = pytest.mark.parametrize + assert_raises = pytest.raises + assert_warns = pytest.warns + skipTest = pytest.skip + _has_pytest = True + def run_module_suite(): + import sys, pytest + pytest.main(sys.argv) +except: + pass + +# otherwise fallback on numpy.testing +if not _has_pytest: + from numpy.testing import dec, assert_raises, assert_warns + from numpy.testing import SkipTest + parametrize = dec.parametrize + def skipTest(msg): + raise SkipTest(msg) + from numpy.testing import run_module_suite + +# always use numpy's assert_equal +import numpy +assert_equal = numpy.testing.assert_equal diff --git a/python/tests/run_all_tests b/python/tests/run_all_tests deleted file mode 100755 index bc6bb8c0..00000000 --- a/python/tests/run_all_tests +++ /dev/null @@ -1,5 +0,0 @@ -#! /usr/bin/env python - -if __name__ == '__main__': - import nose2.main - nose2.discover() diff --git a/python/tests/test_aubio.py b/python/tests/test_aubio.py index 98a61154..5768cac9 100755 --- a/python/tests/test_aubio.py +++ b/python/tests/test_aubio.py @@ -1,6 +1,5 @@ #! /usr/bin/env python -from unittest import main from numpy.testing import TestCase class aubiomodule_test_case(TestCase): @@ -15,5 +14,5 @@ class aubiomodule_test_case(TestCase): self.assertEqual('0', aubio.version[0]) if __name__ == '__main__': + from unittest import main main() - diff --git a/python/tests/test_aubio_cmd.py b/python/tests/test_aubio_cmd.py index 44e16fb3..471ac85c 100755 --- a/python/tests/test_aubio_cmd.py +++ b/python/tests/test_aubio_cmd.py @@ -1,8 +1,7 @@ #! /usr/bin/env python -import aubio.cmd -from nose2 import main from numpy.testing import TestCase +import aubio.cmd class aubio_cmd(TestCase): @@ -31,4 +30,5 @@ class aubio_cmd_utils(TestCase): "3200\t") if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/test_aubio_cut.py b/python/tests/test_aubio_cut.py index cbbfe05f..01ad2c6f 100755 --- a/python/tests/test_aubio_cut.py +++ b/python/tests/test_aubio_cut.py @@ -1,7 +1,6 @@ #! /usr/bin/env python import aubio.cut -from nose2 import main from numpy.testing import TestCase class aubio_cut(TestCase): @@ -13,4 +12,5 @@ class aubio_cut(TestCase): assert self.a_parser.parse_args(['-v']).verbose if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/test_cvec.py b/python/tests/test_cvec.py index 5632784d..73ee6549 100755 --- a/python/tests/test_cvec.py +++ b/python/tests/test_cvec.py @@ -1,6 +1,5 @@ #! /usr/bin/env python -from unittest import main import numpy as np from numpy.testing import TestCase, assert_equal from aubio import cvec, fvec, float_type @@ -141,4 +140,5 @@ class aubio_cvec_wrong_norm_input(TestCase): a.norm = np.zeros((512//2+1, 2), dtype = float_type) if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/test_dct.py b/python/tests/test_dct.py index 0c990f9f..c9b2ba7a 100755 --- a/python/tests/test_dct.py +++ b/python/tests/test_dct.py @@ -66,3 +66,7 @@ class aubio_dct(TestCase): aubio.dct(size) except AssertionError: self.skipTest('creating aubio.dct with size %d did not fail' % size) + +if __name__ == '__main__': + from unittest import main + main() diff --git a/python/tests/test_fft.py b/python/tests/test_fft.py index 484b7149..abe95d3f 100755 --- a/python/tests/test_fft.py +++ b/python/tests/test_fft.py @@ -1,6 +1,5 @@ #! /usr/bin/env python -from unittest import main from numpy.testing import TestCase from numpy.testing import assert_equal, assert_almost_equal import numpy as np @@ -212,4 +211,5 @@ class aubio_fft_wrong_params(TestCase): fft(win_s) if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/test_filter.py b/python/tests/test_filter.py index 6a7a0ded..af588dcb 100755 --- a/python/tests/test_filter.py +++ b/python/tests/test_filter.py @@ -1,9 +1,8 @@ #! /usr/bin/env python -from unittest import main from numpy.testing import TestCase, assert_equal, assert_almost_equal from aubio import fvec, digital_filter -from .utils import array_from_text_file +from utils import array_from_text_file class aubio_filter_test_case(TestCase): @@ -84,4 +83,5 @@ class aubio_filter_wrong_params(TestCase): digital_filter(-1) if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/test_filterbank.py b/python/tests/test_filterbank.py index 8808ba80..67a8558c 100755 --- a/python/tests/test_filterbank.py +++ b/python/tests/test_filterbank.py @@ -4,7 +4,7 @@ import numpy as np from numpy.testing import TestCase, assert_equal, assert_almost_equal from aubio import cvec, filterbank, float_type -from .utils import array_from_text_file +from utils import array_from_text_file class aubio_filterbank_test_case(TestCase): @@ -87,5 +87,5 @@ class aubio_filterbank_wrong_values(TestCase): f(cvec(256)) if __name__ == '__main__': - import nose2 - nose2.main() + from unittest import main + main() diff --git a/python/tests/test_filterbank_mel.py b/python/tests/test_filterbank_mel.py index 4f9f7ec9..07712647 100755 --- a/python/tests/test_filterbank_mel.py +++ b/python/tests/test_filterbank_mel.py @@ -2,12 +2,10 @@ import numpy as np from numpy.testing import TestCase, assert_equal, assert_almost_equal +from _tools import assert_warns from aubio import fvec, cvec, filterbank, float_type -import warnings -warnings.filterwarnings('ignore', category=UserWarning, append=True) - class aubio_filterbank_mel_test_case(TestCase): def test_slaney(self): @@ -75,40 +73,41 @@ class aubio_filterbank_mel_test_case(TestCase): samplerate = 22050 freq_list = [0, samplerate//4, samplerate // 2 + 1] f = filterbank(len(freq_list)-2, 1024) - # TODO add assert_warns - f.set_triangle_bands(fvec(freq_list), samplerate) + with assert_warns(UserWarning): + f.set_triangle_bands(fvec(freq_list), samplerate) def test_triangle_freqs_with_not_enough_filters(self): """make sure set_triangle_bands warns when not enough filters""" samplerate = 22050 freq_list = [0, 100, 1000, 4000, 8000, 10000] f = filterbank(len(freq_list)-3, 1024) - # TODO add assert_warns - f.set_triangle_bands(fvec(freq_list), samplerate) + with assert_warns(UserWarning): + f.set_triangle_bands(fvec(freq_list), samplerate) def test_triangle_freqs_with_too_many_filters(self): """make sure set_triangle_bands warns when too many filters""" samplerate = 22050 freq_list = [0, 100, 1000, 4000, 8000, 10000] f = filterbank(len(freq_list)-1, 1024) - # TODO add assert_warns - f.set_triangle_bands(fvec(freq_list), samplerate) + with assert_warns(UserWarning): + f.set_triangle_bands(fvec(freq_list), samplerate) def test_triangle_freqs_with_double_value(self): """make sure set_triangle_bands works with 2 duplicate freqs""" samplerate = 22050 freq_list = [0, 100, 1000, 4000, 4000, 4000, 10000] f = filterbank(len(freq_list)-2, 1024) - # TODO add assert_warns - f.set_triangle_bands(fvec(freq_list), samplerate) + with assert_warns(UserWarning): + f.set_triangle_bands(fvec(freq_list), samplerate) def test_triangle_freqs_with_triple(self): """make sure set_triangle_bands works with 3 duplicate freqs""" samplerate = 22050 freq_list = [0, 100, 1000, 4000, 4000, 4000, 10000] f = filterbank(len(freq_list)-2, 1024) - # TODO add assert_warns - f.set_triangle_bands(fvec(freq_list), samplerate) + with assert_warns(UserWarning): + f.set_triangle_bands(fvec(freq_list), samplerate) + def test_triangle_freqs_without_norm(self): """make sure set_triangle_bands works without """ @@ -168,5 +167,5 @@ class aubio_filterbank_mel_test_case(TestCase): if __name__ == '__main__': - import nose2 - nose2.main() + from unittest import main + main() diff --git a/python/tests/test_fvec.py b/python/tests/test_fvec.py index 60623ac9..765c9fed 100755 --- a/python/tests/test_fvec.py +++ b/python/tests/test_fvec.py @@ -1,6 +1,5 @@ #! /usr/bin/env python -from unittest import main import numpy as np from numpy.testing import TestCase, assert_equal, assert_almost_equal from aubio import fvec, zero_crossing_rate, alpha_norm, min_removal @@ -148,4 +147,5 @@ class aubio_fvec_test_memory(TestCase): del c if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/test_fvec_shift.py b/python/tests/test_fvec_shift.py index 929fd565..c7a03154 100644 --- a/python/tests/test_fvec_shift.py +++ b/python/tests/test_fvec_shift.py @@ -30,6 +30,6 @@ class aubio_shift_test_case(TestCase): def test_can_shift_fvec_odd(self): self.run_shift_ishift(7) -from unittest import main if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/test_mathutils.py b/python/tests/test_mathutils.py index f68fb110..ee68966c 100755 --- a/python/tests/test_mathutils.py +++ b/python/tests/test_mathutils.py @@ -1,6 +1,5 @@ #! /usr/bin/env python -from unittest import main from numpy.testing import TestCase, assert_equal from numpy import array, arange, isnan, isinf from aubio import bintomidi, miditobin, freqtobin, bintofreq, freqtomidi, miditofreq @@ -101,4 +100,5 @@ class aubio_mathutils(TestCase): assert_equal ( array(b) < 0, False ) if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/test_mfcc.py b/python/tests/test_mfcc.py index e7f3b186..d54f44e1 100755 --- a/python/tests/test_mfcc.py +++ b/python/tests/test_mfcc.py @@ -1,7 +1,6 @@ #! /usr/bin/env python -from nose2 import main -from nose2.tools import params +from _tools import parametrize, assert_raises from numpy import random, count_nonzero from numpy.testing import TestCase from aubio import mfcc, cvec, float_type @@ -15,28 +14,21 @@ samplerate = 44100 new_params = ['buf_size', 'n_filters', 'n_coeffs', 'samplerate'] new_deflts = [1024, 40, 13, 44100] -class aubio_mfcc(TestCase): +class Test_aubio_mfcc(object): - def setUp(self): - self.o = mfcc() + members_args = 'name' - def test_default_creation(self): - pass - - def test_delete(self): - del self.o - - @params(*new_params) + @parametrize(members_args, new_params) def test_read_only_member(self, name): - o = self.o - with self.assertRaises((TypeError, AttributeError)): + o = mfcc() + with assert_raises((TypeError, AttributeError)): setattr(o, name, 0) - @params(*zip(new_params, new_deflts)) + @parametrize('name, expected', zip(new_params, new_deflts)) def test_default_param(self, name, expected): """ test mfcc.{:s} = {:d} """.format(name, expected) - o = self.o - self.assertEqual( getattr(o, name), expected) + o = mfcc() + assert getattr(o, name) == expected class aubio_mfcc_wrong_params(TestCase): @@ -82,9 +74,9 @@ class aubio_mfcc_compute(TestCase): #print coeffs -class aubio_mfcc_all_parameters(TestCase): +class Test_aubio_mfcc_all_parameters(object): - @params( + run_values = [ (2048, 40, 13, 44100), (1024, 40, 13, 44100), (512, 40, 13, 44100), @@ -100,7 +92,10 @@ class aubio_mfcc_all_parameters(TestCase): #(1024, 30, 20, 44100), (1024, 40, 40, 44100), (1024, 40, 3, 44100), - ) + ] + run_args = ['buf_size', 'n_filters', 'n_coeffs', 'samplerate'] + + @parametrize(run_args, run_values) def test_run_with_params(self, buf_size, n_filters, n_coeffs, samplerate): " check mfcc can run with reasonable parameters " o = mfcc(buf_size, n_filters, n_coeffs, samplerate) @@ -111,4 +106,5 @@ class aubio_mfcc_all_parameters(TestCase): #print coeffs if __name__ == '__main__': - main() + from _tools import run_module_suite + run_module_suite() diff --git a/python/tests/test_midi2note.py b/python/tests/test_midi2note.py index 056738e3..5451c581 100755 --- a/python/tests/test_midi2note.py +++ b/python/tests/test_midi2note.py @@ -2,8 +2,7 @@ # -*- coding: utf-8 -*- from aubio import midi2note -from nose2.tools import params -import unittest +from _tools import parametrize, assert_raises list_of_known_midis = ( ( 0, 'C-1' ), @@ -15,31 +14,31 @@ list_of_known_midis = ( ( 127, 'G9' ), ) -class midi2note_good_values(unittest.TestCase): +class Test_midi2note_good_values(object): - @params(*list_of_known_midis) + @parametrize('midi, note', list_of_known_midis) def test_midi2note_known_values(self, midi, note): " known values are correctly converted " - self.assertEqual ( midi2note(midi), note ) + assert midi2note(midi) == (note) -class midi2note_wrong_values(unittest.TestCase): +class Test_midi2note_wrong_values(object): def test_midi2note_negative_value(self): " fails when passed a negative value " - self.assertRaises(ValueError, midi2note, -2) + assert_raises(ValueError, midi2note, -2) def test_midi2note_large(self): " fails when passed a value greater than 127 " - self.assertRaises(ValueError, midi2note, 128) + assert_raises(ValueError, midi2note, 128) def test_midi2note_floating_value(self): " fails when passed a floating point " - self.assertRaises(TypeError, midi2note, 69.2) + assert_raises(TypeError, midi2note, 69.2) def test_midi2note_character_value(self): " fails when passed a value that can not be transformed to integer " - self.assertRaises(TypeError, midi2note, "a") + assert_raises(TypeError, midi2note, "a") if __name__ == '__main__': - import nose2 - nose2.main() + from _tools import run_module_suite + run_module_suite() diff --git a/python/tests/test_musicutils.py b/python/tests/test_musicutils.py index dd54abb3..eaa774f2 100755 --- a/python/tests/test_musicutils.py +++ b/python/tests/test_musicutils.py @@ -1,9 +1,8 @@ #! /usr/bin/env python -from unittest import main import numpy as np from numpy.testing import TestCase -from numpy.testing.utils import assert_equal, assert_almost_equal +from numpy.testing import assert_equal, assert_almost_equal from aubio import window, level_lin, db_spl, silence_detection, level_detection from aubio import fvec, float_type @@ -85,4 +84,5 @@ class aubio_level_detection(TestCase): assert level_detection(ones(1024, dtype = float_type), -70) == 0 if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/test_note2midi.py b/python/tests/test_note2midi.py index 3bbf1c87..06081958 100755 --- a/python/tests/test_note2midi.py +++ b/python/tests/test_note2midi.py @@ -4,8 +4,8 @@ from __future__ import unicode_literals from aubio import note2midi, freq2note, note2freq, float_type -from nose2.tools import params -import unittest +from numpy.testing import TestCase +from _tools import parametrize, assert_raises, skipTest list_of_known_notes = ( ( 'C-1', 0 ), @@ -44,29 +44,32 @@ list_of_unknown_notes = ( ( '2' ), ) -class note2midi_good_values(unittest.TestCase): +class Test_note2midi_good_values(object): - @params(*list_of_known_notes) + @parametrize('note, midi', list_of_known_notes) def test_note2midi_known_values(self, note, midi): " known values are correctly converted " - self.assertEqual ( note2midi(note), midi ) + assert note2midi(note) == midi - @params(*list_of_known_notes_with_unicode_issues) + @parametrize('note, midi', list_of_known_notes_with_unicode_issues) def test_note2midi_known_values_with_unicode_issues(self, note, midi): - " known values are correctly converted, unless decoding is expected to fail" + " difficult values are correctly converted unless expected failure " try: - self.assertEqual ( note2midi(note), midi ) + assert note2midi(note) == midi except UnicodeEncodeError as e: + # platforms with decoding failures include: + # - osx: python <= 2.7.10 + # - win: python <= 2.7.12 import sys - strfmt = "len(u'\\U0001D12A') != 1, excpected decoding failure | {:s} | {:s} {:s}" - strres = strfmt.format(e, sys.platform, sys.version) - # happens with: darwin 2.7.10, windows 2.7.12 + strmsg = "len(u'\\U0001D12A') != 1, expected decoding failure" + strmsg += " | upgrade to Python 3 to fix" + strmsg += " | {:s} | {:s} {:s}" if len('\U0001D12A') != 1 and sys.version[0] == '2': - self.skipTest(strres + " | upgrade to Python 3 to fix") + skipTest(strmsg.format(repr(e), sys.platform, sys.version)) else: raise -class note2midi_wrong_values(unittest.TestCase): +class note2midi_wrong_values(TestCase): def test_note2midi_missing_octave(self): " fails when passed only one character" @@ -104,12 +107,14 @@ class note2midi_wrong_values(unittest.TestCase): " fails when passed a note with a note name longer than expected" self.assertRaises(ValueError, note2midi, 'CB+-3') - @params(*list_of_unknown_notes) +class Test_note2midi_unknown_values(object): + + @parametrize('note', list_of_unknown_notes) def test_note2midi_unknown_values(self, note): " unknown values throw out an error " - self.assertRaises(ValueError, note2midi, note) + assert_raises(ValueError, note2midi, note) -class freq2note_simple_test(unittest.TestCase): +class freq2note_simple_test(TestCase): def test_freq2note_above(self): " make sure freq2note(441) == A4 " @@ -119,7 +124,7 @@ class freq2note_simple_test(unittest.TestCase): " make sure freq2note(439) == A4 " self.assertEqual("A4", freq2note(439)) -class note2freq_simple_test(unittest.TestCase): +class note2freq_simple_test(TestCase): def test_note2freq(self): " make sure note2freq('A3') == 220" @@ -133,5 +138,5 @@ class note2freq_simple_test(unittest.TestCase): self.assertLess(abs(note2freq("A4")-440), 1.e-12) if __name__ == '__main__': - import nose2 - nose2.main() + from _tools import run_module_suite + run_module_suite() diff --git a/python/tests/test_notes.py b/python/tests/test_notes.py index 5b65046f..a95d0101 100755 --- a/python/tests/test_notes.py +++ b/python/tests/test_notes.py @@ -1,8 +1,11 @@ #! /usr/bin/env python -from unittest import main from numpy.testing import TestCase, assert_equal, assert_almost_equal -from aubio import notes +from aubio import notes, source +import numpy as np +from utils import list_all_sounds + +list_of_sounds = list_all_sounds('sounds') AUBIO_DEFAULT_NOTES_SILENCE = -70. AUBIO_DEFAULT_NOTES_RELEASE_DROP = 10. @@ -52,14 +55,9 @@ class aubio_notes_params(TestCase): with self.assertRaises(ValueError): self.o.set_release_drop(val) -from .utils import list_all_sounds -list_of_sounds = list_all_sounds('sounds') - class aubio_notes_sinewave(TestCase): def analyze_file(self, filepath, samplerate=0): - from aubio import source - import numpy as np win_s = 512 # fft size hop_s = 256 # hop size @@ -92,4 +90,5 @@ class aubio_notes_sinewave(TestCase): assert_equal (results[0][1], [69, 123, -1]) if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/test_onset.py b/python/tests/test_onset.py index 8b5f7ba3..08343e20 100755 --- a/python/tests/test_onset.py +++ b/python/tests/test_onset.py @@ -1,6 +1,5 @@ #! /usr/bin/env python -from unittest import main from numpy.testing import TestCase, assert_equal, assert_almost_equal from aubio import onset @@ -84,4 +83,5 @@ class aubio_onset_8000(aubio_onset_params): samplerate = 8000 if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/test_phasevoc.py b/python/tests/test_phasevoc.py index 957d3b1a..e17d1fda 100755 --- a/python/tests/test_phasevoc.py +++ b/python/tests/test_phasevoc.py @@ -1,9 +1,8 @@ #! /usr/bin/env python from numpy.testing import TestCase, assert_equal, assert_array_less +from _tools import parametrize from aubio import fvec, cvec, pvoc, float_type -from nose2 import main -from nose2.tools import params import numpy as np if float_type == 'float32': @@ -18,7 +17,7 @@ def create_sine(hop_s, freq, samplerate): def create_noise(hop_s): return np.random.rand(hop_s).astype(float_type) * 2. - 1. -class aubio_pvoc_test_case(TestCase): +class Test_aubio_pvoc_test_case(object): """ pvoc object test case """ def test_members_automatic_sizes_default(self): @@ -56,7 +55,8 @@ class aubio_pvoc_test_case(TestCase): + 'This is expected when using fftw3 on powerpc.') assert_equal ( r, 0.) - @params( + resynth_noise_args = "hop_s, ratio" + resynth_noise_values = [ ( 256, 8), ( 256, 4), ( 256, 2), @@ -78,13 +78,16 @@ class aubio_pvoc_test_case(TestCase): (8192, 8), (8192, 4), (8192, 2), - ) + ] + + @parametrize(resynth_noise_args, resynth_noise_values) def test_resynth_steps_noise(self, hop_s, ratio): """ check the resynthesis of a random signal is correct """ sigin = create_noise(hop_s) self.reconstruction(sigin, hop_s, ratio) - @params( + resynth_sine_args = "samplerate, hop_s, ratio, freq" + resynth_sine_values = [ (44100, 256, 8, 441), (44100, 256, 4, 1203), (44100, 256, 2, 3045), @@ -99,7 +102,9 @@ class aubio_pvoc_test_case(TestCase): (22050, 256, 8, 445), (96000, 1024, 8, 47000), (96000, 1024, 8, 20), - ) + ] + + @parametrize(resynth_sine_args, resynth_sine_values) def test_resynth_steps_sine(self, samplerate, hop_s, ratio, freq): """ check the resynthesis of a sine is correct """ sigin = create_sine(hop_s, freq, samplerate) @@ -190,5 +195,5 @@ class aubio_pvoc_wrong_params(TestCase): self.skipTest('creating aubio.pvoc with size %d did not fail' % win_s) if __name__ == '__main__': + from unittest import main main() - diff --git a/python/tests/test_pitch.py b/python/tests/test_pitch.py index 749c37b7..63055320 100755 --- a/python/tests/test_pitch.py +++ b/python/tests/test_pitch.py @@ -1,7 +1,6 @@ #! /usr/bin/env python -from unittest import TestCase, main -from numpy.testing import assert_equal +from numpy.testing import TestCase, assert_equal from numpy import sin, arange, mean, median, isnan, pi from aubio import fvec, pitch, freqtomidi, float_type @@ -116,10 +115,11 @@ def create_test (algo, mode): for algo in pitch_algorithms: for mode in signal_modes: - test_method = create_test (algo, mode) - test_method.__name__ = 'test_pitch_%s_%d_%d_%dHz_sin_%.0f' % ( algo, + _test_method = create_test (algo, mode) + _test_method.__name__ = 'test_pitch_%s_%d_%d_%dHz_sin_%.0f' % ( algo, mode[0], mode[1], mode[2], mode[3] ) - setattr (aubio_pitch_Sinusoid, test_method.__name__, test_method) + setattr (aubio_pitch_Sinusoid, _test_method.__name__, _test_method) if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/test_sink.py b/python/tests/test_sink.py index 795032ba..b9f9c56d 100755 --- a/python/tests/test_sink.py +++ b/python/tests/test_sink.py @@ -1,13 +1,9 @@ #! /usr/bin/env python -from nose2 import main -from nose2.tools import params from numpy.testing import TestCase from aubio import fvec, source, sink -from .utils import list_all_sounds, get_tmp_sink_path, del_tmp_sink_path - -import warnings -warnings.filterwarnings('ignore', category=UserWarning, append=True) +from utils import list_all_sounds, get_tmp_sink_path, del_tmp_sink_path +from _tools import parametrize, skipTest, assert_raises list_of_sounds = list_all_sounds('sounds') samplerates = [0, 44100, 8000, 32000] @@ -23,30 +19,26 @@ for soundfile in list_of_sounds: for samplerate in samplerates: all_params.append((hop_size, samplerate, soundfile)) -class aubio_sink_test_case(TestCase): - - def setUp(self): - if not len(list_of_sounds): - self.skipTest('add some sound files in \'python/tests/sounds\'') +class Test_aubio_sink(object): def test_wrong_filename(self): - with self.assertRaises(RuntimeError): + with assert_raises(RuntimeError): sink('') def test_wrong_samplerate(self): - with self.assertRaises(RuntimeError): + with assert_raises(RuntimeError): sink(get_tmp_sink_path(), -1) def test_wrong_samplerate_too_large(self): - with self.assertRaises(RuntimeError): + with assert_raises(RuntimeError): sink(get_tmp_sink_path(), 1536001, 2) def test_wrong_channels(self): - with self.assertRaises(RuntimeError): + with assert_raises(RuntimeError): sink(get_tmp_sink_path(), 44100, -1) def test_wrong_channels_too_large(self): - with self.assertRaises(RuntimeError): + with assert_raises(RuntimeError): sink(get_tmp_sink_path(), 44100, 202020) def test_many_sinks(self): @@ -66,13 +58,13 @@ class aubio_sink_test_case(TestCase): g.close() shutil.rmtree(tmpdir) - @params(*all_params) + @parametrize('hop_size, samplerate, path', all_params) def test_read_and_write(self, hop_size, samplerate, path): - try: f = source(path, samplerate, hop_size) except RuntimeError as e: - self.skipTest('failed opening with hop_s = {:d}, samplerate = {:d} ({:s})'.format(hop_size, samplerate, str(e))) + err_msg = '{:s} (hop_s = {:d}, samplerate = {:d})' + skipTest(err_msg.format(str(e), hop_size, samplerate)) if samplerate == 0: samplerate = f.samplerate sink_path = get_tmp_sink_path() g = sink(sink_path, samplerate) @@ -84,12 +76,13 @@ class aubio_sink_test_case(TestCase): if read < f.hop_size: break del_tmp_sink_path(sink_path) - @params(*all_params) + @parametrize('hop_size, samplerate, path', all_params) def test_read_and_write_multi(self, hop_size, samplerate, path): try: f = source(path, samplerate, hop_size) except RuntimeError as e: - self.skipTest('failed opening with hop_s = {:d}, samplerate = {:d} ({:s})'.format(hop_size, samplerate, str(e))) + err_msg = '{:s} (hop_s = {:d}, samplerate = {:d})' + skipTest(err_msg.format(str(e), hop_size, samplerate)) if samplerate == 0: samplerate = f.samplerate sink_path = get_tmp_sink_path() g = sink(sink_path, samplerate, channels = f.channels) @@ -125,4 +118,5 @@ class aubio_sink_test_case(TestCase): g(vec, 128) if __name__ == '__main__': - main() + from _tools import run_module_suite + run_module_suite() diff --git a/python/tests/test_slicing.py b/python/tests/test_slicing.py index 1d8e42f8..18391e9e 100755 --- a/python/tests/test_slicing.py +++ b/python/tests/test_slicing.py @@ -1,10 +1,9 @@ #! /usr/bin/env python -from unittest import main from numpy.testing import TestCase, assert_equal from aubio import slice_source_at_stamps -from .utils import count_files_in_directory, get_default_test_sound -from .utils import count_samples_in_directory, count_samples_in_file +from utils import count_files_in_directory, get_default_test_sound +from utils import count_samples_in_directory, count_samples_in_file import tempfile import shutil @@ -167,4 +166,5 @@ class aubio_slicing_wrong_ends_test_case(TestCase): shutil.rmtree(self.output_dir) if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/test_source.py b/python/tests/test_source.py index d8809174..6d88c626 100755 --- a/python/tests/test_source.py +++ b/python/tests/test_source.py @@ -1,19 +1,17 @@ #! /usr/bin/env python -from nose2 import main -from nose2.tools import params + from numpy.testing import TestCase, assert_equal from aubio import source -from .utils import list_all_sounds - -import warnings -warnings.filterwarnings('ignore', category=UserWarning, append=True) +from utils import list_all_sounds +import unittest +from _tools import parametrize, assert_raises, assert_equal, skipTest list_of_sounds = list_all_sounds('sounds') samplerates = [0, 44100, 8000, 32000] hop_sizes = [512, 1024, 64] -path = None +default_test_sound = len(list_of_sounds) and list_of_sounds[0] or None all_params = [] for soundfile in list_of_sounds: @@ -21,24 +19,20 @@ for soundfile in list_of_sounds: for samplerate in samplerates: all_params.append((hop_size, samplerate, soundfile)) +no_sounds_msg = "no test sounds, add some in 'python/tests/sounds/'!" -class aubio_source_test_case_base(TestCase): - - def setUp(self): - if not len(list_of_sounds): - self.skipTest('add some sound files in \'python/tests/sounds\'') - self.default_test_sound = list_of_sounds[0] +_debug = False -class aubio_source_test_case(aubio_source_test_case_base): +class Test_aubio_source_test_case(object): - @params(*list_of_sounds) + @parametrize('filename', list_of_sounds) def test_close_file(self, filename): samplerate = 0 # use native samplerate hop_size = 256 f = source(filename, samplerate, hop_size) f.close() - @params(*list_of_sounds) + @parametrize('filename', list_of_sounds) def test_close_file_twice(self, filename): samplerate = 0 # use native samplerate hop_size = 256 @@ -46,7 +40,7 @@ class aubio_source_test_case(aubio_source_test_case_base): f.close() f.close() -class aubio_source_read_test_case(aubio_source_test_case_base): +class Test_aubio_source_read(object): def read_from_source(self, f): total_frames = 0 @@ -56,47 +50,51 @@ class aubio_source_read_test_case(aubio_source_test_case_base): if read < f.hop_size: assert_equal(samples[read:], 0) break - #result_str = "read {:.2f}s ({:d} frames in {:d} blocks at {:d}Hz) from {:s}" - #result_params = total_frames / float(f.samplerate), total_frames, total_frames//f.hop_size, f.samplerate, f.uri - #print (result_str.format(*result_params)) + if _debug: + result_str = "read {:.2f}s ({:d} frames" + result_str += " in {:d} blocks at {:d}Hz) from {:s}" + result_params = total_frames / float(f.samplerate), total_frames, \ + total_frames//f.hop_size, f.samplerate, f.uri + print (result_str.format(*result_params)) return total_frames - @params(*all_params) + @parametrize('hop_size, samplerate, soundfile', all_params) def test_samplerate_hopsize(self, hop_size, samplerate, soundfile): try: f = source(soundfile, samplerate, hop_size) except RuntimeError as e: - self.skipTest('failed opening with hop_s = {:d}, samplerate = {:d} ({:s})'.format(hop_size, samplerate, str(e))) + err_msg = 'failed opening with hop_s={:d}, samplerate={:d} ({:s})' + skipTest(err_msg.format(hop_size, samplerate, str(e))) assert f.samplerate != 0 read_frames = self.read_from_source(f) if 'f_' in soundfile and samplerate == 0: import re - f = re.compile('.*_\([0:9]*f\)_.*') + f = re.compile(r'.*_\([0:9]*f\)_.*') match_f = re.findall('([0-9]*)f_', soundfile) if len(match_f) == 1: expected_frames = int(match_f[0]) - self.assertEqual(expected_frames, read_frames) + assert_equal(expected_frames, read_frames) - @params(*list_of_sounds) + @parametrize('p', list_of_sounds) def test_samplerate_none(self, p): f = source(p) assert f.samplerate != 0 self.read_from_source(f) - @params(*list_of_sounds) + @parametrize('p', list_of_sounds) def test_samplerate_0(self, p): f = source(p, 0) assert f.samplerate != 0 self.read_from_source(f) - @params(*list_of_sounds) + @parametrize('p', list_of_sounds) def test_zero_hop_size(self, p): f = source(p, 0, 0) assert f.samplerate != 0 assert f.hop_size != 0 self.read_from_source(f) - @params(*list_of_sounds) + @parametrize('p', list_of_sounds) def test_seek_to_half(self, p): from random import randint f = source(p, 0, 0) @@ -108,7 +106,7 @@ class aubio_source_read_test_case(aubio_source_test_case_base): b = self.read_from_source(f) assert a == b + c - @params(*list_of_sounds) + @parametrize('p', list_of_sounds) def test_duration(self, p): total_frames = 0 f = source(p) @@ -117,43 +115,44 @@ class aubio_source_read_test_case(aubio_source_test_case_base): _, read = f() total_frames += read if read < f.hop_size: break - self.assertEqual(duration, total_frames) + assert_equal (duration, total_frames) -class aubio_source_test_wrong_params(TestCase): +class Test_aubio_source_wrong_params(object): def test_wrong_file(self): - with self.assertRaises(RuntimeError): + with assert_raises(RuntimeError): source('path_to/unexisting file.mp3') -class aubio_source_test_wrong_params_with_file(aubio_source_test_case_base): +@unittest.skipIf(default_test_sound is None, no_sounds_msg) +class Test_aubio_source_wrong_params_with_file(TestCase): def test_wrong_samplerate(self): - with self.assertRaises(ValueError): - source(self.default_test_sound, -1) + with assert_raises(ValueError): + source(default_test_sound, -1) def test_wrong_hop_size(self): - with self.assertRaises(ValueError): - source(self.default_test_sound, 0, -1) + with assert_raises(ValueError): + source(default_test_sound, 0, -1) def test_wrong_channels(self): - with self.assertRaises(ValueError): - source(self.default_test_sound, 0, 0, -1) + with assert_raises(ValueError): + source(default_test_sound, 0, 0, -1) def test_wrong_seek(self): - f = source(self.default_test_sound) - with self.assertRaises(ValueError): + f = source(default_test_sound) + with assert_raises(ValueError): f.seek(-1) def test_wrong_seek_too_large(self): - f = source(self.default_test_sound) + f = source(default_test_sound) try: - with self.assertRaises(ValueError): + with assert_raises(ValueError): f.seek(f.duration + f.samplerate * 10) - except AssertionError: - self.skipTest('seeking after end of stream failed raising ValueError') + except: + skipTest('seeking after end of stream failed raising ValueError') -class aubio_source_readmulti_test_case(aubio_source_read_test_case): +class Test_aubio_source_readmulti(Test_aubio_source_read): def read_from_source(self, f): total_frames = 0 @@ -163,15 +162,18 @@ class aubio_source_readmulti_test_case(aubio_source_read_test_case): if read < f.hop_size: assert_equal(samples[:,read:], 0) break - #result_str = "read {:.2f}s ({:d} frames in {:d} channels and {:d} blocks at {:d}Hz) from {:s}" - #result_params = total_frames / float(f.samplerate), total_frames, f.channels, int(total_frames/f.hop_size), f.samplerate, f.uri - #print (result_str.format(*result_params)) + if _debug: + result_str = "read {:.2f}s ({:d} frames in {:d} channels" + result_str += " and {:d} blocks at {:d}Hz) from {:s}" + result_params = total_frames / float(f.samplerate), total_frames, \ + f.channels, int(total_frames/f.hop_size), \ + f.samplerate, f.uri + print (result_str.format(*result_params)) return total_frames -class aubio_source_with(aubio_source_test_case_base): +class Test_aubio_source_with(object): - #@params(*list_of_sounds) - @params(*list_of_sounds) + @parametrize('filename', list_of_sounds) def test_read_from_mono(self, filename): total_frames = 0 hop_size = 2048 @@ -185,4 +187,5 @@ class aubio_source_with(aubio_source_test_case_base): assert_equal(total_frames, input_source.duration) if __name__ == '__main__': - main() + from _tools import run_module_suite + run_module_suite() diff --git a/python/tests/test_specdesc.py b/python/tests/test_specdesc.py index d7769dce..32a46fe7 100755 --- a/python/tests/test_specdesc.py +++ b/python/tests/test_specdesc.py @@ -1,6 +1,5 @@ #! /usr/bin/env python -from unittest import main from numpy.testing import TestCase, assert_equal, assert_almost_equal from numpy import random, arange, log, zeros from aubio import specdesc, cvec, float_type @@ -229,4 +228,5 @@ class aubio_specdesc_wrong(TestCase): specdesc("unknown", 512) if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/test_zero_crossing_rate.py b/python/tests/test_zero_crossing_rate.py index 7f6d479c..21f9e405 100755 --- a/python/tests/test_zero_crossing_rate.py +++ b/python/tests/test_zero_crossing_rate.py @@ -1,6 +1,5 @@ #! /usr/bin/env python -from unittest import main from numpy.testing import TestCase from aubio import fvec, zero_crossing_rate @@ -43,4 +42,5 @@ class zero_crossing_rate_test_case(TestCase): self.assertEqual(2./buf_size, zero_crossing_rate(self.vector)) if __name__ == '__main__': + from unittest import main main() diff --git a/python/tests/utils.py b/python/tests/utils.py index b0963fc4..5b789eaa 100644 --- a/python/tests/utils.py +++ b/python/tests/utils.py @@ -8,11 +8,8 @@ from tempfile import mkstemp DEFAULT_SOUND = '22050Hz_5s_brownnoise.wav' def array_from_text_file(filename, dtype = 'float'): - filename = os.path.join(os.path.dirname(__file__), filename) - with open(filename) as f: - lines = f.readlines() - return np.array([line.split() for line in lines], - dtype = dtype) + realpathname = os.path.join(os.path.dirname(__file__), filename) + return np.loadtxt(realpathname, dtype = dtype) def list_all_sounds(rel_dir): datadir = os.path.join(os.path.dirname(__file__), rel_dir) @@ -38,13 +35,10 @@ def del_tmp_sink_path(path): try: os.unlink(path) except WindowsError as e: - print("deleting {:s} failed ({:s}), reopening".format(path, repr(e))) - with open(path, 'wb') as f: - f.close() - try: - os.unlink(path) - except WindowsError as f: - print("deleting {:s} failed ({:s}), aborting".format(path, repr(e))) + # removing the temporary directory sometimes fails on windows + import warnings + errmsg = "failed deleting temporary file {:s} ({:s})" + warnings.warn(UserWarning(errmsg.format(path, repr(e)))) def array_from_yaml_file(filename): import yaml diff --git a/requirements.txt b/requirements.txt index 99ce0ab5..1cc18fc7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ numpy -nose2 +pytest diff --git a/setup.py b/setup.py index 4ff5fcb0..a953e8c3 100755 --- a/setup.py +++ b/setup.py @@ -89,8 +89,4 @@ distrib = setup(name='aubio', 'aubiocut = aubio.cut:main', ], }, - test_suite = 'nose2.collector.collector', - extras_require = { - 'tests': ['numpy'], - }, )