diff --git a/changelog/5017.bugfix.rst b/changelog/5017.bugfix.rst new file mode 100644 index 00000000000..20a64e70cfc --- /dev/null +++ b/changelog/5017.bugfix.rst @@ -0,0 +1 @@ +``pathlib2`` is no longer used, avoiding a number of problems when mixing ``pathlib2.Path`` and ``pathlib.Path`` objects. pytest now always uses the native ``pathlib`` module. diff --git a/doc/en/tmpdir.rst b/doc/en/tmpdir.rst index 01397a5ba2c..d228dd0233a 100644 --- a/doc/en/tmpdir.rst +++ b/doc/en/tmpdir.rst @@ -9,13 +9,11 @@ The ``tmp_path`` fixture ------------------------ - - You can use the ``tmp_path`` fixture which will provide a temporary directory unique to the test invocation, created in the `base temporary directory`_. -``tmp_path`` is a ``pathlib/pathlib2.Path`` object. Here is an example test usage: +``tmp_path`` is a ``pathlib.Path`` object. Here is an example test usage: .. code-block:: python diff --git a/setup.py b/setup.py index 4c87c6429bb..fb110b9fffd 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,6 @@ "attrs>=17.4.0", "more-itertools>=4.0.0", "atomicwrites>=1.0", - 'pathlib2>=2.2.0;python_version<"3.6"', 'colorama;sys_platform=="win32"', "pluggy>=0.12,<1.0", "importlib-metadata>=0.12", diff --git a/src/_pytest/cacheprovider.py b/src/_pytest/cacheprovider.py index 17463959fb4..5cfedb51476 100755 --- a/src/_pytest/cacheprovider.py +++ b/src/_pytest/cacheprovider.py @@ -50,7 +50,7 @@ def for_config(cls, config): @staticmethod def cache_dir_from_config(config): - return resolve_from_str(config.getini("cache_dir"), config.rootdir) + return resolve_from_str(config.getini("cache_dir"), str(config.rootdir)) def warn(self, fmt, **args): from _pytest.warnings import _issue_warning_captured @@ -76,7 +76,8 @@ def makedir(self, name): if len(name.parts) > 1: raise ValueError("name is not allowed to contain path separators") res = self._cachedir.joinpath("d", name) - res.mkdir(exist_ok=True, parents=True) + if not res.is_dir(): + os.makedirs(str(res)) return py.path.local(res) def _getvaluepath(self, key): @@ -115,7 +116,7 @@ def set(self, key, value): cache_dir_exists_already = True else: cache_dir_exists_already = self._cachedir.exists() - path.parent.mkdir(exist_ok=True, parents=True) + os.makedirs(str(path.parent)) except (IOError, OSError): self.warn("could not create cache path {path}", path=path) return @@ -132,14 +133,17 @@ def set(self, key, value): def _ensure_supporting_files(self): """Create supporting files in the cache dir that are not really part of the cache.""" readme_path = self._cachedir / "README.md" - readme_path.write_text(README_CONTENT) + with readme_path.open("w") as f: + f.write(README_CONTENT) gitignore_path = self._cachedir.joinpath(".gitignore") msg = "# Created by pytest automatically.\n*" - gitignore_path.write_text(msg, encoding="UTF-8") + with gitignore_path.open("w", encoding="UTF-8") as f: + f.write(msg) cachedir_tag_path = self._cachedir.joinpath("CACHEDIR.TAG") - cachedir_tag_path.write_bytes(CACHEDIR_TAG_CONTENT) + with cachedir_tag_path.open("wb") as f: + f.write(CACHEDIR_TAG_CONTENT) class LFPlugin: @@ -160,7 +164,7 @@ def last_failed_paths(self): try: return self._last_failed_paths except AttributeError: - rootpath = Path(self.config.rootdir) + rootpath = Path(str(self.config.rootdir)) result = {rootpath / nodeid.split("::")[0] for nodeid in self.lastfailed} result = {x for x in result if x.exists()} self._last_failed_paths = result @@ -174,7 +178,7 @@ def pytest_ignore_collect(self, path): if self.active and self.config.getoption("lf") and path.isfile(): last_failed_paths = self.last_failed_paths() if last_failed_paths: - skip_it = Path(path) not in self.last_failed_paths() + skip_it = Path(str(path)) not in self.last_failed_paths() if skip_it: self._skipped_files += 1 return skip_it @@ -385,7 +389,7 @@ def pytest_report_header(config): # starting with .., ../.. if sensible try: - displaypath = cachedir.relative_to(config.rootdir) + displaypath = cachedir.relative_to(str(config.rootdir)) except ValueError: displaypath = cachedir return "cachedir: {}".format(displaypath) diff --git a/src/_pytest/pathlib.py b/src/_pytest/pathlib.py index 3269c25ed7b..7e5a369424c 100644 --- a/src/_pytest/pathlib.py +++ b/src/_pytest/pathlib.py @@ -11,14 +11,11 @@ from os.path import expandvars from os.path import isabs from os.path import sep +from pathlib import Path +from pathlib import PurePath from posixpath import sep as posix_sep -if sys.version_info[:2] >= (3, 6): - from pathlib import Path, PurePath -else: - from pathlib2 import Path, PurePath - __all__ = ["Path", "PurePath"] @@ -254,7 +251,6 @@ def make_numbered_dir_with_cleanup(root, prefix, keep, lock_timeout): def resolve_from_str(input, root): - assert not isinstance(input, Path), "would break on py2" root = Path(root) input = expanduser(input) input = expandvars(input) diff --git a/src/_pytest/tmpdir.py b/src/_pytest/tmpdir.py index f2c4d905cf5..284815cabd0 100644 --- a/src/_pytest/tmpdir.py +++ b/src/_pytest/tmpdir.py @@ -66,7 +66,8 @@ def getbasetemp(self): # use a sub-directory in the temproot to speed-up # make_numbered_dir() call rootdir = temproot.joinpath("pytest-of-{}".format(user)) - rootdir.mkdir(exist_ok=True) + if not rootdir.is_dir(): + os.mkdir(str(rootdir)) basetemp = make_numbered_dir_with_cleanup( prefix="pytest-", root=rootdir, keep=3, lock_timeout=LOCK_TIMEOUT ) @@ -180,10 +181,6 @@ def tmp_path(request, tmp_path_factory): created as a sub directory of the base temporary directory. The returned object is a :class:`pathlib.Path` object. - - .. note:: - - in python < 3.6 this is a pathlib2.Path """ return _mk_tmp(request, tmp_path_factory) diff --git a/testing/test_cacheprovider.py b/testing/test_cacheprovider.py index a2e701740a0..0989a9c710d 100644 --- a/testing/test_cacheprovider.py +++ b/testing/test_cacheprovider.py @@ -27,7 +27,8 @@ def test_config_cache_dataerror(self, testdir): cache = config.cache pytest.raises(TypeError, lambda: cache.set("key/name", cache)) config.cache.set("key/name", 0) - config.cache._getvaluepath("key/name").write_bytes(b"123invalid") + with config.cache._getvaluepath("key/name").open("wb") as f: + f.write(b"123invalid") val = config.cache.get("key/name", -2) assert val == -2 @@ -1031,12 +1032,15 @@ def test_gitignore(testdir): cache.set("foo", "bar") msg = "# Created by pytest automatically.\n*" gitignore_path = cache._cachedir.joinpath(".gitignore") - assert gitignore_path.read_text(encoding="UTF-8") == msg + with gitignore_path.open("r", encoding="UTF-8") as f: + assert f.read() == msg # Does not overwrite existing/custom one. - gitignore_path.write_text("custom") + with gitignore_path.open("w", encoding="UTF-8") as f: + f.write("custom") cache.set("something", "else") - assert gitignore_path.read_text(encoding="UTF-8") == "custom" + with gitignore_path.open("r", encoding="UTF-8") as f: + assert f.read() == "custom" def test_does_not_create_boilerplate_in_existing_dirs(testdir): @@ -1066,4 +1070,5 @@ def test_cachedir_tag(testdir): cache = Cache.for_config(config) cache.set("foo", "bar") cachedir_tag_path = cache._cachedir.joinpath("CACHEDIR.TAG") - assert cachedir_tag_path.read_bytes() == CACHEDIR_TAG_CONTENT + with cachedir_tag_path.open("rb") as f: + assert f.read() == CACHEDIR_TAG_CONTENT diff --git a/testing/test_reports.py b/testing/test_reports.py index b8b1a5406d1..786d97e9fee 100644 --- a/testing/test_reports.py +++ b/testing/test_reports.py @@ -215,7 +215,7 @@ def test_a(): assert len(reports) == 3 test_a_call = reports[1] test_a_call.path1 = testdir.tmpdir - test_a_call.path2 = Path(testdir.tmpdir) + test_a_call.path2 = Path(str(testdir.tmpdir)) data = test_a_call._to_json() assert data["path1"] == str(testdir.tmpdir) assert data["path2"] == str(testdir.tmpdir) diff --git a/testing/test_tmpdir.py b/testing/test_tmpdir.py index a7c0ed7eaa7..53727137ac3 100644 --- a/testing/test_tmpdir.py +++ b/testing/test_tmpdir.py @@ -322,7 +322,8 @@ def test_rmtree(self, tmp_path): adir.mkdir() afile = adir / "afile" - afile.write_bytes(b"aa") + with afile.open("wb") as f: + f.write(b"aa") rmtree(adir, force=True) assert not adir.exists() @@ -343,10 +344,10 @@ def attempt_symlink_to(path, to_path): """Try to make a symlink from "path" to "to_path", skipping in case this platform does not support it or we don't have sufficient privileges (common on Windows).""" try: - Path(path).symlink_to(Path(to_path)) + Path(str(path)).symlink_to(Path(to_path)) except OSError: pytest.skip("could not create symbolic link") def test_tmpdir_equals_tmp_path(tmpdir, tmp_path): - assert Path(tmpdir) == tmp_path + assert Path(str(tmpdir)) == tmp_path