diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 013dd202..00000000 --- a/.coveragerc +++ /dev/null @@ -1,2 +0,0 @@ -[report] -show_missing = True diff --git a/mir_eval/separation.py b/mir_eval/separation.py index 96570eaf..0201fe40 100644 --- a/mir_eval/separation.py +++ b/mir_eval/separation.py @@ -1,5 +1,11 @@ # -*- coding: utf-8 -*- """ +.. warning:: + The mir_eval.separation module is deprecated in mir_eval version 0.8, and will be removed. + We recommend that you migrate your code to use an alternative package such as sigsep-museval + https://sigsep.github.io/sigsep-mus-eval/ + + Source separation algorithms attempt to extract recordings of individual sources from a recording of a mixture of sources. Evaluation methods for source separation compare the extracted sources from reference sources and @@ -141,6 +147,7 @@ def _any_source_silent(sources): ) +@util.deprecated(version="0.8", version_removed="0.9") def bss_eval_sources(reference_sources, estimated_sources, compute_permutation=True): """ Ordering and measurement of the separation quality for estimated source @@ -251,6 +258,7 @@ def bss_eval_sources(reference_sources, estimated_sources, compute_permutation=T return (sdr, sir, sar, popt) +@util.deprecated(version="0.8", version_removed="0.9") def bss_eval_sources_framewise( reference_sources, estimated_sources, @@ -362,6 +370,7 @@ def bss_eval_sources_framewise( return sdr, sir, sar, perm +@util.deprecated(version="0.8", version_removed="0.9") def bss_eval_images(reference_sources, estimated_sources, compute_permutation=True): """Compute the bss_eval_images function from the BSS_EVAL Matlab toolbox. @@ -496,6 +505,7 @@ def bss_eval_images(reference_sources, estimated_sources, compute_permutation=Tr return (sdr, isr, sir, sar, popt) +@util.deprecated(version="0.8", version_removed="0.9") def bss_eval_images_framewise( reference_sources, estimated_sources, @@ -841,6 +851,7 @@ def _safe_db(num, den): return 10 * np.log10(num / den) +@util.deprecated(version="0.8", version_removed="0.9") def evaluate(reference_sources, estimated_sources, **kwargs): """Compute all metrics for the given reference and estimated signals. diff --git a/mir_eval/util.py b/mir_eval/util.py index 4c9e2326..05778279 100644 --- a/mir_eval/util.py +++ b/mir_eval/util.py @@ -5,6 +5,8 @@ import os import inspect +import warnings +from decorator import decorator import numpy as np @@ -939,3 +941,22 @@ def midi_to_hz(midi): Frequency/frequencies in Hz corresponding to `midi` """ return 440.0 * (2.0 ** ((midi - 69.0) / 12.0)) + + +def deprecated(*, version, version_removed): + """Mark a function as deprecated. + + Using the decorated (old) function will result in a warning. + """ + + def __wrapper(func, *args, **kwargs): + """Warn the user, and then proceed.""" + warnings.warn( + f"{func.__module__}.{func.__name__}\n\tDeprecated as of mir_eval version {version}." + f"\n\tIt will be removed in mir_eval version {version_removed}.", + category=FutureWarning, + stacklevel=3, # Would be 2, but the decorator adds a level + ) + return func(*args, **kwargs) + + return decorator(__wrapper) diff --git a/setup.cfg b/setup.cfg index 1426ed2c..d2973d47 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,13 @@ [tool:pytest] addopts = --cov-report term-missing --cov mir_eval --cov-report=xml --mpl --mpl-baseline-path=baseline_images/test_display +[coverage:report] +show_missing = True + +[coverage:run] +omit = + separation.py + [pydocstyle] # convention = numpy # Below is equivalent to numpy convention + D400 and D205 @@ -48,13 +55,13 @@ keywords = audio music mir dsp install_requires = numpy >= 1.15.4 scipy >= 1.4.0 + decorator [options.extras_require] display = matplotlib >= 3.3.0 tests = matplotlib >= 3.3.0 - decorator pytest pytest-cov pytest-mpl diff --git a/tests/test_display.py b/tests/test_display.py index 943a6674..415e7a1a 100644 --- a/tests/test_display.py +++ b/tests/test_display.py @@ -47,7 +47,7 @@ def test_display_segment(): mir_eval.display.segments(intervals, labels, text=False) # Draw a legend - plt.legend() + plt.legend(loc="upper right") return plt.gcf() @@ -126,7 +126,7 @@ def test_display_labeled_intervals_compare(): ) mir_eval.display.labeled_intervals(est_int, est_labels, alpha=0.5, label="Estimate") - plt.legend() + plt.legend(loc="upper right") return plt.gcf() @@ -198,7 +198,7 @@ def test_display_hierarchy_nolabel(): # Plot reference and estimate with a common label set mir_eval.display.hierarchy([int0, int1], [lab0, lab1]) - plt.legend() + plt.legend(loc="upper right") return plt.gcf() @@ -218,7 +218,7 @@ def test_display_hierarchy_label(): # Plot reference and estimate with a common label set mir_eval.display.hierarchy([int0, int1], [lab0, lab1], levels=["Large", "Small"]) - plt.legend() + plt.legend(loc="upper right") return plt.gcf() @@ -238,7 +238,7 @@ def test_display_pitch_hz(): # Plot pitches on a Hz scale mir_eval.display.pitch(ref_times, ref_freqs, unvoiced=True, label="Reference") mir_eval.display.pitch(est_times, est_freqs, unvoiced=True, label="Estimate") - plt.legend() + plt.legend(loc="upper left") return plt.gcf() @@ -323,7 +323,7 @@ def test_display_multipitch_midi(): mir_eval.display.multipitch(ref_t, ref_p, midi=True, alpha=0.5, label="Reference") mir_eval.display.multipitch(est_t, est_p, midi=True, alpha=0.5, label="Estimate") - plt.legend() + plt.legend(loc="upper left") return plt.gcf() @@ -392,6 +392,7 @@ def test_display_ticker_midi_zoom(): tolerance=6, ) @pytest.mark.xfail(OLD_FT, reason=f"freetype version < {FT_VERSION}", strict=False) +@pytest.mark.skip() def test_display_separation(): plt.figure() @@ -410,6 +411,7 @@ def test_display_separation(): tolerance=6, ) @pytest.mark.xfail(OLD_FT, reason=f"freetype version < {FT_VERSION}", strict=False) +@pytest.mark.skip() def test_display_separation_label(): plt.figure() @@ -419,7 +421,7 @@ def test_display_separation_label(): mir_eval.display.separation([x0, x1, x2], fs=fs, labels=["Alice", "Bob", "Carol"]) - plt.legend() + plt.legend(loc="upper right") return plt.gcf() @@ -439,7 +441,7 @@ def test_display_events(): # Plot both with labels mir_eval.display.events(beats_ref, label="reference") mir_eval.display.events(beats_est, label="estimate") - plt.legend() + plt.legend(loc="upper right") return plt.gcf() diff --git a/tests/test_separation.py b/tests/test_separation.py index 4ad7f553..36fdc95f 100644 --- a/tests/test_separation.py +++ b/tests/test_separation.py @@ -26,6 +26,9 @@ assert len(ref_files) == len(est_files) == len(sco_files) > 0 file_sets = list(zip(ref_files, est_files, sco_files)) +# Skip separation tests since deprecation +pytest.skip(allow_module_level=True) + @pytest.fixture def separation_data(request): @@ -119,8 +122,9 @@ def test_empty_input(metric): # And that the metric returns empty arrays assert np.allclose(metric(*args), np.array([])) - assert "reference_sources is empty" in str(record[0].message) - assert "estimated_sources is empty" in str(record[1].message) + # These warning counters are now offset by 1 because of the deprecation message + assert "reference_sources is empty" in str(record[1].message) + assert "estimated_sources is empty" in str(record[2].message) @pytest.mark.parametrize(