Skip to content

Accept empty message in retry_if_exception_message#651

Open
gaoflow wants to merge 1 commit into
jd:mainfrom
gaoflow:fix-exception-message-empty-string
Open

Accept empty message in retry_if_exception_message#651
gaoflow wants to merge 1 commit into
jd:mainfrom
gaoflow:fix-exception-message-empty-string

Conversation

@gaoflow

@gaoflow gaoflow commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Problem

retry_if_exception_message validates its two mutually-exclusive arguments
with truthiness checks:

if message and match:            # both given
    raise TypeError(...)
if not message and not match:    # neither given
    raise TypeError(...)
...
self.match = re.compile(match) if match else None
...
def _check(self, exception):
    if self.message:             # skips message == ""
        return self.message == str(exception)

An empty string is a valid message target — it matches exceptions whose
str() is empty, e.g. a bare raise RuntimeError() (str(RuntimeError()) == "").
But not message is True for "", so:

retry_if_exception_message(message="")
# TypeError: retry_if_exception_message() missing 1 required argument 'message' or 'match'

The result is an asymmetry: you can match every exception message except
the empty one. _check's if self.message: would drop the empty-message branch
as well, falling through to assert self.match is not None.

Fix

Replace the truthiness guards with is None checks, so an empty message is
accepted and matched like any other. retry_if_not_exception_message inherits
the same constructor and is fixed by the same change.

Tests

Added test_retry_if_exception_message_empty_message and
test_retry_if_not_exception_message_empty_message: construct with message=""
and drive the predicate against a bare RuntimeError() (matches) and a
RuntimeError("boom") (does not), plus the inverse for the not-variant. Both
fail before the change (TypeError at construction) and pass after. The
existing test_..._negative_no_inputs (passing no arguments must raise) still
passes.

Full suite: 167 passed, 1 skipped, 12 subtests. ruff check / ruff format --check clean.

retry_if_exception_message validated its message/match arguments with
truthiness checks (if message and match, if not message and not match).
An empty string is a valid message target — it matches exceptions whose
str() is empty, e.g. a bare RuntimeError() — but 'not message' is True
for '', so retry_if_exception_message(message='') wrongly raised
TypeError('missing 1 required argument'). _check had the same problem:
'if self.message:' skipped the empty-message branch.

Replace the truthiness guards with 'is None' checks so an empty message
is accepted and matched. This makes every message matchable, not every
message except the empty one.
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.

1 participant