Storix session¶
Everything you call on a session. A Storix is created over a backend (or built
by get_storage), and every path argument is resolved the unix way (~, ..,
and the current working directory) before it reaches the backend. Any operation
raises a typed error on failure; nothing returns a boolean you have
to check.
Unless noted, every method has an awaitable twin under storix.aio with the same
name and signature.
Session and navigation¶
pwd¶
The current working directory.
cd¶
Change the working directory. No argument returns to home. Returns the session
for chaining.
ls¶
List a directory (the cwd by default). Dotfiles are hidden unless all=True.
abs=True returns absolute paths instead of names. The eager, names-only
member of the listing family below.
scandir / iterdir / is_empty / empty_children¶
scandir(path=None, *, all=False) -> Iterator[DirEntry] # lazy, rich (name, path, kind, size)
iterdir(path=None, *, all=False) -> Iterator[StorixPath] # lazy names (pathlib-shaped)
is_empty(path=None) -> bool # one round trip; counts hidden entries
empty_children(path=None, *, names=None) -> dict[str, bool]
scandir streams one directory as DirEntry objects carrying the kind and any
size the listing produced for free, so a consumer never stats every entry.
iterdir is its names-only sibling. is_empty answers whether a directory
holds anything (a dotfile-only directory is not empty). empty_children
answers the same question for every immediate child directory. On a backend
with bulk listing it groups one recursive listing; otherwise it probes the
children concurrently. Pass names when you already have the child directory
names from scandir, as the CLI does, to avoid repeating that listing.
walk / find / glob¶
walk(path=None, *, all=False, top_down=True) -> Iterator[DirEntry] # recursive scandir
find(path=None, *, name=None, kind=None) -> Iterator[DirEntry] # walk filtered by glob/kind
glob(pattern, path=None) -> Iterator[StorixPath] # *, ?, ** patterns
The recursive family, after os.walk / unix find / pathlib.glob. walk
streams every descendant lazily (top_down=False for post-order, e.g. size
accumulation). find filters it: name is a basename glob ('*.py'), kind
restricts to files or directories. glob matches a path pattern. All exclude
hidden entries by default, like the rest of the family.
resolve¶
Resolve a path to its absolute, normalized port path (applying cwd, ~, ..),
without touching the backend. Useful for logging and bookmarking.
locate¶
The physical URI of a path (file://..., abfss://...), resolved through any
sandbox. Use it for audit and cross-system references.
Properties¶
backend -> StorageBackend # the raw port, for backend-specific calls
base_backend -> StorageBackend # the real provider, under any layers
layers -> list[StorageBackend] # the active layers, outermost first
root -> StorixPath # always '/'
home -> StorixPath # the '~' anchor
backend hands back the outermost object, which is whatever layer wraps the
session; base_backend walks past the layers to the thing that really talks
to storage, and layers reports what sits in between:
from storix import CacheLayer
fs = get_storage("azure").with_layer(CacheLayer, du=True)
type(fs.base_backend).__name__ # 'AzureBackend'
[type(layer).__name__ for layer in fs.layers] # ['CacheLayer']
any(isinstance(layer, CacheLayer) for layer in fs.layers) # True
Layers are identified structurally, so your own show up beside the built-ins. The list is empty on an unwrapped session.
Reading¶
cat¶
Read one or more files fully and concatenate them into bytes. Use for small,
known-size content. For large files, prefer stream.
stream¶
stream(
path: StrPathLike,
/,
*paths: StrPathLike,
chunk_size: int | None = None,
) -> Iterator[bytes]
Read files back in chunks. chunk_size is the maximum yielded size; None uses
the backend's preferred default. Smaller provider chunks pass through promptly.
Zero or negative values raise ValueError. Streaming-native backends keep memory
bounded; a whole-object custom backend's compatibility fallback does not. See
Reading and writing.
download¶
download(
path: StrPathLike,
dest: BinarySink,
/,
*,
ranges: int | None = None,
chunk_size: int | None = None,
) -> int
Read one file into an open binary sink and return the bytes written. The
parallel counterpart of stream: where stream yields chunks in order for any
consumer, download writes a destination that accepts out-of-order writes, so
it can fetch several byte ranges of the same file at once. That is what makes a
single large file transfer faster than one connection on a high-latency link.
dest is anything that accepts bytes - BinarySink is structural, so
open(path, "wb"), an io.BytesIO, a gzip.GzipFile, a SpooledTemporaryFile
and a socket stream all qualify. A text stream deliberately does not:
storage yields bytes, and a parallel download splits a file at byte offsets that
can fall inside a multi-byte character. The local write is a call the core
performs directly, not an operation on the storage port.
Ranges are written with os.pwrite only when the sink is a standard-library
file writer, whose contract is that the bytes it is handed reach its descriptor
unchanged. Any other sink streams sequentially and gets identical bytes - that
includes sinks that transform what they are given, such as gzip.GzipFile,
which reports the underlying file's descriptor as its own. ranges=None splits a file at or above 64 MiB into up to eight
ranges on a backend that advertises ranged_reads, and ranges=1 forces the
sequential path. A sink without a usable file descriptor (a BytesIO, a pipe)
streams sequentially; the bytes written are identical either way. See
Tune transfers.
stat¶
Facts about a path: kind, size, and (where the backend supports it) content type and custom metadata.
du¶
Total size in bytes of a tree (apparent content bytes).
exists, isfile, isdir¶
exists(path: StrPathLike | None = None) -> bool
isfile(path: StrPathLike | None = None) -> bool
isdir(path: StrPathLike | None = None) -> bool
Existence and kind checks.
Writing and creating¶
echo¶
echo(
data: DataBuffer[str] | DataBuffer[bytes],
path: StrPathLike,
/,
*,
chunk_size: int | None = None,
mode: EchoMode = "w",
content_type: str | None = None,
metadata: Mapping[str, str] | None = None,
) -> None
Write data to path. data accepts native Python: bytes, str, a Buffer,
an open file (IO), or an iterable of chunks (and an async iterable under
storix.aio). mode="a" appends. content_type and metadata are applied where
the backend supports them. chunk_size is the maximum target backend write
batch; None uses its preferred default. Tiny iterator yields are combined and
oversized values are split. Zero or negative values raise ValueError.
touch¶
Create empty files, or refresh their modification time if they exist.
mkdir¶
Create directories. parents=True creates missing parents and does not error if
the directory already exists (unix mkdir -p).
set_metadata¶
Replace a file's custom metadata ({} clears it). merge=True does a
non-atomic read-modify-write to add keys instead of replacing. Requires the
custom_metadata capability.
Moving, copying, removing¶
Move and copy are variadic; the last argument is the destination, like unix.
mv¶
Move or rename. With more than two paths, all sources move into the final directory.
cp¶
Copy. recursive=True to copy directories.
rm¶
Remove files. recursive=True removes directories and their contents (unix
rm -r).
rmdir¶
Remove strictly empty directories.
URLs and sharing¶
url¶
A presigned URL (an Azure SAS link). Requires the presigned_urls capability;
raises UnsupportedOperationError otherwise. Use DataUrlLayer to
get one on any backend.
data_url¶
A base64 data: URL, generated by the core for any backend.
Composition¶
with_layer, with_layer_missing¶
Return a new session with layer wrapping this backend. with_layer_missing
skips the layer when the backend already provides its capability. See
Layers.
without_layer, uncached¶
without_layer(*layers: type) -> Self
uncached -> Self # property; sugar for without_layer(CacheLayer)
Return a session with the given layer types bypassed. Absent layers are a no-op;
a SandboxLayer cannot be stripped.
chroot, scratch¶
chroot(path: StrPathLike, /) -> Self
scratch(*, root: StrPathLike | None = None, prefix: str = "scratch-") -> ContextManager[Storix]
chroot returns a sandboxed session rooted at path. scratch is a context
manager giving a disposable (or pinned, with root) workspace on the same
backend.
Lifecycle¶
Release the backend's resources (idempotent). In async code, use the session as
a context manager: async with get_storage("azure") as fs: ....