5
5
import tempfile
6
6
from configparser import ConfigParser
7
7
from pathlib import Path
8
- from typing import Any , Callable , Dict , List , Optional , Tuple
8
+ from typing import (
9
+ TYPE_CHECKING ,
10
+ Any ,
11
+ Callable ,
12
+ Dict ,
13
+ List ,
14
+ Optional ,
15
+ Tuple ,
16
+ Union ,
17
+ )
9
18
19
+ import py
10
20
import pytest
11
21
from _pytest ._code import ExceptionInfo
12
- from _pytest ._code .code import ReprEntry , ReprFileLocation
22
+ from _pytest ._code .code import ReprEntry , ReprFileLocation , TerminalRepr
23
+ from _pytest ._io import TerminalWriter
13
24
from _pytest .config import Config
14
25
from mypy import build
15
26
from mypy .fscache import FileSystemCache
16
27
from mypy .main import process_options
17
- from py ._io .terminalwriter import TerminalWriter
28
+
29
+ if TYPE_CHECKING :
30
+ from _pytest ._code .code import _TracebackStyle
18
31
19
32
from pytest_mypy_plugins import utils
20
33
from pytest_mypy_plugins .collect import File , YamlTestFile
28
41
29
42
class TraceLastReprEntry (ReprEntry ):
30
43
def toterminal (self , tw : TerminalWriter ) -> None :
44
+ if not self .reprfileloc :
45
+ return
46
+
31
47
self .reprfileloc .toterminal (tw )
32
48
for line in self .lines :
33
49
red = line .startswith ("E " )
@@ -56,6 +72,12 @@ def replace_fpath_with_module_name(line: str, rootdir: Path) -> str:
56
72
return line .strip ().replace (".py:" , ":" )
57
73
58
74
75
+ def maybe_to_abspath (rel_or_abs : str , rootdir : Optional [Path ]) -> str :
76
+ if rootdir is None or os .path .isabs (rel_or_abs ):
77
+ return rel_or_abs
78
+ return str (rootdir / rel_or_abs )
79
+
80
+
59
81
class ReturnCodes :
60
82
SUCCESS = 0
61
83
FAIL = 1
@@ -174,22 +196,11 @@ def typecheck_in_new_subprocess(
174
196
mypy_executable = distutils .spawn .find_executable ("mypy" )
175
197
assert mypy_executable is not None , "mypy executable is not found"
176
198
199
+ rootdir = getattr (getattr (self .parent , "config" , None ), "rootdir" , None )
177
200
# add current directory to path
178
- self .environment_variables ["PYTHONPATH" ] = ":" .join (
179
- [
180
- os .environ .get ("PYTHONPATH" , "" ),
181
- str (execution_path ),
182
- ]
183
- )
184
-
201
+ self ._collect_python_path (rootdir , execution_path )
185
202
# adding proper MYPYPATH variable
186
- mypy_path_parts = []
187
- existing_mypy_path = os .environ .get ("MYPYPATH" , "" )
188
- if existing_mypy_path :
189
- mypy_path_parts .append (existing_mypy_path )
190
- if self .base_ini_fpath :
191
- mypy_path_parts .append (os .path .dirname (self .base_ini_fpath ))
192
- self .environment_variables ["MYPYPATH" ] = ":" .join (mypy_path_parts )
203
+ self ._collect_mypy_path (rootdir )
193
204
194
205
# Windows requires this to be set, otherwise the interpreter crashes
195
206
if "SYSTEMROOT" in os .environ :
@@ -313,7 +324,9 @@ def prepare_mypy_cmd_options(self, execution_path: Path) -> List[str]:
313
324
314
325
return mypy_cmd_options
315
326
316
- def repr_failure (self , excinfo : ExceptionInfo ) -> str :
327
+ def repr_failure (
328
+ self , excinfo : ExceptionInfo [BaseException ], style : Optional ["_TracebackStyle" ] = None
329
+ ) -> Union [str , TerminalRepr ]:
317
330
if excinfo .errisinstance (SystemExit ):
318
331
# We assume that before doing exit() (which raises SystemExit) we've printed
319
332
# enough context about what happened so that a stack trace is not useful.
@@ -323,9 +336,9 @@ def repr_failure(self, excinfo: ExceptionInfo) -> str:
323
336
elif excinfo .errisinstance (TypecheckAssertionError ):
324
337
# with traceback removed
325
338
exception_repr = excinfo .getrepr (style = "short" )
326
- exception_repr .reprcrash .message = ""
339
+ exception_repr .reprcrash .message = "" # type: ignore
327
340
repr_file_location = ReprFileLocation (
328
- path = self .fspath , lineno = self .starting_lineno + excinfo .value .lineno , message = ""
341
+ path = self .fspath , lineno = self .starting_lineno + excinfo .value .lineno , message = "" # type: ignore
329
342
)
330
343
repr_tb_entry = TraceLastReprEntry (
331
344
exception_repr .reprtraceback .reprentries [- 1 ].lines [1 :], None , None , repr_file_location , "short"
@@ -335,5 +348,41 @@ def repr_failure(self, excinfo: ExceptionInfo) -> str:
335
348
else :
336
349
return super ().repr_failure (excinfo , style = "native" )
337
350
338
- def reportinfo (self ) -> Tuple [str , Optional [str ], str ]:
351
+ def reportinfo (self ) -> Tuple [Union [ py . path . local , str ] , Optional [int ], str ]:
339
352
return self .fspath , None , self .name
353
+
354
+ def _collect_python_path (
355
+ self ,
356
+ rootdir : Optional [Path ],
357
+ execution_path : Path ,
358
+ ) -> None :
359
+ python_path_parts = []
360
+
361
+ existing_python_path = os .environ .get ("PYTHONPATH" )
362
+ if existing_python_path :
363
+ python_path_parts .append (existing_python_path )
364
+ if execution_path :
365
+ python_path_parts .append (str (execution_path ))
366
+ python_path_key = self .environment_variables .get ("PYTHONPATH" )
367
+ if python_path_key :
368
+ python_path_parts .append (
369
+ maybe_to_abspath (python_path_key , rootdir ),
370
+ )
371
+
372
+ self .environment_variables ["PYTHONPATH" ] = ":" .join (python_path_parts )
373
+
374
+ def _collect_mypy_path (self , rootdir : Optional [Path ]) -> None :
375
+ mypy_path_parts = []
376
+
377
+ existing_mypy_path = os .environ .get ("MYPYPATH" )
378
+ if existing_mypy_path :
379
+ mypy_path_parts .append (existing_mypy_path )
380
+ if self .base_ini_fpath :
381
+ mypy_path_parts .append (os .path .dirname (self .base_ini_fpath ))
382
+ mypy_path_key = self .environment_variables .get ("MYPYPATH" )
383
+ if mypy_path_key :
384
+ mypy_path_parts .append (
385
+ maybe_to_abspath (mypy_path_key , rootdir ),
386
+ )
387
+
388
+ self .environment_variables ["MYPYPATH" ] = ":" .join (mypy_path_parts )
0 commit comments