Skip to content

Commit 202dd9f

Browse files
committed
pytester: add & use our own copytree instead of py.path's
Fixes the TODO note.
1 parent ccdadb6 commit 202dd9f

File tree

2 files changed

+21
-5
lines changed

2 files changed

+21
-5
lines changed

src/_pytest/pathlib.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ def resolve_package_path(path: Path) -> Optional[Path]:
583583

584584

585585
def visit(
586-
path: str, recurse: Callable[["os.DirEntry[str]"], bool]
586+
path: Union[str, "os.PathLike[str]"], recurse: Callable[["os.DirEntry[str]"], bool]
587587
) -> Iterator["os.DirEntry[str]"]:
588588
"""Walk a directory recursively, in breadth-first order.
589589
@@ -657,3 +657,21 @@ def bestrelpath(directory: Path, dest: Path) -> str:
657657
# Forward from base to dest.
658658
*reldest.parts,
659659
)
660+
661+
662+
# Originates from py. path.local.copy(), with siginficant trims and adjustments.
663+
# TODO(py38): Replace with shutil.copytree(..., symlinks=True, dirs_exist_ok=True)
664+
def copytree(source: Path, target: Path) -> None:
665+
"""Recursively copy a source directory to target."""
666+
assert source.is_dir()
667+
for entry in visit(source, recurse=lambda entry: not entry.is_symlink()):
668+
x = Path(entry)
669+
relpath = x.relative_to(source)
670+
newx = target / relpath
671+
newx.parent.mkdir(exist_ok=True)
672+
if x.is_symlink():
673+
newx.symlink_to(os.readlink(x))
674+
elif x.is_file():
675+
shutil.copyfile(x, newx)
676+
elif x.is_dir():
677+
newx.mkdir(exist_ok=True)

src/_pytest/pytester.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
from _pytest.outcomes import importorskip
6464
from _pytest.outcomes import skip
6565
from _pytest.pathlib import bestrelpath
66+
from _pytest.pathlib import copytree
6667
from _pytest.pathlib import make_numbered_dir
6768
from _pytest.reports import CollectReport
6869
from _pytest.reports import TestReport
@@ -935,10 +936,7 @@ def copy_example(self, name: Optional[str] = None) -> Path:
935936
example_path = example_dir.joinpath(name)
936937

937938
if example_path.is_dir() and not example_path.joinpath("__init__.py").is_file():
938-
# TODO: legacy_path.copy can copy files to existing directories,
939-
# while with shutil.copytree the destination directory cannot exist,
940-
# we will need to roll our own in order to drop legacy_path completely
941-
legacy_path(example_path).copy(legacy_path(self.path))
939+
copytree(example_path, self.path)
942940
return self.path
943941
elif example_path.is_file():
944942
result = self.path.joinpath(example_path.name)

0 commit comments

Comments
 (0)