Skip to content

Commit 0c8ebb7

Browse files
EstrellaXDclaude
andcommitted
fix(error-handling): replace bare except clauses with specific exceptions
- qb_downloader.py: catch httpx network errors in logout() and rename_file() - user.py: log exception details when querying users table fails - download_client.py: log exception when category creation fails - title_parser.py: catch specific exceptions (ValueError, AttributeError, TypeError) instead of broad Exception in raw_parser() Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent d6e89f6 commit 0c8ebb7

4 files changed

Lines changed: 61 additions & 26 deletions

File tree

backend/src/module/database/user.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,15 @@ def add_default_user(self):
7373
try:
7474
result = self.session.exec(statement)
7575
users = list(result.all())
76-
except Exception:
76+
except Exception as e:
77+
# Table may not exist yet during initial setup
78+
logger.debug(
79+
f"[Database] Could not query users table (may not exist yet): {e}"
80+
)
7781
users = []
7882
if len(users) != 0:
7983
return
8084
user = User(username="admin", password=get_password_hash("adminadmin"))
8185
self.session.add(user)
8286
self.session.commit()
87+
logger.info("[Database] Created default admin user")

backend/src/module/downloader/client/qb_downloader.py

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ def _url(self, endpoint: str) -> str:
2626
async def auth(self, retry=3):
2727
times = 0
2828
timeout = httpx.Timeout(connect=3.1, read=10.0, write=10.0, pool=10.0)
29-
self._client = httpx.AsyncClient(
30-
timeout=timeout, verify=self.ssl
31-
)
29+
self._client = httpx.AsyncClient(timeout=timeout, verify=self.ssl)
3230
while times < retry:
3331
try:
3432
resp = await self._client.post(
@@ -61,8 +59,12 @@ async def logout(self):
6159
if self._client:
6260
try:
6361
await self._client.post(self._url("auth/logout"))
64-
except Exception:
65-
pass
62+
except (
63+
httpx.ConnectError,
64+
httpx.RequestError,
65+
httpx.TimeoutException,
66+
) as e:
67+
logger.debug(f"[Downloader] Logout request failed (non-critical): {e}")
6668
await self._client.aclose()
6769
self._client = None
6870

@@ -114,7 +116,9 @@ async def torrents_files(self, torrent_hash: str):
114116
)
115117
return resp.json()
116118

