[Python-checkins] cpython (merge 3.4 -> default): Issue #4180: The warnings registries are now reset when the filters are

antoine.pitrou python-checkins at python.org
Thu Sep 18 02:44:40 CEST 2014


http://hg.python.org/cpython/rev/4bc60eb68d3e
changeset: 92459:4bc60eb68d3e
parent: 92457:04147b0172d7
parent: 92458:8adb2c6e0803
user: Antoine Pitrou <solipsis at pitrou.net>
date: Thu Sep 18 02:42:05 2014 +0200
summary:
 Issue #4180: The warnings registries are now reset when the filters are modified.
files:
 Lib/test/test_warnings.py | 49 +++++++++++++++++++++++++-
 Lib/warnings.py | 17 ++++++++-
 Misc/NEWS | 3 +
 Python/_warnings.c | 41 +++++++++++++++++++---
 4 files changed, 101 insertions(+), 9 deletions(-)
diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py
--- a/Lib/test/test_warnings.py
+++ b/Lib/test/test_warnings.py
@@ -92,6 +92,16 @@
 self.assertRaises(UserWarning, self.module.warn,
 "FilterTests.test_error")
 
+ def test_error_after_default(self):
+ with original_warnings.catch_warnings(module=self.module) as w:
+ self.module.resetwarnings()
+ message = "FilterTests.test_ignore_after_default"
+ def f():
+ self.module.warn(message, UserWarning)
+ f()
+ self.module.filterwarnings("error", category=UserWarning)
+ self.assertRaises(UserWarning, f)
+
 def test_ignore(self):
 with original_warnings.catch_warnings(record=True,
 module=self.module) as w:
@@ -100,6 +110,19 @@
 self.module.warn("FilterTests.test_ignore", UserWarning)
 self.assertEqual(len(w), 0)
 
+ def test_ignore_after_default(self):
+ with original_warnings.catch_warnings(record=True,
+ module=self.module) as w:
+ self.module.resetwarnings()
+ message = "FilterTests.test_ignore_after_default"
+ def f():
+ self.module.warn(message, UserWarning)
+ f()
+ self.module.filterwarnings("ignore", category=UserWarning)
+ f()
+ f()
+ self.assertEqual(len(w), 1)
+
 def test_always(self):
 with original_warnings.catch_warnings(record=True,
 module=self.module) as w:
@@ -111,6 +134,26 @@
 self.module.warn(message, UserWarning)
 self.assertTrue(w[-1].message, message)
 
+ def test_always_after_default(self):
+ with original_warnings.catch_warnings(record=True,
+ module=self.module) as w:
+ self.module.resetwarnings()
+ message = "FilterTests.test_always_after_ignore"
+ def f():
+ self.module.warn(message, UserWarning)
+ f()
+ self.assertEqual(len(w), 1)
+ self.assertEqual(w[-1].message.args[0], message)
+ f()
+ self.assertEqual(len(w), 1)
+ self.module.filterwarnings("always", category=UserWarning)
+ f()
+ self.assertEqual(len(w), 2)
+ self.assertEqual(w[-1].message.args[0], message)
+ f()
+ self.assertEqual(len(w), 3)
+ self.assertEqual(w[-1].message.args[0], message)
+
 def test_default(self):
 with original_warnings.catch_warnings(record=True,
 module=self.module) as w:
@@ -541,7 +584,9 @@
 registry=registry)
 self.assertEqual(w[-1].message, message)
 self.assertEqual(len(w), 1)
- self.assertEqual(len(registry), 1)
+ # One actual registry key plus the "version" key
+ self.assertEqual(len(registry), 2)
+ self.assertIn("version", registry)
 del w[:]
 # Test removal.
 del self.module.defaultaction
@@ -551,7 +596,7 @@
 registry=registry)
 self.assertEqual(w[-1].message, message)
 self.assertEqual(len(w), 1)
- self.assertEqual(len(registry), 1)
+ self.assertEqual(len(registry), 2)
 del w[:]
 # Test setting.
 self.module.defaultaction = "ignore"
diff --git a/Lib/warnings.py b/Lib/warnings.py
--- a/Lib/warnings.py
+++ b/Lib/warnings.py
@@ -53,6 +53,7 @@
 filters.append(item)
 else:
 filters.insert(0, item)
