Add logging to project

This commit is contained in:
Xevion
2021-08-26 19:02:23 -05:00
parent 48801d978b
commit 4571a47910
5 changed files with 56 additions and 15 deletions

View File

@@ -1,9 +1,9 @@
from __future__ import print_function from __future__ import print_function
import datetime import datetime
import logging
import os.path import os.path
import re import re
import traceback
from typing import Any, Iterator, List, Optional, Tuple, Union from typing import Any, Iterator, List, Optional, Tuple, Union
from PyQt5 import QtGui from PyQt5 import QtGui
@@ -23,49 +23,62 @@ TIME_REGEX = re.compile(r'\d{2}:\d{2}(?:AM|PM)')
DATE_FORMAT = '%Y-%m-%d' DATE_FORMAT = '%Y-%m-%d'
DATETIME_FORMAT = DATE_FORMAT + ' %H:%M%p' DATETIME_FORMAT = DATE_FORMAT + ' %H:%M%p'
logger = logging.getLogger(__file__)
logger.setLevel(logging.DEBUG)
class Calendar(object): class Calendar(object):
TOKEN_FILE = 'token.json'
def __init__(self) -> None: def __init__(self) -> None:
self.credentials: Optional[Credentials] = None self.credentials: Optional[Credentials] = None
self.service: Optional[Resource] = None self.service: Optional[Resource] = None
def save_token(self) -> None: def save_token(self) -> None:
"""Store the credentials for later use.""" """Store the credentials for later use."""
with open('token.json', 'w') as token: logger.debug('Saving token to token.json')
with open(Calendar.TOKEN_FILE, 'w') as token:
token.write(self.credentials.to_json()) token.write(self.credentials.to_json())
def authenticate_via_token(self) -> bool: def authenticate_via_token(self) -> bool:
"""Attempt to login using the tokens stored in token.json""" """Attempt to login using the tokens stored in token.json"""
if os.path.exists('token.json'): logger.info('Attempting to authenticate via token')
if os.path.exists(Calendar.TOKEN_FILE):
self.credentials = Credentials.from_authorized_user_file('token.json', SCOPES) self.credentials = Credentials.from_authorized_user_file('token.json', SCOPES)
if self.credentials and self.credentials.expired and self.credentials.refresh_token: if self.credentials and self.credentials.expired and self.credentials.refresh_token:
try: try:
logger.info('Refreshing token')
self.credentials.refresh(Request()) self.credentials.refresh(Request())
except BaseException as e: except BaseException as e:
traceback.print_exc() logger.error('Failed to refresh token', exc_info=e)
return False return False
self.save_token() else:
logger.info('Successfully authenticated via token')
self.save_token()
return True return True
return False return False
def authenticate_via_oauth(self) -> bool: def authenticate_via_oauth(self) -> bool:
"""Attempt to acquire credentials""" """Attempt to acquire credentials"""
try: try:
flow = InstalledAppFlow.from_client_secrets_file( flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)
'credentials.json', SCOPES)
self.credentials = flow.run_local_server(port=0) self.credentials = flow.run_local_server(port=0)
self.save_token()
except BaseException as e: except BaseException as e:
traceback.print_exc() logger.error('Failed to authenticate via OAuth 2.0 flow', exc_info=e)
return False return False
else:
self.save_token()
return True
def setupService(self) -> None: def setupService(self) -> None:
"""Setup the Google App Engine API Service for the Calendar API""" """Setup the Google App Engine API Service for the Calendar API"""
logger.debug('Initializing Calendar API Service')
self.service = build('calendar', 'v3', credentials=self.credentials) self.service = build('calendar', 'v3', credentials=self.credentials)
def getCalendars(self) -> Iterator[Any]: def getCalendars(self) -> Iterator[Any]:
"""Retrieve all calendar data""" """Retrieve all calendar data"""
page_token = None logger.debug('Retrieving all calendar data')
page, page_token = 1, None
while True: while True:
calendar_list = self.service.calendarList().list(pageToken=page_token, minAccessRole='writer').execute() calendar_list = self.service.calendarList().list(pageToken=page_token, minAccessRole='writer').execute()
for entry in calendar_list['items']: for entry in calendar_list['items']:
@@ -76,12 +89,16 @@ class Calendar(object):
yield entry yield entry
# Continue loading more calendars # Continue loading more calendars
page += 1
page_token = calendar_list.get('nextPageToken') page_token = calendar_list.get('nextPageToken')
if page_token is None: if page_token is None:
break break
logger.debug(f'Retrieving page {page} of Calendars')
def getEvents(self, calendarID: str) -> List[Any]: def getEvents(self, calendarID: str) -> List[Any]:
"""Retrieves up to 2500 events for a given calendar ordered by occurrence that happen in the future.""" """Retrieves up to 2500 events for a given calendar ordered by occurrence that happen in the future."""
logger.debug(f'Retrieving all events from Calendar {calendarID}')
now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time
events = self.service.events().list(calendarId=calendarID, timeMin=now, events = self.service.events().list(calendarId=calendarID, timeMin=now,
maxResults=2500, singleEvents=True, maxResults=2500, singleEvents=True,

View File

@@ -1,3 +1,4 @@
import logging
from typing import Iterator, List from typing import Iterator, List
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
@@ -10,12 +11,16 @@ from bulk_reminders.load import LoadDialog
from bulk_reminders.oauth import OAuthDialog from bulk_reminders.oauth import OAuthDialog
from bulk_reminders.undo import IDPair, Stage from bulk_reminders.undo import IDPair, Stage
logging.basicConfig(format='[%(asctime)s] [%(levelname)s] [%(threadName)s] %(message)s')
logger = logging.getLogger(__file__)
logger.setLevel(logging.DEBUG)
class MainWindow(QMainWindow, Ui_MainWindow): class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
# Initial UI setup # Initial UI setup
super(MainWindow, self).__init__(*args, **kwargs) super(MainWindow, self).__init__(*args, **kwargs)
self.setupUi(self) self.setupUi(self)
logger.debug('UI Initialized.')
self.show() self.show()
self.calendar = api.Calendar() self.calendar = api.Calendar()
@@ -63,6 +68,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.loadEventsButton.clicked.connect(self.load_events) self.loadEventsButton.clicked.connect(self.load_events)
self.cachedLoadText = '' self.cachedLoadText = ''
self.readyEvents: List[Event] = [] self.readyEvents: List[Event] = []
self.apiEvents: List[dict] = []
self.populate() self.populate()
@@ -119,6 +125,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.eventCountLabel.setText(f'{len(self.readyEvents)} ready, {undoable} undoable in {stage} stages, {foreign} foreign ({total})') self.eventCountLabel.setText(f'{len(self.readyEvents)} ready, {undoable} undoable in {stage} stages, {foreign} foreign ({total})')
self.eventsView.setRowCount(len(events)) self.eventsView.setRowCount(len(events))
logger.debug(f'Populating table with {self.eventsView.rowCount()} events.')
for row, event in enumerate(events): for row, event in enumerate(events):
event.fill_row(row, self.eventsView) event.fill_row(row, self.eventsView)
@@ -126,4 +133,5 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def comboBoxChanged(self, row) -> None: def comboBoxChanged(self, row) -> None:
"""When the Calendar Selection combobox""" """When the Calendar Selection combobox"""
self.currentCalendarID = self.comboModel.item(row).data() self.currentCalendarID = self.comboModel.item(row).data()
logger.info(f'Switching to Calendar "{self.comboModel.item(row).text()} ({self.currentCalendarID})"')
self.populate() self.populate()

View File

@@ -1,3 +1,4 @@
import logging
import os import os
import re import re
from typing import List, Optional from typing import List, Optional
@@ -9,6 +10,9 @@ from PyQt5.QtWidgets import QApplication, QDialog, QLabel
from bulk_reminders.api import Event from bulk_reminders.api import Event
from bulk_reminders.load_base import Ui_Dialog from bulk_reminders.load_base import Ui_Dialog
logger = logging.getLogger(__file__)
logger.setLevel(logging.DEBUG)
REGEX = re.compile( REGEX = re.compile(
r'\s*([\w\d\s,.;\'!\[\]()]{1,})\s+\|\s+(\d{4}-\d{2}-\d{2})\s+(\d{1,2}:\d{2}(?:AM|PM))?\s*(\d{4}-\d{2}-\d{2})(\d{1,2}:\d{2}(?:AM|PM))?') r'\s*([\w\d\s,.;\'!\[\]()]{1,})\s+\|\s+(\d{4}-\d{2}-\d{2})\s+(\d{1,2}:\d{2}(?:AM|PM))?\s*(\d{4}-\d{2}-\d{2})(\d{1,2}:\d{2}(?:AM|PM))?')
@@ -46,6 +50,7 @@ class LoadDialog(QDialog, Ui_Dialog):
try: try:
self.parsed = list(map(Event.parse_raw, results)) self.parsed = list(map(Event.parse_raw, results))
except ValueError: except ValueError:
logger.debug('Dialog input has data errors (invalid dates etc.)')
resultsText += ' Data error.' resultsText += ' Data error.'
self.eventCountLabel.setText(resultsText) self.eventCountLabel.setText(resultsText)

View File

@@ -1,3 +1,4 @@
import logging
from typing import Callable, Optional from typing import Callable, Optional
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
@@ -5,6 +6,10 @@ from PyQt5.QtWidgets import QDialog
from bulk_reminders.oauth_base import Ui_Dialog from bulk_reminders.oauth_base import Ui_Dialog
logger = logging.getLogger(__file__)
logger.setLevel(logging.DEBUG)
class OAuthDialog(QDialog, Ui_Dialog): class OAuthDialog(QDialog, Ui_Dialog):
def __init__(self, *args, callback: Optional[Callable] = None, **kwargs): def __init__(self, *args, callback: Optional[Callable] = None, **kwargs):
super(QDialog, self).__init__(*args, **kwargs) super(QDialog, self).__init__(*args, **kwargs)
@@ -16,6 +21,7 @@ class OAuthDialog(QDialog, Ui_Dialog):
callback() callback()
self.accept() self.accept()
else: else:
logger.debug('No callback given for OAuth Dialog; closing immediately.')
self.reject() self.reject()
self._closable = True self._closable = True
@@ -23,6 +29,6 @@ class OAuthDialog(QDialog, Ui_Dialog):
if self.closable: if self.closable:
super(QDialog, self).closeEvent(evnt) super(QDialog, self).closeEvent(evnt)
else: else:
logger.debug('Ignoring close event.')
evnt.ignore() evnt.ignore()
self.setWindowState(Qt.WindowMinimized) self.setWindowState(Qt.WindowActive)

View File

@@ -1,9 +1,12 @@
import json import logging
import os import os
from typing import Iterator, List from typing import Iterator, List
import jsonpickle import jsonpickle
logger = logging.getLogger(__file__)
logger.setLevel(logging.DEBUG)
class HistoryManager(object): class HistoryManager(object):
def __init__(self, file: str) -> None: def __init__(self, file: str) -> None:
@@ -20,11 +23,13 @@ class HistoryManager(object):
def load(self) -> None: def load(self) -> None:
"""Load data from the undo history file""" """Load data from the undo history file"""
logger.info('Loading from undo history file.')
with open(self.file, 'r') as file: with open(self.file, 'r') as file:
self.stages = jsonpickle.decode(file.read()) self.stages = jsonpickle.decode(file.read())
def save(self) -> None: def save(self) -> None:
"""Save data to the undo history file.""" """Save data to the undo history file."""
logger.info('Saving to undo history file.')
with open(self.file, 'w') as file: with open(self.file, 'w') as file:
file.write(jsonpickle.encode(self.stages)) file.write(jsonpickle.encode(self.stages))
@@ -34,10 +39,10 @@ class HistoryManager(object):
def exists(self, eventID: 'IDPair') -> int: def exists(self, eventID: 'IDPair') -> int:
"""Check if a given Event ID exists anywhere in the undo history data. Returns the stage index or -1 if it wasn't found.""" """Check if a given Event ID exists anywhere in the undo history data. Returns the stage index or -1 if it wasn't found."""
print(f'Checking for {eventID} in undo history')
for stage in self.stages: for stage in self.stages:
for undoable in stage.events: for undoable in stage.events:
if eventID == undoable.eventID: if eventID == undoable.eventID:
logger.debug(f'Found Event {eventID} in Stage {stage.index}')
return stage.index return stage.index
return -1 return -1
@@ -59,6 +64,7 @@ class HistoryManager(object):
def addStage(self, newStage: 'Stage'): def addStage(self, newStage: 'Stage'):
"""Adds and inserts a new Stage at the start of the history.""" """Adds and inserts a new Stage at the start of the history."""
logger.debug(f'Adding new stage with {len(newStage)} events.')
self.stages.insert(0, newStage) self.stages.insert(0, newStage)
self.save() self.save()
@@ -94,4 +100,3 @@ class IDPair(object):
def __hash__(self): def __hash__(self):
"""Returns a hash value for the IDPair""" """Returns a hash value for the IDPair"""
return hash((self.calendarID, self.eventID)) return hash((self.calendarID, self.eventID))