Update to newest version of Reader, fix webhooks and fix tests
This commit is contained in:
@ -1,18 +1,24 @@
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from contextlib import closing
|
||||
from pathlib import Path
|
||||
from shutil import copyfile
|
||||
|
||||
import sys
|
||||
import time
|
||||
import typer
|
||||
from dhooks import Webhook
|
||||
from discord_webhook import DiscordWebhook
|
||||
from reader import FeedExistsError, make_reader
|
||||
from reader._plugins import global_metadata
|
||||
from reader.exceptions import FeedMetadataNotFoundError
|
||||
|
||||
# Add logging
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
)
|
||||
|
||||
app = typer.Typer()
|
||||
app_dir = typer.get_app_dir("discord-rss-bot")
|
||||
logging.debug(f"App dir: {app_dir}")
|
||||
|
||||
# Create the data directory if it doesn't exist
|
||||
os.makedirs(app_dir, exist_ok=True)
|
||||
@ -20,6 +26,11 @@ os.makedirs(app_dir, exist_ok=True)
|
||||
# Store the database file in the data directory
|
||||
db_name = os.getenv("DATABASE_NAME", "db.sqlite")
|
||||
db_file: Path = Path(os.path.join(app_dir, db_name))
|
||||
logging.debug(f"Database file: {db_file}")
|
||||
|
||||
# Convert Path to string
|
||||
db_file_str: str = str(db_file)
|
||||
logging.debug(f"Database file as string: {db_file_str}")
|
||||
|
||||
|
||||
@app.command()
|
||||
@ -32,13 +43,12 @@ def add(
|
||||
Args:
|
||||
feed_url (str): The url of the feed to add
|
||||
notify_discord (bool): Whether to send a message to Discord when
|
||||
the feed is added
|
||||
the feed is added.
|
||||
"""
|
||||
with closing(make_reader(db_file, plugins=[global_metadata.init_reader])) as reader:
|
||||
with closing(make_reader(db_file_str)) as reader:
|
||||
try:
|
||||
# Add the feed to the database
|
||||
reader.add_feed(feed_url)
|
||||
|
||||
except FeedExistsError:
|
||||
# If the feed already exists, print a message
|
||||
typer.echo(f"{feed_url} already exists")
|
||||
@ -50,25 +60,35 @@ def add(
|
||||
# Mark the feed as read
|
||||
entries = reader.get_entries(feed=feed_url, read=False)
|
||||
for entry in entries:
|
||||
logging.debug(f"Marking {entry.title} as read")
|
||||
reader.mark_entry_as_read(entry)
|
||||
|
||||
if notify_discord:
|
||||
# Send a message to Discord
|
||||
webhook_url = reader.get_global_metadata_item("webhook")
|
||||
hook = Webhook(webhook_url)
|
||||
|
||||
hook.send(
|
||||
webhook_msg = (
|
||||
f"discord-rss-bot: {feed_url} added to the database.\n"
|
||||
f"You now have {reader.get_feed_counts()} feeds."
|
||||
)
|
||||
webhook_url = reader.get_tag((), "webhook")
|
||||
logging.debug(f"Webhook URL: {webhook_url}")
|
||||
|
||||
if not webhook_url:
|
||||
typer.echo("No webhook URL found in the database.")
|
||||
sys.exit()
|
||||
|
||||
webhook = DiscordWebhook(url=str(webhook_url), content=webhook_msg, rate_limit_retry=True)
|
||||
|
||||
response = webhook.execute()
|
||||
if response.status_code != 204:
|
||||
typer.echo(f"Error sending message to Discord - {response.status_code}\n{response.text}")
|
||||
|
||||
typer.echo(f"{feed_url} added")
|
||||
|
||||
|
||||
@app.command()
|
||||
def stats() -> None:
|
||||
"""Print the number of feeds and entries in the database"""
|
||||
with closing(make_reader(db_file, plugins=[global_metadata.init_reader])) as reader:
|
||||
"""Print the amount feeds and entries in the database"""
|
||||
with closing(make_reader(db_file_str)) as reader:
|
||||
feed_count = reader.get_feed_counts()
|
||||
entry_count = reader.get_entry_counts()
|
||||
|
||||
@ -95,7 +115,7 @@ def stats() -> None:
|
||||
@app.command()
|
||||
def check() -> None:
|
||||
"""Check new entries for every feed"""
|
||||
with closing(make_reader(db_file, plugins=[global_metadata.init_reader])) as reader:
|
||||
with closing(make_reader(db_file_str)) as reader:
|
||||
# Update the feeds
|
||||
reader.update_feeds()
|
||||
|
||||
@ -105,12 +125,20 @@ def check() -> None:
|
||||
for entry in entries:
|
||||
# Mark the entry as read
|
||||
reader.mark_entry_as_read(entry)
|
||||
logging.debug(f"Marking {entry.title} as read")
|
||||
|
||||
webhook_url = reader.get_global_metadata_item("webhook")
|
||||
hook = Webhook(webhook_url)
|
||||
webhook_url = reader.get_tag((), "webhook")
|
||||
logging.debug(f"Webhook URL: {webhook_url}")
|
||||
if not webhook_url:
|
||||
typer.echo("No webhook URL found in the database.")
|
||||
sys.exit()
|
||||
|
||||
# Send the entries to Discord
|
||||
hook.send(f":robot: :mega: {entry.title}\n{entry.link}")
|
||||
webhook = DiscordWebhook(url=str(webhook_url), content=f":robot: :mega: {entry.title}\n{entry.link}",
|
||||
rate_limit_retry=True)
|
||||
|
||||
response = webhook.execute()
|
||||
if response.status_code != 204:
|
||||
typer.echo(f"Error sending message to Discord - {response.status_code}\n{response.text}")
|
||||
|
||||
|
||||
@app.command()
|
||||
@ -134,34 +162,43 @@ def delete() -> None:
|
||||
feed_dict = {}
|
||||
feed_number = 0
|
||||
message = ""
|
||||
with closing(make_reader(db_file)) as reader:
|
||||
with closing(make_reader(db_file_str)) as reader:
|
||||
for feed in reader.get_feeds():
|
||||
logging.debug(f"Feed: {feed}")
|
||||
feed_number += 1
|
||||
feed_dict[feed_number] = feed.object_id
|
||||
logging.debug(f"Feed number: {feed_number}")
|
||||
logging.debug(f"Feed URL: {feed.url}")
|
||||
feed_dict[str(feed_number)] = feed.url
|
||||
logging.debug(f"Feed dict: {feed_dict}")
|
||||
message += f"{feed_number}: {feed.title}\n"
|
||||
|
||||
typer.echo(message)
|
||||
|
||||
feed_to_delete: int = typer.prompt("What feed do you want to remove?")
|
||||
feed_id = feed_dict.get(feed_to_delete)
|
||||
feed_to_delete: str = typer.prompt("What feed do you want to remove?")
|
||||
feed_url = feed_dict.get(str(feed_to_delete))
|
||||
|
||||
if not feed_url:
|
||||
typer.echo("Invalid feed number")
|
||||
sys.exit()
|
||||
|
||||
logging.debug(f"Feed URL: {feed_url}")
|
||||
confirm_delete = typer.confirm(
|
||||
f"Are you sure you want to delete {feed_id}?",
|
||||
f"Are you sure you want to delete {feed_url}?",
|
||||
)
|
||||
|
||||
if not confirm_delete:
|
||||
typer.echo("Not deleting")
|
||||
raise typer.Abort()
|
||||
|
||||
reader.delete_feed(feed_id)
|
||||
reader.delete_feed(feed_url)
|
||||
|
||||
typer.echo(f"{feed_id} deleted")
|
||||
typer.echo(f"{feed_url} deleted")
|
||||
|
||||
|
||||
@app.command()
|
||||
def webhook_add(webhook_url: str) -> None:
|
||||
"""Add a webhook to the database"""
|
||||
with closing(make_reader(db_file, plugins=[global_metadata.init_reader])) as reader:
|
||||
reader.set_global_metadata_item("webhook", webhook_url)
|
||||
with closing(make_reader(db_file_str)) as reader:
|
||||
reader.set_tag((), "webhook", webhook_url)
|
||||
typer.echo(f"Webhook set to {webhook_url}")
|
||||
|
||||
|
||||
@ -169,12 +206,13 @@ def webhook_add(webhook_url: str) -> None:
|
||||
def webhook_get() -> None:
|
||||
"""Get the webhook url"""
|
||||
# TODO: Add name to output
|
||||
with closing(make_reader(db_file, plugins=[global_metadata.init_reader])) as reader:
|
||||
with closing(make_reader(db_file_str)) as reader:
|
||||
try:
|
||||
webhook_url = reader.get_global_metadata_item("webhook")
|
||||
webhook_url = reader.get_tag((), "webhook")
|
||||
typer.echo(f"Webhook: {webhook_url}")
|
||||
except FeedMetadataNotFoundError:
|
||||
except Exception as e:
|
||||
typer.echo("No webhook was found. Use `webhook add` to add one.")
|
||||
typer.echo(f"Error: {e}\nPlease report this error to the developer.")
|
||||
sys.exit()
|
||||
|
||||
|
||||
|
337
poetry.lock
generated
337
poetry.lock
generated
@ -1,3 +1,17 @@
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "22.1.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[package.extras]
|
||||
dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"]
|
||||
docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"]
|
||||
tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"]
|
||||
tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"]
|
||||
|
||||
[[package]]
|
||||
name = "beautifulsoup4"
|
||||
version = "4.11.1"
|
||||
@ -15,45 +29,56 @@ lxml = ["lxml"]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2021.10.8"
|
||||
version = "2022.9.24"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
name = "charset-normalizer"
|
||||
version = "2.0.12"
|
||||
version = "2.1.1"
|
||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5.0"
|
||||
python-versions = ">=3.6.0"
|
||||
|
||||
[package.extras]
|
||||
unicode_backport = ["unicodedata2"]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.2"
|
||||
version = "8.1.3"
|
||||
description = "Composable command line interface toolkit"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
colorama = { version = "*", markers = "platform_system == \"Windows\"" }
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.4"
|
||||
version = "0.4.5"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "commonmark"
|
||||
version = "0.9.1"
|
||||
description = "Python parser for the CommonMark Markdown spec"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.extras]
|
||||
test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "discord-webhook"
|
||||
version = "0.16.0"
|
||||
version = "0.17.0"
|
||||
description = "execute discord webhooks"
|
||||
category = "main"
|
||||
optional = false
|
||||
@ -67,7 +92,7 @@ async = ["httpx (>=0.20.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "feedparser"
|
||||
version = "6.0.8"
|
||||
version = "6.0.10"
|
||||
description = "Universal feed parser, handles RSS 0.9x, RSS 1.0, RSS 2.0, CDF, Atom 0.3, and Atom 1.0 feeds"
|
||||
category = "main"
|
||||
optional = false
|
||||
@ -78,12 +103,20 @@ sgmllib3k = "*"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.3"
|
||||
version = "3.4"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "1.1.1"
|
||||
description = "iniconfig: brain-dead simple config-ini parsing"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "iso8601"
|
||||
version = "1.0.2"
|
||||
@ -93,46 +126,133 @@ optional = false
|
||||
python-versions = ">=3.6.2,<4.0"
|
||||
|
||||
[[package]]
|
||||
name = "reader"
|
||||
version = "2.12"
|
||||
description = "A Python feed reader library."
|
||||
name = "packaging"
|
||||
version = "21.3"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.0.0"
|
||||
description = "plugin and hook calling mechanisms for python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "tox"]
|
||||
testing = ["pytest", "pytest-benchmark"]
|
||||
|
||||
[[package]]
|
||||
name = "py"
|
||||
version = "1.11.0"
|
||||
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "Pygments"
|
||||
version = "2.13.0"
|
||||
description = "Pygments is a syntax highlighting package written in Python."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.extras]
|
||||
plugins = ["importlib-metadata"]
|
||||
|
||||
[[package]]
|
||||
name = "pyparsing"
|
||||
version = "3.0.9"
|
||||
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6.8"
|
||||
|
||||
[package.extras]
|
||||
diagrams = ["jinja2", "railroad-diagrams"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "7.1.3"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
beautifulsoup4 = ">=4.5"
|
||||
feedparser = ">=6"
|
||||
iso8601 = "*"
|
||||
requests = ">=2.18"
|
||||
typing-extensions = "*"
|
||||
attrs = ">=19.2.0"
|
||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
iniconfig = "*"
|
||||
packaging = "*"
|
||||
pluggy = ">=0.12,<2.0"
|
||||
py = ">=1.8.2"
|
||||
tomli = ">=1.0.0"
|
||||
|
||||
[package.extras]
|
||||
app = ["flask (>=0.10)", "humanize", "pyyaml"]
|
||||
cli = ["click (>=7)", "pyyaml"]
|
||||
dev = ["tox", "pre-commit", "build", "twine"]
|
||||
docs = ["sphinx", "sphinx-rtd-theme (>=1.0,<2.0)", "click (>=7)", "sphinx-click", "sphinx-issues", "sphinx-hoverxref", "sphinxcontrib-log-cabinet"]
|
||||
readtime = ["readtime"]
|
||||
tests = ["pytest (>=4)", "pytest-randomly", "pytest-subtests", "flaky", "coverage", "pytest-cov", "requests-mock", "requests-wsgi-adapter", "html5lib", "werkzeug", "types-requests", "mypy", "mechanicalsoup", "lxml"]
|
||||
unstable-plugins = ["requests", "mutagen", "beautifulsoup4", "blinker (>=1.4)"]
|
||||
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
name = "reader"
|
||||
version = "3.2"
|
||||
description = "A Python feed reader library."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
|
||||
[package.dependencies]
|
||||
beautifulsoup4 = ">=4.5"
|
||||
feedparser = ">=6"
|
||||
iso8601 = ">=1"
|
||||
requests = ">=2.18"
|
||||
typing-extensions = ">=4"
|
||||
|
||||
[package.extras]
|
||||
app = ["PyYAML", "flask (>=0.10)", "humanize"]
|
||||
cli = ["PyYAML", "click (>=7)"]
|
||||
dev = ["build", "pre-commit", "reader[app,cli,docs,tests,unstable-plugins]", "tox", "twine"]
|
||||
docs = ["click (>=7)", "sphinx", "sphinx-click", "sphinx-hoverxref", "sphinx-issues", "sphinx-rtd-theme (>=1.0,<2.0)", "sphinxcontrib-log-cabinet"]
|
||||
tests = ["coverage", "flaky", "html5lib", "lxml", "mechanicalsoup", "mypy", "pytest (>=4)", "pytest-cov", "pytest-randomly", "pytest-subtests", "requests-mock", "requests-wsgi-adapter", "types-requests", "werkzeug"]
|
||||
unstable-plugins = ["Jinja2 (>=3)", "beautifulsoup4", "blinker (>=1.4)", "mutagen", "requests", "tweepy"]
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.27.1"
|
||||
version = "2.28.1"
|
||||
description = "Python HTTP for Humans."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||
python-versions = ">=3.7, <4"
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2017.4.17"
|
||||
charset-normalizer = { version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\"" }
|
||||
idna = { version = ">=2.5,<4", markers = "python_version >= \"3\"" }
|
||||
charset-normalizer = ">=2,<3"
|
||||
idna = ">=2.5,<4"
|
||||
urllib3 = ">=1.21.1,<1.27"
|
||||
|
||||
[package.extras]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
|
||||
use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||
use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "12.5.1"
|
||||
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6.3,<4.0.0"
|
||||
|
||||
[package.dependencies]
|
||||
commonmark = ">=0.9.0,<0.10.0"
|
||||
pygments = ">=2.6.0,<3.0.0"
|
||||
|
||||
[package.extras]
|
||||
jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "sgmllib3k"
|
||||
@ -144,23 +264,31 @@ python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "shellingham"
|
||||
version = "1.4.0"
|
||||
version = "1.5.0"
|
||||
description = "Tool to Detect Surrounding Shell"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0,!=3.1,!=3.2,!=3.3,>=2.6"
|
||||
python-versions = ">=3.4"
|
||||
|
||||
[[package]]
|
||||
name = "soupsieve"
|
||||
version = "2.3.2"
|
||||
version = "2.3.2.post1"
|
||||
description = "A modern CSS selector implementation for Beautiful Soup."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.0.1"
|
||||
description = "A lil' TOML parser"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "typer"
|
||||
version = "0.4.1"
|
||||
version = "0.6.1"
|
||||
description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
|
||||
category = "main"
|
||||
optional = false
|
||||
@ -168,106 +296,151 @@ python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
click = ">=7.1.1,<9.0.0"
|
||||
colorama = { version = ">=0.4.3,<0.5.0", optional = true, markers = "extra == \"all\"" }
|
||||
shellingham = { version = ">=1.3.0,<2.0.0", optional = true, markers = "extra == \"all\"" }
|
||||
colorama = {version = ">=0.4.3,<0.5.0", optional = true, markers = "extra == \"all\""}
|
||||
rich = {version = ">=10.11.0,<13.0.0", optional = true, markers = "extra == \"all\""}
|
||||
shellingham = {version = ">=1.3.0,<2.0.0", optional = true, markers = "extra == \"all\""}
|
||||
|
||||
[package.extras]
|
||||
all = ["colorama (>=0.4.3,<0.5.0)", "shellingham (>=1.3.0,<2.0.0)"]
|
||||
dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)"]
|
||||
doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "mdx-include (>=1.4.1,<2.0.0)"]
|
||||
test = ["shellingham (>=1.3.0,<2.0.0)", "pytest (>=4.4.0,<5.4.0)", "pytest-cov (>=2.10.0,<3.0.0)", "coverage (>=5.2,<6.0)", "pytest-xdist (>=1.32.0,<2.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "mypy (==0.910)", "black (>=22.3.0,<23.0.0)", "isort (>=5.0.6,<6.0.0)"]
|
||||
all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<13.0.0)", "shellingham (>=1.3.0,<2.0.0)"]
|
||||
dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"]
|
||||
doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)"]
|
||||
test = ["black (>=22.3.0,<23.0.0)", "coverage (>=5.2,<6.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<5.4.0)", "pytest-cov (>=2.10.0,<3.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<2.0.0)", "rich (>=10.11.0,<13.0.0)", "shellingham (>=1.3.0,<2.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.1.1"
|
||||
description = "Backported and Experimental Type Hints for Python 3.6+"
|
||||
version = "4.3.0"
|
||||
description = "Backported and Experimental Type Hints for Python 3.7+"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "1.26.9"
|
||||
version = "1.26.12"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4"
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"]
|
||||
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
|
||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
|
||||
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.9"
|
||||
content-hash = "53b5b383ba400929d442e09fecdcb8178308ba3783cb70426a0be5f730d7aaf0"
|
||||
content-hash = "ac76e6768f510ad14b7f105a76b34c70ab2bb0b3a0aa99d1a875dff9944b7f3b"
|
||||
|
||||
[metadata.files]
|
||||
attrs = [
|
||||
{file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"},
|
||||
{file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"},
|
||||
]
|
||||
beautifulsoup4 = [
|
||||
{ file = "beautifulsoup4-4.11.1-py3-none-any.whl", hash = "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30" },
|
||||
{ file = "beautifulsoup4-4.11.1.tar.gz", hash = "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693" },
|
||||
{file = "beautifulsoup4-4.11.1-py3-none-any.whl", hash = "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30"},
|
||||
{file = "beautifulsoup4-4.11.1.tar.gz", hash = "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693"},
|
||||
]
|
||||
certifi = [
|
||||
{ file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" },
|
||||
{ file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872" },
|
||||
{file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"},
|
||||
{file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"},
|
||||
]
|
||||
charset-normalizer = [
|
||||
{ file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597" },
|
||||
{ file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" },
|
||||
{file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"},
|
||||
{file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"},
|
||||
]
|
||||
click = [
|
||||
{ file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e" },
|
||||
{ file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72" },
|
||||
{file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
|
||||
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
|
||||
]
|
||||
colorama = [
|
||||
{ file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2" },
|
||||
{ file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b" },
|
||||
{file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
|
||||
{file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
|
||||
]
|
||||
commonmark = [
|
||||
{file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"},
|
||||
{file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"},
|
||||
]
|
||||
discord-webhook = [
|
||||
{ file = "discord-webhook-0.16.0.tar.gz", hash = "sha256:6318c2bfab20e35927503cd32f49a449b0aba61f5a848e415fdf5e94e361870c" },
|
||||
{ file = "discord_webhook-0.16.0-py3-none-any.whl", hash = "sha256:b142eadc0588c161840a21496052a97c8d72b44457cf3bd3cf4dc0a6f9b5f50a" },
|
||||
{file = "discord-webhook-0.17.0.tar.gz", hash = "sha256:bb47e5fc83f73614d7b2a3764b84359b52c96a94aadf3302bc3c067dd21b43cc"},
|
||||
{file = "discord_webhook-0.17.0-py3-none-any.whl", hash = "sha256:d869849c4834f928f5c22597dc7600b1a30f9e797d1aeb1d4196711a243d9a73"},
|
||||
]
|
||||
feedparser = [
|
||||
{ file = "feedparser-6.0.8-py3-none-any.whl", hash = "sha256:1b7f57841d9cf85074deb316ed2c795091a238adb79846bc46dccdaf80f9c59a" },
|
||||
{ file = "feedparser-6.0.8.tar.gz", hash = "sha256:5ce0410a05ab248c8c7cfca3a0ea2203968ee9ff4486067379af4827a59f9661" },
|
||||
{file = "feedparser-6.0.10-py3-none-any.whl", hash = "sha256:79c257d526d13b944e965f6095700587f27388e50ea16fd245babe4dfae7024f"},
|
||||
{file = "feedparser-6.0.10.tar.gz", hash = "sha256:27da485f4637ce7163cdeab13a80312b93b7d0c1b775bef4a47629a3110bca51"},
|
||||
]
|
||||
idna = [
|
||||
{ file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff" },
|
||||
{ file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" },
|
||||
{file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
|
||||
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
|
||||
]
|
||||
iniconfig = [
|
||||
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
|
||||
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
|
||||
]
|
||||
iso8601 = [
|
||||
{ file = "iso8601-1.0.2-py3-none-any.whl", hash = "sha256:d7bc01b1c2a43b259570bb307f057abc578786ea734ba2b87b836c5efc5bd443" },
|
||||
{ file = "iso8601-1.0.2.tar.gz", hash = "sha256:27f503220e6845d9db954fb212b95b0362d8b7e6c1b2326a87061c3de93594b1" },
|
||||
{file = "iso8601-1.0.2-py3-none-any.whl", hash = "sha256:d7bc01b1c2a43b259570bb307f057abc578786ea734ba2b87b836c5efc5bd443"},
|
||||
{file = "iso8601-1.0.2.tar.gz", hash = "sha256:27f503220e6845d9db954fb212b95b0362d8b7e6c1b2326a87061c3de93594b1"},
|
||||
]
|
||||
packaging = [
|
||||
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
|
||||
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
|
||||
]
|
||||
pluggy = [
|
||||
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
|
||||
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
|
||||
]
|
||||
py = [
|
||||
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
|
||||
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
|
||||
]
|
||||
Pygments = [
|
||||
{file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"},
|
||||
{file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"},
|
||||
]
|
||||
pyparsing = [
|
||||
{file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
|
||||
{file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
|
||||
]
|
||||
pytest = [
|
||||
{file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"},
|
||||
{file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"},
|
||||
]
|
||||
reader = [
|
||||
{ file = "reader-2.12-py3-none-any.whl", hash = "sha256:e5e776266e6563fd06c6ab0c6fb01e7b66f74c38066fe8f577d2dd889fc10543" },
|
||||
{ file = "reader-2.12.tar.gz", hash = "sha256:f36a2d579c14074fc6ef6e9322de88aaa006debd5edcb08ee42e7ed32661416a" },
|
||||
{file = "reader-3.2-py3-none-any.whl", hash = "sha256:5c50f44e782cc0bff6a0b25134839ccd1e83ceb87b3ff879130dd3febc44d377"},
|
||||
{file = "reader-3.2.tar.gz", hash = "sha256:e065a52e40657701d8a7543f2a1de4556b18daf83d58680e9e1d1c5b2016a245"},
|
||||
]
|
||||
requests = [
|
||||
{ file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d" },
|
||||
{ file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61" },
|
||||
{file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"},
|
||||
{file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"},
|
||||
]
|
||||
rich = [
|
||||
{file = "rich-12.5.1-py3-none-any.whl", hash = "sha256:2eb4e6894cde1e017976d2975ac210ef515d7548bc595ba20e195fb9628acdeb"},
|
||||
{file = "rich-12.5.1.tar.gz", hash = "sha256:63a5c5ce3673d3d5fbbf23cd87e11ab84b6b451436f1b7f19ec54b6bc36ed7ca"},
|
||||
]
|
||||
sgmllib3k = [
|
||||
{ file = "sgmllib3k-1.0.0.tar.gz", hash = "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9" },
|
||||
{file = "sgmllib3k-1.0.0.tar.gz", hash = "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9"},
|
||||
]
|
||||
shellingham = [
|
||||
{ file = "shellingham-1.4.0-py2.py3-none-any.whl", hash = "sha256:536b67a0697f2e4af32ab176c00a50ac2899c5a05e0d8e2dadac8e58888283f9" },
|
||||
{ file = "shellingham-1.4.0.tar.gz", hash = "sha256:4855c2458d6904829bd34c299f11fdeed7cfefbf8a2c522e4caea6cd76b3171e" },
|
||||
{file = "shellingham-1.5.0-py2.py3-none-any.whl", hash = "sha256:a8f02ba61b69baaa13facdba62908ca8690a94b8119b69f5ec5873ea85f7391b"},
|
||||
{file = "shellingham-1.5.0.tar.gz", hash = "sha256:72fb7f5c63103ca2cb91b23dee0c71fe8ad6fbfd46418ef17dbe40db51592dad"},
|
||||
]
|
||||
soupsieve = [
|
||||
{ file = "soupsieve-2.3.2-py3-none-any.whl", hash = "sha256:a714129d3021ec17ce5be346b1007300558b378332c289a1a20e7d4de6ff18a5" },
|
||||
{ file = "soupsieve-2.3.2.tar.gz", hash = "sha256:0bcc6d7432153063e3df09c3ac9442af3eba488715bfcad6a4c38ccb2a523124" },
|
||||
{file = "soupsieve-2.3.2.post1-py3-none-any.whl", hash = "sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759"},
|
||||
{file = "soupsieve-2.3.2.post1.tar.gz", hash = "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d"},
|
||||
]
|
||||
tomli = [
|
||||
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||
]
|
||||
typer = [
|
||||
{ file = "typer-0.4.1-py3-none-any.whl", hash = "sha256:e8467f0ebac0c81366c2168d6ad9f888efdfb6d4e1d3d5b4a004f46fa444b5c3" },
|
||||
{ file = "typer-0.4.1.tar.gz", hash = "sha256:5646aef0d936b2c761a10393f0384ee6b5c7fe0bb3e5cd710b17134ca1d99cff" },
|
||||
{file = "typer-0.6.1-py3-none-any.whl", hash = "sha256:54b19e5df18654070a82f8c2aa1da456a4ac16a2a83e6dcd9f170e291c56338e"},
|
||||
{file = "typer-0.6.1.tar.gz", hash = "sha256:2d5720a5e63f73eaf31edaa15f6ab87f35f0690f8ca233017d7d23d743a91d73"},
|
||||
]
|
||||
typing-extensions = [
|
||||
{ file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2" },
|
||||
{ file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42" },
|
||||
{file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"},
|
||||
{file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"},
|
||||
]
|
||||
urllib3 = [
|
||||
{ file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14" },
|
||||
{ file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" },
|
||||
{file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"},
|
||||
{file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"},
|
||||
]
|
||||
|
@ -6,9 +6,12 @@ authors = ["Joakim Hellsén <tlovinator@gmail.com>"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
reader = "^2.12"
|
||||
typer = { extras = ["all"], version = "^0.4.1" }
|
||||
discord-webhook = "^0.16.0"
|
||||
reader = "^3.2"
|
||||
typer = { extras = ["all"], version = "^0.6.1" }
|
||||
discord-webhook = "^0.17.0"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
pytest = "^7.1.3"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
|
@ -22,6 +22,9 @@ def test_backup():
|
||||
# Where we store backups
|
||||
backup_dir = os.path.join(app_dir, "backup")
|
||||
|
||||
# Make sure the backup directory exists
|
||||
os.makedirs(backup_dir, exist_ok=True)
|
||||
|
||||
# Check how many files in the backup directory
|
||||
files_before = len(os.listdir(backup_dir))
|
||||
|
||||
|
Reference in New Issue
Block a user