From 1828f91164524884452a81c93c3169cca96cf144 Mon Sep 17 00:00:00 2001 From: Kenes Yerassyl Date: Mon, 22 Jun 2026 13:20:50 +0900 Subject: [PATCH] updated repo to py3.12 --- .github/workflows/tox.yml | 5 +++-- README.md | 2 +- basic_pitch/__init__.py | 4 ++-- basic_pitch/constants.py | 1 - basic_pitch/inference.py | 7 +++++-- basic_pitch/layers/signal.py | 4 ++-- basic_pitch/models.py | 5 +++-- basic_pitch/nn.py | 5 ++--- basic_pitch/predict.py | 1 - basic_pitch/train.py | 1 - pyproject.toml | 25 +++++++++++++++---------- tests/data/conftest.py | 10 +++++----- tests/data/test_medleydb_pitch.py | 1 - tests/test_callbacks.py | 2 +- tests/test_inference.py | 2 +- tests/test_nn.py | 2 -- tox.ini | 18 ++++++++++-------- 17 files changed, 50 insertions(+), 45 deletions(-) diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index b06508ac..635769fa 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -14,15 +14,16 @@ jobs: - ubuntu-latest - windows-latest py: + - "3.12" - "3.11" - "3.10" - - "3.9" - - "3.8" include: - os: macos-latest-xlarge py: "3.10.11" - os: macos-latest-xlarge py: "3.11.8" + - os: macos-latest-xlarge + py: "3.12" steps: - name: Setup python for test ${{ matrix.py }} uses: actions/setup-python@v4 diff --git a/README.md b/README.md index 97f122a9..9a38ebcf 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ To update Basic Pitch to the latest version, add `--upgrade` to the above comman #### Compatible Environments: - MacOS, Windows and Ubuntu operating systems -- Python versions 3.7, 3.8, 3.9, 3.10, 3.11 +- Python versions 3.10, 3.11, 3.12 - **For Mac M1 hardware, we currently only support python version 3.10. Otherwise, we suggest using a virtual machine.** diff --git a/basic_pitch/__init__.py b/basic_pitch/__init__.py index b80b2144..275a10b1 100644 --- a/basic_pitch/__init__.py +++ b/basic_pitch/__init__.py @@ -19,7 +19,6 @@ import logging import pathlib - try: import coremltools @@ -79,7 +78,8 @@ class FilenameSuffix(enum.Enum): if TF_PRESENT: - _default_model_type = FilenameSuffix.tf + _tf_major_minor = tuple(int(part) for part in tensorflow.__version__.split(".")[:2]) + _default_model_type = FilenameSuffix.tf if _tf_major_minor < (2, 16) else FilenameSuffix.tflite elif CT_PRESENT: _default_model_type = FilenameSuffix.coreml elif TFLITE_PRESENT: diff --git a/basic_pitch/constants.py b/basic_pitch/constants.py index c2b717aa..db6c67ad 100644 --- a/basic_pitch/constants.py +++ b/basic_pitch/constants.py @@ -19,7 +19,6 @@ from enum import Enum - SEMITONES_PER_OCTAVE = 12 # for frequency bin calculations FFT_HOP = 256 diff --git a/basic_pitch/inference.py b/basic_pitch/inference.py index 06fa54f0..1631f5de 100644 --- a/basic_pitch/inference.py +++ b/basic_pitch/inference.py @@ -39,8 +39,11 @@ try: import tflite_runtime.interpreter as tflite except ImportError: - if TF_PRESENT: - import tensorflow.lite as tflite + try: + from ai_edge_litert import interpreter as tflite + except ImportError: + if TF_PRESENT: + import tensorflow.lite as tflite try: import onnxruntime as ort diff --git a/basic_pitch/layers/signal.py b/basic_pitch/layers/signal.py index f5f629f0..6625415a 100644 --- a/basic_pitch/layers/signal.py +++ b/basic_pitch/layers/signal.py @@ -80,7 +80,7 @@ def padded_window(window_length: int, dtype: tf.dtypes.DType = tf.float32) -> tf self.spec = tf.keras.layers.Lambda( lambda x: tf.pad( x, - [[0, 0] for _ in range(input_shape.rank - 1)] + [[self.fft_length // 2, self.fft_length // 2]], + [[0, 0] for _ in range(len(input_shape) - 1)] + [[self.fft_length // 2, self.fft_length // 2]], mode=self.pad_mode, ) ) @@ -161,7 +161,7 @@ class NormalizedLog(tf.keras.layers.Layer): def build(self, input_shape: tf.Tensor) -> None: self.squeeze_batch = lambda batch: batch - rank = input_shape.rank + rank = len(input_shape) if rank == 4: assert input_shape[1] == 1, "If the rank is 4, the second dimension must be length 1" self.squeeze_batch = lambda batch: tf.squeeze(batch, axis=1) diff --git a/basic_pitch/models.py b/basic_pitch/models.py index 867d9b3c..54f67956 100644 --- a/basic_pitch/models.py +++ b/basic_pitch/models.py @@ -32,6 +32,7 @@ from basic_pitch.layers import signal, nnaudio tfkl = tf.keras.layers +keras_ops = tf.keras.ops if hasattr(tf.keras, "ops") else tf MAX_N_SEMITONES = int(np.floor(12.0 * np.log2(0.5 * AUDIO_SAMPLE_RATE / ANNOTATIONS_BASE_FREQUENCY))) @@ -184,7 +185,7 @@ def get_cqt(inputs: tf.Tensor, n_harmonics: int, use_batchnorm: bool) -> tf.Tens bins_per_octave=12 * CONTOURS_BINS_PER_SEMITONE, )(x) x = signal.NormalizedLog()(x) - x = tf.expand_dims(x, -1) + x = keras_ops.expand_dims(x, -1) if use_batchnorm: x = tfkl.BatchNormalization()(x) return x @@ -263,7 +264,7 @@ def model( x_contours = nn.FlattenFreqCh(name=contour_name)(x_contours) # contour output # reduced contour output as input to notes - x_contours_reduced = tf.expand_dims(x_contours, -1) + x_contours_reduced = keras_ops.expand_dims(x_contours, -1) else: x_contours_reduced = x_contours diff --git a/basic_pitch/nn.py b/basic_pitch/nn.py index 3eaf0352..964c5517 100644 --- a/basic_pitch/nn.py +++ b/basic_pitch/nn.py @@ -18,7 +18,6 @@ from typing import Any, List import tensorflow as tf -import tensorflow.keras.backend as K from basic_pitch.layers.math import log_base_b @@ -97,7 +96,7 @@ class FlattenAudioCh(tf.keras.layers.Layer): def call(self, x: tf.Tensor) -> tf.Tensor: """x: (batch, time, ch)""" - shapes = K.int_shape(x) + shapes = x.shape tf.assert_equal(shapes[2], 1) return tf.squeeze(x, axis=2) @@ -111,7 +110,7 @@ class FlattenFreqCh(tf.keras.layers.Layer): """ def call(self, x: tf.Tensor) -> tf.Tensor: - shapes = K.int_shape(x) + shapes = x.shape batch_size = tf.shape(x)[0] time_dim = shapes[1] freq_dim = shapes[2] diff --git a/basic_pitch/predict.py b/basic_pitch/predict.py index 2b924e26..efba930a 100644 --- a/basic_pitch/predict.py +++ b/basic_pitch/predict.py @@ -27,7 +27,6 @@ ) from basic_pitch.inference import Model - os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" diff --git a/basic_pitch/train.py b/basic_pitch/train.py index 50f01900..07586899 100644 --- a/basic_pitch/train.py +++ b/basic_pitch/train.py @@ -150,7 +150,6 @@ def main( model.compile( loss=loss, optimizer=tf.keras.optimizers.Adam(learning_rate), - sample_weight_mode={"contour": None, "note": None, "onset": None}, ) logging.info("--- Model Training specs ---") diff --git a/pyproject.toml b/pyproject.toml index e8dc15c3..740d202b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,6 +4,7 @@ version = "0.4.0" description = "Basic Pitch, a lightweight yet powerful audio-to-MIDI converter with pitch bend detection." readme = "README.md" keywords = [] +requires-python = ">=3.10" classifiers = [ "Development Status :: 5 - Production/Stable", "Natural Language :: English", @@ -11,25 +12,27 @@ classifiers = [ "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Programming Language :: Python", - "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 :: Implementation :: CPython", ] dependencies = [ "coremltools; platform_system == 'Darwin'", - "librosa>=0.8.0", + "librosa>=0.10.0", "mir_eval>=0.6.0", - "numpy>=1.18", + "numpy>=1.21", "onnxruntime; platform_system == 'Windows' and python_version < '3.11'", + "onnxruntime; platform_system == 'Windows' and python_version >= '3.12'", "pretty_midi>=0.2.9", - "resampy>=0.2.2,<0.4.3", + "resampy>=0.2.2", "scikit-learn", - "scipy>=1.4.1", - "tensorflow>=2.4.1,<2.15.1; platform_system != 'Darwin' and python_version >= '3.11'", - "tensorflow-macos>=2.4.1,<2.15.1; platform_system == 'Darwin' and python_version > '3.11'", + "scipy>=1.7.0", + "tensorflow>=2.4.1,<2.16.0; platform_system != 'Darwin' and python_version >= '3.11' and python_version < '3.12'", + "tensorflow>=2.16.0; platform_system != 'Darwin' and python_version >= '3.12'", + "tensorflow>=2.13.0; platform_system == 'Darwin' and python_version >= '3.12'", "tflite-runtime; platform_system == 'Linux' and python_version < '3.11'", + "ai-edge-litert; platform_system != 'Windows' and python_version >= '3.12'", "typing_extensions", ] @@ -68,8 +71,10 @@ test = [ "mido" ] tf = [ - "tensorflow>=2.4.1,<2.15.1; platform_system != 'Darwin'", - "tensorflow-macos>=2.4.1,<2.15.1; platform_system == 'Darwin' and python_version > '3.7'", + "tensorflow>=2.4.1,<2.16.0; platform_system != 'Darwin' and python_version < '3.12'", + "tensorflow>=2.16.0; platform_system != 'Darwin' and python_version >= '3.12'", + "tensorflow>=2.13.0; platform_system == 'Darwin'", + "tensorboard>=2.4.1", ] coreml = ["coremltools"] onnx = ["onnxruntime"] diff --git a/tests/data/conftest.py b/tests/data/conftest.py index 279f481e..08e1ebe9 100644 --- a/tests/data/conftest.py +++ b/tests/data/conftest.py @@ -12,21 +12,21 @@ SLAKH_TEST_INDEX = json.load(open(RESOURCES_PATH / "data" / "slakh" / "dummy_index.json")) -@pytest.fixture # type: ignore[misc] +@pytest.fixture # type: ignore[untyped-decorator] def mock_slakh_index() -> None: # type: ignore[misc] with mock.patch("mirdata.datasets.slakh.Dataset.download"): with mock.patch("mirdata.datasets.slakh.Dataset._index", new=SLAKH_TEST_INDEX): yield -@pytest.fixture # type: ignore[misc] +@pytest.fixture # type: ignore[untyped-decorator] def mock_medleydb_pitch_index() -> None: # type: ignore[misc] with mock.patch("mirdata.datasets.medleydb_pitch.Dataset.download"): with mock.patch("mirdata.datasets.medleydb_pitch.Dataset._index", new=MEDLEYDB_PITCH_TEST_INDEX): yield -@pytest.fixture # type: ignore[misc] +@pytest.fixture # type: ignore[untyped-decorator] def mock_maestro_index() -> None: # type: ignore[misc] index_with_metadata = MAESTRO_TEST_INDEX metadata = {mdata["midi_filename"].split(".")[0]: mdata for mdata in METADATA_TEST_INDEX} @@ -36,14 +36,14 @@ def mock_maestro_index() -> None: # type: ignore[misc] yield -@pytest.fixture # type: ignore[misc] +@pytest.fixture # type: ignore[untyped-decorator] def mock_guitarset_index() -> None: # type: ignore[misc] with mock.patch("mirdata.datasets.guitarset.Dataset.download"): with mock.patch("mirdata.datasets.guitarset.Dataset._index", new=GUITAR_SET_TEST_INDEX): yield -@pytest.fixture # type: ignore[misc] +@pytest.fixture # type: ignore[untyped-decorator] def mock_ikala_index() -> None: # type: ignore[misc] with mock.patch("mirdata.datasets.ikala.Dataset.download"): with mock.patch("mirdata.datasets.ikala.Dataset._index", new=IKALA_TEST_INDEX): diff --git a/tests/data/test_medleydb_pitch.py b/tests/data/test_medleydb_pitch.py index 7ef77e18..646a2f5f 100644 --- a/tests/data/test_medleydb_pitch.py +++ b/tests/data/test_medleydb_pitch.py @@ -25,7 +25,6 @@ create_input_data, ) - # TODO: Create test_medleydb_pitch_to_tf_example diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py index 33a3af05..a522c458 100644 --- a/tests/test_callbacks.py +++ b/tests/test_callbacks.py @@ -56,6 +56,6 @@ def test_visualize_callback_on_epoch_end(tmpdir: str) -> None: contours=True, ) - vc.model = MockModel() + vc.set_model(MockModel()) vc.on_epoch_end(1, {"loss": np.random.random(), "val_loss": np.random.random()}) diff --git a/tests/test_inference.py b/tests/test_inference.py index eb3a96d8..1a94aa04 100644 --- a/tests/test_inference.py +++ b/tests/test_inference.py @@ -58,7 +58,7 @@ def test_predict() -> None: # Check that model output has the expected length according to the last frame second computed downstream # (via model_frames_to_time) with to a few frames of tolerance - audio_length_s = librosa.get_duration(filename=test_audio_path) + audio_length_s = librosa.get_duration(path=test_audio_path) n_model_output_frames = model_output["note"].shape[0] last_frame_s = note_creation.model_frames_to_time(n_model_output_frames)[-1] np.testing.assert_allclose(last_frame_s, audio_length_s, atol=2 * ANNOTATION_HOP) diff --git a/tests/test_nn.py b/tests/test_nn.py index 7e2b1c05..bbb06403 100644 --- a/tests/test_nn.py +++ b/tests/test_nn.py @@ -67,7 +67,6 @@ def test_defaults(self) -> None: model.compile( loss="binary_crossentropy", optimizer=tf.keras.optimizers.Adam(0.1), - sample_weight_mode=None, ) model.fit( @@ -102,7 +101,6 @@ def test_fractions(self) -> None: model.compile( loss="binary_crossentropy", optimizer=tf.keras.optimizers.Adam(0.1), - sample_weight_mode=None, ) model.fit( diff --git a/tox.ini b/tox.ini index e22a6afc..4a29c003 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py38,py39,py310,py311,full,data,manifest,check-formatting,lint,mypy +envlist = py310,py311,py312,full,data,manifest,check-formatting,lint,mypy skipsdist = True usedevelop = True requires = @@ -19,6 +19,7 @@ setenv = # Tests with TF [testenv:full] +basepython = python3.12 deps = -e .[dev] commands = pytest tests {posargs} @@ -28,8 +29,9 @@ setenv = LINE_LENGTH = "120" [testenv:data] +basepython = python3.12 deps = -e .[data] -commands = +commands = pytest tests/data {posargs} [testenv:manifest] @@ -38,27 +40,27 @@ skip_install = true commands = check-manifest --ignore 'tests' [testenv:check-formatting] -basepython = python3.10 +basepython = python3.12 deps = black skip_install = true commands = - black {env:SOURCE} tests --line-length {env:LINE_LENGTH} --diff --check + black {env:SOURCE} tests --line-length {env:LINE_LENGTH} --target-version py312 --diff --check [testenv:format] -basepython = python3.10 +basepython = python3.12 deps = black skip_install = true commands = - black {env:SOURCE} tests --line-length {env:LINE_LENGTH} + black {env:SOURCE} tests --line-length {env:LINE_LENGTH} --target-version py312 [testenv:lint] -basepython = python3.10 +basepython = python3.12 deps = flake8 skip_install = true commands = flake8 [testenv:mypy] -basepython = python3.10 +basepython = python3.12 deps = mypy commands = mypy basic_pitch tests --strict --ignore-missing-imports --allow-subclassing-any