Skip to content

Commit 238a7b3

Browse files
committed
initial implementation for replacing except-pass
1 parent 731c1e1 commit 238a7b3

8 files changed

Lines changed: 336 additions & 52 deletions

File tree

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ jobs:
116116
# new endpoint file because `pytest tests/` would also re-collect the
117117
# 178 unittest.TestCase subclasses already run in the step above —
118118
# ~2× the CI minutes for zero extra signal.
119-
run: python -m pytest tests/test_api_endpoints.py -v --tb=short
119+
run: python -m pytest tests/test_api_endpoints.py tests/test_parse_failure_logging.py -v --tb=short
120120

121121
# ── PyInstaller desktop build (Windows only, once per workflow) ────────
122122
# Closes #44. Builds the onedir bundle and smoke-tests --help so the

api/logs.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,12 @@ def get_logs():
4848
try:
4949
bubble = json.loads(row["value"])
5050
chat_map.setdefault(chat_id, []).append(bubble)
51-
except Exception:
52-
pass
51+
except Exception as e:
52+
_logger.warning(
53+
"Failed to decode bubble row %s: %s",
54+
row["key"],
55+
e,
56+
)
5357

5458
for chat_id, bubbles in chat_map.items():
5559
bubbles = [b for b in bubbles if isinstance(b, dict)]
@@ -90,8 +94,12 @@ def get_logs():
9094
with open(wj_path, "r", encoding="utf-8") as f:
9195
wd = json.load(f)
9296
workspace_folder = wd.get("folder")
93-
except Exception:
94-
pass
97+
except Exception as e:
98+
_logger.warning(
99+
"Failed to read workspace.json for %s: %s",
100+
name,
101+
e,
102+
)
95103

96104
try:
97105
# closing() guarantees .close() on scope exit (issue #17).
@@ -130,10 +138,18 @@ def get_logs():
130138
"type": "composer",
131139
"messageCount": len(c.get("conversation") or []),
132140
})
133-
except Exception:
134-
pass
135-
except Exception:
136-
pass
141+
except Exception as e:
142+
_logger.warning(
143+
"Failed to read logs from workspace %s: %s",
144+
name,
145+
e,
146+
)
147+
except Exception as e:
148+
_logger.warning(
149+
"Failed to iterate workspaces under %s: %s",
150+
workspace_path,
151+
e,
152+
)
137153

138154
logs.sort(key=lambda log: log.get("timestamp") or 0, reverse=True)
139155
return jsonify({"logs": logs})

api/search.py

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,18 @@ def search():
114114
fn = parts[-1] if parts else None
115115
if fn:
116116
ws_id_to_name[name] = _url_unquote(fn)
117-
except Exception:
118-
pass
119-
except Exception:
120-
pass
117+
except Exception as e:
118+
_logger.warning(
119+
"Failed to read workspace.json for %s: %s",
120+
name,
121+
e,
122+
)
123+
except Exception as e:
124+
_logger.warning(
125+
"Failed to list workspace entries under %s: %s",
126+
workspace_path,
127+
e,
128+
)
121129

122130
# Build composer → workspace mapping
123131
composer_id_to_ws = {}
@@ -139,8 +147,12 @@ def search():
139147
cid = c.get("composerId") if isinstance(c, dict) else None
140148
if cid:
141149
composer_id_to_ws[cid] = entry["name"]
142-
except Exception:
143-
pass
150+
except Exception as e:
151+
_logger.warning(
152+
"Failed to load composer mapping from workspace %s: %s",
153+
entry["name"],
154+
e,
155+
)
144156

145157
# Load bubble text for searching
146158
bubble_map = {}
@@ -261,8 +273,12 @@ def search():
261273
"matchingText": matching_text,
262274
"type": "composer",
263275
})
264-
except Exception:
265-
pass
276+
except Exception as e:
277+
_logger.warning(
278+
"Failed to process Composer from composerData:%s during search: %s",
279+
composer_id,
280+
e,
281+
)
266282

267283
except Exception:
268284
_logger.exception("Error searching global storage")
@@ -288,8 +304,12 @@ def search():
288304
with open(wj_path, "r", encoding="utf-8") as f:
289305
wd = json.load(f)
290306
workspace_folder = wd.get("folder")
291-
except Exception:
292-
pass
307+
except Exception as e:
308+
_logger.warning(
309+
"Failed to read workspace.json for %s: %s",
310+
name,
311+
e,
312+
)
293313
workspace_name = _workspace_display_name_from_folder(workspace_folder, fallback=name)
294314

295315
# try/finally guarantees .close() on every exit path (issue #17).
@@ -362,13 +382,21 @@ def search():
362382
"type": "chat",
363383
})
364384

365-
except Exception:
366-
pass
385+
except Exception as e:
386+
_logger.warning(
387+
"Failed to search legacy workspace %s: %s",
388+
name,
389+
e,
390+
)
367391
finally:
368392
if conn is not None:
369393
conn.close()
370-
except Exception:
371-
pass
394+
except Exception as e:
395+
_logger.warning(
396+
"Failed to iterate legacy workspaces under %s: %s",
397+
workspace_path,
398+
e,
399+
)
372400

373401
# ---------------------------------------------------------------
374402
# Search Cursor CLI sessions (only for type=all)
@@ -386,7 +414,12 @@ def search():
386414

