Fix some check_untyped_defs = True mypy warnings
This commit is contained in:
		
							parent
							
								
									28761c8da1
								
							
						
					
					
						commit
						7259c453d6
					
				|  | @ -5,10 +5,15 @@ import traceback | |||
| from inspect import CO_VARARGS | ||||
| from inspect import CO_VARKEYWORDS | ||||
| from traceback import format_exception_only | ||||
| from types import CodeType | ||||
| from types import TracebackType | ||||
| from typing import Any | ||||
| from typing import Dict | ||||
| from typing import Generic | ||||
| from typing import List | ||||
| from typing import Optional | ||||
| from typing import Pattern | ||||
| from typing import Set | ||||
| from typing import Tuple | ||||
| from typing import TypeVar | ||||
| from typing import Union | ||||
|  | @ -29,7 +34,7 @@ if False:  # TYPE_CHECKING | |||
| class Code: | ||||
|     """ wrapper around Python code objects """ | ||||
| 
 | ||||
|     def __init__(self, rawcode): | ||||
|     def __init__(self, rawcode) -> None: | ||||
|         if not hasattr(rawcode, "co_filename"): | ||||
|             rawcode = getrawcode(rawcode) | ||||
|         try: | ||||
|  | @ -38,7 +43,7 @@ class Code: | |||
|             self.name = rawcode.co_name | ||||
|         except AttributeError: | ||||
|             raise TypeError("not a code object: {!r}".format(rawcode)) | ||||
|         self.raw = rawcode | ||||
|         self.raw = rawcode  # type: CodeType | ||||
| 
 | ||||
|     def __eq__(self, other): | ||||
|         return self.raw == other.raw | ||||
|  | @ -351,7 +356,7 @@ class Traceback(list): | |||
|         """ return the index of the frame/TracebackEntry where recursion | ||||
|             originates if appropriate, None if no recursion occurred | ||||
|         """ | ||||
|         cache = {} | ||||
|         cache = {}  # type: Dict[Tuple[Any, int, int], List[Dict[str, Any]]] | ||||
|         for i, entry in enumerate(self): | ||||
|             # id for the code.raw is needed to work around | ||||
|             # the strange metaprogramming in the decorator lib from pypi | ||||
|  | @ -650,7 +655,7 @@ class FormattedExcinfo: | |||
|                 args.append((argname, saferepr(argvalue))) | ||||
|             return ReprFuncArgs(args) | ||||
| 
 | ||||
|     def get_source(self, source, line_index=-1, excinfo=None, short=False): | ||||
|     def get_source(self, source, line_index=-1, excinfo=None, short=False) -> List[str]: | ||||
|         """ return formatted and marked up source lines. """ | ||||
|         import _pytest._code | ||||
| 
 | ||||
|  | @ -722,7 +727,7 @@ class FormattedExcinfo: | |||
|         else: | ||||
|             line_index = entry.lineno - entry.getfirstlinesource() | ||||
| 
 | ||||
|         lines = [] | ||||
|         lines = []  # type: List[str] | ||||
|         style = entry._repr_style | ||||
|         if style is None: | ||||
|             style = self.style | ||||
|  | @ -799,7 +804,7 @@ class FormattedExcinfo: | |||
|                 exc_msg=str(e), | ||||
|                 max_frames=max_frames, | ||||
|                 total=len(traceback), | ||||
|             ) | ||||
|             )  # type: Optional[str] | ||||
|             traceback = traceback[:max_frames] + traceback[-max_frames:] | ||||
|         else: | ||||
|             if recursionindex is not None: | ||||
|  | @ -812,10 +817,12 @@ class FormattedExcinfo: | |||
| 
 | ||||
|     def repr_excinfo(self, excinfo): | ||||
| 
 | ||||
|         repr_chain = [] | ||||
|         repr_chain = ( | ||||
|             [] | ||||
|         )  # type: List[Tuple[ReprTraceback, Optional[ReprFileLocation], Optional[str]]] | ||||
|         e = excinfo.value | ||||
|         descr = None | ||||
|         seen = set() | ||||
|         seen = set()  # type: Set[int] | ||||
|         while e is not None and id(e) not in seen: | ||||
|             seen.add(id(e)) | ||||
|             if excinfo: | ||||
|  | @ -868,8 +875,8 @@ class TerminalRepr: | |||
| 
 | ||||
| 
 | ||||
| class ExceptionRepr(TerminalRepr): | ||||
|     def __init__(self): | ||||
|         self.sections = [] | ||||
|     def __init__(self) -> None: | ||||
|         self.sections = []  # type: List[Tuple[str, str, str]] | ||||
| 
 | ||||
|     def addsection(self, name, content, sep="-"): | ||||
|         self.sections.append((name, content, sep)) | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ import tokenize | |||
| import warnings | ||||
| from ast import PyCF_ONLY_AST as _AST_FLAG | ||||
| from bisect import bisect_right | ||||
| from typing import List | ||||
| 
 | ||||
| import py | ||||
| 
 | ||||
|  | @ -19,11 +20,11 @@ class Source: | |||
|     _compilecounter = 0 | ||||
| 
 | ||||
|     def __init__(self, *parts, **kwargs): | ||||
|         self.lines = lines = [] | ||||
|         self.lines = lines = []  # type: List[str] | ||||
|         de = kwargs.get("deindent", True) | ||||
|         for part in parts: | ||||
|             if not part: | ||||
|                 partlines = [] | ||||
|                 partlines = []  # type: List[str] | ||||
|             elif isinstance(part, Source): | ||||
|                 partlines = part.lines | ||||
|             elif isinstance(part, (tuple, list)): | ||||
|  | @ -157,8 +158,7 @@ class Source: | |||
|         source = "\n".join(self.lines) + "\n" | ||||
|         try: | ||||
|             co = compile(source, filename, mode, flag) | ||||
|         except SyntaxError: | ||||
|             ex = sys.exc_info()[1] | ||||
|         except SyntaxError as ex: | ||||
|             # re-represent syntax errors from parsing python strings | ||||
|             msglines = self.lines[: ex.lineno] | ||||
|             if ex.offset: | ||||
|  | @ -173,7 +173,8 @@ class Source: | |||
|             if flag & _AST_FLAG: | ||||
|                 return co | ||||
|             lines = [(x + "\n") for x in self.lines] | ||||
|             linecache.cache[filename] = (1, None, lines, filename) | ||||
|             # Type ignored because linecache.cache is private. | ||||
|             linecache.cache[filename] = (1, None, lines, filename)  # type: ignore | ||||
|             return co | ||||
| 
 | ||||
| 
 | ||||
|  | @ -282,7 +283,7 @@ def get_statement_startend2(lineno, node): | |||
|     return start, end | ||||
| 
 | ||||
| 
 | ||||
| def getstatementrange_ast(lineno, source, assertion=False, astnode=None): | ||||
| def getstatementrange_ast(lineno, source: Source, assertion=False, astnode=None): | ||||
|     if astnode is None: | ||||
|         content = str(source) | ||||
|         # See #4260: | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| support for presenting detailed information in failing assertions. | ||||
| """ | ||||
| import sys | ||||
| from typing import Optional | ||||
| 
 | ||||
| from _pytest.assertion import rewrite | ||||
| from _pytest.assertion import truncate | ||||
|  | @ -52,7 +53,9 @@ def register_assert_rewrite(*names): | |||
|             importhook = hook | ||||
|             break | ||||
|     else: | ||||
|         importhook = DummyRewriteHook() | ||||
|         # TODO(typing): Add a protocol for mark_rewrite() and use it | ||||
|         # for importhook and for PytestPluginManager.rewrite_hook. | ||||
|         importhook = DummyRewriteHook()  # type: ignore | ||||
|     importhook.mark_rewrite(*names) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -69,7 +72,7 @@ class AssertionState: | |||
|     def __init__(self, config, mode): | ||||
|         self.mode = mode | ||||
|         self.trace = config.trace.root.get("assertion") | ||||
|         self.hook = None | ||||
|         self.hook = None  # type: Optional[rewrite.AssertionRewritingHook] | ||||
| 
 | ||||
| 
 | ||||
| def install_importhook(config): | ||||
|  | @ -108,6 +111,7 @@ def pytest_runtest_setup(item): | |||
|     """ | ||||
| 
 | ||||
|     def callbinrepr(op, left, right): | ||||
|         # type: (str, object, object) -> Optional[str] | ||||
|         """Call the pytest_assertrepr_compare hook and prepare the result | ||||
| 
 | ||||
|         This uses the first result from the hook and then ensures the | ||||
|  | @ -133,12 +137,13 @@ def pytest_runtest_setup(item): | |||
|                 if item.config.getvalue("assertmode") == "rewrite": | ||||
|                     res = res.replace("%", "%%") | ||||
|                 return res | ||||
|         return None | ||||
| 
 | ||||
|     util._reprcompare = callbinrepr | ||||
| 
 | ||||
|     if item.ihook.pytest_assertion_pass.get_hookimpls(): | ||||
| 
 | ||||
|         def call_assertion_pass_hook(lineno, expl, orig): | ||||
|         def call_assertion_pass_hook(lineno, orig, expl): | ||||
|             item.ihook.pytest_assertion_pass( | ||||
|                 item=item, lineno=lineno, orig=orig, expl=expl | ||||
|             ) | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ from typing import Dict | |||
| from typing import List | ||||
| from typing import Optional | ||||
| from typing import Set | ||||
| from typing import Tuple | ||||
| 
 | ||||
| import atomicwrites | ||||
| 
 | ||||
|  | @ -48,13 +49,13 @@ class AssertionRewritingHook(importlib.abc.MetaPathFinder): | |||
|         except ValueError: | ||||
|             self.fnpats = ["test_*.py", "*_test.py"] | ||||
|         self.session = None | ||||
|         self._rewritten_names = set() | ||||
|         self._must_rewrite = set() | ||||
|         self._rewritten_names = set()  # type: Set[str] | ||||
|         self._must_rewrite = set()  # type: Set[str] | ||||
|         # flag to guard against trying to rewrite a pyc file while we are already writing another pyc file, | ||||
|         # which might result in infinite recursion (#3506) | ||||
|         self._writing_pyc = False | ||||
|         self._basenames_to_check_rewrite = {"conftest"} | ||||
|         self._marked_for_rewrite_cache = {} | ||||
|         self._marked_for_rewrite_cache = {}  # type: Dict[str, bool] | ||||
|         self._session_paths_checked = False | ||||
| 
 | ||||
|     def set_session(self, session): | ||||
|  | @ -203,7 +204,7 @@ class AssertionRewritingHook(importlib.abc.MetaPathFinder): | |||
| 
 | ||||
|         return self._is_marked_for_rewrite(name, state) | ||||
| 
 | ||||
|     def _is_marked_for_rewrite(self, name, state): | ||||
|     def _is_marked_for_rewrite(self, name: str, state): | ||||
|         try: | ||||
|             return self._marked_for_rewrite_cache[name] | ||||
|         except KeyError: | ||||
|  | @ -218,7 +219,7 @@ class AssertionRewritingHook(importlib.abc.MetaPathFinder): | |||
|             self._marked_for_rewrite_cache[name] = False | ||||
|             return False | ||||
| 
 | ||||
|     def mark_rewrite(self, *names): | ||||
|     def mark_rewrite(self, *names: str) -> None: | ||||
|         """Mark import names as needing to be rewritten. | ||||
| 
 | ||||
|         The named module or package as well as any nested modules will | ||||
|  | @ -385,6 +386,7 @@ def _format_boolop(explanations, is_or): | |||
| 
 | ||||
| 
 | ||||
| def _call_reprcompare(ops, results, expls, each_obj): | ||||
|     # type: (Tuple[str, ...], Tuple[bool, ...], Tuple[str, ...], Tuple[object, ...]) -> str | ||||
|     for i, res, expl in zip(range(len(ops)), results, expls): | ||||
|         try: | ||||
|             done = not res | ||||
|  | @ -400,11 +402,13 @@ def _call_reprcompare(ops, results, expls, each_obj): | |||
| 
 | ||||
| 
 | ||||
| def _call_assertion_pass(lineno, orig, expl): | ||||
|     # type: (int, str, str) -> None | ||||
|     if util._assertion_pass is not None: | ||||
|         util._assertion_pass(lineno=lineno, orig=orig, expl=expl) | ||||
|         util._assertion_pass(lineno, orig, expl) | ||||
| 
 | ||||
| 
 | ||||
| def _check_if_assertion_pass_impl(): | ||||
|     # type: () -> bool | ||||
|     """Checks if any plugins implement the pytest_assertion_pass hook | ||||
|     in order not to generate explanation unecessarily (might be expensive)""" | ||||
|     return True if util._assertion_pass else False | ||||
|  | @ -578,7 +582,7 @@ class AssertionRewriter(ast.NodeVisitor): | |||
|     def _assert_expr_to_lineno(self): | ||||
|         return _get_assertion_exprs(self.source) | ||||
| 
 | ||||
|     def run(self, mod): | ||||
|     def run(self, mod: ast.Module) -> None: | ||||
|         """Find all assert statements in *mod* and rewrite them.""" | ||||
|         if not mod.body: | ||||
|             # Nothing to do. | ||||
|  | @ -620,12 +624,12 @@ class AssertionRewriter(ast.NodeVisitor): | |||
|         ] | ||||
|         mod.body[pos:pos] = imports | ||||
|         # Collect asserts. | ||||
|         nodes = [mod] | ||||
|         nodes = [mod]  # type: List[ast.AST] | ||||
|         while nodes: | ||||
|             node = nodes.pop() | ||||
|             for name, field in ast.iter_fields(node): | ||||
|                 if isinstance(field, list): | ||||
|                     new = [] | ||||
|                     new = []  # type: List | ||||
|                     for i, child in enumerate(field): | ||||
|                         if isinstance(child, ast.Assert): | ||||
|                             # Transform assert. | ||||
|  | @ -699,7 +703,7 @@ class AssertionRewriter(ast.NodeVisitor): | |||
|         .explanation_param(). | ||||
| 
 | ||||
|         """ | ||||
|         self.explanation_specifiers = {} | ||||
|         self.explanation_specifiers = {}  # type: Dict[str, ast.expr] | ||||
|         self.stack.append(self.explanation_specifiers) | ||||
| 
 | ||||
|     def pop_format_context(self, expl_expr): | ||||
|  | @ -742,7 +746,8 @@ class AssertionRewriter(ast.NodeVisitor): | |||
|             from _pytest.warning_types import PytestAssertRewriteWarning | ||||
|             import warnings | ||||
| 
 | ||||
|             warnings.warn_explicit( | ||||
|             # Ignore type: typeshed bug https://github.com/python/typeshed/pull/3121 | ||||
|             warnings.warn_explicit(  # type: ignore | ||||
|                 PytestAssertRewriteWarning( | ||||
|                     "assertion is always true, perhaps remove parentheses?" | ||||
|                 ), | ||||
|  | @ -751,15 +756,15 @@ class AssertionRewriter(ast.NodeVisitor): | |||
|                 lineno=assert_.lineno, | ||||
|             ) | ||||
| 
 | ||||
|         self.statements = [] | ||||
|         self.variables = [] | ||||
|         self.statements = []  # type: List[ast.stmt] | ||||
|         self.variables = []  # type: List[str] | ||||
|         self.variable_counter = itertools.count() | ||||
| 
 | ||||
|         if self.enable_assertion_pass_hook: | ||||
|             self.format_variables = [] | ||||
|             self.format_variables = []  # type: List[str] | ||||
| 
 | ||||
|         self.stack = [] | ||||
|         self.expl_stmts = [] | ||||
|         self.stack = []  # type: List[Dict[str, ast.expr]] | ||||
|         self.expl_stmts = []  # type: List[ast.stmt] | ||||
|         self.push_format_context() | ||||
|         # Rewrite assert into a bunch of statements. | ||||
|         top_condition, explanation = self.visit(assert_.test) | ||||
|  | @ -897,7 +902,7 @@ warn_explicit( | |||
|         # Process each operand, short-circuiting if needed. | ||||
|         for i, v in enumerate(boolop.values): | ||||
|             if i: | ||||
|                 fail_inner = [] | ||||
|                 fail_inner = []  # type: List[ast.stmt] | ||||
|                 # cond is set in a prior loop iteration below | ||||
|                 self.expl_stmts.append(ast.If(cond, fail_inner, []))  # noqa | ||||
|                 self.expl_stmts = fail_inner | ||||
|  | @ -908,10 +913,10 @@ warn_explicit( | |||
|             call = ast.Call(app, [expl_format], []) | ||||
|             self.expl_stmts.append(ast.Expr(call)) | ||||
|             if i < levels: | ||||
|                 cond = res | ||||
|                 cond = res  # type: ast.expr | ||||
|                 if is_or: | ||||
|                     cond = ast.UnaryOp(ast.Not(), cond) | ||||
|                 inner = [] | ||||
|                 inner = []  # type: List[ast.stmt] | ||||
|                 self.statements.append(ast.If(cond, inner, [])) | ||||
|                 self.statements = body = inner | ||||
|         self.statements = save | ||||
|  | @ -977,7 +982,7 @@ warn_explicit( | |||
|         expl = pat % (res_expl, res_expl, value_expl, attr.attr) | ||||
|         return res, expl | ||||
| 
 | ||||
|     def visit_Compare(self, comp): | ||||
|     def visit_Compare(self, comp: ast.Compare): | ||||
|         self.push_format_context() | ||||
|         left_res, left_expl = self.visit(comp.left) | ||||
|         if isinstance(comp.left, (ast.Compare, ast.BoolOp)): | ||||
|  | @ -1010,7 +1015,7 @@ warn_explicit( | |||
|             ast.Tuple(results, ast.Load()), | ||||
|         ) | ||||
|         if len(comp.ops) > 1: | ||||
|             res = ast.BoolOp(ast.And(), load_names) | ||||
|             res = ast.BoolOp(ast.And(), load_names)  # type: ast.expr | ||||
|         else: | ||||
|             res = load_names[0] | ||||
|         return res, self.explanation_param(self.pop_format_context(expl_call)) | ||||
|  |  | |||
|  | @ -1,6 +1,9 @@ | |||
| """Utilities for assertion debugging""" | ||||
| import pprint | ||||
| from collections.abc import Sequence | ||||
| from typing import Callable | ||||
| from typing import List | ||||
| from typing import Optional | ||||
| 
 | ||||
| import _pytest._code | ||||
| from _pytest import outcomes | ||||
|  | @ -10,11 +13,11 @@ from _pytest._io.saferepr import saferepr | |||
| # interpretation code and assertion rewriter to detect this plugin was | ||||
| # loaded and in turn call the hooks defined here as part of the | ||||
| # DebugInterpreter. | ||||
| _reprcompare = None | ||||
| _reprcompare = None  # type: Optional[Callable[[str, object, object], Optional[str]]] | ||||
| 
 | ||||
| # Works similarly as _reprcompare attribute. Is populated with the hook call | ||||
| # when pytest_runtest_setup is called. | ||||
| _assertion_pass = None | ||||
| _assertion_pass = None  # type: Optional[Callable[[int, str, str], None]] | ||||
| 
 | ||||
| 
 | ||||
| def format_explanation(explanation): | ||||
|  | @ -177,7 +180,7 @@ def _diff_text(left, right, verbose=0): | |||
|     """ | ||||
|     from difflib import ndiff | ||||
| 
 | ||||
|     explanation = [] | ||||
|     explanation = []  # type: List[str] | ||||
| 
 | ||||
|     def escape_for_readable_diff(binary_text): | ||||
|         """ | ||||
|  | @ -235,7 +238,7 @@ def _compare_eq_verbose(left, right): | |||
|     left_lines = repr(left).splitlines(keepends) | ||||
|     right_lines = repr(right).splitlines(keepends) | ||||
| 
 | ||||
|     explanation = [] | ||||
|     explanation = []  # type: List[str] | ||||
|     explanation += ["-" + line for line in left_lines] | ||||
|     explanation += ["+" + line for line in right_lines] | ||||
| 
 | ||||
|  | @ -259,7 +262,7 @@ def _compare_eq_iterable(left, right, verbose=0): | |||
| 
 | ||||
| def _compare_eq_sequence(left, right, verbose=0): | ||||
|     comparing_bytes = isinstance(left, bytes) and isinstance(right, bytes) | ||||
|     explanation = [] | ||||
|     explanation = []  # type: List[str] | ||||
|     len_left = len(left) | ||||
|     len_right = len(right) | ||||
|     for i in range(min(len_left, len_right)): | ||||
|  | @ -327,7 +330,7 @@ def _compare_eq_set(left, right, verbose=0): | |||
| 
 | ||||
| 
 | ||||
| def _compare_eq_dict(left, right, verbose=0): | ||||
|     explanation = [] | ||||
|     explanation = []  # type: List[str] | ||||
|     set_left = set(left) | ||||
|     set_right = set(right) | ||||
|     common = set_left.intersection(set_right) | ||||
|  |  | |||
|  | @ -9,6 +9,15 @@ import types | |||
| import warnings | ||||
| from functools import lru_cache | ||||
| from pathlib import Path | ||||
| from types import TracebackType | ||||
| from typing import Any | ||||
| from typing import Callable | ||||
| from typing import Dict | ||||
| from typing import List | ||||
| from typing import Optional | ||||
| from typing import Sequence | ||||
| from typing import Set | ||||
| from typing import Tuple | ||||
| 
 | ||||
| import attr | ||||
| import py | ||||
|  | @ -32,6 +41,10 @@ from _pytest.outcomes import fail | |||
| from _pytest.outcomes import Skipped | ||||
| from _pytest.warning_types import PytestConfigWarning | ||||
| 
 | ||||
| if False:  # TYPE_CHECKING | ||||
|     from typing import Type | ||||
| 
 | ||||
| 
 | ||||
| hookimpl = HookimplMarker("pytest") | ||||
| hookspec = HookspecMarker("pytest") | ||||
| 
 | ||||
|  | @ -40,7 +53,7 @@ class ConftestImportFailure(Exception): | |||
|     def __init__(self, path, excinfo): | ||||
|         Exception.__init__(self, path, excinfo) | ||||
|         self.path = path | ||||
|         self.excinfo = excinfo | ||||
|         self.excinfo = excinfo  # type: Tuple[Type[Exception], Exception, TracebackType] | ||||
| 
 | ||||
| 
 | ||||
| def main(args=None, plugins=None): | ||||
|  | @ -237,14 +250,18 @@ class PytestPluginManager(PluginManager): | |||
| 
 | ||||
|     def __init__(self): | ||||
|         super().__init__("pytest") | ||||
|         self._conftest_plugins = set() | ||||
|         # The objects are module objects, only used generically. | ||||
|         self._conftest_plugins = set()  # type: Set[object] | ||||
| 
 | ||||
|         # state related to local conftest plugins | ||||
|         self._dirpath2confmods = {} | ||||
|         self._conftestpath2mod = {} | ||||
|         # Maps a py.path.local to a list of module objects. | ||||
|         self._dirpath2confmods = {}  # type: Dict[Any, List[object]] | ||||
|         # Maps a py.path.local to a module object. | ||||
|         self._conftestpath2mod = {}  # type: Dict[Any, object] | ||||
|         self._confcutdir = None | ||||
|         self._noconftest = False | ||||
|         self._duplicatepaths = set() | ||||
|         # Set of py.path.local's. | ||||
|         self._duplicatepaths = set()  # type: Set[Any] | ||||
| 
 | ||||
|         self.add_hookspecs(_pytest.hookspec) | ||||
|         self.register(self) | ||||
|  | @ -653,7 +670,7 @@ class Config: | |||
| 
 | ||||
|         args = attr.ib() | ||||
|         plugins = attr.ib() | ||||
|         dir = attr.ib() | ||||
|         dir = attr.ib(type=Path) | ||||
| 
 | ||||
|     def __init__(self, pluginmanager, *, invocation_params=None): | ||||
|         from .argparsing import Parser, FILE_OR_DIR | ||||
|  | @ -674,10 +691,10 @@ class Config: | |||
|         self.pluginmanager = pluginmanager | ||||
|         self.trace = self.pluginmanager.trace.root.get("config") | ||||
|         self.hook = self.pluginmanager.hook | ||||
|         self._inicache = {} | ||||
|         self._override_ini = () | ||||
|         self._opt2dest = {} | ||||
|         self._cleanup = [] | ||||
|         self._inicache = {}  # type: Dict[str, Any] | ||||
|         self._override_ini = ()  # type: Sequence[str] | ||||
|         self._opt2dest = {}  # type: Dict[str, str] | ||||
|         self._cleanup = []  # type: List[Callable[[], None]] | ||||
|         self.pluginmanager.register(self, "pytestconfig") | ||||
|         self._configured = False | ||||
|         self.hook.pytest_addoption.call_historic(kwargs=dict(parser=self._parser)) | ||||
|  | @ -778,7 +795,7 @@ class Config: | |||
|     def pytest_load_initial_conftests(self, early_config): | ||||
|         self.pluginmanager._set_initial_conftests(early_config.known_args_namespace) | ||||
| 
 | ||||
|     def _initini(self, args): | ||||
|     def _initini(self, args) -> None: | ||||
|         ns, unknown_args = self._parser.parse_known_and_unknown_args( | ||||
|             args, namespace=copy.copy(self.option) | ||||
|         ) | ||||
|  | @ -879,8 +896,7 @@ class Config: | |||
|             self.hook.pytest_load_initial_conftests( | ||||
|                 early_config=self, args=args, parser=self._parser | ||||
|             ) | ||||
|         except ConftestImportFailure: | ||||
|             e = sys.exc_info()[1] | ||||
|         except ConftestImportFailure as e: | ||||
|             if ns.help or ns.version: | ||||
|                 # we don't want to prevent --help/--version to work | ||||
|                 # so just let is pass and print a warning at the end | ||||
|  | @ -946,7 +962,7 @@ class Config: | |||
|         assert isinstance(x, list) | ||||
|         x.append(line)  # modifies the cached list inline | ||||
| 
 | ||||
|     def getini(self, name): | ||||
|     def getini(self, name: str): | ||||
|         """ return configuration value from an :ref:`ini file <inifiles>`. If the | ||||
|         specified name hasn't been registered through a prior | ||||
|         :py:func:`parser.addini <_pytest.config.Parser.addini>` | ||||
|  | @ -957,7 +973,7 @@ class Config: | |||
|             self._inicache[name] = val = self._getini(name) | ||||
|             return val | ||||
| 
 | ||||
