Skip to content

Commit

Permalink
Code update/pylint mypy (#95)
Browse files Browse the repository at this point in the history
* Update code to latest pylint recommendations
* Add python 3.9 to workflow
* mypy types requirements
* add copyright notice
* mypy recommendations
* ignore last two mypy errors (TODO: find out, how to solve them instead of ignoring)
* remove encoding for binary files
* add codeql-analysis on github
  • Loading branch information
lowtower authored Dec 1, 2021
1 parent a33712a commit d7ff0ba
Show file tree
Hide file tree
Showing 15 changed files with 111 additions and 31 deletions.
70 changes: 70 additions & 0 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"

on:
push:
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '35 6 * * 1'

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support

steps:
- name: Checkout repository
uses: actions/checkout@v2

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language

#- run: |
# make bootstrap
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
strategy:
max-parallel: 4
matrix:
python-version: [3.6, 3.7, 3.8]
python-version: [3.6, 3.7, 3.8, 3.9]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
Expand Down
3 changes: 2 additions & 1 deletion gpxtrackposter/calendar_drawer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import calendar
import datetime

import pint # type: ignore
import svgwrite # type: ignore

from gpxtrackposter import utils
Expand Down Expand Up @@ -104,7 +105,7 @@ def _draw(self, dr: svgwrite.Drawing, g: svgwrite.container.Group, size: XY, off
text_date = date.strftime("%Y-%m-%d")
if text_date in self.poster.tracks_by_date:
tracks = self.poster.tracks_by_date[text_date]
length = sum([t.length() for t in tracks])
length = pint.quantity.Quantity(sum([t.length() for t in tracks]))
has_special = len([t for t in tracks if t.special]) > 0
color = self.color(self.poster.length_range_by_date, length, has_special)
g.add(dr.rect(pos, dim, fill=color))
Expand Down
2 changes: 1 addition & 1 deletion gpxtrackposter/circular_drawer.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ def _draw_circle_segment(
values: str = "",
key_times: str = "",
) -> None:
length = sum([t.length() for t in tracks])
length = pint.quantity.Quantity(sum([t.length() for t in tracks]))
has_special = len([t for t in tracks if t.special]) > 0
color = self.color(self.poster.length_range_by_date, length, has_special)
max_length = self.poster.length_range_by_date.upper()
Expand Down
9 changes: 5 additions & 4 deletions gpxtrackposter/github_drawer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import datetime
import locale

import pint # type: ignore
import svgwrite # type: ignore

from gpxtrackposter import utils
Expand All @@ -17,7 +18,7 @@


class GithubDrawer(TracksDrawer):
"""Draw a gtihub profile-like poster"""
"""Draw a github profile-like poster"""

def __init__(self, the_poster: Poster):
super().__init__(the_poster)
Expand All @@ -37,9 +38,9 @@ def draw(self, dr: svgwrite.Drawing, g: svgwrite.container.Group, size: XY, offs
start_date_weekday, _ = calendar.monthrange(year, 1)
github_rect_first_day = datetime.date(year, 1, 1)
# Github profile the first day start from the last Monday of the last year or the first Monday of this year
# It depands on if the first day of this year is Monday or not.
# It depends on if the first day of this year is Monday or not.
github_rect_day = github_rect_first_day + datetime.timedelta(-start_date_weekday)
year_length = total_length_year_dict.get(year, 0)
year_length = pint.quantity.Quantity(total_length_year_dict.get(year, 0))
year_length_str = utils.format_float(self.poster.m2u(year_length))
month_names = [
locale.nl_langinfo(day)[:3] # Get only first three letters
Expand Down Expand Up @@ -105,7 +106,7 @@ def draw(self, dr: svgwrite.Drawing, g: svgwrite.container.Group, size: XY, offs
date_title = str(github_rect_day)
if date_title in self.poster.tracks_by_date:
tracks = self.poster.tracks_by_date[date_title]
length = sum([t.length() for t in tracks])
length = pint.quantity.Quantity(sum([t.length() for t in tracks]))
distance1 = self.poster.special_distance["special_distance"]
distance2 = self.poster.special_distance["special_distance2"]
has_special = distance1 < length < distance2
Expand Down
14 changes: 7 additions & 7 deletions gpxtrackposter/poster.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class Poster:
"""Create a poster from track data.
Attributes:
athlete: Name of athlete to be displayed on poster.
title: Title of poster.
_athlete: Name of athlete to be displayed on poster.
_title: Title of poster.
tracks_by_date: Tracks organized temporally if needed.
tracks: List of tracks to be used in the poster.
length_range: Range of lengths of tracks in poster.
Expand All @@ -59,7 +59,7 @@ def __init__(self) -> None:
self.tracks: typing.List[Track] = []
self.length_range = QuantityRange()
self.length_range_by_date = QuantityRange()
self.total_length_year_dict: typing.Dict[int, pint.quantity.Quantity] = defaultdict(int)
self.total_length_year_dict: typing.Dict[int, pint.quantity.Quantity] = defaultdict(int) # type: ignore
self.units = "metric"
self.colors = {
"background": "#222222",
Expand Down Expand Up @@ -150,12 +150,12 @@ def set_tracks(self, tracks: typing.List[Track]) -> None:
continue
text_date = track.start_time().strftime("%Y-%m-%d")
year = track.start_time().year
if not text_date in self.tracks_by_date:
if text_date not in self.tracks_by_date:
self.year_tracks_date_count_dict[year] += 1
self.tracks_by_date[text_date].append(track)
self.length_range.extend(track.length())
for date_tracks in self.tracks_by_date.values():
length = sum([t.length() for t in date_tracks])
length = pint.quantity.Quantity(sum([t.length() for t in date_tracks]))
self.length_range_by_date.extend(length)

def draw(self, drawer: "TracksDrawer", output: str) -> None:
Expand Down Expand Up @@ -280,8 +280,8 @@ def _draw_footer(self, d: svgwrite.Drawing) -> None:
assert min_length is not None
assert max_length is not None
else:
min_length = 0.0
max_length = 0.0
min_length = pint.quantity.Quantity(0.0)
max_length = pint.quantity.Quantity(0.0)
g.add(
d.text(
self.translate("Min") + ": " + self.format_distance(min_length),
Expand Down
4 changes: 2 additions & 2 deletions gpxtrackposter/quantity_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def diameter(self) -> pint.quantity.Quantity:
assert self._upper is not None
assert self._lower is not None
return self._upper - self._lower
return 0
return pint.quantity.Quantity(0)

def contains(self, value: pint.quantity.Quantity) -> bool:
if not self.is_valid():
Expand Down Expand Up @@ -67,7 +67,7 @@ def interpolate(self, relative: float) -> pint.quantity.Quantity:

def relative_position(self, value: pint.quantity.Quantity) -> float:
if not self.is_valid():
raise ValueError("Cannot get relaitive_position for invalid QuantityRange")
raise ValueError("Cannot get relative_position for invalid QuantityRange")
assert self._lower is not None
assert self._upper is not None
if value <= self._lower:
Expand Down
8 changes: 4 additions & 4 deletions gpxtrackposter/track.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def load_gpx(self, file_name: str, timezone_adjuster: typing.Optional[TimezoneAd
# (for example, treadmill runs pulled via garmin-connect-export)
if os.path.getsize(file_name) == 0:
raise TrackLoadError("Empty GPX file")
with open(file_name, "r") as file:
with open(file_name, "r", encoding="utf8") as file:
self._load_gpx_data(gpxpy.parse(file), timezone_adjuster)
except TrackLoadError as e:
raise e
Expand Down Expand Up @@ -130,7 +130,7 @@ def _load_gpx_data(self, gpx: gpxpy.gpx.GPX, timezone_adjuster: typing.Optional[
if not self.has_time():
raise TrackLoadError("Track has no start or end time.")
if timezone_adjuster:
lat, _, lng, _ = list(gpx.get_bounds())
lat, _, lng, _ = list(gpx.get_bounds()) # type: ignore
latlng = s2sphere.LatLng.from_degrees(lat, lng)
self.set_start_time(timezone_adjuster.adjust(self.start_time(), latlng))
self.set_end_time(timezone_adjuster.adjust(self.end_time(), latlng))
Expand Down Expand Up @@ -163,7 +163,7 @@ def load_cache(self, cache_file_name: str) -> None:
TrackLoadError: An error occurred while loading the track data from the cache file.
"""
try:
with open(cache_file_name) as data_file:
with open(cache_file_name, encoding="utf8") as data_file:
data = json.load(data_file)
self.set_start_time(datetime.datetime.strptime(data["start"], "%Y-%m-%d %H:%M:%S"))
self.set_end_time(datetime.datetime.strptime(data["end"], "%Y-%m-%d %H:%M:%S"))
Expand All @@ -181,7 +181,7 @@ def store_cache(self, cache_file_name: str) -> None:
dir_name = os.path.dirname(cache_file_name)
if not os.path.isdir(dir_name):
os.makedirs(dir_name)
with open(cache_file_name, "w") as json_file:
with open(cache_file_name, "w", encoding="utf8") as json_file:
lines_data = []
for line in self.polylines:
lines_data.append([{"lat": latlng.lat().degrees, "lng": latlng.lng().degrees} for latlng in line])
Expand Down
11 changes: 6 additions & 5 deletions gpxtrackposter/track_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,12 @@ def load_strava_tracks(self, strava_config: str) -> typing.List[Track]:
if self.cache_dir:
self.strava_cache_file = os.path.join(self.cache_dir, strava_config)
if os.path.isfile(self.strava_cache_file):
with open(self.strava_cache_file) as f:
with open(self.strava_cache_file, encoding="utf8") as f:
strava_cache_data = json.load(f)
tracks = [self._strava_cache_to_track(i) for i in strava_cache_data]
tracks_names = [track.file_names[0] for track in tracks]

with open(strava_config) as f:
with open(strava_config, encoding="utf8") as f:
strava_data = json.load(f)
filter_type = strava_data.pop("activity_type", None)
client = Client()
Expand Down Expand Up @@ -176,7 +176,7 @@ def _filter_and_merge_tracks(self, tracks: typing.List[Track]) -> typing.List[Tr
# filter out tracks with length < min_length
tracks = [t for t in tracks if t.length() >= self._min_length]
# filter out tracks with wrong activity type
tracks = [t for t in tracks if t.activity_type == self._activity_type or self._activity_type == "all"]
tracks = [t for t in tracks if self._activity_type in (t.activity_type, "all")]
return tracks

@staticmethod
Expand Down Expand Up @@ -280,7 +280,7 @@ def _store_strava_tracks_to_cache(self, tracks: typing.List[Track]) -> None:
os.makedirs(dirname)
log.info("Storing %d track(s) to cache...", len(tracks))
to_cache_tracks = [self._make_strava_cache_dict(track) for track in tracks]
with open(self.strava_cache_file, "w") as f:
with open(self.strava_cache_file, "w", encoding="utf8") as f:
json.dump(to_cache_tracks, f)

@staticmethod
Expand Down Expand Up @@ -325,7 +325,8 @@ def _get_cache_file_name(self, file_name: str) -> str:
return self._cache_file_names[file_name]

try:
checksum = hashlib.sha256(open(file_name, "rb").read()).hexdigest()
with open(file_name, "rb") as file:
checksum = hashlib.sha256(file.read()).hexdigest()
except PermissionError as e:
raise TrackLoadError("Failed to compute checksum (bad permissions).") from e
except Exception as e:
Expand Down
2 changes: 1 addition & 1 deletion gpxtrackposter/tracks_drawer.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
import pint # type: ignore
import svgwrite # type: ignore

from gpxtrackposter import utils
from gpxtrackposter.poster import Poster
from gpxtrackposter.quantity_range import QuantityRange
from gpxtrackposter.xy import XY
from gpxtrackposter import utils


class TracksDrawer:
Expand Down
2 changes: 2 additions & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ pylint
pytest
pytest-mock~=3.3
python-dateutil
types-python-dateutil
types-pytz
4 changes: 2 additions & 2 deletions scripts/bump_year.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

def bump_year(file_name: str) -> None:
lines = []
with open(file_name, "r") as f:
with open(file_name, "r", encoding="utf8") as f:
for line in f.readlines():
m = re_year.search(line)
if m and (m.group(1) != THIS_YEAR):
Expand All @@ -32,7 +32,7 @@ def bump_year(file_name: str) -> None:

lines.append(line)

with open(file_name, "w") as f:
with open(file_name, "w", encoding="utf8") as f:
f.writelines(lines)


Expand Down
2 changes: 1 addition & 1 deletion scripts/check_copyright.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def has_valid_copyright(file_name: str) -> bool:
copyright_found = False
copyright_bad_year_found = False

with open(file_name, "r") as f:
with open(file_name, "r", encoding="utf8") as f:
for line in f.readlines():
empty = False
if re_copyright.search(line):
Expand Down
4 changes: 2 additions & 2 deletions scripts/update_readme.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
raise RuntimeError(f"Bad README.md file: {readme_md_file_name}")

# replace usage in README.md
with open(readme_md_file_name, "r") as f:
with open(readme_md_file_name, "r", encoding="utf8") as f:
lines = f.readlines()

with open(readme_md_file_name, "w") as f:
with open(readme_md_file_name, "w", encoding="utf8") as f:
STATE = 0
for line in lines:
if STATE == 0:
Expand Down
5 changes: 5 additions & 0 deletions tests/test_track_loader.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Copyright 2020-2021 Florian Pigorsch & Contributors. All rights reserved.
#
# Use of this source code is governed by a MIT-style
# license that can be found in the LICENSE file.

import datetime
import json
from pathlib import Path
Expand Down

0 comments on commit d7ff0ba

Please sign in to comment.