bagof-paths
One path API for local files and the cloud.
Wrap a path or a URL, then use it like pathlib.Path. The same code reads a
local file, an object on S3, or anything the underlying libraries reach.
from bagof.paths import Path
Path("/data/train.zarr") # a local file
Path("s3://my-bucket/train.zarr") # an object on S3
Both give you the same methods: read_bytes, exists, iterdir, /, and
the rest of the pathlib surface.
>>> from bagof.paths import Path
>>> p = Path("/data/sets/train.zarr")
>>> p.name
'train.zarr'
>>> p.parent
Path('/data/sets')
>>> p / "chunks"
Path('/data/sets/train.zarr/chunks')
Features
- One API for every path. Local files, cloud storage, and unknown backends all use the same methods.
- Missing methods are filled in. When a library lacks a method,
bagof.pathsbuilds it from simpler ones. It reads text from bytes, and copies a folder by copying its files. - One error to catch. An operation that cannot work raises a single
UnsupportedPathOperation, the same for every library. - Async support.
AsyncPathgives you the same methods withawait. - No required dependency. Local paths use only the standard library, and a URL can be parsed and rebuilt with no backend installed.
Installation
pip install bagof-paths # local paths
pip install bagof-paths[upath] # add remote paths via universal-pathlib
pip install bagof-paths[cloud] # add cloud paths via cloudpathlib
A remote store also needs its own library, such as s3fs for s3:// or
cloudpathlib[s3].
The same code, local or remote
Path reads the start of the string to choose a backend. A plain path is a
local file. A URL uses universal-pathlib, or cloudpathlib if you have it.
from bagof.paths import Path
def load(location: str) -> bytes:
return Path(location).read_bytes()
load("/data/train.bin")
load("s3://my-bucket/train.bin")
Credentials
Pass connection details with storage_options. They go straight to the
backend.
from bagof.paths import Path
Path(
"s3://my-bucket/train.bin",
storage_options={"key": "AKIA...", "secret": "...", "endpoint_url": "..."},
)
Leave storage_options off to use ambient credentials, such as environment
variables, ~/.aws/config, or an instance role.
Set defaults once for a scheme with set_storage_options, and a per-call
storage_options overrides them key by key.
from bagof.paths import set_storage_options
set_storage_options("s3", {"endpoint_url": "https://minio.local"})
Async
AsyncPath turns the methods that touch storage into coroutines. The methods
that only describe a path (name, parent, /) stay synchronous.
import asyncio
from bagof.paths import AsyncPath
async def main() -> None:
p = AsyncPath("s3://my-bucket/train.bin")
if await p.exists():
data = await p.read_bytes()
asyncio.run(main())
For a cloud store whose library speaks async (such as s3:// through s3fs),
AsyncPath talks to it directly, with no threads. For every other path it runs
the synchronous driver in a worker thread, so the same code works either way.
Parsing without a backend
Every method that only describes a path — name, parent, suffix,
with_name, /, match — works on a URL even when no path library is
installed. A Path falls back to plain parsing, and raises only when an
actual read or write is attempted.
from bagof.paths import Path
# With no backend installed, the URL is still parsed.
p = Path("s3://my-bucket/data/train.zarr")
p.name # 'train.zarr'
p.parent # Path('s3://my-bucket/data')
p / "chunks" # Path('s3://my-bucket/data/train.zarr/chunks')
p.read_bytes() # raises UnsupportedPathOperation until a backend is installed
For a value that must never touch storage, use PurePath. It has the same
parsing surface as Path and none of the I/O methods, so a read or write is
not even offered.
>>> from bagof.paths import Path, PurePath
>>> pure = PurePath("/data/sets/train.zarr")
>>> pure.name
'train.zarr'
>>> pure.with_suffix(".zip")
PurePath('/data/sets/train.zip')
>>> pure == Path("/data/sets/train.zarr")
True
A PurePath and a Path to the same place compare equal and hash alike, so
either one looks the other up in a set or a dictionary. This mirrors
pathlib, where a PurePath equals the Path beside it.
Learn more
See how it compares to pathlib, UPath, and AnyPath.
Metadata
Release files for bagof-paths 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bagof_paths-0.2.0.tar.gz | 84.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bagof_paths-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 144.5 kB
Release files / bagof_paths-0.2.0.tar.gz
| Download URL | bagof_paths-0.2.0.tar.gz |
|---|---|
| Size | 84.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8bc651a368565ed01c9fcdcf3630c341adb79a33b8fac20cb70e02d3551f1d37
|
|
BLAKE2b-256 checksum How to use checksums |
45d555a52c5de5ace7cc5d89b42144e152837fdcc2fa878eec623464d8b2d564
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / bagof_paths-0.2.0-py3-none-any.whl
| Download URL | bagof_paths-0.2.0-py3-none-any.whl |
|---|---|
| Size | 59.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e5ee3bd2adfac20f64ccc5ac39679f0bcd60ff94b1445fe29a8b8755a6913daf
|
|
BLAKE2b-256 checksum How to use checksums |
c26ed1a173b3ab60ccc25600472236c276d348fc0d341866c1b420655ea0b0ab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|