diff -r 2344e8b7a8aa Doc/library/test.rst --- a/Doc/library/test.rst Sun Jun 21 17:12:16 2015 +0300 +++ b/Doc/library/test.rst Sun Jun 21 18:00:32 2015 +0200 @@ -580,6 +580,43 @@ .. versionadded:: 3.5 +.. function:: check__all__(test_instance, module, name_of_module, expected=None, blacklist=None) + + Assert that *module*'s ``__all__`` variable contains all documented names. + + *name_of_module* must be either a string or iterable of strings. One case for + the latter is when module imports names from its C backend (e.g. ``csv``, + ``_csv``). + + *expected* can be a initial set of module names, that wouldn't otherwise be + automatically detected as "documented names" (like objects without proper + ``__module__`` attribute). + + *blacklist* can be a set of names that must not be treated as part of + documented API even though their names indicate otherwise. + + Example use:: + + import unittest + from test import support + import foo + + class MiscTestCase(unittest.TestCase): + def test__all__(self): + support.check__all__(self, foo, 'foo') + + Using *expected* and *blacklist*:: + + class MiscTestCase(unittest.TestCase): + def test__all__(self): + expected = {'BAR_CONST', 'FOO_CONST'} + blacklist = {'baz'} # Undocumented name. + support.check__all__(self, foo, 'foo', expected=expected, + blacklist=blacklist) + + .. versionadded:: 3.5 + + The :mod:`test.support` module defines the following classes: .. class:: TransientResource(exc, **kwargs) diff -r 2344e8b7a8aa Lib/test/support/__init__.py --- a/Lib/test/support/__init__.py Sun Jun 21 17:12:16 2015 +0300 +++ b/Lib/test/support/__init__.py Sun Jun 21 18:00:32 2015 +0200 @@ -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,50 @@ return missing_items +def check__all__(test_instance, module, name_of_module, expected=None, + blacklist=None): + """Assert that `module`'s __all__ variable contains all documented names. + + name_of_module must be either a string or iterable of strings. One case for + the latter is when module imports names from its C backend (e.g. ``csv``, + ``_csv``). + + expected can be a initial set of module names, that wouldn't otherwise be + automatically detected as "documented names" (like objects without proper + __module__ attribute). + + blacklist can be a set of names that must not be treated as part of + documented API even though their names indicate otherwise. + + Usage: + import unittest + from test import support + import foo + + class MiscTestCase(unittest.TestCase): + def test__all__(self): + support.check__all__(self, foo, 'foo') + + """ + if isinstance(name_of_module, str): + name_of_module = (name_of_module, ) + + if expected is None: + expected = set() + + if blacklist is None: + blacklist = set() + + for name in dir(module): + if name.startswith('_') or name in blacklist: + continue + module_object = getattr(module, name) + if isinstance(module_object, types.ModuleType): + continue + if getattr(module_object, '__module__', None) in name_of_module: + expected.add(name) + test_instance.assertCountEqual(module.__all__, expected) + class SuppressCrashReport: """Try to prevent a crash report from popping up. diff -r 2344e8b7a8aa Lib/test/test_support.py --- a/Lib/test/test_support.py Sun Jun 21 17:12:16 2015 +0300 +++ b/Lib/test/test_support.py Sun Jun 21 18:00:32 2015 +0200 @@ -312,6 +312,21 @@ self.OtherClass, self.RefClass, ignore=ignore) self.assertEqual(set(), missing_items) + def test_check__all__(self): + expected = {'TextTestResult', 'installHandler'} + blacklist = {'load_tests', "TestProgram", "BaseTestSuite"} + support.check__all__(self, + unittest, + ("unittest", "unittest.result", "unittest.case", + "unittest.suite", "unittest.loader", + "unittest.main", "unittest.runner", + "unittest.signals"), + expected=expected, + blacklist=blacklist) + + self.assertRaises(AssertionError, support.check__all__, self, unittest, + "unittest") + # XXX -follows a list of untested API # make_legacy_pyc # is_resource_enabled