diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml new file mode 100644 index 0000000..b46cf32 --- /dev/null +++ b/.github/workflows/black.yml @@ -0,0 +1,10 @@ +name: Black + +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: psf/black@stable diff --git a/poetry.lock b/poetry.lock index 144e920..a6c5103 100644 --- a/poetry.lock +++ b/poetry.lock @@ -19,7 +19,7 @@ pyyaml = "*" [[package]] name = "astroid" -version = "2.6.5" +version = "2.8.0" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false @@ -28,7 +28,7 @@ python-versions = "~=3.6" [package.dependencies] lazy-object-proxy = ">=1.4.0" typed-ast = {version = ">=1.4.0,<1.5", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} -typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} +typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} wrapt = ">=1.11,<1.13" [[package]] @@ -237,6 +237,18 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] pyparsing = ">=2.0.2" +[[package]] +name = "platformdirs" +version = "2.3.0" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] +test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] + [[package]] name = "pluggy" version = "0.13.1" @@ -281,18 +293,20 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pylint" -version = "2.9.6" +version = "2.11.1" description = "python code static checker" category = "dev" optional = false python-versions = "~=3.6" [package.dependencies] -astroid = ">=2.6.5,<2.7" +astroid = ">=2.8.0,<2.9" colorama = {version = "*", markers = "sys_platform == \"win32\""} isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.7" +platformdirs = ">=2.2.0" toml = ">=0.7.1" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} [[package]] name = "pyparsing" @@ -457,7 +471,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt [metadata] lock-version = "1.1" python-versions = "^3.6" -content-hash = "2997368a36d88fc670a42bd44abb3ae8065d0869c0fcd4ae63aab5ee9464baa0" +content-hash = "5ee93b78656e5bc815fc41056cd80448eac2f8cee62db11c140c7248ab8b2834" [metadata.files] appdirs = [ @@ -469,8 +483,8 @@ appdirs = [ {file = "aspy.yaml-1.3.0.tar.gz", hash = "sha256:e7c742382eff2caed61f87a39d13f99109088e5e93f04d76eb8d4b28aa143f45"}, ] astroid = [ - {file = "astroid-2.6.5-py3-none-any.whl", hash = "sha256:7b963d1c590d490f60d2973e57437115978d3a2529843f160b5003b721e1e925"}, - {file = "astroid-2.6.5.tar.gz", hash = "sha256:83e494b02d75d07d4e347b27c066fd791c0c74fc96c613d1ea3de0c82c48168f"}, + {file = "astroid-2.8.0-py3-none-any.whl", hash = "sha256:dcc06f6165f415220013801642bd6c9808a02967070919c4b746c6864c205471"}, + {file = "astroid-2.8.0.tar.gz", hash = "sha256:fe81f80c0b35264acb5653302ffbd935d394f1775c5e4487df745bf9c2442708"}, ] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, @@ -572,6 +586,10 @@ packaging = [ {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, ] +platformdirs = [ + {file = "platformdirs-2.3.0-py3-none-any.whl", hash = "sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"}, + {file = "platformdirs-2.3.0.tar.gz", hash = "sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f"}, +] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, @@ -585,8 +603,8 @@ py = [ {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, ] pylint = [ - {file = "pylint-2.9.6-py3-none-any.whl", hash = "sha256:2e1a0eb2e8ab41d6b5dbada87f066492bb1557b12b76c47c2ee8aa8a11186594"}, - {file = "pylint-2.9.6.tar.gz", hash = "sha256:8b838c8983ee1904b2de66cce9d0b96649a91901350e956d78f289c3bc87b48e"}, + {file = "pylint-2.11.1-py3-none-any.whl", hash = "sha256:0f358e221c45cbd4dad2a1e4b883e75d28acdcccd29d40c76eb72b307269b126"}, + {file = "pylint-2.11.1.tar.gz", hash = "sha256:2c9843fff1a88ca0ad98a256806c82c5a8f86086e7ccbdb93297d86c3f90c436"}, ] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, diff --git a/pyproject.toml b/pyproject.toml index 61c11ad..5569818 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "rfd" -version = "0.7.2" +version = "0.8.0" description = "view RedFlagDeals.com from the command line" authors = ["Dave Gallant "] license = "GPL-3.0-or-later" @@ -16,7 +16,7 @@ soupsieve = "<3.0" [tool.poetry.dev-dependencies] pre-commit = "1.21.0" -pylint = "^2.9.6" +pylint = "^2.11.1" pytest = ">=4.6.6" rope = "0.20.1" diff --git a/rfd/api.py b/rfd/api.py index 7db722f..961b4a4 100644 --- a/rfd/api.py +++ b/rfd/api.py @@ -27,7 +27,7 @@ def get_safe_per_page(limit): def create_user_map(users): """Create a map of user ids to usernames.""" - m = dict() + m = {} for user in users: m[user.get("user_id")] = user.get("username") return m @@ -47,12 +47,12 @@ def get_threads(forum_id, pages): try: for page in range(1, pages + 1): response = requests.get( - "{}/api/topics?forum_id={}&per_page=40&page={}".format( - API_BASE_URL, forum_id, page - ) + f"{API_BASE_URL}/api/topics?forum_id={forum_id}&per_page=40&page={page}" ) if response.status_code != 200: - raise Exception("When collecting threads, received a status code: %s" % response.status_code) + raise Exception( + f"When collecting threads, received a status code: {response.status_code}" + ) threads += response.json().get("topics") except JSONDecodeError as err: logging.error("Unable to decode threads. %s", err) @@ -76,16 +76,14 @@ def get_posts(post): raise ValueError() response = requests.get( - "{}/api/topics/{}/posts?per_page=40&page=1".format(API_BASE_URL, post_id) + f"{API_BASE_URL}/api/topics/{post_id}/posts?per_page=40&page=1" ) total_pages = response.json().get("pager").get("total_pages") for page in range(0, total_pages + 1): response = requests.get( - "{}/api/topics/{}/posts?per_page={}&page={}".format( - API_BASE_URL, post_id, 40, page - ) + f"{API_BASE_URL}/api/topics/{post_id}/posts?per_page=40&page={page}" ) users = create_user_map(response.json().get("users")) diff --git a/rfd/cli.py b/rfd/cli.py index 32f5685..5fd56eb 100644 --- a/rfd/cli.py +++ b/rfd/cli.py @@ -4,9 +4,10 @@ from __future__ import unicode_literals import logging import sys import click + try: from importlib import metadata -except ImportError: # for Python<3.8 +except ImportError: # for Python<3.8 import importlib_metadata as metadata from colorama import init from .api import get_threads, get_posts @@ -24,6 +25,7 @@ logging.getLogger().addHandler(logging.StreamHandler()) def get_version(): return "rfd v" + metadata.version("rfd") + def print_version(ctx, _, value): if not value or ctx.resilient_parsing: return @@ -91,7 +93,9 @@ def threads(forum_id, pages, sort_by): 74 \t shopping discussion 88 \t cell phones """ - _threads = sort_threads(parse_threads(get_threads(forum_id, pages)), sort_by=sort_by) + _threads = sort_threads( + parse_threads(get_threads(forum_id, pages)), sort_by=sort_by + ) click.echo_via_pager(generate_thread_output(_threads)) diff --git a/rfd/posts.py b/rfd/posts.py index 1dd8bb9..5cf19d4 100644 --- a/rfd/posts.py +++ b/rfd/posts.py @@ -3,19 +3,22 @@ import os from colorama import Fore, Style from .scores import get_vote_color + class Post: def __init__(self, body, score, user): self.body = body self.score = score self.user = user + def get_terminal_width(): _, columns = os.popen("stty size", "r").read().split() return int(columns) + def generate_posts_output(posts): output = "" - output += ("-" * get_terminal_width()) + output += "-" * get_terminal_width() for post in posts: output += ( " -" @@ -23,10 +26,10 @@ def generate_posts_output(posts): + Fore.RESET + post.body + Fore.YELLOW - + " ({})".format(post.user) + + f" ({post.user})" ) - output += (Style.RESET_ALL) + output += Style.RESET_ALL output += "\n" - output += ("-" * get_terminal_width()) + output += "-" * get_terminal_width() output += "\n" return output diff --git a/rfd/threads.py b/rfd/threads.py index 6ddb7a7..91656f4 100644 --- a/rfd/threads.py +++ b/rfd/threads.py @@ -3,7 +3,7 @@ from colorama import Fore, Style from . import API_BASE_URL from .scores import calculate_score, get_vote_color -# pylint: disable=old-style-class + class Thread: def __init__(self, title, dealer_name, score, url, views): self.dealer_name = dealer_name @@ -13,11 +13,11 @@ class Thread: self.views = views def __repr__(self): - return "Thread(%s)" % self.title + return f"Thread({self.title})" def build_web_path(slug): - return "{}{}".format(API_BASE_URL, slug) + return f"{API_BASE_URL}{slug}" def get_dealer(topic): @@ -88,12 +88,12 @@ def generate_thread_output(threads): + "." + get_vote_color(thread.score) + Fore.RESET - + "%s%s" % (dealer, thread.title) + + f"{dealer}{thread.title}" + Fore.LIGHTYELLOW_EX - + " (%d views)" % thread.views + + f" ({thread.views} views)" + Fore.RESET ) - output += Fore.BLUE + " {}".format(thread.url) + output += Fore.BLUE + f" {thread.url}" output += Style.RESET_ALL output += "\n\n" yield output