v0.1.0 (CHANGELOG)
This commit is contained in:
parent
86456cafa3
commit
bf1d77feb1
29
CHANGELOG.md
29
CHANGELOG.md
@ -1,18 +1,39 @@
|
||||
# CHANGELOG
|
||||
|
||||
- 2025-04-25 - initial commit
|
||||
- **2025-04-26 – Commit v0.1.0**
|
||||
|
||||
- **Geändert:**
|
||||
- [x] `treescanner.py` umgebaut zu kombinierter Modul- und Standalone-Version
|
||||
- [x] `scan_directory()`: Platzhalter `<und …>` wird jetzt mit Datei-Icon und korrektem Connector (`├──`/`└──`) ausgegeben.
|
||||
- [x] `main()`: CLI-Parameterunterstützung via `argparse` implementiert (`-h/--help`, `-n/--max-files-per-dir`, `-d/--max-depth`, `--no-align-comments`).
|
||||
- [x] [README.md](./README.md) überarbeitet
|
||||
|
||||
- **Hinzugefügt:**
|
||||
- [x] Vollständige Google-Style Docstrings für alle Klassen, Methoden und Funktionen.
|
||||
- [x] Umfangreiche Inline-Kommentare zur Erläuterung von Logik und Parametern.
|
||||
|
||||
- **Geprüft:**
|
||||
- [x] Ausgabe von `<und …>` mit Icon und Connector validiert.
|
||||
- [x] CLI-Parameterhandling und Hilfe (`-h`) getestet.
|
||||
- [x] Google-Style Docstrings in VS Code-Tooltips überprüft.
|
||||
|
||||
---
|
||||
|
||||
- **2025-04-25 - initial commit**
|
||||
|
||||
- **Geändert:**
|
||||
- [x] `scanner.py` umgebaut zu kombinierter Modul- und Standalone-Version
|
||||
- [x] Konfigurationsklasse `TreeScannerConfig` eingebaut
|
||||
- [x] Klasse `TreeScanner` erstellt und bestehende Logik dorthin verschoben
|
||||
|
||||
- **Hinzugefügt:**
|
||||
- [x] `test_usage.py` als __Beispiel__ für modulare Verwendung
|
||||
- [x] `test_usage.py` als **Beispiel** für modulare Verwendung
|
||||
- [x] `README.md` erstellt mit Anleitung für Standalone- und Modulnutzung (Template)
|
||||
- [x] `pyproject.toml` erstellt für spätere Paketinstallation mit PEP 621
|
||||
- [ ] `TODO.md` ist eingefügt aber wird vorerst noch nicht versioniert.
|
||||
- [X] `TODO.md` ist eingefügt aber wird vorerst noch nicht versioniert.
|
||||
- [x] `LICENSE.md` eingefügt und vorerst MIT Lizensiert.
|
||||
|
||||
- **Geprüft:**
|
||||
- [x] `scanner.py` solo in ein Verzeichnis kopieren und ausführen mit `python scanner.py`
|
||||
- [x] Import und Nutzung als Modul aus `test_usage.py`
|
||||
|
||||
---
|
||||
|
77
README.md
77
README.md
@ -1,48 +1,83 @@
|
||||
# TreeScanner
|
||||
# README for TreeScanner
|
||||
|
||||
Ein flexibler Verzeichnisscanner für die Kommandozeile **und** zur Einbindung als Python-Modul.
|
||||
Ein flexibler Verzeichnisscanner für die Kommandozeile und zur Einbindung als Python-Modul.
|
||||
|
||||
## Projektstruktur
|
||||
|
||||
```plaintext
|
||||
|
||||
treescanner/
|
||||
├── __init__.py
|
||||
├── __main__.py # Standalone-Ausführung
|
||||
├── scanner.py # Das eigentliche Modul mit Klasse + Logik
|
||||
├── config.py # Konfigurationsklasse separat
|
||||
└── test_usage.py # Beispielverwendung als Modul
|
||||
📁 treescannerASCII/ # Projekt-Root
|
||||
├── 📁 media # Bilder/Icons für GitHub, Ausgabe etc.
|
||||
├── 📄 .gitignore # Ignorierte Dateien
|
||||
├── 📄 CHANGELOG.md # Änderungsprotokoll (Markdown)
|
||||
├── 📄 LICENSE # Lizenzdatei (MIT)
|
||||
├── 📄 README.md # Diese Anleitung
|
||||
├── 📄 TODO.md # Offene Aufgaben
|
||||
├── 📄 __init__.py # Modul-Initialisierung
|
||||
├── 📄 __main__.py # Einstiegspunkt für `python -m treescanner`
|
||||
├── 📄 scanner.py # Hauptimplementierung
|
||||
└── 📄 test_usage.py # Beispiel für Modul-Integration
|
||||
```
|
||||
|
||||
## 🔧 Verwendung als Standalone
|
||||
## 🔧 Standalone-Ausführung (CLI)
|
||||
|
||||
```bash
|
||||
python treescanner.py
|
||||
python scanner.py [root_path] [-n N] [-d DEPTH] [--no-align-comments] [-h]
|
||||
```
|
||||
|
||||
Erzeugt eine Datei `tree.txt` mit der Verzeichnisstruktur ab dem aktuellen Pfad.
|
||||
| Parameter | Beschreibung |
|
||||
|-------------------------|---------------------------------------------------------------------------------------------------------------|
|
||||
| `root_path` | Optionales Verzeichnis, ab dem gescannt wird (Default: aktueller Pfad). |
|
||||
| `-n`, `--max-files-per-dir` | Begrenze die Anzahl an Dateien pro Verzeichnis (Default: 2). |
|
||||
| `-d`, `--max-depth` | Maximale Tiefe der Rekursion; unbegrenzt, wenn nicht gesetzt. |
|
||||
| `--no-align-comments` | Deaktiviert die Ausrichtung der Kommentar-Platzhalter am Zeilenende. |
|
||||
| `-h`, `--help` | Zeigt diese Hilfe an und beendet das Programm. |
|
||||
|
||||
Die Ausgabe wird in die Datei `tree.txt` geschrieben.
|
||||
|
||||
## 🧩 Verwendung als Modul
|
||||
|
||||
```python
|
||||
from treescanner import TreeScanner, TreeScannerConfig
|
||||
|
||||
config = TreeScannerConfig(root_path=".", max_depth=2)
|
||||
# Konfiguration mit Pfad, Auswahl der Maximaltiefe und Ausrichtung
|
||||
config = TreeScannerConfig(
|
||||
root_path="./", # zu scannender Pfad
|
||||
max_depth=3, # maximale Rekursionstiefe
|
||||
max_files_per_dir=5, # bis zu 5 Dateien pro Ordner anzeigen
|
||||
align_comments=True # Kommentare ausrichten
|
||||
)
|
||||
scanner = TreeScanner(config)
|
||||
output = scanner.generate_tree()
|
||||
print(output)
|
||||
```
|
||||
|
||||
## ⚙️ Konfiguration
|
||||
> Hinweis: Alle Klassen und Methoden sind mit **Google-Style Docstrings** versehen. Moderne IDEs (VS Code, PyCharm) zeigen so direkt Parameter und Rückgabetypen als Tooltip an.
|
||||
|
||||
Die `TreeScannerConfig`-Klasse erlaubt dir u. a.:
|
||||
## ⚙️ Konfiguration via `TreeScannerConfig`
|
||||
|
||||
- `root_path`: Startverzeichnis
|
||||
- `max_depth`: maximale Rekursionstiefe
|
||||
- `max_files_per_dir`: wie viele Dateien pro Ordner angezeigt werden
|
||||
- `align_comments`: Kommentar-Ausrichtung aktivieren
|
||||
- `folder_icon` / `file_icon`: Anzeige-Icons
|
||||
| Attribut | Typ | Beschreibung |
|
||||
|-----------------------|-------------------|-------------------------------------------------------------------------|
|
||||
| `root_path: str` | Pfad | Basisverzeichnis zum Scannen (Default: `.`) |
|
||||
| `folder_icon: str` | Unicode-Zeichen | Symbol für Verzeichnisse (Default: 📁) |
|
||||
| `file_icon: str` | Unicode-Zeichen | Symbol für Dateien und Platzhalter (Default: 📄) |
|
||||
| `max_files_per_dir: int` | Ganzzahl | Maximale angezeigte Dateien pro Verzeichnis (Default: 2) |
|
||||
| `max_depth: Optional[int]` | Ganzzahl/None | Maximale Rekursionstiefe, `None` = unlimitiert |
|
||||
| `align_comments: bool` | Wahr/Falsch | Kommentare am Zeilenende ausrichten (Default: `True`) |
|
||||
|
||||
## 📄 Beispielausgabe
|
||||
|
||||
```plaintext
|
||||
📁 treescannerASCII/
|
||||
├── 📁 media
|
||||
│ ├── 📄 favicon.ico
|
||||
│ ├── 📄 logo-bw-1024x1024.png
|
||||
│ └── 📄 <und 3 weitere Dateien>
|
||||
├── 📄 .gitignore
|
||||
├── 📄 CHANGELOG.md
|
||||
├── 📄 README.md
|
||||
└── 📄 <und 12 weitere Dateien>
|
||||
```
|
||||
|
||||
## 📄 Lizenz
|
||||
|
||||
MIT (optional anpassen)
|
||||
MIT – siehe [LICENSE](./LICENSE)
|
||||
|
182
scanner.py
182
scanner.py
@ -1,22 +1,50 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Verzeichnisscanner mit strukturierter Ausgabe.
|
||||
Funktioniert sowohl als Standalone-Skript als auch als einbindbares Modul.
|
||||
TreeScanner: Verzeichnisbaum-Ausgabe mit ASCII-Art.
|
||||
|
||||
Standalone-Ausführung unterstützt folgende CLI-Parameter:
|
||||
root_path Pfad des Stammverzeichnisses (Default: aktuelles Verzeichnis).
|
||||
-n, --max-files-per-dir Maximale Anzahl Dateien pro Verzeichnis (Default: 2).
|
||||
-d, --max-depth Maximale Rekursionstiefe (Default: unbegrenzt).
|
||||
--no-align-comments Deaktiviert das Ausrichten der Kommentare.
|
||||
-h, --help Diese Hilfe anzeigen und Programm beenden.
|
||||
"""
|
||||
|
||||
import os
|
||||
import argparse
|
||||
from typing import Optional, List
|
||||
|
||||
# === Konfigurationsklasse ===
|
||||
class TreeScannerConfig:
|
||||
def __init__(self,
|
||||
root_path: str = ".",
|
||||
folder_icon: str = "\U0001F4C1",
|
||||
file_icon: str = "\U0001F4C4",
|
||||
max_files_per_dir: int = 100,
|
||||
max_depth: Optional[int] = None,
|
||||
align_comments: bool = True): #
|
||||
"""
|
||||
Konfigurationsklasse für den TreeScanner.
|
||||
|
||||
Attributes:
|
||||
root_path (str): Pfad des Stammverzeichnisses.
|
||||
folder_icon (str): Icon für Ordner.
|
||||
file_icon (str): Icon für Dateien und Platzhalter.
|
||||
max_files_per_dir (int): Maximale Anzahl Dateien, die pro Verzeichnis angezeigt werden.
|
||||
max_depth (Optional[int]): Maximale Tiefe der Rekursion (None = unbeschränkt).
|
||||
align_comments (bool): Ob Kommentare am Zeilenende ausgerichtet werden sollen.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
root_path: str = ".",
|
||||
folder_icon: str = "\U0001F4C1",
|
||||
file_icon: str = "\U0001F4C4",
|
||||
max_files_per_dir: int = 2,
|
||||
max_depth: Optional[int] = None,
|
||||
align_comments: bool = True,
|
||||
):
|
||||
"""
|
||||
Args:
|
||||
root_path (str): Pfad des Stammverzeichnisses.
|
||||
folder_icon (str): Icon für Ordner.
|
||||
file_icon (str): Icon für Dateien und Platzhalter.
|
||||
max_files_per_dir (int): Maximale Anzahl Dateien pro Verzeichnis.
|
||||
max_depth (Optional[int]): Maximale Rekursionstiefe, None = unlimitiert.
|
||||
align_comments (bool): Kommentare ausrichten, wenn True.
|
||||
"""
|
||||
self.root_path = root_path
|
||||
self.folder_icon = folder_icon
|
||||
self.file_icon = file_icon
|
||||
@ -24,63 +52,157 @@ class TreeScannerConfig:
|
||||
self.max_depth = max_depth
|
||||
self.align_comments = align_comments
|
||||
|
||||
# === Hauptklasse ===
|
||||
class TreeScanner:
|
||||
"""
|
||||
Klasse zum Scannen von Verzeichnissen und Erzeugen einer ASCII-Baumstruktur.
|
||||
"""
|
||||
|
||||
def __init__(self, config: TreeScannerConfig):
|
||||
"""
|
||||
Args:
|
||||
config (TreeScannerConfig): Konfiguration für den Scanner.
|
||||
"""
|
||||
self.config = config
|
||||
|
||||
def scan_directory(self, path: str, depth: int = 0, prefix: str = "") -> List[str]:
|
||||
lines = []
|
||||
"""
|
||||
Scannt ein Verzeichnis und gibt eine Liste von ASCII-Zeilen zurück.
|
||||
|
||||
Args:
|
||||
path (str): Pfad des zu scannenden Verzeichnisses.
|
||||
depth (int): Aktuelle Rekursionstiefe.
|
||||
prefix (str): Präfix für Einrückung und Connectoren.
|
||||
|
||||
Returns:
|
||||
List[str]: Zeilen mit ASCII-Baumstruktur für dieses Verzeichnis.
|
||||
"""
|
||||
lines: List[str] = []
|
||||
try:
|
||||
entries = sorted(os.listdir(path))
|
||||
except PermissionError:
|
||||
# Zugriff verweigert: Spezielle Rückgabe, kein Rekursionsaufruf
|
||||
return [f"{prefix}└── [Zugriff verweigert] {path}"]
|
||||
|
||||
# Aufteilen in Ordner und Dateien
|
||||
folders = [e for e in entries if os.path.isdir(os.path.join(path, e))]
|
||||
files = [e for e in entries if os.path.isfile(os.path.join(path, e))]
|
||||
|
||||
# 1) Verzeichnisse verarbeiten
|
||||
for idx, folder in enumerate(folders):
|
||||
folder_path = os.path.join(path, folder)
|
||||
# ├──, wenn nicht letzter Ordner oder noch Dateien folgen, sonst └──
|
||||
connector = "├── " if idx < len(folders) - 1 or files else "└── "
|
||||
line = f"{prefix}{connector}{self.config.folder_icon} {folder}"
|
||||
lines.append(line)
|
||||
lines.append(f"{prefix}{connector}{self.config.folder_icon} {folder}")
|
||||
# Rekursive Ausgabe, falls max_depth nicht überschritten
|
||||
if self.config.max_depth is None or depth < self.config.max_depth:
|
||||
# Verlängerung des Präfixes: '│ ' oder Leerraum
|
||||
extension = "│ " if idx < len(folders) - 1 or files else " "
|
||||
lines.extend(self.scan_directory(folder_path, depth + 1, prefix + extension))
|
||||
|
||||
for idx, file in enumerate(files[:self.config.max_files_per_dir]):
|
||||
connector = "├── " if idx < len(files[:self.config.max_files_per_dir]) - 1 else "└── "
|
||||
line = f"{prefix}{connector}{self.config.file_icon} {file}"
|
||||
lines.append(line)
|
||||
# 2) Dateien plus Platzhalter als kombinierte Liste behandeln
|
||||
visible_files = files[: self.config.max_files_per_dir]
|
||||
remaining = len(files) - len(visible_files)
|
||||
|
||||
if len(files) > self.config.max_files_per_dir:
|
||||
remaining = len(files) - self.config.max_files_per_dir
|
||||
lines.append(f"{prefix}└── <und {remaining} weitere Dateien>")
|
||||
# Kombinieren: echte Dateien + Platzhalter
|
||||
combined = visible_files.copy()
|
||||
if remaining > 0:
|
||||
combined.append(f"<und {remaining} weitere Dateien>")
|
||||
|
||||
# Ausgabe mit Datei-Icon für echte Dateien UND Platzhalter
|
||||
for idx, name in enumerate(combined):
|
||||
# ├── für alle außer dem letzten Eintrag, sonst └──
|
||||
connector = "├── " if idx < len(combined) - 1 else "└── "
|
||||
# Icon hinzufügen (auch beim Platzhalter)
|
||||
lines.append(f"{prefix}{connector}{self.config.file_icon} {name}")
|
||||
|
||||
return lines
|
||||
|
||||
def align_lines_with_comments(self, lines: List[str]) -> List[str]:
|
||||
"""
|
||||
Richtet alle Zeilen so aus, dass Kommentare am gleichen Spaltenindex stehen.
|
||||
|
||||
Args:
|
||||
lines (List[str]): Liste der Baumstruktur-Zeilen ohne Kommentare.
|
||||
|
||||
Returns:
|
||||
List[str]: Zeilen mit ausgerichteten Kommentar-Platzhaltern (#).
|
||||
"""
|
||||
# Bestimme Länge der längsten Zeile (ohne Trailing Spaces)
|
||||
max_length = max(len(line.rstrip()) for line in lines)
|
||||
return [
|
||||
line.rstrip() + (" " * (max_length - len(line.rstrip()) + 2)) + "# "
|
||||
for line in lines
|
||||
]
|
||||
aligned: List[str] = []
|
||||
for line in lines:
|
||||
text = line.rstrip()
|
||||
# Padding-Breite: definierte Spaltenausrichtung (+2 Leerzeichen)
|
||||
padding = " " * (max_length - len(text) + 2)
|
||||
aligned.append(text + padding + "# ")
|
||||
return aligned
|
||||
|
||||
def generate_tree(self) -> str:
|
||||
"""
|
||||
Generiert den vollständigen Verzeichnisbaum als String.
|
||||
|
||||
Returns:
|
||||
str: Mehrzeiliger String mit Ordner-Icon, Ordner- und Dateienstruktur.
|
||||
"""
|
||||
# Stammverzeichnisname ermitteln
|
||||
root_name = os.path.basename(os.path.abspath(self.config.root_path)) or self.config.root_path
|
||||
lines = [f"{self.config.folder_icon} {root_name}/"]
|
||||
# Baumstruktur dahinter generieren
|
||||
lines += self.scan_directory(self.config.root_path)
|
||||
|
||||
# Optional Kommentare ausrichten
|
||||
if self.config.align_comments:
|
||||
lines = self.align_lines_with_comments(lines)
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
# === Standalone-Ausführung ===
|
||||
def main():
|
||||
config = TreeScannerConfig()
|
||||
"""
|
||||
Standalone-Ausführung mit CLI-Parameter-Unterstützung.
|
||||
Parse CLI-Argumente und generiere tree.txt.
|
||||
"""
|
||||
# CLI-Parser konfigurieren
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generiert eine ASCII-Baumstruktur eines Verzeichnisses."
|
||||
)
|
||||
# Positionsargument: root_path (optional)
|
||||
parser.add_argument(
|
||||
"root_path",
|
||||
nargs="?",
|
||||
default=".",
|
||||
help="Pfad des Stammverzeichnisses (default: aktuelles Verzeichnis)."
|
||||
)
|
||||
# Optionale Flags und Parameter
|
||||
parser.add_argument(
|
||||
"-n", "--max-files-per-dir",
|
||||
type=int,
|
||||
default=2,
|
||||
help="Maximale Anzahl Dateien pro Verzeichnis (default: 2)."
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d", "--max-depth",
|
||||
type=int,
|
||||
help="Maximale Rekursionstiefe; unbegrenzt, wenn nicht gesetzt."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-align-comments",
|
||||
action="store_false",
|
||||
dest="align_comments",
|
||||
help="Deaktiviert das Ausrichten der Kommentare am Zeilenende."
|
||||
)
|
||||
|
||||
# CLI-Argumente einlesen
|
||||
args = parser.parse_args()
|
||||
|
||||
# Konfiguration auf Basis der CLI-Argumente erstellen
|
||||
config = TreeScannerConfig(
|
||||
root_path=args.root_path,
|
||||
max_files_per_dir=args.max_files_per_dir,
|
||||
max_depth=args.max_depth,
|
||||
align_comments=args.align_comments
|
||||
)
|
||||
scanner = TreeScanner(config)
|
||||
tree_output = scanner.generate_tree()
|
||||
|
||||
# Ausgabe in tree.txt schreiben
|
||||
with open("tree.txt", "w", encoding="utf-8") as f:
|
||||
f.write(tree_output + "\n")
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user