Skip to content

Commit 2679fd9

Browse files
Merge pull request #51 from freedomofpress/add-flake8-black
Add flake8, black, isort; GitHub action
2 parents 198c568 + b414a7e commit 2679fd9

File tree

8 files changed

+105
-82
lines changed

8 files changed

+105
-82
lines changed

.flake8

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[flake8]
2+
max-line-length = 100

.github/workflows/ci.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: CI
2+
on: [push, pull_request]
3+
4+
jobs:
5+
lint:
6+
runs-on: ubuntu-latest
7+
steps:
8+
- uses: actions/checkout@v3
9+
- name: Install dependencies
10+
run: |
11+
apt-get update && apt-get install --yes --no-install-recommends make python3-pip
12+
pip install black==23.7.0 flake8==6.0.0 isort==5.12.0
13+
- name: Run lint
14+
run: |
15+
make lint-all

Makefile

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.PHONY: flake8 isort isort-fix black black-fix lint-all
2+
3+
# Directory to run the linters on
4+
DIR = .
5+
6+
flake8:
7+
@echo "Running Flake8"
8+
@flake8 $(DIR)
9+
10+
isort:
11+
@echo "Running isort"
12+
@isort --check --diff $(DIR)
13+
14+
isort-fix:
15+
@echo "Running isort (fix)"
16+
@isort $(DIR)
17+
18+
black:
19+
@echo "Running Black"
20+
@black --check $(DIR)
21+
22+
black-fix:
23+
@echo "Running Black (fix)"
24+
@black $(DIR)
25+
26+
lint-all: flake8 isort black
27+
@echo "Linting complete"

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[tool.black]
2+
line-length = 100
3+
target-version = ['py39']

requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ readability-lxml==0.8.1
77
requests==2.31.0
88
tweepy==4.14.0
99
Mastodon.py==1.8.1
10+
black==23.7.0
11+
flake8==6.0.0
12+
isort==5.12.0

setup.py

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,31 @@
1-
from setuptools import setup, find_packages
1+
from setuptools import find_packages, setup
22

3-
with open('requirements.txt') as f:
3+
with open("requirements.txt") as f:
44
reqs = f.read().split()
55

6-
with open('README.md') as f:
6+
with open("README.md") as f:
77
readme = f.read()
88

99
setup(
10-
name='trackthenews',
11-
version='0.2',
12-
description='Monitor RSS feeds for keywords and act on matching results. A special project of the Freedom of the Press Foundation.',
10+
name="trackthenews",
11+
version="0.2",
12+
description="Monitor RSS feeds for keywords and act on matching results."
13+
" A special project of the Freedom of the Press Foundation.",
1314
long_description=readme,
14-
long_description_content_type='text/markdown',
15+
long_description_content_type="text/markdown",
1516
install_requires=reqs,
16-
author='Parker Higgins',
17-
author_email='[email protected]',
18-
url='https://github.com/freedomofpress/trackthenews',
19-
entry_points={
20-
'console_scripts': ['trackthenews=trackthenews:main']
21-
},
22-
package_data={
23-
'trackthenews': ['fonts/*']
24-
},
17+
author="Parker Higgins",
18+
author_email="[email protected]",
19+
url="https://github.com/freedomofpress/trackthenews",
20+
entry_points={"console_scripts": ["trackthenews=trackthenews:main"]},
21+
package_data={"trackthenews": ["fonts/*"]},
2522
include_package_data=True,
26-
license='MIT',
23+
license="MIT",
2724
classifiers=[
28-
'License :: OSI Approved :: MIT License',
29-
'Programming Language :: Python',
30-
'Programming Language :: Python :: 3',
31-
'Programming Language :: Python :: 3.9'],
32-
packages=find_packages(exclude=('ttnconfig',))
25+
"License :: OSI Approved :: MIT License",
26+
"Programming Language :: Python",
27+
"Programming Language :: Python :: 3",
28+
"Programming Language :: Python :: 3.9",
29+
],
30+
packages=find_packages(exclude=("ttnconfig",)),
3331
)

trackthenews/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from .core import *
1+
from .core import main # noqa: F401

trackthenews/core.py

Lines changed: 34 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,26 @@
44

55
from __future__ import unicode_literals
66

7-
from typing import IO, Iterable, List
8-
97
import argparse
108
import json
119
import os
1210
import sqlite3
13-
import time
14-
import textwrap
1511
import sys
16-
12+
import textwrap
13+
import time
14+
from builtins import input
1715
from datetime import datetime
1816
from io import BytesIO, open
19-
from builtins import input
17+
from typing import IO, Iterable, List
2018

