Filesystem
pytruenas.fs
Filesystem paths for a :class:~pytruenas.TrueNASClient.
client.path(...) returns a pathlib_next path:
- local client (running on the NAS) -> a plain
:class:
pathlib_next.LocalPath(no extra dependencies); - remote client -> a :class:
~pytruenas.fs.truenas.TruenasPath, which prefers SFTP and falls back to the middlewarefilesystem.*websocket API (:class:~pytruenas.fs.tnasws.TnasWsPath).
The old bespoke multi-backend Path proxy is gone; these are real
pathlib_next path types, so every generic operation (read_bytes/walk/
glob/copy/...) comes from pathlib_next for free.
__all__ = ['LocalPath', 'TnasWsPath', 'TnasWsBackend', 'TruenasPath', 'path']
module-attribute
TnasWsBackend(client)
Backend state for :class:TnasWsPath: it just holds the client.
Mirrors the role of SftpBackend/AsyncsshSftpBackend (which hold an
SSH/SFTP connection); here the "connection" is the middleware
:class:~pytruenas.TrueNASClient, whose api.filesystem namespace does the
actual work.
Source code in src/pytruenas/fs/tnasws.py
74 75 | |
__slots__ = ('client',)
class-attribute
instance-attribute
client = client
instance-attribute
TnasWsPath
Bases: UriPath
A path on a TrueNAS host, served by the middleware filesystem.* API.
__SCHEMES = (_SCHEME,)
class-attribute
instance-attribute
__slots__ = ()
class-attribute
instance-attribute
chmod(mode, *, follow_symlinks=True)
Source code in src/pytruenas/fs/tnasws.py
158 159 160 161 162 163 | |
chown(uid=None, gid=None, *, follow_symlinks=True, recursive=False, traverse=True)
Source code in src/pytruenas/fs/tnasws.py
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | |
rmdir()
Source code in src/pytruenas/fs/tnasws.py
199 200 | |
stat(*, follow_symlinks=True)
Source code in src/pytruenas/fs/tnasws.py
109 110 111 112 113 114 | |
unlink(missing_ok=False)
Source code in src/pytruenas/fs/tnasws.py
190 191 192 193 194 195 196 197 | |
TruenasPath
Bases: TnasWsPath
Remote TrueNAS path: SFTP-preferred, websocket-filesystem.* fallback.
Subclasses :class:~pytruenas.fs.tnasws.TnasWsPath so the always-available
websocket backend is the base behaviour; the SFTP-preferred operations
(unlink/rmdir/rename/symlink_to/readlink) are overridden to try SFTP first.
resolve is overridden too but never reaches SFTP -- SftpPath has no
resolve -- so it always returns self. Carries the same
TnasWsBackend (holding the client); the SFTP leg is built lazily from
the host's SSH configuration (client.config.ssh, an
:class:hostctl.host.SshConfig).
__SCHEMES = ('truenas',)
class-attribute
instance-attribute
__slots__ = ()
class-attribute
instance-attribute
readlink()
Source code in src/pytruenas/fs/truenas.py
158 159 160 161 162 163 | |
rename(target)
Source code in src/pytruenas/fs/truenas.py
152 153 154 155 156 | |
resolve(strict=False)
Always returns self -- neither leg can resolve symlinks.
The SFTP attempt below is structural, not effective: pathlib_next's
SftpPath implements no resolve, so _try_sftp raises
NotImplementedError on every host and the fallback runs even when
the SFTP leg is fully configured. The middleware has no realpath
either, so returning the path unchanged is the best effort available --
matching a filesystem with no symlink resolution. The branch is kept so
the operation starts working the day SftpPath grows a resolve.
Source code in src/pytruenas/fs/truenas.py
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | |
rmdir()
Source code in src/pytruenas/fs/truenas.py
146 147 148 149 150 | |
symlink_to(target, target_is_directory=False, *, force=False, onremove=None)
Create a symlink, with pytruenas's force= convenience.
force removes a conflicting existing target first (a bool, a single
file-type, or a set of file-types that may be replaced); onremove is a
callback consulted before each removal. Not part of pathlib_next -- kept
from the original pytruenas API. The link itself is created via the SFTP
leg (filesystem.* has no symlink op), so a host with no SFTP leg
raises NotImplementedError -- and raises it before force
removes anything, so a call that cannot succeed leaves the existing
target alone rather than deleting it and then failing.
Source code in src/pytruenas/fs/truenas.py
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | |
unlink(missing_ok=False)
Source code in src/pytruenas/fs/truenas.py
140 141 142 143 144 | |
path(client, *segments, backend=None)
Build the appropriate path type for client and segments.
backend forces a specific type: "local" -> :class:LocalPath,
"ws"/"api" -> :class:TnasWsPath, "truenas"/"auto" ->
:class:TruenasPath. Default (None/"auto"): LocalPath for a local
client, otherwise TruenasPath.
Source code in src/pytruenas/fs/__init__.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | |