diff --git a/evaluation_function/backend_test.py b/evaluation_function/backend_test.py new file mode 100644 index 0000000..82a48c4 --- /dev/null +++ b/evaluation_function/backend_test.py @@ -0,0 +1,64 @@ +""" +backend_test.py +=============== +Tests that the audio-to-MIDI transcription backend is actually available. + +Basic Pitch does not ship inference code of its own. It picks a backend at +import time from whichever of CoreML, TensorFlow, TFLite or ONNX Runtime it +finds installed, and if it finds none it fails while defining +ICASSP_2022_MODEL_PATH: + + NameError: name '_default_model_type' is not defined + +Basic Pitch declares those backends behind platform markers, so which one +arrives depends on the machine doing the install: + + - macOS -> coremltools + - Linux/amd64 -> tensorflow + - Linux/arm64 -> the `tensorflow` wheel is an empty shim that requires + `tensorflow-cpu-aws`, which does not get resolved into + our lock, so no backend is installed at all + +The third case is not hypothetical: it is every container built on an Apple +Silicon machine, where the worker dies at import and the container never +starts. CI and the AWS build are amd64, so they never see it. + +The fix is to stop relying on those markers and declare a backend +explicitly. ONNX Runtime is the one with wheels for every platform we +build for, so these tests assert it is present. + +Run locally with: python -m pytest evaluation_function/backend_test.py -v +""" + +import importlib + + +def test_onnx_runtime_is_installed(): + """ + A backend must be declared explicitly rather than inherited from a + platform marker, so that arm64 containers get one too. + """ + assert importlib.util.find_spec("onnxruntime") is not None, ( + "onnxruntime is not installed; basic-pitch needs an explicitly " + "declared inference backend so that every build platform gets one" + ) + + +def test_basic_pitch_resolves_a_model_path(): + """ + The symptom that takes the container down. Importing this name fails + with NameError when no backend is installed. + """ + from basic_pitch import ICASSP_2022_MODEL_PATH + + assert ICASSP_2022_MODEL_PATH is not None + + +def test_model_loads_through_our_own_loader(): + """ + Guards the entry point the evaluation function actually calls, so a + missing or broken backend fails here rather than at container start. + """ + from .audio_processing import load_basic_pitch_model + + assert load_basic_pitch_model() is not None diff --git a/poetry.lock b/poetry.lock index b065fde..65a6478 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.0 and should not be changed by hand. [[package]] name = "absl-py" @@ -162,6 +162,7 @@ coremltools = {version = "*", markers = "platform_system == \"Darwin\""} librosa = ">=0.8.0" mir-eval = ">=0.6" numpy = ">=1.18" +onnxruntime = {version = "*", optional = true, markers = "extra == \"onnx\""} pretty-midi = ">=0.2.9" resampy = ">=0.2.2,<0.4.3" scikit-learn = "*" @@ -1063,7 +1064,6 @@ description = "The FlatBuffers serialization format for Python" optional = false python-versions = "*" groups = ["main"] -markers = "platform_system != \"Darwin\"" files = [ {file = "flatbuffers-25.12.19-py2.py3-none-any.whl", hash = "sha256:7634f50c427838bb021c2d66a3d1168e9d199b0607e6329399f04846d42e20b4"}, ] @@ -2148,6 +2148,7 @@ sympy = ">=1.12,<2.0" ujson = "5.10.0" [package.extras] +gcs = ["google-cloud-storage (>=2.18,<3.0)"] http = ["fastapi (>=0.115.0,<0.116.0)"] ipc = ["pywin32 (>=306,<307) ; sys_platform == \"win32\""] parsing = ["antlr4-python3-runtime (==4.13.2)", "lark (==1.2.2)", "latex2sympy @ git+https://github.com/purdue-tlt/latex2sympy.git@1.12.0"] @@ -2156,7 +2157,7 @@ parsing = ["antlr4-python3-runtime (==4.13.2)", "lark (==1.2.2)", "latex2sympy @ type = "git" url = "https://github.com/lambda-feedback/toolkit-python.git" reference = "main" -resolved_reference = "8a687d35284c156f045dde4da15a2e717112c9de" +resolved_reference = "ae52fa6f23c585f2595e6f32dc56ac8984c8fc50" [[package]] name = "libclang" @@ -2941,6 +2942,50 @@ rsa = ["cryptography (>=3.0.0)"] signals = ["blinker (>=1.4.0)"] signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] +[[package]] +name = "onnxruntime" +version = "1.29.0" +description = "ONNX Runtime is a runtime accelerator for Machine Learning models" +optional = false +python-versions = ">=3.11" +groups = ["main"] +files = [ + {file = "onnxruntime-1.29.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:07c5907474dec4a2792fd7626b753dc66707808385a6d9eecf993db0066a9d0f"}, + {file = "onnxruntime-1.29.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:16925ef8497e2c07e4b5ae15b504079b3ab3f65e22c58efd10dde0f3caea969a"}, + {file = "onnxruntime-1.29.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:85f8e8406c52658735fe5c7fbfd3ebaa1ed340768324f6252e4274e374580a23"}, + {file = "onnxruntime-1.29.0-cp311-cp311-win_amd64.whl", hash = "sha256:0d4f427afac434b0070fe992b540ddf20a7aff2265f760f314d91331935b6b98"}, + {file = "onnxruntime-1.29.0-cp311-cp311-win_arm64.whl", hash = "sha256:4eae472cf7dc3107dec1bb53cd6d142d1964616d08aae48654cd4254b2363c4b"}, + {file = "onnxruntime-1.29.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3a3814c041251d6a77fdf513fb282056538ee826d2f1178a0df3c549d3fff6ba"}, + {file = "onnxruntime-1.29.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d2fb19e848f7c33ed8d3182b52504aaa11c5e8da438bbb47296f85b133cbcf6b"}, + {file = "onnxruntime-1.29.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:2b80d8c7ec2cc7438e4da3760b88c24568cba72c9ace96d668800a6c79419acb"}, + {file = "onnxruntime-1.29.0-cp312-cp312-win_amd64.whl", hash = "sha256:4acf2b4948b7ede87221ca6332344b8facdc8059d6ac751a7d367d04532b02dd"}, + {file = "onnxruntime-1.29.0-cp312-cp312-win_arm64.whl", hash = "sha256:dc61a79cb39afd66ab3f01fd2c23591a7f01de89c1668e1fb6315067fc279164"}, + {file = "onnxruntime-1.29.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:be0f8ed688cfb1d4d5765a137193b7bfab0c8ea214eed99260b380bb525a3a7f"}, + {file = "onnxruntime-1.29.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:d67673c5367727860922c5262d724472f1b5539fb7ccf4c81a638f9b71719803"}, + {file = "onnxruntime-1.29.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e2128f31f449e922c62dbe5d8b6b7b079f0bcaf2d56a102fa203cb6e5bb5ab19"}, + {file = "onnxruntime-1.29.0-cp313-cp313-win_amd64.whl", hash = "sha256:2945e1f82f81f27e88decea88c7861f45baea23818950d467bf3909aa303119e"}, + {file = "onnxruntime-1.29.0-cp313-cp313-win_arm64.whl", hash = "sha256:4b940b0d777590c7e20bf298f5c16af1ea6ad1b400a1c822a6be192f64f4d954"}, + {file = "onnxruntime-1.29.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:533f8370ce124304e5cb08ab961836cf755631e3dd77adc5f3bbdab70c2b7d99"}, + {file = "onnxruntime-1.29.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:c1ad3f437153fe77f9d01a08fbaac0beb030e09b8a80ace1603bcf69b6c95481"}, + {file = "onnxruntime-1.29.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:e74b278af1d949876f5d91d1268fd6c680e79f2bac194967394eaba9fdf69e7e"}, + {file = "onnxruntime-1.29.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:939e5d65f332e6d399774b2bd0d3559fd8fa629c1e77833db29d968d2384f23d"}, + {file = "onnxruntime-1.29.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:6c0c37b92f67ed68dd36221ce0403e1d9bd4f7efce724439978a2597848530e5"}, + {file = "onnxruntime-1.29.0-cp314-cp314-win_amd64.whl", hash = "sha256:4a3129ae56e70d2618ff773920166916310370a7e3cacb60b9e0e8910092725f"}, + {file = "onnxruntime-1.29.0-cp314-cp314-win_arm64.whl", hash = "sha256:e417ef8628dcce310d2d53023e750ea298ec14d4341ae6dc3a572bfd9bc7fa97"}, + {file = "onnxruntime-1.29.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:11264bb58f7b7cf6af835ab10d36838d73680580820fd6f51d90124a1ca8f449"}, + {file = "onnxruntime-1.29.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1ea91cef3b971506e51ae9c37c16d027774ec64994a524ec1bdfb027d68a9832"}, +] + +[package.dependencies] +flatbuffers = "*" +numpy = ">=1.21.6" +packaging = "*" +protobuf = ">=4.25.8" + +[package.extras] +quantization = ["ml_dtypes"] +symbolic = ["sympy"] + [[package]] name = "opt-einsum" version = "3.4.0" @@ -5422,4 +5467,4 @@ cffi = ["cffi (>=1.17,<2.0) ; platform_python_implementation != \"PyPy\" and pyt [metadata] lock-version = "2.1" python-versions = ">=3.11,<3.12" -content-hash = "47bf7d0a1f4ad2a4d8bcc6c63b3a918a85411923f78a250939f67d3eb2e4fc53" +content-hash = "43383321d186b8a5e7ea30d2109ec5abbac95d41a08d4641de06840ae1175380" diff --git a/pyproject.toml b/pyproject.toml index cc7a9d8..c33d30c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,10 @@ matplotlib = "^3.11.0" pretty-midi = "^0.2.11" pandas = "^3.0.3" librosa = "^0.11.0" -basic-pitch = "^0.4.0" +# The "onnx" extra pins an inference backend explicitly. Without it, +# basic-pitch relies on platform markers that leave linux/arm64 with no +# backend at all, so the container dies at import. See backend_test.py. +basic-pitch = { version = "^0.4.0", extras = ["onnx"] } setuptools = "<81" tqdm = "^4.68.4" huggingface-hub = "^1.23.0"