|     def _getini(self, name): | ||||
|     def _getini(self, name: str) -> Any: | ||||
|         try: | ||||
|             description, type, default = self._parser._inidict[name] | ||||
|         except KeyError: | ||||
|  | @ -1002,7 +1018,7 @@ class Config: | |||
|             values.append(relroot) | ||||
|         return values | ||||
| 
 | ||||
|     def _get_override_ini_value(self, name): | ||||
|     def _get_override_ini_value(self, name: str) -> Optional[str]: | ||||
|         value = None | ||||
|         # override_ini is a list of "ini=value" options | ||||
|         # always use the last item if multiple values are set for same ini-name, | ||||
|  | @ -1017,7 +1033,7 @@ class Config: | |||
|                     value = user_ini_value | ||||
|         return value | ||||
| 
 | ||||
|     def getoption(self, name, default=notset, skip=False): | ||||
|     def getoption(self, name: str, default=notset, skip: bool = False): | ||||
|         """ return command line option value. | ||||
| 
 | ||||
|         :arg name: name of the option.  You may also specify | ||||
|  |  | |||
|  | @ -2,6 +2,11 @@ import argparse | |||
| import sys | ||||
| import warnings | ||||
| from gettext import gettext | ||||
| from typing import Any | ||||
| from typing import Dict | ||||
| from typing import List | ||||
| from typing import Optional | ||||
| from typing import Tuple | ||||
| 
 | ||||
| import py | ||||
| 
 | ||||
|  | @ -21,12 +26,12 @@ class Parser: | |||
| 
 | ||||
|     def __init__(self, usage=None, processopt=None): | ||||
|         self._anonymous = OptionGroup("custom options", parser=self) | ||||
|         self._groups = [] | ||||
|         self._groups = []  # type: List[OptionGroup] | ||||
|         self._processopt = processopt | ||||
|         self._usage = usage | ||||
|         self._inidict = {} | ||||
|         self._ininames = [] | ||||
|         self.extra_info = {} | ||||
|         self._inidict = {}  # type: Dict[str, Tuple[str, Optional[str], Any]] | ||||
|         self._ininames = []  # type: List[str] | ||||
|         self.extra_info = {}  # type: Dict[str, Any] | ||||
| 
 | ||||
|     def processoption(self, option): | ||||
|         if self._processopt: | ||||
|  | @ -80,7 +85,7 @@ class Parser: | |||
|         args = [str(x) if isinstance(x, py.path.local) else x for x in args] | ||||
|         return self.optparser.parse_args(args, namespace=namespace) | ||||
| 
 | ||||
|     def _getparser(self): | ||||
|     def _getparser(self) -> "MyOptionParser": | ||||
|         from _pytest._argcomplete import filescompleter | ||||
| 
 | ||||
|         optparser = MyOptionParser(self, self.extra_info, prog=self.prog) | ||||
|  | @ -94,7 +99,10 @@ class Parser: | |||
|                     a = option.attrs() | ||||
|                     arggroup.add_argument(*n, **a) | ||||
|         # bash like autocompletion for dirs (appending '/') | ||||
|         optparser.add_argument(FILE_OR_DIR, nargs="*").completer = filescompleter | ||||
|         # Type ignored because typeshed doesn't know about argcomplete. | ||||
|         optparser.add_argument(  # type: ignore | ||||
|             FILE_OR_DIR, nargs="*" | ||||
|         ).completer = filescompleter | ||||
|         return optparser | ||||
| 
 | ||||
|     def parse_setoption(self, args, option, namespace=None): | ||||
|  | @ -103,13 +111,15 @@ class Parser: | |||
|             setattr(option, name, value) | ||||
|         return getattr(parsedoption, FILE_OR_DIR) | ||||
| 
 | ||||
|     def parse_known_args(self, args, namespace=None): | ||||
|     def parse_known_args(self, args, namespace=None) -> argparse.Namespace: | ||||
|         """parses and returns a namespace object with known arguments at this | ||||
|         point. | ||||
|         """ | ||||
|         return self.parse_known_and_unknown_args(args, namespace=namespace)[0] | ||||
| 
 | ||||
|     def parse_known_and_unknown_args(self, args, namespace=None): | ||||
|     def parse_known_and_unknown_args( | ||||
|         self, args, namespace=None | ||||
|     ) -> Tuple[argparse.Namespace, List[str]]: | ||||
|         """parses and returns a namespace object with known arguments, and | ||||
|         the remaining arguments unknown at this point. | ||||
|         """ | ||||
|  | @ -163,8 +173,8 @@ class Argument: | |||
|     def __init__(self, *names, **attrs): | ||||
|         """store parms in private vars for use in add_argument""" | ||||
|         self._attrs = attrs | ||||
|         self._short_opts = [] | ||||
|         self._long_opts = [] | ||||
|         self._short_opts = []  # type: List[str] | ||||
|         self._long_opts = []  # type: List[str] | ||||
|         self.dest = attrs.get("dest") | ||||
|         if "%default" in (attrs.get("help") or ""): | ||||
|             warnings.warn( | ||||
|  | @ -268,8 +278,8 @@ class Argument: | |||
|                     ) | ||||
|                 self._long_opts.append(opt) | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         args = [] | ||||
|     def __repr__(self) -> str: | ||||
|         args = []  # type: List[str] | ||||
|         if self._short_opts: | ||||
|             args += ["_short_opts: " + repr(self._short_opts)] | ||||
|         if self._long_opts: | ||||
|  | @ -286,7 +296,7 @@ class OptionGroup: | |||
|     def __init__(self, name, description="", parser=None): | ||||
|         self.name = name | ||||
|         self.description = description | ||||
|         self.options = [] | ||||
|         self.options = []  # type: List[Argument] | ||||
|         self.parser = parser | ||||
| 
 | ||||
|     def addoption(self, *optnames, **attrs): | ||||
|  | @ -421,7 +431,7 @@ class DropShorterLongHelpFormatter(argparse.HelpFormatter): | |||
|         option_map = getattr(action, "map_long_option", {}) | ||||
|         if option_map is None: | ||||
|             option_map = {} | ||||
|         short_long = {} | ||||
|         short_long = {}  # type: Dict[str, str] | ||||
|         for option in options: | ||||
|             if len(option) == 2 or option[2] == " ": | ||||
|                 continue | ||||
|  |  | |||
|  | @ -1,10 +1,15 @@ | |||
| import os | ||||
| from typing import List | ||||
| from typing import Optional | ||||
| 
 | ||||
| import py | ||||
| 
 | ||||
| from .exceptions import UsageError | ||||
| from _pytest.outcomes import fail | ||||
| 
 | ||||
| if False: | ||||
|     from . import Config  # noqa: F401 | ||||
| 
 | ||||
| 
 | ||||
| def exists(path, ignore=EnvironmentError): | ||||
|     try: | ||||
|  | @ -102,7 +107,12 @@ def get_dirs_from_args(args): | |||
| CFG_PYTEST_SECTION = "[pytest] section in {filename} files is no longer supported, change to [tool:pytest] instead." | ||||
| 
 | ||||
| 
 | ||||
| def determine_setup(inifile, args, rootdir_cmd_arg=None, config=None): | ||||
| def determine_setup( | ||||
|     inifile: str, | ||||
|     args: List[str], | ||||
|     rootdir_cmd_arg: Optional[str] = None, | ||||
|     config: Optional["Config"] = None, | ||||
| ): | ||||
|     dirs = get_dirs_from_args(args) | ||||
|     if inifile: | ||||
|         iniconfig = py.iniconfig.IniConfig(inifile) | ||||
|  |  | |||
|  | @ -51,6 +51,8 @@ class MarkEvaluator: | |||
|         except TEST_OUTCOME: | ||||
|             self.exc = sys.exc_info() | ||||
|             if isinstance(self.exc[1], SyntaxError): | ||||
|                 # TODO: Investigate why SyntaxError.offset is Optional, and if it can be None here. | ||||
|                 assert self.exc[1].offset is not None | ||||
|                 msg = [" " * (self.exc[1].offset + 4) + "^"] | ||||
|                 msg.append("SyntaxError: invalid syntax") | ||||
|             else: | ||||
|  |  | |||
|  | @ -292,7 +292,7 @@ class MarkGenerator: | |||
|     _config = None | ||||
|     _markers = set()  # type: Set[str] | ||||
| 
 | ||||
|     def __getattr__(self, name): | ||||
|     def __getattr__(self, name: str) -> MarkDecorator: | ||||
|         if name[0] == "_": | ||||
|             raise AttributeError("Marker name must NOT start with underscore") | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,14 +1,26 @@ | |||
| import os | ||||
| import warnings | ||||
| from functools import lru_cache | ||||
| from typing import Any | ||||
| from typing import Dict | ||||
| from typing import List | ||||
| from typing import Set | ||||
| from typing import Tuple | ||||
| from typing import Union | ||||
| 
 | ||||
| import py | ||||
| 
 | ||||
| import _pytest._code | ||||
| from _pytest.compat import getfslineno | ||||
| from _pytest.mark.structures import Mark | ||||
| from _pytest.mark.structures import MarkDecorator | ||||
| from _pytest.mark.structures import NodeKeywords | ||||
| from _pytest.outcomes import fail | ||||
| 
 | ||||
| if False:  # TYPE_CHECKING | ||||
|     # Imported here due to circular import. | ||||
|     from _pytest.fixtures import FixtureDef | ||||
| 
 | ||||
| SEP = "/" | ||||
| 
 | ||||
| tracebackcutdir = py.path.local(_pytest.__file__).dirpath() | ||||
|  | @ -78,13 +90,13 @@ class Node: | |||
|         self.keywords = NodeKeywords(self) | ||||
| 
 | ||||
|         #: the marker objects belonging to this node | ||||
|         self.own_markers = [] | ||||
|         self.own_markers = []  # type: List[Mark] | ||||
| 
 | ||||
|         #: allow adding of extra keywords to use for matching | ||||
|         self.extra_keyword_matches = set() | ||||
|         self.extra_keyword_matches = set()  # type: Set[str] | ||||
| 
 | ||||
|         # used for storing artificial fixturedefs for direct parametrization | ||||
|         self._name2pseudofixturedef = {} | ||||
|         self._name2pseudofixturedef = {}  # type: Dict[str, FixtureDef] | ||||
| 
 | ||||
|         if nodeid is not None: | ||||
|             assert "::()" not in nodeid | ||||
|  | @ -127,7 +139,8 @@ class Node: | |||
|                 ) | ||||
|             ) | ||||
|         path, lineno = get_fslocation_from_item(self) | ||||
|         warnings.warn_explicit( | ||||
|         # Type ignored: https://github.com/python/typeshed/pull/3121 | ||||
|         warnings.warn_explicit(  # type: ignore | ||||
|             warning, | ||||
|             category=None, | ||||
|             filename=str(path), | ||||
|  | @ -160,7 +173,9 @@ class Node: | |||
|         chain.reverse() | ||||
|         return chain | ||||
| 
 | ||||
|     def add_marker(self, marker, append=True): | ||||
|     def add_marker( | ||||
|         self, marker: Union[str, MarkDecorator], append: bool = True | ||||
|     ) -> None: | ||||
|         """dynamically add a marker object to the node. | ||||
| 
 | ||||
