Skip to content

Commit 9bc616c

Browse files
gh-91061: also accept pathlib.Path for winsound.PlaySound (#91489)
Fixes #91061 Co-authored-by: Jelle Zijlstra <[email protected]>
1 parent e39cd76 commit 9bc616c

File tree

3 files changed

+38
-7
lines changed

3 files changed

+38
-7
lines changed

Lib/test/test_winsound.py

+22
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Ridiculously simple test of the winsound module for Windows.
22

33
import functools
4+
import pathlib
45
import time
56
import unittest
67

@@ -84,6 +85,13 @@ def test_keyword_args(self):
8485
safe_MessageBeep(type=winsound.MB_OK)
8586

8687

88+
# A class for testing winsound when the given path resolves
89+
# to bytes rather than str.
90+
class BytesPath(pathlib.WindowsPath):
91+
def __fspath__(self):
92+
return bytes(super().__fspath__(), 'UTF-8')
93+
94+
8795
class PlaySoundTest(unittest.TestCase):
8896

8997
def test_errors(self):
@@ -116,6 +124,20 @@ def test_snd_filename(self):
116124
fn = support.findfile('pluck-pcm8.wav', subdir='audiodata')
117125
safe_PlaySound(fn, winsound.SND_FILENAME | winsound.SND_NODEFAULT)
118126

127+
def test_snd_filepath(self):
128+
fn = support.findfile('pluck-pcm8.wav', subdir='audiodata')
129+
path = pathlib.Path(fn)
130+
safe_PlaySound(path, winsound.SND_FILENAME | winsound.SND_NODEFAULT)
131+
132+
def test_snd_filepath_as_bytes(self):
133+
fn = support.findfile('pluck-pcm8.wav', subdir='audiodata')
134+
self.assertRaises(
135+
TypeError,
136+
winsound.PlaySound,
137+
BytesPath(fn),
138+
winsound.SND_FILENAME | winsound.SND_NODEFAULT
139+
)
140+
119141
def test_aliases(self):
120142
aliases = [
121143
"SystemAsterisk",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Accept os.PathLike for the argument to winsound.PlaySound

PC/winsound.c

+15-7
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,25 @@ winsound_PlaySound_impl(PyObject *module, PyObject *sound, int flags)
9494
return NULL;
9595
}
9696
wsound = (wchar_t *)view.buf;
97+
} else if (PyBytes_Check(sound)) {
98+
PyErr_Format(PyExc_TypeError,
99+
"'sound' must be str, os.PathLike, or None, not '%s'",
100+
Py_TYPE(sound)->tp_name);
101+
return NULL;
97102
} else {
98-
if (!PyUnicode_Check(sound)) {
103+
PyObject *obj = PyOS_FSPath(sound);
104+
// Either <obj> is unicode/bytes/NULL, or a helpful message
105+
// has been surfaced to the user about how they gave a non-path.
106+
if (obj == NULL) return NULL;
107+
if (PyBytes_Check(obj)) {
99108
PyErr_Format(PyExc_TypeError,
100-
"'sound' must be str or None, not '%s'",
101-
Py_TYPE(sound)->tp_name);
102-
return NULL;
103-
}
104-
wsound = PyUnicode_AsWideCharString(sound, NULL);
105-
if (wsound == NULL) {
109+
"'sound' must resolve to str, not bytes");
110+
Py_DECREF(obj);
106111
return NULL;
107112
}
113+
wsound = PyUnicode_AsWideCharString(obj, NULL);
114+
Py_DECREF(obj);
115+
if (wsound == NULL) return NULL;
108116
}
109117

110118

0 commit comments

Comments
 (0)