Skip to content

Commit afc9ec3

Browse files
committed
feat: Stronger typing for validate_feed
1 parent 81cf71a commit afc9ec3

File tree

5 files changed

+27
-12
lines changed

5 files changed

+27
-12
lines changed

example/uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "django-rss-filter"
3-
version = "0.8.0"
3+
version = "0.9.0"
44
description = "Filter public RSS feeds, remove articles that contain certain keywords or categories."
55
authors = [
66
{name = "Kevin Renskers", email = "[email protected]"},

rssfilter/models.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ def clean(self):
3030
# Make sure we have a valid feed.
3131
# Let's assume it's valid if it's already in FeedCache.
3232
if not FeedCache.objects.filter(feed_url=self.feed_url).exists():
33-
valid, message = validate_feed(self.feed_url)
34-
if not valid:
35-
raise ValidationError({"feed_url": message})
33+
result = validate_feed(self.feed_url)
34+
if not result.valid:
35+
raise ValidationError({"feed_url": result.error})
3636

3737
def get_filtered_feed_body(self) -> str:
3838
five_mins_ago = timezone.now() - timedelta(seconds=RSS_FILTER_CACHE_SECONDS)

rssfilter/utils.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from dataclasses import dataclass
2+
from typing import Literal
3+
14
import feedparser
25
import httpx
36
from feedgen.feed import FeedGenerator
@@ -7,7 +10,19 @@
710
from . import USER_AGENT
811

912

10-
def validate_feed(feed_url: str) -> tuple[bool, str | FeedParserDict]:
13+
@dataclass
14+
class FeedValidationSuccess:
15+
valid: Literal[True]
16+
feed: FeedParserDict
17+
18+
19+
@dataclass
20+
class FeedValidationError:
21+
valid: Literal[False]
22+
error: str
23+
24+
25+
def validate_feed(feed_url: str) -> FeedValidationSuccess | FeedValidationError:
1126
try:
1227
# Fetch content using httpx rather than having feedparser do this,
1328
# since we can't set a timeout with feedparser. It also makes sure
@@ -18,14 +33,14 @@ def validate_feed(feed_url: str) -> tuple[bool, str | FeedParserDict]:
1833
feed = feedparser.parse(r.text)
1934
version = feed.get("version", "")
2035
if not version:
21-
return False, "This doesn't seem to be a valid RSS or Atom feed"
22-
return True, feed
36+
return FeedValidationError(False, "This doesn't seem to be a valid RSS or Atom feed")
37+
return FeedValidationSuccess(True, feed)
2338
except ValueError:
24-
return False, "This doesn't seem to be a valid RSS or Atom feed"
39+
return FeedValidationError(False, "This doesn't seem to be a valid RSS or Atom feed")
2540
except ConnectTimeout:
26-
return False, "Couldn't load the URL due to a connection timeout"
41+
return FeedValidationError(False, "Couldn't load the URL due to a connection timeout")
2742
except ConnectError:
28-
return False, "Couldn't load the URL due to a connection error"
43+
return FeedValidationError(False, "Couldn't load the URL due to a connection error")
2944

3045

3146
def filter_feed(feed_body: str, filtered_words: str, filtered_categories: str) -> str:

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)