+ _filters_mutated()
 
 def simplefilter(action, category=Warning, lineno=0, append=False):
 """Insert a simple entry into the list of warnings filters (at the front).
@@ -73,10 +74,12 @@
 filters.append(item)
 else:
 filters.insert(0, item)
+ _filters_mutated()
 
 def resetwarnings():
 """Clear the list of warning filters, so that no filters are active."""
 filters[:] = []
+ _filters_mutated()
 
 class _OptionError(Exception):
 """Exception used by option processing helpers."""
@@ -206,6 +209,9 @@
 module = module[:-3] # XXX What about leading pathname?
 if registry is None:
 registry = {}
+ if registry.get('version', 0) != _filters_version:
+ registry.clear()
+ registry['version'] = _filters_version
 if isinstance(message, Warning):
 text = str(message)
 category = message.__class__
@@ -331,6 +337,7 @@
 self._entered = True
 self._filters = self._module.filters
 self._module.filters = self._filters[:]
+ self._module._filters_mutated()
 self._showwarning = self._module.showwarning
 if self._record:
 log = []
@@ -345,6 +352,7 @@
 if not self._entered:
 raise RuntimeError("Cannot exit %r without entering first" % self)
 self._module.filters = self._filters
+ self._module._filters_mutated()
 self._module.showwarning = self._showwarning
 
 
@@ -359,15 +367,22 @@
 _warnings_defaults = False
 try:
 from _warnings import (filters, _defaultaction, _onceregistry,
- warn, warn_explicit)
+ warn, warn_explicit, _filters_mutated)
 defaultaction = _defaultaction
 onceregistry = _onceregistry
 _warnings_defaults = True
+
 except ImportError:
 filters = []
 defaultaction = "default"
 onceregistry = {}
 
+ _filters_version = 1
+
+ def _filters_mutated():
+ global _filters_version
+ _filters_version += 1
+
 
 # Module initialization
 _processoptions(sys.warnoptions)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -132,6 +132,9 @@
 Library
 -------
 
+- Issue #4180: The warnings registries are now reset when the filters
+ are modified.
+
 - Issue #22419: Limit the length of incoming HTTP request in wsgiref server to
 65536 bytes and send a 414 error code for higher lengths. Patch contributed
 by Devin Cook.
diff --git a/Python/_warnings.c b/Python/_warnings.c
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -12,6 +12,7 @@
 static PyObject *_filters; /* List */
 static PyObject *_once_registry; /* Dict */
 static PyObject *_default_action; /* String */
+static long _filters_version;
 
 _Py_IDENTIFIER(argv);
 _Py_IDENTIFIER(stderr);
@@ -178,16 +179,33 @@
 static int
 already_warned(PyObject *registry, PyObject *key, int should_set)
 {
- PyObject *already_warned;
+ PyObject *version_obj, *already_warned;
+ _Py_IDENTIFIER(version);
 
 if (key == NULL)
 return -1;
 
- already_warned = PyDict_GetItem(registry, key);
- if (already_warned != NULL) {
- int rc = PyObject_IsTrue(already_warned);
- if (rc != 0)
- return rc;
+ version_obj = _PyDict_GetItemId(registry, &PyId_version);
+ if (version_obj == NULL
+ || !PyLong_CheckExact(version_obj)
+ || PyLong_AsLong(version_obj) != _filters_version) {
+ PyDict_Clear(registry);
+ version_obj = PyLong_FromLong(_filters_version);
+ if (version_obj == NULL)
+ return -1;
+ if (_PyDict_SetItemId(registry, &PyId_version, version_obj) < 0) {
+ Py_DECREF(version_obj);
+ return -1;
+ }
+ Py_DECREF(version_obj);
+ }
+ else {
+ already_warned = PyDict_GetItem(registry, key);
+ if (already_warned != NULL) {
+ int rc = PyObject_IsTrue(already_warned);
+ if (rc != 0)
+ return rc;
+ }
 }
 
 /* This warning wasn't found in the registry, set it. */
@@ -751,6 +769,13 @@
 registry, NULL);
 }
 
+static PyObject *
+warnings_filters_mutated(PyObject *self, PyObject *args)
+{
+ _filters_version++;
+ Py_RETURN_NONE;
+}
+
 
 /* Function to issue a warning message; may raise an exception. */
 
@@ -918,6 +943,8 @@
 warn_doc},
 {"warn_explicit", (PyCFunction)warnings_warn_explicit,
 METH_VARARGS | METH_KEYWORDS, warn_explicit_doc},
+ {"_filters_mutated", (PyCFunction)warnings_filters_mutated, METH_NOARGS,
+ NULL},
 /* XXX(brett.cannon): add showwarning? */
 /* XXX(brett.cannon): Reasonable to add formatwarning? */
 {NULL, NULL} /* sentinel */
@@ -1070,5 +1097,7 @@
 Py_INCREF(_default_action);
 if (PyModule_AddObject(m, "_defaultaction", _default_action) < 0)
 return NULL;
+
+ _filters_version = 0;
 return m;
 }
-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /