Closes #27748: Merge with 3.5

This commit is contained in:
Zachary Ware 2016-09-05 16:15:20 -05:00
commit 0e76e67246
2 changed files with 60 additions and 201 deletions

View File

@ -1,13 +0,0 @@
rem Check for a working sound-card - exit with 0 if OK, 1 otherwise.
set wmi = GetObject("winmgmts:")
set scs = wmi.InstancesOf("win32_sounddevice")
for each sc in scs
set status = sc.Properties_("Status")
wscript.Echo(sc.Properties_("Name") + "/" + status)
if status = "OK" then
wscript.Quit 0 rem normal exit
end if
next
rem No sound card found - exit with status code of 1
wscript.Quit 1

View File

@ -1,38 +1,42 @@
# Ridiculously simple test of the winsound module for Windows. # Ridiculously simple test of the winsound module for Windows.
import unittest import functools
from test import support
support.requires('audio')
import time
import os import os
import subprocess import subprocess
import time
import unittest
from test import support
support.requires('audio')
winsound = support.import_module('winsound') winsound = support.import_module('winsound')
ctypes = support.import_module('ctypes')
import winreg
def has_sound(sound):
"""Find out if a particular event is configured with a default sound"""
try:
# Ask the mixer API for the number of devices it knows about.
# When there are no devices, PlaySound will fail.
if ctypes.windll.winmm.mixerGetNumDevs() == 0:
return False
key = winreg.OpenKeyEx(winreg.HKEY_CURRENT_USER, # Unless we actually have an ear in the room, we have no idea whether a sound
"AppEvents\Schemes\Apps\.Default\{0}\.Default".format(sound)) # actually plays, and it's incredibly flaky trying to figure out if a sound
return winreg.EnumValue(key, 0)[1] != "" # even *should* play. Instead of guessing, just call the function and assume
except OSError: # it either passed or raised the RuntimeError we expect in case of failure.
return False def sound_func(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
ret = func(*args, **kwargs)
except RuntimeError as e:
if support.verbose:
print(func.__name__, 'failed:', e)
else:
if support.verbose:
print(func.__name__, 'returned')
return ret
return wrapper
safe_Beep = sound_func(winsound.Beep)
safe_MessageBeep = sound_func(winsound.MessageBeep)
safe_PlaySound = sound_func(winsound.PlaySound)
class BeepTest(unittest.TestCase): class BeepTest(unittest.TestCase):
# As with PlaySoundTest, incorporate the _have_soundcard() check
# into our test methods. If there's no audio device present,
# winsound.Beep returns 0 and GetLastError() returns 127, which
# is: ERROR_PROC_NOT_FOUND ("The specified procedure could not
# be found"). (FWIW, virtual/Hyper-V systems fall under this
# scenario as they have no sound devices whatsoever (not even
# a legacy Beep device).)
def test_errors(self): def test_errors(self):
self.assertRaises(TypeError, winsound.Beep) self.assertRaises(TypeError, winsound.Beep)
@ -40,27 +44,12 @@ class BeepTest(unittest.TestCase):
self.assertRaises(ValueError, winsound.Beep, 32768, 75) self.assertRaises(ValueError, winsound.Beep, 32768, 75)
def test_extremes(self): def test_extremes(self):
self._beep(37, 75) safe_Beep(37, 75)
self._beep(32767, 75) safe_Beep(32767, 75)
def test_increasingfrequency(self): def test_increasingfrequency(self):
for i in range(100, 2000, 100): for i in range(100, 2000, 100):
self._beep(i, 75) safe_Beep(i, 75)
def _beep(self, *args):
# these tests used to use _have_soundcard(), but it's quite
# possible to have a soundcard, and yet have the beep driver
# disabled. So basically, we have no way of knowing whether
# a beep should be produced or not, so currently if these
# tests fail we're ignoring them
#
# XXX the right fix for this is to define something like
# _have_enabled_beep_driver() and use that instead of the
# try/except below
try:
winsound.Beep(*args)
except RuntimeError:
pass
class MessageBeepTest(unittest.TestCase): class MessageBeepTest(unittest.TestCase):
@ -70,22 +59,22 @@ class MessageBeepTest(unittest.TestCase):
def test_default(self): def test_default(self):
self.assertRaises(TypeError, winsound.MessageBeep, "bad") self.assertRaises(TypeError, winsound.MessageBeep, "bad")
self.assertRaises(TypeError, winsound.MessageBeep, 42, 42) self.assertRaises(TypeError, winsound.MessageBeep, 42, 42)
winsound.MessageBeep() safe_MessageBeep()
def test_ok(self): def test_ok(self):
winsound.MessageBeep(winsound.MB_OK) safe_MessageBeep(winsound.MB_OK)
def test_asterisk(self): def test_asterisk(self):
winsound.MessageBeep(winsound.MB_ICONASTERISK) safe_MessageBeep(winsound.MB_ICONASTERISK)
def test_exclamation(self): def test_exclamation(self):
winsound.MessageBeep(winsound.MB_ICONEXCLAMATION) safe_MessageBeep(winsound.MB_ICONEXCLAMATION)
def test_hand(self): def test_hand(self):
winsound.MessageBeep(winsound.MB_ICONHAND) safe_MessageBeep(winsound.MB_ICONHAND)
def test_question(self): def test_question(self):
winsound.MessageBeep(winsound.MB_ICONQUESTION) safe_MessageBeep(winsound.MB_ICONQUESTION)
class PlaySoundTest(unittest.TestCase): class PlaySoundTest(unittest.TestCase):
@ -99,151 +88,34 @@ class PlaySoundTest(unittest.TestCase):
"none", winsound.SND_ASYNC | winsound.SND_MEMORY "none", winsound.SND_ASYNC | winsound.SND_MEMORY
) )
@unittest.skipUnless(has_sound("SystemAsterisk"), def test_aliases(self):
"No default SystemAsterisk") aliases = [
def test_alias_asterisk(self): "SystemAsterisk",
if _have_soundcard(): "SystemExclamation",
winsound.PlaySound('SystemAsterisk', winsound.SND_ALIAS) "SystemExit",
else: "SystemHand",
self.assertRaises( "SystemQuestion",
RuntimeError, ]
winsound.PlaySound, for alias in aliases:
'SystemAsterisk', winsound.SND_ALIAS with self.subTest(alias=alias):
) safe_PlaySound(alias, winsound.SND_ALIAS)
@unittest.skipUnless(has_sound("SystemExclamation"),
"No default SystemExclamation")
def test_alias_exclamation(self):
if _have_soundcard():
winsound.PlaySound('SystemExclamation', winsound.SND_ALIAS)
else:
self.assertRaises(
RuntimeError,
winsound.PlaySound,
'SystemExclamation', winsound.SND_ALIAS
)
@unittest.skipUnless(has_sound("SystemExit"), "No default SystemExit")
def test_alias_exit(self):
if _have_soundcard():
winsound.PlaySound('SystemExit', winsound.SND_ALIAS)
else:
self.assertRaises(
RuntimeError,
winsound.PlaySound,
'SystemExit', winsound.SND_ALIAS
)
@unittest.skipUnless(has_sound("SystemHand"), "No default SystemHand")
def test_alias_hand(self):
if _have_soundcard():
winsound.PlaySound('SystemHand', winsound.SND_ALIAS)
else:
self.assertRaises(
RuntimeError,
winsound.PlaySound,
'SystemHand', winsound.SND_ALIAS
)
@unittest.skipUnless(has_sound("SystemQuestion"),
"No default SystemQuestion")
def test_alias_question(self):
if _have_soundcard():
winsound.PlaySound('SystemQuestion', winsound.SND_ALIAS)
else:
self.assertRaises(
RuntimeError,
winsound.PlaySound,
'SystemQuestion', winsound.SND_ALIAS
)
def test_alias_fallback(self): def test_alias_fallback(self):
# In the absence of the ability to tell if a sound was actually safe_PlaySound('!"$%&/(#+*', winsound.SND_ALIAS)
# played, this test has two acceptable outcomes: success (no error,
# sound was theoretically played; although as issue #19987 shows
# a box without a soundcard can "succeed") or RuntimeError. Any
# other error is a failure.
try:
winsound.PlaySound('!"$%&/(#+*', winsound.SND_ALIAS)
except RuntimeError:
pass
def test_alias_nofallback(self): def test_alias_nofallback(self):
if _have_soundcard(): safe_PlaySound('!"$%&/(#+*', winsound.SND_ALIAS | winsound.SND_NODEFAULT)
# Note that this is not the same as asserting RuntimeError
# will get raised: you cannot convert this to
# self.assertRaises(...) form. The attempt may or may not
# raise RuntimeError, but it shouldn't raise anything other
# than RuntimeError, and that's all we're trying to test
# here. The MS docs aren't clear about whether the SDK
# PlaySound() with SND_ALIAS and SND_NODEFAULT will return
# True or False when the alias is unknown. On Tim's WinXP
# box today, it returns True (no exception is raised). What
# we'd really like to test is that no sound is played, but
# that requires first wiring an eardrum class into unittest
# <wink>.
try:
winsound.PlaySound(
'!"$%&/(#+*',
winsound.SND_ALIAS | winsound.SND_NODEFAULT
)
except RuntimeError:
pass
else:
self.assertRaises(
RuntimeError,
winsound.PlaySound,
'!"$%&/(#+*', winsound.SND_ALIAS | winsound.SND_NODEFAULT
)
def test_stopasync(self): def test_stopasync(self):
if _have_soundcard(): safe_PlaySound(
winsound.PlaySound( 'SystemQuestion',
'SystemQuestion', winsound.SND_ALIAS | winsound.SND_ASYNC | winsound.SND_LOOP
winsound.SND_ALIAS | winsound.SND_ASYNC | winsound.SND_LOOP )
) time.sleep(0.5)
time.sleep(0.5) safe_PlaySound('SystemQuestion', winsound.SND_ALIAS | winsound.SND_NOSTOP)
try: # Issue 8367: PlaySound(None, winsound.SND_PURGE)
winsound.PlaySound( # does not raise on systems without a sound card.
'SystemQuestion', winsound.PlaySound(None, winsound.SND_PURGE)
winsound.SND_ALIAS | winsound.SND_NOSTOP
)
except RuntimeError:
pass
else: # the first sound might already be finished
pass
winsound.PlaySound(None, winsound.SND_PURGE)
else:
# Issue 8367: PlaySound(None, winsound.SND_PURGE)
# does not raise on systems without a sound card.
pass
def _get_cscript_path():
"""Return the full path to cscript.exe or None."""
for dir in os.environ.get("PATH", "").split(os.pathsep):
cscript_path = os.path.join(dir, "cscript.exe")
if os.path.exists(cscript_path):
return cscript_path
__have_soundcard_cache = None
def _have_soundcard():
"""Return True iff this computer has a soundcard."""
global __have_soundcard_cache
if __have_soundcard_cache is None:
cscript_path = _get_cscript_path()
if cscript_path is None:
# Could not find cscript.exe to run our VBScript helper. Default
# to True: most computers these days *do* have a soundcard.
return True
check_script = os.path.join(os.path.dirname(__file__),
"check_soundcard.vbs")
p = subprocess.Popen([cscript_path, check_script],
stdout=subprocess.PIPE)
__have_soundcard_cache = not p.wait()
p.stdout.close()
return __have_soundcard_cache
if __name__ == "__main__": if __name__ == "__main__":