]> granicus.if.org Git - python/commitdiff
Issue #18604: Consolidated checks for GUI availability.
authorZachary Ware <zachary.ware@gmail.com>
Fri, 2 May 2014 15:33:49 +0000 (10:33 -0500)
committerZachary Ware <zachary.ware@gmail.com>
Fri, 2 May 2014 15:33:49 +0000 (10:33 -0500)
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).

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

index 95e1728861938980fdd816ac1075ecdd25aba949..aff6441b200551ea7fb0665d28751761aab2c0e3 100644 (file)
@@ -14,49 +14,6 @@ import test.test_support
 
 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 @@ def get_tests_modules(basepath=this_dir_path, gui=True, packages=None):
     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'
 
index 495b4160f2c0291fbc5f95879280fd28bcf820f8..66dd8af24f77cfbc650026416a8bb06efa4a7774 100644 (file)
@@ -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.)
index 44b422412adab13c4d7af4aad35a96cba08bceb0..31b311915f98bcf30a8ee91db1f87d260b29a81f 100644 (file)
@@ -270,12 +270,16 @@ def forget(modname):
         # 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 @@ if sys.platform.startswith('win'):
             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 @@ def requires(resource, msg=None):
     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 _id(obj):
 
 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:
index 8625db27c47c19112faaab7429c3e2430341a591..56eef47dfa83050108e7591bccdefa167c04678a 100644 (file)
@@ -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 @@ lib_tk_test = os.path.abspath(os.path.join(this_dir, os.path.pardir,
 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:
index e0368be6a080a27bdcbaa814a93bcec132ac6ac8..47ddefb11c8fca74ccffb34c97ebf4cb5ff38c72 100644 (file)
@@ -2,8 +2,9 @@ import os
 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 @@ lib_tk_test = os.path.abspath(os.path.join(this_dir, os.path.pardir,
 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
 
index ab71e0173ee00b95c4cd13a1f9af362b955164d9..e71c04965b5a546df872697e0f07f742f3cddd92 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -329,6 +329,10 @@ IDLE
 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.