v0.1.0 (CHANGELOG)

This commit is contained in:
Adam Skotarczak 2025-04-26 04:13:07 +02:00
parent 86456cafa3
commit bf1d77feb1
3 changed files with 233 additions and 55 deletions

View File

@ -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`
---

View File

@ -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)

View File

@ -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")