When implementing backup-and-restore logic around a block of code (e.g. backing up poetry.lock before a subprocess and restoring it afterwards), always use a context manager instead of separate _backup and _restore helper functions with a try/finally block.
Why it matters: A context manager encapsulates the setup/teardown lifecycle into a single construct, making the calling code cleaner and eliminating the risk of forgetting the finally block or mismatching the backup/restore calls. It also makes the intent clearer at the call site (with _frozen_poetry_lock(path): vs. manual backup + try/finally + restore).
Where observed: src/usethis/_backend/poetry/call.py — the initial implementation used _backup_poetry_lock and _restore_poetry_lock as separate helpers, which was refactored into a _frozen_poetry_lock context manager in PR #1774.
Lesson for agents: When writing code that needs to preserve and restore state around a block of operations, reach for @contextmanager as the first-choice pattern.
When implementing backup-and-restore logic around a block of code (e.g. backing up
poetry.lockbefore a subprocess and restoring it afterwards), always use a context manager instead of separate_backupand_restorehelper functions with atry/finallyblock.Why it matters: A context manager encapsulates the setup/teardown lifecycle into a single construct, making the calling code cleaner and eliminating the risk of forgetting the
finallyblock or mismatching the backup/restore calls. It also makes the intent clearer at the call site (with _frozen_poetry_lock(path):vs. manual backup + try/finally + restore).Where observed:
src/usethis/_backend/poetry/call.py— the initial implementation used_backup_poetry_lockand_restore_poetry_lockas separate helpers, which was refactored into a_frozen_poetry_lockcontext manager in PR #1774.Lesson for agents: When writing code that needs to preserve and restore state around a block of operations, reach for
@contextmanageras the first-choice pattern.