55import tempfile
66from configparser import ConfigParser
77from 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+ )
918
19+ import py
1020import pytest
1121from _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
1324from _pytest .config import Config
1425from mypy import build
1526from mypy .fscache import FileSystemCache
1627from mypy .main import process_options
17- from py ._io .terminalwriter import TerminalWriter
28+
29+ if TYPE_CHECKING :
30+ from _pytest ._code .code import _TracebackStyle
1831
1932from pytest_mypy_plugins import utils
2033from pytest_mypy_plugins .collect import File , YamlTestFile
2841
2942class TraceLastReprEntry (ReprEntry ):
3043 def toterminal (self , tw : TerminalWriter ) -> None :
44+ if not self .reprfileloc :
45+ return
46+
3147 self .reprfileloc .toterminal (tw )
3248 for line in self .lines :
3349 red = line .startswith ("E " )
@@ -56,6 +72,12 @@ def replace_fpath_with_module_name(line: str, rootdir: Path) -> str:
5672 return line .strip ().replace (".py:" , ":" )
5773
5874
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+
5981class ReturnCodes :
6082 SUCCESS = 0
6183 FAIL = 1
@@ -174,22 +196,11 @@ def typecheck_in_new_subprocess(
174196 mypy_executable = distutils .spawn .find_executable ("mypy" )
175197 assert mypy_executable is not None , "mypy executable is not found"
176198
199+ rootdir = getattr (getattr (self .parent , "config" , None ), "rootdir" , None )
177200 # 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 )
185202 # 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 )
193204
194205 # Windows requires this to be set, otherwise the interpreter crashes
195206 if "SYSTEMROOT" in os .environ :
@@ -313,7 +324,9 @@ def prepare_mypy_cmd_options(self, execution_path: Path) -> List[str]:
313324
314325 return mypy_cmd_options
315326
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 ]:
317330 if excinfo .errisinstance (SystemExit ):
318331 # We assume that before doing exit() (which raises SystemExit) we've printed
319332 # enough context about what happened so that a stack trace is not useful.
@@ -323,9 +336,9 @@ def repr_failure(self, excinfo: ExceptionInfo) -> str:
323336 elif excinfo .errisinstance (TypecheckAssertionError ):
324337 # with traceback removed
325338 exception_repr = excinfo .getrepr (style = "short" )
326- exception_repr .reprcrash .message = ""
339+ exception_repr .reprcrash .message = "" # type: ignore
327340 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
329342 )
330343 repr_tb_entry = TraceLastReprEntry (
331344 exception_repr .reprtraceback .reprentries [- 1 ].lines [1 :], None , None , repr_file_location , "short"
@@ -335,5 +348,41 @@ def repr_failure(self, excinfo: ExceptionInfo) -> str:
335348 else :
336349 return super ().repr_failure (excinfo , style = "native" )
337350
338- def reportinfo (self ) -> Tuple [str , Optional [str ], str ]:
351+ def reportinfo (self ) -> Tuple [Union [ py . path . local , str ] , Optional [int ], str ]:
339352 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