|         :type marker: ``str`` or ``pytest.mark.*``  object | ||||
|  | @ -168,17 +183,19 @@ class Node: | |||
|             ``append=True`` whether to append the marker, | ||||
|             if ``False`` insert at position ``0``. | ||||
|         """ | ||||
|         from _pytest.mark import MarkDecorator, MARK_GEN | ||||
|         from _pytest.mark import MARK_GEN | ||||
| 
 | ||||
|         if isinstance(marker, str): | ||||
|             marker = getattr(MARK_GEN, marker) | ||||
|         elif not isinstance(marker, MarkDecorator): | ||||
|             raise ValueError("is not a string or pytest.mark.* Marker") | ||||
|         self.keywords[marker.name] = marker | ||||
|         if append: | ||||
|             self.own_markers.append(marker.mark) | ||||
|         if isinstance(marker, MarkDecorator): | ||||
|             marker_ = marker | ||||
|         elif isinstance(marker, str): | ||||
|             marker_ = getattr(MARK_GEN, marker) | ||||
|         else: | ||||
|             self.own_markers.insert(0, marker.mark) | ||||
|             raise ValueError("is not a string or pytest.mark.* Marker") | ||||
|         self.keywords[marker_.name] = marker | ||||
|         if append: | ||||
|             self.own_markers.append(marker_.mark) | ||||
|         else: | ||||
|             self.own_markers.insert(0, marker_.mark) | ||||
| 
 | ||||
|     def iter_markers(self, name=None): | ||||
|         """ | ||||
|  | @ -211,7 +228,7 @@ class Node: | |||
| 
 | ||||
