`aifc` module is deprecated (and removed in Python 3.13)
This package still uses the aifc module that is deprecated since Python 3.11, and was removed in Python 3.13.
As a result, the test suite fails with 3.13.0b2:
$ tox -e py313
py313: install_deps> python -I -m pip install pytest
.pkg: _optional_hooks> python /usr/lib/python3.12/site-packages/pyproject_api/_backend.py True flit_core.buildapi
.pkg: get_requires_for_build_sdist> python /usr/lib/python3.12/site-packages/pyproject_api/_backend.py True flit_core.buildapi
.pkg: build_sdist> python /usr/lib/python3.12/site-packages/pyproject_api/_backend.py True flit_core.buildapi
py313: install_package> python -I -m pip install --force-reinstall --no-deps /tmp/audioread/.tox/.tmp/package/2/audioread-3.0.2.tar.gz
py313: commands[0]> pytest
========================================================= test session starts =========================================================
platform linux -- Python 3.13.0b2, pytest-8.2.2, pluggy-1.5.0
cachedir: .tox/py313/.pytest_cache
rootdir: /tmp/audioread
configfile: pyproject.toml
collected 4 items
test/test_audioread.py FFFF [100%]
============================================================== FAILURES ===============================================================
__________________________________________________ test_audioread_early_exit[test-1] __________________________________________________
audiofile = <conftest.AudiofileSpec object at 0x7efcb006cad0>
def test_audioread_early_exit(audiofile):
"""Abort the read before it is completed.
This test guards against regressions such as
https://github.com/beetbox/audioread/pull/78
"""
> with audioread.audio_open(audiofile.path) as a:
test/test_audioread.py:29:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.tox/py313/lib/python3.13/site-packages/audioread/__init__.py:123: in audio_open
backends = available_backends()
.tox/py313/lib/python3.13/site-packages/audioread/__init__.py:80: in available_backends
from . import rawread
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
# This file is part of audioread.
# Copyright 2011, Adrian Sampson.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
"""Uses standard-library modules to read AIFF, AIFF-C, and WAV files."""
> import aifc
E ModuleNotFoundError: No module named 'aifc'
.tox/py313/lib/python3.13/site-packages/audioread/rawread.py:16: ModuleNotFoundError
__________________________________________________ test_audioread_early_exit[test-2] __________________________________________________
audiofile = <conftest.AudiofileSpec object at 0x7efcb001bc50>
def test_audioread_early_exit(audiofile):
"""Abort the read before it is completed.
This test guards against regressions such as
https://github.com/beetbox/audioread/pull/78
"""
> with audioread.audio_open(audiofile.path) as a:
test/test_audioread.py:29:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.tox/py313/lib/python3.13/site-packages/audioread/__init__.py:123: in audio_open
backends = available_backends()
.tox/py313/lib/python3.13/site-packages/audioread/__init__.py:80: in available_backends
from . import rawread
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
# This file is part of audioread.
# Copyright 2011, Adrian Sampson.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
"""Uses standard-library modules to read AIFF, AIFF-C, and WAV files."""
> import aifc
E ModuleNotFoundError: No module named 'aifc'
.tox/py313/lib/python3.13/site-packages/audioread/rawread.py:16: ModuleNotFoundError
_____________________________________________________ test_audioread_full[test-1] _____________________________________________________
audiofile = <conftest.AudiofileSpec object at 0x7efcafd8c2d0>
def test_audioread_full(audiofile):
"""Read the audio data from the file."""
> with audioread.audio_open(audiofile.path) as a:
test/test_audioread.py:38:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.tox/py313/lib/python3.13/site-packages/audioread/__init__.py:123: in audio_open
backends = available_backends()
.tox/py313/lib/python3.13/site-packages/audioread/__init__.py:80: in available_backends
from . import rawread
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
# This file is part of audioread.
# Copyright 2011, Adrian Sampson.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
"""Uses standard-library modules to read AIFF, AIFF-C, and WAV files."""
> import aifc
E ModuleNotFoundError: No module named 'aifc'
.tox/py313/lib/python3.13/site-packages/audioread/rawread.py:16: ModuleNotFoundError
_____________________________________________________ test_audioread_full[test-2] _____________________________________________________
audiofile = <conftest.AudiofileSpec object at 0x7efcafff7950>
def test_audioread_full(audiofile):
"""Read the audio data from the file."""
> with audioread.audio_open(audiofile.path) as a:
test/test_audioread.py:38:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.tox/py313/lib/python3.13/site-packages/audioread/__init__.py:123: in audio_open
backends = available_backends()
.tox/py313/lib/python3.13/site-packages/audioread/__init__.py:80: in available_backends
from . import rawread
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
# This file is part of audioread.
# Copyright 2011, Adrian Sampson.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
"""Uses standard-library modules to read AIFF, AIFF-C, and WAV files."""
> import aifc
E ModuleNotFoundError: No module named 'aifc'
.tox/py313/lib/python3.13/site-packages/audioread/rawread.py:16: ModuleNotFoundError
======================================================= short test summary info =======================================================
FAILED test/test_audioread.py::test_audioread_early_exit[test-1] - ModuleNotFoundError: No module named 'aifc'
FAILED test/test_audioread.py::test_audioread_early_exit[test-2] - ModuleNotFoundError: No module named 'aifc'
FAILED test/test_audioread.py::test_audioread_full[test-1] - ModuleNotFoundError: No module named 'aifc'
FAILED test/test_audioread.py::test_audioread_full[test-2] - ModuleNotFoundError: No module named 'aifc'
========================================================== 4 failed in 0.08s ==========================================================
py313: exit 1 (0.38 seconds) /tmp/audioread> pytest pid=97746
.pkg: _exit> python /usr/lib/python3.12/site-packages/pyproject_api/_backend.py True flit_core.buildapi
py313: FAIL code 1 (5.46=setup[5.08]+cmd[0.38] seconds)
evaluation failed :( (5.57 seconds)
It's worth mentioning that the sunau module is also deprecated and being removed at the same time.
(There was discussion about wave, but looks like they'd decided to keep it in python core)
There's an attempt to make the deprecated libraries available as pip dependencies: https://github.com/youknowone/python-deadlib However, it seems there's currently a couple of issues with that repository which means it won't work with 3.13 yet.
I've submitted a pull request to the python-deadlib library to try to get its aifc fork from the python core working on python 3.13: https://github.com/youknowone/python-deadlib/pull/9
Another potential approach would be to handle the ModuleNotFoundError more gracefully here. That would reduce the range of file types supported on python3.13, but is still better than a hard error, even when aifc support isn't needed!
The python-deadlib modules have now been fixed up and can be used to replace the missing modules from python core.
So a workaround to this issue is pip install standard-aifc standard-sunau
The library does not build on python 3.12 too https://github.com/Anjok07/ultimatevocalremovergui/issues/1578#issuecomment-2525067265
pipx >(analyze_pip_output:311): pip seemed to fail to build package:
audioread==3.0.0
Some possibly relevant errors from pip install:
error: subprocess-exited-with-error
ModuleNotFoundError: No module named 'imp'
@montvid I don't think your error is related to this issue.
Looks like that the imp issue might have been fixed in 3.0.1 (see https://github.com/beetbox/audioread/issues/136 ) I'd guess ultimatevocalremovergui just needs to update its dependencies to the latest release.
I wonder if using https://github.com/scientific-python/lazy-loader could help? Then the modules would only be loaded (and thus fail to be found) on demand.
@ISSOtm That approach would mean some uses of audioread would work in python 3.13, but others would error. Whilst it's tempting (and would certainly solve my personal use of it), I think it'd cause confusing results to people unfamiliar with the internal implementation. The question of "is this library supported in python 3.13?" would need an answer of "it depends", followed by details of the nuance. Given the effort needed to introduce lazy-loader, it seems just as simple to fully support python 3.13, and in doing so be much clearer to users of the library.
@ISSOtm That approach would mean some uses of audioread would work in python 3.13, but others would error. Whilst it's tempting (and would certainly solve my personal use of it), I think it'd cause confusing results to people unfamiliar with the internal implementation. The question of "is this library supported in python 3.13?" would need an answer of "it depends", followed by details of the nuance. Given the effort needed to introduce lazy-loader, it seems just as simple to fully support python 3.13, and in doing so be much clearer to users of the library.
Isn't this always the case though? The formats supported by any particular installation of audioread generally depend on several factors that can't be strictly determined by python dependencies. For example, if it calls out to the ffmpeg backend, the supported formats will depend on whatever that version of ffmpeg happened to be compiled with.
Isn't this always the case though? The formats supported by any particular installation of audioread generally depend on several factors that can't be strictly determined by python dependencies. For example, if it calls out to the ffmpeg backend, the supported formats will depend on whatever that version of ffmpeg happened to be compiled with.
In my mind, which runtime versions a library supports feels more fundamental than other programmes it interacts with. But taking a step back, I concede that distinction is kinda arbitrary.
So I guess the real question is whether people prefer to face more errors at install time, or make installs easier with the potential for more runtime errors. As a user of the library, I'm in favour of install time errors I find them much easier to identify and debug than runtime errors. But I understand others may disagree.
As a user of the library, I'm in favour of install time errors I find them much easier to identify and debug than runtime errors.
I'm with you on that. 😅 There's a limit to what python package specs can realistically accomplish here though.
For whatever it's worth, I like the solution of having a 3.13-specific dependency for aifc and sunau (as done in #145 ). One variation on this could be putting it in an extras_require section, so you could do eg pip install audioread[legacy] to be extra-sure that these formats will be supported at install-time, but otherwise let them drop or be supported by other backends.
Irrespective of the argument below, I am in favour of #145 over using e.g. `lazy_loader`. The argument being “spoiler'd” is only for completeness' sake, since we have an “ideal” PR it should just be merged.
I agree that an error should be at compile time instead of at runtime, but the difference here is that the library does not compile at all with 3.13, whereas the runtime route allows most functionality to be restored. Therein lies the tradeoff.
And as a downstream packager, I would prefer a solution where these modules are optional (even if they are always listed as dependencies, but still ImportError does not cause a complete failure). I don't want to have to add more unmaintained packages for formats that most of our users have never seen in their lives.
Quick follow-up to this thread, I've implemented in #148 the alternative solution described above: a soft-failure (warning) without lazy-loading, and a pip install audioread[legacy] mode to force the external packages on modern python.
I don't mind if this PR is not accepted, I just wanted to help get progress unstuck in case @sampsyo wants to go this direction.
Giving a nudge on this thread - there are now two viable PRs to resolve the issue, and getting this patched and released would unblock python 3.13 support downstream.
Out of curiosity, does anyone in this thread actually have permission to make the decision to merge either PR? I notice there's been no commits to this repo since 2023, so I'm wondering if there are any active maintainers keeping an eye on it.
Pinging others from beets repo to see if they have merge privledges
@snejus @JOJ0
Nudging this again @sampsyo
I've managed to unstick my downstream releases from this issue for the time being, but it is going to be a problem long-term. I did just now identify an extra reason why a soft dependency (as in #148 ) might be preferable to a hard dependency with a version filter (as in #145 ): conda-forge packaging.
In pypi, we can easily enough say that a requirement is only needed on python>=3.13. On conda-forge, it's a bit more difficult, and doing so (as far as I understand) conflicts with "noarch" packaging. So any downstream package (audioread->librosa->anything else) would need to ship separate packages for each platform, even if the package is pure python.
However, if the legacy codec requirements are soft, then we can simply not include them in the conda-forge package at all. The downstream packages never need to worry about changing their builds, and any user that really wants the legacy codec support could still install them via pypi if they wanted to.
Note @sampsyo had not been active recently, tagging @beetbox/maintainers may be your best bet if you need something that needs looking at!
From Gentoo perspective, I find this far from a good solution. We're only packaging audioread because of pyacoustid, and I honestly doubt anyone would use this package on top of some ancient sunAU files. "Dead batteries" are just a bunch of stuff copied from Python 3.13 that's been dumped and is not maintained, with incomplete source distributions and unresponsive maintainer. The way I see it, it's a supply chain attack waiting to happen.
@mgorny In my opinion, dropping support in audioread for those old file types is likely fine; but would be a breaking change, so should be something for a version 4.
I agree using the dead batteries isn't an ideal long-term solution, but it was the simplest way of keeping the current version of audioread working with the latest versions of python.
Should we create a new issue for dropping these entirely and can discuss the best way to handle their deprecation?
Well, I'm fine with whatever works for you. FWICS Gentoo previously already included #148 which is kinda messy on our end.