(original) (raw)

changeset: 99132:f8fa7bc837a3 user: Martin Panter vadmium+py@gmail.com date: Sat Nov 14 11:47:00 2015 +0000 files: Doc/library/test.rst Lib/test/support/__init__.py Lib/test/test_gettext.py Lib/test/test_support.py Misc/ACKS description: Issue #23883: Add test.support.check__all__() and test gettext.__all__ Patches by Jacek Kołodziej. diff -r 139c18943d9b -r f8fa7bc837a3 Doc/library/test.rst --- a/Doc/library/test.rst Sat Nov 14 08:54:30 2015 +0000 +++ b/Doc/library/test.rst Sat Nov 14 11:47:00 2015 +0000 @@ -580,6 +580,48 @@ .. versionadded:: 3.5 +.. function:: check__all__(test_case, module, name_of_module=None, extra=(), blacklist=()) + + Assert that the ``__all__`` variable of *module* contains all public names. + + The module's public names (its API) are detected automatically + based on whether they match the public name convention and were defined in + *module*. + + The *name_of_module* argument can specify (as a string or tuple thereof) what + module(s) an API could be defined in in order to be detected as a public + API. One case for this is when *module* imports part of its public API from + other modules, possibly a C backend (like ``csv`` and its ``_csv``). + + The *extra* argument can be a set of names that wouldn't otherwise be automatically + detected as "public", like objects without a proper ``__module__`` + attribute. If provided, it will be added to the automatically detected ones. + + The *blacklist* argument can be a set of names that must not be treated as part of + the public API even though their names indicate otherwise. + + Example use:: + + import bar + import foo + import unittest + from test import support + + class MiscTestCase(unittest.TestCase): + def test__all__(self): + support.check__all__(self, foo) + + class OtherTestCase(unittest.TestCase): + def test__all__(self): + extra = {'BAR_CONST', 'FOO_CONST'} + blacklist = {'baz'} # Undocumented name. + # bar imports part of its API from _bar. + support.check__all__(self, bar, ('bar', '_bar'), + extra=extra, blacklist=blacklist) + + .. versionadded:: 3.6 + + The :mod:`test.support` module defines the following classes: .. class:: TransientResource(exc, **kwargs) diff -r 139c18943d9b -r f8fa7bc837a3 Lib/test/support/__init__.py --- a/Lib/test/support/__init__.py Sat Nov 14 08:54:30 2015 +0000 +++ b/Lib/test/support/__init__.py Sat Nov 14 11:47:00 2015 +0000 @@ -26,6 +26,7 @@ import sysconfig import tempfile import time +import types import unittest import urllib.error import warnings @@ -89,6 +90,7 @@ "bigmemtest", "bigaddrspacetest", "cpython_only", "get_attribute", "requires_IEEE_754", "skip_unless_xattr", "requires_zlib", "anticipate_failure", "load_package_tests", "detect_api_mismatch", + "check__all__", # sys "is_jython", "check_impl_detail", # network @@ -2199,6 +2201,65 @@ return missing_items +def check__all__(test_case, module, name_of_module=None, extra=(), + blacklist=()): + """Assert that the __all__ variable of 'module' contains all public names. + + The module's public names (its API) are detected automatically based on + whether they match the public name convention and were defined in + 'module'. + + The 'name_of_module' argument can specify (as a string or tuple thereof) + what module(s) an API could be defined in in order to be detected as a + public API. One case for this is when 'module' imports part of its public + API from other modules, possibly a C backend (like 'csv' and its '_csv'). + + The 'extra' argument can be a set of names that wouldn't otherwise be + automatically detected as "public", like objects without a proper + '__module__' attriubute. If provided, it will be added to the + automatically detected ones. + + The 'blacklist' argument can be a set of names that must not be treated + as part of the public API even though their names indicate otherwise. + + Usage: + import bar + import foo + import unittest + from test import support + + class MiscTestCase(unittest.TestCase): + def test__all__(self): + support.check__all__(self, foo) + + class OtherTestCase(unittest.TestCase): + def test__all__(self): + extra = {'BAR_CONST', 'FOO_CONST'} + blacklist = {'baz'} # Undocumented name. + # bar imports part of its API from _bar. + support.check__all__(self, bar, ('bar', '_bar'), + extra=extra, blacklist=blacklist) + + """ + + if name_of_module is None: + name_of_module = (module.__name__, ) + elif isinstance(name_of_module, str): + name_of_module = (name_of_module, ) + + expected = set(extra) + + for name in dir(module): + if name.startswith('_') or name in blacklist: + continue + obj = getattr(module, name) + if (getattr(obj, '__module__', None) in name_of_module or + (not hasattr(obj, '__module__') and + not isinstance(obj, types.ModuleType))): + expected.add(name) + test_case.assertCountEqual(module.__all__, expected) + + class SuppressCrashReport: """Try to prevent a crash report from popping up. diff -r 139c18943d9b -r f8fa7bc837a3 Lib/test/test_gettext.py --- a/Lib/test/test_gettext.py Sat Nov 14 08:54:30 2015 +0000 +++ b/Lib/test/test_gettext.py Sat Nov 14 11:47:00 2015 +0000 @@ -440,6 +440,12 @@ self.assertEqual(t.__class__, DummyGNUTranslations) +class MiscTestCase(unittest.TestCase): + def test__all__(self): + blacklist = {'c2py', 'ENOENT'} + support.check__all__(self, gettext, blacklist=blacklist) + + def test_main(): support.run_unittest(__name__) diff -r 139c18943d9b -r f8fa7bc837a3 Lib/test/test_support.py --- a/Lib/test/test_support.py Sat Nov 14 08:54:30 2015 +0000 +++ b/Lib/test/test_support.py Sat Nov 14 11:47:00 2015 +0000 @@ -312,6 +312,28 @@ self.OtherClass, self.RefClass, ignore=ignore) self.assertEqual(set(), missing_items) + def test_check__all__(self): + extra = {'tempdir'} + blacklist = {'template'} + support.check__all__(self, + tempfile, + extra=extra, + blacklist=blacklist) + + extra = {'TextTestResult', 'installHandler'} + blacklist = {'load_tests', "TestProgram", "BaseTestSuite"} + + support.check__all__(self, + unittest, + ("unittest.result", "unittest.case", + "unittest.suite", "unittest.loader", + "unittest.main", "unittest.runner", + "unittest.signals"), + extra=extra, + blacklist=blacklist) + + self.assertRaises(AssertionError, support.check__all__, self, unittest) + # XXX -follows a list of untested API # make_legacy_pyc # is_resource_enabled diff -r 139c18943d9b -r f8fa7bc837a3 Misc/ACKS --- a/Misc/ACKS Sat Nov 14 08:54:30 2015 +0000 +++ b/Misc/ACKS Sat Nov 14 11:47:00 2015 +0000 @@ -765,6 +765,7 @@ Marko Kohtala Vajrasky Kok Guido Kollerie +Jacek Kołodziej Jacek Konieczny Марк Коренберг Arkady Koplyarov /vadmium+py@gmail.com