Skip to content

Commit 63bcb99

Browse files
committed
Replace some usages of config.{rootdir,inifile} with config.{rootpath,inipath}
1 parent 7c1ce06 commit 63bcb99

File tree

10 files changed

+116
-99
lines changed

10 files changed

+116
-99
lines changed

src/_pytest/cacheprovider.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def clear_cache(cls, cachedir: Path) -> None:
7878

7979
@staticmethod
8080
def cache_dir_from_config(config: Config) -> Path:
81-
return resolve_from_str(config.getini("cache_dir"), config.rootdir)
81+
return resolve_from_str(config.getini("cache_dir"), config.rootpath)
8282

8383
def warn(self, fmt: str, **args: object) -> None:
8484
import warnings
@@ -264,7 +264,7 @@ def __init__(self, config: Config) -> None:
264264

265265
def get_last_failed_paths(self) -> Set[Path]:
266266
"""Return a set with all Paths()s of the previously failed nodeids."""
267-
rootpath = Path(str(self.config.rootdir))
267+
rootpath = self.config.rootpath
268268
result = {rootpath / nodeid.split("::")[0] for nodeid in self.lastfailed}
269269
return {x for x in result if x.exists()}
270270

@@ -495,7 +495,7 @@ def pytest_report_header(config: Config) -> Optional[str]:
495495
# starting with .., ../.. if sensible
496496

497497
try:
498-
displaypath = cachedir.relative_to(str(config.rootdir))
498+
displaypath = cachedir.relative_to(config.rootpath)
499499
except ValueError:
500500
displaypath = cachedir
501501
return "cachedir: {}".format(displaypath)

