Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cb2ad80

Browse files
committed
Closes #18604: Merge with 3.4
2 parents 6b7786b + ceced6b commit cb2ad80

6 files changed

Lines changed: 64 additions & 73 deletions

File tree

Lib/test/support/__init__.py

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -378,12 +378,16 @@ def forget(modname):
378378
unlink(importlib.util.cache_from_source(source, debug_override=True))
379379
unlink(importlib.util.cache_from_source(source, debug_override=False))
380380

381-
# On some platforms, should not run gui test even if it is allowed
382-
# in `use_resources'.
383-
if sys.platform.startswith('win'):
384-
import ctypes
385-
import ctypes.wintypes
386-
def _is_gui_available():
381+
# Check whether a gui is actually available
382+
def _is_gui_available():
383+
if hasattr(_is_gui_available, 'result'):
384+
return _is_gui_available.result
385+
reason = None
386+
if sys.platform.startswith('win'):
387+
# if Python is running as a service (such as the buildbot service),
388+
# gui interaction may be disallowed
389+
import ctypes
390+
import ctypes.wintypes
387391
UOI_FLAGS = 1
388392
WSF_VISIBLE = 0x0001
389393
class USEROBJECTFLAGS(ctypes.Structure):
@@ -403,10 +407,49 @@ class USEROBJECTFLAGS(ctypes.Structure):
403407
ctypes.byref(needed))
404408
if not res:
405409
raise ctypes.WinError()
406-
return bool(uof.dwFlags & WSF_VISIBLE)
407-
else:
408-
def _is_gui_available():
409-
return True
410+
if not bool(uof.dwFlags & WSF_VISIBLE):
411+
reason = "gui not available (WSF_VISIBLE flag not set)"
412+
elif sys.platform == 'darwin':
413+
# The Aqua Tk implementations on OS X can abort the process if
414+
# being called in an environment where a window server connection
415+
# cannot be made, for instance when invoked by a buildbot or ssh
416+
# process not running under the same user id as the current console
417+
# user. To avoid that, raise an exception if the window manager
418+
# connection is not available.
419+
from ctypes import cdll, c_int, pointer, Structure
420+
from ctypes.util import find_library
421+
422+
app_services = cdll.LoadLibrary(find_library("ApplicationServices"))
423+
424+
if app_services.CGMainDisplayID() == 0:
425+
reason = "gui tests cannot run without OS X window manager"
426+
else:
427+
class ProcessSerialNumber(Structure):
428+
_fields_ = [("highLongOfPSN", c_int),
429+
("lowLongOfPSN", c_int)]
430+
psn = ProcessSerialNumber()
431+
psn_p = pointer(psn)
432+
if ( (app_services.GetCurrentProcess(psn_p) < 0) or
433+
(app_services.SetFrontProcess(psn_p) < 0) ):
434+
reason = "cannot run without OS X gui process"
435+
436+
# check on every platform whether tkinter can actually do anything
437+
if not reason:
438+
try:
439+
from tkinter import Tk
440+
root = Tk()
441+
root.destroy()
442+
except Exception as e:
443+
err_string = str(e)
444+
if len(err_string) > 50:
445+
err_string = err_string[:50] + ' [...]'
446+
reason = 'Tk unavailable due to {}: {}'.format(type(e).__name__,
447+
err_string)
448+
449+
_is_gui_available.reason = reason
450+
_is_gui_available.result = not reason
451+
452+
return _is_gui_available.result
410453

411454
def is_resource_enabled(resource):
412455
"""Test whether a resource is enabled. Known resources are set by
@@ -421,7 +464,7 @@ def requires(resource, msg=None):
421464
executing.
422465
"""
423466
if resource == 'gui' and not _is_gui_available():
424-
raise unittest.SkipTest("Cannot use the 'gui' resource")
467+
raise ResourceDenied(_is_gui_available.reason)
425468
# see if the caller's module is __main__ - if so, treat as if
426469
# the resource was set
427470
if sys._getframe(1).f_globals.get("__name__") == "__main__":
@@ -1589,7 +1632,7 @@ def _id(obj):
15891632

15901633
def requires_resource(resource):
15911634
if resource == 'gui' and not _is_gui_available():
1592-
return unittest.skip("resource 'gui' is not available")
1635+
return unittest.skip(_is_gui_available.reason)
15931636
if is_resource_enabled(resource):
15941637
return _id
15951638
else:

Lib/test/test_idle.py

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,12 @@
11
import unittest
22
from test import support
3-
from test.support import import_module, use_resources
3+
from test.support import import_module
44

55
# Skip test if _thread or _tkinter wasn't built or idlelib was deleted.
66
import_module('threading') # imported by PyShell, imports _thread
77
tk = import_module('tkinter') # imports _tkinter
88
idletest = import_module('idlelib.idle_test')
99

10-
# If buildbot improperly sets gui resource (#18365, #18441), remove it
11-
# so requires('gui') tests are skipped while non-gui tests still run.
12-
# If there is a problem with Macs, see #18441, msg 193805
13-
if use_resources and 'gui' in use_resources:
14-
try:
15-
root = tk.Tk()
16-
root.destroy()
17-
del root
18-
except tk.TclError:
19-
while 'gui' in use_resources:
20-
use_resources.remove('gui')
21-
2210
# Without test_main present, regrtest.runtest_inner (line1219) calls
2311
# unittest.TestLoader().loadTestsFromModule(this_module) which calls
2412
# load_tests() if it finds it. (Unittest.main does the same.)

Lib/test/test_tk.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
support.import_fresh_module('tkinter')
77

88
# Skip test if tk cannot be initialized.
9-
from tkinter.test.support import check_tk_availability
10-
check_tk_availability()
9+
support.requires('gui')
1110

1211
from tkinter.test import runtktests
1312

Lib/test/test_ttk_guionly.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99
support.import_fresh_module('tkinter')
1010

1111
# Skip test if tk cannot be initialized.
12-
from tkinter.test.support import check_tk_availability
13-
check_tk_availability()
12+
support.requires('gui')
1413

1514
from _tkinter import TclError
1615
from tkinter import ttk

Lib/tkinter/test/support.py

Lines changed: 2 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,10 @@
11
import sys
22
import tkinter
33
import unittest
4-
5-
_tk_unavailable = None
6-
7-
def check_tk_availability():
8-
"""Check that Tk is installed and available."""
9-
global _tk_unavailable
10-
11-
if _tk_unavailable is None:
12-
_tk_unavailable = False
13-
if sys.platform == 'darwin':
14-
# The Aqua Tk implementations on OS X can abort the process if
15-
# being called in an environment where a window server connection
16-
# cannot be made, for instance when invoked by a buildbot or ssh
17-
# process not running under the same user id as the current console
18-
# user. To avoid that, raise an exception if the window manager
19-
# connection is not available.
20-
from ctypes import cdll, c_int, pointer, Structure
21-
from ctypes.util import find_library
22-
23-
app_services = cdll.LoadLibrary(find_library("ApplicationServices"))
24-
25-
if app_services.CGMainDisplayID() == 0:
26-
_tk_unavailable = "cannot run without OS X window manager"
27-
else:
28-
class ProcessSerialNumber(Structure):
29-
_fields_ = [("highLongOfPSN", c_int),
30-
("lowLongOfPSN", c_int)]
31-
psn = ProcessSerialNumber()
32-
psn_p = pointer(psn)
33-
if ( (app_services.GetCurrentProcess(psn_p) < 0) or
34-
(app_services.SetFrontProcess(psn_p) < 0) ):
35-
_tk_unavailable = "cannot run without OS X gui process"
36-
else: # not OS X
37-
import tkinter
38-
try:
39-
tkinter.Button()
40-
except tkinter.TclError as msg:
41-
# assuming tk is not available
42-
_tk_unavailable = "tk not available: %s" % msg
43-
44-
if _tk_unavailable:
45-
raise unittest.SkipTest(_tk_unavailable)
46-
return
4+
from test.support import requires
475

486
def get_tk_root():
49-
check_tk_availability() # raise exception if tk unavailable
7+
requires('gui') # raise exception if tk unavailable
508
try:
519
root = tkinter._default_root
5210
except AttributeError:

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,10 @@ Documentation
383383
Tests
384384
-----
385385

386+
- Issue #18604: Consolidated checks for GUI availability. All platforms now
387+
at least check whether Tk can be instantiated when the GUI resource is
388+
requested.
389+
386390
- Issue #21275: Fix a socket test on KFreeBSD.
387391

388392
- Issue #21223: Pass test_site/test_startup_imports when some of the extensions

0 commit comments

Comments
 (0)