FTP Path API
pathapi.ftp
FTP and FTPS paths on the standard library alone (ftplib).
FTPPath is a Path for a directory tree on an FTP server and needs no URI;
FTPBackend holds the connections to one server and account.
DEFAULT_PORT = 21
module-attribute
The control port FTPBackend connects to when it is not given one. tls
asks for explicit FTPS on that same port; port 990 is never assumed.
DEFAULT_TIMEOUT = 30.0
module-attribute
Socket timeout, in seconds, FTPBackend applies to connect, replies and
transfers when the caller does not pass one.
IDLE_PROBE_SECONDS = 1.0
module-attribute
A cached control connection that carried a command within this many seconds
is used as it is. One that has been idle longer, or has not carried a command
yet, is probed with NOOP first and replaced if the server dropped it.
Servers close idle sessions after tens of seconds at the least, so a run of
operations pays no probe and a pause long enough to lose the session pays one.
BaseFTPBackend
Bases: object
Contract for obtaining a connected, logged-in ftplib.FTP (or
FTP_TLS). Subclass this to plug in custom connection handling (tests
mock it directly, no real server); FTPBackend is the real
implementation. endpoint, when a subclass sets it, is a hashable value
naming the server and account: two backends with equal endpoints serve
the same files.
endpoint = None
class-attribute
instance-attribute
client()
A new connected, logged-in client.
Source code in src/pathapi/ftp/_backend.py
56 57 58 | |
close()
Closes every control connection this backend holds, whichever thread opened it; one a command is running on closes when that command ends. Harmless when called again; a later use connects afresh.
Source code in src/pathapi/ftp/_backend.py
60 61 62 63 64 65 | |
FTPBackend(host, port=DEFAULT_PORT, *, user=None, password=None, tls=False, timeout=DEFAULT_TIMEOUT, ssl_context=None, verify=True)
Bases: BaseFTPBackend
The connections to one FTP server, as one account: stdlib
ftplib.FTP, or ftplib.FTP_TLS with tls=True (explicit FTPS on the
control port, PROT P for an encrypted data channel too).
Nothing connects when the backend is built. Each thread opens a control
connection on its first use and keeps it, so paths that share a backend
share a connection per thread (close() ends them, and so does the end
of the thread). timeout (seconds, default DEFAULT_TIMEOUT = 30)
bounds connect, every reply and every transfer read; None blocks
forever. Without user the login is anonymous.
tls=True verifies the server certificate and host name by default
(ssl.create_default_context()), before USER/PASS are sent. To
trust a private CA or a self-signed certificate, pass your own
ssl_context (e.g. ssl.create_default_context(cafile=...)). To turn
verification off entirely -- accepting any certificate, so anyone on
the network path can read the password -- pass verify=False.
ssl_context wins over verify when both are given. Data connections
reuse the control connection's TLS session.
A context manager: leaving the block calls close().
Source code in src/pathapi/ftp/_backend.py
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | |
endpoint
property
host = str(host)
instance-attribute
password = password
instance-attribute
port = DEFAULT_PORT if port is None else int(port)
instance-attribute
ssl_context = ssl_context
instance-attribute
timeout = timeout
instance-attribute
tls = bool(tls)
instance-attribute
user = user
instance-attribute
verify = verify
instance-attribute
client()
Source code in src/pathapi/ftp/_backend.py
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | |
FTPEndpoint
Bases: NamedTuple
The server and account a backend connects to: what two backends must share for their paths to name the same files. The password is not part of it.
host
instance-attribute
port
instance-attribute
tls
instance-attribute
user
instance-attribute
FTPPath(*segments, backend=None, host=None, port=DEFAULT_PORT, user=None, password=None, tls=False, timeout=DEFAULT_TIMEOUT, ssl_context=None, verify=True)
Bases: TreePath
A path on an FTP server, read and written through stdlib ftplib,
with a thread-keyed connection cache (FTPBackend; a thread's connections
close when it ends). A listing prefers MLSD (RFC 3659 -- type/size/modify
facts in one round trip) and a stat MLST of the entry itself where FEAT
lists it, else its parent's MLSD; servers that don't support them fall
back to NLST for listing (names only) and SIZE/CWD for stat (no portable
"not found vs. is a directory" distinction in that path).
FTPPath("/pub/x", host="h", user="u", tls=True) builds the path's own
FTPBackend; backend= shares one connection cache between paths built
separately, or plugs a BaseFTPBackend of your own. A path joined from
another keeps its backend. Names are read from the server root: pub/x and
/pub/x are one file.
Source code in src/pathapi/ftp/_path.py
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | |
backend
property
The FTPBackend (or custom BaseFTPBackend) holding the
connections of this path.
as_uri()
Source code in src/pathapi/ftp/_path.py
167 168 169 170 171 172 173 174 175 176 177 178 | |
chmod(mode, *, follow_symlinks=True)
Source code in src/pathapi/ftp/_path.py
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 | |
iterdir()
Source code in src/pathapi/ftp/_path.py
369 370 371 | |
rename(target)
Source code in src/pathapi/ftp/_path.py
508 509 510 511 512 513 514 515 516 517 518 519 520 521 | |
rmdir()
Source code in src/pathapi/ftp/_path.py
486 487 488 489 490 | |
stat(*, follow_symlinks=True)
Source code in src/pathapi/ftp/_path.py
373 374 | |
unlink(missing_ok=False)
Source code in src/pathapi/ftp/_path.py
477 478 479 480 481 482 483 484 | |