|     def listextrakeywords(self): | ||||
|         """ Return a set of all extra keywords in self and any parents.""" | ||||
|         extra_keywords = set() | ||||
|         extra_keywords = set()  # type: Set[str] | ||||
|         for item in self.listchain(): | ||||
|             extra_keywords.update(item.extra_keyword_matches) | ||||
|         return extra_keywords | ||||
|  | @ -239,7 +256,8 @@ class Node: | |||
|         pass | ||||
| 
 | ||||
|     def _repr_failure_py(self, excinfo, style=None): | ||||
|         if excinfo.errisinstance(fail.Exception): | ||||
|         # Type ignored: see comment where fail.Exception is defined. | ||||
|         if excinfo.errisinstance(fail.Exception):  # type: ignore | ||||
|             if not excinfo.value.pytrace: | ||||
|                 return str(excinfo.value) | ||||
|         fm = self.session._fixturemanager | ||||
|  | @ -385,13 +403,13 @@ class Item(Node): | |||
| 
 | ||||
|     def __init__(self, name, parent=None, config=None, session=None, nodeid=None): | ||||
|         super().__init__(name, parent, config, session, nodeid=nodeid) | ||||
|         self._report_sections = [] | ||||
|         self._report_sections = []  # type: List[Tuple[str, str, str]] | ||||
| 
 | ||||
|         #: user properties is a list of tuples (name, value) that holds user | ||||
|         #: defined properties for this test. | ||||
|         self.user_properties = [] | ||||
|         self.user_properties = []  # type: List[Tuple[str, Any]] | ||||
| 
 | ||||
