Skip to content
9 changes: 7 additions & 2 deletions Doc/library/wave.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ 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
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.
Expand All @@ -52,6 +53,10 @@ 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 <path-like object>`
and :term:`bytes-like objects <bytes-like object>`.

.. exception:: Error

An error raised when something is impossible because it violates the WAV
Expand Down
22 changes: 22 additions & 0 deletions Lib/test/test_wave.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import unittest
from test import audiotests
from test import support
from test.support.os_helper import FakePath
import io
import os
import struct
import tempfile
import sys
import wave

Expand Down Expand Up @@ -206,5 +208,25 @@ def test_open_in_write_raises(self):
self.assertIsNone(cm.unraisable)


class WaveOpen(unittest.TestCase):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't there a place for this test in an existing class? You can also look in audiotests -- if this was added before removing aifc, the test should be added there.

Copy link
Contributor Author

@mbyrnepr2 mbyrnepr2 Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had also considered adding the new tests to MiscTestCase or WaveLowLevelTest - I don't have a good reason to create a new class now that I think of it, except that perhaps they don't strictly belong in either of those places.

Just to clarify your point about adding the tests to audiotests.py - are you saying that the new tests should simply be moved there instead? Or do you mean that the existing tests in test_wave.py should inherit the new tests similar to the existing design?
My rationale for adding the tests to test_wave.py is I did feel like they belonged in test_wave.py and not audiotests.py since the classes in audiotests.py are inherited by the classes in test_wave.py to assert a range of things which felt redundant for the new tests to also perform.

def test_open_pathlike(self):
"""It is possible to use `wave.read` and `wave.write` with a path-like object"""
with tempfile.NamedTemporaryFile(delete_on_close=False) as fp:
cases = (
FakePath(fp.name),
FakePath(os.fsencode(fp.name)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test also for os.fsencode(fp.name).

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__':
unittest.main()
5 changes: 3 additions & 2 deletions Lib/wave.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@

from collections import namedtuple
import builtins
import os
import struct
import sys

Expand Down Expand Up @@ -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, (bytes, str, os.PathLike)):
f = builtins.open(f, 'rb')
self._i_opened_the_file = f
# else, assume it is an open file object already
Expand Down Expand Up @@ -431,7 +432,7 @@ class Wave_write:

def __init__(self, f):
self._i_opened_the_file = None
if isinstance(f, str):
if isinstance(f, (bytes, str, os.PathLike)):
f = builtins.open(f, 'wb')
self._i_opened_the_file = f
try:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support of :term:`path-like objects <path-like object>` and :term:`bytes-like objects <bytes-like object>` in :func:`wave.open`.
Loading