Open
Conversation
* start_time == outcome_timestamp is possible * logging.Formatter uses explicitly hard-coded `\n` newlines (as opposed to using the platform-specific os.linesep)
...rather than sometimes allowing a default return of `None` Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: Slava Skvortsov <kondor1995@mail.ru>
* Fix iscoroutinefunction check (inspect & asyncio) * Add real async wrap & preserve retry attributes * Adjust to pep8 * Add test to ensure retryable_coroutine attributes * Fix `blank line contains whitespace` pep8 error
* chore: add missing noqa statements * docs: fix autoinstanceattribute
chore: add support for Python 3.9
* Copy whole internal state when retry_with (#233) Both `retry_error_cls` and `retry_error_callback` were missing from the copy, resulting in a copy that presents a different behavior than the original function. * Apply review feedback - define `_first_set` only once - get away with unittest - use pytest.raises
This should make sure we don't forget to put a release note before merging a PR. Related to #284
ci(mergify): force release notes to be present
Tweak Mergify config
* Make logger more compatible * Add release note * Fix black formatting * Ignore D402 error in flake8 * Update PR Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
* Add retry_except_exception_type Fixes #256 * Apply suggestions from code review Co-authored-by: Julien Danjou <julien@danjou.info> * rename 'except' to 'if not' * fix test * rename again Co-authored-by: Julien Danjou <julien@danjou.info>
Drop support for deprecated Pythons
- Use `black` for code formatting and validate using `black --check`. Code compatibility: py26-py39. - Enforce maximal line length to 120 symbols
Use black instead of "flake8-black" on CI.
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
- Pin runner to ubuntu-24.04 for reproducibility (matches CI) - Drop contents:write permission (only id-token:write needed for PyPI trusted publishing) Change-Id: I62d46b341d351e3576d3a1e37bc203949c368c1d
On Python 3.11+, Self is available in the standard typing module. Only fall back to typing_extensions for Python 3.10 (under TYPE_CHECKING only, so no runtime dependency added). Change-Id: I3e39dfbf6ab99b6005026315ff7f070b0910a9dc Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Tornado 4.x and 5.x are long EOL. Tornado 6.0 was released in March 2019 and is the minimum version that supports Python 3.10+ (our minimum). This aligns the declared floor with reality since older versions cannot install on supported Python versions anyway. Change-Id: I821043167849e8df30ef6f7d37409dfc707a7cd3 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Remove the sys.path hack (unnecessary — tenacity is installed as a package when running via uv). Remove doctest_path (sphinx.ext.doctest finds tenacity through the installed package). Remove commented-out sphinx options that were never configured. Remove unused os/sys imports. Change-Id: I9ab61b9422939b1b396fdc4ad66f25f834e74315 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The __all__ list already declares public exports, making the F401 noqa comments on re-export imports unnecessary. Also remove bare noqa on iter/begin_iter (was suppressing UP007) and fix the Union type annotation to use X | Y syntax. Change-Id: I7327e94a653fb97a3497fcddf0566b542746744a Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Enable C4, FURB, PERF, PIE, RET, RUF, SIM, TCH rule sets. Key changes: - Remove all stale noqa comments across the codebase (RUF100) - Sort __all__ alphabetically (RUF022) - Remove superfluous else after return/raise (RET505/RET506) - Replace try/except/pass with contextlib.suppress (SIM105) - Move type-only imports into TYPE_CHECKING blocks (TC001/TC003) - Quote type expressions in typing.cast() calls (TC006) - Use list comprehension instead of loop-append (PERF401) - Fix Cyrillic character in docstring (RUF002) - Remove unnecessary int() wrapping round() (RUF046) - Replace dict() call with literal (C408) Ignored rules: - RUF003: ambiguous unicode in comments (copyright holder names) - RUF005: iterable unpacking vs concatenation (less readable) - RUF012: mutable class defaults (false positive on test fixtures) - SIM108: ternary expressions (less readable in context) Change-Id: I88ea78e2254b8a9fee00743464e44e6d33400f47 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Remove blanket mypy disable comments from test_tenacity.py, test_asyncio.py, test_tornado.py, and test_after.py. Add type annotations to all test methods, helper functions, and inner functions so they pass mypy strict without suppressions. Targeted type: ignore comments are used only for intentional type mismatches in tests (e.g. passing None where BaseRetrying is expected) and dynamically-added attributes on decorated functions (.statistics, .retry, .retry_with). Change-Id: I872c723b28364cf30c546c767ad665336ef62df4 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Remove the positional-only marker (/) from LoggerProtocol.log(). logging.Logger.log() defines msg as a regular parameter, so the positional-only constraint caused mypy to reject logging.Logger as incompatible with the protocol. Closes #554 Change-Id: Icc8ffaff0d828c5103c13e97dd2ca7701089713f Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This field was declared and reset but never read or written anywhere in the codebase. The actual delay tracking uses statistics["delay_since_first_attempt"] instead. Change-Id: If82d3ab8694516b21cae6d33147694e19b7cdc45 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
reraise() is typed as NoReturn and always raises internally. The outer `raise` keyword was dead code that could never execute, and was misleading since it suggested reraise() returns an exception rather than raising one directly. Change-Id: I8ef31ce3d62db7d56adb0053855a1131b54f1fa5 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
typing.Pattern has been deprecated since Python 3.9 in favor of re.Pattern. Since we require Python >=3.10, use the standard form. Change-Id: Ic4a74dff54b2877ff64112220c6805f17c1ffefc Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- "there existence" → "their existence" - "there own view" → "their own view" - "some what" → "somewhat" - "to wraps for" → "to wrap for" Change-Id: Ie9509ff1d7de851708793c9023f3fd728681a868 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
`RetryCallState.seconds_since_start` returns None when `outcome_timestamp` is not set. The `%` format operator in `after_log` would crash with a TypeError in this case. Fall back to "?" when the value is None. Change-Id: Ib18f8aced63c084204b2d4719579fae4b8e557f5 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
When using `Retrying` or `AsyncRetrying` as a context manager, log
callbacks showed '<unknown>' as the function name since no `fn` is
set. A new `name` parameter allows users to provide a meaningful
identifier:
for attempt in Retrying(name='ws_listener', before_sleep=before_sleep_log(...)):
with attempt:
...
`RetryCallState.get_fn_name()` is introduced as the single source of
truth for resolving the display name: it returns the decorated
function's qualified name when used as a decorator, falls back to
`str(retry_object)` in context manager mode. `BaseRetrying.__str__`
returns `name` if set, else '<unknown>'. The three log helpers
(before_log, after_log, before_sleep_log) all use `get_fn_name()`
instead of the repeated `fn is None` boilerplate.
Closes #273, closes #333
Change-Id: I717d4d3977028b499612cecb567d0ebc49b5f539
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
#599) Add an attribute reference for RetryCallState in the docs, listing attempt_number, outcome, seconds_since_start, idle_for, and start_time. Includes a short example showing how to log total elapsed time via the after callback — directly addressing the common confusion between seconds_since_start (wall-clock elapsed) and idle_for (sleep time only). Closes #303 Change-Id: I1dbaa9072c2f47822e05f859514a42dcf83ae6d3 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Add _RetryDecorated Protocol that combines the original callable signature (via ParamSpec) with the retry control attributes. Update all retry() overloads, _AsyncRetryDecorator, and wraps() methods to return _RetryDecorated[P, R] instead of bare WrappedFn. This lets mypy see .retry, .statistics, and .retry_with on decorated functions without # type: ignore, fixing a long-standing typing gap. Removes ~30 now-unnecessary type: ignore comments from tests. Closes #346 Change-Id: I8c2bc7b49a0cb51175a8e0bf33d9742f10bc49a0 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add examples for two frequently asked usage patterns: - Running setup code between retries (before_sleep for reconnection) - Accessing the attempt number inside the function (iterator API) These address recurring questions from issues #298, #316, #344, #361. Change-Id: Ic4cea9f63db72a6f9cb47287597a8dacffdc8533 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
) Closes #421 Change-Id: I104d68d8dbfe41282632b8183c267aa88d682be3 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…606) The delegation to __ror__/__rand__ introduced for async retry support broke composing retry_base instances with plain callables. Add an isinstance guard so delegation only happens for retry_base subclasses, while plain callables fall through to direct retry_all/retry_any wrapping. Also widen type annotations on retry_any/retry_all and the operator methods to accept RetryBaseT (the union of retry_base and plain callables), matching the runtime behavior. Fixes #481 Change-Id: I24e081b67dfa7e184266621f73cec4de5177ea25 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
AttemptManager now supports `async with` in addition to `with`, allowing cleaner usage inside `async for` loops. Closes #469 Change-Id: If6d24d58fbb4a0eaba5b62b20f6821d2ccd073a9 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
When enabled=False, the decorated function is called directly without any retry logic. This is useful during development or testing. Closes #467 Change-Id: I2ae833504b87df74ac94503c0c7059a3587730b9 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
When composing multiple retry conditions like `a | b | c`, the operators now flatten into `retry_any(a, b, c)` instead of nesting `retry_any(retry_any(a, b), c)`. This reduces call stack depth when debugging complex retry conditions. Flattening is done in __ror__/__rand__ (where containers are created) and in retry_any.__ror__/retry_all.__rand__ (to extend existing containers). Async versions get the same treatment. Fixes #476 Change-Id: I3a58c9dfeed2309427e65a1c79cb9ac252db0c2a Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Fixes #64 Fixes #66 Fixes #138 Document that @Retry does not support generator functions, and that generators passed as arguments to retried functions will be exhausted after the first attempt. Include a workaround using factory functions. Change-Id: I4fe3ba2d82d1204a7f583b054064999dc1720a03 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…#615) Add __getstate__/__setstate__ to BaseRetrying to exclude the unpicklable threading.local object during serialization. Replace lambdas in retry strategy classes with bound methods so they can be pickled with standard pickle. Fixes #147 Change-Id: Ia3cb014c783078a08492014bb7088f10f95e4ae9 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Fixes #613 func.retry.statistics was always empty because func.retry points to the original Retrying object, but begin() (which populates statistics) is only called on the per-invocation copy. Fix by pointing the original's _local.statistics to the copy's statistics dict so they share the same object. Change-Id: I0299c76659ae6fc0c6354efae22b17946dca223c Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Replace t.Optional, t.Union, and typing.Union with X | None / X | Y union syntax (PEP 604). Change-Id: I569081564348eac6cdfd934c8abcc92b144d35c6 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Change-Id: If2ab751202beaf911d9c8127982c4692ec686acc Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The contextmanager helper was defined but never called. Also removes the now-unused warnings, contextmanager, and copy imports. Change-Id: I9cbcd372905800951e853543ae3d878f76370c7a Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add PGH (pygrep-hooks): enforces specific `# type: ignore[code]` - Add PYI (flake8-pyi): catches redundant numeric unions, stub issues - Rename deprecated TCH prefix to TC - Suppress PYI036 (false positive on string-quoted __exit__ annotations) - Fix PYI041: simplify `int | float` to `float` in wait_exponential Change-Id: If3863e7940c5f32e5a39d7719984f32684799bf9 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Enable 11 new zero-violation guardrail rules (ASYNC, DTZ, EXE, FLY, ICN, ISC, LOG, PTH, SLF, SLOT, T10) and RSE (8 auto-fixed unnecessary parentheses on raises). Suppress ASYNC105 on the intentional unawaited trio.sleep return in _portable_async_sleep. Change-Id: I0c9ce63d66f43757ed2292d6151c031a4a21362d Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Y