From ff0aa027787845da62cff7e3b08d35e9385b9bdc Mon Sep 17 00:00:00 2001 From: Stefan Sullivan Date: Mon, 9 Dec 2024 23:02:13 -0800 Subject: [PATCH 01/10] development version bump --- jams/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jams/version.py b/jams/version.py index b8321287..093385af 100644 --- a/jams/version.py +++ b/jams/version.py @@ -3,4 +3,4 @@ """Version info""" short_version = '0.3' -version = '0.3.4' +version = '0.3.5a' From 5f4f1fd60aa396904e54236c5a96137879bf580a Mon Sep 17 00:00:00 2001 From: Stefan Sullivan Date: Mon, 2 Dec 2024 16:58:26 -0800 Subject: [PATCH 02/10] pkg_resources is deprecated. Replace with importlib --- jams/__init__.py | 16 +++++++--------- jams/schema.py | 9 +++------ 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/jams/__init__.py b/jams/__init__.py index ebcf0a18..9aa3c83d 100644 --- a/jams/__init__.py +++ b/jams/__init__.py @@ -2,7 +2,8 @@ """Top-level module for JAMS""" import os -from pkg_resources import resource_filename +from importlib import resources +from itertools import chain # Import the necessary modules from .exceptions import * @@ -18,14 +19,11 @@ # Populate the namespace mapping -for _ in util.find_with_extension(resource_filename(__name__, schema.NS_SCHEMA_DIR), - 'json'): - schema.add_namespace(_) +for ns in chain(*map(lambda p: p.rglob('*.json'), resources.files('jams.schemata.namespaces').iterdir())): + schema.add_namespace(ns) # Populate local namespaces -try: - for _ in util.find_with_extension(os.environ['JAMS_SCHEMA_DIR'], 'json'): - schema.add_namespace(_) -except KeyError: - pass +if 'JAMS_SCHEMA_DIR' in os.environ: + for ns in util.find_with_extension(os.environ['JAMS_SCHEMA_DIR'], 'json'): + schema.add_namespace(ns) diff --git a/jams/schema.py b/jams/schema.py index 561079a3..34c5c926 100644 --- a/jams/schema.py +++ b/jams/schema.py @@ -21,7 +21,6 @@ import json import os import copy -from pkg_resources import resource_filename import numpy as np import jsonschema @@ -231,11 +230,9 @@ def __get_dtype(typespec): def __load_jams_schema(): '''Load the schema file from the package.''' - - schema_file = os.path.join(SCHEMA_DIR, 'jams_schema.json') - - jams_schema = None - with open(resource_filename(__name__, schema_file), mode='r') as fdesc: + abs_schema_dir = os.path.join(os.path.dirname(__file__), SCHEMA_DIR) + schema_file = os.path.join(abs_schema_dir, 'jams_schema.json') + with open(schema_file, mode='r') as fdesc: jams_schema = json.load(fdesc) if jams_schema is None: From 6b6b1f3d5a19ce459bc1d6cbf1fc5a4c9b6aa186 Mon Sep 17 00:00:00 2001 From: Stefan Sullivan Date: Mon, 2 Dec 2024 17:00:33 -0800 Subject: [PATCH 03/10] Update pytest to version 8.x pytest 4.* is incompatible with python 3.12 because of importlib --- pyproject.toml | 13 +++++++++++++ setup.cfg | 2 -- setup.py | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 pyproject.toml delete mode 100644 setup.cfg diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..0d4c8318 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,13 @@ +[build-system] +requires = ["setuptools >= 61.0"] +build-backend = "setuptools.build_meta" + +[tool.pytest.ini_options] +addopts = [ + "-v", + "--cov-report=term-missing", + "--cov=jams", +] +testpaths = [ + "tests" +] \ No newline at end of file diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index f2c8a11a..00000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[tool:pytest] -addopts = -v --cov-report term-missing --cov jams diff --git a/setup.py b/setup.py index 1f5948dc..0506891b 100644 --- a/setup.py +++ b/setup.py @@ -55,7 +55,7 @@ def load_source(modname, filename): ], extras_require={ 'display': ['matplotlib>=1.5.0'], - 'tests': ['pytest < 4', 'pytest-cov'], + 'tests': ['pytest ~= 8.0', 'pytest-cov', 'matplotlib>=3'], }, scripts=['scripts/jams_to_lab.py'] ) From a5d0816a2a7790372a28794225b421253775309f Mon Sep 17 00:00:00 2001 From: Stefan Sullivan Date: Fri, 6 Dec 2024 03:46:06 -0800 Subject: [PATCH 04/10] pytest issues errors when invoking fixtures directly --- tests/test_jams.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_jams.py b/tests/test_jams.py index 3f952c82..d74a89b0 100644 --- a/tests/test_jams.py +++ b/tests/test_jams.py @@ -496,7 +496,6 @@ def test_jams_add_conflict(on_conflict): assert jam.file_metadata == jam_orig.file_metadata -@pytest.fixture(scope='module') def jam_search(): jam = jams.load('tests/fixtures/valid.jams', validate=False) jam.annotations[0].sandbox.foo = None From 885b90b9e1847a5ca673773227beb614ac523ca1 Mon Sep 17 00:00:00 2001 From: Stefan Sullivan Date: Fri, 6 Dec 2024 04:43:32 -0800 Subject: [PATCH 05/10] pytest doesn't like when you invoke a fixture --- tests/test_jams.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/tests/test_jams.py b/tests/test_jams.py index d74a89b0..02690338 100644 --- a/tests/test_jams.py +++ b/tests/test_jams.py @@ -496,22 +496,19 @@ def test_jams_add_conflict(on_conflict): assert jam.file_metadata == jam_orig.file_metadata -def jam_search(): - jam = jams.load('tests/fixtures/valid.jams', validate=False) - jam.annotations[0].sandbox.foo = None - return jam +jam = jams.load('tests/fixtures/valid.jams', validate=False) +jam.annotations[0].sandbox.foo = None @parametrize('query, expected', - [(dict(corpus='SMC_MIREX'), jam_search().annotations), + [(dict(corpus='SMC_MIREX'), jam.annotations), (dict(), []), - (dict(namespace='beat'), jam_search().annotations[:1]), - (dict(namespace='tag_open'), jam_search().annotations[1:]), + (dict(namespace='beat'), jam.annotations[:1]), + (dict(namespace='tag_open'), jam.annotations[1:]), (dict(namespace='segment_tut'), jams.AnnotationArray()), (dict(foo='bar'), jams.AnnotationArray())]) -def test_jams_search(jam_search, query, expected): - - result = jam_search.search(**query) +def test_jams_search(query, expected): + result = jam.search(**query) assert result == expected From eb6471592719e7815247114bc02be983b3c3d468 Mon Sep 17 00:00:00 2001 From: Stefan Sullivan Date: Fri, 6 Dec 2024 04:47:31 -0800 Subject: [PATCH 06/10] pytest doesn't let you mark individual parameters for failure --- tests/test_display.py | 10 +++++-- tests/test_jams.py | 64 +++++++++++++++++++++++++++++++++++-------- tests/test_ns.py | 17 +++++++----- tests/test_schema.py | 18 ++++++++---- 4 files changed, 83 insertions(+), 26 deletions(-) diff --git a/tests/test_display.py b/tests/test_display.py index fcbfd8d4..e7851d6d 100644 --- a/tests/test_display.py +++ b/tests/test_display.py @@ -18,14 +18,20 @@ @pytest.mark.parametrize('namespace', ['segment_open', 'chord', 'multi_segment', 'pitch_contour', 'beat_position', 'beat', - 'onset', 'note_midi', 'tag_open', - pytest.mark.xfail('tempo', raises=NamespaceError)]) + 'onset', 'note_midi', 'tag_open']) @pytest.mark.parametrize('meta', [False, True]) def test_display(namespace, meta): ann = jams.Annotation(namespace=namespace) jams.display.display(ann, meta=meta) +@pytest.mark.parametrize('namespace', ['tempo']) +@pytest.mark.parametrize('meta', [False, True]) +def test_display_exception(namespace, meta): + with pytest.raises(NamespaceError): + ann = jams.Annotation(namespace=namespace) + jams.display.display(ann, meta=meta) + def test_display_multi(): diff --git a/tests/test_jams.py b/tests/test_jams.py index 02690338..31bd26c2 100644 --- a/tests/test_jams.py +++ b/tests/test_jams.py @@ -289,8 +289,7 @@ def test_filemetadata(): assert meta[k] == dict_fm[k] -@parametrize('strict', [False, xfail(True, raises=jams.SchemaError)]) -def test_filemetadata_validation(strict): +def test_filemetadata_validation_warning(): # This should fail validation because null duration is not allowed fm = jams.FileMetadata(title='Test track', @@ -306,6 +305,17 @@ def test_filemetadata_validation(strict): assert len(out) > 0 assert out[0].category is UserWarning assert 'failed validating' in str(out[0].message).lower() +def test_filemetadata_validation_strict(): + # This should fail validation because null duration is not allowed + fm = jams.FileMetadata(title='Test track', + artist='Test artist', + release='Test release', + duration=None) + + clean_warning_registry() + + with pytest.raises(jams.SchemaError): + fm.validate(strict=True) # AnnotationArray @@ -473,9 +483,7 @@ def test_jams_add(tag_data): @parametrize('on_conflict', - ['overwrite', 'ignore', - xfail('fail', raises=jams.JamsError), - xfail('bad_fail_mdoe', raises=jams.ParameterError)]) + ['overwrite', 'ignore']) def test_jams_add_conflict(on_conflict): fn = 'tests/fixtures/valid.jams' @@ -496,6 +504,23 @@ def test_jams_add_conflict(on_conflict): assert jam.file_metadata == jam_orig.file_metadata +@parametrize('on_conflict,exception', [ + ('fail', jams.JamsError), + ('bad_fail_mdoe', jams.ParameterError) +]) +def test_jams_add_conflict_exceptions(on_conflict, exception): + fn = 'tests/fixtures/valid.jams' + + # The original jam + jam = jams.load(fn) + + # The copy + jam2 = jams.load(fn) + jam2.file_metadata = jams.FileMetadata() + + with pytest.raises(exception): + jam.add(jam2, on_conflict=on_conflict) + jam = jams.load('tests/fixtures/valid.jams', validate=False) jam.annotations[0].sandbox.foo = None @@ -529,18 +554,21 @@ def jam_validate(): return j1 -@parametrize('strict', [False, xfail(True, raises=jams.SchemaError)]) -def test_jams_validate_bad(jam_validate, strict): +def test_jams_validate_warning(jam_validate): clean_warning_registry() with warnings.catch_warnings(record=True) as out: jam_validate.validate(strict=strict) +def test_jams_validate_exception(jam_validate): assert len(out) > 0 assert out[0].category is UserWarning assert 'failed validating' in str(out[0].message).lower() + clean_warning_registry() + with pytest.raises(jams.SchemaError): + jam_validate.validate(strict=True) @xfail(raises=jams.SchemaError) def test_jams_bad_field(): @@ -549,8 +577,7 @@ def test_jams_bad_field(): jam.out_of_schema = None -@parametrize('strict', [False, xfail(True, raises=jams.SchemaError)]) -def test_jams_bad_annotation(strict): +def test_jams_bad_annotation_warnings(): jam = jams.JAMS() jam.file_metadata.duration = 10 @@ -560,14 +587,22 @@ def test_jams_bad_annotation(strict): with warnings.catch_warnings(record=True) as out: jam.validate(strict=strict) +def test_jams_bad_annotation_exception(): + jam = jams.JAMS() + jam.file_metadata.duration = 10 + + jam.annotations.append('not an annotation') assert len(out) > 0 assert out[0].category is UserWarning assert 'is not a well-formed jams annotation' in str(out[0].message).lower() + clean_warning_registry() + + with pytest.raises(jams.SchemaError): + jam.validate(strict=True) -@parametrize('strict', [False, xfail(True, raises=jams.SchemaError)]) -def test_jams_bad_jam(strict): +def test_jams_bad_jam_warning(): jam = jams.JAMS() clean_warning_registry() @@ -578,6 +613,13 @@ def test_jams_bad_jam(strict): assert len(out) > 0 assert out[0].category is UserWarning assert 'failed validating' in str(out[0].message).lower() +def test_jams_bad_jam_exception(): + jam = jams.JAMS() + + clean_warning_registry() + + with pytest.raises(jams.SchemaError): + jam.validate(strict=True) def test_jams_repr(input_jam): diff --git a/tests/test_ns.py b/tests/test_ns.py index 49f7c967..3f9122dc 100644 --- a/tests/test_ns.py +++ b/tests/test_ns.py @@ -328,19 +328,22 @@ def test_ns_contour_invalid(): @parametrize('value', - ['B#:locrian', six.u('A:minor'), 'N', 'E', - xfail('asdf', raises=SchemaError), - xfail('A&:phrygian', raises=SchemaError), - xfail(11, raises=SchemaError), - xfail('', raises=SchemaError), - xfail(':dorian', raises=SchemaError), - xfail(None, raises=SchemaError)]) + ['B#:locrian', six.u('A:minor'), 'N', 'E']) def test_ns_key_mode(value): ann = Annotation(namespace='key_mode') ann.append(time=0, duration=0, value=value, confidence=None) ann.validate() +@parametrize('value', + ['asdf', 'A&:phrygian', 11, '', ':dorian', None]) +def test_ns_key_mode_schema_error(value): + + ann = Annotation(namespace='key_mode') + ann.append(time=0, duration=0, value=value, confidence=None) + with pytest.raises(jams.SchemaError): + ann.validate() + @parametrize('value', ['A:9', 'Gb:sus2(1,3,5)', 'X', 'C:13(*9)/b7']) diff --git a/tests/test_schema.py b/tests/test_schema.py index c77996ef..36a74985 100644 --- a/tests/test_schema.py +++ b/tests/test_schema.py @@ -11,9 +11,7 @@ import jams -@pytest.mark.parametrize('ns_key', - ['pitch_hz', 'beat', - pytest.mark.xfail('DNE', raises=NamespaceError)]) +@pytest.mark.parametrize('ns_key', ['pitch_hz', 'beat']) def test_schema_namespace(ns_key): # Get the schema @@ -27,15 +25,23 @@ def test_schema_namespace(ns_key): for key in ['time', 'duration']: assert key in schema['properties'] +@pytest.mark.parametrize('ns_key', ['DNE']) +def test_schema_namespace_exception(ns_key): + with pytest.raises(NamespaceError): + jams.schema.namespace(ns_key) + @pytest.mark.parametrize('ns, dense', [('pitch_hz', True), - ('beat', False), - pytest.mark.xfail(('DNE', False), - raises=NamespaceError)]) + ('beat', False)]) def test_schema_is_dense(ns, dense): assert dense == jams.schema.is_dense(ns) +@pytest.mark.parametrize('ns', ['DNE']) +def test_schema_is_dense_exception(ns): + with pytest.raises(NamespaceError): + jams.schema.is_dense(ns) + @pytest.fixture def local_namespace(): From 281a536d00a46545664834a9cf03c38a2da57425 Mon Sep 17 00:00:00 2001 From: Stefan Sullivan Date: Mon, 9 Dec 2024 20:09:05 -0800 Subject: [PATCH 07/10] replace xfail with pytest.raises There's 2 reasons for this change: 1) pytest has deprecated xfail on parametrize'd values 2) xfail means that a test is _allowed_ to fail, whereas pytest.raises means that a test _passes_ when the exception is raised. Throwing an exception is not the same thing as failing a test. --- tests/test_convert.py | 8 +- tests/test_display.py | 6 +- tests/test_jams.py | 32 +- tests/test_ns.py | 749 ++++++++++++++++++++++-------------------- tests/test_schema.py | 12 +- tests/test_sonify.py | 8 +- 6 files changed, 430 insertions(+), 385 deletions(-) diff --git a/tests/test_convert.py b/tests/test_convert.py index adf0e13d..2041517d 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -9,23 +9,23 @@ from jams import NamespaceError -@pytest.mark.xfail(raises=NamespaceError) def test_bad_target(): ann = jams.Annotation(namespace='tag_open') ann.append(time=0, duration=1, value='foo', confidence=1) - jams.convert(ann, 'bad namespace') + with pytest.raises(NamespaceError): + jams.convert(ann, 'bad namespace') @pytest.mark.parametrize('target', ['pitch_hz', 'pitch_midi', 'segment_open', 'tag_open', 'beat', 'chord']) -@pytest.mark.xfail(raises=NamespaceError) def test_bad_sources(target): ann = jams.Annotation(namespace='vector') - jams.convert(ann, target) + with pytest.raises(NamespaceError): + jams.convert(ann, target) @pytest.mark.parametrize('namespace', list(jams.schema.__NAMESPACE__.keys())) diff --git a/tests/test_display.py b/tests/test_display.py index e7851d6d..40b3cd5c 100644 --- a/tests/test_display.py +++ b/tests/test_display.py @@ -75,8 +75,8 @@ def test_display_labeled_events(): jams.display.display(ann) -@pytest.mark.xfail(raises=jams.ParameterError) def test_display_multi_fail(): - anns = jams.AnnotationArray() - jams.display.display_multi(anns) + + with pytest.raises(jams.ParameterError): + jams.display.display_multi(anns) diff --git a/tests/test_jams.py b/tests/test_jams.py index 31bd26c2..f7e2e8da 100644 --- a/tests/test_jams.py +++ b/tests/test_jams.py @@ -267,12 +267,13 @@ def test_annotation_interval_values(tag_data): assert values == ['one', 'two'] -@xfail(raises=jams.JamsError) def test_annotation_badtype(): an = jams.Annotation(namespace='tag_open') + # This should throw a jams error because NoneType can't be indexed - an.data.add(None) + with pytest.raises(jams.JamsError): + an.data.add(None) # FileMetadata @@ -410,13 +411,14 @@ def test_annotation_array_composite(): assert len(jam.annotations['beat', 2::2]) == 4 -@xfail(raises=IndexError) def test_annotation_array_index_error(): jam = jams.JAMS() ann = jams.Annotation(namespace='beat') jam.annotations.append(ann) - jam.annotations[None] + + with pytest.raises(IndexError): + _ = jam.annotations[None] # JAMS @@ -570,11 +572,12 @@ def test_jams_validate_exception(jam_validate): with pytest.raises(jams.SchemaError): jam_validate.validate(strict=True) -@xfail(raises=jams.SchemaError) + def test_jams_bad_field(): jam = jams.JAMS() - jam.out_of_schema = None + with pytest.raises(jams.SchemaError): + jam.out_of_schema = None def test_jams_bad_annotation_warnings(): @@ -716,12 +719,12 @@ def __test_warn(filename, valid, strict): __test_warn(fn, True, False) -@xfail(raises=jams.ParameterError) def test_annotation_trim_bad_params(): # end_time must be greater than start_time ann = jams.Annotation('tag_open') - ann.trim(5, 3, strict=False) + with pytest.raises(jams.ParameterError): + ann.trim(5, 3, strict=False) def test_annotation_trim_no_duration(): @@ -979,12 +982,12 @@ def test_annotation_trim_multiple(): assert ann_trim.data == expected_ann.data -@xfail(raises=jams.JamsError) def test_jams_trim_no_duration(): # Empty jam has no file metadata, can't trim! jam = jams.JAMS() - jam.trim(0, 1, strict=False) + with pytest.raises(jams.JamsError): + jam.trim(0, 1, strict=False) def test_jams_trim_bad_params(): @@ -1249,7 +1252,6 @@ def test_annotation_to_samples(confidence): assert values == [['one'], ['one', 'two'], ['two', 'three'], ['three'], ['four'], []] -@pytest.mark.xfail(raises=jams.ParameterError) def test_annotation_to_samples_fail_neg(): ann = jams.Annotation('tag_open') @@ -1259,10 +1261,11 @@ def test_annotation_to_samples_fail_neg(): ann.append(time=0.75, duration=0.5, value='three', confidence=0.3) ann.append(time=1.5, duration=0.5, value='four', confidence=0.4) - values = ann.to_samples([-0.2, 0.4, 0.75, 1.25, 1.75, 1.4]) + with pytest.raises(jams.ParameterError): + values = ann.to_samples([-0.2, 0.4, 0.75, 1.25, 1.75, 1.4]) + -@pytest.mark.xfail(raises=jams.ParameterError) def test_annotation_to_samples_fail_shape(): ann = jams.Annotation('tag_open') @@ -1272,5 +1275,6 @@ def test_annotation_to_samples_fail_shape(): ann.append(time=0.75, duration=0.5, value='three', confidence=0.3) ann.append(time=1.5, duration=0.5, value='four', confidence=0.4) - values = ann.to_samples([[0.2, 0.4, 0.75, 1.25, 1.75, 1.4]]) + with pytest.raises(jams.ParameterError): + values = ann.to_samples([[0.2, 0.4, 0.75, 1.25, 1.75, 1.4]]) diff --git a/tests/test_ns.py b/tests/test_ns.py index 3f9122dc..96aaa748 100644 --- a/tests/test_ns.py +++ b/tests/test_ns.py @@ -7,6 +7,7 @@ import pytest +import jams from jams import SchemaError from jams import Annotation, Observation @@ -14,7 +15,6 @@ from test_util import srand -xfail = pytest.mark.xfail parametrize = pytest.mark.parametrize @@ -28,7 +28,6 @@ def test_ns_time_valid(): ann.validate() -@xfail(raises=SchemaError) @parametrize('time, duration', [(-1, 0), (1, -1)]) def test_ns_time_invalid(time, duration): @@ -38,7 +37,8 @@ def test_ns_time_invalid(time, duration): ann.data.add(Observation(time=time, duration=duration, value=None, confidence=None)) - ann.validate() + with pytest.raises(jams.SchemaError): + ann.validate() def test_ns_beat_valid(): @@ -55,7 +55,6 @@ def test_ns_beat_valid(): ann.validate() -@xfail(raises=SchemaError) def test_ns_beat_invalid(): ann = Annotation(namespace='beat') @@ -63,7 +62,8 @@ def test_ns_beat_invalid(): for time in np.arange(5.0): ann.append(time=time, duration=0.0, value='foo', confidence=None) - ann.validate() + with pytest.raises(jams.SchemaError): + ann.validate() def test_ns_beat_position_valid(): @@ -88,7 +88,6 @@ def test_ns_beat_position_valid(): ('beat_units', -1), ('beat_units', 1.5), ('beat_units', 3), ('beat_units', 'a'), ('beat_units', None)]) -@xfail(raises=SchemaError) def test_ns_beat_position_invalid(key, value): data = dict(position=1, measure=1, num_beats=3, beat_units=4) @@ -96,19 +95,22 @@ def test_ns_beat_position_invalid(key, value): ann = Annotation(namespace='beat_position') ann.append(time=0, duration=1.0, value=data) - ann.validate() + + with pytest.raises(jams.SchemaError): + ann.validate() @parametrize('key', ['position', 'measure', 'num_beats', 'beat_units']) -@xfail(raises=SchemaError) def test_ns_beat_position_missing(key): data = dict(position=1, measure=1, num_beats=3, beat_units=4) del data[key] ann = Annotation(namespace='beat_position') ann.append(time=0, duration=1.0, value=data) - ann.validate() + + with pytest.raises(jams.SchemaError): + ann.validate() def test_ns_mood_thayer_valid(): @@ -121,12 +123,12 @@ def test_ns_mood_thayer_valid(): @parametrize('value', [[0], [0, 1, 2], ['a', 'b'], None, 0]) -@xfail(raises=SchemaError) def test_ns_mood_thayer_invalid(value): ann = Annotation(namespace='mood_thayer') ann.append(time=0, duration=1.0, value=value) - ann.validate() + with pytest.raises(jams.SchemaError): + ann.validate() def test_ns_onset(): @@ -144,9 +146,7 @@ def test_ns_onset(): @parametrize('lyric', - ['Check yourself', six.u('before you wreck yourself'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError)]) + ['Check yourself', six.u('before you wreck yourself')]) def test_ns_lyrics(lyric): ann = Annotation(namespace='lyrics') @@ -154,6 +154,14 @@ def test_ns_lyrics(lyric): ann.validate() +@parametrize('lyric', [23, None]) +def test_ns_lyrics_invalid(lyric): + ann = Annotation(namespace='lyrics') + ann.append(time=0, duration=1, value=lyric) + with pytest.raises(SchemaError): + ann.validate() + + def test_ns_tempo_valid(): ann = Annotation(namespace='tempo') @@ -163,7 +171,6 @@ def test_ns_tempo_valid(): ann.validate() -@xfail(SchemaError) @parametrize('value, confidence', [(-1, 0.5), (-0.5, 0.5), ('a', 0.5), (120.0, -1), (120.0, -0.5), @@ -172,7 +179,9 @@ def test_ns_tempo_invalid(value, confidence): ann = Annotation(namespace='tempo') ann.append(time=0, duration=0, value=value, confidence=confidence) - ann.validate() + + with pytest.raises(jams.SchemaError): + ann.validate() def test_ns_note_hz_valid(): @@ -193,12 +202,13 @@ def test_ns_note_hz_valid(): @parametrize('value', ['a', -23]) -@xfail(raises=SchemaError) def test_ns_note_hz_invalid(value): ann = Annotation(namespace='note_hz') ann.append(time=0, duration=0, value=value, confidence=0.5) - ann.validate() + + with pytest.raises(jams.SchemaError): + ann.validate() def test_ns_pitch_hz_valid(): @@ -219,12 +229,13 @@ def test_ns_pitch_hz_valid(): @parametrize('value', ['a']) -@xfail(raises=SchemaError) def test_ns_pitch_hz_invalid(value): ann = Annotation(namespace='pitch_hz') ann.append(time=0, duration=0, value=value, confidence=0.5) - ann.validate() + + with pytest.raises(jams.SchemaError): + ann.validate() def test_ns_note_midi_valid(): @@ -245,12 +256,13 @@ def test_ns_note_midi_valid(): @parametrize('value', ['a']) -@xfail(raises=SchemaError) def test_ns_note_midi_invalid(value): ann = Annotation(namespace='note_midi') ann.append(time=0, duration=0, value=value, confidence=0.5) - ann.validate() + + with pytest.raises(jams.SchemaError): + ann.validate() def test_ns_pitch_midi_valid(): @@ -271,12 +283,13 @@ def test_ns_pitch_midi_valid(): @parametrize('value', ['a']) -@xfail(raises=SchemaError) def test_ns_pitch_midi_invalid(value): ann = Annotation(namespace='pitch_midi') ann.append(time=0, duration=0, value=value, confidence=0.5) - ann.validate() + + with pytest.raises(jams.SchemaError): + ann.validate() def test_ns_contour_valid(): @@ -361,12 +374,12 @@ def test_ns_chord_valid(value): for _ in [64, 'z', 'mj', 'Ab', 'iiii', False, None]] + ['C/{}'.format(_) for _ in ['A', 7.5, '8b']] + [None]) -@xfail(raises=SchemaError) def test_ns_chord_invalid(value): ann = Annotation(namespace='chord') ann.append(time=0, duration=1.0, value=value) - ann.validate() + with pytest.raises(SchemaError): + ann.validate() @parametrize('value', ['B:7', 'Gb:(1,3,5)', 'A#:(*3)', 'C:sus4(*5)/b7']) @@ -384,12 +397,12 @@ def test_ns_chord_harte_valid(value): for _ in [64, 'z', 'mj', 'Ab', 'iiii', False, None]] + ['C/{}'.format(_) for _ in ['A', 7.5, '8b']] + [None]) -@xfail(raises=SchemaError) def test_ns_chord_harte_invalid(value): ann = Annotation(namespace='chord_harte') ann.append(time=0, duration=1.0, value=value) - ann.validate() + with pytest.raises(SchemaError): + ann.validate() @parametrize('value', @@ -402,7 +415,6 @@ def test_ns_chord_roman_valid(value): ann.validate() -@xfail(SchemaError) @parametrize('key, value', [('tonic', 42), ('tonic', 'H'), ('tonic', 'a'), ('tonic', 'F#b'), @@ -418,10 +430,10 @@ def test_ns_chord_roman_invalid(key, value): ann = Annotation(namespace='chord_roman') ann.append(time=0, duration=1.0, value=data) - ann.validate() + with pytest.raises(SchemaError): + ann.validate() -@xfail(SchemaError) @parametrize('key', ['tonic', 'chord']) def test_ns_chord_roman_missing(key): data = dict(tonic='E', chord='iv64') @@ -429,7 +441,8 @@ def test_ns_chord_roman_missing(key): ann = Annotation(namespace='chord_roman') ann.append(time=0, duration=1.0, value=data) - ann.validate() + with pytest.raises(SchemaError): + ann.validate() @parametrize('value', @@ -449,207 +462,242 @@ def test_ns_pitch_class_valid(value): ('pitch', 1.5), ('pitch', 'xyz'), ('pitch', '3'), ('pitch', False), ('pitch', None)]) -@xfail(raises=SchemaError) def test_ns_pitch_class_invalid(key, value): data = dict(tonic='E', pitch=7) data[key] = value ann = Annotation(namespace='pitch_class') ann.append(time=0, duration=1.0, value=data) - ann.validate() + with pytest.raises(SchemaError): + ann.validate() @parametrize('key', ['tonic', 'pitch']) -@xfail(raises=SchemaError) def test_ns_pitch_class_missing(key): data = dict(tonic='E', pitch=7) del data[key] ann = Annotation(namespace='pitch_class') ann.append(time=0, duration=1.0, value=data) - ann.validate() - - -@parametrize('tag', - ['Emotion-Angry_/_Aggressive', - 'Genre--_Metal/Hard_Rock', - six.u('Genre-Best-Jazz'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError), - xfail('GENRE-BEST-JAZZ', raises=SchemaError)]) -def test_ns_tag_cal500(tag): - - ann = Annotation(namespace='tag_cal500') - ann.append(time=0, duration=1, value=tag) - ann.validate() - - -@parametrize('tag', - ['a dub production', "boomin' kick drum", - six.u('rock & roll ? roots'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError), - xfail('A DUB PRODUCTION', raises=SchemaError)]) -def test_ns_tag_cal10k(tag): + with pytest.raises(SchemaError): + ann.validate() - ann = Annotation(namespace='tag_cal10k') +@parametrize('namespace,tag', [ + ('tag_cal500', 'Emotion-Angry_/_Aggressive' ), + ('tag_cal500', 'Genre--_Metal/Hard_Rock' ), + ('tag_cal500', six.u('Genre-Best-Jazz') ), + ('tag_cal10k', 'a dub production'), + ('tag_cal10k', "boomin' kick drum"), + ('tag_cal10k', six.u('rock & roll ? roots')), + ('tag_gtzan', 'blues'), + ('tag_gtzan', 'classical'), + ('tag_gtzan', 'country'), + ('tag_gtzan', 'disco'), + ('tag_gtzan', 'hip-hop'), + ('tag_gtzan', 'jazz'), + ('tag_gtzan', 'metal'), + ('tag_gtzan', 'pop'), + ('tag_gtzan', 'reggae'), + ('tag_gtzan', six.u('rock')), + ('tag_msd_tagtraum_cd1', 'reggae'), + ('tag_msd_tagtraum_cd1', 'pop/rock'), + ('tag_msd_tagtraum_cd1', 'rnb'), + ('tag_msd_tagtraum_cd1', 'jazz'), + ('tag_msd_tagtraum_cd1', 'vocal'), + ('tag_msd_tagtraum_cd1', 'new age'), + ('tag_msd_tagtraum_cd1', 'latin'), + ('tag_msd_tagtraum_cd1', 'rap'), + ('tag_msd_tagtraum_cd1', 'country'), + ('tag_msd_tagtraum_cd1', 'international'), + ('tag_msd_tagtraum_cd1', 'blues'), + ('tag_msd_tagtraum_cd1', 'electronic'), + ('tag_msd_tagtraum_cd1', six.u('folk')), + ('tag_medleydb_instruments','accordion'), + ('tag_medleydb_instruments','alto saxophone'), + ('tag_medleydb_instruments',six.u('fx/processed sound')), + ('tag_open', 'a tag'), + ('segment_open', 'a segment'), + ('segment_salami_lower','a'), + ('segment_salami_lower',"a'"), + ('segment_salami_lower',"a'''"), + ('segment_salami_lower',"silence"), + ('segment_salami_lower',"Silence"), + ('segment_salami_lower',six.u('a')), + ('segment_salami_lower','aa'), + ('segment_salami_lower',"aa'"), + ('segment_salami_lower','ab'), + ('segment_salami_upper', 'A'), + ('segment_salami_upper', "A'"), + ('segment_salami_upper', "A'''"), + ('segment_salami_upper', "silence"), + ('segment_salami_upper', "Silence"), + ('segment_salami_upper', six.u('A')), + ('segment_salami_function', 'verse'), + ('segment_salami_function', "chorus"), + ('segment_salami_function', "theme"), + ('segment_salami_function', "voice"), + ('segment_salami_function', "silence"), + ('segment_salami_function', six.u('verse')), + ('segment_tut', 'verse'), + ('segment_tut', "refrain"), + ('segment_tut', "Si"), + ('segment_tut', "bridge"), + ('segment_tut', "Bridge"), + ('segment_tut', six.u('verse')), + ('vector', [1]), + ('vector', [1, 2]), + ('vector', np.asarray([1])), + ('vector', np.asarray([1, 2])), + ('blob', 'a tag'), + ('blob', six.u('a unicode tag')), + ('blob', 23), + ('blob', None), + ('blob', dict()), + ('blob', list()), + ('lyrics_bow', [['foo', 23]],), + ('lyrics_bow', [['foo', 23], ['bar', 35]],), + ('lyrics_bow', [['foo', 23], [['foo', 'bar'], 13]],), + ('lyrics_bow', []), + ('tag_audioset', 'Accordion'), + ('tag_audioset', 'Afrobeat'), + ('tag_audioset', six.u('Cacophony')), + ('tag_audioset_genre', 'Afrobeat'), + ('tag_audioset_genre', 'Disco'), + ('tag_audioset_genre', six.u('Opera')), + ('tag_audioset_instruments' ,'Organ'), + ('tag_audioset_instruments' ,'Harmonica'), + ('tag_audioset_instruments' ,six.u('Zither')), + ('tag_fma_genre', 'Blues'), + ('tag_fma_genre', 'Classical'), + ('tag_fma_genre', six.u('Soul-RnB')), + ('tag_fma_subgenre', 'Blues'), + ('tag_fma_subgenre', 'British Folk'), + ('tag_fma_subgenre', six.u('Klezmer')), + ('tag_urbansound', 'air_conditioner'), + ('tag_urbansound', 'car_horn'), + ('tag_urbansound', 'children_playing'), + ('tag_urbansound', 'dog_bark'), + ('tag_urbansound', 'drilling'), + ('tag_urbansound', 'engine_idling'), + ('tag_urbansound', 'gun_shot'), + ('tag_urbansound', 'jackhammer'), + ('tag_urbansound', 'siren'), + ('tag_urbansound', six.u('street_music')), +]) +def test_ns_tag(namespace, tag): + + ann = Annotation(namespace=namespace) ann.append(time=0, duration=1, value=tag) - ann.validate() -@parametrize('tag', - ['blues', 'classical', 'country', 'disco', - 'hip-hop', 'jazz', 'metal', 'pop', - 'reggae', six.u('rock'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError), - xfail('ROCK', raises=SchemaError)]) -def test_ns_tag_gtzan(tag): - - ann = Annotation(namespace='tag_gtzan') - ann.append(time=0, duration=1, value=tag) - ann.validate() +@parametrize('namespace', [ + 'tag_cal500', + 'tag_cal10k', + 'tag_gtzan', + 'tag_msd_tagtraum_cd1', + 'tag_medleydb_instruments', + 'tag_open', + 'segment_open', + 'segment_salami_lower', + 'segment_salami_upper', + 'segment_salami_function', + 'segment_tut', + 'tag_audioset', + 'tag_audioset_genre', + 'tag_audioset_instruments', + 'tag_fma_genre', + 'tag_fma_subgenre', + 'tag_urbansound', + 'multi_segment', +]) +@parametrize('value', [23, None]) +def test_ns_tag_invalid_type(namespace, value): + + ann = Annotation(namespace=namespace) + ann.append(time=0, duration=1, value=value) + with pytest.raises(SchemaError): + ann.validate() +@parametrize('namespace,value', [ + ('tag_cal500', 'GENRE-BEST-JAZZ'), + ('tag_cal10k', 'A DUB PRODUCTION'), + ('tag_gtzan', 'ROCK'), + ('tag_msd_tagtraum_cd1', 'FOLK'), + ('tag_medleydb_instruments', 'ACCORDION'), + ('segment_salami_lower', 'A'), + ('segment_salami_lower', 'S'), + ('segment_salami_lower', 'a23'), + ('segment_salami_lower', ' Silence 23'), + ('segment_salami_lower', 'aba'), + ('segment_salami_lower', 'aab'), + ('segment_salami_upper', 'a'), + ('segment_salami_upper', 'A23'), + ('segment_salami_upper', ' Silence 23'), + ('segment_salami_upper', 'ABA'), + ('segment_salami_upper', 'AAB'), + ('segment_salami_upper', 'AA'), + ('segment_salami_function', 'a'), + ('segment_salami_function', 'a'), + ('segment_salami_function', 'A23'), + ('segment_salami_function', ' Silence 23'), + ('segment_salami_function', 'Some Garbage'), + ('segment_tut', 'chorus'), + ('segment_tut', 'a'), + ('segment_tut', 'a'), + ('segment_tut', 'A23'), + ('segment_tut', ' Silence 23'), + ('segment_tut', 'Some Garbage'), + ('vector', 'a tag'), + ('vector', six.u('a unicode tag')), + ('vector', 23), + ('vector', None), + ('vector', dict()), + ('vector', list()), + ('lyrics_bow', ('foo', 23)), + ('lyrics_bow', [('foo', -23)]), + ('lyrics_bow', [(23, 'foo')]), + ('tag_audioset', 'ACCORDION'), + ('tag_audioset_genre', 'Accordion'), + ('tag_audioset_instruments', 'Afrobeat'), + ('tag_fma_genre', 'Afrobeat'), + ('tag_fma_subgenre', 'title'), + ('tag_urbansound', 'air conditioner'), + ('tag_urbansound', 'AIR_CONDITIONER'), +]) +def test_ns_invalid_value(namespace, value): + ann = Annotation(namespace=namespace) + ann.append(time=0, duration=1, value=value) + with pytest.raises(SchemaError): + ann.validate() -@parametrize('tag', - ['reggae', 'pop/rock', 'rnb', 'jazz', - 'vocal', 'new age', 'latin', 'rap', - 'country', 'international', 'blues', 'electronic', - six.u('folk'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError), - xfail('FOLK', raises=SchemaError)]) -@parametrize('confidence', - [0.0, 1.0, None, - xfail(1.2, raises=SchemaError), - xfail(-0.1, raises=SchemaError)]) -def test_ns_tag_msd_tagtraum_cd1(tag, confidence): +@parametrize('confidence', [0.0, 1.0, None]) +def test_ns_tag_msd_tagtraum_cd1_confidence(confidence): ann = Annotation(namespace='tag_msd_tagtraum_cd1') - - ann.append(time=0, duration=1, value=tag, confidence=confidence) - + ann.append(time=0, duration=1, value='rnb', confidence=confidence) ann.validate() -@parametrize('tag', - ['reggae', 'latin', 'metal', - 'rnb', 'jazz', 'punk', 'pop', - 'new age', 'country', 'rap', 'rock', - 'world', 'blues', 'electronic', six.u('folk'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError), - xfail('FOLK', raises=SchemaError)]) -@parametrize('confidence', - [0.0, 1.0, None, - xfail(1.2, raises=SchemaError), - xfail(-0.1, raises=SchemaError)]) -def test_ns_tag_msd_tagtraum_cd2(tag, confidence): - - ann = Annotation(namespace='tag_msd_tagtraum_cd2') - ann.append(time=0, duration=1, value=tag, confidence=confidence) - ann.validate() - - -@parametrize('tag', - ['accordion', 'alto saxophone', six.u('fx/processed sound'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError), - xfail('ACCORDION', raises=SchemaError)]) -def test_ns_tag_medleydb(tag): - - ann = Annotation(namespace='tag_medleydb_instruments') - ann.append(time=0, duration=1, value=tag) - ann.validate() - - -@parametrize('tag', - ['a tag', six.u('a unicode tag'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError)]) -def test_ns_tag_open(tag): - - ann = Annotation(namespace='tag_open') - ann.append(time=0, duration=1, value=tag) - ann.validate() - - -@parametrize('segment', - ['a segment', six.u('a unicode segment'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError)]) -def test_segment_tag_open(segment): - - ann = Annotation(namespace='segment_open') - ann.append(time=0, duration=1, value=segment) - ann.validate() - - -@parametrize('label', - ['a', "a'", "a'''", "silence", "Silence", - six.u('a'), 'aa', "aa'", 'ab'] + - [xfail(_, raises=SchemaError) - for _ in [23, None, 'A', 'S', 'a23', - ' Silence 23', 'aba', 'aab']]) -def test_ns_segment_salami_lower(label): - - ann = Annotation(namespace='segment_salami_lower') - ann.append(time=0, duration=1, value=label) - ann.validate() - - -@parametrize('label', - ['A', "A'", "A'''", "silence", "Silence", - six.u('A')] + - [xfail(_, raises=SchemaError) - for _ in [23, None, 'a', 'A23', - ' Silence 23', 'ABA', 'AAB', 'AA']]) -def test_ns_segment_salami_upper(label): - - ann = Annotation(namespace='segment_salami_upper') - ann.append(time=0, duration=1, value=label) - ann.validate() - - -@parametrize('label', - ['verse', "chorus", "theme", "voice", - "silence", six.u('verse')] + - [xfail(_, raises=SchemaError) - for _ in [23, None, 'a', 'a', 'A23', - ' Silence 23', 'Some Garbage']]) -def test_ns_segment_salami_function(label): - - ann = Annotation(namespace='segment_salami_function') - ann.append(time=0, duration=1, value=label) - ann.validate() - - -@parametrize('label', - ['verse', "refrain", "Si", "bridge", "Bridge", six.u('verse')] + - [xfail(_, raises=SchemaError) - for _ in [23, None, 'chorus', 'a', 'a', - 'A23', ' Silence 23', 'Some Garbage']]) -def test_ns_segment_tut(label): - - ann = Annotation(namespace='segment_tut') - ann.append(time=0, duration=1, value=label) - ann.validate() +@parametrize('confidence', [1.2, -0.1]) +def test_ns_tag_msd_tagtraum_cd1_bad_confidence(confidence): + ann = Annotation(namespace='tag_msd_tagtraum_cd1') + ann.append(time=0, duration=1, value='rnb', confidence=confidence) + with pytest.raises(SchemaError): + ann.validate() -@parametrize('pattern', [dict(midi_pitch=3, morph_pitch=5, staff=1, - pattern_id=1, occurrence_id=1), - dict(midi_pitch=-3, morph_pitch=-1.5, staff=1.0, - pattern_id=1, occurrence_id=1)]) +@parametrize('pattern', [ + dict(midi_pitch=3, morph_pitch=5, staff=1, pattern_id=1, occurrence_id=1), + dict(midi_pitch=-3, morph_pitch=-1.5, staff=1.0, pattern_id=1, occurrence_id=1) +]) def test_ns_pattern_valid(pattern): ann = Annotation(namespace='pattern_jku') ann.append(time=0, duration=1.0, value=pattern) ann.validate() -@xfail(raises=SchemaError) -@parametrize('key', ['midi_pitch', 'morph_pitch', 'staff', - 'pattern_id', 'occurrence_id']) +@parametrize('key', ['midi_pitch', 'morph_pitch', 'staff', 'pattern_id', 'occurrence_id']) @parametrize('value', ['foo', None, dict(), list()]) def test_ns_pattern_invalid(key, value): @@ -659,10 +707,11 @@ def test_ns_pattern_invalid(key, value): ann = Annotation(namespace='pattern_jku') ann.append(time=0, duration=1.0, value=data) - ann.validate() + + with pytest.raises(SchemaError): + ann.validate() -@xfail(raises=SchemaError) @parametrize('key', ['pattern_id', 'occurrence_id']) @parametrize('value', [-1, 0, 0.5]) def test_ns_pattern_invalid_bounded(key, value): @@ -672,144 +721,63 @@ def test_ns_pattern_invalid_bounded(key, value): ann = Annotation(namespace='pattern_jku') ann.append(time=0, duration=1.0, value=data) - ann.validate() - - -@parametrize('label', ['a tag', six.u('a unicode tag'), 23, - None, dict(), list()]) -def test_ns_blob(label): - ann = Annotation(namespace='blob') - ann.append(time=0, duration=1, value=label) - ann.validate() - - -@parametrize('label', [[1], [1, 2], np.asarray([1]), np.asarray([1, 2])] + - [xfail(_, raises=SchemaError) for _ in - ['a tag', six.u('a unicode tag'), 23, - None, dict(), list()]]) -def test_ns_vector(label): - - ann = Annotation(namespace='vector') - ann.append(time=0, duration=1, value=label) - ann.validate() + with pytest.raises(SchemaError): + ann.validate() -@parametrize('label', ['a segment', six.u('a unicode segment'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError)]) -@parametrize('level', [0, 2, - xfail(-1, raises=SchemaError), - xfail('foo', raises=SchemaError), - xfail(None, raises=SchemaError)]) -def test_ns_multi_segment(label, level): +@parametrize('label', ['a segment', six.u('a unicode segment')]) +@parametrize('level', [0, 2]) +def test_ns_multi_segment_label(label, level): ann = Annotation(namespace='multi_segment') ann.append(time=0, duration=1, value=dict(label=label, level=level)) ann.validate() - -@xfail(raises=SchemaError) -def test_ns_multi_segment_bad(): +@parametrize('label', [23, None]) +def test_ns_multi_segment_invalid_label(label): ann = Annotation(namespace='multi_segment') - ann.append(time=0, duration=1, value='a string') - ann.validate() - - -@parametrize('label', [[['foo', 23]], - [['foo', 23], ['bar', 35]], - [['foo', 23], [['foo', 'bar'], 13]], - [], - xfail(('foo', 23), raises=SchemaError), - xfail([('foo', -23)], raises=SchemaError), - xfail([(23, 'foo')], raises=SchemaError)]) -def test_ns_lyrics_bow(label): - - ann = Annotation(namespace='lyrics_bow') - ann.append(time=0, duration=1, value=label) - ann.validate() - - -@parametrize('tag', - ['Accordion', 'Afrobeat', six.u('Cacophony'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError), - xfail('ACCORDION', raises=SchemaError)]) -def test_ns_tag_audioset(tag): - - ann = Annotation(namespace='tag_audioset') - ann.append(time=0, duration=1, value=tag) - ann.validate() - - -@parametrize('tag', - ['Afrobeat', 'Disco', six.u('Opera'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError), - xfail('Accordion', raises=SchemaError)]) -def test_ns_tag_audioset_genre(tag): - - ann = Annotation(namespace='tag_audioset_genre') - ann.append(time=0, duration=1, value=tag) - ann.validate() - - -@parametrize('tag', - ['Organ', 'Harmonica', six.u('Zither'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError), - xfail('Afrobeat', raises=SchemaError)]) -def test_ns_tag_audioset_instruments(tag): - - ann = Annotation(namespace='tag_audioset_instruments') - ann.append(time=0, duration=1, value=tag) - ann.validate() - - -@parametrize('tag', - ['Blues', 'Classical', six.u('Soul-RnB'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError), - xfail('Afrobeat', raises=SchemaError)]) -def test_ns_tag_fma_genre(tag): + ann.append(time=0, duration=1, value=dict(label=label, level=0)) + with pytest.raises(SchemaError): + ann.validate() - ann = Annotation(namespace='tag_fma_genre') - ann.append(time=0, duration=1, value=tag) - ann.validate() +@parametrize('level', [-1, 'foo', None]) +def test_ns_multi_segment_invalid_level(level): + ann = Annotation(namespace='multi_segment') + ann.append(time=0, duration=1, value=dict(label='a segment', level=level)) + with pytest.raises(SchemaError): + ann.validate() +def test_ns_multi_segment_invalid_both(): + ann = Annotation(namespace='multi_segment') + ann.append(time=0, duration=1, value=dict(label=None, level=None)) + with pytest.raises(SchemaError): + ann.validate() -@parametrize('tag', - ['Blues', 'British Folk', six.u('Klezmer'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError), - xfail('title', raises=SchemaError)]) -def test_ns_tag_fma_subgenre(tag): - ann = Annotation(namespace='tag_fma_subgenre') - ann.append(time=0, duration=1, value=tag) - ann.validate() +def test_ns_multi_segment_bad_type(): + ann = Annotation(namespace='multi_segment') + ann.append(time=0, duration=1, value='a string') + with pytest.raises(SchemaError): + ann.validate() -@parametrize('tag', - ['air_conditioner', 'car_horn', 'children_playing', 'dog_bark', - 'drilling', 'engine_idling', 'gun_shot', 'jackhammer', 'siren', - six.u('street_music'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError), - xfail('air conditioner', raises=SchemaError), - xfail('AIR_CONDITIONER', raises=SchemaError)]) -def test_ns_tag_urbansound(tag): +@pytest.fixture +def scraper_value(): + return { + "source_time": 0.0, + "event_duration": 0.5310546236891855, + "event_time": 5.6543442662431795, + "time_stretch": 0.8455598669219283, + "pitch_shift": -1.2204911976305648, + "snr": 7.790682558359417, + "label": 'gun_shot', + "role": "foreground", + "source_file": "/audio/foreground/gun_shot/135544-6-17-0.wav" + } - ann = Annotation(namespace='tag_urbansound') - ann.append(time=0, duration=1, value=tag) - ann.validate() -@parametrize('source_time', - [0, 5, 1.0, - xfail(-1, raises=SchemaError), - xfail(-1.0, raises=SchemaError), - xfail('zero', raises=SchemaError), - xfail(None, raises=SchemaError)]) +@parametrize('source_time', [0, 5, 1.0]) def test_ns_scaper_source_time(source_time): ann = Annotation(namespace='scaper') @@ -830,13 +798,19 @@ def test_ns_scaper_source_time(source_time): ann.validate() +@parametrize('source_time', [-1, -1.0, 'zero', None]) +def test_ns_scraper_source_time_invalid(scraper_value, source_time): + + ann = Annotation(namespace='scaper') + value = dict(scraper_value, source_time=source_time) + ann.append(time=0, duration=1, value=value) + + with pytest.raises(SchemaError): + ann.validate() + + @parametrize('event_duration', - [0.5, 5, 1.0, - xfail(0, raises=SchemaError), - xfail(-1, raises=SchemaError), - xfail(-1.0, raises=SchemaError), - xfail('zero', raises=SchemaError), - xfail(None, raises=SchemaError)]) + [0.5, 5, 1.0]) def test_ns_scaper_event_duration(event_duration): ann = Annotation(namespace='scaper') @@ -857,12 +831,19 @@ def test_ns_scaper_event_duration(event_duration): ann.validate() +@parametrize('event_duration', [0, -1, -1.0, 'zero', None]) +def test_ns_scraper_event_duration_invalid(scraper_value, event_duration): + + ann = Annotation(namespace='scaper') + value = dict(scraper_value, event_duration=event_duration) + ann.append(time=0, duration=1, value=value) + + with pytest.raises(SchemaError): + ann.validate() + + @parametrize('event_time', - [0, 5, 1.0, - xfail(-1, raises=SchemaError), - xfail(-1.0, raises=SchemaError), - xfail('zero', raises=SchemaError), - xfail(None, raises=SchemaError)]) + [0, 5, 1.0]) def test_ns_scaper_event_time(event_time): ann = Annotation(namespace='scaper') @@ -883,12 +864,19 @@ def test_ns_scaper_event_time(event_time): ann.validate() +@parametrize('event_time', [-1, -1.0, 'zero', None]) +def test_ns_scraper_event_time_invalid(scraper_value, event_time): + + ann = Annotation(namespace='scaper') + value = dict(scraper_value, event_time=event_time) + ann.append(time=0, duration=1, value=value) + + with pytest.raises(SchemaError): + ann.validate() + + @parametrize('time_stretch', - [0.5, 5, 1.0, None, - xfail(0, raises=SchemaError), - xfail(-1, raises=SchemaError), - xfail(-1.0, raises=SchemaError), - xfail('zero', raises=SchemaError)]) + [0.5, 5, 1.0, None]) def test_ns_scaper_time_stretch(time_stretch): ann = Annotation(namespace='scaper') @@ -909,9 +897,19 @@ def test_ns_scaper_time_stretch(time_stretch): ann.validate() +@parametrize('time_stretch', [0, -1, -1.0, 'zero']) +def test_ns_scraper_time_stretch_invalid(scraper_value, time_stretch): + + ann = Annotation(namespace='scaper') + value = dict(scraper_value, time_stretch=time_stretch) + ann.append(time=0, duration=1, value=value) + + with pytest.raises(SchemaError): + ann.validate() + + @parametrize('pitch_shift', - [0.5, 5, 1.0, -1, -3.5, 0, None, - xfail('zero', raises=SchemaError)]) + [0.5, 5, 1.0, -1, -3.5, 0, None]) def test_ns_scaper_pitch_shift(pitch_shift): ann = Annotation(namespace='scaper') @@ -932,10 +930,18 @@ def test_ns_scaper_pitch_shift(pitch_shift): ann.validate() +def test_ns_scraper_pitch_shift_invalid(scraper_value): + + ann = Annotation(namespace='scaper') + value = dict(scraper_value, pitch_shift='zero') + ann.append(time=0, duration=1, value=value) + + with pytest.raises(SchemaError): + ann.validate() + + @parametrize('snr', - [0.5, 5, 1.0, -1, -3.5, 0, - xfail(None, raises=SchemaError), - xfail('zero', raises=SchemaError)]) + [0.5, 5, 1.0, -1, -3.5, 0]) def test_ns_scaper_snr(snr): ann = Annotation(namespace='scaper') @@ -956,11 +962,19 @@ def test_ns_scaper_snr(snr): ann.validate() +@parametrize('snr', ['zero', None]) +def test_ns_scraper_snr_invalid(scraper_value, snr): + + ann = Annotation(namespace='scaper') + value = dict(scraper_value, snr=snr) + ann.append(time=0, duration=1, value=value) + + with pytest.raises(SchemaError): + ann.validate() + + @parametrize('label', - ['air_conditioner', 'car_horn', six.u('street_music'), - 'any string', - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError)]) + ['air_conditioner', 'car_horn', six.u('street_music'), 'any string']) def test_ns_scaper_label(label): ann = Annotation(namespace='scaper') @@ -981,13 +995,20 @@ def test_ns_scaper_label(label): ann.validate() +@parametrize('label', [23, None]) +def test_ns_scraper_label_invalid(scraper_value, label): + + ann = Annotation(namespace='scaper') + value = dict(scraper_value, label=label) + ann.append(time=0, duration=1, value=value) + + with pytest.raises(SchemaError): + ann.validate() + + @parametrize('role', ['foreground', 'background', six.u('background'), - xfail('FOREGROUND', raises=SchemaError), - xfail('BACKGROUND', raises=SchemaError), - xfail('something', raises=SchemaError), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError)]) + ]) def test_ns_scaper_role(role): ann = Annotation(namespace='scaper') @@ -1008,10 +1029,19 @@ def test_ns_scaper_role(role): ann.validate() +@parametrize('role', ['FOREGROUND', 'BACKGROUND', 'something', 23, None]) +def test_ns_scraper_role_invalid(scraper_value, role): + + ann = Annotation(namespace='scaper') + value = dict(scraper_value, role=role) + ann.append(time=0, duration=1, value=value) + + with pytest.raises(SchemaError): + ann.validate() + + @parametrize('source_file', - ['filename', '/a/b/c.wav', six.u('filename.wav'), - xfail(23, raises=SchemaError), - xfail(None, raises=SchemaError)]) + ['filename', '/a/b/c.wav', six.u('filename.wav')]) def test_ns_scaper_source_file(source_file): ann = Annotation(namespace='scaper') @@ -1030,3 +1060,14 @@ def test_ns_scaper_source_file(source_file): ann.append(time=0, duration=1, value=value) ann.validate() + + +@parametrize('source_file', [23, None]) +def test_ns_scraper_source_file_invalid(scraper_value, source_file): + + ann = Annotation(namespace='scaper') + value = dict(scraper_value, source_file=source_file) + ann.append(time=0, duration=1, value=value) + + with pytest.raises(SchemaError): + ann.validate() diff --git a/tests/test_schema.py b/tests/test_schema.py index 36a74985..e5fcead9 100644 --- a/tests/test_schema.py +++ b/tests/test_schema.py @@ -86,14 +86,14 @@ def test_schema_values_pass(): 'pop', 'reggae', 'rock'] -@pytest.mark.xfail(raises=NamespaceError) def test_schema_values_missing(): - jams.schema.values('imaginary namespace') + with pytest.raises(NamespaceError): + jams.schema.values('imaginary namespace') -@pytest.mark.xfail(raises=NamespaceError) def test_schema_values_notenum(): - jams.schema.values('chord_harte') + with pytest.raises(NamespaceError): + jams.schema.values('chord_harte') def test_schema_dtypes(): @@ -102,9 +102,9 @@ def test_schema_dtypes(): jams.schema.get_dtypes(n) -@pytest.mark.xfail(raises=NamespaceError) def test_schema_dtypes_badns(): - jams.schema.get_dtypes('unknown namespace') + with pytest.raises(NamespaceError): + jams.schema.get_dtypes('unknown namespace') def test_list_namespaces(): diff --git a/tests/test_sonify.py b/tests/test_sonify.py index 56a7a4f8..31b9648f 100644 --- a/tests/test_sonify.py +++ b/tests/test_sonify.py @@ -9,19 +9,19 @@ import jams -@pytest.mark.xfail(raises=jams.NamespaceError) def test_no_sonify(): ann = jams.Annotation(namespace='vector') - jams.sonify.sonify(ann) + with pytest.raises(jams.NamespaceError): + jams.sonify.sonify(ann) -@pytest.mark.xfail(raises=jams.SchemaError) def test_bad_sonify(): ann = jams.Annotation(namespace='chord') ann.append(time=0, duration=1, value='not a chord') - jams.sonify.sonify(ann) + with pytest.raises(jams.SchemaError): + jams.sonify.sonify(ann) @pytest.mark.parametrize('ns', ['segment_open', 'chord']) From f40b91b35ecbf93f467d1aadc547d7a9f238996f Mon Sep 17 00:00:00 2001 From: Stefan Sullivan Date: Mon, 9 Dec 2024 22:55:07 -0800 Subject: [PATCH 08/10] skip path test on windows --- tests/test_util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_util.py b/tests/test_util.py index 7d47b889..a1d30b90 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # CHANGED:2015-03-05 17:53:32 by Brian McFee """Test the util module""" - +import sys import tempfile import os import pytest @@ -142,6 +142,7 @@ def test_find_with_extension(root_and_files, level, sort): assert sorted(results) == sorted(files[:level]) +@pytest.mark.skipif(sys.platform == "win32", reason="os.path.normpath does something different on windows") def test_expand_filepaths(): targets = ['foo.bar', 'dir/file.txt', 'dir2///file2.txt', '/q.bin'] From adf1a5ecb98fceef6d61939c8356c1cce3bd24f0 Mon Sep 17 00:00:00 2001 From: Stefan Sullivan Date: Mon, 9 Dec 2024 22:58:08 -0800 Subject: [PATCH 09/10] fix warnings tests --- tests/test_jams.py | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/tests/test_jams.py b/tests/test_jams.py index f7e2e8da..9fe72082 100644 --- a/tests/test_jams.py +++ b/tests/test_jams.py @@ -6,6 +6,7 @@ import os import tempfile import json + import six import sys import warnings @@ -16,7 +17,6 @@ import jams -xfail = pytest.mark.xfail parametrize = pytest.mark.parametrize @@ -300,12 +300,10 @@ def test_filemetadata_validation_warning(): clean_warning_registry() - with warnings.catch_warnings(record=True) as out: - fm.validate(strict=strict) + with pytest.warns(UserWarning, match='.*(Failed validating).*') as out: + fm.validate(strict=False) + - assert len(out) > 0 - assert out[0].category is UserWarning - assert 'failed validating' in str(out[0].message).lower() def test_filemetadata_validation_strict(): # This should fail validation because null duration is not allowed fm = jams.FileMetadata(title='Test track', @@ -560,13 +558,11 @@ def test_jams_validate_warning(jam_validate): clean_warning_registry() - with warnings.catch_warnings(record=True) as out: - jam_validate.validate(strict=strict) + with pytest.warns(UserWarning, match='.*(Failed validating).*') as out: + jam_validate.validate(strict=False) + def test_jams_validate_exception(jam_validate): - assert len(out) > 0 - assert out[0].category is UserWarning - assert 'failed validating' in str(out[0].message).lower() clean_warning_registry() with pytest.raises(jams.SchemaError): @@ -588,17 +584,16 @@ def test_jams_bad_annotation_warnings(): clean_warning_registry() - with warnings.catch_warnings(record=True) as out: - jam.validate(strict=strict) + with pytest.warns(UserWarning, match='.*(is not a well-formed JAMS Annotation).*') as out: + jam.validate(strict=False) + + def test_jams_bad_annotation_exception(): jam = jams.JAMS() jam.file_metadata.duration = 10 jam.annotations.append('not an annotation') - assert len(out) > 0 - assert out[0].category is UserWarning - assert 'is not a well-formed jams annotation' in str(out[0].message).lower() clean_warning_registry() with pytest.raises(jams.SchemaError): @@ -610,12 +605,10 @@ def test_jams_bad_jam_warning(): clean_warning_registry() - with warnings.catch_warnings(record=True) as out: - jam.validate(strict=strict) + with pytest.warns(UserWarning, match='.*(Failed validating).*') as out: + jam.validate(strict=False) + - assert len(out) > 0 - assert out[0].category is UserWarning - assert 'failed validating' in str(out[0].message).lower() def test_jams_bad_jam_exception(): jam = jams.JAMS() @@ -698,13 +691,9 @@ def test_load_invalid(): def __test_warn(filename, valid, strict): clean_warning_registry() - with warnings.catch_warnings(record=True) as out: + with pytest.warns(UserWarning, match='.*(Failed validating).*'): jams.load(filename, validate=valid, strict=strict) - assert len(out) > 0 - assert out[0].category is UserWarning - assert 'failed validating' in str(out[0].message).lower() - # 5. test bad jams file with strict validation # 6. test bad jams file without strict validation fn = 'tests/fixtures/invalid.jams' From 9b53cee1fd657993bd3794d59df5dd3c37ee16f1 Mon Sep 17 00:00:00 2001 From: Stefan Sullivan Date: Tue, 10 Dec 2024 15:11:56 -0800 Subject: [PATCH 10/10] Update setup.py to reflect up-to-date supported python versions I'm using the currently supported versions of python https://devguide.python.org/versions/ --- setup.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/setup.py b/setup.py index 0506891b..a1e9de9f 100644 --- a/setup.py +++ b/setup.py @@ -32,26 +32,24 @@ def load_source(modname, filename): "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "Topic :: Multimedia :: Sound/Audio :: Analysis", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8" + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ], + python_requires=">=3.9", keywords='audio music json', license='ISC', install_requires=[ 'pandas', 'sortedcontainers>=2.0.0', - 'pyrsistent<0.15; python_version=="3.4"', 'jsonschema>=3.0.0', 'numpy>=1.8.0', 'six', 'decorator', - 'mir_eval>=0.5', + 'mir_eval>0.7', ], extras_require={ 'display': ['matplotlib>=1.5.0'],