Source code for sec_interp.core.utils.resource_manager

from __future__ import annotations

"""Resource management utilities for SecInterp.

This module provides context managers for handling temporary QGIS resources
and system files to ensure proper cleanup and prevent resource leaks.
"""

import contextlib
import os
import tempfile
from collections.abc import Generator

from qgis.core import QgsMapLayer, QgsProject, QgsVectorLayer

from sec_interp.logger_config import get_logger

logger = get_logger(__name__)


[docs] @contextlib.contextmanager def temporary_memory_layer( uri: str, name: str, provider: str = "memory" ) -> Generator[QgsVectorLayer, None, None]: """Context manager for a temporary QGIS memory layer. The layer is created and optionally added to the project. It is automatically removed from the project and deleted when the context exits. Args: uri: Layer URI (e.g., "LineString?crs=EPSG:4326"). name: Layer name for display. provider: Provider ID (default "memory"). Yields: The created temporary layer. """ layer = QgsVectorLayer(uri, name, provider) if not layer.isValid(): logger.error(f"Failed to create temporary layer: {name} (URI: {uri})") yield layer return try: logger.debug(f"Created temporary layer: {name}") yield layer finally: if layer.isValid(): # Ensure it's removed if it was added to the project if QgsProject.instance().mapLayer(layer.id()): QgsProject.instance().removeMapLayer(layer.id()) logger.debug(f"Cleaned up temporary layer: {name}")
[docs] @contextlib.contextmanager def temporary_file( suffix: str | None = None, prefix: str | None = None, dir: str | None = None, ) -> Generator[str, None, None]: """Context manager for a temporary file path. Creates a temporary file and yields its absolute path. The file is automatically deleted when the context exits. Args: suffix: File suffix. prefix: File prefix. dir: Directory to create the file in. Yields: Absolute path to the temporary file. """ fd, path = tempfile.mkstemp(suffix=suffix, prefix=prefix, dir=dir) os.close(fd) try: yield path finally: if os.path.exists(path): try: os.remove(path) logger.debug(f"Removed temporary file: {path}") except Exception as e: logger.warning(f"Failed to remove temporary file {path}: {e}")
[docs] class ResourceManager: """Consolidated resource manager for plugin-wide cleanup."""
[docs] @staticmethod def cleanup_layer(layer: QgsMapLayer): """Remove a layer safely from the project. Args: layer: The QGIS map layer to remove. """ if not layer: return try: QgsProject.instance().removeMapLayer(layer.id()) logger.debug(f"Layer {layer.name()} ({layer.id()}) removed.") except Exception as e: logger.warning(f"Error removing layer {layer.id()}: {e}")