From 9c507b59c629011cc5313791696ad433fa0c9f29 Mon Sep 17 00:00:00 2001 From: CJ Wong Date: Fri, 26 Mar 2021 03:34:18 -0700 Subject: [PATCH] Lint project files with Flake8 and mypy. --- config.py | 42 +++++++++++++++++++++++------------------- google/calendar.py | 8 ++++---- google/sheets.py | 25 +++++++++++++------------ 3 files changed, 40 insertions(+), 35 deletions(-) diff --git a/config.py b/config.py index 273324f..117238c 100644 --- a/config.py +++ b/config.py @@ -1,4 +1,4 @@ -# Copyright 2019 cj-wong +# Copyright 2019-2021 cj-wong # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,11 +13,29 @@ # limitations under the License. import logging import logging.handlers +from typing import Dict, List import pendulum import yaml +class InvalidConfiguration(ValueError): + """An invalid configuration was detected. + + The configuration error most likely stems from no calendars with + corresponding tabs in TAB_NAMES. + + """ + + def __init__(self) -> None: + """Initialize the configuration error with a message.""" + super().__init__( + 'Your configuration was invalid. Most likely you did not put ' + 'tabs into your calendars.\nTabs must be present in both the ' + 'calendar ("tabs") and spreadsheet settings ("tabs").' + ) + + _LOGGER_NAME = 'caltab' LOGGER = logging.getLogger(_LOGGER_NAME) @@ -48,14 +66,13 @@ SPREADSHEET_ID = CONF['spreadsheet']['id'] TABS = CONF['spreadsheet']['tabs'] -# TAB_NAMES consists of tabs (keys) and their aliases (values) -TAB_NAMES = {} +# TAB_NAMES consists of tabs and their aliases (list of aliases) +TAB_NAMES: Dict[str, List[str]] = {} # CALS consists of calendars that have tabs belonging in TAB_NAMES -CALS = [] +CALS: List[str] = [] for calendar, cal_vals in CONF['calendars'].items(): - tabs = cal_vals['tabs'] - for tab in tabs: + for tab in cal_vals['tabs']: if tab in TABS: if tab not in TAB_NAMES: TAB_NAMES[tab] = TABS[tab]['aliases'] @@ -65,16 +82,3 @@ # Both CALS and TAB_NAMES must not be empty. if not CALS and not TAB_NAMES: raise InvalidConfiguration - - -class InvalidConfiguration(ValueError): - """An invalid configuration was detected, stemming from - no calendars with corresponding tabs in TAB_NAMES. - - """ - def __init__(self) -> None: - super().__init__( - 'Your configuration was invalid. Most likely you did not put ' - 'tabs into your calendars.\nTabs must be present in both the ' - 'calendar ("tabs") and spreadsheet settings ("tabs").' - ) diff --git a/google/calendar.py b/google/calendar.py index f1497b0..4d212c1 100644 --- a/google/calendar.py +++ b/google/calendar.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from collections import defaultdict -from typing import Dict, Union +from typing import Dict import pendulum from google.oauth2 import service_account @@ -24,7 +24,7 @@ # datetime -> pendulum -def get_tab(entry: str) -> Union[str, None]: +def get_tab(entry: str) -> str: """Get a tab given its name, if it exists in `config.TAB_NAMES`. Args: @@ -106,7 +106,7 @@ def get_entries(self, cal_name: str, cal_id: str) -> Dict[str, int]: dict: {tab: hours} """ - tab_hours = defaultdict(int) + tab_hours: Dict[str, int] = defaultdict(int) all_entries = self.interface.events().list( calendarId=cal_id, @@ -123,7 +123,7 @@ def get_entries(self, cal_name: str, cal_id: str) -> Dict[str, int]: continue start = pendulum.parse(entry['start']['dateTime']) end = pendulum.parse(entry['end']['dateTime']) - tab_hours[tab] += (end - start).seconds/3600 + tab_hours[tab] += (end - start).seconds / 3600 if tab_hours[tab] >= 24: config.LOGGER.warning(f'Hours exceeded 24 for tab {tab}') diff --git a/google/sheets.py b/google/sheets.py index f361b2e..585248d 100644 --- a/google/sheets.py +++ b/google/sheets.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import re -from typing import Dict, Union +from typing import Dict import pendulum from googleapiclient.discovery import build @@ -26,7 +26,7 @@ ORD_Z = ord('Z') -def get_yesterday_cell(start: Dict[str, Union[str, int]]) -> str: +def get_yesterday_cell(cell: str, start: Dict[str, int]) -> str: """Retrieve the cell location representing yesterday. The cell location can be determined given the starting cell location and @@ -34,9 +34,8 @@ def get_yesterday_cell(start: Dict[str, Union[str, int]]) -> str: or TypeError may be raised, albeit indirectly. Args: - start (Dict[str, Union[str, int]]): the characteristics of - the starting (top-left) cell in the sheet; contains - 'cell' (spreadsheet format), 'year', and 'month' + cell (str): starting cell of spreadsheet in spreadsheet format + start (Dict[str, int]): month and year of the starting cell Returns: str: the cell in spreadsheet format, e.g. 'A1' @@ -46,9 +45,11 @@ def get_yesterday_cell(start: Dict[str, Union[str, int]]) -> str: TypeError: slicing or casting on None """ - cell = start['cell'] first = pendulum.datetime(start['year'], start['month'], 1, tz='local') - col_end = ALPHA.search(cell).end() + search = ALPHA.search(cell) + if not search: + raise ValueError(f'RegEx could not match {cell}') + col_end = search.end() col = cell[:col_end].upper() # We want to perform math on cols to get the right column. # To do so, we must convert the letters using `ord()`. @@ -59,12 +60,12 @@ def get_yesterday_cell(start: Dict[str, Union[str, int]]) -> str: col = chr(ncol) else: # After Z in columns are AA, AB, etc. col = f'A{chr(ncol - 26)}' - # `monthy` represents the row given year and month, with offsets + # `row_year_month` represents the row given year and month, with offsets # from `start`. - monthy = int(cell[col_end:]) - monthy += (config.YESTERDAY - first).months + row_year_month = int(cell[col_end:]) + row_year_month += (config.YESTERDAY - first).months - return f'{col}{monthy}' + return f'{col}{row_year_month}' class Sheets: @@ -104,7 +105,7 @@ def get_tab_cells(self) -> Dict[str, str]: cell = start['cell'] try: - yesterday = get_yesterday_cell(start) + yesterday = get_yesterday_cell(cell, start) except (AttributeError, TypeError, ValueError) as e: config.LOGGER.error(f'Skipping {tab}: {e}') continue