Skip to content

Conversation

@TTsangSC
Copy link
Collaborator

Just noticed that I made the same mistake in #323, #332, and #339, where @contextlib.contextmanager is used to wrap generator functions to construct context managers: the yield statement and the subsequent cleanup code wasn't wrapped in a tryfinally block, so the cleanup is eschewed if any exception occurred inside the with block/decorated function.

This PR fixes the bug in three functions:

  • kernprof.py::_restore_list() (used by main())
  • line_profiler/autoprofile/autoprofile.py::run.<locals>.restore_dict()
  • tests/test_line_profiler.py::check_timings()

One test is added to verify that the old behavior is problematic and is fixed by the PR:

  • tests/test_kernprof.py::test_kernprof_sys_restoration()

Sorry for any inconvenience caused.

TTsangSC added 3 commits May 11, 2025 02:28
line_profiler/autoprofile/autoprofile.py::run()
kernprof.py::main()
tests/test_line_profiler.py::check_timings()
    Fixed bug in `@contextlib.contextmanager`s where the cleanup code is
    not called if an error occurred inside the `with` block
@TTsangSC
Copy link
Collaborator Author

@Erotemic looks like your initial hunch was right on the money, I did mess the context managers up...

@TTsangSC TTsangSC changed the title @contextlib.contextmanager fix FIX: fixed cleanup code in @contextlib.contextmanager May 11, 2025
@codecov
Copy link

codecov bot commented May 11, 2025

Codecov Report

Attention: Patch coverage is 76.92308% with 3 lines in your changes missing coverage. Please review.

Project coverage is 63.78%. Comparing base (53a3846) to head (7988790).
Report is 9 commits behind head on main.

Files with missing lines Patch % Lines
line_profiler/autoprofile/autoprofile.py 76.92% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #340      +/-   ##
==========================================
+ Coverage   63.63%   63.78%   +0.14%     
==========================================
  Files          13       13              
  Lines        1034     1041       +7     
  Branches      229      228       -1     
==========================================
+ Hits          658      664       +6     
- Misses        315      316       +1     
  Partials       61       61              
Files with missing lines Coverage Δ
line_profiler/autoprofile/autoprofile.py 93.61% <76.92%> (-1.39%) ⬇️

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3537a50...7988790. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Erotemic
Copy link
Member

Can we just change these to class based context managers with __enter__ and __exit__? I find those much easier to reason about. No need to try/except/finally just handle cleanup in the __exit__ function.

@TTsangSC
Copy link
Collaborator Author

TTsangSC commented May 11, 2025

Will do.

IMO class-based CMs may add a bit of boilerplate, but maybe the pros (clarity) outweigh the cons here, considering that I just footgunned myself here with the alternative... anyway, will push in a moment, and then we can review which is better for the codebase.

kernprof.py::_restore_list()
line_profiler/autoprofile/autoprofile.py::run().<locals>.restore_dict
tests/test_line_profiler.py::check_timings
    Refactored to use classes instead of `@contextlib.contextmanager`

tests/test_kernprof.py::test_kernprof_sys_restoration()
    Extended to also check for the restoration of `sys.modules`

tests/test_line_profiler.py::check_timings
    Fixed on-exit assertion, which was always true regardless of the
    timings because it was written `assert (cond, msg)` instead of
    `assert cond, (msg)`
@TTsangSC
Copy link
Collaborator Author

Somehow CI keeps failing on MacOS with error 429 (b8dab90: https://github.com/pyutils/line_profiler/actions/runs/14977439218/job/42074090570, 7988790: https://github.com/pyutils/line_profiler/actions/runs/14977545152/job/42074530015)... seems to be a rate-limiting issue, probably because I pushed the two commits in quick succession...

@Erotemic Erotemic merged commit 1ea11bb into pyutils:main May 13, 2025
69 of 70 checks passed
@Erotemic
Copy link
Member

Reran the CI, and it worked. Everything else looks good. Merging.

@TTsangSC
Copy link
Collaborator Author

Cheers!

@TTsangSC TTsangSC deleted the ctx-fix branch May 14, 2025 12:55
TTsangSC added a commit to TTsangSC/line_profiler that referenced this pull request May 19, 2025
tests/test_explicit_profile.py::enter_tmpdir
    Now explicitly defined as a class, instead of using
    `@contextlib.contextmanager` (see pyutils#340)
TTsangSC added a commit to TTsangSC/line_profiler that referenced this pull request May 20, 2025
tests/test_explicit_profile.py::enter_tmpdir
    Now explicitly defined as a class, instead of using
    `@contextlib.contextmanager` (see pyutils#340)
TTsangSC added a commit to TTsangSC/line_profiler that referenced this pull request May 24, 2025
tests/test_explicit_profile.py::enter_tmpdir
    Now explicitly defined as a class, instead of using
    `@contextlib.contextmanager` (see pyutils#340)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants