Initialer stabiler Stand
- Bootstrap mit .venv-Autoinstall und Relaunch - Logging-Modul mit Loglevel-Fallback und optionaler Rotation - .env-Support via python-dotenv - Beispielstruktur für portable Python-Apps - Umfangreiche README mit Anleitung und Logging-Kapitel - .env.example enthalten - VS Code-Tasks integriert
This commit is contained in:
parent
ee80f056ff
commit
39aacfa931
8
.env.example
Normal file
8
.env.example
Normal file
@ -0,0 +1,8 @@
|
||||
# APP_MODE ungenutzt im Template
|
||||
APP_MODE=
|
||||
|
||||
# LOGLEVEL: "CRITICAL"- "ERROR" - "WARNING" - "INFO" - "DEBUG"
|
||||
LOGLEVEL=INFO
|
||||
|
||||
# Pfad zum log z.B log/template.log
|
||||
LOGFILE=log/template.log
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -129,6 +129,8 @@ celerybeat.pid
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
@ -172,3 +174,9 @@ cython_debug/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
# Custom:
|
||||
logs/
|
||||
log/
|
||||
*.zip
|
||||
|
||||
|
7
.vscode/extensions.json
vendored
Normal file
7
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"ms-python.python",
|
||||
"ms-python.vscode-pylance",
|
||||
"ms-toolsai.jupyter"
|
||||
]
|
||||
}
|
24
.vscode/settings.json
vendored
Normal file
24
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"python.linting.enabled": true,
|
||||
"python.linting.pylintEnabled": true,
|
||||
"python.linting.mypyEnabled": true,
|
||||
"python.linting.pylintArgs": ["--disable=C0114,C0115,C0116"],
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": "explicit"
|
||||
},
|
||||
"python.analysis.typeCheckingMode": "basic",
|
||||
|
||||
// Abschliessende Leerzeichen entfernen:
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.insertFinalNewline": true,
|
||||
|
||||
// Markdown für das Entfernen von abschliessenden Leerzeichen rausnehmen:
|
||||
"[markdown]": {
|
||||
"files.trimTrailingWhitespace": false
|
||||
},
|
||||
"[python]": {
|
||||
"editor.tabSize": 4,
|
||||
"editor.insertSpaces": true
|
||||
}
|
||||
}
|
17
.vscode/tasks.json
vendored
Normal file
17
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Linter (pylint)",
|
||||
"type": "shell",
|
||||
"command": "pylint beispiel.py",
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "Typprüfung (mypy)",
|
||||
"type": "shell",
|
||||
"command": "mypy beispiel.py",
|
||||
"group": "build"
|
||||
}
|
||||
]
|
||||
}
|
117
README.md
117
README.md
@ -1,6 +1,7 @@
|
||||
# Python Bootstrap-Template mit `.venv` und `.env` Support
|
||||
|
||||
Dieses Projekt bietet ein portables Start-Template für Python-Anwendungen mit folgenden Features:
|
||||
Dieses Template nutzt PEP 8, Type Hints, Docstrings und einen vordefinierten Workspace für sauberen Python-Code.
|
||||
Ausserdem bietet es ein portables Start-Template für Python-Anwendungen mit folgenden Features:
|
||||
|
||||
- Automatische Erstellung einer virtuellen Umgebung (`.venv`)
|
||||
- Automatische Installation von Abhängigkeiten aus `requirements.txt`
|
||||
@ -9,6 +10,10 @@ Dieses Projekt bietet ein portables Start-Template für Python-Anwendungen mit f
|
||||
- Sauberer Einstiegspunkt über `run.py`
|
||||
- Keine systemweiten Python-Pakete notwendig
|
||||
|
||||
Das Template ist durchdacht, pragmatisch und stark auf Entwicklerkomfort ausgelegt.
|
||||
Es bietet eine sehr gute Grundlage für Projekte aller Art – insbesondere CLI-Tools, kleine Services und lokale Anwendungen.
|
||||
Die automatische Einrichtung der virtuellen Umgebung hebt es funktional deutlich von Standard-Vorlagen ab.
|
||||
|
||||
---
|
||||
|
||||
- [Python Bootstrap-Template mit `.venv` und `.env` Support](#python-bootstrap-template-mit-venv-und-env-support)
|
||||
@ -19,8 +24,14 @@ Dieses Projekt bietet ein portables Start-Template für Python-Anwendungen mit f
|
||||
- [⚙️ .env-Datei (optional)](#️-env-datei-optional)
|
||||
- [📜 Beispielausgabe](#-beispielausgabe)
|
||||
- [🧼 Optional: `.env.example`](#-optional-envexample)
|
||||
- [🪵 Logging](#-logging)
|
||||
- [🔧 Konfiguration (in `.env`)](#-konfiguration-in-env)
|
||||
- [📥 Beispielausgabe](#-beispielausgabe-1)
|
||||
- [📌 Logik im Code](#-logik-im-code)
|
||||
- [📁 Logrotation](#-logrotation)
|
||||
- [🛠 Hinweise](#-hinweise)
|
||||
- [🧪 Getestet mit](#-getestet-mit)
|
||||
- [🛠 Einsatz Linter (`pylint`)](#-einsatz-linter-pylint)
|
||||
- [📁 Lizenz](#-lizenz)
|
||||
|
||||
---
|
||||
@ -29,14 +40,20 @@ Dieses Projekt bietet ein portables Start-Template für Python-Anwendungen mit f
|
||||
|
||||
```plaintext
|
||||
|
||||
template-root/
|
||||
├── .env # Projektkonfiguration (optional, wird automatisch geladen)
|
||||
├── requirements.txt # Abhängigkeiten (z. B. python-dotenv)
|
||||
├── run.py # Einstiegspunkt für die Anwendung
|
||||
└── app/
|
||||
├── __init__.py
|
||||
├── main.py # Hauptlogik der Anwendung
|
||||
└── bootstrap.py # Setup- und Relaunch-Logik
|
||||
📁 template-root/
|
||||
├── 📁 .vscode/ # Projekteinstellungen VS-Code
|
||||
│ ├── 📄 settings.json # Einstellungen
|
||||
│ └── 📄 extensions.json # Erweiterungen
|
||||
├── 📄 .env # Projektkonfiguration (optional, nicht im git)
|
||||
├── 📄 .env.example # Vorlage der .env
|
||||
├── 📄 requirements.txt # Abhängigkeiten (z.B. python-dotenv)
|
||||
├── 📄 README.md # diese Datei
|
||||
├── 📄 VERSION # Versionsinfo zum Paket
|
||||
├── 📄 run.py # Einstiegspunkt für die Anwendung
|
||||
└── 📁 app/ #
|
||||
├── 📄 __init__.py #
|
||||
├── 📄 main.py # Hauptlogik der Anwendung
|
||||
└── 📄 bootstrap.py # Setup- und Relaunch-Logik
|
||||
```
|
||||
|
||||
---
|
||||
@ -59,7 +76,8 @@ python run.py
|
||||
|
||||
## 📦 Abhängigkeiten
|
||||
|
||||
Alle Abhängigkeiten werden aus `requirements.txt` installiert. Beispiel:
|
||||
Alle Abhängigkeiten werden aus `requirements.txt` installiert.
|
||||
**Beispiel:**
|
||||
|
||||
```text
|
||||
python-dotenv
|
||||
@ -69,7 +87,8 @@ python-dotenv
|
||||
|
||||
## ⚙️ .env-Datei (optional)
|
||||
|
||||
Wenn vorhanden, wird `.env` automatisch geladen. Beispiel:
|
||||
Wenn vorhanden, wird `.env` automatisch geladen.
|
||||
**Beispiel:**
|
||||
|
||||
```dotenv
|
||||
APP_MODE=development
|
||||
@ -106,6 +125,56 @@ LOGLEVEL=info
|
||||
|
||||
---
|
||||
|
||||
## 🪵 Logging
|
||||
|
||||
Dieses Template verwendet ein integriertes Logging-Modul mit folgenden Eigenschaften:
|
||||
|
||||
- Ausgabe in die Konsole (immer aktiv)
|
||||
- Optionale Ausgabe in eine Logdatei (`LOGFILE`)
|
||||
- Unterstützung für rotierende Logdateien
|
||||
- Loglevel konfigurierbar über `.env`
|
||||
- Plattformunabhängig (Windows, Linux, macOS)
|
||||
- Keine externen Abhängigkeiten
|
||||
|
||||
### 🔧 Konfiguration (in `.env`)
|
||||
|
||||
```dotenv
|
||||
LOGLEVEL=INFO # Möglich: DEBUG, INFO, WARNING, ERROR, CRITICAL
|
||||
LOGFILE=logs/app.log # Optionaler Pfad zur Logdatei (relativ oder absolut)
|
||||
```
|
||||
|
||||
> Wenn `LOGFILE` nicht gesetzt ist, wird nur in die Konsole geloggt.
|
||||
|
||||
### 📥 Beispielausgabe
|
||||
|
||||
```bash
|
||||
[2025-04-23 14:10:00] INFO app.main: Template ready.
|
||||
[2025-04-23 14:10:00] DEBUG app.main: Dies ist eine Debug-Meldung.
|
||||
```
|
||||
|
||||
### 📌 Logik im Code
|
||||
|
||||
In beliebigen Modulen kannst du so einen Logger verwenden:
|
||||
|
||||
```python
|
||||
from app.logging_utils import get_logger
|
||||
|
||||
log = get_logger(__name__)
|
||||
log.info("Template ready.")
|
||||
```
|
||||
|
||||
### 📁 Logrotation
|
||||
|
||||
Die Logdatei wird bei 1 MB automatisch rotiert (max. 3 Backups), z. B.:
|
||||
|
||||
```bash
|
||||
logs/app.log
|
||||
logs/app.log.1
|
||||
logs/app.log.2
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠 Hinweise
|
||||
|
||||
- Das Template ist portabel und benötigt keine global installierten Pakete.
|
||||
@ -122,6 +191,32 @@ LOGLEVEL=info
|
||||
|
||||
---
|
||||
|
||||
## 🛠 Einsatz Linter (`pylint`)
|
||||
|
||||
|
||||
|
||||
```cmd
|
||||
PS C:\Users\adams\Documents\template> .\.venv\Scripts\activate
|
||||
```
|
||||
|
||||
```cmd
|
||||
(.venv) PS C:\Users\adams\Documents\template> pylint.exe run.py
|
||||
```
|
||||
|
||||
```cmd
|
||||
************* Module run
|
||||
run.py:27:4: C0412: Imports from package app are not grouped (ungrouped-imports)
|
||||
run.py:12:0: W0611: Unused import os (unused-import)
|
||||
|
||||
-----------------------------------
|
||||
Your code has been rated at 8.33/10
|
||||
```
|
||||
|
||||
**Bonus:**
|
||||
Durch den Einsatz der <.vscode/task.json> für VS-Code, kannst du in VS-Code mit `Strg + Umschalt + P` → `Tasks: Run Task` → `Linter (pylint)` oder `Typprüfung (mypy)` aufrufen.
|
||||
|
||||
---
|
||||
|
||||
## 📁 Lizenz
|
||||
|
||||
MIT – frei verwendbar in eigenen Projekten.
|
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Hier liegen die Dateien für die primäre Logik der Anwendung
|
||||
|
||||
Diese Information hier stammt aus der datei ./app/__init__.py
|
||||
"""
|
@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Bootstrap-Modul für automatische Einrichtung und Start der App.
|
||||
@ -8,8 +10,8 @@ Dieses Modul stellt sicher, dass:
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Pfad zur virtuellen Umgebung im Projektverzeichnis
|
||||
@ -17,14 +19,15 @@ VENV_DIR = Path(__file__).resolve().parent.parent / ".venv"
|
||||
# Pfad zum Python-Interpreter in der venv
|
||||
PYTHON_EXE = VENV_DIR / ("Scripts" if os.name == "nt" else "bin") / "python"
|
||||
|
||||
|
||||
def ensure_venv():
|
||||
"""
|
||||
Prüft, ob die .venv existiert und ob das aktuelle Skript
|
||||
bereits innerhalb der venv ausgeführt wird.
|
||||
Falls nicht, wird:
|
||||
- die venv erstellt
|
||||
- die .venv erstellt
|
||||
- requirements.txt installiert
|
||||
- das Skript in der venv neu gestartet
|
||||
- das Skript in der .venv neu gestartet
|
||||
"""
|
||||
if os.environ.get("BOOTSTRAPPED") == "1":
|
||||
return # Bereits innerhalb der .venv → nichts tun
|
||||
@ -35,6 +38,7 @@ def ensure_venv():
|
||||
if Path(sys.executable).resolve() != PYTHON_EXE.resolve():
|
||||
_relaunch()
|
||||
|
||||
|
||||
def _create_venv():
|
||||
"""
|
||||
Legt eine virtuelle Umgebung im Projektverzeichnis an
|
||||
@ -48,9 +52,14 @@ def _create_venv():
|
||||
|
||||
req_file = Path(__file__).resolve().parent.parent / "requirements.txt"
|
||||
if req_file.exists():
|
||||
subprocess.check_call([str(PYTHON_EXE), "-m", "pip", "install", "-r", str(req_file)])
|
||||
subprocess.check_call(
|
||||
[str(PYTHON_EXE), "-m", "pip", "install", "-r", str(req_file)]
|
||||
)
|
||||
else:
|
||||
print("[BOOTSTRAP] ⚠️ Keine requirements.txt gefunden – Installation übersprungen.")
|
||||
print(
|
||||
"[BOOTSTRAP] ⚠️ Keine requirements.txt gefunden – Installation übersprungen."
|
||||
)
|
||||
|
||||
|
||||
def _relaunch():
|
||||
"""
|
||||
|
62
app/logging_utils.py
Normal file
62
app/logging_utils.py
Normal file
@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Zentrales Logging-Modul
|
||||
→ Unterstützt LOGLEVEL und LOGFILE aus der .env
|
||||
→ Plattformunabhängig (Windows/Linux)
|
||||
→ Erstellt automatisch das Log-Verzeichnis bei Bedarf
|
||||
→ Fällt bei ungültigem Log-Level sicher auf INFO zurück
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def safe_log_level(level_str: str) -> int:
|
||||
"""Wandelt einen Level-String in einen gültigen Logging-Level um."""
|
||||
levels = {
|
||||
"CRITICAL": logging.CRITICAL,
|
||||
"ERROR": logging.ERROR,
|
||||
"WARNING": logging.WARNING,
|
||||
"INFO": logging.INFO,
|
||||
"DEBUG": logging.DEBUG,
|
||||
"NOTSET": logging.NOTSET,
|
||||
}
|
||||
return levels.get(level_str.upper(), logging.INFO)
|
||||
|
||||
|
||||
LOGLEVEL = safe_log_level(os.getenv("LOGLEVEL", "INFO"))
|
||||
LOGFILE = os.getenv("LOGFILE") # z. B. logs/app.log
|
||||
|
||||
|
||||
def get_logger(name: str) -> logging.Logger:
|
||||
logger = logging.getLogger(name)
|
||||
if logger.handlers:
|
||||
return logger # Logger bereits konfiguriert
|
||||
|
||||
logger.setLevel(LOGLEVEL)
|
||||
|
||||
formatter = logging.Formatter("[%(asctime)s] %(levelname)s %(name)s: %(message)s")
|
||||
|
||||
# Konsole
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setFormatter(formatter)
|
||||
logger.addHandler(console_handler)
|
||||
|
||||
# Datei (optional)
|
||||
if LOGFILE:
|
||||
logfile_path = Path(LOGFILE)
|
||||
try:
|
||||
logfile_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
file_handler = RotatingFileHandler(
|
||||
logfile_path, maxBytes=1_000_000, backupCount=3, encoding="utf-8"
|
||||
)
|
||||
file_handler.setFormatter(formatter)
|
||||
logger.addHandler(file_handler)
|
||||
except Exception as e:
|
||||
logger.warning(f"Konnte Logdatei nicht schreiben: {e}")
|
||||
|
||||
return logger
|
33
app/main.py
33
app/main.py
@ -1,12 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
./app/main.py
|
||||
|
||||
Hier beginnt deine eigentliche Anwendung.
|
||||
Alle Konfigurationen aus .env sind jetzt über os.getenv() verfügbar.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from app.logging_utils import get_logger
|
||||
|
||||
log = get_logger(__name__)
|
||||
|
||||
|
||||
def main():
|
||||
mode = os.getenv("APP_MODE", "development")
|
||||
print(f"[APP] Starte Anwendung im Modus: {mode}")
|
||||
print("[APP] Hello, world!")
|
||||
"""
|
||||
Hier liegen die Dateien für die primäre Logik der Anwendung
|
||||
Diese Information hier stammt aus der datei ./app/__init__.py
|
||||
"""
|
||||
# Hole APP_MODE aus der .env
|
||||
mode = os.getenv("APP_MODE", "DEVEL")
|
||||
|
||||
# Testausgabe:
|
||||
print(f"[APP] 🚀 Starte Anwendung im Modus: {mode}")
|
||||
print("[APP] 📦 -= Hello, world! =-")
|
||||
|
||||
|
||||
def logtest():
|
||||
"""
|
||||
wirft testweise alle Logvarianten aus.
|
||||
"""
|
||||
log.info("Template ready.")
|
||||
log.debug("Dies ist eine Debug-Meldung.")
|
||||
log.warning("Dies ist eine Warnung.")
|
||||
log.error("Dies ist eine Fehlermeldung.")
|
||||
log.critical("Dies ist eine kritische Meldung.")
|
||||
|
@ -1 +1,16 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# falls man .env verwenden möchte:
|
||||
python-dotenv
|
||||
|
||||
# Projektbezogen ab hier:
|
||||
|
||||
|
||||
# --- ALLES AB HIER IST OPTIONAL ---
|
||||
|
||||
# Pytest, Linter und Typprüfung:
|
||||
pytest
|
||||
pytest-cov
|
||||
pytest-mock
|
||||
pylint
|
||||
mypy
|
||||
|
17
run.py
17
run.py
@ -1,7 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Einstiegspunkt der Anwendung.
|
||||
|
||||
Sorgt dafür, dass beim ersten Start automatisch:
|
||||
- eine virtuelle Umgebung (.venv) angelegt wird
|
||||
- alle Abhängigkeiten installiert werden
|
||||
@ -10,19 +12,28 @@
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from app.bootstrap import ensure_venv
|
||||
|
||||
if __name__ == "__main__":
|
||||
ensure_venv()
|
||||
|
||||
# .env laden – jetzt ist python-dotenv installiert (innerhalb der venv)
|
||||
from dotenv import load_dotenv, find_dotenv
|
||||
from dotenv import find_dotenv, load_dotenv
|
||||
|
||||
dotenv_path = find_dotenv()
|
||||
if dotenv_path:
|
||||
print(f"\n[RUN] Lade .env aus: {dotenv_path}")
|
||||
print(f"\n[RUN] 🚀 Lade .env aus: {dotenv_path}")
|
||||
load_dotenv(dotenv_path=dotenv_path, override=True)
|
||||
else:
|
||||
print("[RUN] ⚠️ Keine .env-Datei gefunden")
|
||||
print("\n[RUN] ⚠️ Keine .env-Datei gefunden")
|
||||
|
||||
# Ab hier deine Funktionen aufrufen:
|
||||
|
||||
from app.main import main
|
||||
|
||||
main()
|
||||
|
||||
from app.main import logtest
|
||||
|
||||
logtest()
|
||||
|
Loading…
x
Reference in New Issue
Block a user