initial commit

This commit is contained in:
Adam Skotarczak 2025-04-24 13:52:37 +02:00
commit cda71fb8c1
16 changed files with 784 additions and 0 deletions

10
.env.example Normal file
View File

@ -0,0 +1,10 @@
# APP_MODE ungenutzt im Template (production/ development)
APP_MODE=development
# LOGLEVEL: "CRITICAL"- "ERROR" - "WARNING" - "INFO" - "DEBUG"
LOGLEVEL=INFO
# Pfad zum log z.B log/template.log (relativ und absolut beachten!)
# Pfad ist ausgehend vom Ort der run.py und Verzeichnisse werden automatisch erstellt.
# DEFAULT: log/template.log
LOGFILE=log/template.log

184
.gitignore vendored Normal file
View File

@ -0,0 +1,184 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.env.*
!.env.example
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# Ruff stuff:
.ruff_cache/
# PyPI configuration file
.pypirc
# Custom:
logs/
log/
release/
#media/
*.zip
NOTES.md

7
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"recommendations": [
"ms-python.python",
"ms-python.vscode-pylance",
"ms-toolsai.jupyter"
]
}

30
.vscode/settings.jsonc vendored Normal file
View File

@ -0,0 +1,30 @@
{ // Bitte daran denken das Kommentare eigentlich nicht von json unterstützt werden :-)
// Das funktioniert hier nur in Microsofts jsonc im VS-Code!
"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,
"editor.wordWrap": "off"
},
// Für Pythonfiles Tababstand definieren und Tabs durch Leerzeichen ersetzen
"[python]": {
"editor.tabSize": 4,
"editor.insertSpaces": true
},
}

17
.vscode/tasks.json vendored Normal file
View 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"
}
]
}

14
CHANGELOG.md Normal file
View File