|     def add_report_section(self, when, key, content): | ||||
|     def add_report_section(self, when: str, key: str, content: str) -> None: | ||||
|         """ | ||||
|         Adds a new report section, similar to what's done internally to add stdout and | ||||
|         stderr captured output:: | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| from pprint import pprint | ||||
| from typing import Optional | ||||
| from typing import Union | ||||
| 
 | ||||
| import py | ||||
| 
 | ||||
|  | @ -221,7 +222,6 @@ class BaseReport: | |||
|                 reprcrash = reportdict["longrepr"]["reprcrash"] | ||||
| 
 | ||||
|                 unserialized_entries = [] | ||||
|                 reprentry = None | ||||
|                 for entry_data in reprtraceback["reprentries"]: | ||||
|                     data = entry_data["data"] | ||||
|                     entry_type = entry_data["type"] | ||||
|  | @ -242,7 +242,7 @@ class BaseReport: | |||
|                             reprlocals=reprlocals, | ||||
|                             filelocrepr=reprfileloc, | ||||
|                             style=data["style"], | ||||
|                         ) | ||||
|                         )  # type: Union[ReprEntry, ReprEntryNative] | ||||
|                     elif entry_type == "ReprEntryNative": | ||||
|                         reprentry = ReprEntryNative(data["lines"]) | ||||
|                     else: | ||||
|  | @ -352,7 +352,8 @@ class TestReport(BaseReport): | |||
|             if not isinstance(excinfo, ExceptionInfo): | ||||
|                 outcome = "failed" | ||||
|                 longrepr = excinfo | ||||
|             elif excinfo.errisinstance(skip.Exception): | ||||
|             # Type ignored -- see comment where skip.Exception is defined. | ||||
|             elif excinfo.errisinstance(skip.Exception):  # type: ignore | ||||
|                 outcome = "skipped" | ||||
|                 r = excinfo._getreprcrash() | ||||
|                 longrepr = (str(r.path), r.lineno, r.message) | ||||
|  |  | |||
|  | @ -3,6 +3,10 @@ import bdb | |||
| import os | ||||
| import sys | ||||
| from time import time | ||||
| from typing import Callable | ||||
| from typing import Dict | ||||
| from typing import List | ||||
| from typing import Tuple | ||||
| 
 | ||||
| import attr | ||||
| 
 | ||||
|  | @ -10,10 +14,14 @@ from .reports import CollectErrorRepr | |||
| from .reports import CollectReport | ||||
| from .reports import TestReport | ||||
| from _pytest._code.code import ExceptionInfo | ||||
| from _pytest.nodes import Node | ||||
| from _pytest.outcomes import Exit | ||||
| from _pytest.outcomes import Skipped | ||||
| from _pytest.outcomes import TEST_OUTCOME | ||||
| 
 | ||||
| if False:  # TYPE_CHECKING | ||||
|     from typing import Type | ||||
| 
 | ||||
| # | ||||
| # pytest plugin hooks | ||||
| 
 | ||||
|  | @ -118,6 +126,7 @@ def pytest_runtest_call(item): | |||
|     except Exception: | ||||
|         # Store trace info to allow postmortem debugging | ||||
|         type, value, tb = sys.exc_info() | ||||
|         assert tb is not None | ||||
|         tb = tb.tb_next  # Skip *this* frame | ||||
|         sys.last_type = type | ||||
|         sys.last_value = value | ||||
|  | @ -185,7 +194,7 @@ def check_interactive_exception(call, report): | |||
| def call_runtest_hook(item, when, **kwds): | ||||
|     hookname = "pytest_runtest_" + when | ||||
|     ihook = getattr(item.ihook, hookname) | ||||
|     reraise = (Exit,) | ||||
|     reraise = (Exit,)  # type: Tuple[Type[BaseException], ...] | ||||
|     if not item.config.getoption("usepdb", False): | ||||
|         reraise += (KeyboardInterrupt,) | ||||
|     return CallInfo.from_call( | ||||
|  | @ -252,7 +261,8 @@ def pytest_make_collect_report(collector): | |||
|         skip_exceptions = [Skipped] | ||||
|         unittest = sys.modules.get("unittest") | ||||
|         if unittest is not None: | ||||
|             skip_exceptions.append(unittest.SkipTest) | ||||
|             # Type ignored because unittest is loaded dynamically. | ||||
|             skip_exceptions.append(unittest.SkipTest)  # type: ignore | ||||
|         if call.excinfo.errisinstance(tuple(skip_exceptions)): | ||||
|             outcome = "skipped" | ||||
|             r = collector._repr_failure_py(call.excinfo, "line").reprcrash | ||||
|  | @ -266,7 +276,7 @@ def pytest_make_collect_report(collector): | |||
|     rep = CollectReport( | ||||
|         collector.nodeid, outcome, longrepr, getattr(call, "result", None) | ||||
|     ) | ||||
|     rep.call = call  # see collect_one_node | ||||
|     rep.call = call  # type: ignore # see collect_one_node | ||||
|     return rep | ||||
| 
 | ||||
| 
 | ||||
|  | @ -274,8 +284,8 @@ class SetupState: | |||
|     """ shared state for setting up/tearing down test items or collectors. """ | ||||
| 
 | ||||
|     def __init__(self): | ||||
|         self.stack = [] | ||||
|         self._finalizers = {} | ||||
|         self.stack = []  # type: List[Node] | ||||
|         self._finalizers = {}  # type: Dict[Node, List[Callable[[], None]]] | ||||
| 
 | ||||
|     def addfinalizer(self, finalizer, colitem): | ||||
|         """ attach a finalizer to the given colitem. """ | ||||
|  | @ -302,6 +312,7 @@ class SetupState: | |||
|                     exc = sys.exc_info() | ||||
|         if exc: | ||||
|             _, val, tb = exc | ||||
|             assert val is not None | ||||
|             raise val.with_traceback(tb) | ||||
| 
 | ||||
|     def _teardown_with_finalization(self, colitem): | ||||
|  | @ -335,6 +346,7 @@ class SetupState: | |||
|                     exc = sys.exc_info() | ||||
|         if exc: | ||||
|             _, val, tb = exc | ||||
|             assert val is not None | ||||
|             raise val.with_traceback(tb) | ||||
| 
 | ||||
|     def prepare(self, colitem): | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue