From 154d6b29dd9a30ede8a25882c7ff777a45bf6dc3 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 20 Apr 2020 15:15:47 +0000 Subject: [PATCH] Listen to pylint --- PFERD/__init__.py | 9 +++++ PFERD/cookie_jar.py | 10 +++--- PFERD/ilias/__init__.py | 4 +++ PFERD/utils.py | 80 +++++++++++++++++++++++++++++------------ 4 files changed, 76 insertions(+), 27 deletions(-) diff --git a/PFERD/__init__.py b/PFERD/__init__.py index 3f44c6e..21ecb0d 100644 --- a/PFERD/__init__.py +++ b/PFERD/__init__.py @@ -1,3 +1,8 @@ +""" +This module exports only what you need for a basic configuration. If you want a +more complex configuration, you need to import the other submodules manually. +""" + import logging STYLE = "{" @@ -12,6 +17,10 @@ FORMATTER = logging.Formatter( def enable_logging(name: str = "PFERD", level: int = logging.INFO) -> None: + """ + Enable and configure logging via the logging module. + """ + handler = logging.StreamHandler() handler.setFormatter(FORMATTER) diff --git a/PFERD/cookie_jar.py b/PFERD/cookie_jar.py index e4b26d1..4ef1049 100644 --- a/PFERD/cookie_jar.py +++ b/PFERD/cookie_jar.py @@ -7,7 +7,7 @@ from typing import Optional import requests -logger = logging.getLogger(__name__) +LOGGER = logging.getLogger(__name__) class CookieJar: @@ -35,10 +35,10 @@ class CookieJar: return try: - logger.info(f"Loading old cookies from {self._cookies.filename}") + LOGGER.info(f"Loading old cookies from {self._cookies.filename}") self._cookies.load(ignore_discard=True) except (FileNotFoundError, LoadError): - logger.warn( + LOGGER.warning( f"No valid cookie file found at {self._cookies.filename}, " "continuing with no cookies" ) @@ -49,9 +49,9 @@ class CookieJar: return if reason is None: - logger.info("Saving cookies") + LOGGER.info("Saving cookies") else: - logger.info(f"Saving cookies ({reason})") + LOGGER.info(f"Saving cookies ({reason})") # TODO figure out why ignore_discard is set # TODO possibly catch a few more exceptions diff --git a/PFERD/ilias/__init__.py b/PFERD/ilias/__init__.py index 631e36c..b68f34d 100644 --- a/PFERD/ilias/__init__.py +++ b/PFERD/ilias/__init__.py @@ -1 +1,5 @@ +""" +Synchronizing files from ILIAS instances (https://www.ilias.de/). +""" + from .authenticators import * diff --git a/PFERD/utils.py b/PFERD/utils.py index dc50ba6..8233ad1 100644 --- a/PFERD/utils.py +++ b/PFERD/utils.py @@ -1,6 +1,8 @@ +""" +A few utility bobs and bits. +""" + import logging -import os -import sys from pathlib import Path, PurePath from typing import Optional, Tuple @@ -9,24 +11,42 @@ from colorama import Fore, Style def move(path: PurePath, from_folders: Tuple[str], to_folders: Tuple[str]) -> Optional[PurePath]: - l = len(from_folders) - if path.parts[:l] == from_folders: - return PurePath(*to_folders, *path.parts[l:]) + """ + If the input path is located anywhere within from_folders, replace the + from_folders with to_folders. Returns None otherwise. + """ + + length = len(from_folders) + if path.parts[:length] == from_folders: + return PurePath(*to_folders, *path.parts[length:]) return None def rename(path: PurePath, to_name: str) -> PurePath: + """ + Set the file name of the input path to to_name. + """ + return PurePath(*path.parts[:-1], to_name) def stream_to_path(response: requests.Response, to_path: Path, chunk_size: int = 1024 ** 2) -> None: - with open(to_path, 'wb') as fd: + """ + Download a requests response content to a file by streaming it. This + function avoids excessive memory usage when downloading large files. The + chunk_size is in bytes. + """ + + with open(to_path, 'wb') as file_descriptor: for chunk in response.iter_content(chunk_size=chunk_size): - fd.write(chunk) + file_descriptor.write(chunk) def prompt_yes_no(question: str, default: Optional[bool] = None) -> bool: - """Prompts the user and returns their choice.""" + """ + Prompts the user a yes/no question and returns their choice. + """ + if default is True: prompt = "[Y/n]" elif default is False: @@ -35,30 +55,22 @@ def prompt_yes_no(question: str, default: Optional[bool] = None) -> bool: prompt = "[y/n]" text = f"{question} {prompt} " - WRONG_REPLY = "Please reply with 'yes'/'y' or 'no'/'n'." + wrong_reply = "Please reply with 'yes'/'y' or 'no'/'n'." while True: response = input(text).strip().lower() if response in {"yes", "ye", "y"}: return True - elif response in {"no", "n"}: + if response in {"no", "n"}: return False - elif response == "": - if default is None: - print(WRONG_REPLY) - else: - return default - else: - print(WRONG_REPLY) + if response == "" and default is not None: + return default + print(wrong_reply) class ResolveException(Exception): """An exception while resolving a file.""" - def __init__(self, message: str): - """Create a new exception.""" - super().__init__(message) - def resolve_path(directory: Path, target_file: Path) -> Path: """Resolve a file relative to the path of this organizer. @@ -76,22 +88,46 @@ def resolve_path(directory: Path, target_file: Path) -> Path: class PrettyLogger: + """ + A logger that prints some specially formatted log messages in color. + """ def __init__(self, logger: logging.Logger) -> None: self.logger = logger def modified_file(self, file_name: Path) -> None: + """ + An existing file has changed. + """ + self.logger.info( f"{Fore.MAGENTA}{Style.BRIGHT}Modified {file_name}.{Style.RESET_ALL}") def new_file(self, file_name: Path) -> None: + """ + A new file has been downloaded. + """ + self.logger.info( f"{Fore.GREEN}{Style.BRIGHT}Created {file_name}.{Style.RESET_ALL}") def ignored_file(self, file_name: Path) -> None: + """ + Nothing in particular happened to this file. + """ + self.logger.info(f"{Style.DIM}Ignored {file_name}.{Style.RESET_ALL}") - def starting_synchronizer(self, target_directory: Path, synchronizer_name: str, subject: Optional[str] = None) -> None: + def starting_synchronizer( + self, + target_directory: Path, + synchronizer_name: str, + subject: Optional[str] = None, + ) -> None: + """ + A special message marking that a synchronizer has been started. + """ + subject_str = f"{subject} " if subject else "" self.logger.info("") self.logger.info((