From 9bc616cb4cd0610c21611554b50791f4d4c850e8 Mon Sep 17 00:00:00 2001 From: Mori Bellamy Date: Sun, 22 May 2022 18:54:24 -0700 Subject: [PATCH] gh-91061: also accept pathlib.Path for winsound.PlaySound (#91489) Fixes #91061 Co-authored-by: Jelle Zijlstra --- Lib/test/test_winsound.py | 22 +++++++++++++++++++ ...2-04-12-18-35-20.gh-issue-91061.x40hSK.rst | 1 + PC/winsound.c | 22 +++++++++++++------ 3 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2022-04-12-18-35-20.gh-issue-91061.x40hSK.rst diff --git a/Lib/test/test_winsound.py b/Lib/test/test_winsound.py index 3c3359b9004..a59d0d24f5d 100644 --- a/Lib/test/test_winsound.py +++ b/Lib/test/test_winsound.py @@ -1,6 +1,7 @@ # Ridiculously simple test of the winsound module for Windows. import functools +import pathlib import time import unittest @@ -84,6 +85,13 @@ def test_keyword_args(self): safe_MessageBeep(type=winsound.MB_OK) +# A class for testing winsound when the given path resolves +# to bytes rather than str. +class BytesPath(pathlib.WindowsPath): + def __fspath__(self): + return bytes(super().__fspath__(), 'UTF-8') + + class PlaySoundTest(unittest.TestCase): def test_errors(self): @@ -116,6 +124,20 @@ def test_snd_filename(self): fn = support.findfile('pluck-pcm8.wav', subdir='audiodata') safe_PlaySound(fn, winsound.SND_FILENAME | winsound.SND_NODEFAULT) + def test_snd_filepath(self): + fn = support.findfile('pluck-pcm8.wav', subdir='audiodata') + path = pathlib.Path(fn) + safe_PlaySound(path, winsound.SND_FILENAME | winsound.SND_NODEFAULT) + + def test_snd_filepath_as_bytes(self): + fn = support.findfile('pluck-pcm8.wav', subdir='audiodata') + self.assertRaises( + TypeError, + winsound.PlaySound, + BytesPath(fn), + winsound.SND_FILENAME | winsound.SND_NODEFAULT + ) + def test_aliases(self): aliases = [ "SystemAsterisk", diff --git a/Misc/NEWS.d/next/Windows/2022-04-12-18-35-20.gh-issue-91061.x40hSK.rst b/Misc/NEWS.d/next/Windows/2022-04-12-18-35-20.gh-issue-91061.x40hSK.rst new file mode 100644 index 00000000000..aadc3034420 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2022-04-12-18-35-20.gh-issue-91061.x40hSK.rst @@ -0,0 +1 @@ +Accept os.PathLike for the argument to winsound.PlaySound diff --git a/PC/winsound.c b/PC/winsound.c index fd04e1e55b5..65025ddc5e1 100644 --- a/PC/winsound.c +++ b/PC/winsound.c @@ -94,17 +94,25 @@ winsound_PlaySound_impl(PyObject *module, PyObject *sound, int flags) return NULL; } wsound = (wchar_t *)view.buf; + } else if (PyBytes_Check(sound)) { + PyErr_Format(PyExc_TypeError, + "'sound' must be str, os.PathLike, or None, not '%s'", + Py_TYPE(sound)->tp_name); + return NULL; } else { - if (!PyUnicode_Check(sound)) { + PyObject *obj = PyOS_FSPath(sound); + // Either is unicode/bytes/NULL, or a helpful message + // has been surfaced to the user about how they gave a non-path. + if (obj == NULL) return NULL; + if (PyBytes_Check(obj)) { PyErr_Format(PyExc_TypeError, - "'sound' must be str or None, not '%s'", - Py_TYPE(sound)->tp_name); - return NULL; - } - wsound = PyUnicode_AsWideCharString(sound, NULL); - if (wsound == NULL) { + "'sound' must resolve to str, not bytes"); + Py_DECREF(obj); return NULL; } + wsound = PyUnicode_AsWideCharString(obj, NULL); + Py_DECREF(obj); + if (wsound == NULL) return NULL; }