From 5253780cc8aa4aef778fe4deaa8bdefce4fe7470 Mon Sep 17 00:00:00 2001 From: Inex Code Date: Wed, 19 Jul 2023 15:59:51 +0300 Subject: [PATCH] style: linting of backups module --- selfprivacy_api/backup/backuppers/__init__.py | 12 +-- .../backup/backuppers/restic_backupper.py | 92 +++++++++++++------ selfprivacy_api/backup/storage.py | 8 +- 3 files changed, 79 insertions(+), 33 deletions(-) diff --git a/selfprivacy_api/backup/backuppers/__init__.py b/selfprivacy_api/backup/backuppers/__init__.py index 05adede..7051a6a 100644 --- a/selfprivacy_api/backup/backuppers/__init__.py +++ b/selfprivacy_api/backup/backuppers/__init__.py @@ -5,7 +5,7 @@ from selfprivacy_api.models.backup.snapshot import Snapshot class AbstractBackupper(ABC): - def __init__(self): + def __init__(self) -> None: pass @abstractmethod @@ -13,11 +13,11 @@ class AbstractBackupper(ABC): raise NotImplementedError @abstractmethod - def set_creds(self, account: str, key: str, repo: str): + def set_creds(self, account: str, key: str, repo: str) -> None: raise NotImplementedError @abstractmethod - def start_backup(self, folders: List[str], repo_name: str): + def start_backup(self, folders: List[str], repo_name: str) -> Snapshot: raise NotImplementedError @abstractmethod @@ -26,7 +26,7 @@ class AbstractBackupper(ABC): raise NotImplementedError @abstractmethod - def init(self): + def init(self) -> None: raise NotImplementedError @abstractmethod @@ -35,7 +35,7 @@ class AbstractBackupper(ABC): snapshot_id: str, folders: List[str], verify=True, - ): + ) -> None: """Restore a target folder using a snapshot""" raise NotImplementedError @@ -44,5 +44,5 @@ class AbstractBackupper(ABC): raise NotImplementedError @abstractmethod - def forget_snapshot(self, snapshot_id): + def forget_snapshot(self, snapshot_id) -> None: raise NotImplementedError diff --git a/selfprivacy_api/backup/backuppers/restic_backupper.py b/selfprivacy_api/backup/backuppers/restic_backupper.py index fa7b2ee..60e8285 100644 --- a/selfprivacy_api/backup/backuppers/restic_backupper.py +++ b/selfprivacy_api/backup/backuppers/restic_backupper.py @@ -21,7 +21,7 @@ from selfprivacy_api.backup.local_secret import LocalBackupSecret class ResticBackupper(AbstractBackupper): - def __init__(self, login_flag: str, key_flag: str, type: str): + def __init__(self, login_flag: str, key_flag: str, type: str) -> None: self.login_flag = login_flag self.key_flag = key_flag self.type = type @@ -29,7 +29,7 @@ class ResticBackupper(AbstractBackupper): self.key = "" self.repo = "" - def set_creds(self, account: str, key: str, repo: str): + def set_creds(self, account: str, key: str, repo: str) -> None: self.account = account self.key = key self.repo = repo @@ -79,7 +79,11 @@ class ResticBackupper(AbstractBackupper): def mount_repo(self, dir): mount_command = self.restic_command("mount", dir) mount_command.insert(0, "nohup") - handle = subprocess.Popen(mount_command, stdout=subprocess.DEVNULL, shell=False) + handle = subprocess.Popen( + mount_command, + stdout=subprocess.DEVNULL, + shell=False, + ) sleep(2) if "ids" not in listdir(dir): raise IOError("failed to mount dir ", dir) @@ -109,12 +113,13 @@ class ResticBackupper(AbstractBackupper): result.append(item) return result - def start_backup(self, folders: List[str], tag: str): + def start_backup(self, folders: List[str], tag: str) -> Snapshot: """ Start backup with restic """ - # but maybe it is ok to accept a union of a string and an array of strings + # but maybe it is ok to accept a union + # of a string and an array of strings assert not isinstance(folders, str) backup_command = self.restic_command( @@ -125,20 +130,34 @@ class ResticBackupper(AbstractBackupper): ) messages = [] - job = get_backup_job(get_service_by_id(tag)) + + service = get_service_by_id(tag) + if service is None: + raise ValueError("No service with id ", tag) + + job = get_backup_job(service) try: for raw_message in output_yielder(backup_command): - message = self.parse_message(raw_message, job) + message = self.parse_message( + raw_message, + job, + ) messages.append(message) - return ResticBackupper._snapshot_from_backup_messages(messages, tag) + return ResticBackupper._snapshot_from_backup_messages( + messages, + tag, + ) except ValueError as e: - raise ValueError("could not create a snapshot: ", messages) from e + raise ValueError("Could not create a snapshot: ", messages) from e @staticmethod def _snapshot_from_backup_messages(messages, repo_name) -> Snapshot: for message in messages: if message["message_type"] == "summary": - return ResticBackupper._snapshot_from_fresh_summary(message, repo_name) + return ResticBackupper._snapshot_from_fresh_summary( + message, + repo_name, + ) raise ValueError("no summary message in restic json output") def parse_message(self, raw_message_line: str, job=None) -> dict: @@ -162,7 +181,7 @@ class ResticBackupper(AbstractBackupper): service_name=repo_name, ) - def init(self): + def init(self) -> None: init_command = self.restic_command( "init", ) @@ -173,7 +192,7 @@ class ResticBackupper(AbstractBackupper): stderr=subprocess.STDOUT, ) as process_handle: output = process_handle.communicate()[0].decode("utf-8") - if not "created restic repository" in output: + if "created restic repository" not in output: raise ValueError("cannot init a repo: " + output) def is_initted(self) -> bool: @@ -182,7 +201,11 @@ class ResticBackupper(AbstractBackupper): "--json", ) - with subprocess.Popen(command, stdout=subprocess.PIPE, shell=False) as handle: + with subprocess.Popen( + command, + stdout=subprocess.PIPE, + shell=False, + ) as handle: output = handle.communicate()[0].decode("utf-8") if not ResticBackupper.has_json(output): return False @@ -216,7 +239,7 @@ class ResticBackupper(AbstractBackupper): snapshot_id, folders: List[str], verify=True, - ): + ) -> None: """ Restore from backup with restic """ @@ -235,9 +258,7 @@ class ResticBackupper(AbstractBackupper): for folder in folders: src = join(snapshot_root, folder.strip("/")) if not exists(src): - raise ValueError( - f"there is no such path: {src}. We tried to find {folder}" - ) + raise ValueError(f"No such path: {src}. We tried to find {folder}") dst = folder sync(src, dst) @@ -254,7 +275,8 @@ class ResticBackupper(AbstractBackupper): restore_command, stdout=subprocess.PIPE, shell=False ) as handle: - # for some reason restore does not support nice reporting of progress via json + # for some reason restore does not support + # nice reporting of progress via json output = handle.communicate()[0].decode("utf-8") if "restoring" not in output: raise ValueError("cannot restore a snapshot: " + output) @@ -264,21 +286,36 @@ class ResticBackupper(AbstractBackupper): ) # none should be impossible after communicate if handle.returncode != 0: raise ValueError( - "restore exited with errorcode", returncode, ":", output + "restore exited with errorcode", + handle.returncode, + ":", + output, ) - def forget_snapshot(self, snapshot_id): - """either removes snapshot or marks it for deletion later depending on server settings""" + def forget_snapshot(self, snapshot_id) -> None: + """ + Either removes snapshot or marks it for deletion later, + depending on server settings + """ forget_command = self.restic_command( "forget", snapshot_id, ) with subprocess.Popen( - forget_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False + forget_command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=False, ) as handle: - # for some reason restore does not support nice reporting of progress via json - output, err = [string.decode("utf-8") for string in handle.communicate()] + # for some reason restore does not support + # nice reporting of progress via json + output, err = [ + string.decode( + "utf-8", + ) + for string in handle.communicate() + ] if "no matching ID found" in err: raise ValueError( @@ -290,7 +327,10 @@ class ResticBackupper(AbstractBackupper): ) # none should be impossible after communicate if handle.returncode != 0: raise ValueError( - "forget exited with errorcode", returncode, ":", output + "forget exited with errorcode", + handle.returncode, + ":", + output, ) def _load_snapshots(self) -> object: @@ -336,7 +376,7 @@ class ResticBackupper(AbstractBackupper): starting_index = ResticBackupper.json_start(output) if starting_index == -1: - raise ValueError("There is no json in the restic output : " + output) + raise ValueError("There is no json in the restic output: " + output) truncated_output = output[starting_index:] json_messages = truncated_output.splitlines() diff --git a/selfprivacy_api/backup/storage.py b/selfprivacy_api/backup/storage.py index 29a5462..99a4950 100644 --- a/selfprivacy_api/backup/storage.py +++ b/selfprivacy_api/backup/storage.py @@ -74,11 +74,17 @@ class Storage: return None snapshot = hash_as_model(redis, key, Snapshot) + if not snapshot: + return None return snapshot.created_at @staticmethod def store_last_timestamp(service_id: str, snapshot: Snapshot): - store_model_as_hash(redis, Storage.__last_backup_key(service_id), snapshot) + store_model_as_hash( + redis, + Storage.__last_backup_key(service_id), + snapshot, + ) @staticmethod def cache_snapshot(snapshot: Snapshot):