Skip to content

Commit

Permalink
Improve network error handling and fix linter warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
sanjacob committed Sep 16, 2024
1 parent a7f94c9 commit 435296f
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 106 deletions.
3 changes: 2 additions & 1 deletion blackboard_sync/__about__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.

__all__ = [
"__id__",
Expand Down
6 changes: 6 additions & 0 deletions blackboard_sync/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@
__copyright__
)

__all__ = [
'__id__', '__title__', '__summary__', '__uri__', '__homepage__',
'__author__', '__email__', '__publisher__', '__license__',
'__license_spdx__', '__copyright__'
]

# Console Output
logger = logging.getLogger(__name__)
logger.addHandler(logging.StreamHandler())
Expand Down
3 changes: 2 additions & 1 deletion blackboard_sync/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.

from .sync_controller import SyncController

Expand Down
34 changes: 21 additions & 13 deletions blackboard_sync/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.

import logging
import configparser
from typing import Any, Optional
from typing import Any
from pathlib import Path
from functools import wraps
from datetime import datetime
Expand All @@ -36,10 +37,14 @@
class Config(configparser.ConfigParser):
"""Base configuration manager class, which wraps a ConfigParser."""


def __init__(self, config_file: Path, *args, **kwargs):
super().__init__(converters={'path': Path, 'date': datetime.fromisoformat},
interpolation=None, *args, **kwargs)
converters: dict[str, Callable[[str], Any]] = {
'path': Path, 'date': datetime.fromisoformat
}

super().__init__(converters=converters, interpolation=None,
*args, **kwargs)

self._config_file = config_file
self.read(self._config_file)

Expand Down Expand Up @@ -68,28 +73,31 @@ class SyncConfig(Config):
_config_filename = "blackboard_sync"

def __init__(self, custom_dir=None):
config_dir = custom_dir or Path(user_config_dir(appauthor=__author__, roaming=True))
super().__init__(config_dir / self._config_filename, empty_lines_in_values=False)
default_dir = Path(user_config_dir(appauthor=__author__, roaming=True))

config_dir = custom_dir or default_dir
super().__init__(config_dir / self._config_filename,
empty_lines_in_values=False)

if 'Sync' not in self:
self['Sync'] = {}

self._sync = self['Sync']

@property
def last_sync_time(self) -> Optional[datetime]:
def last_sync_time(self) -> datetime | None:
return self._sync.getdate('last_sync_time')

@last_sync_time.setter
@Config.persist
def last_sync_time(self, last: Optional[datetime]) -> None:
def last_sync_time(self, last: datetime | None) -> None:
if last is None:
self.remove_option('Sync', 'last_sync_time')
else:
self._sync['last_sync_time'] = last.isoformat()

@property
def download_location(self) -> Optional[Path]:
def download_location(self) -> Path | None:
# Default download location
default = Path(Path.home(), 'Downloads', 'BlackboardSync')
return self._sync.getpath('download_location') or default
Expand All @@ -100,7 +108,7 @@ def download_location(self, sync_dir: Path) -> None:
self._sync['download_location'] = str(sync_dir)

@property
def university_index(self) -> Optional[int]:
def university_index(self) -> int | None:
return self._sync.getint('university')

@university_index.setter
Expand All @@ -109,10 +117,10 @@ def university_index(self, university: int) -> None:
self._sync['university'] = str(university)

@property
def min_year(self) -> Optional[int]:
def min_year(self) -> int | None:
return self._sync.getint('min_year')

@min_year.setter
@Config.persist
def min_year(self, year: Optional[int])-> None:
def min_year(self, year: int | None) -> None:
self._sync['min_year'] = str(year or 0)
2 changes: 1 addition & 1 deletion blackboard_sync/content/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def __init__(self, content: BBCourseContent, api_path: BBContentPath,
try:
self.handler = Handler(content, api_path, job)
except (ValidationError, JSONDecodeError,
BBBadRequestError, BBForbiddenError, RequestException):
BBBadRequestError, BBForbiddenError):
logger.exception(f"Error fetching {content.title}")

try:
Expand Down
26 changes: 10 additions & 16 deletions blackboard_sync/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,17 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.

import logging
import platform
from requests.exceptions import RequestException
from pathlib import Path
from typing import Optional
from dateutil.parser import parse
from datetime import datetime, timezone
from concurrent.futures import ThreadPoolExecutor

from blackboard.api_extended import BlackboardExtended
from blackboard.blackboard import BBCourseContent, BBResourceType
from blackboard.filters import BBMembershipFilter, BWFilter

from .content import ExternalLink, ContentBody, Document, Folder, Content
from .content import BBContentPath
from .content.job import DownloadJob
from .content.course import Course

Expand All @@ -50,8 +44,8 @@ class BlackboardDownload:

def __init__(self, sess: BlackboardExtended,
download_location: Path,
last_downloaded: Optional[datetime] = None,
min_year: Optional[int] = None):
last_downloaded: datetime | None = None,
min_year: int | None = None):
"""BlackboardDownload constructor
Download all files in blackboard recursively to download_location,
Expand All @@ -61,8 +55,8 @@ def __init__(self, sess: BlackboardExtended,
:param BlackboardExtended sess: UCLan BB user session
:param (str / Path) download_location: Where files will be stored
:param str last_downloaded: Files modified before this will not be downloaded
:param min_year: Only courses created on or after this year will be downloaded
:param str last_downloaded: Files modified before are ignored
:param min_year: Courses created before are ignored
"""

self._sess = sess
Expand All @@ -75,8 +69,7 @@ def __init__(self, sess: BlackboardExtended,
if last_downloaded is not None:
self._last_downloaded = last_downloaded


def download(self) -> Optional[datetime]:
def download(self) -> datetime | None:
"""Retrieve the user's courses, and start download of all contents
:return: Datetime when method was called.
Expand All @@ -99,7 +92,8 @@ def download(self) -> Optional[datetime]:
courses = self._sess.ex_fetch_courses(user_id=self.user_id,
result_filter=course_filter)

job = DownloadJob(session=self._sess, last_downloaded=self._last_downloaded)
job = DownloadJob(session=self._sess,
last_downloaded=self._last_downloaded)

for course in courses:
if self.cancelled:
Expand All @@ -109,7 +103,7 @@ def download(self) -> Optional[datetime]:

Course(course, job).write(self.download_location, self.executor)

logger.info(f"Shutting down download workers")
logger.info("Shutting down download workers")
self.executor.shutdown(wait=True, cancel_futures=self.cancelled)

return start_time if not self.cancelled else None
Expand Down
4 changes: 2 additions & 2 deletions blackboard_sync/institutions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.

import json
import logging
from pathlib import Path

import requests
from pydantic import HttpUrl, BaseModel

from .ip import find_my_ip, find_ip_entity
Expand Down
2 changes: 1 addition & 1 deletion blackboard_sync/ip.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def find_my_ip() -> str | None:
try:
r = requests.get(IP_API, timeout=IP_TIMEOUT)
r.raise_for_status()
except requests.RequestException:
except requests.RequestException:
return None
else:
return r.text
Expand Down
Loading

0 comments on commit 435296f

Please sign in to comment.