Fix some type errors around py.path.local

These errors are found using a typed version of py.path.local.
This commit is contained in:
Ran Benita 2020-06-12 15:52:22 +03:00
parent 0256cb3aae
commit 1cf9405075
11 changed files with 36 additions and 29 deletions

View File

@ -23,6 +23,8 @@ from typing import Set
from typing import Tuple from typing import Tuple
from typing import Union from typing import Union
import py
from _pytest._io.saferepr import saferepr from _pytest._io.saferepr import saferepr
from _pytest._version import version from _pytest._version import version
from _pytest.assertion import util from _pytest.assertion import util
@ -177,10 +179,10 @@ class AssertionRewritingHook(importlib.abc.MetaPathFinder, importlib.abc.Loader)
""" """
if self.session is not None and not self._session_paths_checked: if self.session is not None and not self._session_paths_checked:
self._session_paths_checked = True self._session_paths_checked = True
for path in self.session._initialpaths: for initial_path in self.session._initialpaths:
# Make something as c:/projects/my_project/path.py -> # Make something as c:/projects/my_project/path.py ->
# ['c:', 'projects', 'my_project', 'path.py'] # ['c:', 'projects', 'my_project', 'path.py']
parts = str(path).split(os.path.sep) parts = str(initial_path).split(os.path.sep)
# add 'path' to basenames to be checked. # add 'path' to basenames to be checked.
self._basenames_to_check_rewrite.add(os.path.splitext(parts[-1])[0]) self._basenames_to_check_rewrite.add(os.path.splitext(parts[-1])[0])
@ -213,7 +215,7 @@ class AssertionRewritingHook(importlib.abc.MetaPathFinder, importlib.abc.Loader)
return True return True
if self.session is not None: if self.session is not None:
if self.session.isinitpath(fn): if self.session.isinitpath(py.path.local(fn)):
state.trace( state.trace(
"matched test file (was specified on cmdline): {!r}".format(fn) "matched test file (was specified on cmdline): {!r}".format(fn)
) )

View File

@ -495,7 +495,7 @@ def pytest_report_header(config: Config) -> Optional[str]:
# starting with .., ../.. if sensible # starting with .., ../.. if sensible
try: try:
displaypath = cachedir.relative_to(config.rootdir) displaypath = cachedir.relative_to(str(config.rootdir))
except ValueError: except ValueError:
displaypath = cachedir displaypath = cachedir
return "cachedir: {}".format(displaypath) return "cachedir: {}".format(displaypath)

View File

@ -308,10 +308,9 @@ class PytestPluginManager(PluginManager):
self._dirpath2confmods = {} # type: Dict[Any, List[object]] self._dirpath2confmods = {} # type: Dict[Any, List[object]]
# Maps a py.path.local to a module object. # Maps a py.path.local to a module object.
self._conftestpath2mod = {} # type: Dict[Any, object] self._conftestpath2mod = {} # type: Dict[Any, object]
self._confcutdir = None self._confcutdir = None # type: Optional[py.path.local]
self._noconftest = False self._noconftest = False
# Set of py.path.local's. self._duplicatepaths = set() # type: Set[py.path.local]
self._duplicatepaths = set() # type: Set[Any]
self.add_hookspecs(_pytest.hookspec) self.add_hookspecs(_pytest.hookspec)
self.register(self) self.register(self)
@ -945,13 +944,12 @@ class Config:
ns, unknown_args = self._parser.parse_known_and_unknown_args( ns, unknown_args = self._parser.parse_known_and_unknown_args(
args, namespace=copy.copy(self.option) args, namespace=copy.copy(self.option)
) )
r = determine_setup( self.rootdir, self.inifile, self.inicfg = determine_setup(
ns.inifilename, ns.inifilename,
ns.file_or_dir + unknown_args, ns.file_or_dir + unknown_args,
rootdir_cmd_arg=ns.rootdir or None, rootdir_cmd_arg=ns.rootdir or None,
config=self, config=self,
) )
self.rootdir, self.inifile, self.inicfg = r
self._parser.extra_info["rootdir"] = self.rootdir self._parser.extra_info["rootdir"] = self.rootdir
self._parser.extra_info["inifile"] = self.inifile self._parser.extra_info["inifile"] = self.inifile
self._parser.addini("addopts", "extra command line options", "args") self._parser.addini("addopts", "extra command line options", "args")
@ -1162,6 +1160,8 @@ class Config:
# in this case, we already have a list ready to use # in this case, we already have a list ready to use
# #
if type == "pathlist": if type == "pathlist":
# TODO: This assert is probably not valid in all cases.
assert self.inifile is not None
dp = py.path.local(self.inifile).dirpath() dp = py.path.local(self.inifile).dirpath()
input_values = shlex.split(value) if isinstance(value, str) else value input_values = shlex.split(value) if isinstance(value, str) else value
return [dp.join(x, abs=True) for x in input_values] return [dp.join(x, abs=True) for x in input_values]

