Skip to content

Commit

Permalink
Add a set of linting fixes to resolve flake issues (#56)
Browse files Browse the repository at this point in the history
* Linting fixes

* Linting fixes

* Add a set of linting fixes for flake8

* Update changelog

* Fix which errors we care about in github action tests

* Update version in preparation for new release
  • Loading branch information
j6k4m8 committed Jan 13, 2022
1 parent a070f2b commit 51eb352
Show file tree
Hide file tree
Showing 16 changed files with 153 additions and 158 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/python-package.yml
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7, 3.8]
python-version: [3.7, 3.8, 3.9, '3.10']

steps:
- uses: actions/checkout@v2
Expand All @@ -33,7 +33,7 @@ jobs:
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --max-complexity=20 --max-line-length=127 --statistics
flake8 . --count --max-complexity=30 --max-line-length=127 --statistics --ignore E501,W503
- name: Test with pytest
run: |
pytest --cov=./ --cov-report=xml
Expand Down
10 changes: 9 additions & 1 deletion CHANGELOG.md
@@ -1,20 +1,28 @@
# CHANGELOG

### **Unreleased**
### **0.4.0** (January 13 2022)

> Multiple fixes and improvements
- Fixes

- Changed some document name comparisons to case insensitive (prevent document overwrites, esp. for Windows users)
- Switched upload to require named arguments rather than positional
- Fixes the `limit` arg in the RSS provider, which was being ignored

- Improvements

- Improve typing support
- Added more error handling for file and syntax handling
- Change to using the `VissibleName` attribute in all cases rather than filename
- Added code for upcoming additional sanity checks
- Added more information on how to customize your goospaper in the docs, @kwillno (#54)
- Adds the option to provide a global config (thanks @sedennial! #48)
- Lots of new options to customize the upload and generation process (thanks @sedennial! #48)

- Housekeeping

- Fixes a bunch of flake8 errors and warnings to keep things tidy

### **0.3.1** (April 29 2021)

Expand Down
4 changes: 3 additions & 1 deletion goosepaper/__init__.py
@@ -1 +1,3 @@
from .goosepaper import Goosepaper
from .goosepaper import Goosepaper # noqa

__version__ = "0.4.0"
4 changes: 2 additions & 2 deletions goosepaper/__main__.py
Expand Up @@ -3,7 +3,7 @@

from goosepaper.goosepaper import Goosepaper
from goosepaper.util import construct_story_providers_from_config_dict
from goosepaper.upload import do_upload
from goosepaper.upload import upload
from goosepaper.multiparser import MultiParser


Expand Down Expand Up @@ -48,7 +48,7 @@ def main():
)
)
else:
do_upload(filepath=filename, multiparser=multiparser)
upload(filepath=filename, multiparser=multiparser)

return 0

Expand Down
8 changes: 5 additions & 3 deletions goosepaper/auth.py
@@ -1,6 +1,8 @@
from rmapy.api import Client
from rmapy.exceptions import AuthError

CODE_URL = "https://my.remarkable.com/connect/remarkable"


def auth_client():
client = Client()
Expand All @@ -9,14 +11,14 @@ def auth_client():
client.renew_token()
except AuthError:
print(
"Looks like this if the first time you've uploaded, need to register the device"
"Looks like this is the first time you've uploaded. You need to "
f"register the device. Input a code from {CODE_URL}"
)
print("Get the code from here: https://my.remarkable.com/connect/remarkable")
code = input()
print("registering")
client.register_device(code)
if not client.renew_token():
print("Honk! Registration failed D:")
print("Honk! Registration renewal failed.")
return False
else:
print("registration successful")
Expand Down
1 change: 0 additions & 1 deletion goosepaper/goosepaper.json
Expand Up @@ -7,6 +7,5 @@
"output": null,
"folder": null,
"nostory": false,
"replace": false,
"cleanup": false
}
30 changes: 23 additions & 7 deletions goosepaper/goosepaper.py
@@ -1,5 +1,4 @@
import datetime
import os

from uuid import uuid4
from typing import List, Type
Expand All @@ -9,7 +8,6 @@

from .util import PlacementPreference
from .storyprovider import StoryProvider
from .story import Story


