(original) (raw)
changeset: 90536:5f75eadecff1 branch: 2.7 parent: 90517:0f6bdc2b0e38 user: Zachary Ware zachary.ware@gmail.com date: Fri May 02 10:33:49 2014 -0500 files: Lib/lib-tk/test/runtktests.py Lib/test/test_idle.py Lib/test/test_support.py Lib/test/test_tk.py Lib/test/test_ttk_guionly.py Misc/NEWS description: Issue #18604: Consolidated checks for GUI availability. test_support._is_gui_available is now defined the same way on every platform, and now includes the Windows-specific check that had been in the Windows version of _is_gui_available and the OSX-specific check that was in runtktests.check_tk_availability. Also, every platform checks whether Tk can be instantiated (if the platform-specific checks passed). diff -r 0f6bdc2b0e38 -r 5f75eadecff1 Lib/lib-tk/test/runtktests.py --- a/Lib/lib-tk/test/runtktests.py Tue Apr 29 16:11:18 2014 +0100 +++ b/Lib/lib-tk/test/runtktests.py Fri May 02 10:33:49 2014 -0500 @@ -14,49 +14,6 @@ this_dir_path = os.path.abspath(os.path.dirname(__file__)) -_tk_unavailable = None - -def check_tk_availability(): - """Check that Tk is installed and available.""" - global _tk_unavailable - - if _tk_unavailable is None: - _tk_unavailable = False - if sys.platform == 'darwin': - # The Aqua Tk implementations on OS X can abort the process if - # being called in an environment where a window server connection - # cannot be made, for instance when invoked by a buildbot or ssh - # process not running under the same user id as the current console - # user. To avoid that, raise an exception if the window manager - # connection is not available. - from ctypes import cdll, c_int, pointer, Structure - from ctypes.util import find_library - - app_services = cdll.LoadLibrary(find_library("ApplicationServices")) - - if app_services.CGMainDisplayID() == 0: - _tk_unavailable = "cannot run without OS X window manager" - else: - class ProcessSerialNumber(Structure): - _fields_ = [("highLongOfPSN", c_int), - ("lowLongOfPSN", c_int)] - psn = ProcessSerialNumber() - psn_p = pointer(psn) - if ( (app_services.GetCurrentProcess(psn_p) < 0) or - (app_services.SetFrontProcess(psn_p) < 0) ): - _tk_unavailable = "cannot run without OS X gui process" - else: # not OS X - import Tkinter - try: - Tkinter.Button() - except Tkinter.TclError as msg: - # assuming tk is not available - _tk_unavailable = "tk not available: %s" % msg - - if _tk_unavailable: - raise unittest.SkipTest(_tk_unavailable) - return - def is_package(path): for name in os.listdir(path): if name in ('__init__.py', '__init__.pyc', '__init.pyo'): @@ -68,7 +25,7 @@ and are inside packages found in the path starting at basepath. If packages is specified it should contain package names that want - their tests colleted. + their tests collected. """ py_ext = '.py' diff -r 0f6bdc2b0e38 -r 5f75eadecff1 Lib/test/test_idle.py --- a/Lib/test/test_idle.py Tue Apr 29 16:11:18 2014 +0100 +++ b/Lib/test/test_idle.py Fri May 02 10:33:49 2014 -0500 @@ -1,24 +1,12 @@ import unittest from test import test_support as support -from test.test_support import import_module, use_resources +from test.test_support import import_module # Skip test if _thread or _tkinter wasn't built or idlelib was deleted. import_module('threading') # imported by idlelib.PyShell, imports _thread tk = import_module('Tkinter') # imports _tkinter idletest = import_module('idlelib.idle_test') -# If buildbot improperly sets gui resource (#18365, #18441), remove it -# so requires('gui') tests are skipped while non-gui tests still run. -# If there is a problem with Macs, see #18441, msg 193805 -if use_resources and 'gui' in use_resources: - try: - root = tk.Tk() - root.destroy() - del root - except tk.TclError: - while 'gui' in use_resources: - use_resources.remove('gui') - # Without test_main present, regrtest.runtest_inner (line1219) calls # unittest.TestLoader().loadTestsFromModule(this_module) which calls # load_tests() if it finds it. (Unittest.main does the same.) diff -r 0f6bdc2b0e38 -r 5f75eadecff1 Lib/test/test_support.py --- a/Lib/test/test_support.py Tue Apr 29 16:11:18 2014 +0100 +++ b/Lib/test/test_support.py Fri May 02 10:33:49 2014 -0500 @@ -270,12 +270,16 @@ # is exited) but there is a .pyo file. unlink(os.path.join(dirname, modname + os.extsep + 'pyo')) -# On some platforms, should not run gui test even if it is allowed -# in `use_resources'. -if sys.platform.startswith('win'): - import ctypes - import ctypes.wintypes - def _is_gui_available(): +# Check whether a gui is actually available +def _is_gui_available(): + if hasattr(_is_gui_available, 'result'): + return _is_gui_available.result + reason = None + if sys.platform.startswith('win'): + # if Python is running as a service (such as the buildbot service), + # gui interaction may be disallowed + import ctypes + import ctypes.wintypes UOI_FLAGS = 1 WSF_VISIBLE = 0x0001 class USEROBJECTFLAGS(ctypes.Structure): @@ -295,10 +299,49 @@ ctypes.byref(needed)) if not res: raise ctypes.WinError() - return bool(uof.dwFlags & WSF_VISIBLE) -else: - def _is_gui_available(): - return True + if not bool(uof.dwFlags & WSF_VISIBLE): + reason = "gui not available (WSF_VISIBLE flag not set)" + elif sys.platform == 'darwin': + # The Aqua Tk implementations on OS X can abort the process if + # being called in an environment where a window server connection + # cannot be made, for instance when invoked by a buildbot or ssh + # process not running under the same user id as the current console + # user. To avoid that, raise an exception if the window manager + # connection is not available. + from ctypes import cdll, c_int, pointer, Structure + from ctypes.util import find_library + + app_services = cdll.LoadLibrary(find_library("ApplicationServices")) + + if app_services.CGMainDisplayID() == 0: + reason = "gui tests cannot run without OS X window manager" + else: + class ProcessSerialNumber(Structure): + _fields_ = [("highLongOfPSN", c_int), + ("lowLongOfPSN", c_int)] + psn = ProcessSerialNumber() + psn_p = pointer(psn) + if ( (app_services.GetCurrentProcess(psn_p) < 0) or + (app_services.SetFrontProcess(psn_p) < 0) ): + reason = "cannot run without OS X gui process" + + # check on every platform whether tkinter can actually do anything + if not reason: + try: + from Tkinter import Tk + root = Tk() + root.destroy() + except Exception as e: + err_string = str(e) + if len(err_string) > 50: + err_string = err_string[:50] + ' [...]' + reason = 'Tk unavailable due to {}: {}'.format(type(e).__name__, + err_string) + + _is_gui_available.reason = reason + _is_gui_available.result = not reason + + return _is_gui_available.result def is_resource_enabled(resource): """Test whether a resource is enabled. Known resources are set by @@ -311,7 +354,7 @@ If the caller's module is __main__ then automatically return True. The possibility of False being returned occurs when regrtest.py is executing.""" if resource == 'gui' and not _is_gui_available(): - raise unittest.SkipTest("Cannot use the 'gui' resource") + raise ResourceDenied(_is_gui_available.reason) # see if the caller's module is __main__ - if so, treat as if # the resource was set if sys._getframe(1).f_globals.get("__name__") == "__main__": @@ -1213,7 +1256,7 @@ def requires_resource(resource): if resource == 'gui' and not _is_gui_available(): - return unittest.skip("resource 'gui' is not available") + return unittest.skip(_is_gui_available.reason) if is_resource_enabled(resource): return _id else: diff -r 0f6bdc2b0e38 -r 5f75eadecff1 Lib/test/test_tk.py --- a/Lib/test/test_tk.py Tue Apr 29 16:11:18 2014 +0100 +++ b/Lib/test/test_tk.py Fri May 02 10:33:49 2014 -0500 @@ -1,8 +1,9 @@ import os from test import test_support -# Skip test if _tkinter wasn't built. +# Skip test if _tkinter wasn't built or gui resource is not available. test_support.import_module('_tkinter') +test_support.requires('gui') this_dir = os.path.dirname(os.path.abspath(__file__)) lib_tk_test = os.path.abspath(os.path.join(this_dir, os.path.pardir, @@ -11,9 +12,6 @@ with test_support.DirsOnSysPath(lib_tk_test): import runtktests -# Skip test if tk cannot be initialized. -runtktests.check_tk_availability() - def test_main(enable_gui=False): if enable_gui: if test_support.use_resources is None: diff -r 0f6bdc2b0e38 -r 5f75eadecff1 Lib/test/test_ttk_guionly.py --- a/Lib/test/test_ttk_guionly.py Tue Apr 29 16:11:18 2014 +0100 +++ b/Lib/test/test_ttk_guionly.py Fri May 02 10:33:49 2014 -0500 @@ -2,8 +2,9 @@ import unittest from test import test_support -# Skip this test if _tkinter wasn't built. +# Skip this test if _tkinter wasn't built or gui resource is not available. test_support.import_module('_tkinter') +test_support.requires('gui') this_dir = os.path.dirname(os.path.abspath(__file__)) lib_tk_test = os.path.abspath(os.path.join(this_dir, os.path.pardir, @@ -12,9 +13,6 @@ with test_support.DirsOnSysPath(lib_tk_test): import runtktests -# Skip test if tk cannot be initialized. -runtktests.check_tk_availability() - import ttk from _tkinter import TclError diff -r 0f6bdc2b0e38 -r 5f75eadecff1 Misc/NEWS --- a/Misc/NEWS Tue Apr 29 16:11:18 2014 +0100 +++ b/Misc/NEWS Fri May 02 10:33:49 2014 -0500 @@ -329,6 +329,10 @@ Tests ----- +- Issue #18604: Consolidated checks for GUI availability. All platforms now + at least check whether Tk can be instantiated when the GUI resource is + requested. + - Issue #20946: Correct alignment assumptions of some ctypes tests. - Issue #20743: Fix a reference leak in test_tcl. /zachary.ware@gmail.com