From 99e7d5a29d9c07fe90026008db5ad713e6f2772e Mon Sep 17 00:00:00 2001 From: Mark Byrne Date: Mon, 3 Nov 2025 16:42:22 +0100 Subject: [PATCH 01/10] wave.py - Allow opening of path-like files. --- Lib/test/test_wave.py | 14 ++++++++++++++ Lib/wave.py | 5 +++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py index 226b1aa84bd73c..f8d911c99a8a68 100644 --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -3,7 +3,9 @@ from test import support import io import os +import pathlib import struct +import tempfile import sys import wave @@ -205,6 +207,18 @@ def test_open_in_write_raises(self): support.gc_collect() self.assertIsNone(cm.unraisable) + def test_open_pathlike(self): + """It is possible to use `wave.read` and `wave.write` with a path-like file""" + with tempfile.NamedTemporaryFile(delete_on_close=False) as fp: + WAV_FILE = pathlib.Path(fp.name) + with wave.open(WAV_FILE, 'wb') as f: + f.setnchannels(1) + f.setsampwidth(2) + f.setframerate(44100) + + with wave.open(WAV_FILE, 'rb') as f: + pass + if __name__ == '__main__': unittest.main() diff --git a/Lib/wave.py b/Lib/wave.py index 5af745e2217ec3..68cf2d3b86161e 100644 --- a/Lib/wave.py +++ b/Lib/wave.py @@ -69,6 +69,7 @@ from collections import namedtuple import builtins +import os import struct import sys @@ -274,7 +275,7 @@ def initfp(self, file): def __init__(self, f): self._i_opened_the_file = None - if isinstance(f, str): + if isinstance(f, (str, os.PathLike)): f = builtins.open(f, 'rb') self._i_opened_the_file = f # else, assume it is an open file object already @@ -431,7 +432,7 @@ class Wave_write: def __init__(self, f): self._i_opened_the_file = None - if isinstance(f, str): + if isinstance(f, (str, os.PathLike)): f = builtins.open(f, 'wb') self._i_opened_the_file = f try: From 6475b2c634a5f0963b2fa25657d1b2fc5329ab50 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 15:51:43 +0000 Subject: [PATCH 02/10] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-11-03-15-51-42.gh-issue-140952.EFVhKR.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-11-03-15-51-42.gh-issue-140952.EFVhKR.rst diff --git a/Misc/NEWS.d/next/Library/2025-11-03-15-51-42.gh-issue-140952.EFVhKR.rst b/Misc/NEWS.d/next/Library/2025-11-03-15-51-42.gh-issue-140952.EFVhKR.rst new file mode 100644 index 00000000000000..3b09bd79c167b5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-11-03-15-51-42.gh-issue-140952.EFVhKR.rst @@ -0,0 +1 @@ +wave.py - Allow opening of path-like files. From a36d5fc0c3948a9555d115272cb761f77577fcb7 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 4 Nov 2025 12:16:14 +0000 Subject: [PATCH 03/10] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst diff --git a/Misc/NEWS.d/next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst b/Misc/NEWS.d/next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst new file mode 100644 index 00000000000000..3b09bd79c167b5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst @@ -0,0 +1 @@ +wave.py - Allow opening of path-like files. From a09e5c37bb1a16340db54b35441cbb12115019ab Mon Sep 17 00:00:00 2001 From: Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com> Date: Tue, 4 Nov 2025 13:16:48 +0100 Subject: [PATCH 04/10] Delete Misc/NEWS.d/next/Library/2025-11-03-15-51-42.gh-issue-140952.EFVhKR.rst --- .../next/Library/2025-11-03-15-51-42.gh-issue-140952.EFVhKR.rst | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Misc/NEWS.d/next/Library/2025-11-03-15-51-42.gh-issue-140952.EFVhKR.rst diff --git a/Misc/NEWS.d/next/Library/2025-11-03-15-51-42.gh-issue-140952.EFVhKR.rst b/Misc/NEWS.d/next/Library/2025-11-03-15-51-42.gh-issue-140952.EFVhKR.rst deleted file mode 100644 index 3b09bd79c167b5..00000000000000 --- a/Misc/NEWS.d/next/Library/2025-11-03-15-51-42.gh-issue-140952.EFVhKR.rst +++ /dev/null @@ -1 +0,0 @@ -wave.py - Allow opening of path-like files. From 95b2fcec25983662abe7bb79f472f32e7d87e0af Mon Sep 17 00:00:00 2001 From: Mark Byrne Date: Tue, 4 Nov 2025 13:44:09 +0100 Subject: [PATCH 05/10] Update the `wave.py` documentation. --- Doc/library/wave.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/wave.rst b/Doc/library/wave.rst index a3f5bfd5e2f99c..ef20b5a51bd2c3 100644 --- a/Doc/library/wave.rst +++ b/Doc/library/wave.rst @@ -25,7 +25,7 @@ The :mod:`wave` module defines the following function and exception: .. function:: open(file, mode=None) - If *file* is a string, open the file by that name, otherwise treat it as a + If *file* is a string or a :term:`path-like object`, open the file by that name, otherwise treat it as a file-like object. *mode* can be: ``'rb'`` From 9b96c88c3ac8d2ec74ce0cfcc8ec6d84c4090e9b Mon Sep 17 00:00:00 2001 From: Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com> Date: Thu, 6 Nov 2025 15:22:12 +0100 Subject: [PATCH 06/10] Update Misc/NEWS.d/next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst Co-authored-by: Serhiy Storchaka --- .../next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst b/Misc/NEWS.d/next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst index 3b09bd79c167b5..85975c5331bde7 100644 --- a/Misc/NEWS.d/next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst +++ b/Misc/NEWS.d/next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst @@ -1 +1 @@ -wave.py - Allow opening of path-like files. +Add support of :term:`path-like objects ` in :func:`wave.open`. From ec5b3df9ec72dbab1b1604afcb8e54145755f997 Mon Sep 17 00:00:00 2001 From: Mark Byrne Date: Thu, 6 Nov 2025 15:28:27 +0100 Subject: [PATCH 07/10] Code review improvements: - Use `FakePath` instead of `pathlib.Path`. - Add an extra test case for the bytes path case. - Format the doc and add `versionchanged`. --- Doc/library/wave.rst | 7 +++++-- Lib/test/test_wave.py | 26 +++++++++++++++++--------- Lib/wave.py | 4 ++-- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Doc/library/wave.rst b/Doc/library/wave.rst index ef20b5a51bd2c3..0e13f4a3dcf2d9 100644 --- a/Doc/library/wave.rst +++ b/Doc/library/wave.rst @@ -25,8 +25,8 @@ The :mod:`wave` module defines the following function and exception: .. function:: open(file, mode=None) - If *file* is a string or a :term:`path-like object`, open the file by that name, otherwise treat it as a - file-like object. *mode* can be: + If *file* is a string or a :term:`path-like object`, open the file by that name, + otherwise treat it as a file-like object. *mode* can be: ``'rb'`` Read only mode. @@ -52,6 +52,9 @@ The :mod:`wave` module defines the following function and exception: .. versionchanged:: 3.4 Added support for unseekable files. + .. versionchanged:: 3.15 + Added support for :term:`path-like objects `. + .. exception:: Error An error raised when something is impossible because it violates the WAV diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py index f8d911c99a8a68..814cbba8c92616 100644 --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -1,6 +1,7 @@ import unittest from test import audiotests from test import support +from test.support.os_helper import FakePath import io import os import pathlib @@ -207,17 +208,24 @@ def test_open_in_write_raises(self): support.gc_collect() self.assertIsNone(cm.unraisable) + +class WaveOpen(unittest.TestCase): def test_open_pathlike(self): - """It is possible to use `wave.read` and `wave.write` with a path-like file""" + """It is possible to use `wave.read` and `wave.write` with a path-like object""" with tempfile.NamedTemporaryFile(delete_on_close=False) as fp: - WAV_FILE = pathlib.Path(fp.name) - with wave.open(WAV_FILE, 'wb') as f: - f.setnchannels(1) - f.setsampwidth(2) - f.setframerate(44100) - - with wave.open(WAV_FILE, 'rb') as f: - pass + cases = ( + FakePath(fp.name), + FakePath(os.fsencode(fp.name)), + ) + for fake_path in cases: + with self.subTest(fake_path): + with wave.open(fake_path, 'wb') as f: + f.setnchannels(1) + f.setsampwidth(2) + f.setframerate(44100) + + with wave.open(fake_path, 'rb') as f: + pass if __name__ == '__main__': diff --git a/Lib/wave.py b/Lib/wave.py index 68cf2d3b86161e..056bd6aab7ffa3 100644 --- a/Lib/wave.py +++ b/Lib/wave.py @@ -275,7 +275,7 @@ def initfp(self, file): def __init__(self, f): self._i_opened_the_file = None - if isinstance(f, (str, os.PathLike)): + if isinstance(f, (bytes, str, os.PathLike)): f = builtins.open(f, 'rb') self._i_opened_the_file = f # else, assume it is an open file object already @@ -432,7 +432,7 @@ class Wave_write: def __init__(self, f): self._i_opened_the_file = None - if isinstance(f, (str, os.PathLike)): + if isinstance(f, (bytes, str, os.PathLike)): f = builtins.open(f, 'wb') self._i_opened_the_file = f try: From ba5ed6fd42538f6250d73b07814932d63e70cda3 Mon Sep 17 00:00:00 2001 From: Mark Byrne Date: Thu, 6 Nov 2025 15:32:37 +0100 Subject: [PATCH 08/10] Remove unused import. --- Lib/test/test_wave.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py index 814cbba8c92616..6a3c640d2d4dc6 100644 --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -4,7 +4,6 @@ from test.support.os_helper import FakePath import io import os -import pathlib import struct import tempfile import sys From 31cc9c5f4298782275a8bafe3e7cb6534edd04a6 Mon Sep 17 00:00:00 2001 From: Mark Byrne Date: Tue, 11 Nov 2025 17:23:46 +0100 Subject: [PATCH 09/10] Use code review improvements: - More accurate documentation. - More complete test cases. --- Doc/library/wave.rst | 8 +++++--- Lib/test/test_wave.py | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Doc/library/wave.rst b/Doc/library/wave.rst index 0e13f4a3dcf2d9..7ff2c97992c4e3 100644 --- a/Doc/library/wave.rst +++ b/Doc/library/wave.rst @@ -25,8 +25,9 @@ The :mod:`wave` module defines the following function and exception: .. function:: open(file, mode=None) - If *file* is a string or a :term:`path-like object`, open the file by that name, - otherwise treat it as a file-like object. *mode* can be: + If *file* is a string, a :term:`path-like object` or a + :term:`bytes-like object` open the file by that name, otherwise treat it as + a file-like object. *mode* can be: ``'rb'`` Read only mode. @@ -53,7 +54,8 @@ The :mod:`wave` module defines the following function and exception: Added support for unseekable files. .. versionchanged:: 3.15 - Added support for :term:`path-like objects `. + Added support for :term:`path-like objects ` + and :term:`bytes-like objects `. .. exception:: Error diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py index 6a3c640d2d4dc6..4c21f16553775c 100644 --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -215,6 +215,7 @@ def test_open_pathlike(self): cases = ( FakePath(fp.name), FakePath(os.fsencode(fp.name)), + os.fsencode(fp.name), ) for fake_path in cases: with self.subTest(fake_path): From 6c2b7de2e9e13d1f928b592cd1e524a6c12d9c90 Mon Sep 17 00:00:00 2001 From: Mark Byrne Date: Wed, 12 Nov 2025 08:47:23 +0100 Subject: [PATCH 10/10] Update the news with the full information. --- .../next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst b/Misc/NEWS.d/next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst index 85975c5331bde7..9a31af9c110454 100644 --- a/Misc/NEWS.d/next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst +++ b/Misc/NEWS.d/next/Library/2025-11-04-12-16-13.gh-issue-75593.EFVhKR.rst @@ -1 +1 @@ -Add support of :term:`path-like objects ` in :func:`wave.open`. +Add support of :term:`path-like objects ` and :term:`bytes-like objects ` in :func:`wave.open`.