src/_pytest/config/__init__.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
from _pytest.compat import TYPE_CHECKING
4646
from _pytest.outcomes import fail
4747
from _pytest.outcomes import Skipped
48+
from _pytest.pathlib import bestrelpath
4849
from _pytest.pathlib import import_path
4950
from _pytest.pathlib import ImportMode
5051
from _pytest.pathlib import Path
@@ -1008,9 +1009,9 @@ def notify_exception(
10081009

10091010
def cwd_relative_nodeid(self, nodeid: str) -> str:
10101011
# nodeid's are relative to the rootpath, compute relative to cwd.
1011-
if self.invocation_dir != self.rootdir:
1012-
fullpath = self.rootdir.join(nodeid)
1013-
nodeid = self.invocation_dir.bestrelpath(fullpath)
1012+
if self.invocation_params.dir != self.rootpath:
1013+
fullpath = self.rootpath / nodeid
1014+
nodeid = bestrelpath(self.invocation_params.dir, fullpath)
10141015
return nodeid
10151016

10161017
@classmethod
@@ -1048,8 +1049,8 @@ def _initini(self, args: Sequence[str]) -> None:
10481049
self.rootpath = rootpath
10491050
self.inipath = inipath
10501051
self.inicfg = inicfg
1051-
self._parser.extra_info["rootdir"] = self.rootdir
1052-
self._parser.extra_info["inifile"] = self.inifile
1052+
self._parser.extra_info["rootdir"] = str(self.rootpath)
1053+
self._parser.extra_info["inifile"] = str(self.inipath)
10531054
self._parser.addini("addopts", "extra command line options", "args")
10541055
self._parser.addini("minversion", "minimally required pytest version")
10551056
self._parser.addini(
@@ -1138,9 +1139,8 @@ def _preparse(self, args: List[str], addopts: bool = True) -> None:
11381139
args, namespace=copy.copy(self.option)
11391140
)
11401141
self._validate_plugins()
1141-
if self.known_args_namespace.confcutdir is None and self.inifile:
1142-
confcutdir = py.path.local(self.inifile).dirname
1143-
self.known_args_namespace.confcutdir = confcutdir
1142+
if self.known_args_namespace.confcutdir is None and self.inipath:
1143+
self.known_args_namespace.confcutdir = str(self.inipath.parent)
11441144
try:
11451145
self.hook.pytest_load_initial_conftests(
11461146
early_config=self, args=args, parser=self._parser
@@ -1172,13 +1172,13 @@ def _checkversion(self) -> None:
11721172

11731173
if not isinstance(minver, str):
11741174
raise pytest.UsageError(
1175-
"%s: 'minversion' must be a single value" % self.inifile
1175+
"%s: 'minversion' must be a single value" % self.inipath
11761176
)
11771177

11781178
if Version(minver) > Version(pytest.__version__):
11791179
raise pytest.UsageError(
11801180
"%s: 'minversion' requires pytest-%s, actual pytest-%s'"
1181-
% (self.inifile, minver, pytest.__version__,)
1181+
% (self.inipath, minver, pytest.__version__,)
11821182
)
11831183

11841184
def _validate_keys(self) -> None:
@@ -1248,10 +1248,10 @@ def parse(self, args: List[str], addopts: bool = True) -> None:
12481248
args, self.option, namespace=self.option
12491249
)
12501250
if not args:
1251-
if self.invocation_dir == self.rootdir:
1251+
if self.invocation_params.dir == self.rootpath:
12521252
args = self.getini("testpaths")
12531253
if not args:
1254-
args = [str(self.invocation_dir)]
1254+
args = [str(self.invocation_params.dir)]
12551255
self.args = args
12561256
except PrintHelp:
12571257
pass
@@ -1311,10 +1311,10 @@ def _getini(self, name: str):
13111311
#
13121312
if type == "pathlist":
13131313
# TODO: This assert is probably not valid in all cases.
1314-
assert self.inifile is not None
1315-
dp = py.path.local(self.inifile).dirpath()
1314+
assert self.inipath is not None
1315+
dp = self.inipath.parent
13161316
input_values = shlex.split(value) if isinstance(value, str) else value
1317-
return [dp.join(x, abs=True) for x in input_values]
1317+
return [py.path.local(str(dp / x)) for x in input_values]
13181318
elif type == "args":
13191319
return shlex.split(value) if isinstance(value, str) else value
13201320
elif type == "linelist":

src/_pytest/fixtures.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
from _pytest.mark import ParameterSet
5151
from _pytest.outcomes import fail
5252
from _pytest.outcomes import TEST_OUTCOME
53+
from _pytest.pathlib import absolutepath
5354

5455
if TYPE_CHECKING:
5556
from typing import Deque
@@ -1450,7 +1451,7 @@ def getfixtureinfo(
14501451
def pytest_plugin_registered(self, plugin: _PluggyPlugin) -> None:
14511452
nodeid = None
14521453
try:
1453-
p = py.path.local(plugin.__file__) # type: ignore[attr-defined]
1454+
p = absolutepath(plugin.__file__) # type: ignore[attr-defined]
14541455
except AttributeError:
14551456
pass
14561457
else:
@@ -1459,8 +1460,13 @@ def pytest_plugin_registered(self, plugin: _PluggyPlugin) -> None:
14591460
# Construct the base nodeid which is later used to check
14601461
# what fixtures are visible for particular tests (as denoted
14611462
# by their test id).
1462-
if p.basename.startswith("conftest.py"):
1463-
nodeid = p.dirpath().relto(self.config.rootdir)
1463+
if p.name.startswith("conftest.py"):
1464+
try:
1465+
nodeid = str(p.parent.relative_to(self.config.rootpath))
1466+
except ValueError:
1467+
nodeid = ""
1468+
if nodeid == ".":
1469+
nodeid = ""
14641470
if os.sep != nodes.SEP:
14651471
nodeid = nodeid.replace(os.sep, nodes.SEP)
14661472

src/_pytest/logging.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ def set_log_path(self, fname: str) -> None:
603603
fpath = Path(fname)
604604

605605
if not fpath.is_absolute():
606-
fpath = Path(str(self._config.rootdir), fpath)
606+
fpath = self._config.rootpath / fpath
607607

608608
if not fpath.parent.exists():
609609
fpath.parent.mkdir(exist_ok=True, parents=True)

src/_pytest/main.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from _pytest.fixtures import FixtureManager
3434
from _pytest.outcomes import exit
3535
from _pytest.pathlib import absolutepath
36+
from _pytest.pathlib import bestrelpath
3637
from _pytest.pathlib import Path
3738
from _pytest.pathlib import visit
3839
from _pytest.reports import CollectReport
@@ -417,11 +418,11 @@ class Failed(Exception):
417418

418419

419420
@attr.s
420-
class _bestrelpath_cache(Dict[py.path.local, str]):
421-
path = attr.ib(type=py.path.local)
421+
class _bestrelpath_cache(Dict[Path, str]):
422+
path = attr.ib(type=Path)
422423

423-
def __missing__(self, path: py.path.local) -> str:
424-
r = self.path.bestrelpath(path) # type: str
424+
def __missing__(self, path: Path) -> str:
425+
r = bestrelpath(self.path, path)
425426
self[path] = r
426427
return r
427428

@@ -436,8 +437,8 @@ class Session(nodes.FSCollector):
436437
exitstatus = None # type: Union[int, ExitCode]
437438

438439
def __init__(self, config: Config) -> None:
439-
nodes.FSCollector.__init__(
440-
self, config.rootdir, parent=None, config=config, session=self, nodeid=""
440+
super().__init__(
441+
config.rootdir, parent=None, config=config, session=self, nodeid=""
441442
)
442443
self.testsfailed = 0
443444
self.testscollected = 0
@@ -462,8 +463,8 @@ def __init__(self, config: Config) -> None:
462463
self._collection_pkg_roots = {} # type: Dict[str, Package]
463464

464465
self._bestrelpathcache = _bestrelpath_cache(
465-
config.rootdir
466-
) # type: Dict[py.path.local, str]
466+
config.rootpath
467+
) # type: Dict[Path, str]
467468

468469
self.config.pluginmanager.register(self, name="session")
469470

@@ -481,7 +482,7 @@ def __repr__(self) -> str:
481482
self.testscollected,
482483
)
483484

484-
def _node_location_to_relpath(self, node_path: py.path.local) -> str:
485+
def _node_location_to_relpath(self, node_path: Path) -> str:
485486
# bestrelpath is a quite slow function.
486487
return self._bestrelpathcache[node_path]
487488

@@ -589,7 +590,9 @@ def _perform_collect( # noqa: F811
589590
self.items = items = [] # type: List[nodes.Item]
590591
for arg in args:
591592
fspath, parts = resolve_collection_argument(
592-
self.config.invocation_dir, arg, as_pypath=self.config.option.pyargs
593+
self.config.invocation_params.dir,
594+
arg,
595+
as_pypath=self.config.option.pyargs,
593596
)
594597
self._initial_parts.append((fspath, parts))
595598
initialpaths.append(fspath)
@@ -800,7 +803,7 @@ def search_pypath(module_name: str) -> str:
800803

801804

802805
def resolve_collection_argument(
803-
invocation_dir: py.path.local, arg: str, *, as_pypath: bool = False
806+
invocation_path: Path, arg: str, *, as_pypath: bool = False
804807
) -> Tuple[py.path.local, List[str]]:
805808
"""Parse path arguments optionally containing selection parts and return (fspath, names).
806809
@@ -827,7 +830,7 @@ def resolve_collection_argument(
827830
strpath, *parts = str(arg).split("::")
828831
if as_pypath:
829832
strpath = search_pypath(strpath)
830-
fspath = Path(str(invocation_dir), strpath)
833+
fspath = invocation_path / strpath
831834
fspath = absolutepath(fspath)
832835
if not fspath.exists():
833836
msg = (

src/_pytest/nodes.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from _pytest.mark.structures import MarkDecorator
3333
from _pytest.mark.structures import NodeKeywords
3434
from _pytest.outcomes import fail
35+
from _pytest.pathlib import absolutepath
3536
from _pytest.pathlib import Path
3637
from _pytest.store import Store
3738

@@ -402,7 +403,7 @@ def _repr_failure_py(
402403
# It will be better to just always display paths relative to invocation_dir, but
403404
# this requires a lot of plumbing (#6428).
404405
try:
405-
abspath = Path(os.getcwd()) != Path(str(self.config.invocation_dir))
406+
abspath = Path(os.getcwd()) != self.config.invocation_params.dir
406407
except OSError:
407408
abspath = True
408409

@@ -633,10 +634,7 @@ def reportinfo(self) -> Tuple[Union[py.path.local, str], Optional[int], str]:
633634
@cached_property
634635
def location(self) -> Tuple[str, Optional[int], str]:
635636
location = self.reportinfo()
636-
if isinstance(location[0], py.path.local):
637-
fspath = location[0]
638-
else:
639-
fspath = py.path.local(location[0])
637+
fspath = absolutepath(str(location[0]))
640638
relfspath = self.session._node_location_to_relpath(fspath)
641639
assert type(location[2]) is str
642640
return (relfspath, location[1], location[2])

src/_pytest/pathlib.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,7 @@ def make_numbered_dir_with_cleanup(
366366
raise e
367367

368368

369-
def resolve_from_str(input: str, root: py.path.local) -> Path:
370-
rootpath = Path(root)
369+
def resolve_from_str(input: str, rootpath: Path) -> Path:
371370
input = expanduser(input)
372371
input = expandvars(input)
373372
if isabs(input):

src/_pytest/terminal.py

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
from _pytest.config.argparsing import Parser
4141
from _pytest.nodes import Item
4242
from _pytest.nodes import Node
43+
from _pytest.pathlib import absolutepath
44+
from _pytest.pathlib import bestrelpath
45+
from _pytest.pathlib import Path
4346
from _pytest.reports import BaseReport
4447
from _pytest.reports import CollectReport
4548
from _pytest.reports import TestReport
@@ -297,9 +300,9 @@ def get_location(self, config: Config) -> Optional[str]:
297300
if self.fslocation:
298301
if isinstance(self.fslocation, tuple) and len(self.fslocation) >= 2:
299302
filename, linenum = self.fslocation[:2]
300-
relpath = py.path.local(filename).relto(config.invocation_dir)
301-
if not relpath:
302-
relpath = str(filename)
303+
relpath = bestrelpath(
304+
config.invocation_params.dir, absolutepath(filename)
305+
)
303306
return "{}:{}".format(relpath, linenum)
304307
else:
305308
return str(self.fslocation)
@@ -319,11 +322,12 @@ def __init__(self, config: Config, file: Optional[TextIO] = None) -> None:
319322
self._main_color = None # type: Optional[str]
320323
self._known_types = None # type: Optional[List[str]]
321324
self.startdir = config.invocation_dir
325+
self.startpath = config.invocation_params.dir
322326
if file is None:
323327
file = sys.stdout
324328
self._tw = _pytest.config.create_terminal_writer(config, file)
325329
self._screen_width = self._tw.fullwidth
326-
self.currentfspath = None # type: Any
330+
self.currentfspath = None # type: Union[None, Path, str, int]
327331
self.reportchars = getreportopt(config)
328332
self.hasmarkup = self._tw.hasmarkup
329333
self.isatty = file.isatty()
@@ -385,19 +389,17 @@ def hasopt(self, char: str) -> bool:
385389
return char in self.reportchars
386390

387391
def write_fspath_result(self, nodeid: str, res, **markup: bool) -> None:
388-
fspath = self.config.rootdir.join(nodeid.split("::")[0])
389-
# NOTE: explicitly check for None to work around py bug, and for less
390-
# overhead in general (https://github.com/pytest-dev/py/pull/207).
392+
fspath = self.config.rootpath / nodeid.split("::")[0]
391393
if self.currentfspath is None or fspath != self.currentfspath:
392394
if self.currentfspath is not None and self._show_progress_info:
393395
self._write_progress_information_filling_space()
394396
self.currentfspath = fspath
395-
relfspath = self.startdir.bestrelpath(fspath)
397+
relfspath = bestrelpath(self.startpath, fspath)
396398
self._tw.line()
397399
self._tw.write(relfspath + " ")
398400
self._tw.write(res, flush=True, **markup)
399401

400-
def write_ensure_prefix(self, prefix, extra: str = "", **kwargs) -> None:
402+
def write_ensure_prefix(self, prefix: str, extra: str = "", **kwargs) -> None:
401403
if self.currentfspath != prefix:
402404
self._tw.line()
403405
self.currentfspath = prefix
@@ -709,14 +711,14 @@ def _write_report_lines_from_hooks(
709711
self.write_line(line)
710712

711713
def pytest_report_header(self, config: Config) -> List[str]:
712-
line = "rootdir: %s" % config.rootdir
714+
line = "rootdir: %s" % config.rootpath
713715

714-
if config.inifile:
715-
line += ", configfile: " + config.rootdir.bestrelpath(config.inifile)
716+
if config.inipath:
717+
line += ", configfile: " + bestrelpath(config.rootpath, config.inipath)
716718

717719
testpaths = config.getini("testpaths")
718720
if testpaths and config.args == testpaths:
719-
rel_paths = [config.rootdir.bestrelpath(x) for x in testpaths]
721+
rel_paths = [bestrelpath(config.rootpath, x) for x in testpaths]
720722
line += ", testpaths: {}".format(", ".join(rel_paths))
721723
result = [line]
722724

@@ -860,7 +862,7 @@ def mkrel(nodeid):
860862
if self.verbosity >= 2 and nodeid.split("::")[0] != fspath.replace(
861863
"\\", nodes.SEP
862864
):
863-
res += " <- " + self.startdir.bestrelpath(fspath)
865+
res += " <- " + bestrelpath(self.startpath, fspath)
864866
else:
865867
res = "[location]"
866868
return res + " "
@@ -1102,7 +1104,7 @@ def show_xpassed(lines: List[str]) -> None:
11021104

11031105
def show_skipped(lines: List[str]) -> None:
11041106
skipped = self.stats.get("skipped", []) # type: List[CollectReport]
1105-
fskips = _folded_skips(self.startdir, skipped) if skipped else []
1107+
fskips = _folded_skips(self.startpath, skipped) if skipped else []
11061108
if not fskips:
11071109
return
11081110
verbose_word = skipped[0]._get_verbose_word(self.config)
@@ -1230,7 +1232,7 @@ def _get_line_with_reprcrash_message(
12301232

12311233

12321234
def _folded_skips(
1233-
startdir: py.path.local, skipped: Sequence[CollectReport],
1235+
startpath: Path, skipped: Sequence[CollectReport],
12341236
) -> List[Tuple[int, str, Optional[int], str]]:
12351237
d = {} # type: Dict[Tuple[str, Optional[int], str], List[CollectReport]]
12361238
for event in skipped:
@@ -1239,7 +1241,7 @@ def _folded_skips(
12391241
assert len(event.longrepr) == 3, (event, event.longrepr)
12401242
fspath, lineno, reason = event.longrepr
12411243
# For consistency, report all fspaths in relative form.
1242-
fspath = startdir.bestrelpath(py.path.local(fspath))
1244+
fspath = bestrelpath(startpath, Path(fspath))
12431245
keywords = getattr(event, "keywords", {})
12441246
# Folding reports with global pytestmark variable.
12451247
# This is a workaround, because for now we cannot identify the scope of a skip marker

0 commit comments

Comments
 (0)