Files
Plugin_SN_Basis/functions/sys_wrapper.py
T
DanielandClaude Sonnet 5 716820be4c get_plugin_root() löst keine Symlinks/Junctions mehr auf (Verfahrensgebiet #50)
Ursache für "QML-Dateien greifen nicht" (Verfahrensgebiet #50): get_plugin_root()
nutzte Path(__file__).resolve(), was Junctions zum echten Zielverzeichnis
auflöst. link_qgis_profile.py verknüpft die Klone im QGIS-Profil per Junction
unter ihrem Paketnamen (sn_verfahrensgebiet, sn_plan41, ...) - .resolve()
sprang dabei zurück zum Workspace-Root, wo die Klone unter ihrem Repo-Namen
(Plugin_SN_*) liegen. Alle Aufrufer von get_plugin_root() (Stilpruefer,
ly_style_wrapper.apply_style, LayerLoader.apply_style, Datenschreiber,
sn_plan41 vln_api_logic/tab_a_logic) suchten dadurch am falschen Ort.

.absolute() statt .resolve(): __file__ liefert beim Import über die Junction
bereits den korrekten, unaufgelösten Pfad - nichts, was aufgelöst werden
müsste. Für echte ZIP-/Repository-Installationen (kein Symlink im Plugin-
Ordner) ändert sich nichts, da dort nichts aufzulösen ist.

Test test_get_plugin_root_folgt_keiner_verzeichnisverknuepfung legt eine
echte Verzeichnisverknüpfung an (Symlink, unter Windows via Junction wie
link_qgis_profile.py) und zeigt den Fehler vor dem Fix rot, danach grün.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 16:11:58 +02:00

113 lines
2.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
sn_basis/functions/sys_wrapper.py – System- und Pfad-Abstraktion
"""
from pathlib import Path
from typing import Union
import sys
from sn_basis.functions.os_wrapper import is_absolute_path, basename
_PathLike = Union[str, Path]
# ---------------------------------------------------------
# Plugin Root
# ---------------------------------------------------------
def get_plugin_root() -> Path:
"""
Liefert das Basisverzeichnis des Plugins.
Löst bewusst keine Symlinks/Junctions auf (``.absolute()`` statt
``.resolve()``): ``link_qgis_profile.py`` verknüpft die Klone im
QGIS-Profil per Junction unter ihrem Paketnamen. Würde hier aufgelöst,
landete man beim Workspace-Root (wo die Klone unter ihrem Repo-Namen
liegen) statt beim QGIS-Plugin-Ordner – Assets von Fachplugins wären dann
nicht mehr auffindbar (Verfahrensgebiet #50).
"""
return Path(__file__).absolute().parents[2]
# ---------------------------------------------------------
# Pfad-Utilities
# ---------------------------------------------------------
def join_path(*parts: _PathLike) -> Path:
"""
Verbindet Pfadbestandteile OS-sicher.
"""
path = Path(parts[0])
for part in parts[1:]:
path /= part
return path
def file_exists(path: _PathLike) -> bool:
"""
Prüft, ob eine Datei existiert.
"""
try:
return Path(path).exists()
except Exception:
return False
def ensure_dir(path: _PathLike) -> Path:
"""
Stellt sicher, dass ein Verzeichnis existiert.
"""
p = Path(path)
p.mkdir(parents=True, exist_ok=True)
return p
# ---------------------------------------------------------
# Datei-IO
# ---------------------------------------------------------
def read_text(path: _PathLike, encoding: str = "utf-8") -> str:
"""
Liest eine Textdatei.
"""
try:
return Path(path).read_text(encoding=encoding)
except Exception:
return ""
def write_text(
path: _PathLike,
content: str,
encoding: str = "utf-8",
) -> bool:
"""
Schreibt eine Textdatei.
"""
try:
Path(path).write_text(content, encoding=encoding)
return True
except Exception:
return False
def add_to_sys_path(path: Union[str, Path]) -> None:
"""
Fügt einen Pfad zu sys.path hinzu, falls er noch nicht enthalten ist.
"""
p = str(path)
if p not in sys.path:
sys.path.insert(0, p)
def getattr_safe(obj, attr, default=None):
"""
Sicherer Zugriff auf ein Attribut.
Gibt das Attribut zurück, wenn es existiert,
ansonsten den Default-Wert (None, wenn nicht angegeben).
"""
try:
return getattr(obj, attr)
except Exception:
return default