2019-09-10 00:54:28 +00:00
|
|
|
# Created By: Virgil Dupras
|
|
|
|
# Created On: 2006/02/21
|
|
|
|
# Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
|
|
# which should be included with this package. The terms are also available at
|
2019-09-10 00:54:28 +00:00
|
|
|
# http://www.gnu.org/licenses/gpl-3.0.html
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
|
2020-06-26 04:26:48 +00:00
|
|
|
import pytest
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
from ..path import Path, pathify
|
|
|
|
from ..testutil import eq_
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2020-06-26 04:26:48 +00:00
|
|
|
@pytest.fixture
|
|
|
|
def force_ossep(request):
|
|
|
|
monkeypatch = request.getfixturevalue("monkeypatch")
|
2020-01-01 02:16:27 +00:00
|
|
|
monkeypatch.setattr(os, "sep", "/")
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_empty(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
path = Path("")
|
|
|
|
eq_("", str(path))
|
|
|
|
eq_(0, len(path))
|
2019-09-10 00:54:28 +00:00
|
|
|
path = Path(())
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_("", str(path))
|
|
|
|
eq_(0, len(path))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_single(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
path = Path("foobar")
|
|
|
|
eq_("foobar", path)
|
|
|
|
eq_(1, len(path))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_multiple(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
path = Path("foo/bar")
|
|
|
|
eq_("foo/bar", path)
|
|
|
|
eq_(2, len(path))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_init_with_tuple_and_list(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
path = Path(("foo", "bar"))
|
|
|
|
eq_("foo/bar", path)
|
|
|
|
path = Path(["foo", "bar"])
|
|
|
|
eq_("foo/bar", path)
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_init_with_invalid_value(force_ossep):
|
|
|
|
try:
|
2020-06-27 06:08:12 +00:00
|
|
|
path = Path(42) # noqa: F841
|
2019-09-10 00:54:28 +00:00
|
|
|
assert False
|
|
|
|
except TypeError:
|
|
|
|
pass
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_access(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
path = Path("foo/bar/bleh")
|
|
|
|
eq_("foo", path[0])
|
|
|
|
eq_("foo", path[-3])
|
|
|
|
eq_("bar", path[1])
|
|
|
|
eq_("bar", path[-2])
|
|
|
|
eq_("bleh", path[2])
|
|
|
|
eq_("bleh", path[-1])
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_slicing(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
path = Path("foo/bar/bleh")
|
2019-09-10 00:54:28 +00:00
|
|
|
subpath = path[:2]
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_("foo/bar", subpath)
|
|
|
|
assert isinstance(subpath, Path)
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_parent(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
path = Path("foo/bar/bleh")
|
2019-09-10 00:54:28 +00:00
|
|
|
subpath = path.parent()
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_("foo/bar", subpath)
|
2019-09-10 00:54:28 +00:00
|
|
|
assert isinstance(subpath, Path)
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_filename(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
path = Path("foo/bar/bleh.ext")
|
|
|
|
eq_(path.name, "bleh.ext")
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_deal_with_empty_components(force_ossep):
|
|
|
|
"""Keep ONLY a leading space, which means we want a leading slash.
|
|
|
|
"""
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_("foo//bar", str(Path(("foo", "", "bar"))))
|
|
|
|
eq_("/foo/bar", str(Path(("", "foo", "bar"))))
|
|
|
|
eq_("foo/bar", str(Path("foo/bar/")))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_old_compare_paths(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_(Path("foobar"), Path("foobar"))
|
|
|
|
eq_(Path("foobar/"), Path("foobar\\", "\\"))
|
|
|
|
eq_(Path("/foobar/"), Path("\\foobar\\", "\\"))
|
|
|
|
eq_(Path("/foo/bar"), Path("\\foo\\bar", "\\"))
|
|
|
|
eq_(Path("/foo/bar"), Path("\\foo\\bar\\", "\\"))
|
|
|
|
assert Path("/foo/bar") != Path("\\foo\\foo", "\\")
|
|
|
|
# We also have to test __ne__
|
|
|
|
assert not (Path("foobar") != Path("foobar"))
|
|
|
|
assert Path("/a/b/c.x") != Path("/a/b/c.y")
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_old_split_path(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_(Path("foobar"), ("foobar",))
|
|
|
|
eq_(Path("foo/bar"), ("foo", "bar"))
|
|
|
|
eq_(Path("/foo/bar/"), ("", "foo", "bar"))
|
|
|
|
eq_(Path("\\foo\\bar", "\\"), ("", "foo", "bar"))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_representation(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_("('foo', 'bar')", repr(Path(("foo", "bar"))))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_add(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_("foo/bar/bar/foo", Path(("foo", "bar")) + Path("bar/foo"))
|
|
|
|
eq_("foo/bar/bar/foo", Path("foo/bar") + "bar/foo")
|
|
|
|
eq_("foo/bar/bar/foo", Path("foo/bar") + ("bar", "foo"))
|
|
|
|
eq_("foo/bar/bar/foo", ("foo", "bar") + Path("bar/foo"))
|
|
|
|
eq_("foo/bar/bar/foo", "foo/bar" + Path("bar/foo"))
|
|
|
|
# Invalid concatenation
|
2019-09-10 00:54:28 +00:00
|
|
|
try:
|
2020-01-01 02:16:27 +00:00
|
|
|
Path(("foo", "bar")) + 1
|
2019-09-10 00:54:28 +00:00
|
|
|
assert False
|
|
|
|
except TypeError:
|
|
|
|
pass
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_path_slice(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
foo = Path("foo")
|
|
|
|
bar = Path("bar")
|
|
|
|
foobar = Path("foo/bar")
|
|
|
|
eq_("bar", foobar[foo:])
|
|
|
|
eq_("foo", foobar[:bar])
|
|
|
|
eq_("foo/bar", foobar[bar:])
|
|
|
|
eq_("foo/bar", foobar[:foo])
|
|
|
|
eq_((), foobar[foobar:])
|
|
|
|
eq_((), foobar[:foobar])
|
|
|
|
abcd = Path("a/b/c/d")
|
|
|
|
a = Path("a")
|
2020-06-27 06:08:12 +00:00
|
|
|
b = Path("b") # noqa: #F841
|
|
|
|
c = Path("c") # noqa: #F841
|
2020-01-01 02:16:27 +00:00
|
|
|
d = Path("d")
|
|
|
|
z = Path("z")
|
|
|
|
eq_("b/c", abcd[a:d])
|
|
|
|
eq_("b/c/d", abcd[a : d + z])
|
|
|
|
eq_("b/c", abcd[a : z + d])
|
|
|
|
eq_("a/b/c/d", abcd[:z])
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_add_with_root_path(force_ossep):
|
|
|
|
"""if I perform /a/b/c + /d/e/f, I want /a/b/c/d/e/f, not /a/b/c//d/e/f
|
|
|
|
"""
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_("/foo/bar", str(Path("/foo") + Path("/bar")))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_create_with_tuple_that_have_slash_inside(force_ossep, monkeypatch):
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_(("", "foo", "bar"), Path(("/foo", "bar")))
|
|
|
|
monkeypatch.setattr(os, "sep", "\\")
|
|
|
|
eq_(("", "foo", "bar"), Path(("\\foo", "bar")))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_auto_decode_os_sep(force_ossep, monkeypatch):
|
|
|
|
"""Path should decode any either / or os.sep, but always encode in os.sep.
|
|
|
|
"""
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_(("foo\\bar", "bleh"), Path("foo\\bar/bleh"))
|
|
|
|
monkeypatch.setattr(os, "sep", "\\")
|
|
|
|
eq_(("foo", "bar/bleh"), Path("foo\\bar/bleh"))
|
|
|
|
path = Path("foo/bar")
|
|
|
|
eq_(("foo", "bar"), path)
|
|
|
|
eq_("foo\\bar", str(path))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_contains(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
p = Path(("foo", "bar"))
|
|
|
|
assert Path(("foo", "bar", "bleh")) in p
|
|
|
|
assert Path(("foo", "bar")) in p
|
|
|
|
assert "foo" in p
|
|
|
|
assert "bleh" not in p
|
|
|
|
assert Path("foo") not in p
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_is_parent_of(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
assert Path(("foo", "bar")).is_parent_of(Path(("foo", "bar", "bleh")))
|
|
|
|
assert not Path(("foo", "bar")).is_parent_of(Path(("foo", "baz")))
|
|
|
|
assert not Path(("foo", "bar")).is_parent_of(Path(("foo", "bar")))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_windows_drive_letter(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
p = Path(("c:",))
|
|
|
|
eq_("c:\\", str(p))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_root_path(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
p = Path("/")
|
|
|
|
eq_("/", str(p))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_str_encodes_unicode_to_getfilesystemencoding(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
p = Path(("foo", "bar\u00e9"))
|
|
|
|
eq_("foo/bar\u00e9".encode(sys.getfilesystemencoding()), p.tobytes())
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_unicode(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
p = Path(("foo", "bar\u00e9"))
|
|
|
|
eq_("foo/bar\u00e9", str(p))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_str_repr_of_mix_between_non_ascii_str_and_unicode(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
u = "foo\u00e9"
|
2019-09-10 00:54:28 +00:00
|
|
|
encoded = u.encode(sys.getfilesystemencoding())
|
2020-01-01 02:16:27 +00:00
|
|
|
p = Path((encoded, "bar"))
|
2019-09-10 00:54:28 +00:00
|
|
|
print(repr(tuple(p)))
|
2020-01-01 02:16:27 +00:00
|
|
|
eq_("foo\u00e9/bar".encode(sys.getfilesystemencoding()), p.tobytes())
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_Path_of_a_Path_returns_self(force_ossep):
|
2020-01-01 02:16:27 +00:00
|
|
|
# if Path() is called with a path as value, just return value.
|
|
|
|
p = Path("foo/bar")
|
2019-09-10 00:54:28 +00:00
|
|
|
assert Path(p) is p
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_getitem_str(force_ossep):
|
|
|
|
# path['something'] returns the child path corresponding to the name
|
2020-01-01 02:16:27 +00:00
|
|
|
p = Path("/foo/bar")
|
|
|
|
eq_(p["baz"], Path("/foo/bar/baz"))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_getitem_path(force_ossep):
|
|
|
|
# path[Path('something')] returns the child path corresponding to the name (or subpath)
|
2020-01-01 02:16:27 +00:00
|
|
|
p = Path("/foo/bar")
|
|
|
|
eq_(p[Path("baz/bleh")], Path("/foo/bar/baz/bleh"))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
2020-06-26 04:26:48 +00:00
|
|
|
@pytest.mark.xfail(reason="pytest's capture mechanism is flaky, I have to investigate")
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_log_unicode_errors(force_ossep, monkeypatch, capsys):
|
|
|
|
# When an there's a UnicodeDecodeError on path creation, log it so it can be possible
|
|
|
|
# to debug the cause of it.
|
2020-01-01 02:16:27 +00:00
|
|
|
monkeypatch.setattr(sys, "getfilesystemencoding", lambda: "ascii")
|
2020-06-26 04:26:48 +00:00
|
|
|
with pytest.raises(UnicodeDecodeError):
|
2020-01-01 02:16:27 +00:00
|
|
|
Path(["", b"foo\xe9"])
|
2019-09-10 00:54:28 +00:00
|
|
|
out, err = capsys.readouterr()
|
2020-01-01 02:16:27 +00:00
|
|
|
assert repr(b"foo\xe9") in err
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_has_drive_letter(monkeypatch):
|
2020-01-01 02:16:27 +00:00
|
|
|
monkeypatch.setattr(os, "sep", "\\")
|
|
|
|
p = Path("foo\\bar")
|
2019-09-10 00:54:28 +00:00
|
|
|
assert not p.has_drive_letter()
|
2020-01-01 02:16:27 +00:00
|
|
|
p = Path("C:\\")
|
2019-09-10 00:54:28 +00:00
|
|
|
assert p.has_drive_letter()
|
2020-01-01 02:16:27 +00:00
|
|
|
p = Path("z:\\foo")
|
2019-09-10 00:54:28 +00:00
|
|
|
assert p.has_drive_letter()
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def test_remove_drive_letter(monkeypatch):
|
2020-01-01 02:16:27 +00:00
|
|
|
monkeypatch.setattr(os, "sep", "\\")
|
|
|
|
p = Path("foo\\bar")
|
|
|
|
eq_(p.remove_drive_letter(), Path("foo\\bar"))
|
|
|
|
p = Path("C:\\")
|
|
|
|
eq_(p.remove_drive_letter(), Path(""))
|
|
|
|
p = Path("z:\\foo")
|
|
|
|
eq_(p.remove_drive_letter(), Path("foo"))
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_pathify():
|
|
|
|
@pathify
|
2020-01-01 02:16:27 +00:00
|
|
|
def foo(a: Path, b, c: Path):
|
2019-09-10 00:54:28 +00:00
|
|
|
return a, b, c
|
2020-01-01 02:16:27 +00:00
|
|
|
|
|
|
|
a, b, c = foo("foo", 0, c=Path("bar"))
|
2019-09-10 00:54:28 +00:00
|
|
|
assert isinstance(a, Path)
|
2020-01-01 02:16:27 +00:00
|
|
|
assert a == Path("foo")
|
2019-09-10 00:54:28 +00:00
|
|
|
assert b == 0
|
|
|
|
assert isinstance(c, Path)
|
2020-01-01 02:16:27 +00:00
|
|
|
assert c == Path("bar")
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def test_pathify_preserve_none():
|
|
|
|
# @pathify preserves None value and doesn't try to return a Path
|
|
|
|
@pathify
|
|
|
|
def foo(a: Path):
|
|
|
|
return a
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
a = foo(None)
|
|
|
|
assert a is None
|