Index: Lib/warnings.py =================================================================== --- Lib/warnings.py (revision 54927) +++ Lib/warnings.py (working copy) @@ -30,36 +30,26 @@ if category is None: category = UserWarning assert issubclass(category, Warning) + # Get context information try: caller = sys._getframe(stacklevel) except ValueError: - globals = sys.__dict__ + # This should only happen if given an inappropriately high + # stacklevel. It can also happen if called from C during + # startup/shutdown, when the python stack is empty. + module_globals = sys.__dict__ lineno = 1 + filename = "" else: - globals = caller.f_globals + module_globals = caller.f_globals lineno = caller.f_lineno - if '__name__' in globals: - module = globals['__name__'] - else: - module = "" - filename = globals.get('__file__') - if filename: - fnl = filename.lower() - if fnl.endswith((".pyc", ".pyo")): - filename = filename[:-1] - else: - if module == "__main__": - try: - filename = sys.argv[0] - except AttributeError: - # embedded interpreters don't have sys.argv, see bug #839151 - filename = '__main__' - if not filename: - filename = module - registry = globals.setdefault("__warningregistry__", {}) + filename = caller.f_code.co_filename + + module = module_globals.get('__name__', "") + registry = module_globals.setdefault("__warningregistry__", {}) warn_explicit(message, category, filename, lineno, module, registry, - globals) + module_globals) def warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None): Index: Lib/test/test_warnings.py =================================================================== --- Lib/test/test_warnings.py (revision 54927) +++ Lib/test/test_warnings.py (working copy) @@ -1,5 +1,6 @@ import warnings import os +import sys import unittest from test import test_support @@ -77,31 +78,38 @@ self.assertEqual(os.path.basename(w.filename), "warning_tests.py") warning_tests.outer("spam2") self.assertEqual(os.path.basename(w.filename), "warning_tests.py") + warning_tests.string("spam3") + self.assertEqual(w.filename, "") def test_stacklevel(self): # Test stacklevel argument # make sure all messages are different, so the warning won't be skipped with test_support.catch_warning() as w: - warning_tests.inner("spam3", stacklevel=1) + warning_tests.inner("spam4", stacklevel=1) self.assertEqual(os.path.basename(w.filename), "warning_tests.py") - warning_tests.outer("spam4", stacklevel=1) + warning_tests.outer("spam5", stacklevel=1) self.assertEqual(os.path.basename(w.filename), "warning_tests.py") + warning_tests.string("spam6", stacklevel=1) + self.assertEqual(w.filename, "") - warning_tests.inner("spam5", stacklevel=2) + warning_tests.inner("spam7", stacklevel=2) self.assertEqual(os.path.basename(w.filename), "test_warnings.py") - warning_tests.outer("spam6", stacklevel=2) + warning_tests.outer("spam8", stacklevel=2) self.assertEqual(os.path.basename(w.filename), "warning_tests.py") + warning_tests.string("spam9", stacklevel=2) + self.assertEqual(os.path.basename(w.filename), "warning_tests.py") - warning_tests.inner("spam7", stacklevel=9999) - self.assertEqual(os.path.basename(w.filename), "sys") + warning_tests.inner("spam10", stacklevel=9999) + self.assertEqual(w.filename, "") def test_main(verbose=None): - # Obscure hack so that this test passes after reloads or repeated calls - # to test_main (regrtest -R). - if '__warningregistry__' in globals(): - del globals()['__warningregistry__'] - test_support.run_unittest(TestModule) + # Entries in the various '__warningregistry__' objects persist + # across test runs, causing regrtest -R to fail. + # guard_warnings_registry protects against this. + with test_support.guard_warnings_registry(sys, warning_tests, + sys.modules[__name__]): + test_support.run_unittest(TestModule) if __name__ == "__main__": test_main(verbose=True) Index: Lib/test/warning_tests.py =================================================================== --- Lib/test/warning_tests.py (revision 54927) +++ Lib/test/warning_tests.py (working copy) @@ -7,3 +7,6 @@ def inner(message, stacklevel=1): warnings.warn(message, stacklevel=stacklevel) + +def string(message, stacklevel=1): + eval('warnings.warn(message, stacklevel=stacklevel)') Index: Lib/test/test_support.py =================================================================== --- Lib/test/test_support.py (revision 54927) +++ Lib/test/test_support.py (working copy) @@ -282,6 +282,21 @@ finally: warnings.filters = original_filters +@contextlib.contextmanager +def guard_warnings_registry(*modules): + """Guard the warning registries from being permanently changed. + + Must be given one or more modules who's registries are to be protected. + """ + assert modules + backups = [getattr(mod, "__warningregistry__", {}).copy() + for mod in modules] + try: + yield + finally: + for mod, backup in zip(modules, backups): + mod.__warningregistry__ = backup + class WarningMessage(object): "Holds the result of the latest showwarning() call" def __init__(self):