summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/support/__init__.py67
-rw-r--r--Lib/test/test_idle.py14
-rw-r--r--Lib/test/test_tk.py3
-rw-r--r--Lib/test/test_ttk_guionly.py3
-rw-r--r--Lib/tkinter/test/support.py46
-rw-r--r--Misc/NEWS4
6 files changed, 64 insertions, 73 deletions
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 9857f9d..d26281a 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -378,12 +378,16 @@ def forget(modname):
unlink(importlib.util.cache_from_source(source, debug_override=True))
unlink(importlib.util.cache_from_source(source, debug_override=False))
-# 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):
@@ -403,10 +407,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
@@ -421,7 +464,7 @@ def requires(resource, msg=None):
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__":
@@ -1589,7 +1632,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:
diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py
index 7770ee5..2eb0e6e 100644
--- a/Lib/test/test_idle.py
+++ b/Lib/test/test_idle.py
@@ -1,24 +1,12 @@
import unittest
from test import support
-from test.support import import_module, use_resources
+from test.support import import_module
# Skip test if _thread or _tkinter wasn't built or idlelib was deleted.
import_module('threading') # imported by 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 --git a/Lib/test/test_tk.py b/Lib/test/test_tk.py
index 7551a7f..589f66d 100644
--- a/Lib/test/test_tk.py
+++ b/Lib/test/test_tk.py
@@ -6,8 +6,7 @@ support.import_module('_tkinter')
support.import_fresh_module('tkinter')
# Skip test if tk cannot be initialized.
-from tkinter.test.support import check_tk_availability
-check_tk_availability()
+support.requires('gui')
from tkinter.test import runtktests
diff --git a/Lib/test/test_ttk_guionly.py b/Lib/test/test_ttk_guionly.py
index 3a3459b..502b067 100644
--- a/Lib/test/test_ttk_guionly.py
+++ b/Lib/test/test_ttk_guionly.py
@@ -9,8 +9,7 @@ support.import_module('_tkinter')
support.import_fresh_module('tkinter')
# Skip test if tk cannot be initialized.
-from tkinter.test.support import check_tk_availability
-check_tk_availability()
+support.requires('gui')
from _tkinter import TclError
from tkinter import ttk
diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py
index fcd9ffc..7ae0cbb 100644
--- a/Lib/tkinter/test/support.py
+++ b/Lib/tkinter/test/support.py
@@ -1,52 +1,10 @@
import sys
import tkinter
import unittest
-
-_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
+from test.support import requires
def get_tk_root():
- check_tk_availability() # raise exception if tk unavailable
+ requires('gui') # raise exception if tk unavailable
try:
root = tkinter._default_root
except AttributeError:
diff --git a/Misc/NEWS b/Misc/NEWS
index 5d52ce7..9034371 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -259,6 +259,10 @@ Documentation
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 #21275: Fix a socket test on KFreeBSD.
- Issue #21223: Pass test_site/test_startup_imports when some of the extensions