Source code for qiskit_aqt_provider._file_job_store

# This code is part of Qiskit.
#
# (C) Copyright Alpine Quantum Technologies GmbH 2026
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0).
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

import os
from dataclasses import dataclass
from pathlib import Path
from tempfile import NamedTemporaryFile

import platformdirs

from qiskit_aqt_provider.exceptions import AQTJobNotFoundError, AQTJobPersistenceError


[docs] @dataclass(frozen=True) class FileJobStore: """A filesystem adapter for the :class:`~qiskit_aqt_provider.persistence.JobStore` port.""" root: Path | None = None def __post_init__(self) -> None: if self.root is None: root = Path(platformdirs.user_data_dir("qiskit_aqt_provider")) / "jobs" else: root = Path(self.root) object.__setattr__(self, "root", root)
[docs] def save(self, job_id: str, payload: bytes) -> None: """Atomically save a payload under a job ID.""" filepath = self._filepath(job_id) try: filepath.parent.mkdir(parents=True, exist_ok=True, mode=0o700) except OSError as exc: raise AQTJobPersistenceError(f"Unable to create job store {filepath.parent}") from exc temporary_path: Path | None = None try: with NamedTemporaryFile(dir=filepath.parent, prefix=".job-", suffix=".tmp", delete=False) as temporary: temporary_path = Path(temporary.name) temporary.write(payload) temporary.flush() os.fsync(temporary.fileno()) temporary_path.chmod(0o600) temporary_path.replace(filepath) except OSError as exc: if temporary_path is not None: temporary_path.unlink(missing_ok=True) raise AQTJobPersistenceError(f"Unable to persist job {job_id}") from exc
[docs] def load(self, job_id: str) -> bytes: """Load a payload by job ID.""" filepath = self._filepath(job_id) try: return filepath.read_bytes() except FileNotFoundError as exc: raise AQTJobNotFoundError(f"No persisted job found for ID {job_id}") from exc except OSError as exc: raise AQTJobPersistenceError(f"Unable to read persisted job {job_id}") from exc
[docs] def delete(self, job_id: str) -> None: """Delete a payload by job ID; missing payloads are ignored.""" try: self._filepath(job_id).unlink(missing_ok=True) except OSError as exc: raise AQTJobPersistenceError(f"Unable to delete persisted job {job_id}") from exc
def _filepath(self, job_id: str) -> Path: if ( not isinstance(job_id, str) or not job_id or Path(job_id).name != job_id or "/" in job_id or "\\" in job_id or job_id in {".", ".."} ): raise AQTJobPersistenceError(f"Invalid job ID: {job_id}") if self.root is None: raise AQTJobPersistenceError("Job store has no root directory") return self.root / f"{job_id}.aqt-job"