forked from AG_QGIS/Plugin_SN_Basis
186 lines
4.3 KiB
Python
186 lines
4.3 KiB
Python
|
|
"""
|
|||
|
|
snbasis/functions/syswrapper.py – zentrale OS-/Dateisystem-Abstraktion
|
|||
|
|
Robust, testfreundlich, mock-fähig.
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import os
|
|||
|
|
import tempfile
|
|||
|
|
import pathlib
|
|||
|
|
import sys
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ---------------------------------------------------------
|
|||
|
|
# Dateisystem‑Funktionen
|
|||
|
|
# ---------------------------------------------------------
|
|||
|
|
|
|||
|
|
def file_exists(path: str) -> bool:
|
|||
|
|
"""Prüft, ob eine Datei existiert."""
|
|||
|
|
try:
|
|||
|
|
return os.path.exists(path)
|
|||
|
|
except Exception:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
|
|||
|
|
def is_file(path: str) -> bool:
|
|||
|
|
"""Prüft, ob ein Pfad eine Datei ist."""
|
|||
|
|
try:
|
|||
|
|
return os.path.isfile(path)
|
|||
|
|
except Exception:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
|
|||
|
|
def is_dir(path: str) -> bool:
|
|||
|
|
"""Prüft, ob ein Pfad ein Verzeichnis ist."""
|
|||
|
|
try:
|
|||
|
|
return os.path.isdir(path)
|
|||
|
|
except Exception:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
|
|||
|
|
def join_path(*parts) -> str:
|
|||
|
|
"""Verbindet Pfadbestandteile OS‑unabhängig."""
|
|||
|
|
try:
|
|||
|
|
return os.path.join(*parts)
|
|||
|
|
except Exception:
|
|||
|
|
# Fallback: naive Verkettung
|
|||
|
|
return "/".join(str(p) for p in parts)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ---------------------------------------------------------
|
|||
|
|
# Pfad‑ und Systemfunktionen
|
|||
|
|
# ---------------------------------------------------------
|
|||
|
|
|
|||
|
|
def get_temp_dir() -> str:
|
|||
|
|
"""Gibt das temporäre Verzeichnis zurück."""
|
|||
|
|
try:
|
|||
|
|
return tempfile.gettempdir()
|
|||
|
|
except Exception:
|
|||
|
|
return "/tmp"
|
|||
|
|
|
|||
|
|
|
|||
|
|
def get_plugin_root() -> str:
|
|||
|
|
"""
|
|||
|
|
Ermittelt den Plugin‑Root‑Pfad.
|
|||
|
|
Annahme: syswrapper liegt in sn_basis/funktions/
|
|||
|
|
→ also zwei Ebenen hoch.
|
|||
|
|
"""
|
|||
|
|
try:
|
|||
|
|
here = pathlib.Path(__file__).resolve()
|
|||
|
|
return str(here.parent.parent)
|
|||
|
|
except Exception:
|
|||
|
|
# Fallback: aktuelles Arbeitsverzeichnis
|
|||
|
|
return os.getcwd()
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ---------------------------------------------------------
|
|||
|
|
# Datei‑I/O (optional, aber nützlich)
|
|||
|
|
# ---------------------------------------------------------
|
|||
|
|
|
|||
|
|
def read_file(path: str, mode="r"):
|
|||
|
|
"""Liest eine Datei ein. Gibt None zurück, wenn Fehler auftreten."""
|
|||
|
|
try:
|
|||
|
|
with open(path, mode) as f:
|
|||
|
|
return f.read()
|
|||
|
|
except Exception:
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
|
|||
|
|
def write_file(path: str, data, mode="w"):
|
|||
|
|
"""Schreibt Daten in eine Datei. Gibt True/False zurück."""
|
|||
|
|
try:
|
|||
|
|
with open(path, mode) as f:
|
|||
|
|
f.write(data)
|
|||
|
|
return True
|
|||
|
|
except Exception:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ---------------------------------------------------------
|
|||
|
|
# Mock‑Modus (optional erweiterbar)
|
|||
|
|
# ---------------------------------------------------------
|
|||
|
|
|
|||
|
|
class FakeFileSystem:
|
|||
|
|
"""
|
|||
|
|
Minimaler Mock‑Dateisystem‑Ersatz.
|
|||
|
|
Wird nicht automatisch aktiviert, aber kann in Tests gepatcht werden.
|
|||
|
|
"""
|
|||
|
|
files = {}
|
|||
|
|
|
|||
|
|
@classmethod
|
|||
|
|
def add_file(cls, path, content=""):
|
|||
|
|
cls.files[path] = content
|
|||
|
|
|
|||
|
|
@classmethod
|
|||
|
|
def exists(cls, path):
|
|||
|
|
return path in cls.files
|
|||
|
|
|
|||
|
|
@classmethod
|
|||
|
|
def read(cls, path):
|
|||
|
|
return cls.files.get(path, None)
|
|||
|
|
|
|||
|
|
# ---------------------------------------------------------
|
|||
|
|
# Betriebssystem‑Erkennung
|
|||
|
|
# ---------------------------------------------------------
|
|||
|
|
|
|||
|
|
import platform
|
|||
|
|
|
|||
|
|
def get_os() -> str:
|
|||
|
|
"""
|
|||
|
|
Gibt das Betriebssystem zurück:
|
|||
|
|
- 'windows'
|
|||
|
|
- 'linux'
|
|||
|
|
- 'mac'
|
|||
|
|
"""
|
|||
|
|
system = platform.system().lower()
|
|||
|
|
|
|||
|
|
if "windows" in system:
|
|||
|
|
return "windows"
|
|||
|
|
if "darwin" in system:
|
|||
|
|
return "mac"
|
|||
|
|
if "linux" in system:
|
|||
|
|
return "linux"
|
|||
|
|
|
|||
|
|
return "unknown"
|
|||
|
|
|
|||
|
|
|
|||
|
|
def is_windows() -> bool:
|
|||
|
|
return get_os() == "windows"
|
|||
|
|
|
|||
|
|
|
|||
|
|
def is_linux() -> bool:
|
|||
|
|
return get_os() == "linux"
|
|||
|
|
|
|||
|
|
|
|||
|
|
def is_mac() -> bool:
|
|||
|
|
return get_os() == "mac"
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ---------------------------------------------------------
|
|||
|
|
# Pfad‑Normalisierung
|
|||
|
|
# ---------------------------------------------------------
|
|||
|
|
|
|||
|
|
def normalize_path(path: str) -> str:
|
|||
|
|
"""
|
|||
|
|
Normalisiert Pfade OS‑unabhängig:
|
|||
|
|
- ersetzt Backslashes durch Slashes
|
|||
|
|
- entfernt doppelte Slashes
|
|||
|
|
- löst relative Pfade auf
|
|||
|
|
"""
|
|||
|
|
try:
|
|||
|
|
p = pathlib.Path(path).resolve()
|
|||
|
|
return str(p)
|
|||
|
|
except Exception:
|
|||
|
|
# Fallback: einfache Normalisierung
|
|||
|
|
return path.replace("\\", "/").replace("//", "/")
|
|||
|
|
|
|||
|
|
def add_to_sys_path(path: str) -> None:
|
|||
|
|
"""
|
|||
|
|
Fügt einen Pfad sicher zum Python-Importpfad hinzu.
|
|||
|
|
"""
|
|||
|
|
try:
|
|||
|
|
if path not in sys.path:
|
|||
|
|
sys.path.insert(0, path)
|
|||
|
|
except Exception:
|
|||
|
|
pass
|
|||
|
|
|