Skip to content

Respect enabled=False on the direct-call path - #645

Merged
mergify[bot] merged 2 commits into
jd:mainfrom
mahirhir:fix/respect-enabled-false-in-direct-call
Aug 6, 2026
Merged

Respect enabled=False on the direct-call path#645
mergify[bot] merged 2 commits into
jd:mainfrom
mahirhir:fix/respect-enabled-false-in-direct-call

Conversation

@mahirhir

Copy link
Copy Markdown
Contributor

Retrying(enabled=False)(fn) and AsyncRetrying(enabled=False)(fn) ignore enabled=False on the direct-call path — they run the full retry loop and wrap the original exception in RetryError, instead of calling the function once and propagating its exception.

PR #643 added the enabled=False short-circuit to the iterator protocols (__iter__/__aiter__/__anext__) but the direct-call protocol (__call__) was left behind, since iter() itself never consults enabled. The fix adds the same short-circuit at the top of each __call__ (awaiting coroutine callables for the async path).

Verified both ways: old runs the function 5× and raises RetryError (sync and async); fixed calls once and raises the original ValueError, matching the iterator/decorator paths. 154 existing tests green; +4 regression tests (which fail on the unfixed code) → 158 passed.

mahirhir added 2 commits June 26, 2026 16:10
`Retrying.__call__` and `AsyncRetrying.__call__` ignored the `enabled`
flag: calling a controller created with `enabled=False` still ran the
full retry loop, so a failing function was retried and the original
exception was wrapped in a `RetryError`.

This makes the direct-call protocol consistent with the decorator
(`@retry(enabled=False)`) and the iterator protocols
(`__iter__`/`__aiter__`, fixed in jd#643): with `enabled=False` the
function is executed exactly once and any exception propagates
unchanged.
@mahirhir
mahirhir force-pushed the fix/respect-enabled-false-in-direct-call branch from 731b7c6 to 6b6acfb Compare June 28, 2026 13:06

@jd jd left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving — I verified the premise and the fix empirically against current main, and the merged result passes the full poe all (lint, mypy, 183 tests, docs).

The bug is real. On main, Retrying(enabled=False, stop=stop_after_attempt(5))(fails) calls the function 5 times, fires before/after on every attempt, and raises RetryError. With this PR: 1 call, no hooks, original ValueError. Same for AsyncRetrying, including the sync-callable-passed-to-AsyncRetrying case.

It is consistent with the paths that already got this right. wrapped_f (the decorator) and __iter__/__aiter__ both short-circuit the same way, and all three leave statistics as {} and skip the callbacks when disabled — I checked that the new path matches rather than inventing a third behaviour. Hoisting is_async above the check is the right call since the early return needs it.

The type: ignore codes in the async early return are correct and still load-bearing under the repo's current config — warn_unused_ignores is on, and mypy is clean.

Two follow-ups, neither blocking:

  1. TornadoRetrying.__call__ still ignores enabled=False. It is the one remaining direct-call path. Verified on this branch: TornadoRetrying(enabled=False, stop=stop_after_attempt(5)) runs the function 5 times and raises RetryError. Worth a separate PR (it needs a @gen.coroutine-shaped early return, so it is not a copy-paste of this one).
  2. No release note. The repo's contributing checklist asks for one, though #643 landed without one too, so this is a nit rather than something I would hold the PR for.

Thanks for the clear reproduction in the description — it matched exactly what I measured.

@mergify

mergify Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

This pull request spent 16 seconds in the queue, including 2 seconds running CI.

Required conditions to merge

@mergify
mergify Bot merged commit 26f719d into jd:main Aug 6, 2026
9 checks passed
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