gh-135801: Improve filtering by module in warn_explicit() without module argument (GH-140151)
* Try to match the module name pattern with module names constructed starting from different parent directories of the filename. E.g., for "/path/to/package/module" try to match with "path.to.package.module", "to.package.module", "package.module" and "module". * Ignore trailing "/__init__.py". * Ignore trailing ".pyw" on Windows. * Keep matching with the full filename (without optional ".py" extension) for compatibility. * Only ignore the case of the ".py" extension on Windows.
This commit is contained in:
@@ -487,7 +487,14 @@ Available Functions
|
||||
ignored.
|
||||
|
||||
*module*, if supplied, should be the module name.
|
||||
If no module is passed, the filename with ``.py`` stripped is used.
|
||||
If no module is passed, the module regular expression in
|
||||
:ref:`warnings filter <warning-filter>` will be tested against the module
|
||||
names constructed from the path components starting from all parent
|
||||
directories (with ``/__init__.py``, ``.py`` and, on Windows, ``.pyw``
|
||||
stripped) and against the filename with ``.py`` stripped.
|
||||
For example, when the filename is ``'/path/to/package/module.py'``, it will
|
||||
be tested against ``'path.to.package.module'``, ``'to.package.module'``
|
||||
``'package.module'``, ``'module'``, and ``'/path/to/package/module'``.
|
||||
|
||||
*registry*, if supplied, should be the ``__warningregistry__`` dictionary
|
||||
of the module.
|
||||
@@ -506,6 +513,10 @@ Available Functions
|
||||
.. versionchanged:: 3.6
|
||||
Add the *source* parameter.
|
||||
|
||||
.. versionchanged:: next
|
||||
If no module is passed, test the filter regular expression against
|
||||
module names created from the path, not only the path itself.
|
||||
|
||||
|
||||
.. function:: showwarning(message, category, filename, lineno, file=None, line=None)
|
||||
|
||||
|
||||
@@ -611,6 +611,18 @@ unittest
|
||||
(Contributed by Garry Cairns in :gh:`134567`.)
|
||||
|
||||
|
||||
warnings
|
||||
--------
|
||||
|
||||
* Improve filtering by module in :func:`warnings.warn_explicit` if no *module*
|
||||
argument is passed.
|
||||
It now tests the module regular expression in the warnings filter not only
|
||||
against the filename with ``.py`` stripped, but also against module names
|
||||
constructed starting from different parent directories of the filename
|
||||
(with ``/__init__.py``, ``.py`` and, on Windows, ``.pyw`` stripped).
|
||||
(Contributed by Serhiy Storchaka in :gh:`135801`.)
|
||||
|
||||
|
||||
venv
|
||||
----
|
||||
|
||||
|
||||
@@ -520,20 +520,50 @@ def warn(message, category=None, stacklevel=1, source=None,
|
||||
)
|
||||
|
||||
|
||||
def _match_filename(pattern, filename, *, MS_WINDOWS=(sys.platform == 'win32')):
|
||||
if not filename:
|
||||
return pattern.match('<unknown>') is not None
|
||||
if filename[0] == '<' and filename[-1] == '>':
|
||||
return pattern.match(filename) is not None
|
||||
|
||||
is_py = (filename[-3:].lower() == '.py'
|
||||
if MS_WINDOWS else
|
||||
filename.endswith('.py'))
|
||||
if is_py:
|
||||
filename = filename[:-3]
|
||||
if pattern.match(filename): # for backward compatibility
|
||||
return True
|
||||
if MS_WINDOWS:
|
||||
if not is_py and filename[-4:].lower() == '.pyw':
|
||||
filename = filename[:-4]
|
||||
is_py = True
|
||||
if is_py and filename[-9:].lower() in (r'\__init__', '/__init__'):
|
||||
filename = filename[:-9]
|
||||
filename = filename.replace('\\', '/')
|
||||
else:
|
||||
if is_py and filename.endswith('/__init__'):
|
||||
filename = filename[:-9]
|
||||
filename = filename.replace('/', '.')
|
||||
i = 0
|
||||
while True:
|
||||
if pattern.match(filename, i):
|
||||
return True
|
||||
i = filename.find('.', i) + 1
|
||||
if not i:
|
||||
return False
|
||||
|
||||
|
||||
def warn_explicit(message, category, filename, lineno,
|
||||
module=None, registry=None, module_globals=None,
|
||||
source=None):
|
||||
lineno = int(lineno)
|
||||
if module is None:
|
||||
module = filename or "<unknown>"
|
||||
if module[-3:].lower() == ".py":
|
||||
module = module[:-3] # XXX What about leading pathname?
|
||||
if isinstance(message, Warning):
|
||||
text = str(message)
|
||||
category = message.__class__
|
||||
else:
|
||||
text = message
|
||||
message = category(message)
|
||||
modules = None
|
||||
key = (text, category, lineno)
|
||||
with _wm._lock:
|
||||
if registry is None:
|
||||
@@ -549,9 +579,11 @@ def warn_explicit(message, category, filename, lineno,
|
||||
action, msg, cat, mod, ln = item
|
||||
if ((msg is None or msg.match(text)) and
|
||||
issubclass(category, cat) and
|
||||
(mod is None or mod.match(module)) and
|
||||
(ln == 0 or lineno == ln)):
|
||||
break
|
||||
(ln == 0 or lineno == ln) and
|
||||
(mod is None or (_match_filename(mod, filename)
|
||||
if module is None else
|
||||
mod.match(module)))):
|
||||
break
|
||||
else:
|
||||
action = _wm.defaultaction
|
||||
# Early exit actions
|
||||
|
||||
@@ -13,6 +13,7 @@ import tempfile
|
||||
import textwrap
|
||||
import types
|
||||
import unittest
|
||||
import warnings
|
||||
import weakref
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
@@ -1069,6 +1070,19 @@ class AST_Tests(unittest.TestCase):
|
||||
self.assertIsInstance(tree.body[0].value.values[0], ast.Constant)
|
||||
self.assertIsInstance(tree.body[0].value.values[1], ast.Interpolation)
|
||||
|
||||
def test_filter_syntax_warnings_by_module(self):
|
||||
filename = support.findfile('test_import/data/syntax_warnings.py')
|
||||
with open(filename, 'rb') as f:
|
||||
source = f.read()
|
||||
with warnings.catch_warnings(record=True) as wlog:
|
||||
warnings.simplefilter('error')
|
||||
warnings.filterwarnings('always', module=r'<unknown>\z')
|
||||
ast.parse(source)
|
||||
self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10])
|
||||
for wm in wlog:
|
||||
self.assertEqual(wm.filename, '<unknown>')
|
||||
self.assertIs(wm.category, SyntaxWarning)
|
||||
|
||||
|
||||
class CopyTests(unittest.TestCase):
|
||||
"""Test copying and pickling AST nodes."""
|
||||
|
||||
@@ -1088,6 +1088,28 @@ class BuiltinTest(ComplexesAreIdenticalMixin, unittest.TestCase):
|
||||
three_freevars.__globals__,
|
||||
closure=my_closure)
|
||||
|
||||
def test_exec_filter_syntax_warnings_by_module(self):
|
||||
filename = support.findfile('test_import/data/syntax_warnings.py')
|
||||
with open(filename, 'rb') as f:
|
||||
source = f.read()
|
||||
with warnings.catch_warnings(record=True) as wlog:
|
||||
warnings.simplefilter('error')
|
||||
warnings.filterwarnings('always', module=r'<string>\z')
|
||||
exec(source, {})
|
||||
self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21])
|
||||
for wm in wlog:
|
||||
self.assertEqual(wm.filename, '<string>')
|
||||
self.assertIs(wm.category, SyntaxWarning)
|
||||
|
||||
with warnings.catch_warnings(record=True) as wlog:
|
||||
warnings.simplefilter('error')
|
||||
warnings.filterwarnings('always', module=r'<string>\z')
|
||||
exec(source, {'__name__': 'package.module', '__file__': filename})
|
||||
self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21])
|
||||
for wm in wlog:
|
||||
self.assertEqual(wm.filename, '<string>')
|
||||
self.assertIs(wm.category, SyntaxWarning)
|
||||
|
||||
|
||||
def test_filter(self):
|
||||
self.assertEqual(list(filter(lambda c: 'a' <= c <= 'z', 'Hello World')), list('elloorld'))
|
||||
|
||||
@@ -810,6 +810,19 @@ class CmdLineTest(unittest.TestCase):
|
||||
out, err = p.communicate()
|
||||
self.assertEqual(out, b"12345678912345678912345\n")
|
||||
|
||||
def test_filter_syntax_warnings_by_module(self):
|
||||
filename = support.findfile('test_import/data/syntax_warnings.py')
|
||||
rc, out, err = assert_python_ok(
|
||||
'-Werror',
|
||||
'-Walways:::test.test_import.data.syntax_warnings',
|
||||
filename)
|
||||
self.assertEqual(err.count(b': SyntaxWarning: '), 6)
|
||||
|
||||
rc, out, err = assert_python_ok(
|
||||
'-Werror',
|
||||
'-Walways:::syntax_warnings',
|
||||
filename)
|
||||
self.assertEqual(err.count(b': SyntaxWarning: '), 6)
|
||||
|
||||
|
||||
def tearDownModule():
|
||||
|
||||
@@ -1745,6 +1745,20 @@ class TestSpecifics(unittest.TestCase):
|
||||
self.assertEqual(wm.category, SyntaxWarning)
|
||||
self.assertIn("\"is\" with 'int' literal", str(wm.message))
|
||||
|
||||
def test_filter_syntax_warnings_by_module(self):
|
||||
filename = support.findfile('test_import/data/syntax_warnings.py')
|
||||
with open(filename, 'rb') as f:
|
||||
source = f.read()
|
||||
module_re = r'test\.test_import\.data\.syntax_warnings\z'
|
||||
with warnings.catch_warnings(record=True) as wlog:
|
||||
warnings.simplefilter('error')
|
||||
warnings.filterwarnings('always', module=module_re)
|
||||
compile(source, filename, 'exec')
|
||||
self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21])
|
||||
for wm in wlog:
|
||||
self.assertEqual(wm.filename, filename)
|
||||
self.assertIs(wm.category, SyntaxWarning)
|
||||
|
||||
@support.subTests('src', [
|
||||
textwrap.dedent("""
|
||||
def f():
|
||||
|
||||
@@ -15,6 +15,7 @@ import marshal
|
||||
import os
|
||||
import py_compile
|
||||
import random
|
||||
import re
|
||||
import shutil
|
||||
import stat
|
||||
import subprocess
|
||||
@@ -23,6 +24,7 @@ import textwrap
|
||||
import threading
|
||||
import time
|
||||
import types
|
||||
import warnings
|
||||
import unittest
|
||||
from unittest import mock
|
||||
import _imp
|
||||
@@ -51,7 +53,7 @@ from test.support.os_helper import (
|
||||
TESTFN, rmtree, temp_umask, TESTFN_UNENCODABLE)
|
||||
from test.support import script_helper
|
||||
from test.support import threading_helper
|
||||
from test.test_importlib.util import uncache
|
||||
from test.test_importlib.util import uncache, temporary_pycache_prefix
|
||||
from types import ModuleType
|
||||
try:
|
||||
import _testsinglephase
|
||||
@@ -412,7 +414,6 @@ class ImportTests(unittest.TestCase):
|
||||
self.assertIsNotNone(cm.exception)
|
||||
|
||||
def test_from_import_star_invalid_type(self):
|
||||
import re
|
||||
with ready_to_import() as (name, path):
|
||||
with open(path, 'w', encoding='utf-8') as f:
|
||||
f.write("__all__ = [b'invalid_type']")
|
||||
@@ -1250,6 +1251,35 @@ os.does_not_exist
|
||||
origin = "a\x00b"
|
||||
_imp.create_dynamic(Spec2())
|
||||
|
||||
def test_filter_syntax_warnings_by_module(self):
|
||||
module_re = r'test\.test_import\.data\.syntax_warnings\z'
|
||||
unload('test.test_import.data.syntax_warnings')
|
||||
with (os_helper.temp_dir() as tmpdir,
|
||||
temporary_pycache_prefix(tmpdir),
|
||||
warnings.catch_warnings(record=True) as wlog):
|
||||
warnings.simplefilter('error')
|
||||
warnings.filterwarnings('always', module=module_re)
|
||||
import test.test_import.data.syntax_warnings
|
||||
self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21])
|
||||
filename = test.test_import.data.syntax_warnings.__file__
|
||||
for wm in wlog:
|
||||
self.assertEqual(wm.filename, filename)
|
||||
self.assertIs(wm.category, SyntaxWarning)
|
||||
|
||||
module_re = r'syntax_warnings\z'
|
||||
unload('test.test_import.data.syntax_warnings')
|
||||
with (os_helper.temp_dir() as tmpdir,
|
||||
temporary_pycache_prefix(tmpdir),
|
||||
warnings.catch_warnings(record=True) as wlog):
|
||||
warnings.simplefilter('error')
|
||||
warnings.filterwarnings('always', module=module_re)
|
||||
import test.test_import.data.syntax_warnings
|
||||
self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21])
|
||||
filename = test.test_import.data.syntax_warnings.__file__
|
||||
for wm in wlog:
|
||||
self.assertEqual(wm.filename, filename)
|
||||
self.assertIs(wm.category, SyntaxWarning)
|
||||
|
||||
|
||||
@skip_if_dont_write_bytecode
|
||||
class FilePermissionTests(unittest.TestCase):
|
||||
|
||||
21
Lib/test/test_import/data/syntax_warnings.py
Normal file
21
Lib/test/test_import/data/syntax_warnings.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# Syntax warnings emitted in different parts of the Python compiler.
|
||||
|
||||
# Parser/lexer/lexer.c
|
||||
x = 1or 0 # line 4
|
||||
|
||||
# Parser/tokenizer/helpers.c
|
||||
'\z' # line 7
|
||||
|
||||
# Parser/string_parser.c
|
||||
'\400' # line 10
|
||||
|
||||
# _PyCompile_Warn() in Python/codegen.c
|
||||
assert(x, 'message') # line 13
|
||||
x is 1 # line 14
|
||||
|
||||
# _PyErr_EmitSyntaxWarning() in Python/ast_preprocess.c
|
||||
def f():
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
return 42 # line 21
|
||||
@@ -5,6 +5,7 @@ Test the API of the symtable module.
|
||||
import re
|
||||
import textwrap
|
||||
import symtable
|
||||
import warnings
|
||||
import unittest
|
||||
|
||||
from test import support
|
||||
@@ -586,6 +587,20 @@ class SymtableTest(unittest.TestCase):
|
||||
# check error path when 'compile_type' AC conversion failed
|
||||
self.assertRaises(TypeError, symtable.symtable, '', mortal_str, 1)
|
||||
|
||||
def test_filter_syntax_warnings_by_module(self):
|
||||
filename = support.findfile('test_import/data/syntax_warnings.py')
|
||||
with open(filename, 'rb') as f:
|
||||
source = f.read()
|
||||
module_re = r'test\.test_import\.data\.syntax_warnings\z'
|
||||
with warnings.catch_warnings(record=True) as wlog:
|
||||
warnings.simplefilter('error')
|
||||
warnings.filterwarnings('always', module=module_re)
|
||||
symtable.symtable(source, filename, 'exec')
|
||||
self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10])
|
||||
for wm in wlog:
|
||||
self.assertEqual(wm.filename, filename)
|
||||
self.assertIs(wm.category, SyntaxWarning)
|
||||
|
||||
|
||||
class ComprehensionTests(unittest.TestCase):
|
||||
def get_identifiers_recursive(self, st, res):
|
||||
|
||||
@@ -249,10 +249,23 @@ class FilterTests(BaseTest):
|
||||
self.module.warn_explicit('msg', UserWarning, 'filename', 42,
|
||||
module='package.module')
|
||||
self.assertEqual(len(w), 1)
|
||||
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module', 42)
|
||||
self.assertEqual(len(w), 2)
|
||||
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module.py', 42)
|
||||
self.assertEqual(len(w), 3)
|
||||
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module/__init__.py', 42)
|
||||
self.assertEqual(len(w), 4)
|
||||
with self.assertRaises(UserWarning):
|
||||
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module', 42)
|
||||
with self.assertRaises(UserWarning):
|
||||
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module.py', 42)
|
||||
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module/__init__', 42)
|
||||
if MS_WINDOWS:
|
||||
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.PY', 42)
|
||||
self.assertEqual(len(w), 5)
|
||||
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module\__INIT__.PY', 42)
|
||||
self.assertEqual(len(w), 6)
|
||||
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.PYW', 42)
|
||||
self.assertEqual(len(w), 7)
|
||||
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module\__INIT__.PYW', 42)
|
||||
self.assertEqual(len(w), 8)
|
||||
|
||||
with self.module.catch_warnings(record=True) as w:
|
||||
self.module.simplefilter('error')
|
||||
@@ -276,9 +289,8 @@ class FilterTests(BaseTest):
|
||||
with self.assertRaises(UserWarning):
|
||||
self.module.warn_explicit('msg', UserWarning, '/PATH/TO/PACKAGE/MODULE', 42)
|
||||
if MS_WINDOWS:
|
||||
if self.module is py_warnings:
|
||||
self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module.PY', 42)
|
||||
self.assertEqual(len(w), 3)
|
||||
self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module.PY', 42)
|
||||
self.assertEqual(len(w), 3)
|
||||
with self.assertRaises(UserWarning):
|
||||
self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module/__init__.py', 42)
|
||||
with self.assertRaises(UserWarning):
|
||||
@@ -302,9 +314,8 @@ class FilterTests(BaseTest):
|
||||
self.assertEqual(len(w), 1)
|
||||
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.py', 42)
|
||||
self.assertEqual(len(w), 2)
|
||||
if self.module is py_warnings:
|
||||
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.PY', 42)
|
||||
self.assertEqual(len(w), 3)
|
||||
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.PY', 42)
|
||||
self.assertEqual(len(w), 3)
|
||||
with self.assertRaises(UserWarning):
|
||||
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.pyw', 42)
|
||||
with self.assertRaises(UserWarning):
|
||||
@@ -399,7 +410,7 @@ class FilterTests(BaseTest):
|
||||
|
||||
def test_mutate_filter_list(self):
|
||||
class X:
|
||||
def match(self, a):
|
||||
def match(self, a, start=0):
|
||||
L[:] = []
|
||||
|
||||
L = [("default",X(),UserWarning,X(),0) for i in range(2)]
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Improve filtering by module in :func:`warnings.warn_explicit` if no *module*
|
||||
argument is passed. It now tests the module regular expression in the
|
||||
warnings filter not only against the filename with ``.py`` stripped, but
|
||||
also against module names constructed starting from different parent
|
||||
directories of the filename (with ``/__init__.py``, ``.py`` and, on Windows,
|
||||
``.pyw`` stripped).
|
||||
@@ -171,7 +171,7 @@ _PyWarnings_InitState(PyInterpreterState *interp)
|
||||
/*************************************************************************/
|
||||
|
||||
static int
|
||||
check_matched(PyInterpreterState *interp, PyObject *obj, PyObject *arg)
|
||||
check_matched(PyInterpreterState *interp, PyObject *obj, PyObject *arg, PyObject *arg2)
|
||||
{
|
||||
PyObject *result;
|
||||
int rc;
|
||||
@@ -182,6 +182,9 @@ check_matched(PyInterpreterState *interp, PyObject *obj, PyObject *arg)
|
||||
|
||||
/* An internal plain text default filter must match exactly */
|
||||
if (PyUnicode_CheckExact(obj)) {
|
||||
if (arg == NULL) {
|
||||
return 0;
|
||||
}
|
||||
int cmp_result = PyUnicode_Compare(obj, arg);
|
||||
if (cmp_result == -1 && PyErr_Occurred()) {
|
||||
return -1;
|
||||
@@ -190,10 +193,19 @@ check_matched(PyInterpreterState *interp, PyObject *obj, PyObject *arg)
|
||||
}
|
||||
|
||||
/* Otherwise assume a regex filter and call its match() method */
|
||||
result = PyObject_CallMethodOneArg(obj, &_Py_ID(match), arg);
|
||||
if (arg != NULL) {
|
||||
result = PyObject_CallMethodOneArg(obj, &_Py_ID(match), arg);
|
||||
}
|
||||
else {
|
||||
PyObject *match = PyImport_ImportModuleAttrString("_py_warnings", "_match_filename");
|
||||
if (match == NULL) {
|
||||
return -1;
|
||||
}
|
||||
result = PyObject_CallFunctionObjArgs(match, obj, arg2, NULL);
|
||||
Py_DECREF(match);
|
||||
}
|
||||
if (result == NULL)
|
||||
return -1;
|
||||
|
||||
rc = PyObject_IsTrue(result);
|
||||
Py_DECREF(result);
|
||||
return rc;
|
||||
@@ -423,7 +435,7 @@ get_default_action(PyInterpreterState *interp)
|
||||
static bool
|
||||
filter_search(PyInterpreterState *interp, PyObject *category,
|
||||
PyObject *text, Py_ssize_t lineno,
|
||||
PyObject *module, char *list_name, PyObject *filters,
|
||||
PyObject *module, PyObject *filename, char *list_name, PyObject *filters,
|
||||
PyObject **item, PyObject **matched_action) {
|
||||
bool result = true;
|
||||
*matched_action = NULL;
|
||||
@@ -459,14 +471,14 @@ filter_search(PyInterpreterState *interp, PyObject *category,
|
||||
break;
|
||||
}
|
||||
|
||||
good_msg = check_matched(interp, msg, text);
|
||||
good_msg = check_matched(interp, msg, text, NULL);
|
||||
if (good_msg == -1) {
|
||||
Py_DECREF(tmp_item);
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
good_mod = check_matched(interp, mod, module);
|
||||
good_mod = check_matched(interp, mod, module, filename);
|
||||
if (good_mod == -1) {
|
||||
Py_DECREF(tmp_item);
|
||||
result = false;
|
||||
@@ -504,7 +516,7 @@ filter_search(PyInterpreterState *interp, PyObject *category,
|
||||
static PyObject*
|
||||
get_filter(PyInterpreterState *interp, PyObject *category,
|
||||
PyObject *text, Py_ssize_t lineno,
|
||||
PyObject *module, PyObject **item)
|
||||
PyObject *module, PyObject *filename, PyObject **item)
|
||||
{
|
||||
#ifdef Py_DEBUG
|
||||
WarningsState *st = warnings_get_state(interp);
|
||||
@@ -522,7 +534,7 @@ get_filter(PyInterpreterState *interp, PyObject *category,
|
||||
use_global_filters = true;
|
||||
} else {
|
||||
PyObject *context_action = NULL;
|
||||
if (!filter_search(interp, category, text, lineno, module, "_warnings_context _filters",
|
||||
if (!filter_search(interp, category, text, lineno, module, filename, "_warnings_context _filters",
|
||||
context_filters, item, &context_action)) {
|
||||
Py_DECREF(context_filters);
|
||||
return NULL;
|
||||
@@ -541,7 +553,7 @@ get_filter(PyInterpreterState *interp, PyObject *category,
|
||||
if (filters == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (!filter_search(interp, category, text, lineno, module, "filters",
|
||||
if (!filter_search(interp, category, text, lineno, module, filename, "filters",
|
||||
filters, item, &action)) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -612,39 +624,6 @@ already_warned(PyInterpreterState *interp, PyObject *registry, PyObject *key,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* New reference. */
|
||||
static PyObject *
|
||||
normalize_module(PyObject *filename)
|
||||
{
|
||||
PyObject *module;
|
||||
int kind;
|
||||
const void *data;
|
||||
Py_ssize_t len;
|
||||
|
||||
len = PyUnicode_GetLength(filename);
|
||||
if (len < 0)
|
||||
return NULL;
|
||||
|
||||
if (len == 0)
|
||||
return PyUnicode_FromString("<unknown>");
|
||||
|
||||
kind = PyUnicode_KIND(filename);
|
||||
data = PyUnicode_DATA(filename);
|
||||
|
||||
/* if filename.endswith(".py"): */
|
||||
if (len >= 3 &&
|
||||
PyUnicode_READ(kind, data, len-3) == '.' &&
|
||||
PyUnicode_READ(kind, data, len-2) == 'p' &&
|
||||
PyUnicode_READ(kind, data, len-1) == 'y')
|
||||
{
|
||||
module = PyUnicode_Substring(filename, 0, len-3);
|
||||
}
|
||||
else {
|
||||
module = Py_NewRef(filename);
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
static int
|
||||
update_registry(PyInterpreterState *interp, PyObject *registry, PyObject *text,
|
||||
PyObject *category, int add_zero)
|
||||
@@ -812,15 +791,6 @@ warn_explicit(PyThreadState *tstate, PyObject *category, PyObject *message,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Normalize module. */
|
||||
if (module == NULL) {
|
||||
module = normalize_module(filename);
|
||||
if (module == NULL)
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
Py_INCREF(module);
|
||||
|
||||
/* Normalize message. */
|
||||
Py_INCREF(message); /* DECREF'ed in cleanup. */
|
||||
if (PyObject_TypeCheck(message, (PyTypeObject *)PyExc_Warning)) {
|
||||
@@ -858,7 +828,7 @@ warn_explicit(PyThreadState *tstate, PyObject *category, PyObject *message,
|
||||
/* Else this warning hasn't been generated before. */
|
||||
}
|
||||
|
||||
action = get_filter(interp, category, text, lineno, module, &item);
|
||||
action = get_filter(interp, category, text, lineno, module, filename, &item);
|
||||
if (action == NULL)
|
||||
goto cleanup;
|
||||
|
||||
@@ -921,7 +891,6 @@ warn_explicit(PyThreadState *tstate, PyObject *category, PyObject *message,
|
||||
Py_XDECREF(key);
|
||||
Py_XDECREF(text);
|
||||
Py_XDECREF(lineno_obj);
|
||||
Py_DECREF(module);
|
||||
Py_XDECREF(message);
|
||||
return result; /* Py_None or NULL. */
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user