Repository navigation
Fix abuse of return in a with test block #85
Description
As of 0.15.1, the contents of a with test block are implicitly lifted into a function. This in itself is fine; it is documented behavior, and arguably the simplest way to achieve what the macro needs to do.
The problem is that to declare the expression whose value should be checked to decide the result of the test, the syntax is currently return expr. This is effectively a keyword hijack — in the spirit of pytest's assert rewriting — where a standard Python construct is repurposed to mean something else inside a specific block. Not very pythonic. It conflicts with the established meaning of return and will confuse code analyzers and human readers alike.
Plan
Step 1 — 2.2.0 (non-breaking)
Add an expr macro to declare the tested expression, so the code reads more like standard Python. Name needs some thought:
returns[]— closest to intent, but will confuse humans as to why there is a separatereturnsvs. the standardreturn.result[],results_in[],evaluates_into[]— semantically slightly off; we want to declare a check, not a result.check[]— checkmate in t(h)ree? Probably the best so far.- Whatever the final name, it should be compact (preferably one short-ish word) while making the intent blindingly obvious.
During 2.2.0, using return expr inside a with test block continues to work, but emits a DeprecationWarning suggesting the new macro.
Step 2 — 3.0.0 (breaking)
Let return inside a with test block have its usual Python meaning (return from the enclosing function). unpythonic aims to be as pythonic as possible; undoing the keyword hijack — not banning return — is the point.
This likely means the with test: body can no longer be implicitly lifted to a function (or the lift has to transparently propagate return out to the enclosing function). Implementation details TBD — tracked here because the user-visible end state is clear even if the mechanism needs design work.
Scope note
Local variables assigned inside with test: would still be test-local under the current implementation (scope boundary from the implicit lift), which is acceptable precedent — comprehensions and generator expressions do the same, as do unpythonic's continuations. If a variable needs to be visible in the parent scope, use a box (or nonlocal / global as appropriate).
Activity
testingtools: add `expect[]`, deprecate `return` in `with test:` (#85 …
TODO_DEFERRED: rename `testing_testingtools.py`, relocate its demo
Technologicat commentedon May 5, 2026
Step 1 shipped in 2.2.0 (commit `7034add`, master).
Summary of what landed:
Naming choice: tried `returns[]`, `result[]`, `evaluates_into[]`, `check[]` per the ticket's draft list — `expect[]` reads most cleanly at the use site (`expect[x == 42]` parses naturally as English) and avoids the `returns`/`return` collision.
Step 2 (3.0.0): un-hijack `return` — still open. Re-milestoning this issue to 3.0.0; the ticket already documents the full plan, so keeping it as a single issue from start to finish.
— Claude (Opus 4.7)
briefs: update 2.2.0-remaining-issues for next-session handoff
testing: rename testing_testingtools.py → selftest_testingtools.py
Release 2.2.0 "Hail Eris"