codekingpro/portable-devtools
115k
1"""
2Tests which scan for certain occurrences in the code, they may not find
3all of these occurrences but should catch almost all.
4"""
5import ast
6import tokenize
7from pathlib import Path
8
9import pytest
10
11import numpy
12
13
14class ParseCall(ast.NodeVisitor):
15 def __init__(self):
16 self.ls = []
17
18 def visit_Attribute(self, node):
19 ast.NodeVisitor.generic_visit(self, node)
20 self.ls.append(node.attr)
21
22 def visit_Name(self, node):
23 self.ls.append(node.id)
24
25
26class FindFuncs(ast.NodeVisitor):
27 def __init__(self, filename):
28 super().__init__()
29 self.__filename = filename
30
31 def visit_Call(self, node):
32 p = ParseCall()
33 p.visit(node.func)
34 ast.NodeVisitor.generic_visit(self, node)
35
36 if p.ls[-1] == 'simplefilter' or p.ls[-1] == 'filterwarnings':
37 if getattr(node.args[0], "value", None) == "ignore":
38 if not self.__filename.name.startswith("test_"):
39 raise AssertionError(
40 "ignore filters should only be used in tests; "
41 f"found in {self.__filename} on line {node.lineno}")
42
43 if p.ls[-1] == 'warn' and (
44 len(p.ls) == 1 or p.ls[-2] == 'warnings'):
45
46 if "testing/tests/test_warnings.py" == self.__filename:
47 # This file
48 return
49
50 # See if stacklevel exists:
51 if len(node.args) == 3:
52 return
53 args = {kw.arg for kw in node.keywords}
54 if "stacklevel" in args:
55 return
56 raise AssertionError(
57 "warnings should have an appropriate stacklevel; "
58 f"found in {self.__filename} on line {node.lineno}")
59
60
61@pytest.mark.slow
62def test_warning_calls():
63 # combined "ignore" and stacklevel error
64 base = Path(numpy.__file__).parent
65
66 for path in base.rglob("*.py"):
67 if base / "testing" in path.parents:
68 continue
69 if path == base / "__init__.py":
70 continue
71 if path == base / "random" / "__init__.py":
72 continue
73 if path == base / "conftest.py":
74 continue
75 # use tokenize to auto-detect encoding on systems where no
76 # default encoding is defined (e.g. LANG='C')
77 with tokenize.open(str(path)) as file:
78 tree = ast.parse(file.read())
79 FindFuncs(path).visit(tree)
80 