@ -0,0 +1,14 @@
# CHANGELOG - Python Flask Template
- [CHANGELOG - Python Flask Template](#changelog---python-flask-template)
- [2025-..-.. - Commit v1.0.1](#2025-----commit-v101)
- [2025-..-.. - Release v1.0.0](#2025-----release-v100)
## 2025-..-.. - Commit v1.0.1
- **Geändert:**
- [ ]
## 2025-..-.. - Release v1.0.0
- **Release 1.0.0** 🚀

254
README.md Normal file
View File

@ -0,0 +1,254 @@
# Python Bootstrap-Flask-Template mit `.venv`- und `.env` Support
![Logo](./media/logo.png)
> ⚙️ Dieses Projekt verwendet [Git Subtree](SUBTREE.md) zur Integration des Basis-Templates. Details siehe [`SUBTREE.md`](SUBTREE.md).
Dieses Template nutzt PEP 8, Type Hints, Docstrings und einen vordefinierten Workspace für sauberen Python-Code.
Außerdem 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`
- Automatischer Neustart in der virtuellen Umgebung
- Unterstützung von Umgebungsvariablen über eine `.env`-Datei
- Sauberer Einstiegspunkt über `run.py`
- Keine systemweiten Python-Pakete notwendig
- Logging-Utils bereits integriert
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.
**Was dieses template __nicht__ ist:**
- [ ] [pep-518](https://peps.python.org/pep-0518/)-konform 🚫
> ⚠️ Dieses Template verfolgt kein komplexes Build-System.
Es ist dafür gedacht, dir in Sekunden eine saubere, gekapselte Python-Umgebung bereitzustellen perfekt zum schnellen Testen, Debuggen oder Projektstart.
Einfach deinen Code in main.py werfen, bei Bedarf requirements.txt anpassen, run.py starten fertig. Kein Setup-Wahnsinn, kein Overhead.
---
## 🔜 Inhalt der Readme
- [Python Bootstrap-Flask-Template mit `.venv`- und `.env` Support](#python-bootstrap-flask-template-mit-venv--und-env-support)
- [🔜 Inhalt der Readme](#-inhalt-der-readme)
- [🔧 Projektstruktur](#-projektstruktur)
- [🚀 Erste Schritte](#-erste-schritte)
- [Beim ersten Start passiert:](#beim-ersten-start-passiert)
- [📦 Abhängigkeiten](#-abhängigkeiten)
- [⚙️ .env-Datei (optional)](#-env-datei-optional)
- [📜 Beispielausgabe](#-beispielausgabe)
- [🪵 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 von `Linter` (`pylint`)](#-einsatz-von-linter-pylint)
- [📁 Lizenz](#-lizenz)
---
## 🔧 Projektstruktur
```plaintext
📁 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
├── 📄 CHANGELOG.md #
├── 📄 VERSION # Versionsinfo zum Paket
├── 📄 run.py # Einstiegspunkt für die Anwendung
├── 📁 media/
│ └── 📄 logo.png # Logo für GitHub
└── 📁 app/
├── 📄 __init__.py #
├── 📄 main.py # Hauptlogik der Anwendung
└── 📄 bootstrap.py # Setup- und Relaunch-Logik
```
> Release-Pakete als `.zip` sind bereits von unötigem Balast bereinigt. Die dargestellte Struktur entspricht einem `git clone`.
[🔝](#-inhalt-der-readme)
---
## 🚀 Erste Schritte
- [ ] `.env.example` in `.env` umbenennen und individuell befüllen.
- [ ] `.vscode`-Verzeichnis löschen, wenn du eigene Einstellungen nutzt. Ich habe es versehentlich committet und aus Bequemlichkeit drin gelassen, weil es meinem Standard entspicht.
- [ ] `requirements.txt` auf deine Bedürfnisse anpassen.
- [ ] `media/`Verzeichnis Löschen falls vorhanden.
**Erster Start des Templates:**
```bash
python run.py
```
### Beim ersten Start passiert:
1. `.venv` wird erstellt (wenn noch nicht vorhanden)
2. `requirements.txt` wird installiert
3. Das Skript wird automatisch innerhalb der venv neu gestartet
4. `.env` wird geladen (falls vorhanden)
5. **Die App startet 🚀**
> Es erfolgen einige Ausgaben, die alle aus der `main.py` stammen, außer du `DEBUG` in der `.env` aktiviert hast.
[🔝](#-inhalt-der-readme)
---
## 📦 Abhängigkeiten
Alle Abhängigkeiten werden aus `requirements.txt` installiert.
**Beispiel:**
```text
python-dotenv
```
[🔝](#-inhalt-der-readme)
---
## ⚙️ .env-Datei (optional)
Wenn vorhanden, wird `.env` automatisch geladen.
**Beispiel:**
```dotenv
APP_MODE=development
LOGLEVEL=debug
PORT=8080
```
Diese Werte sind im Code über `os.getenv("APP_MODE")` verfügbar.
[🔝](#-inhalt-der-readme)
---
## 📜 Beispielausgabe
```text
[BOOTSTRAP] Erstelle virtuelle Umgebung...
[BOOTSTRAP] Installiere pip + requirements.txt...
[BOOTSTRAP] Starte in virtueller Umgebung neu...
[RUN] Lade .env aus: ./cliqrcode/.env
[APP] Starte Anwendung im Modus: development
[APP] Hello, world!
```
[🔝](#-inhalt-der-readme)
---
## 🪵 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 1MB automatisch rotiert (max. 3 Backups), z.B.:
```bash
logs/app.log
logs/app.log.1
logs/app.log.2
```
[🔝](#-inhalt-der-readme)
---
## 🛠 Hinweise
- Das Template ist portabel und benötigt keine global installierten Pakete.
- Du kannst es für jede neue App wiederverwenden.
- `run.py` ist der einzige Einstiegspunkt keine direkten Aufrufe von `main.py`.
[🔝](#-inhalt-der-readme)
---
## 🧪 Getestet mit
- Python 3.11, 3.12, 3.13
- Windows & Linux
- VS Code, Terminal, PowerShell
[🔝](#-inhalt-der-readme)
---
## 🛠 Einsatz von `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.
[🔝](#-inhalt-der-readme)
---
## 📁 Lizenz
MIT frei verwendbar in eigenen Projekten.

20
SUBTREE.md Normal file
View File

@ -0,0 +1,20 @@
# 🌳 Subtree-Konfiguration
Dieses Projekt verwendet einen Git-Subtree zum Einbinden des Basis-Templates:
## 📦 Eingebundenes Repository
- **Name:** `python-template`
- **Quelle:** <https://github.com/realAscot/python-template.git>
- **Branch:** `main`
- **Pfad im Projekt:** `base/`
## 🛠 Einrichtung (einmalig)
```bash
git remote add python-template https://github.com/realAscot/python-template.git
git fetch python-template
git subtree add --prefix base python-template main --squash
```
Dies betrifft dich hautsächlich NUR, wenn Du aktiv an diesem Template weiterentickeln möchtest.

1
VERSION Normal file
View File

@ -0,0 +1 @@
1.0.1

8
app/__init__.py Normal file
View File

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

71
app/bootstrap.py Normal file
View File

@ -0,0 +1,71 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Bootstrap-Modul für automatische Einrichtung und Start der App.
Dieses Modul stellt sicher, dass:
- eine .venv angelegt ist
- python -m pip install -r requirements.txt ausgeführt wurde
- das Skript in der .venv neu gestartet wird, falls nötig
"""
import os
import subprocess
import sys
from pathlib import Path
# Pfad zur virtuellen Umgebung im Projektverzeichnis
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
- requirements.txt installiert
- das Skript in der .venv neu gestartet
"""
if os.environ.get("BOOTSTRAPPED") == "1":
return # Bereits innerhalb der .venv → nichts tun
if not VENV_DIR.exists():
_create_venv()
if Path(sys.executable).resolve() != PYTHON_EXE.resolve():
_relaunch()
def _create_venv():
"""
Legt eine virtuelle Umgebung im Projektverzeichnis an
und installiert alle Pakete aus requirements.txt.
"""
print("[BOOTSTRAP] Erstelle virtuelle Umgebung...")
subprocess.check_call([sys.executable, "-m", "venv", str(VENV_DIR)])
print("[BOOTSTRAP] Installiere pip + requirements.txt...")
subprocess.check_call([str(PYTHON_EXE), "-m", "pip", "install", "--upgrade", "pip"])
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)]
)
else:
print(
"[BOOTSTRAP] ⚠️ Keine requirements.txt gefunden Installation übersprungen."
)
def _relaunch():
"""
Startet das Skript innerhalb der .venv neu.
Verwendet os.execv(), um den Prozess vollständig zu ersetzen.
"""
print("\n[BOOTSTRAP] Starte in virtueller Umgebung neu...")
os.environ["BOOTSTRAPPED"] = "1"
os.execv(str(PYTHON_EXE), [str(PYTHON_EXE)] + sys.argv)

70
app/logging_utils.py Normal file
View File

@ -0,0 +1,70 @@
#!/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", "log/app.log") # 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)
# Debug: Logpfad anzeigen (nur bei DEBUG)
if logger.isEnabledFor(logging.DEBUG):
try:
logger.debug(f"Logdatei: {logfile_path.resolve()}")
except Exception:
pass # Debug-Ausgabe darf nicht blockieren
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

41
app/main.py Normal file
View File

@ -0,0 +1,41 @@
#!/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():
"""
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.
"""
print(f"\n[IFO] 📰 Loglevel aus .env: {os.getenv('LOGFILE')}\n")
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.")

BIN
media/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 KiB

20
requirements.txt Normal file
View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# falls man .env verwenden möchte:
python-dotenv
# Flask
flask
# Projektbezogen ab hier:
# --- ALLES AB HIER IST OPTIONAL ---
# Pytest, Linter und Typ-Prüfung (entfernen bei fertigem Code):
pytest
pytest-cov
pytest-mock
pylint
mypy

37
run.py Normal file
View File

@ -0,0 +1,37 @@
#!/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
- das Skript in der .venv neu gestartet wird
Erst danach wird die .env geladen und die App gestartet.
"""
from app.bootstrap import ensure_venv
if __name__ == "__main__":
ensure_venv()
# .env laden jetzt ist python-dotenv installiert (innerhalb der venv)
from dotenv import find_dotenv, load_dotenv
dotenv_path = find_dotenv()
if dotenv_path:
print(f"\n[RUN] 🚀 Lade .env aus: {dotenv_path}")
load_dotenv(dotenv_path=dotenv_path, override=True)
else:
print("\n[RUN] ⚠️ Keine .env-Datei gefunden")
# Ab hier deine Funktionen aufrufen:
from app.main import main
main()
from app.main import logtest
logtest()