2119
import feedparser
2220
import html2text
2321
import requests
22+
import tweepy
2423
import yaml
25-
24+
from mastodon import Mastodon, MastodonError, MastodonNetworkError
2625
from PIL import Image, ImageDraw, ImageFont
2726
from readability import Document
28-
from mastodon import Mastodon, MastodonNetworkError, MastodonError
29-
import tweepy
3027

3128
# TODO: add/remove RSS feeds from within the script.
3229
# Currently the matchwords list and RSS feeds list must be edited separately.
@@ -118,11 +115,7 @@ def truncate_alt_text(self, text, max_chars=1500):
118115
"""Truncates the alt text to fit within the character limit."""
119116
alt_text = "Excerpt: " + text
120117
remaining_chars = max_chars - 3 # 3 chars for the ellipsis
121-
alt_text = (
122-
(alt_text[:remaining_chars] + "…")
123-
if len(alt_text) > max_chars
124-
else alt_text
125-
)
118+
alt_text = (alt_text[:remaining_chars] + "…") if len(alt_text) > max_chars else alt_text
126119
return alt_text
127120

128121
def tweet(self):
@@ -165,9 +158,7 @@ def toot(self):
165158
for idx, img_file in enumerate(img_files):
166159
try:
167160
alt_text = self.truncate_alt_text(self.matching_grafs[idx])
168-
res = mastodon.media_post(
169-
img_file, mime_type="image/jpeg", description=alt_text
170-
)
161+
res = mastodon.media_post(img_file, mime_type="image/jpeg", description=alt_text)
171162
media_ids.append(res["id"])
172163
except MastodonError:
173164
pass
@@ -218,9 +209,7 @@ def get_twitter_client_v1():
218209
oauth_token = config["twitter"]["oauth_token"]
219210
oauth_token_secret = config["twitter"]["oauth_secret"]
220211

221-
tweepy_auth = tweepy.OAuth1UserHandler(
222-
app_key, app_secret, oauth_token, oauth_token_secret
223-
)
212+
tweepy_auth = tweepy.OAuth1UserHandler(app_key, app_secret, oauth_token, oauth_token_secret)
224213

225214
return tweepy.API(tweepy_auth)
226215

@@ -235,7 +224,7 @@ def upload_twitter_images(img_files: Iterable[IO]) -> List[tweepy.models.Media]:
235224
try:
236225
res = twitter.media_upload(filename="image", file=img)
237226
media.append(res)
238-
except tweepy.errors.TweepyException as e:
227+
except tweepy.errors.TweepyException:
239228
pass
240229

241230
return media
@@ -311,7 +300,6 @@ def parse_feed(outlet, url, delicate, redirects):
311300

312301

313302
def config_twitter(config):
314-
315303
twitter_setup = input("Would you like the bot to post to Twitter? (Y/n) ")
316304
if twitter_setup.lower().startswith("n"):
317305
return config
@@ -425,24 +413,20 @@ def setup_matchlist():
425413
with open(path, "w") as f:
426414
f.write("")
427415
print(
428-
"A new matchlist has been generated at {path}. You can add case insensitive entries to match, one per line.".format(
429-
**locals()
430-
)
416+
"A new matchlist has been generated at {path}."
417+
" You can add case insensitive entries to match, one per line.".format(**locals())
431418
)
432419

433420
if os.path.isfile(path_case_sensitive):
434421
print(
435-
"A case-sensitive matchlist already exists at {path_case_sensitive}.".format(
436-
**locals()
437-
)
422+
"A case-sensitive matchlist already exists at {path_case_sensitive}.".format(**locals())
438423
)
439424
else:
440425
with open(path_case_sensitive, "w") as f:
441426
f.write("")
442427
print(
443-
"A new case-sensitive matchlist has been generated at {path_case_sensitive}. You can add case-sensitive entries to match, one per line.".format(
444-
**locals()
445-
)
428+
"A new case-sensitive matchlist has been generated at {path_case_sensitive}."
429+
" You can add case-sensitive entries to match, one per line.".format(**locals())
446430
)
447431

448432
return
@@ -457,9 +441,7 @@ def setup_rssfeedsfile():
457441
else:
458442
with open(path, "w") as f:
459443
f.write("")
460-
print(
461-
"A new RSS feeds file has been generated at {path}.".format(**locals())
462-
)
444+
print("A new RSS feeds file has been generated at {path}.".format(**locals()))
463445

