fix(fossil): narrow generic exception handlers in forum adapter - #961
Conversation
justinmclean
left a comment
There was a problem hiding this comment.
Findings
Blocking — narrowing to FossilError alone drops the "corrupt" half of what the handler promises (tools/fossil/src/magpie_fossil/forum.py:88, same at :137)
Issue #954 says explicitly: "Read what each try block can actually raise before narrowing." Working through the body:
run_fossil(...)raisesFossilErrorfor a missing binary and for a non-zero exit. Covered.parse_forum_artifact(art_text)is pure string handling and always returns all five keys, so neither it nor theparsed[...]lookups can raise. Nothing to cover.run_fossilalso callssubprocess.run(..., text=True), andclient.py:55converts onlyFileNotFoundError. When the artifact blob is not valid UTF-8, the decode happens insidesubprocess.runand raisesUnicodeDecodeError, which passes straight throughrun_fossiluncaught. I confirmed the mechanism:subprocess.run(text=True)on non-UTF-8 stdout raisesUnicodeDecodeError: 'utf-8' codec can't decode byte 0xff.
That is precisely the case the handler exists for. Its own message reads "skipped corrupt or missing forum post artifact". Before this change, except Exception caught the corrupt case and skipped one row. After it, a single corrupt blob aborts list_forum_threads entirely and the caller gets a traceback instead of a list, so one bad artifact takes out the whole forum listing.
Smallest correct fix, at both sites:
except (FossilError, UnicodeDecodeError) as exc:Major — the change ships with no test in either direction (tools/fossil/tests/test_fossil.py)
Issue #954's acceptance criteria include "An unexpected exception propagates". Nothing asserts that, and nothing asserted the old skip-and-warn behaviour either: test_list_forum_threads and test_read_forum_thread are both happy-path, with run_fossil mocked to return a well-formed manifest. So the entire behaviour this PR changes is currently unobserved by the suite, which is why pytest passing tells us nothing here.
Two small tests using the @patch("magpie_fossil.forum.run_fossil") decorator already in the file would cover it:
run_fossilraisesFossilErroron the second of three rows: assert the warning reaches stderr and the other two threads are still returned.run_fossilraises something genuinely unexpected, sayRuntimeError: assert it propagates.
Add the UnicodeDecodeError case to the first test once the handler names it.
This review was drafted by an AI-assisted tool and confirmed by a Magpie maintainer. After you've addressed the points above and pushed an update, a Magpie maintainer, a real person, will take the next look at the PR. The findings cite the project's review criteria; if you think one of them is mis-applied, please reply on the PR and a maintainer will weigh in.
…pt skipping and exception propagation
|
Thanks for the detailed review @justinmclean! I have updated the PR to address both points:
|
potiuk
left a comment
There was a problem hiding this comment.
Both of Justin's points are addressed, and I verified them rather than taking the description on trust.
Handlers. except (FossilError, UnicodeDecodeError) at forum.py:88 and :137 — exactly the smallest correct fix Justin identified. The UnicodeDecodeError path is real: run_fossil calls subprocess.run(..., text=True) and client.py converts only FileNotFoundError, so a non-UTF-8 artifact blob raises straight through. Without it, one corrupt blob would abort the whole forum listing instead of skipping one row — the opposite of what the handler's own message promises.
Tests. Five added, covering both call sites: FossilError skip, UnicodeDecodeError skip, and RuntimeError propagation.
I mutation-tested them, because a test that passes either way is worse than none:
- Revert the handlers to bare
except Exception→ both propagation tests fail withDID NOT RAISE RuntimeError. - Narrow them to
except FossilErroralone (the original mistake) → bothUnicodeDecodeErrortests fail with the decode error escaping.
So they genuinely pin the behaviour in both directions, which is what issue #954's acceptance criteria asked for. Suite is 21 green on the branch.
Nice work, @HeaTTap — the UnicodeDecodeError("utf-8", b"\xff", 0, 1, ...) construction in the fixtures is the right way to exercise that path without a real corrupt repo.
Both findings are addressed and verified, so dismissing this as stale rather than unanswered.
Handlers are now except (FossilError, UnicodeDecodeError) at forum.py:88 and :137 — the smallest correct fix you specified. Five tests added across both call sites.
I mutation-tested them rather than trusting a green run:
- handlers reverted to bare except Exception -> both propagation tests fail (DID NOT RAISE RuntimeError)
- handlers narrowed to except FossilError alone (the original mistake) -> both UnicodeDecodeError tests fail, decode error escaping
So they pin the behaviour in both directions, which is what #954's acceptance criteria asked for. Suite 21 green on the branch.
Dismissed by @potiuk so the PR can merge; reopen anything I have missed and I will revert.
Fixes #954
Narrowed generic
except Exceptionblocks intools/fossil/src/magpie_fossil/forum.pytoexcept FossilError, ensuring unexpected system exceptions are properly raised.