View File

@ -63,7 +63,7 @@ def load_config_dict_from_file(
elif filepath.ext == ".toml": elif filepath.ext == ".toml":
import toml import toml
config = toml.load(filepath) config = toml.load(str(filepath))
result = config.get("tool", {}).get("pytest", {}).get("ini_options", None) result = config.get("tool", {}).get("pytest", {}).get("ini_options", None)
if result is not None: if result is not None:
@ -161,16 +161,18 @@ def determine_setup(
args: List[str], args: List[str],
rootdir_cmd_arg: Optional[str] = None, rootdir_cmd_arg: Optional[str] = None,
config: Optional["Config"] = None, config: Optional["Config"] = None,
) -> Tuple[py.path.local, Optional[str], Dict[str, Union[str, List[str]]]]: ) -> Tuple[py.path.local, Optional[py.path.local], Dict[str, Union[str, List[str]]]]:
rootdir = None rootdir = None
dirs = get_dirs_from_args(args) dirs = get_dirs_from_args(args)
if inifile: if inifile:
inicfg = load_config_dict_from_file(py.path.local(inifile)) or {} inipath_ = py.path.local(inifile)
inipath = inipath_ # type: Optional[py.path.local]
inicfg = load_config_dict_from_file(inipath_) or {}
if rootdir_cmd_arg is None: if rootdir_cmd_arg is None:
rootdir = get_common_ancestor(dirs) rootdir = get_common_ancestor(dirs)
else: else:
ancestor = get_common_ancestor(dirs) ancestor = get_common_ancestor(dirs)
rootdir, inifile, inicfg = locate_config([ancestor]) rootdir, inipath, inicfg = locate_config([ancestor])
if rootdir is None and rootdir_cmd_arg is None: if rootdir is None and rootdir_cmd_arg is None:
for possible_rootdir in ancestor.parts(reverse=True): for possible_rootdir in ancestor.parts(reverse=True):
if possible_rootdir.join("setup.py").exists(): if possible_rootdir.join("setup.py").exists():
@ -178,7 +180,7 @@ def determine_setup(
break break
else: else:
if dirs != [ancestor]: if dirs != [ancestor]:
rootdir, inifile, inicfg = locate_config(dirs) rootdir, inipath, inicfg = locate_config(dirs)
if rootdir is None: if rootdir is None:
if config is not None: if config is not None:
cwd = config.invocation_dir cwd = config.invocation_dir
@ -196,4 +198,5 @@ def determine_setup(
rootdir rootdir
) )
) )
return rootdir, inifile, inicfg or {} assert rootdir is not None
return rootdir, inipath, inicfg or {}

View File

@ -586,7 +586,7 @@ class LoggingPlugin:
fpath = Path(fname) fpath = Path(fname)
if not fpath.is_absolute(): if not fpath.is_absolute():
fpath = Path(self._config.rootdir, fpath) fpath = Path(str(self._config.rootdir), fpath)
if not fpath.parent.exists(): if not fpath.parent.exists():
fpath.parent.mkdir(exist_ok=True, parents=True) fpath.parent.mkdir(exist_ok=True, parents=True)

View File

