host.transfer¶
File transfer backends for otto hosts — one package, both host families.
Public API (also re-exported from otto.host): register_transfer_backend,
build_transfer_backend, the Rich progress helpers, and the Nc* selector
Literals. Importing this package registers every built-in backend.
-
class otto.host.transfer.BaseFileTransfer(name, max_filename_len=
255)¶ Bases:
ABCShared API + progress plumbing for any file-transfer backend.
The public
put_files/get_filessurface (filename-length validation, shared Rich progress acquisition) is owned by this base. Concrete backends (Unix’sUnixFileTransfersubclasses (ScpFileTransfer,SftpFileTransfer,FtpFileTransfer,NcFileTransfer), embedded’sEmbeddedFileTransfersubclasses (ConsoleFileTransfer,TftpFileTransfer), and any future ones) implement two abstract methods —_run_putand_run_get— both of which receive aTransferProgressFactoryand are responsible for invoking it at least once per source file, terminating withbytes_done == bytes_totalto mark completion.The progress-bar capability is enforced at the type system level:
abc.abstractmethodrefuses to instantiate a subclass that omits either method, so a new backend cannot be defined without supplying a way to report progress. The runtime contract test (TestTransferProgressContract) verifies the factory is actually invoked, not just that the methods exist.-
host_families : --is-rst--:py:class:`frozenset`\ \[:py:class:`str`] =
frozenset({})¶ a subset of
{'unix', 'embedded'}. Subclasses declare it; the spec field_validator rejects a backend on a host of the wrong family. A backend with an empty set can never validate and is rejected at registration.- Type:¶
Host families this backend serves
- classmethod create(ctx)¶
Build a transfer backend from a
TransferContext.The uniform construction seam (WS#4). Concrete backends override this to run their exact construction against the ctx fields they need. Not an
abstractmethoddeliberately: only registered built-ins are ever constructed throughcreate, and test doubles that subclassBaseFileTransferonly to exercise the progress contract must not be forced to implement it.- Return type:¶
-
host_families : --is-rst--:py:class:`frozenset`\ \[:py:class:`str`] =
-
class otto.host.transfer.TransferContext(transfer, host_name, max_filename_len=
255, exec_cmd=None, connections=None, nc_options=None, scp_options=None, get_local_ip=None, filesystem=None)¶ Bases:
objectConstruction inputs a host provides to build its transfer backend via
BaseFileTransfer.create(). The frozen public seam for custom transfer backends. Carries the union of what any family’s built-ins receive at their call sites; a unix backend reads the unix fields, an embedded backend the embedded ones. Selector validation (host-family applicability) runs before construction, so a backend never sees a ctx missing the fields it needs.- transfer : --is-rst--:py:class:`str`¶
- host_name : --is-rst--:py:class:`str`¶
-
max_filename_len : --is-rst--:py:class:`int` =
255¶
-
exec_cmd : --is-rst--:py:class:`~collections.abc.Callable`\ \[:py:data:`...<Ellipsis>`, :py:class:`~collections.abc.Coroutine`\ \[:py:data:`~typing.Any`, :py:data:`~typing.Any`, :py:class:`~otto.utils.CommandStatus`]] | :py:obj:`None` =
None¶
-
connections : --is-rst--:py:class:`~otto.host.connections.ConnectionManager` | :py:obj:`None` =
None¶
-
nc_options : --is-rst--:py:class:`~otto.host.options.NcOptions` | :py:obj:`None` =
None¶
-
scp_options : --is-rst--:py:class:`~otto.host.options.ScpOptions` | :py:obj:`None` =
None¶
-
get_local_ip : --is-rst--:py:class:`~collections.abc.Callable`\ \[\[], :py:class:`str`] | :py:obj:`None` =
None¶
-
filesystem : --is-rst--:py:class:`~otto.host.embedded_filesystem.EmbeddedFileSystem` | :py:obj:`None` =
None¶
- otto.host.transfer.validate_filename_lengths(files, limit, host_name)¶
Reject files whose basename exceeds the host’s filesystem cap.
Shared by
UnixFileTransfer(Unix) andEmbeddedFileTransfer(embedded) so every backend surfaces the same self-explaining error. Without this guard the failure modes are: :rtype:tuple[Status,str]Unix SCP/SFTP/FTP: server returns
File name too long(errno 36), mid-transfer, after the local file is already read.Embedded FAT (8.3, no LFN) or LittleFS over
NAME_MAX: device failsfs_openwith-ENOENT, giving no hint that the name was the problem.
Returns
(Status.Success, '')when every basename fits.
- otto.host.transfer.TransferProgressHandler¶
alias of
Callable[[str,str,int,int],None]
- otto.host.transfer.TransferProgressFactory¶
alias of
Callable[[],Callable[[str,str,int,int],None]]
- otto.host.transfer.make_rich_progress_handler(progress, host_name)¶
Return a TransferProgressHandler that drives the given Rich Progress bar.
One task is created per source file, detected by a change in src_path. The caller is responsible for the Progress context (entering and exiting it).
Example:
with make_transfer_progress() as progress: handler = make_rich_progress_handler(progress, host_name=host.hostname) status, err = await host.get(files, dest, progress_handler=handler)- Return type:¶
Callable[[str,str,int,int],None]
- otto.host.transfer.make_rich_progress_factory(progress, host_name)¶
Return a factory that creates a fresh TransferProgressHandler per file.
Each call to the returned factory produces an independent handler with its own closure state, so concurrent transfers don’t share progress tracking.
Example:
with make_transfer_progress() as progress: factory = make_rich_progress_factory(progress, host_name=host.name) status, err = await host.put(files, dest)- Return type:¶
Callable[[],Callable[[str,str,int,int],None]]
- otto.host.transfer.make_transfer_progress()¶
Return a pre-configured Rich Progress suited for file transfers.
- Return type:¶
Progress
- otto.host.transfer.register_transfer_backend(name, cls)¶
Make a custom transfer backend available to lab data under name.
Call from an init module listed in
.otto/settings.toml. The backend must declare a non-emptyBaseFileTransfer.host_families; otherwise it could never validate against any host and is rejected here.- Return type:¶
None
- otto.host.transfer.build_transfer_backend(name)¶
Return the transfer-backend class registered under name.
- Return type:¶
type[BaseFileTransfer]
Raises¶
- ValueError
If name is not registered; the message lists the registered names.
-
class otto.host.transfer.NcFileTransfer(connections, name, transfer, nc_options, get_local_ip, exec_cmd, max_filename_len=
255)¶ Bases:
UnixFileTransferHandles netcat file transfers for a UnixHost.
Receives injectable callables for open_session and oneshot so it can be tested without real connections.
Inherits
put_files/get_filesfromBaseFileTransferand unix scaffolding (_connections,_exec_cmd,_warmup_for_transfer) fromUnixFileTransfer; implements the abstract_run_put/_run_getas direct calls to_put_files_nc/_get_files_nc.-
host_families : --is-rst--:py:class:`frozenset`\ \[:py:class:`str`] =
frozenset({'unix'})¶ a subset of
{'unix', 'embedded'}. Subclasses declare it; the spec field_validator rejects a backend on a host of the wrong family. A backend with an empty set can never validate and is rejected at registration.- Type:¶
Host families this backend serves
- classmethod create(ctx)¶
Build a transfer backend from a
TransferContext.The uniform construction seam (WS#4). Concrete backends override this to run their exact construction against the ctx fields they need. Not an
abstractmethoddeliberately: only registered built-ins are ever constructed throughcreate, and test doubles that subclassBaseFileTransferonly to exercise the progress contract must not be forced to implement it.- Return type:¶
- async prepare()¶
Resolve port + listener strategies in a single round-trip.
Runs the shared _STRATEGY_PROBE script through _control_run so the port and listener strategies are resolved up front rather than lazily at first-transfer time. Idempotent — a second call with both strategies already cached is a no-op.
Callers use _warmup_for_transfer to run this concurrently with exec-pool warming; direct callers can invoke prepare() alone.
If the probe itself fails (non-zero exit, malformed output), the caches stay unset and the lazy cascades in _find_free_port_auto / _resolve_listener_strategy still kick in as fallbacks.
- Return type:¶
None
-
host_families : --is-rst--:py:class:`frozenset`\ \[:py:class:`str`] =
-
class otto.host.transfer.UnixFileTransfer(connections, name, exec_cmd, max_filename_len=
255)¶ Bases:
BaseFileTransferCommon unix scaffolding shared by all SSH/Telnet transfer backends.
Stores the two mandatory unix fields (
_connections,_exec_cmd), provides_warmup_for_transfer()(concurrent strategy-probe + pool warming), and supplies a no-opprepare()that subclasses override when they need a real probe.-
host_families : --is-rst--:py:class:`frozenset`\ \[:py:class:`str`] =
frozenset({'unix'})¶ a subset of
{'unix', 'embedded'}. Subclasses declare it; the spec field_validator rejects a backend on a host of the wrong family. A backend with an empty set can never validate and is rejected at registration.- Type:¶
Host families this backend serves
-
host_families : --is-rst--:py:class:`frozenset`\ \[:py:class:`str`] =
-
class otto.host.transfer.EmbeddedFileTransfer(name, exec_cmd=
None, filesystem=None, max_filename_len=255, transfer=None)¶ Bases:
BaseFileTransferShared base for embedded file-transfer backends (console, tftp).
Subclasses
BaseFileTransfer, inheriting itsput_files/get_filesAPI (filename-length validation, shared Rich progress acquisition). Holds the fields common to all embedded selectors: the shell runner (exec_cmd), the on-device filesystem model, and the idempotent mount-done flag. Concrete subclasses implement_run_put/_run_get.-
host_families : --is-rst--:py:class:`frozenset`\ \[:py:class:`str`] =
frozenset({'embedded'})¶ a subset of
{'unix', 'embedded'}. Subclasses declare it; the spec field_validator rejects a backend on a host of the wrong family. A backend with an empty set can never validate and is rejected at registration.- Type:¶
Host families this backend serves
- classmethod create(ctx)¶
Construct from a
TransferContext.Subclasses override this to read selector-specific ctx fields.
- Return type:¶
-
host_families : --is-rst--:py:class:`frozenset`\ \[:py:class:`str`] =
-
class otto.host.transfer.ConsoleFileTransfer(name, exec_cmd, filesystem=
None, max_filename_len=255, transfer=None)¶ Bases:
EmbeddedFileTransferFile transfer for an embedded host, over the device shell only.
Subclasses
EmbeddedFileTransfer, inheriting itsput_files/get_filesAPI (filename-length validation, shared Rich progress acquisition). Implements the abstract_run_put/_run_getagainst the device’sfsshell. The shell command runner is injected asexec_cmdso the class is testable against a fake shell with no real connection.- classmethod create(ctx)¶
Construct from a
TransferContext.Subclasses override this to read selector-specific ctx fields.
- Return type:¶
-
class otto.host.transfer.TftpFileTransfer(name, exec_cmd=
None, filesystem=None, max_filename_len=255, transfer=None)¶ Bases:
EmbeddedFileTransferReserved: TFTP transfer for embedded hosts is not yet implemented.
- classmethod create(ctx)¶
Construct from a
TransferContext.Subclasses override this to read selector-specific ctx fields.
- Return type:¶
-
class otto.host.transfer.ScpFileTransfer(connections, name, exec_cmd, scp_options, max_filename_len=
255)¶ Bases:
UnixFileTransferSCP file transfer backend for UnixHost.
Inherits
put_files/get_filesfromBaseFileTransferand unix scaffolding (_connections,_exec_cmd,_warmup_for_transfer) fromUnixFileTransfer; implements_run_put/_run_getdirectly for the SCP protocol.-
host_families : --is-rst--:py:class:`frozenset`\ \[:py:class:`str`] =
frozenset({'unix'})¶ a subset of
{'unix', 'embedded'}. Subclasses declare it; the spec field_validator rejects a backend on a host of the wrong family. A backend with an empty set can never validate and is rejected at registration.- Type:¶
Host families this backend serves
- classmethod create(ctx)¶
Build a transfer backend from a
TransferContext.The uniform construction seam (WS#4). Concrete backends override this to run their exact construction against the ctx fields they need. Not an
abstractmethoddeliberately: only registered built-ins are ever constructed throughcreate, and test doubles that subclassBaseFileTransferonly to exercise the progress contract must not be forced to implement it.- Return type:¶
-
host_families : --is-rst--:py:class:`frozenset`\ \[:py:class:`str`] =
-
class otto.host.transfer.SftpFileTransfer(connections, name, exec_cmd, max_filename_len=
255)¶ Bases:
UnixFileTransferSFTP file transfer backend for UnixHost.
Inherits
put_files/get_filesfromBaseFileTransferand unix scaffolding (_connections,_exec_cmd,_warmup_for_transfer) fromUnixFileTransfer; implements_run_put/_run_getdirectly for the SFTP protocol.-
host_families : --is-rst--:py:class:`frozenset`\ \[:py:class:`str`] =
frozenset({'unix'})¶ a subset of
{'unix', 'embedded'}. Subclasses declare it; the spec field_validator rejects a backend on a host of the wrong family. A backend with an empty set can never validate and is rejected at registration.- Type:¶
Host families this backend serves
- classmethod create(ctx)¶
Build a transfer backend from a
TransferContext.The uniform construction seam (WS#4). Concrete backends override this to run their exact construction against the ctx fields they need. Not an
abstractmethoddeliberately: only registered built-ins are ever constructed throughcreate, and test doubles that subclassBaseFileTransferonly to exercise the progress contract must not be forced to implement it.- Return type:¶
-
host_families : --is-rst--:py:class:`frozenset`\ \[:py:class:`str`] =
-
class otto.host.transfer.FtpFileTransfer(connections, name, exec_cmd, max_filename_len=
255)¶ Bases:
UnixFileTransferFTP file transfer backend for UnixHost.
Inherits
put_files/get_filesfromBaseFileTransferand unix scaffolding (_connections,_exec_cmd,_warmup_for_transfer) fromUnixFileTransfer; implements_run_put/_run_getdirectly for the FTP protocol.-
host_families : --is-rst--:py:class:`frozenset`\ \[:py:class:`str`] =
frozenset({'unix'})¶ a subset of
{'unix', 'embedded'}. Subclasses declare it; the spec field_validator rejects a backend on a host of the wrong family. A backend with an empty set can never validate and is rejected at registration.- Type:¶
Host families this backend serves
- classmethod create(ctx)¶
Build a transfer backend from a
TransferContext.The uniform construction seam (WS#4). Concrete backends override this to run their exact construction against the ctx fields they need. Not an
abstractmethoddeliberately: only registered built-ins are ever constructed throughcreate, and test doubles that subclassBaseFileTransferonly to exercise the progress contract must not be forced to implement it.- Return type:¶
-
host_families : --is-rst--:py:class:`frozenset`\ \[:py:class:`str`] =