pathapi
A robust, extensible pathlib-like base for any resource addressable as a
path. Same method names, signatures, semantics and exception types as
pathlib.Path wherever a pathlib.Path equivalent exists: write code against
Path once and it works against your local disk, an in-memory tree, an FTP
server or the members of a zip or tar file, and against any path class built on
it. It has no dependencies.
Deliberate behavioral differences from pathlib are listed, with their
reasons, in Divergences from pathlib.
pathapi was published as pathlib-next up to 0.10.0; pip install pathlib-next
now installs a shim that depends on this package. The changelog
has the migration from pathlib_next.
Installation
pip install pathapi
There are no extras: everything runs on the standard library. pytest is
needed only to import pathapi.testing and pathapi.http.testing.
Paths for other places are separate distributions built on this one:
| Distribution | Provides |
|---|---|
uripath |
URIPath: one class for any URI (file:, data:, ftp:, zip:, tar:, http:, dav:), and the uripath command |
sftppath |
SFTPPath (paramiko or asyncssh) |
objpath |
S3Path, GSPath and AZPath |
repopath |
RepoPath, GitHubPath and GitLabPath |
pathapi-requests |
RequestsTransport for pathapi.http |
Tour
Local filesystem, as pathlib.Path:
from pathapi import Path
p = Path("data") / "report.txt"
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text("hello")
print(p.read_text())
In memory, a virtual filesystem for tests and mocks:
from pathapi.mempath import MemPath
p = MemPath("/config/settings.json")
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text('{"debug": true}')
print(p.stat().st_size, [child.name for child in p.parent.iterdir()])
Archives: a member inside a zip or tar, the archive itself any path:
import zipfile
from pathapi import ZipPath
with zipfile.ZipFile("backup.zip", "w") as archive:
archive.writestr("etc/config.ini", "[main]\n")
member = ZipPath("etc/config.ini", archive="backup.zip")
print(member.read_text())
FTP shares the same contract (this needs a reachable server):
from pathapi import FTPPath
for child in FTPPath("/pub", host="ftp.example.com", user="anonymous").iterdir():
print(child.name, child.stat().st_size)
exists(), is_dir(), iterdir(), glob(), walk(),
read_text()/write_text(), copy()/move() and rm() behave the same way
on every class; what a backend cannot do (for example mkdir() on a tar file)
raises NotImplementedError.
Where to go next
- Extending: add a path type by subclassing
Path, and verify it with the bundled contracts. - Divergences from pathlib: every deliberate behavioral
difference from
pathlib.Path. - API Reference: generated from the docstrings.
- Changelog.