def test_ordering(): p = Path("a", "b", 1, True) assert p < Path("a", "b", 2, False) assert p > Path("a", "b", 1, False) assert p < Path("z", "a", 0, False) assert p >= p assert p <= p
def test_path_access(): pt = PathTuple([1, (2, 3)]) assert pt[Path(0)] == 1 assert pt[Path(1)] == (2, 3) assert pt[Path(1, 1)] == 3 assert Path(1, 1) in pt assert Path(0, 1) not in pt
def iterate_flattened(d, key=Path(), key_func=_by_str_key, include_nodes=False): """ Recursively iterate over the entries of nested dicts, lists, and tuples. Provides a full Path for each leaf. """ if isinstance(d, Mapping): if include_nodes: yield key, type(d)() for k, value in sorted(d.items(), key=key_func): yield from iterate_flattened(value, key + Path(k), key_func=key_func) elif isinstance(d, (list, tuple)): if include_nodes: yield key, type(d)() for i, value in enumerate(d): yield from iterate_flattened(value, key + Path(i), key_func=key_func) else: yield key, d
def test_pathcontainer_conversion(): cfg = PathDict() cfg["a"] = (1, [2, 3], {"four": (5, 8)}) assert isinstance(cfg.a, PathTuple) assert isinstance(cfg.a[1], PathList) assert isinstance(cfg.a[2], PathDict) assert isinstance(cfg.a[2].four, PathTuple) assert cfg[Path("a", 1, 0)] == 2 assert cfg[Path("a", 2, "four", 1)] == 8
def test_supports_path_access(): cfg = PathDict({"a": {"b": {"c": 4}}}) assert cfg[Path("a")] is cfg.a assert cfg[Path.from_str("a.b")] is cfg.a.b assert cfg[Path.from_str("a.b.c")] is cfg.a.b.c assert cfg[Path.from_str("a.b.c")] == 4 cfg[Path.from_str("a.b.c")] = 6 assert cfg[Path.from_str("a.b.c")] == 6 cfg[Path.from_str("a.b.d")] = 8 assert cfg[Path.from_str("a.b.d")] == 8 cfg[Path.from_str("a.b")] = {"e": 9} assert set(cfg.a.b.keys()) == {"e"} assert cfg[Path.from_str("a.b.e")] == 9
def test_ordering_failure(): p = Path("a", 1) with pytest.raises(TypeError): fail = p > "a[1]" with pytest.raises(TypeError): fail = p > ("a", 1)
def test_delitem_path(): cfg = PathDict({"lol": {"rofl": 42}}) del cfg[Path.from_str("lol.rofl")] assert_value(cfg, "lol", {}) with pytest.raises(KeyError): _ = cfg["lol.rofl"] with pytest.raises(AttributeError): _ = cfg.lol.rofl
def to_dict(self, restrict=Path(), priority=0): compatible_paths = [ k for k in self.entries_by_path.keys() if restrict.is_compatible_with(k) ] d = PathDict() for path in sorted(compatible_paths, key=lambda p: len(p)): entry = self.get_entry_for_priority(path, priority=priority) if self.check_write_access(path, entry.priority): d[path] = entry.value return d
def test_contains_path(): b = PathDict({"ponies": {"are": "pretty!"}}) assert Path.from_str("ponies") in b assert ("foo" in b) is False assert Path.from_str("ponies.are") in b assert Path.from_str("ponies.foo") not in b b["foo"] = 42 assert Path.from_str("foo") in b assert Path.from_str("ponies.foo") not in b b.ponies.foo = "hai" assert Path.from_str("ponies.foo") in b
def test_hash(parts): assert isinstance(hash(Path(*parts)), int) assert hash(Path(*parts)) == hash(Path(*parts)) assert hash(Path(*parts)) != hash(Path(*parts) + Path("b"))
def test_len(parts): assert len(Path(*parts)) == len(parts)
def test_empty(): assert not Path()
def test_eq(parts): p1 = Path(*parts) p2 = Path(*parts) assert p1 == p2 assert p1 != parts
def test_initialization(parts): p = Path(*parts) assert isinstance(p, Path) assert p.parts == parts
def test_is_suffix_of(): p = Path.from_str("a.b[2].c[True].e.foo") for i in range(1, len(p)): assert p[i:].is_suffix_of(p) assert not p.is_suffix_of(p[i:])
def test_is_prefix_of(): p = Path.from_str("a.b[2].c[True].e.foo") for i in range(len(p)): assert p[:i].is_prefix_of(p) assert not p.is_prefix_of(p[:i])
def test_add_fail(): p = Path("a", "b") with pytest.raises(TypeError): q = p + "c" with pytest.raises(TypeError): q = p + ("c", )
def test_getitem(parts): p = Path(*parts) for i in range(len(parts)): assert p[i] == parts[i]
def test_init_from_path_dict(): cfg = PathDict({Path("a", "b"): 12, Path("a", 2): "foo"}) assert_value(cfg, "a", PathDict({"b": 12, 2: "foo"}))
def test_from_str_fallback(): p = Path.from_str("a[foobar]") assert p.parts == ("a", "foobar")
def test_from_str_fancy_numbers(str_path, parts): ps = Path.from_str(str_path) pp = Path(*parts) assert ps == pp
def test_from_str(str_path, parts): ps = Path.from_str(str_path) pp = Path(*parts) assert ps == pp assert repr(ps) == str_path
def test_repr(str_path, parts): assert repr(Path(*parts)) == str_path
def test_empty_path(): cfg = PathDict({"a": 1, "b.c": 10, "d": {"e": 10}, True: False, 2: 3}) empty = Path() assert cfg[empty] is cfg assert empty in cfg
def test_pickle(parts): p = Path(*parts) p2 = pickle.loads(pickle.dumps(p)) assert p == p2
assert isinstance(pt[1], PathTuple) def test_path_access(): pt = PathTuple([1, (2, 3)]) assert pt[Path(0)] == 1 assert pt[Path(1)] == (2, 3) assert pt[Path(1, 1)] == 3 assert Path(1, 1) in pt assert Path(0, 1) not in pt @pytest.mark.parametrize( "path, expected_exc, error_path", [ (Path(1, 4), IndexError, Path(1, 4)), (Path(1, 4, 0, 0), IndexError, Path(1, 4)), (Path(4, 1, 0, 0), IndexError, Path(4)), (Path("a", "b"), TypeError, Path("a")), (Path(0, 1), TypeError, Path(0)), ], ) def test_path_error(path, expected_exc, error_path): pt = PathTuple((1, (2, 3, (4, 5)))) with pytest.raises(expected_exc) as exc_info: _ = pt[path] assert exc_info.value.args[1] == error_path def test_nested_eq(): assert PathTuple((1, 2, (3, 4))) == (1, 2, (3, 4))
def test_getitem_slice(parts): p = Path(*parts) for i in range(len(parts)): for j in range(i, len(parts)): assert p[i:j] == Path(*parts[i:j])
def test_copy(parts): p = Path(*parts) assert copy(p) == p assert deepcopy(p) == p
def test_add(): assert Path("foo") + Path("bar") == Path("foo", "bar") assert Path("foo") + Path(2) == Path("foo", 2) assert Path() + Path("foo", "bar") + Path() == Path("foo", "bar") p = Path() p += Path("a") p += Path("b") assert p == Path("a", "b")
def test_path_access(): pl = PathList([1, [2, 3]]) assert pl[Path(0)] == 1 assert pl[Path(1)] == [2, 3] assert pl[Path(1, 1)] == 3