464446
return
465447

@@ -472,9 +454,9 @@ def initial_setup():
472454
config = yaml.full_load(f)
473455
else:
474456
to_configure = input(
475-
"It looks like this is the first time you've run trackthenews, or you've moved or deleted its configuration files.\nWould you like to create a new configuration in {}? (Y/n) ".format(
476-
home
477-
)
457+
"It looks like this is the first time you've run trackthenews,"
458+
" or you've moved or deleted its configuration files.\n"
459+
"Would you like to create a new configuration in {}? (Y/n) ".format(home)
478460
)
479461

480462
config = {}
@@ -487,15 +469,17 @@ def initial_setup():
487469
else:
488470
try:
489471
os.makedirs(home)
490-
except:
472+
except Exception:
491473
pass
492474

493475
if "db" not in config:
494476
config["db"] = "trackthenews.db"
495477

496478
if "user-agent" not in config:
497479
ua = input(
498-
"What would you like your script's user-agent to be?\nThis should be something that is meaningful to you and may show up in the logs of the sites you are tracking: "
480+
"What would you like your script's user-agent to be?\n"
481+
"This should be something that is meaningful to you and"
482+
" may show up in the logs of the sites you are tracking: "
499483
)
500484

501485
ua = ua + " / powered by trackthenews (a project of freedom.press)"
@@ -516,9 +500,7 @@ def initial_setup():
516500

517501
# check if either Twitter or Mastodon has been configured
518502
if "twitter" not in config and "mastodon" not in config:
519-
print(
520-
"Error: The bot must have at least one of Twitter or Mastodon configured."
521-
)
503+
print("Error: The bot must have at least one of Twitter or Mastodon configured.")
522504
sys.exit(1)
523505

524506
with open(configfile, "w") as f:
@@ -540,12 +522,11 @@ def apply_migrations(conn):
540522

541523
def main():
542524
parser = argparse.ArgumentParser(
543-
description="Track articles from RSS feeds for a custom list of keywords and act on the matches."
525+
description="Track articles from RSS feeds for a custom list of keywords"
526+
" and act on the matches."
544527
)
545528

546-
parser.add_argument(
547-
"-c", "--config", help="Run configuration process", action="store_true"
548-
)
529+
parser.add_argument("-c", "--config", help="Run configuration process", action="store_true")
549530
parser.add_argument(
550531
"dir",
551532
nargs="?",
@@ -563,7 +544,8 @@ def main():
563544
if args.config:
564545
initial_setup()
565546
sys.exit(
566-
"Created new configuration files. Now go populate the RSS Feed file and the list of matchwords!"
547+
"Created new configuration files."
548+
" Now go populate the RSS Feed file and the list of matchwords!"
567549
)
568550

569551
configfile = os.path.join(home, "config.yaml")
@@ -599,9 +581,8 @@ def main():
599581

600582
if not (matchwords or matchwords_case_sensitive):
601583
sys.exit(
602-
"You must add words to at least one of the matchwords lists, located at {} and {}.".format(
603-
matchlist, matchlist_case_sensitive
604-
)
584+
"You must add words to at least one of the matchwords lists,"
585+
" located at {} and {}.".format(matchlist, matchlist_case_sensitive)
605586
)
606587

607588
sys.path.append(home)
@@ -634,9 +615,7 @@ def main():
634615
rss_feeds = json.load(f)
635616
except json.JSONDecodeError:
636617
sys.exit(
637-
"You must add RSS feeds to the RSS feeds list, located at {}.".format(
638-
rssfeedsfile
639-
)
618+
"You must add RSS feeds to the RSS feeds list, located at {}.".format(rssfeedsfile)
640619
)
641620

642621
for feed in rss_feeds:
@@ -656,15 +635,11 @@ def main():
656635
deduped.append(article)
657636

658637
for counter, article in enumerate(deduped, 1):
659-
print(
660-
"Checking {} article {}/{}".format(
661-
article.outlet, counter, len(deduped)
662-
)
663-
)
638+
print("Checking {} article {}/{}".format(article.outlet, counter, len(deduped)))
664639

665640
try:
666641
article.check_for_matches()
667-
except:
642+
except Exception:
668643
print("Having trouble with that article. Skipping for now.")
669644
pass
670645

0 commit comments

Comments
 (0)