mirror of
https://github.com/aserper/masto-rss.git
synced 2025-12-17 05:15:25 +00:00
Fix linting errors: Remove unused imports and reformat with black
This commit is contained in:
1
bot.py
1
bot.py
@@ -1,7 +1,6 @@
|
||||
"""Mastodon RSS Bot - Core functionality"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import List, Optional, Set
|
||||
|
||||
35
main.py
35
main.py
@@ -3,7 +3,7 @@ import os
|
||||
import sys
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
from typing import List
|
||||
|
||||
from bot import MastodonRSSBot
|
||||
|
||||
@@ -11,7 +11,7 @@ from bot import MastodonRSSBot
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
handlers=[logging.StreamHandler(sys.stdout)]
|
||||
handlers=[logging.StreamHandler(sys.stdout)],
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -19,6 +19,7 @@ logger = logging.getLogger(__name__)
|
||||
@dataclass
|
||||
class Config:
|
||||
"""Configuration loaded from environment variables."""
|
||||
|
||||
instance_url: str
|
||||
client_id: str
|
||||
client_secret: str
|
||||
@@ -26,7 +27,9 @@ class Config:
|
||||
feed_urls: List[str] = field(default_factory=list)
|
||||
toot_visibility: str = "public"
|
||||
check_interval: int = 300
|
||||
state_file: Path = field(default_factory=lambda: Path("/state/processed_entries.txt"))
|
||||
state_file: Path = field(
|
||||
default_factory=lambda: Path("/state/processed_entries.txt")
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_env(cls) -> "Config":
|
||||
@@ -38,18 +41,22 @@ class Config:
|
||||
|
||||
if not all([instance_url, client_id, client_secret, access_token]):
|
||||
missing = [
|
||||
k for k, v in {
|
||||
k
|
||||
for k, v in {
|
||||
"MASTODON_INSTANCE_URL": instance_url,
|
||||
"MASTODON_CLIENT_ID": client_id,
|
||||
"MASTODON_CLIENT_SECRET": client_secret,
|
||||
"MASTODON_ACCESS_TOKEN": access_token
|
||||
}.items() if not v
|
||||
"MASTODON_ACCESS_TOKEN": access_token,
|
||||
}.items()
|
||||
if not v
|
||||
]
|
||||
raise ValueError(f"Missing required environment variables: {', '.join(missing)}")
|
||||
raise ValueError(
|
||||
f"Missing required environment variables: {', '.join(missing)}"
|
||||
)
|
||||
|
||||
# Parse feeds
|
||||
feed_urls = []
|
||||
|
||||
|
||||
# 1. Legacy single feed URL
|
||||
if os.environ.get("RSS_FEED_URL"):
|
||||
feed_urls.append(os.environ["RSS_FEED_URL"])
|
||||
@@ -83,17 +90,21 @@ class Config:
|
||||
unique_feed_urls = list(dict.fromkeys(feed_urls))
|
||||
|
||||
if not unique_feed_urls:
|
||||
raise ValueError("No RSS feeds configured. Please set RSS_FEED_URL, RSS_FEEDS, or FEEDS_FILE.")
|
||||
raise ValueError(
|
||||
"No RSS feeds configured. Please set RSS_FEED_URL, RSS_FEEDS, or FEEDS_FILE."
|
||||
)
|
||||
|
||||
return cls(
|
||||
instance_url=instance_url, # type: ignore # checked above
|
||||
client_id=client_id, # type: ignore
|
||||
client_secret=client_secret,# type: ignore
|
||||
client_id=client_id, # type: ignore
|
||||
client_secret=client_secret, # type: ignore
|
||||
access_token=access_token, # type: ignore
|
||||
feed_urls=unique_feed_urls,
|
||||
toot_visibility=os.environ.get("TOOT_VISIBILITY", "public"),
|
||||
check_interval=int(os.environ.get("CHECK_INTERVAL", "300")),
|
||||
state_file=Path(os.environ.get("PROCESSED_ENTRIES_FILE", "/state/processed_entries.txt"))
|
||||
state_file=Path(
|
||||
os.environ.get("PROCESSED_ENTRIES_FILE", "/state/processed_entries.txt")
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
||||
21
test_bot.py
21
test_bot.py
@@ -52,7 +52,7 @@ class TestMastodonRSSBot(unittest.TestCase):
|
||||
def test_save_processed_entries_error(self, mock_mastodon):
|
||||
"""Test error handling when saving processed entries fails"""
|
||||
bot = MastodonRSSBot(**self.test_config)
|
||||
|
||||
|
||||
# Mock Path.write_text to raise exception
|
||||
with patch.object(Path, "write_text", side_effect=Exception("Disk full")):
|
||||
# Should not raise exception
|
||||
@@ -70,17 +70,17 @@ class TestMastodonRSSBot(unittest.TestCase):
|
||||
feed = bot.parse_feed("https://example.com/feed.xml")
|
||||
|
||||
self.assertIsNotNone(feed)
|
||||
# We can't easily assert the log/print was called without mocking logging,
|
||||
# We can't easily assert the log/print was called without mocking logging,
|
||||
# but execution flow is covered.
|
||||
|
||||
@patch("bot.Mastodon")
|
||||
def test_run_keyboard_interrupt(self, mock_mastodon):
|
||||
"""Test clean exit on KeyboardInterrupt"""
|
||||
bot = MastodonRSSBot(**self.test_config)
|
||||
|
||||
|
||||
# Mock process_new_entries to raise KeyboardInterrupt
|
||||
bot.process_new_entries = Mock(side_effect=KeyboardInterrupt)
|
||||
|
||||
|
||||
# Should exit cleanly
|
||||
bot.run()
|
||||
bot.process_new_entries.assert_called_once()
|
||||
@@ -90,12 +90,14 @@ class TestMastodonRSSBot(unittest.TestCase):
|
||||
def test_run_exception_retry(self, mock_mastodon, mock_sleep):
|
||||
"""Test retry logic on exception in main loop"""
|
||||
bot = MastodonRSSBot(**self.test_config)
|
||||
|
||||
|
||||
# Raise exception once, then KeyboardInterrupt to exit loop
|
||||
bot.process_new_entries = Mock(side_effect=[Exception("Network Error"), KeyboardInterrupt])
|
||||
|
||||
bot.process_new_entries = Mock(
|
||||
side_effect=[Exception("Network Error"), KeyboardInterrupt]
|
||||
)
|
||||
|
||||
bot.run()
|
||||
|
||||
|
||||
self.assertEqual(bot.process_new_entries.call_count, 2)
|
||||
mock_sleep.assert_called_with(bot.check_interval)
|
||||
|
||||
@@ -107,6 +109,7 @@ class TestMainEntry(unittest.TestCase):
|
||||
def test_config_missing_vars(self):
|
||||
"""Test Config raises ValueError when env vars are missing"""
|
||||
from main import Config
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
Config.from_env()
|
||||
|
||||
@@ -123,6 +126,7 @@ class TestMainEntry(unittest.TestCase):
|
||||
def test_config_no_feeds(self):
|
||||
"""Test Config raises ValueError when no feeds are configured"""
|
||||
from main import Config
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
Config.from_env()
|
||||
|
||||
@@ -139,6 +143,7 @@ class TestMainEntry(unittest.TestCase):
|
||||
def test_config_feed_file_error(self):
|
||||
"""Test Config handles missing/bad feeds file gracefully (logs warning but continues check)"""
|
||||
from main import Config
|
||||
|
||||
# Should raise ValueError ultimately because no feeds are found,
|
||||
# but cover the file reading path
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
|
||||
Reference in New Issue
Block a user