Bases: Path
In-memory Path implementation over nested dicts (see
MemPathBackend) -- a lightweight virtual filesystem for mocks, tests,
or transient storage, and the reference exemplar for Track A of
extending this library (subclassing Path directly; see
docs/guides/extending.md).
Source code in src/pathlib_next/mempath.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155 | def __init__(
self, *segments: str | Pathname | Path, backend: MemPathBackend = None, **kwargs
):
# Joined and normalized like `PurePosixPath`: empty and "." segments
# collapse, and an absolute argument restarts the join. Raw
# concatenation made `MemPath("/") / "a"` the path "//a", unequal to
# (and hashed apart from) `MemPath("/a")`, gave "d/" an empty name,
# and let `MemPath("/root") / "/etc"` address "/root/etc".
path = ""
_backend = None
for segment in segments:
if isinstance(segment, MemPath):
text = segment.as_posix()
_backend = segment.backend
elif isinstance(segment, Path):
raise NotImplementedError()
elif isinstance(segment, Pathname):
text = "/".join(segment.segments)
elif isinstance(segment, str):
text = segment
else:
raise TypeError(
"argument should be a str or a Pathname, "
f"not {type(segment).__name__!r}"
)
if text.startswith("/") or not path:
path = text
elif text:
path = f"{path}/{text}"
self._segments = self._parse(path)
# `is not None`, not truthiness: a freshly-created root's backend is
# an *empty* dict, which is falsy -- `if _backend:` silently treated
# that as "no backend found" and gave the child a disconnected new
# one, breaking backend sharing for any join off an empty MemPath.
if _backend is not None and backend is None:
backend = _backend
self._backend = backend if backend is not None else MemPathBackend()
self._normalized = None
|
as_uri()
Source code in src/pathlib_next/mempath.py
| def as_uri(self):
return f"mempath:{_urlquote(self.as_posix())}"
|
iterdir()
Source code in src/pathlib_next/mempath.py
308
309
310
311
312
313
314
315
316 | def iterdir(self):
parent, name = self._parent_container()
content = parent.get(name) if name else parent
if content is None:
raise _os_error(FileNotFoundError, _errno.ENOENT, self)
if not isinstance(content, dict):
raise _os_error(NotADirectoryError, _errno.ENOTDIR, self)
for c in list(content.keys()):
yield self.with_segments(*self.segments, c)
|
relative_to(other)
Source code in src/pathlib_next/mempath.py
| def relative_to(self, other):
raise NotImplementedError()
|
rmdir()
Source code in src/pathlib_next/mempath.py
260
261
262
263
264
265
266
267
268
269
270
271
272
273 | def rmdir(self):
parent, name = self._parent_container()
if not name:
raise _os_error(FileNotFoundError, _errno.ENOENT, self)
content = parent.get(name)
if content is None:
raise _os_error(FileNotFoundError, _errno.ENOENT, self)
elif not isinstance(content, dict):
raise _os_error(NotADirectoryError, _errno.ENOTDIR, self)
elif len(content) != 0:
# pathlib raises OSError(ENOTEMPTY); FileExistsError (EEXIST)
# carried no errno and matched no caller's ENOTEMPTY check.
raise OSError(_errno.ENOTEMPTY, "Directory not empty", str(self))
parent.pop(name)
|
stat(*, follow_symlinks=True)
Source code in src/pathlib_next/mempath.py
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306 | def stat(self, *, follow_symlinks=True):
parent, name = self._parent_container()
if not name:
return FileStat(is_dir=True)
if name not in parent:
raise _os_error(FileNotFoundError, _errno.ENOENT, self)
content = parent[name]
is_dir = isinstance(content, dict)
# st_size was never set for files (always defaulted to 0), which
# silently broke any size-based checksum (e.g. PathSyncer's default
# usage pattern).
return FileStat(
is_dir=is_dir,
st_size=0 if is_dir else len(content),
st_mtime=getattr(content, "mtime", 0),
)
|
unlink(missing_ok=False)
Source code in src/pathlib_next/mempath.py
275
276
277
278
279
280
281
282
283
284
285
286
287 | def unlink(self, missing_ok=False):
parent, name = self._parent_container()
if not name:
# The root exists and is a directory: missing_ok does not apply.
raise _os_error(IsADirectoryError, _errno.EISDIR, self)
content = parent.get(name)
if content is None:
if missing_ok:
return
raise _os_error(FileNotFoundError, _errno.ENOENT, self)
elif isinstance(content, dict):
raise _os_error(IsADirectoryError, _errno.EISDIR, self)
parent.pop(name)
|
with_segments(*segments)
Source code in src/pathlib_next/mempath.py
| def with_segments(self, *segments: str):
if all(isinstance(segment, str) for segment in segments):
# The `Pathname` protocol's spelling: segments joined with "/",
# a leading "" marking the root (`("", "a")` is "/a").
segments = ("/".join(segments),)
return type(self)(*segments, backend=self.backend)
|