qq_lib.wipe

Utilities for removing the working directory of a qq job.

This module defines the Wiper class, an extension of Navigator responsible for safely deleting a job's remote working directory once it is no longer needed.

Wiper distinguishes between shared-storage jobs and scratch-based jobs, and guards against accidental deletion of the job's input directory.

 1# Released under MIT License.
 2# Copyright (c) 2025-2026 Ladislav Bartos and Robert Vacha Lab
 3
 4"""
 5Utilities for removing the working directory of a qq job.
 6
 7This module defines the `Wiper` class, an extension of `Navigator` responsible for
 8safely deleting a job's remote working directory once it is no longer needed.
 9
10`Wiper` distinguishes between shared-storage jobs and scratch-based jobs, and
11guards against accidental deletion of the job's input directory.
12"""
13
14from .wiper import Wiper
15
16__all__ = [
17    "Wiper",
18]
class Wiper(qq_lib.core.navigator.Navigator):
13class Wiper(Navigator):
14    """
15    Class to manage deleting working directory of a job.
16    """
17
18    def ensure_suitable(self) -> None:
19        """
20        Verify that the job is in a state where its working directory can be deleted.
21
22        Raises:
23            QQNotSuitableError: If the working directory is not expected to exist
24                or if the working directory is the input directory.
25        """
26        if self._work_dir_is_input_dir():
27            raise QQNotSuitableError(
28                "Working directory of the job is the input directory of the job. Cannot delete the input directory."
29            )
30
31        if self._is_queued():
32            raise QQNotSuitableError(
33                f"Job is {str(self._informer.get_real_state()).lower()} and does not have a working directory yet."
34            )
35
36        if self._is_running() or self._is_suspended():
37            raise QQNotSuitableError(
38                f"Job is {str(self._informer.get_real_state()).lower()}. It is not safe to delete the working directory."
39            )
40
41        if self._is_synchronized():
42            raise QQNotSuitableError(
43                "Job has been completed and was synchronized: working directory no longer exists."
44            )
45
46        if self._is_finished():
47            raise QQNotSuitableError(
48                "It may not be safe to delete the working directory of a successfully finished job. Rerun as 'qq wipe --force' if sure."
49            )
50
51        if not self.has_destination():
52            raise QQNotSuitableError("Job does not have a working directory.")
53
54    def wipe(self) -> str:
55        """
56        Delete the working directory on the computing node.
57
58        Returns:
59            str: The identifier of the job which working directory was deleted.
60
61        Raises:
62            QQError: If the working directory of the job does not exist or cannot be deleted.
63        """
64        if not self.has_destination():
65            raise QQError(
66                "Host ('main_node') or working directory ('work_dir') are not defined."
67            )
68
69        # hint for type checker
70        # work_dir and main_node must be set - we check that in self.hasDestination
71        assert self._work_dir and self._main_node
72
73        # we cannot delete the input directory even if the `--force` flag is used
74        if self._work_dir_is_input_dir():
75            raise QQError(
76                "Working directory of the job is the input directory of the job. Cannot delete the input directory."
77            )
78
79        logger.info(
80            f"Deleting working directory '{str(self._work_dir)}' on '{self._main_node}'."
81        )
82        self._batch_system.delete_remote_dir(self._main_node, self._work_dir)
83
84        return self._informer.info.job_id

Class to manage deleting working directory of a job.

def ensure_suitable(self) -> None:
18    def ensure_suitable(self) -> None:
19        """
20        Verify that the job is in a state where its working directory can be deleted.
21
22        Raises:
23            QQNotSuitableError: If the working directory is not expected to exist
24                or if the working directory is the input directory.
25        """
26        if self._work_dir_is_input_dir():
27            raise QQNotSuitableError(
28                "Working directory of the job is the input directory of the job. Cannot delete the input directory."
29            )
30
31        if self._is_queued():
32            raise QQNotSuitableError(
33                f"Job is {str(self._informer.get_real_state()).lower()} and does not have a working directory yet."
34            )
35
36        if self._is_running() or self._is_suspended():
37            raise QQNotSuitableError(
38                f"Job is {str(self._informer.get_real_state()).lower()}. It is not safe to delete the working directory."
39            )
40
41        if self._is_synchronized():
42            raise QQNotSuitableError(
43                "Job has been completed and was synchronized: working directory no longer exists."
44            )
45
46        if self._is_finished():
47            raise QQNotSuitableError(
48                "It may not be safe to delete the working directory of a successfully finished job. Rerun as 'qq wipe --force' if sure."
49            )
50
51        if not self.has_destination():
52            raise QQNotSuitableError("Job does not have a working directory.")

Verify that the job is in a state where its working directory can be deleted.

Raises:
  • QQNotSuitableError: If the working directory is not expected to exist or if the working directory is the input directory.
def wipe(self) -> str:
54    def wipe(self) -> str:
55        """
56        Delete the working directory on the computing node.
57
58        Returns:
59            str: The identifier of the job which working directory was deleted.
60
61        Raises:
62            QQError: If the working directory of the job does not exist or cannot be deleted.
63        """
64        if not self.has_destination():
65            raise QQError(
66                "Host ('main_node') or working directory ('work_dir') are not defined."
67            )
68
69        # hint for type checker
70        # work_dir and main_node must be set - we check that in self.hasDestination
71        assert self._work_dir and self._main_node
72
73        # we cannot delete the input directory even if the `--force` flag is used
74        if self._work_dir_is_input_dir():
75            raise QQError(
76                "Working directory of the job is the input directory of the job. Cannot delete the input directory."
77            )
78
79        logger.info(
80            f"Deleting working directory '{str(self._work_dir)}' on '{self._main_node}'."
81        )
82        self._batch_system.delete_remote_dir(self._main_node, self._work_dir)
83
84        return self._informer.info.job_id

Delete the working directory on the computing node.

Returns:

str: The identifier of the job which working directory was deleted.

Raises:
  • QQError: If the working directory of the job does not exist or cannot be deleted.