Skip to content

fix: safe formatting for surrogates in pluggy tracing - #716

Closed
ltsyk wants to merge 1 commit into
pytest-dev:mainfrom
ltsyk:fix/tracing-surrogate-encode-error
Closed

ltsyk wants to merge 1 commit into
pytest-dev:mainfrom
ltsyk:fix/tracing-surrogate-encode-error

Conversation

@ltsyk

@ltsyk ltsyk commented Jul 30, 2026

Copy link
Copy Markdown

Summary

Tracing crashed with UnicodeEncodeError when hook args contained surrogate escapes.

Change

Format trace values with backslashreplace so surrogates are escaped safely.

Fixes #681

Avoid UnicodeEncodeError in tracing (issue pytest-dev#681)
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pluggy that referenced this pull request Sep 12, 2026
Tracing could turn a working hook call into a failing one in two ways:
an object whose __repr__/__str__ raises propagated that exception out of
the hook call (pytest-dev#424), and a lone surrogate in a hook argument or return
value produced a message the writer could not encode (pytest-dev#681).

Both are now handled in one place. _safe_repr()/_safe_str() wrap the
conversion the way pytest's saferepr does -- KeyboardInterrupt and
SystemExit still propagate, anything else is rendered as an
unpresentable-object marker -- and escape lone surrogates with
backslashreplace afterwards, which also covers surrogates that come out
of an object's own __repr__.

Traced values -- hook kwargs and the hook result -- now use repr() so
their type is visible in the log; structural labels such as the hook
name and the finish/--> markers keep using str() and stay unquoted.

Supersedes pytest-dev#627, pytest-dev#666, pytest-dev#684 and pytest-dev#716.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pluggy that referenced this pull request Sep 23, 2026
Tracing could turn a working hook call into a failing one in two ways:
an object whose __repr__/__str__ raises propagated that exception out of
the hook call (pytest-dev#424), and a lone surrogate in a hook argument or return
value produced a message the writer could not encode (pytest-dev#681).

Both are now handled in one place. _safe_repr()/_safe_str() wrap the
conversion the way pytest's saferepr does -- KeyboardInterrupt and
SystemExit still propagate, anything else is rendered as an
unpresentable-object marker -- and escape lone surrogates with
backslashreplace afterwards, which also covers surrogates that come out
of an object's own __repr__.

Traced values -- hook kwargs and the hook result -- now use repr() so
their type is visible in the log; structural labels such as the hook
name and the finish/--> markers keep using str() and stay unquoted.

Supersedes pytest-dev#627, pytest-dev#666, pytest-dev#684 and pytest-dev#716.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pluggy that referenced this pull request Sep 24, 2026
Tracing could turn a working hook call into a failing one in two ways:
an object whose __repr__/__str__ raises propagated that exception out of
the hook call (pytest-dev#424), and a lone surrogate in a hook argument or return
value produced a message the writer could not encode (pytest-dev#681).

Both are now handled in one place. _safe_repr()/_safe_str() catch
Exception from the conversion and render an unpresentable-object marker
in the shape of pytest's saferepr, naming the exception, or only its
type when the exception's own repr fails too, so no user code runs in the
last fallback. Anything outside Exception -- KeyboardInterrupt,
SystemExit, pytest's outcome exceptions -- propagates: a __str__ or
__repr__ that raises one of those is a bug in that object, not something
tracing should hide. Lone surrogates are escaped with backslashreplace
afterwards, which also covers surrogates that come out of an object's
own __repr__.

Traced values -- hook kwargs and the hook result -- now use repr() so
their type is visible in the log; structural labels such as the hook
name and the finish/--> markers keep using str() and stay unquoted.

Supersedes pytest-dev#627, pytest-dev#666, pytest-dev#684 and pytest-dev#716.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
@RonnyPfannschmidt

Copy link
Copy Markdown
Member

Written by Claude Opus 5.5 via Claude Code for the PR author; I prompted it, it did the work, I read it.

Superseded by #728, which is now merged and carries this PR's contribution. See the "Relation to the existing PRs" section there for what was taken from each. Thank you. Closing.

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.

Tracing crashes with UnicodeEncodeError on surrogate escapes in hook arguments/results

2 participants