class Goosepaper:
Expand Down Expand Up @@ -43,7 +41,12 @@ def to_html(self) -> str:
stories = self.get_stories()

# Get ears:
ears = [s for s in stories if s.placement_preference == PlacementPreference.EAR]
ears = [
s
for s in stories
# TODO: Which to prioritize?
if s.placement_preference == PlacementPreference.EAR
]
right_ear = ""
left_ear = ""
if len(ears) > 0:
Expand All @@ -67,7 +70,10 @@ def to_html(self) -> str:
return f"""
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta
http-equiv="Content-type"
content="text/html;
charset=utf-8" />
<meta charset="UTF-8" />
</head>
<body>
Expand All @@ -89,7 +95,10 @@ def to_html(self) -> str:
"""

def to_pdf(
self, filename: str, style: Type[Style] = AutumnStyle, font_size: int = 14
self,
filename: str,
style: Type[Style] = AutumnStyle,
font_size: int = 14,
) -> str:
"""
Renders the current Goosepaper to a PDF file on disk.
Expand All @@ -107,7 +116,10 @@ def to_pdf(
return filename

def to_epub(
self, filename: str, style: Type[Style] = AutumnStyle, font_size: int = 14
self,
filename: str,
style: Type[Style] = AutumnStyle,
font_size: int = 14,
) -> str:

"""
Expand Down Expand Up @@ -159,7 +171,11 @@ def to_epub(

if no_headlines:
file = f"{uuid4().hex}.xhtml"
chapter = epub.EpubHtml(title="From Reddit", file_name=file, lang="en")
chapter = epub.EpubHtml(
title="From Reddit",
file_name=file,
lang="en",
)
links.append(file)
chapter.content = "<br>".join([s.to_html() for s in no_headlines])
book.add_item(chapter)
Expand Down
77 changes: 31 additions & 46 deletions goosepaper/multiparser.py
@@ -1,6 +1,5 @@
import argparse
import os
from os import getenv
import pathlib

from goosepaper.util import load_config_file

Expand All @@ -15,8 +14,8 @@ def _split_lines(self, text, width):
class MultiParser:
def __init__(self):
"""
Creates a new MultiParser, which abstracts acessing command line arguments and config
file entries.
Creates a new MultiParser, which abstracts acessing command line
arguments and config file entries.
"""

Expand Down Expand Up @@ -104,11 +103,10 @@ def __init__(self):
# 3. Specified on the command line.

defaultconfigs = [
os.getenv("HOME") + "/.goosepaper.json",
str(pathlib.Path("~").expanduser()) + "/.goosepaper.json",
"./goosepaper.json",
self.args.config,
]
foundconfig = False
self.config = {}
outputcount = 0
debug_configs = True if self.args.showconfig else None
Expand All @@ -119,21 +117,26 @@ def __init__(self):

pp = pprint.PrettyPrinter(indent=3)
print(
"Command line arguments received:\n(including default values)\n--------------------------------"
"\n".join(
[
"Command line arguments received:",
"(including default values)",
"--------------------------------",
]
)
)
pp.pprint(self.args)

# If passed a config file on the command line, assume it's important so fail
# if not readable.
# If passed a config file on the command line, assume it's important
# so fail if not readable.

if self.args.config:
try:
valid = load_config_file(self.args.config)
load_config_file(self.args.config)
except FileNotFoundError:
print(
"Honk! Honk! Somebody stole my egg! Couldn't find config file ({0}) specified on the command line. Aborting migration.".format(
self.args.config
)
f"Couldn't find config file ({self.args.config}) "
"specified on the command line. Aborting."
)
exit(1)

Expand All @@ -147,68 +150,50 @@ def __init__(self):
tempconfig["stories"].append(story)

self.config.update(tempconfig)
foundconfig = True
if debug_configs:
print(
f"\nConfig options found in {defconfigfile}:\n---------------------\n"
f"\nConfig options found in {defconfigfile}:"
"\n---------------------\n"
)
pp.pprint(load_config_file(defconfigfile))
except FileNotFoundError as e:
except FileNotFoundError:
pass

if debug_configs:
print("\nFinal config values are:\n------------------")
pp.pprint(self.config)
print("")

if foundconfig is not True:
print(
"Honk! Honk! Unable to locate a config file. You must have at least one of the following! '$HOME/.goosepaper.json', './goosepaper.json', or a config file specified on the command line."
)
exit(1)

# Not sure if you should able to override the output destination or not.

# if outputcount > 0:
# print ("Honk! Honk! You've specified more than one output destination in your config files. A flying flock can only have one lead goose in a skein. Please resolve this.")
# exit(1)
# if 'output' in self.config and self.args.output:
# print ("Honk! Honk! You have both config file and command line output file options. I don't know which flock with which to fly with so I'm not flying anywhere. Please fix.")
# exit(1)

# --noreplace only makes sense to me on the command line, so if present in a config file ignore it.
# Same with --noupload.

if "noreplace" in self.config:
del self.config["noreplace"]
if "noupload" in self.config:
del self.config["upload"]

def argumentOrConfig(self, key, default=None, dependency=None):
"""
Returns a command line argument or an entry from the config file
Arguments:
key: the command line option name (as in --key) or config file entry
default (str: None): the default value, returned if the key was not set both as a
command line argument and a config entry
dependency (str: None): the name of a dependency command line argument or config
entry that must be present for this call to be valid
key: the command line option name (as in --key) or config entry
default (str: None): the default value, returned if the key was not
set both as a command line argument and a config entry
dependency (str: None): the name of a dependency command line
argument or config entry that must be present for this call to
be valid
Returns:
If a command line option with 'key' name was set, returns it. Else, if a config
entry named 'key' was set, returns it. If none of the previous was returned,
returns the default value specified by the 'default' argument.
If a command line option with 'key' name was set, returns it. Else,
if a config entry named 'key' was set, returns it. If none of
the previous was returned, returns the default value specified
by the 'default' argument.
"""

d = vars(self.args)
if key in d and d[key] is not None:
if dependency and (not dependency in d):
if dependency and dependency not in d:
self.parser.error(f"--{key} requires --{dependency}.")
value = d[key]
elif key in self.config:
value = self.config[key]
value = self.config[key] or default
else:
value = default

Expand Down
40 changes: 24 additions & 16 deletions goosepaper/rss.py
Expand Up @@ -5,12 +5,29 @@
import multiprocessing

from .story import Story
from .util import PlacementPreference
from .storyprovider import StoryProvider


def parallelizable_request(entry):
req = requests.get(entry["link"])
if not req.ok:
print(f"Honk! Couldn't get content for {entry['link']}")
return None

doc = Document(req.content)
source = entry["link"].split(".")[1]
story = Story(doc.title(), body_html=doc.summary(), byline=source)

return story


class RSSFeedStoryProvider(StoryProvider):
def __init__(self, rss_path: str, limit: int = 5, parallel: bool = True) -> None:
def __init__(
self,
rss_path: str,
limit: int = 5,
parallel: bool = True,
) -> None:
self.limit = limit
self.feed_url = rss_path
self._parallel = parallel
Expand All @@ -23,20 +40,11 @@ def get_stories(self, limit: int = 5) -> List[Story]:

if self._parallel:
with multiprocessing.Pool(multiprocessing.cpu_count()) as pool:
stories = pool.map(self.parallelizable_request, feed.entries[:limit])
stories = pool.map(
parallelizable_request,
feed.entries[:limit],
)
else:
stories = [self.parallelizable_request(e) for e in feed.entries[:limit]]
stories = [parallelizable_request(e) for e in feed.entries[:limit]]

return list(filter(None, stories))

def parallelizable_request(self, entry):
req = requests.get(entry["link"])
if not req.ok:
print(f"Honk! Couldn't grab content for {self.feed_url}")
return None

doc = Document(req.content)
source = entry["link"].split(".")[1]
story = Story(doc.title(), body_html=doc.summary(), byline=source)

return story
3 changes: 0 additions & 3 deletions goosepaper/styles.py
@@ -1,6 +1,3 @@
from typing import Union


class Style:
def get_stylesheets(self) -> list:
...
Expand Down

0 comments on commit 51eb352

Please sign in to comment.