diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9e05d13c..407f1aea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,13 +7,14 @@ jobs: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.9", "3.10", "3.11", "3.12"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: 'pip' # caching pip dependencies diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 405daf20..355983a0 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -27,18 +27,18 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -51,6 +51,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" diff --git a/madmom/__init__.py b/madmom/__init__.py index 9e6a3838..3e4e43f9 100644 --- a/madmom/__init__.py +++ b/madmom/__init__.py @@ -17,13 +17,13 @@ import doctest -import pkg_resources +from importlib.metadata import distribution # import all packages from . import audio, evaluation, features, io, ml, models, processors, utils # define a version variable -__version__ = pkg_resources.get_distribution("madmom").version +__version__ = distribution("madmom") .version # Create a doctest output checker that optionally ignores the unicode string # literal. @@ -98,4 +98,4 @@ def check_output(self, want, got, optionflags): doctest.OutputChecker = _OutputChecker # keep namespace clean -del pkg_resources, doctest +del doctest diff --git a/madmom/evaluation/notes.py b/madmom/evaluation/notes.py index bb484d09..3ee3be67 100644 --- a/madmom/evaluation/notes.py +++ b/madmom/evaluation/notes.py @@ -133,9 +133,9 @@ def note_onset_evaluation(detections, annotations, window=WINDOW): tp_, fp_, _, fn_, err_ = onset_evaluation(det[:, 0], ann[:, 0], window) # convert returned arrays to lists and append the detections and # annotations to the correct lists - tp = np.vstack((tp, det[np.in1d(det[:, 0], tp_)])) - fp = np.vstack((fp, det[np.in1d(det[:, 0], fp_)])) - fn = np.vstack((fn, ann[np.in1d(ann[:, 0], fn_)])) + tp = np.vstack((tp, det[np.isin(det[:, 0], tp_)])) + fp = np.vstack((fp, det[np.isin(det[:, 0], fp_)])) + fn = np.vstack((fn, ann[np.isin(ann[:, 0], fn_)])) # append the note number to the errors err_ = np.vstack((np.array(err_), np.repeat(np.asarray([note]), len(err_)))).T diff --git a/madmom/evaluation/tempo.py b/madmom/evaluation/tempo.py index 44ff8c2c..08a5dcb6 100644 --- a/madmom/evaluation/tempo.py +++ b/madmom/evaluation/tempo.py @@ -38,7 +38,8 @@ def sort_tempo(tempo): Tempi sorted according to their strength. """ - tempo = np.array(tempo, copy=False, ndmin=1) + if not isinstance(tempo, np.ndarray): + tempo = np.array(tempo, ndmin=1) if tempo.ndim != 2: raise ValueError('`tempo` has no strength information, cannot sort ' 'them.') diff --git a/madmom/features/beats.py b/madmom/features/beats.py index cc452282..c20e73f2 100644 --- a/madmom/features/beats.py +++ b/madmom/features/beats.py @@ -1082,7 +1082,8 @@ def process_online(self, activations, reset=True, **kwargs): """ # cast as 1-dimensional array # Note: in online mode, activations are just float values - activations = np.array(activations, copy=False, subok=True, ndmin=1) + if not isinstance(activations, np.ndarray): + activations = np.array(activations, ndmin=1) # reset to initial state if reset: self.reset() diff --git a/madmom/features/beats_hmm.py b/madmom/features/beats_hmm.py index 63d18464..06d21b8d 100644 --- a/madmom/features/beats_hmm.py +++ b/madmom/features/beats_hmm.py @@ -478,8 +478,8 @@ def __init__(self, transition_models, transition_prob=None): new_probabilities = [] for p in range(num_patterns): # indices of states/prev_states/probabilities - idx = np.logical_and(np.in1d(prev_states, last_states[p]), - np.in1d(states, first_states[p])) + idx = np.logical_and(np.isin(prev_states, last_states[p]), + np.isin(states, first_states[p])) # transition probability prob = probabilities[idx] # update transitions to same pattern with new probability @@ -487,8 +487,8 @@ def __init__(self, transition_models, transition_prob=None): # distribute that part among all other patterns for p_ in np.setdiff1d(range(num_patterns), p): idx_ = np.logical_and( - np.in1d(prev_states, last_states[p_]), - np.in1d(states, first_states[p_])) + np.isin(prev_states, last_states[p_]), + np.isin(states, first_states[p_])) # make sure idx and idx_ have same length if len(np.nonzero(idx)[0]) != len(np.nonzero(idx_)[0]): raise ValueError('Cannot add transition between ' diff --git a/madmom/features/onsets.py b/madmom/features/onsets.py index 3cdb5eba..68924525 100644 --- a/madmom/features/onsets.py +++ b/madmom/features/onsets.py @@ -1125,7 +1125,8 @@ def process_online(self, activations, reset=True, **kwargs): """ # cast as 1-dimensional array # Note: in online mode, activations are just float values - activations = np.array(activations, copy=False, subok=True, ndmin=1) + if not isinstance(activations, np.ndarray): + activations = np.array(activations, ndmin=1) # buffer data if self.buffer is None or reset: # reset the processor diff --git a/madmom/features/tempo.py b/madmom/features/tempo.py index 36168107..4b6326a0 100644 --- a/madmom/features/tempo.py +++ b/madmom/features/tempo.py @@ -392,8 +392,8 @@ def process_online(self, activations, reset=True, **kwargs): Corresponding delays [frames]. """ - - activations = np.array(activations, copy=False, subok=True, ndmin=1, dtype=float) + if not isinstance(activations, np.ndarray): + activations = np.array(activations, ndmin=1, dtype=float) # reset to initial state if reset: self.reset() @@ -402,7 +402,7 @@ def process_online(self, activations, reset=True, **kwargs): # iterate over all activations # Note: in online mode, activations are just float values, thus cast # them as 1-dimensional array - for act in np.array(activations, copy=False, subok=True, ndmin=1): + for act in activations: # online feed backward comb filter (y[n] = x[n] + α * y[n - τ]) y_n = act + self.alpha * self._comb_buffer[idx] # shift output buffer with new value diff --git a/madmom/ml/hmm.pyx b/madmom/ml/hmm.pyx index 84e40b7f..c79f2df0 100644 --- a/madmom/ml/hmm.pyx +++ b/madmom/ml/hmm.pyx @@ -21,6 +21,7 @@ import numpy as np cimport numpy as np cimport cython +np.import_array() from numpy.math cimport INFINITY diff --git a/madmom/ml/nn/layers.py b/madmom/ml/nn/layers.py index c0214c54..89ba088a 100644 --- a/madmom/ml/nn/layers.py +++ b/madmom/ml/nn/layers.py @@ -1220,7 +1220,7 @@ def activate(self, data, **kwargs): Reshaped data. """ - return np.reshape(data, self.newshape, self.order) + return np.reshape(data, self.newshape, order=self.order) class AverageLayer(Layer): diff --git a/madmom/processors.py b/madmom/processors.py index dd371a03..a212a9c1 100644 --- a/madmom/processors.py +++ b/madmom/processors.py @@ -797,7 +797,7 @@ def process(self, data, **kwargs): ndmin = len(self.buffer_size) # cast the data to have that many dimensions if data.ndim < ndmin: - data = np.array(data, copy=False, subok=True, ndmin=ndmin) + data = np.array(data, ndmin=ndmin) # length of the data data_length = len(data) # if length of data exceeds buffer length simply replace buffer data diff --git a/pyproject.toml b/pyproject.toml index 4541488d..b66347b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,6 +3,6 @@ requires = [ "setuptools", "wheel", "cython>=0.25", - "oldest-supported-numpy" + "numpy>2", ] build-backend = "setuptools.build_meta" diff --git a/setup.py b/setup.py index c28ff123..e26bb88b 100755 --- a/setup.py +++ b/setup.py @@ -56,10 +56,10 @@ # some PyPI metadata classifiers = [ 'Development Status :: 3 - Beta', - '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', 'Environment :: Console', 'License :: OSI Approved :: BSD License', 'License :: Free for non-commercial use', @@ -70,8 +70,7 @@ # requirements requirements = [ 'numpy>=1.13.4', - 'scipy>=0.16', - 'cython>=0.25', + 'scipy>=1.13', 'mido>=1.2.6', ] diff --git a/tests/test_bin.py b/tests/test_bin.py index 9c6b71e4..b9451ac5 100644 --- a/tests/test_bin.py +++ b/tests/test_bin.py @@ -7,12 +7,13 @@ from __future__ import absolute_import, division, print_function -import imp import os import shutil import sys import tempfile +import types import unittest +from importlib.machinery import SourceFileLoader from os.path import join as pj try: @@ -45,7 +46,9 @@ def run_program(program): # import module, capture stdout - test = imp.load_source('test', program[0]) + loader = SourceFileLoader('test', program[0]) + test = types.ModuleType(loader.name) + loader.exec_module(test) sys.argv = program backup = sys.stdout sys.stdout = StringIO() @@ -105,7 +108,9 @@ def run_load(program, infile, outfile, online=False, args=None): def run_help(program): - test = imp.load_source('test', program) + loader = SourceFileLoader('test', program) + test = types.ModuleType(loader.name) + loader.exec_module(test) sys.argv = [program, '-h'] try: test.main() diff --git a/tests/test_bin_evaluate.py b/tests/test_bin_evaluate.py index b0b11e3d..3e90e8dd 100644 --- a/tests/test_bin_evaluate.py +++ b/tests/test_bin_evaluate.py @@ -7,10 +7,11 @@ from __future__ import absolute_import, division, print_function -import imp import os import sys +import types import unittest +from importlib.machinery import SourceFileLoader try: from cStringIO import StringIO @@ -30,7 +31,9 @@ def run_script(task, det_suffix=None, args=None): # import module, capture stdout - test = imp.load_source('test', eval_script) + loader = SourceFileLoader('test', eval_script) + test = types.ModuleType(loader.name) + loader.exec_module(test) sys.argv = [eval_script, task, '--csv', DETECTIONS_PATH, ANNOTATIONS_PATH] if det_suffix: sys.argv.extend(['-d', det_suffix])