@ -439,7 +439,7 @@ class Session(nodes.FSCollector):
) # type: Dict[Tuple[Type[nodes.Collector], str], CollectReport] ) # type: Dict[Tuple[Type[nodes.Collector], str], CollectReport]
# Dirnames of pkgs with dunder-init files. # Dirnames of pkgs with dunder-init files.
self._collection_pkg_roots = {} # type: Dict[py.path.local, Package] self._collection_pkg_roots = {} # type: Dict[str, Package]
self._bestrelpathcache = _bestrelpath_cache( self._bestrelpathcache = _bestrelpath_cache(
config.rootdir config.rootdir
@ -601,7 +601,7 @@ class Session(nodes.FSCollector):
col = self._collectfile(pkginit, handle_dupes=False) col = self._collectfile(pkginit, handle_dupes=False)
if col: if col:
if isinstance(col[0], Package): if isinstance(col[0], Package):
self._collection_pkg_roots[parent] = col[0] self._collection_pkg_roots[str(parent)] = col[0]
# always store a list in the cache, matchnodes expects it # always store a list in the cache, matchnodes expects it
self._collection_node_cache1[col[0].fspath] = [col[0]] self._collection_node_cache1[col[0].fspath] = [col[0]]
@ -623,8 +623,8 @@ class Session(nodes.FSCollector):
for x in self._collectfile(pkginit): for x in self._collectfile(pkginit):
yield x yield x
if isinstance(x, Package): if isinstance(x, Package):
self._collection_pkg_roots[dirpath] = x self._collection_pkg_roots[str(dirpath)] = x
if dirpath in self._collection_pkg_roots: if str(dirpath) in self._collection_pkg_roots:
# Do not collect packages here. # Do not collect packages here.
continue continue

View File

@ -393,7 +393,7 @@ class Node(metaclass=NodeMeta):
# It will be better to just always display paths relative to invocation_dir, but # It will be better to just always display paths relative to invocation_dir, but
# this requires a lot of plumbing (#6428). # this requires a lot of plumbing (#6428).
try: try:
abspath = Path(os.getcwd()) != Path(self.config.invocation_dir) abspath = Path(os.getcwd()) != Path(str(self.config.invocation_dir))
except OSError: except OSError:
abspath = True abspath = True

View File

@ -656,7 +656,7 @@ class Package(Module):
parts_ = parts(path.strpath) parts_ = parts(path.strpath)
if any( if any(
pkg_prefix in parts_ and pkg_prefix.join("__init__.py") != path str(pkg_prefix) in parts_ and pkg_prefix.join("__init__.py") != path
for pkg_prefix in pkg_prefixes for pkg_prefix in pkg_prefixes
): ):
continue continue
@ -1332,7 +1332,7 @@ def _show_fixtures_per_test(config, session):
def get_best_relpath(func): def get_best_relpath(func):
loc = getlocation(func, curdir) loc = getlocation(func, curdir)
return curdir.bestrelpath(loc) return curdir.bestrelpath(py.path.local(loc))
def write_fixture(fixture_def): def write_fixture(fixture_def):
argname = fixture_def.argname argname = fixture_def.argname
@ -1406,7 +1406,7 @@ def _showfixtures_main(config: Config, session: Session) -> None:
( (
len(fixturedef.baseid), len(fixturedef.baseid),
fixturedef.func.__module__, fixturedef.func.__module__,
curdir.bestrelpath(loc), curdir.bestrelpath(py.path.local(loc)),
fixturedef.argname, fixturedef.argname,
fixturedef, fixturedef,
) )

View File

@ -380,9 +380,9 @@ class TerminalReporter:
if self.currentfspath is not None and self._show_progress_info: if self.currentfspath is not None and self._show_progress_info:
self._write_progress_information_filling_space() self._write_progress_information_filling_space()
self.currentfspath = fspath self.currentfspath = fspath
fspath = self.startdir.bestrelpath(fspath) relfspath = self.startdir.bestrelpath(fspath)
self._tw.line() self._tw.line()
self._tw.write(fspath + " ") self._tw.write(relfspath + " ")
self._tw.write(res, flush=True, **markup) self._tw.write(res, flush=True, **markup)
def write_ensure_prefix(self, prefix, extra: str = "", **kwargs) -> None: def write_ensure_prefix(self, prefix, extra: str = "", **kwargs) -> None:

View File

@ -580,8 +580,9 @@ class TestInvocationVariants:
assert res.ret == 0 assert res.ret == 0
res.stdout.fnmatch_lines(["*1 passed*"]) res.stdout.fnmatch_lines(["*1 passed*"])
def test_equivalence_pytest_pytest(self): def test_equivalence_pytest_pydottest(self) -> None:
assert pytest.main == py.test.cmdline.main # Type ignored because `py.test` is not and will not be typed.
assert pytest.main == py.test.cmdline.main # type: ignore[attr-defined]
def test_invoke_with_invalid_type(self): def test_invoke_with_invalid_type(self):
with pytest.raises( with pytest.raises(

View File

@ -629,13 +629,14 @@ class TestConfigFromdictargs:
) )
with cwd.ensure(dir=True).as_cwd(): with cwd.ensure(dir=True).as_cwd():
config = Config.fromdictargs(option_dict, ()) config = Config.fromdictargs(option_dict, ())
inipath = py.path.local(inifile)
assert config.args == [str(cwd)] assert config.args == [str(cwd)]
assert config.option.inifilename == inifile assert config.option.inifilename == inifile
assert config.option.capture == "no" assert config.option.capture == "no"
# this indicates this is the file used for getting configuration values # this indicates this is the file used for getting configuration values
assert config.inifile == inifile assert config.inifile == inipath
assert config.inicfg.get("name") == "value" assert config.inicfg.get("name") == "value"
assert config.inicfg.get("should_not_be_set") is None assert config.inicfg.get("should_not_be_set") is None