test_warnings.py 2.4 KB

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