paramikos getcwd() liefert None, solange kein chdir() erfolgt ist. Der
Rueckfall auf "." landete als remote_path in der App, woraus _join()/_abs()
Pfade wie "/./datei" bauten. Der Server loeste die relativ zum Dateisystem-
Root statt zum Home auf -> "No such file" beim Download, "Permission denied"
beim Upload. Das Listing funktionierte, weil listdir(".") serverseitig
relativ zum Home aufgeloest wird -- daher fiel es erst beim Transfer auf.
- connect()/chdir()/listdir() loesen den Pfad ueber sftp.normalize() auf
- _abs() haengt relative Pfade an das CWD an, statt blind "/" voranzustellen
- _copy_tree(): die beiden mkdir-Zweige waren vertauscht. Beim Download
wurde backend.mkdir() auf einen lokalen Pfad angewendet (Verzeichnis
entstand auf dem Server), beim Upload os.makedirs() auf einen entfernten.
Ordner-Transfers waren dadurch in beide Richtungen defekt.
Verifiziert per End-to-End-Test gegen einen echten sshd/SFTP-Server:
Datei- und rekursiver Ordner-Transfer in beide Richtungen.
Closes #3
ftptui
Interaktiver FTP- und SFTP-Client als Terminal-User-Interface in Python.
ftptui ist ein schlanker, aber vollwertiger Dateibrowser für die Kommandozeile.
Er unterstützt klassisches FTP (RFC 959, über die Python-Standardbibliothek
ftplib) sowie SFTP (SSH File Transfer Protocol, über paramiko). Damit deckt
das Tool den überwiegenden Teil der realen Dateiübertragungs-Szenarien ab –
einschließlich SSH-basiertem FTP.
Das Interface ist zweispaltig aufgebaut:
- links das lokale Dateisystem,
- rechts das entfernte System,
mit Dateiübertragung in beide Richtungen, rekursivem Hoch-/Herunterladen von Verzeichnissen, Anlegen, Umbenennen und Löschen sowie speicherbaren Verbindungsprofilen.
Inhaltsverzeichnis
- Funktionen
- Unterstützte Protokolle
- Installation
- Verwendung
- Tastaturkürzel
- Projektstruktur
- Architektur
- Konfiguration & Profile
- Entwicklung
- Testen
- Lizenz
Funktionen
- Dual-Pane-Dateibrowser – Layout und Bedienung im Stil von Total Commander / Midnight Commander: zwei benachbarte Panele (lokal & entfernt) mit den Spalten Name, Größe, Datum, einer Pfadleiste oben, einer Statusleiste unten und grün markiertem aktivem Panel.
- Klassisches Terminal-Thema – schlanker Dark-Look angelehnt an den Dateimanager ranger: schwarzer Hintergrund, Verzeichnisse grün/fett, Auswahl per inverser (hellblauer) Markierung.
- FTP über die Standardbibliothek, SFTP über
paramiko(SSH-FTP). - Herunterladen (
l) und Hochladen (u) einzelner Dateien. - Rekursive Übertragung kompletter Verzeichnisbäume.
- Verzeichnisse anlegen (
n), umbenennen (r), löschen (d), rekursives Löschen nicht-leerer Ordner. - Navigation mit Maus/Tastatur, „eine Ebene hoch“ (
←/⌫),Enteröffnet. - Verbindungsprofile werden als JSON unter
~/.config/ftptui/profiles.jsongespeichert und können wieder geladen werden. - Passwortfelder sind abgedunkelt (
password=True). - Gebaut mit dem terminalfreundlichen TUI-Framework Textual, ohne fancy Material-Design – ein „echtes“ Konsolenprogramm.
Unterstützte Protokolle
| Protokoll | Beschreibung | Bibliothek / Quelle |
|---|---|---|
ftp |
Klassisches File Transfer Protocol (RFC 959) | Standard (kein Drittpaket nötig) |
sftp |
SSH File Transfer Protocol (SSH-FTP) | paramiko |
Hinweis: „SSH-FTP“ kann zweierlei bedeuten – das SFTP-Subsystem über eine SSH-Schicht (hier umgesetzt) oder FTP über einen SSH-Tunnel (sog. „FTP over SSH“). In
ftptuiwird SFTP über SSH unterstützt, der heute übliche und sichere Weg.
Installation
Voraussetzungen
- Python ≥ 3.10
pipund idealerweise eine virtuelle Umgebung
Aus dem Quellverzeichnis
# virtuelle Umgebung anlegen und aktivieren
python3 -m venv .venv
source .venv/bin/activate
# Abhängigkeiten installieren
pip install -e .
# Abhängigkeiten (nur Laufzeit):
# textual - TUI-Framework
# paramiko - SFTP/SSH
Installations- & Deinstallations-Skripte (systemweit)
Im Projektverzeichnis liegen zwei Scripts für eine systemweite Installation
auf Debian/Ubuntu (PEP 668 „externally managed“ wird berücksichtigt: es wird eine
eigene Umgebung unter /opt/ftptui/venv angelegt und nach
/usr/local/bin/ftptui verlinkt):
./install.sh # systemweit installieren (fragt ggf. nach sudo)
./install.sh --force # erneut installieren/aktualisieren
./uninstall.sh # systemweite Installation entfernen (Nutzdaten bleiben)
./uninstall.sh --purge # zusätzlich Konfigurationsdateien löschen
Nach ./install.sh steht das Kommando ftptui global im PATH bereit.
Als Paket
pip install .
Als installiertes Kommando
Nach pip install -e . steht das Kommando ftptui global in der Umgebung bereit:
ftptui
Verwendung
-
Starten:
ftptui -
Im Verbindungsbildschirm die Daten eingeben:
- Verbindungsprofil – ein zuvor gespeichertes Profil auswählen, oder ein neues anlegen.
- Protokoll –
sftp(SSH) oderftp. - Host, Port (SFTP-Vorgabe
22, FTP-Vorgabe21), Benutzer, Passwort. - Auf Verbinden klicken. Der Port wird bei Protokollwechsel automatisch auf den jeweiligen Standard gesetzt.
-
Nach erfolgreicher Verbindung erscheint der Browser-Bildschirm mit zwei Panelen:
- links
/des lokalen Rechners bzw. das Home-Verzeichnis, - rechts das Home-/Root-Verzeichnis des entfernten Systems.
- links
-
Zwischen den Paneelen wechseln mit
Tab. Die fokussierte Tabelle erhält die Aktionen (Hoch-/Herunterladen, Umbenennen, Löschen …).
Tipp: Die Aktionen
u/lwirken auf das gerade in der fokussierten Tabelle angewählte Element und übertragen in die jeweils andere Seite.
Tastaturkürzel
| Taste | Aktion |
|---|---|
Tab |
Zwischen lokalem und entferntem Paneel wechseln |
↑ / ↓ |
Zeilenauswahl bewegen |
→ |
Markierten Ordner/Eintrag öffnen |
← / ⌫ |
Eine Verzeichnisebene höher |
Enter |
Ordner öffnen (aktiv: fokussiertes Paneel) |
↑ .. |
Eine Ebene höher (Tabellenzeile) |
l |
Auswahl herunterladen (entfernt → lokal) |
u |
Auswahl hochladen (lokal → entfernt) |
n |
Neues Verzeichnis anlegen |
d |
Auswahl löschen (rekursiv) |
r |
Auswahl umbenennen |
q / Esc |
Beenden |
Hinweis: Hoch-/Herunterladen (
u/l), Anlegen (n), Löschen (d) und Umbenennen (r) wirken auf das aktive (grün markierte) Paneel. Wechsel der Seite mitTab. Die Pfeiltasten→/←navigieren die Verzeichnisstruktur (öffnen / eine Ebene hoch),↑/↓bewegen die Zeilenauswahl.
Projektstruktur
ftptui/
├── pyproject.toml # Paketmetadaten, Abhängigkeiten, Einstiegspunkt
├── README.md # diese Dokumentation
├── install.sh # systemweite Installation (/opt/ftptui/venv)
├── uninstall.sh # Deinstallation systemweiter Installation
├── .gitignore
└── ftptui/
├── __init__.py # Versionsnummer
├── app.py # Textual-TUI: Verbindungs- & Browser-Bildschirme
├── backend.py # Fabrik: wählt FTP- oder SFTP-Transport
├── config.py # Speicherung/Laden der Verbindungsprofile (JSON)
├── models.py # Datentypen & Transport-Protokoll
├── ftp_backend.py # FTP-Adapter (ftplib)
└── sftp_backend.py # SFTP-Adapter (paramiko)
Architektur
Die App trennt Oberfläche (Textual) von Transport (Netzwerkprotokolle) durch ein kleines Protokoll/Interface:
FileTransferBackend(inmodels.py) definiert die gemeinsame API.FTPBackendundSFTPBackendimplementieren sie.create_backend(protocol)inbackend.pyliefert den passenden Adapter.
Gemeinsame Schnittstelle (Auszug):
def connect(host, port, username, password) -> None
def listdir(path) -> list[RemoteEntry]
def chdir(path) / pwd() -> str
def download(remote, local) -> None
def upload(local, remote) -> None
def mkdir(path) / remove / rmdir / rename
def close() -> None
RemoteEntry beschreibt einen Eintrag mit name, kind (file/dir),
size und modified. Dadurch kann die Oberfläche unabhängig vom Protokoll
arbeiten – das Hinzufügen weiterer Backends (z. B. WebDAV) ist ohne Änderung
der UI möglich.
Pfadbehandlung
Beide Backends normalisieren Pfade zu absoluten Angaben relativ zum Root
des entfernten Systems. FTP-Operationen setzen das Arbeitsverzeichnis vor einer
Aktion auf /, sodass Dateiübertragungen unabhängig vom zuletzt betrachteten
Ordner zuverlässig funktionieren. SFTP nutzt absolute Pfade direkt.
Profilwertung
Profile werden als JSON in ~/.config/ftptui/profiles.json (bzw.
$XDG_CONFIG_HOME/ftptui/profiles.json) gespeichert. Das Passwort wird nur
abgelegt, wenn es entsprechend markiert wurde (aktuell standardmäßig direkt
gespeichert – Datenschutz-Hinweis siehe unten).
Konfiguration & Profile
Profile speichern: im Verbindungsbildschirm Daten eingeben und Profil speichern drücken. Gespeicherte Einträge erscheinen künftig im Dropdown Verbindungsprofil.
Beispieldatei ~/.config/ftptui/profiles.json:
[
{
"name": "git.sysdaemon.xyz",
"protocol": "sftp",
"host": "git.sysdaemon.xyz",
"port": 22,
"username": "user",
"password": "",
"save_password": false
},
{
"name": "backup-server",
"protocol": "ftp",
"host": "backup.local",
"port": 21,
"username": "ftpuser",
"password": "secret",
"save_password": true
}
]
Sicherheitshinweis: Speichern Sie Passwörter in Profilen nur auf vertrauenswürdigen Systemen. Die Datei liegt im Klartext im Benutzerverzeichnis.
Entwicklung
# Umgebung
python3 -m venv .venv && source .venv/bin/activate
pip install -e . "textual>=0.80.0" "paramiko>=3.4.0"
# Laufzeit prüfen
python -c "import ftptui; print(ftptui.__version__)"
# App booten (Konsolen-Test)
ftptui
Code-Stil & Qualität
- Typannotationen (
from __future__ import annotations) durchgängig. - Protokoll-/Interface-basierte Implementierung mit
typing.Protocol. - Keine Abhängigkeit auf Drittanbieter außer
textualundparamiko.
Testen
Die Backends werden gegen lokale Testserver end-to-end getestet:
- FTP gegen
pyftpdlib(nur für Tests; nicht Teil der Laufzeit-Abhängigkeiten), - SFTP gegen eine eigene
paramiko-SSH-Server-Implementierung.
Ablauf der Tests: Verbinden, Listings, Download, Upload, mkdir, rename,
remove, rekursives rmdir, close – für beide Protokolle.
pip install pyftpdlib
python tests/test_backends.py # Beispieldatei (siehe Entwicklung/Skripte)
Ein ausführbares Testskript kann ergänzt und an dieser Stelle dokumentiert werden; die Backends sind derart modular, dass sie ohne Terminal getestet werden können.
Lizenz
MIT – siehe Projektträger/Repositories. Keine gewerblichen Einschränkungen.
Changelog
v0.3.0
- Bugfix (Pfeil-Navigation): Im Dateibrowser navigieren die Pfeiltasten nun
im File-Manager-Stil:
←wechselt eine Ebene nach oben,→öffnet den markierten Eintrag,↑/↓bewegen die Auswahl. Zuvor verschluckte dasDataTable-Widget die Tasten (Widget-Bindings haben Vorrang). Dafür wird die neueFileTable-Klasse genutzt, dieleft/rightpassend umbindet. - Bugfix (Tab-Panel-Wechsel):
Tabwechselt jetzt zuverlässig zwischen dem lokalen und dem entfernten Paneel (expliziteaction_focus_nextstatt unzuverlässigemfocus_next). - Bugfix (
_selected): Die Auswahlauswertung liefert jetzt die Klartext-Zeichenkette statt einesrich.Text-Objekts, wodurch Öffnen/Enter nicht mehr mitAttributeErrorabstürzte. - Neu:
install.sh/uninstall.shfür systemweite Installation (PEP-668-konform via/opt/ftptui/venv+/usr/local/bin/ftptui).
v0.2.0
- Bugfix: Wechsel in den Browser-Bildschirm korrigiert
(
set_screen→switch_screen). Vorher führte eine erfolgreiche Verbindung in einenAttributeErrorund der FTP/SFTP-Client beendete sich. - Theme: Umstellung auf ein klassisches Terminal-Design im Stil von ranger (Dark-Look, grün/fette Verzeichnisse, inverse Auswahl).
- Layout: Neuaufbau als Total-Commander-artiger Dual-Pane-Browser mit Pfadleiste oben, Statusleiste unten und grün markiertem aktivem Panel.
- Datums-Spalte wird nun als lesbares Datum (
YYYY-MM-DD HH:MM) angezeigt.
v0.1.0
- Erste Veröffentlichung: FTP- & SFTP-Backends, TUI, Verbindungsprofile.
Projekt wird innerhalb der sysdaemon.xyz-Instanz über Gitea verwaltet –
https://git.sysdaemon.xyz/x3/ftptui.