117-
async def add_torrents(self, torrent_urls, torrent_files, save_path, category, tags=None):
119+
async def add_torrents(
120+
self, torrent_urls, torrent_files, save_path, category, tags=None
121+
):
118122
data = {
119123
"savepath": save_path,
120124
"category": category,
@@ -133,9 +137,17 @@ async def add_torrents(self, torrent_urls, torrent_files, save_path, category, t
133137
if torrent_files:
134138
if isinstance(torrent_files, list):
135139
for i, f in enumerate(torrent_files):
136-
files[f"torrents_{i}"] = (f"torrent_{i}.torrent", f, "application/x-bittorrent")
140+
files[f"torrents_{i}"] = (
141+
f"torrent_{i}.torrent",
142+
f,
143+
"application/x-bittorrent",
144+
)
137145
else:
138-
files["torrents"] = ("torrent.torrent", torrent_files, "application/x-bittorrent")
146+
files["torrents"] = (
147+
"torrent.torrent",
148+
torrent_files,
149+
"application/x-bittorrent",
150+
)
139151

140152
max_retries = 3
141153
for attempt in range(max_retries):
@@ -153,14 +165,14 @@ async def add_torrents(self, torrent_urls, torrent_files, save_path, category, t
153165
)
154166
await asyncio.sleep(2)
155167
else:
156-
logger.error(f"[Downloader] Failed to add torrent after {max_retries} attempts: {e}")
168+
logger.error(
169+
f"[Downloader] Failed to add torrent after {max_retries} attempts: {e}"
170+
)
157171
raise
158172

159173
async def get_torrents_by_tag(self, tag: str) -> list[dict]:
160174
"""Get all torrents with a specific tag."""
161-
resp = await self._client.get(
162-
self._url("torrents/info"), params={"tag": tag}
163-
)
175+
resp = await self._client.get(self._url("torrents/info"), params={"tag": tag})
164176
return resp.json()
165177

166178
async def torrents_delete(self, hash, delete_files: bool = True):
@@ -191,7 +203,8 @@ async def torrents_rename_file(self, torrent_hash, old_path, new_path) -> bool:
191203
logger.debug(f"Conflict409Error: {old_path} >> {new_path}")
192204
return False
193205
return resp.status_code == 200
194-
except Exception:
206+
except (httpx.ConnectError, httpx.RequestError, httpx.TimeoutException) as e:
207+
logger.warning(f"[Downloader] Failed to rename file {old_path}: {e}")
195208
return False
196209

197210
async def rss_add_feed(self, url, item_path):
@@ -216,6 +229,7 @@ async def rss_get_feeds(self):
216229

217230
async def rss_set_rule(self, rule_name, rule_def):
218231
import json
232+
219233
await self._client.post(
220234
self._url("rss/setRule"),
221235
data={"ruleName": rule_name, "ruleDef": json.dumps(rule_def)},

backend/src/module/downloader/download_client.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,13 @@ async def init_downloader(self):
7070
"rss_refresh_interval": 30,
7171
}
7272
await self.client.prefs_init(prefs=prefs)
73+
# Category creation may fail if it already exists (HTTP 409) or network issues
7374
try:
7475
await self.client.add_category("BangumiCollection")
75-
except Exception:
76-
logger.debug("[Downloader] Cannot add new category, maybe already exists.")
76+
except Exception as e:
77+
logger.debug(
78+
f"[Downloader] Could not add category (may already exist): {e}"
79+
)
7780
if settings.downloader.path == "":
7881
prefs = await self.client.get_app_prefs()
7982
settings.downloader.path = self._join_path(prefs["save_path"], "Bangumi")
@@ -107,7 +110,9 @@ async def set_rules(self, bangumi_info: list[Bangumi]):
107110
await asyncio.gather(*[self.set_rule(info) for info in bangumi_info])
108111
logger.debug("[Downloader] Finished.")
109112

110-
async def get_torrent_info(self, category="Bangumi", status_filter="completed", tag=None):
113+
async def get_torrent_info(
114+
self, category="Bangumi", status_filter="completed", tag=None
115+
):
111116
return await self.client.torrents_info(
112117
status_filter=status_filter, category=category, tag=tag
113118
)
@@ -137,7 +142,9 @@ async def add_torrent(self, torrent: Torrent | list, bangumi: Bangumi) -> bool:
137142
async with RequestContent() as req:
138143
if isinstance(torrent, list):
139144
if len(torrent) == 0:
140-
logger.debug(f"[Downloader] No torrent found: {bangumi.official_title}")
145+
logger.debug(
146+
f"[Downloader] No torrent found: {bangumi.official_title}"
147+
)
141148
return False
142149
if "magnet" in torrent[0].url:
143150
torrent_url = [t.url for t in torrent]
@@ -149,7 +156,9 @@ async def add_torrent(self, torrent: Torrent | list, bangumi: Bangumi) -> bool:
149156
# Filter out None values (failed fetches)
150157
torrent_file = [f for f in torrent_file if f is not None]
151158
if not torrent_file:
152-
logger.warning(f"[Downloader] Failed to fetch torrent files for: {bangumi.official_title}")
159+
logger.warning(
160+
f"[Downloader] Failed to fetch torrent files for: {bangumi.official_title}"
161+
)
153162
return False
154163
torrent_url = None
155164
else:
@@ -159,7 +168,9 @@ async def add_torrent(self, torrent: Torrent | list, bangumi: Bangumi) -> bool:
159168
else:
160169
torrent_file = await req.get_content(torrent.url)
161170
if torrent_file is None:
162-
logger.warning(f"[Downloader] Failed to fetch torrent file for: {bangumi.official_title}")
171+
logger.warning(
172+
f"[Downloader] Failed to fetch torrent file for: {bangumi.official_title}"
173+
)
163174
return False
164175
torrent_url = None
165176
# Create tag with bangumi_id for offset lookup during rename
@@ -175,10 +186,14 @@ async def add_torrent(self, torrent: Torrent | list, bangumi: Bangumi) -> bool:
175186
logger.debug(f"[Downloader] Add torrent: {bangumi.official_title}")
176187
return True
177188
else:
178-
logger.debug(f"[Downloader] Torrent added before: {bangumi.official_title}")
189+
logger.debug(
190+
f"[Downloader] Torrent added before: {bangumi.official_title}"
191+
)
179192
return False
180193
except Exception as e:
181-
logger.error(f"[Downloader] Failed to add torrent for {bangumi.official_title}: {e}")
194+
logger.error(
195+
f"[Downloader] Failed to add torrent for {bangumi.official_title}: {e}"
196+
)
182197
return False
183198

184199
async def move_torrent(self, hashes, location):

backend/src/module/parser/title_parser.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ async def tmdb_parser(title: str, season: int, language: str):
4444

4545
@staticmethod
4646
async def tmdb_poster_parser(bangumi: Bangumi):
47-
tmdb_info = await tmdb_parser(bangumi.official_title, settings.rss_parser.language)
47+
tmdb_info = await tmdb_parser(
48+
bangumi.official_title, settings.rss_parser.language
49+
)
4850
if tmdb_info:
4951
logger.debug(f"TMDB Matched, official title is {tmdb_info.title}")
5052
bangumi.poster_link = tmdb_info.poster_link
@@ -98,9 +100,8 @@ def raw_parser(raw: str) -> Bangumi | None:
98100
offset=0,
99101
filter=",".join(settings.rss_parser.filter),
100102
)
101-
except Exception as e:
102-
logger.debug(e)
103-
logger.warning(f"Cannot parse {raw}.")
103+
except (ValueError, AttributeError, TypeError) as e:
104+
logger.warning(f"Cannot parse '{raw}': {type(e).__name__}: {e}")
104105
return None
105106

106107
@staticmethod

0 commit comments

Comments
 (0)