Listen to pylint

This commit is contained in:
Joscha 2020-04-20 15:15:47 +00:00
parent 62ac569ec4
commit 154d6b29dd
4 changed files with 76 additions and 27 deletions

View File

@ -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 import logging
STYLE = "{" STYLE = "{"
@ -12,6 +17,10 @@ FORMATTER = logging.Formatter(
def enable_logging(name: str = "PFERD", level: int = logging.INFO) -> None: def enable_logging(name: str = "PFERD", level: int = logging.INFO) -> None:
"""
Enable and configure logging via the logging module.
"""
handler = logging.StreamHandler() handler = logging.StreamHandler()
handler.setFormatter(FORMATTER) handler.setFormatter(FORMATTER)

View File

@ -7,7 +7,7 @@ from typing import Optional
import requests import requests
logger = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
class CookieJar: class CookieJar:
@ -35,10 +35,10 @@ class CookieJar:
return return
try: 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) self._cookies.load(ignore_discard=True)
except (FileNotFoundError, LoadError): except (FileNotFoundError, LoadError):
logger.warn( LOGGER.warning(
f"No valid cookie file found at {self._cookies.filename}, " f"No valid cookie file found at {self._cookies.filename}, "
"continuing with no cookies" "continuing with no cookies"
) )
@ -49,9 +49,9 @@ class CookieJar:
return return
if reason is None: if reason is None:
logger.info("Saving cookies") LOGGER.info("Saving cookies")
else: else:
logger.info(f"Saving cookies ({reason})") LOGGER.info(f"Saving cookies ({reason})")
# TODO figure out why ignore_discard is set # TODO figure out why ignore_discard is set
# TODO possibly catch a few more exceptions # TODO possibly catch a few more exceptions

View File

@ -1 +1,5 @@
"""
Synchronizing files from ILIAS instances (https://www.ilias.de/).
"""
from .authenticators import * from .authenticators import *

View File

@ -1,6 +1,8 @@
"""
A few utility bobs and bits.
"""
import logging import logging
import os
import sys
from pathlib import Path, PurePath from pathlib import Path, PurePath
from typing import Optional, Tuple 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]: def move(path: PurePath, from_folders: Tuple[str], to_folders: Tuple[str]) -> Optional[PurePath]:
l = len(from_folders) """
if path.parts[:l] == from_folders: If the input path is located anywhere within from_folders, replace the
return PurePath(*to_folders, *path.parts[l:]) 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 return None
def rename(path: PurePath, to_name: str) -> PurePath: 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) return PurePath(*path.parts[:-1], to_name)
def stream_to_path(response: requests.Response, to_path: Path, chunk_size: int = 1024 ** 2) -> None: 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): 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: 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: if default is True:
prompt = "[Y/n]" prompt = "[Y/n]"
elif default is False: elif default is False:
@ -35,30 +55,22 @@ def prompt_yes_no(question: str, default: Optional[bool] = None) -> bool:
prompt = "[y/n]" prompt = "[y/n]"
text = f"{question} {prompt} " 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: while True:
response = input(text).strip().lower() response = input(text).strip().lower()
if response in {"yes", "ye", "y"}: if response in {"yes", "ye", "y"}:
return True return True
elif response in {"no", "n"}: if response in {"no", "n"}:
return False return False
elif response == "": if response == "" and default is not None:
if default is None: return default
print(WRONG_REPLY) print(wrong_reply)
else:
return default
else:
print(WRONG_REPLY)
class ResolveException(Exception): class ResolveException(Exception):
"""An exception while resolving a file.""" """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: def resolve_path(directory: Path, target_file: Path) -> Path:
"""Resolve a file relative to the path of this organizer. """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: class PrettyLogger:
"""
A logger that prints some specially formatted log messages in color.
"""
def __init__(self, logger: logging.Logger) -> None: def __init__(self, logger: logging.Logger) -> None:
self.logger = logger self.logger = logger
def modified_file(self, file_name: Path) -> None: def modified_file(self, file_name: Path) -> None:
"""
An existing file has changed.
"""
self.logger.info( self.logger.info(
f"{Fore.MAGENTA}{Style.BRIGHT}Modified {file_name}.{Style.RESET_ALL}") f"{Fore.MAGENTA}{Style.BRIGHT}Modified {file_name}.{Style.RESET_ALL}")
def new_file(self, file_name: Path) -> None: def new_file(self, file_name: Path) -> None:
"""
A new file has been downloaded.
"""
self.logger.info( self.logger.info(
f"{Fore.GREEN}{Style.BRIGHT}Created {file_name}.{Style.RESET_ALL}") f"{Fore.GREEN}{Style.BRIGHT}Created {file_name}.{Style.RESET_ALL}")
def ignored_file(self, file_name: Path) -> None: 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}") 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 "" subject_str = f"{subject} " if subject else ""
self.logger.info("") self.logger.info("")
self.logger.info(( self.logger.info((