Source code for ogstools.ogs6py.python_script
# SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
# SPDX-License-Identifier: BSD-3-Clause
import shutil
from pathlib import Path
from lxml import etree as ET
from ogstools.core.storage import StorageBase
from ogstools.ogs6py import build_tree
[docs]
class PythonScript(build_tree.BuildTree, StorageBase):
"""
Class managing the python script file (.py) for an OGS project.
Tracks both the XML reference to the script and the actual file,
enabling proper save/copy operations.
"""
__hash__ = None
[docs]
def __init__(self, tree: ET.ElementTree) -> None:
"""
Initialize a PythonScript object.
:param tree: The Project's XML ElementTree (shared reference)
"""
build_tree.BuildTree.__init__(self, tree)
StorageBase.__init__(self, "PythonScript", "py")
self.root = self.tree.getroot()
self.populate_tree(self.root, "python_script", overwrite=True)
@property
def filename(self) -> str | None:
"""Get the python script filename from the XML tree."""
script_elem = self.root.find("python_script")
if script_elem is not None and script_elem.text:
return script_elem.text.strip() or None
return None
[docs]
def add_python_script(self, file_pathname: str | Path) -> None:
"""
Add/set a python script file.
:param file_pathname: The file path and name of the python script
"""
file_pathname = Path(file_pathname)
self._bind_to_path(file_pathname)
self.populate_tree(
self.root,
"python_script",
text=str(file_pathname.name),
overwrite=True,
)
[docs]
def set_pyscript(self, filename: str) -> None:
"""
Set a filename for a python script.
:param filename:
"""
self.add_python_script(filename)
def _propagate_target(self) -> None:
"""No children to propagate to."""
def _save_impl(self, dry_run: bool = False) -> list[Path]:
"""
Save the python script file to the target location.
:param dry_run: If True, don't actually copy the file
:returns: List of saved file paths
"""
if not self.filename:
return []
target = self.next_target
if dry_run:
return [target]
target.parent.mkdir(parents=True, exist_ok=True)
if (
self.active_target
and self.active_target.exists()
and self.active_target.resolve() != target.resolve()
):
shutil.copy2(self.active_target, target)
return [target]
[docs]
def save(
self,
target: Path | str | None = None,
overwrite: bool | None = None,
dry_run: bool = False,
archive: bool = False,
id: str | None = None,
) -> list[Path]:
"""
Save the python script file.
:param target: Optional target path
:param overwrite: If True, overwrite existing files
:param dry_run: If True, simulate without writing
:param archive: If True, materialize symlinks
:param id: Optional identifier. Mutually exclusive with target.
:returns: List of saved file paths
"""
if not self.filename:
return []
user_defined = self._pre_save(target, overwrite, dry_run, id=id)
files = self._save_impl(dry_run)
if files:
self._post_save(user_defined, archive, dry_run)
return files
def __eq__(self, other: object) -> bool:
if not isinstance(other, PythonScript):
return NotImplemented
# Compare file contents by full path
if self.active_target is None or other.active_target is None:
return self.active_target == other.active_target
if not self.active_target.exists() or not other.active_target.exists():
return False
return (
self.active_target.read_bytes() == other.active_target.read_bytes()
)
def __repr__(self) -> str:
return f"PythonScript(filename={self.filename!r}, is_saved={self.is_saved})"
def __str__(self) -> str:
if not self.filename:
return "PythonScript: (no script defined)"
return f"PythonScript: {self.filename})"