diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -662,20 +662,6 @@ print(count(len(skipped), "test"), "skipped:") printlist(skipped) - e = _ExpectedSkips() - plat = sys.platform - if e.isvalid(): - surprise = set(skipped) - e.getexpected() - set(resource_denieds) - if surprise: - print(count(len(surprise), "skip"), \ - "unexpected on", plat + ":") - printlist(surprise) - else: - print("Those skips are all expected on", plat + ".") - else: - print("Ask someone to teach regrtest.py about which tests are") - print("expected to get skipped on", plat + ".") - if verbose2 and bad: print("Re-running failed tests in verbose mode") for test in bad: @@ -1211,293 +1197,6 @@ print(fill(' '.join(str(elt) for elt in sorted(x)), width, initial_indent=blanks, subsequent_indent=blanks)) -# Map sys.platform to a string containing the basenames of tests -# expected to be skipped on that platform. -# -# Special cases: -# test_pep277 -# The _ExpectedSkips constructor adds this to the set of expected -# skips if not os.path.supports_unicode_filenames. -# test_timeout -# Controlled by test_timeout.skip_expected. Requires the network -# resource and a socket module. -# -# Tests that are expected to be skipped everywhere except on one platform -# are also handled separately. - -_expectations = { - 'win32': - """ - test__locale - test_crypt - test_curses - test_dbm - test_fcntl - test_fork1 - test_epoll - test_dbm_gnu - test_dbm_ndbm - test_grp - test_ioctl - test_largefile - test_kqueue - test_openpty - test_ossaudiodev - test_pipes - test_poll - test_posix - test_pty - test_pwd - test_resource - test_signal - test_syslog - test_threadsignals - test_wait3 - test_wait4 - """, - 'linux2': - """ - test_curses - test_largefile - test_kqueue - test_ossaudiodev - """, - 'unixware7': - """ - test_epoll - test_largefile - test_kqueue - test_minidom - test_openpty - test_pyexpat - test_sax - test_sundry - """, - 'openunix8': - """ - test_epoll - test_largefile - test_kqueue - test_minidom - test_openpty - test_pyexpat - test_sax - test_sundry - """, - 'sco_sv3': - """ - test_asynchat - test_fork1 - test_epoll - test_gettext - test_largefile - test_locale - test_kqueue - test_minidom - test_openpty - test_pyexpat - test_queue - test_sax - test_sundry - test_thread - test_threaded_import - test_threadedtempfile - test_threading - """, - 'darwin': - """ - test__locale - test_curses - test_epoll - test_dbm_gnu - test_gdb - test_largefile - test_locale - test_minidom - test_ossaudiodev - test_poll - """, - 'sunos5': - """ - test_curses - test_dbm - test_epoll - test_kqueue - test_dbm_gnu - test_gzip - test_openpty - test_zipfile - test_zlib - """, - 'hp-ux11': - """ - test_curses - test_epoll - test_dbm_gnu - test_gzip - test_largefile - test_locale - test_kqueue - test_minidom - test_openpty - test_pyexpat - test_sax - test_zipfile - test_zlib - """, - 'cygwin': - """ - test_curses - test_dbm - test_epoll - test_ioctl - test_kqueue - test_largefile - test_locale - test_ossaudiodev - test_socketserver - """, - 'os2emx': - """ - test_audioop - test_curses - test_epoll - test_kqueue - test_largefile - test_mmap - test_openpty - test_ossaudiodev - test_pty - test_resource - test_signal - """, - 'freebsd4': - """ - test_epoll - test_dbm_gnu - test_locale - test_ossaudiodev - test_pep277 - test_pty - test_socketserver - test_tcl - test_tk - test_ttk_guionly - test_ttk_textonly - test_timeout - test_urllibnet - test_multiprocessing - """, - 'aix5': - """ - test_bz2 - test_epoll - test_dbm_gnu - test_gzip - test_kqueue - test_ossaudiodev - test_tcl - test_tk - test_ttk_guionly - test_ttk_textonly - test_zipimport - test_zlib - """, - 'openbsd3': - """ - test_ctypes - test_epoll - test_dbm_gnu - test_locale - test_normalization - test_ossaudiodev - test_pep277 - test_tcl - test_tk - test_ttk_guionly - test_ttk_textonly - test_multiprocessing - """, - 'netbsd3': - """ - test_ctypes - test_curses - test_epoll - test_dbm_gnu - test_locale - test_ossaudiodev - test_pep277 - test_tcl - test_tk - test_ttk_guionly - test_ttk_textonly - test_multiprocessing - """, -} -_expectations['freebsd5'] = _expectations['freebsd4'] -_expectations['freebsd6'] = _expectations['freebsd4'] -_expectations['freebsd7'] = _expectations['freebsd4'] -_expectations['freebsd8'] = _expectations['freebsd4'] - -class _ExpectedSkips: - def __init__(self): - import os.path - from test import test_timeout - - self.valid = False - if sys.platform in _expectations: - s = _expectations[sys.platform] - self.expected = set(s.split()) - - # These are broken tests, for now skipped on every platform. - # XXX Fix these! - self.expected.add('test_nis') - - # expected to be skipped on every platform, even Linux - if not os.path.supports_unicode_filenames: - self.expected.add('test_pep277') - - # doctest, profile and cProfile tests fail when the codec for the - # fs encoding isn't built in because PyUnicode_Decode() adds two - # calls into Python. - encs = ("utf-8", "latin-1", "ascii", "mbcs", "utf-16", "utf-32") - if sys.getfilesystemencoding().lower() not in encs: - self.expected.add('test_profile') - self.expected.add('test_cProfile') - self.expected.add('test_doctest') - - if test_timeout.skip_expected: - self.expected.add('test_timeout') - - if sys.platform != "win32": - # test_sqlite is only reliable on Windows where the library - # is distributed with Python - WIN_ONLY = {"test_unicode_file", "test_winreg", - "test_winsound", "test_startfile", - "test_sqlite"} - self.expected |= WIN_ONLY - - if sys.platform != 'sunos5': - self.expected.add('test_nis') - - if support.python_is_optimized(): - self.expected.add("test_gdb") - - self.valid = True - - def isvalid(self): - "Return true iff _ExpectedSkips knows about the current platform." - return self.valid - - def getexpected(self): - """Return set of test names we expect to skip on current platform. - - self.isvalid() must be true. - """ - - assert self.isvalid() - return self.expected - def _make_temp_dir_for_build(TEMPDIR): # When tests are run from the Python build directory, it is best practice # to keep the test files in a subfolder. It eases the cleanup of leftover diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -75,17 +75,53 @@ yield -def import_module(name, deprecated=False): +def import_module(name, deprecated=False, *, optional=[], required_on=[]): """Import and return the module to be tested, raising SkipTest if it is not available. If deprecated is True, any module or package deprecation messages - will be suppressed.""" + will be suppressed. + + If sys.platform or os.name is listed in required_on then the ImportError + is propagated instead of SkipTest. The opposite is true for 'optional'. + Use of 'optional' is always preferred as it is better to have to actively + list a platform a test is expected to be skipped on, i.e., whitelist vs. + blacklist. + + Known sys.platform values are: + + * win32 + * linux2 + * unixware7 + * openunix8 + * sco_sv3 + * darwin + * sunos5 + * hp-ux11 + * cygwin + * os2emx + * freebsd4 + * freebsd5 + * freebsd6 + * freebsd7 + * freebsd8 + * aix5 + * openbsd3 + * netbsd3 + + """ with _ignore_deprecated_imports(deprecated): try: return importlib.import_module(name) - except ImportError as msg: - raise unittest.SkipTest(str(msg)) + except ImportError as import_exc: + msg = '{0!r} not available'.format(name) + if required_on: + if sys.platform in required_on or os.name in required_on: + raise + elif optional: + if sys.platform not in optional and os.name not in optional: + raise + raise unittest.SkipTest(msg) from import_exc def _save_and_remove_module(name, orig_modules): diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py --- a/Lib/test/test_cprofile.py +++ b/Lib/test/test_cprofile.py @@ -31,6 +31,12 @@ def test_main(): + import _codecs + codec_name = sys.getfilesystemencoding().lower().replace('-', '_') + fxn_name = codec_name + '_decode' + if not hasattr(_codecs, fxn_name): + msg = 'FS encoding needs to be from _codecs to prevent false-negative' + raise unittest.SkipTest(msg) run_unittest(CProfileTest) def main(): diff --git a/Lib/test/test_crypt.py b/Lib/test/test_crypt.py --- a/Lib/test/test_crypt.py +++ b/Lib/test/test_crypt.py @@ -1,7 +1,7 @@ from test import support import unittest -crypt = support.import_module('crypt') +crypt = support.import_module('crypt', optional=['win32']) class CryptTestCase(unittest.TestCase): diff --git a/Lib/test/test_ctypes.py b/Lib/test/test_ctypes.py --- a/Lib/test/test_ctypes.py +++ b/Lib/test/test_ctypes.py @@ -3,7 +3,7 @@ from test.support import run_unittest, import_module # Skip tests if _ctypes module was not built. -import_module('_ctypes') +import_module('_ctypes', optional=['openbsd3', 'netbsd3']) import ctypes.test diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -2474,6 +2474,12 @@ ###################################################################### def test_main(): + import _codecs + codec_name = sys.getfilesystemencoding().lower().replace('-', '_') + fxn_name = codec_name + '_decode' + if not hasattr(_codecs, fxn_name): + msg = 'FS encoding needs to be from _codecs to prevent false-negative' + raise unittest.SkipTest(msg) # Check the doctest cases in doctest itself: support.run_doctest(doctest, verbosity=True) # Check the doctest cases defined here: diff --git a/Lib/test/test_fcntl.py b/Lib/test/test_fcntl.py --- a/Lib/test/test_fcntl.py +++ b/Lib/test/test_fcntl.py @@ -10,7 +10,7 @@ from test.support import verbose, TESTFN, unlink, run_unittest, import_module # Skip test if no fnctl module. -fcntl = import_module('fcntl') +fcntl = import_module('fcntl', optional=['win32']) # TODO - Write tests for flock() and lockf(). diff --git a/Lib/test/test_grp.py b/Lib/test/test_grp.py --- a/Lib/test/test_grp.py +++ b/Lib/test/test_grp.py @@ -3,7 +3,8 @@ import unittest from test import support -grp = support.import_module('grp') +grp = support.import_module('grp', optional=['win32']) + class GroupDatabaseTestCase(unittest.TestCase): diff --git a/Lib/test/test_nis.py b/Lib/test/test_nis.py --- a/Lib/test/test_nis.py +++ b/Lib/test/test_nis.py @@ -3,7 +3,7 @@ import sys # Skip test if nis module does not exist. -nis = support.import_module('nis') +nis = support.import_module('nis', optional=['win32']) class NisTests(unittest.TestCase): diff --git a/Lib/test/test_pipes.py b/Lib/test/test_pipes.py --- a/Lib/test/test_pipes.py +++ b/Lib/test/test_pipes.py @@ -1,11 +1,10 @@ -import pipes import os import string import unittest -from test.support import TESTFN, run_unittest, unlink, reap_children +from test.support import (TESTFN, run_unittest, unlink, reap_children, + import_module) -if os.name != 'posix': - raise unittest.SkipTest('pipes module only works on posix') +pipes = import_module('pipes', required_on=['posix']) TESTFN2 = TESTFN + "2" diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -3,7 +3,7 @@ from test import support # Skip these tests if there is no posix module. -posix = support.import_module('posix') +posix = support.import_module('posix', required_on=['posix']) import errno import sys diff --git a/Lib/test/test_profile.py b/Lib/test/test_profile.py --- a/Lib/test/test_profile.py +++ b/Lib/test/test_profile.py @@ -97,6 +97,12 @@ def test_main(): + import _codecs + codec_name = sys.getfilesystemencoding().lower().replace('-', '_') + fxn_name = codec_name + '_decode' + if not hasattr(_codecs, fxn_name): + msg = 'FS encoding needs to be from _codecs to prevent false-negative' + raise unittest.SkipTest(msg) run_unittest(ProfileTest) def main(): diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py --- a/Lib/test/test_pty.py +++ b/Lib/test/test_pty.py @@ -3,6 +3,9 @@ #Skip these tests if either fcntl or termios is not available fcntl = import_module('fcntl') import_module('termios') +pty = import_module('pty', + optional=['win32', 'os2emx', 'freebsd4', 'freebsd5', 'freebsd6', + 'freebsd7', 'freebsd8']) import errno import pty diff --git a/Lib/test/test_pwd.py b/Lib/test/test_pwd.py --- a/Lib/test/test_pwd.py +++ b/Lib/test/test_pwd.py @@ -2,7 +2,7 @@ import unittest from test import support -pwd = support.import_module('pwd') +pwd = support.import_module('pwd', optional=['win32']) class PwdTest(unittest.TestCase): diff --git a/Lib/test/test_resource.py b/Lib/test/test_resource.py --- a/Lib/test/test_resource.py +++ b/Lib/test/test_resource.py @@ -2,7 +2,8 @@ from test import support import time -resource = support.import_module('resource') +resource = support.import_module('resource', optional=['win32']) + # This test is checking a few specific problem spots with the resource module. diff --git a/Lib/test/test_sqlite.py b/Lib/test/test_sqlite.py --- a/Lib/test/test_sqlite.py +++ b/Lib/test/test_sqlite.py @@ -1,7 +1,7 @@ import test.support # Skip test if _sqlite3 module not installed -test.support.import_module('_sqlite3') +test.support.import_module('_sqlite3', required_on=['win32']) import sqlite3 from sqlite3.test import (dbapi, types, userfunctions, diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_support.py @@ -0,0 +1,42 @@ +from test import support +import os +import sys +import unittest + + +class import_module_Tests(unittest.TestCase): + + nonexistent_name = "asdfasdfasdflaksdfasdfasdlfjasdflkjas;lfjsadklf" + + def test_skipping(self): + with self.assertRaises(unittest.SkipTest): + support.import_module(self.nonexistent_name) + + def test_requiring_on(self): + # sys.platform and os.name are both supported. + for require in (sys.platform, os.name): + with self.assertRaises(ImportError): + support.import_module(self.nonexistent_name, + required_on=[require]) + with self.assertRaises(unittest.SkipTest): + support.import_module(self.nonexistent_name, + required_on=['no real platform']) + + def test_optional(self): + for optional in (sys.platform, os.name): + with self.assertRaises(unittest.SkipTest): + support.import_module(self.nonexistent_name, + optional=[optional]) + with self.assertRaises(ImportError): + support.import_module(self.nonexistent_name, + optional=['no real platform']) + + +def test_main(): + support.run_unittest( + import_module_Tests + ) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_syslog.py b/Lib/test/test_syslog.py --- a/Lib/test/test_syslog.py +++ b/Lib/test/test_syslog.py @@ -1,6 +1,7 @@ from test import support -syslog = support.import_module("syslog") #skip if not supported +syslog = support.import_module("syslog", optional=['win32']) + import unittest # XXX(nnorwitz): This test sucks. I don't know of a platform independent way diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -8,7 +8,7 @@ from platform import machine # Do this first so test will be skipped if module doesn't exist -support.import_module('winreg') +support.import_module('winreg', required_on=['win32']) # Now import everything from winreg import * diff --git a/Lib/test/test_winsound.py b/Lib/test/test_winsound.py --- a/Lib/test/test_winsound.py +++ b/Lib/test/test_winsound.py @@ -7,7 +7,7 @@ import os import subprocess -winsound = support.import_module('winsound') +winsound = support.import_module('winsound', required_on=['win32']) ctypes = support.import_module('ctypes') import winreg