387415
try:
388416
messages = traverse_blobs(session["db_path"])
389-
except Exception:
417+
except Exception as e:
418+
_logger.warning(
419+
"Failed to traverse CLI session blobs for %s: %s",
420+
session_id,
421+
e,
422+
)
390423
continue
391424

392425
bubbles = messages_to_bubbles(messages, created_ms)

api/workspaces.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,12 @@ def get_workspace(workspace_id):
117117
inferred = _infer_workspace_name_from_context(workspace_path, workspace_id)
118118
if inferred:
119119
workspace_name = inferred
120-
except Exception:
120+
except Exception as e:
121+
_logger.warning(
122+
"Failed to read workspace.json for %s: %s",
123+
workspace_id,
124+
e,
125+
)
121126
inferred = _infer_workspace_name_from_context(workspace_path, workspace_id)
122127
if inferred:
123128
workspace_name = inferred

services/workspace_listing.py

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
from __future__ import annotations
22

33
import json
4+
import logging
45
import os
56
import sqlite3
67
from datetime import datetime, timezone
78

9+
_logger = logging.getLogger(__name__)
10+
811
from utils.cli_chat_reader import list_cli_projects
912
from utils.exclusion_rules import build_searchable_text, is_excluded_by_rules
1013
from utils.path_helpers import (
@@ -14,6 +17,7 @@
1417
)
1518
from utils.workspace_descriptor import read_json_file
1619
from utils.workspace_path import get_cli_chats_path
20+
from models import Composer, SchemaError
1721
from services.workspace_db import (
1822
_build_composer_id_to_workspace_id,
1923
_collect_invalid_workspace_ids,
@@ -72,7 +76,32 @@ def _safe_fetchall(query: str, params: tuple = ()) -> list:
7276
for row in composer_rows:
7377
cid = row["key"].split(":")[1]
7478
try:
75-
cd = json.loads(row["value"])
79+
parsed = json.loads(row["value"])
80+
except (json.JSONDecodeError, TypeError, ValueError) as e:
81+
_logger.warning(
82+
"Failed to decode Composer from composerData:%s: %s",
83+
cid,
84+
e,
85+
)
86+
continue
87+
if not isinstance(parsed, dict):
88+
_logger.warning(
89+
"Failed to parse Composer from composerData:%s: expected object, got %s",
90+
cid,
91+
type(parsed).__name__,
92+
)
93+
continue
94+
try:
95+
composer = Composer.from_dict(parsed, composer_id=cid)
96+
except SchemaError as e:
97+
_logger.warning(
98+
"Failed to parse Composer from composerData:%s: %s",
99+
cid,
100+
e,
101+
)
102+
continue
103+
cd = composer.raw
104+
try:
76105
pid = _determine_project_for_conversation(
77106
cd, cid, project_layouts_map,
78107
project_name_map, workspace_path_map,
@@ -98,10 +127,14 @@ def _safe_fetchall(query: str, params: tuple = ()) -> list:
98127
"lastUpdatedAt": to_epoch_ms(cd.get("lastUpdatedAt")) or to_epoch_ms(cd.get("createdAt")) or 0,
99128
"createdAt": to_epoch_ms(cd.get("createdAt")) or 0,
100129
})
101-
except Exception:
102-
pass
103-
except Exception:
104-
pass
130+
except Exception as e:
131+
_logger.warning(
132+
"Failed to process Composer from composerData:%s: %s",
133+
cid,
134+
e,
135+
)
136+
except Exception as e:
137+
_logger.error("Failed to load composer rows from global storage: %s", e)
105138

106139
# Group workspace entries by normalized folder path
107140
folder_to_entries: dict[str, list] = {}
@@ -114,8 +147,12 @@ def _safe_fetchall(query: str, params: tuple = ()) -> list:
114147
first_folder = folders[0] if folders else None
115148
if first_folder:
116149
norm_folder = normalize_file_path(first_folder)
117-
except Exception:
118-
pass
150+
except Exception as e:
151+
_logger.warning(
152+
"Failed to read workspace.json for %s: %s",
153+
entry["name"],
154+
e,
155+
)
119156
if not norm_folder:
120157
norm_folder = entry["name"] # fallback to workspace ID
121158
entry_folder_map[entry["name"]] = norm_folder
@@ -139,7 +176,12 @@ def _safe_fetchall(query: str, params: tuple = ()) -> list:
139176
for e in group
140177
if os.path.isfile(os.path.join(workspace_path, e["name"], "state.vscdb"))
141178
)
142-
except Exception:
179+
except Exception as e:
180+
_logger.warning(
181+
"Failed to resolve mtime for workspace folder %s: %s",
182+
norm_folder,
183+
e,
184+
)
143185
mtime = 0
144186

145187
workspace_name = _get_workspace_display_name(workspace_path, primary["name"])
@@ -238,7 +280,7 @@ def _safe_fetchall(query: str, params: tuple = ()) -> list:
238280
"source": "cli",
239281
})
240282
except Exception as e:
241-
print(f"Failed to load CLI projects: {e}")
283+
_logger.warning("Failed to load CLI projects: %s", e)
242284

243285
projects.sort(key=lambda p: p["lastModified"], reverse=True)
244286
return projects

0 commit comments

Comments
 (0)