Repository navigation
fix(vendor): pin except BaseException and correct a false docstring clause - #876
Conversation
|
Adjudicating the pylint disagreement, since I published the original claim and the worker measured against it. The worker reported that removing the pragma does reintroduce So R1720 does not fire on this |
|
NEEDS CHANGES on
That is exactly the So: restore Items 1 and 2, confirmed: the new One honest limitation, not blocking: if a |
…lause GitHub issue #875, a follow-up to #872/#873 (merged as 6877210). - Pin pcapkit.vendor.__main__._snapshot_and_restore's `except BaseException:` itself, not just its effect. Narrowing it to `except Exception:` left the existing suite fully green, because nothing had raised anything BaseException-but-not-Exception during a run. Added a test whose stub raises KeyboardInterrupt after the destination has already been truncated (via the same print()-patch technique the other failure tests use); it asserts the content is restored byte-for-byte, that no backup file survives in the directory, and that the KeyboardInterrupt itself still propagates out of run() rather than being converted into a plain False return. - Corrected a false clause in _snapshot_and_restore's own docstring (pcapkit/vendor/__main__.py). It claimed a crawler whose _dest_path cannot be resolved without instance state "goes on to fail loudly anyway" once Vendor.__init__ calls the same method -- true of the first trigger listed (a crawler outside the real pcapkit.vendor tree, which fails the identical way whether or not the snapshot ran) but false of the second: an instance-method _dest_path raises TypeError on the classmethod-style call this function makes, but resolves fine on the bound instance call inside __init__, so that crawler actually runs unprotected and succeeds silently -- run() returns True, the file is replaced, nothing warns that no snapshot was ever taken. The clause is narrowed to the first trigger and the second is now stated plainly, matching what the test module's own docstring already said correctly. - The `# pylint: disable=no-else-raise` pragma at _snapshot_and_restore's `try:` line is kept, not dropped. Re-measured with the Makefile's own PYLINT_FLAGS (what CI actually runs): R1720 does fire on this try/except/else without the pragma (9.87 -> 9.74), because pylint 4 extends no-else-raise to a try/except whose except ends in raise. The structure it flags is deliberate -- the comment at :153-163 already explains why the else: is not a style default pylint would pick -- so the finding is suppressed rather than the structure changed. Verified: tests/vendor/test_vendor_snapshot_restore_unit.py (4 methods) and tests/vendor/test_vendor_exit_code_unit.py (5 methods), 9/9 together, under plain unittest. The new test_a_keyboard_interrupt_still_restores_and_propagates method passes on this code (content and directory listing restored, the KeyboardInterrupt still propagates). Mutated `except BaseException:` to `except Exception:` at its exact line (content of that line asserted before mutating, since `os.replace(backup, const_file)` also appears in prose elsewhere in the same file and a string-index mutation would otherwise silently hit that instead): the method then fails on its content assertion ('' != 'GOOD CONTENT\n'); a direct follow-up check confirmed the predicted orphaned backup file ('.const.py.<random>.bak') left in the directory afterwards. pylint $(PYLINT_FLAGS) pcapkit/vendor/__main__.py, pragma present: no R1720, 9.87/10 (only W1203, pre-existing). Pragma absent (checked and reverted, not shipped): R1720 at the try: line, 9.74/10.
0331e2f to
f302eaf
Compare
|
GOOD TO GO on The worker re-measured under the real Everything in the |
Please follow the guide below
make pylint,make mypy,make isort)make testpasses, and a test case covers the changedocs/source/changelog/and regeneratedCHANGELOG.md, if the change is user-visible -- N/A, changelog centralised in docs(changelog): shared 1.5.0 changelog — long-lived, merges last (#610, #616, #617, #618, #620) #657What is the purpose of your pull request?
fix— corrects a defectDescription of your pull request and other information
Closes #875. Three follow-ups from #873's review that arrived after it merged as
687721091. No behaviour in the merged code was wrong; one invariant was unpinned and two pieces of prose/lint were inaccurate.1.
except BaseException:in_snapshot_and_restoreis now pinned. Mutating it toexcept Exception:previously lefttests/vendor/test_vendor_snapshot_restore_unit.pyfully green (run=3 failures=0 errors=0), while the measured consequence of aKeyboardInterruptmid-crawl under that mutant is a truncated const file and an orphaned.const.py.*.bakinsidepcapkit/const/. The newtest_a_keyboard_interrupt_still_restores_and_propagatesasserts all three halves of the invariant — content restored byte-for-byte, no.baksurviving, and theKeyboardInterruptstill propagating rather than being converted into aFalsereturn. It discriminates: real coderun=4 failures=0 errors=0; against theexcept Exception:mutantrun=4 failures=1, failing'' != 'GOOD CONTENT\n', with the predicted['.const.py.<random>.bak', 'const.py']left behind.2. A false clause in
_snapshot_and_restore's docstring is corrected. It claimed a crawler whose_dest_pathcannot be resolved "goes on to fail loudly anyway onceVendor.__init__calls the same_dest_pathitself". That holds for one of its two enumerated triggers and not the other: an instance-method_dest_pathraisesTypeErroron the class call this function makes, so the snapshot is skipped, but the instance call inside__init__bindsselfand resolves fine — so the target runs unprotected and succeeds silently (run()→True, content replaced, nothing warns). Measured with a constructed instance-method-only stub.test_vendor_snapshot_restore_unit.py's own module docstring already described this correctly, so the two no longer disagree.3. The
# pylint: disable=no-else-raisepragma is KEPT. This was going to be a third fix, on the belief that R1720 never applies totry/except/else. That was wrong, and the measurement that appeared to support it was a message-control artefact:--disable=all --enable=no-else-raisedoes not re-enable the check, where--enable=Rdoes. Under theMakefile's ownPYLINT_FLAGS— what CI runs — pylint 4.0.8 does flag it:The
else:it objects to is deliberate and the comment at:153-163explains why: it is what makes the cleanup unreachable from theexcept, and deleting theraisethat would otherwise be load-bearing is a mutation the suite must catch. So the suppression stays.Deliberately out of scope: deleting
os.close(fd)survives as an untested fd leak (harmless here — the path still exists andcopy2reopens it), and swapping theelse:back to an unindented statement while keepingraisealso survives, correctly, since the two forms are semantically identical and no test can distinguish them.One commit on top of
687721091.tests/vendor/test_vendor_snapshot_restore_unit.pyisrun=4 failures=0 errors=0andtests/vendor/test_vendor_exit_code_unit.pyisrun=5 failures=0 errors=0, both underPYTHONSAFEPATH=1with the editable finders evicted andpcapkit.__file__asserted against the tree under test.