Repository navigation
parity: Markup's % escapes each conversion; %-format keyed-argument rules (0182, 0106) - #549
Merged
Merged
Conversation
…lue is the only argument left (0182, 0106) Markup % and format() on Markup pass the arguments through and let PythonPercentFormat escape the text of %s/%r/%a, as markupsafe's _MarkupEscapeHelper does, so %r prints the escaped repr of the original and containers print their own repr escaped as a whole. %c, %x, %X and %o raise on a Markup format, as on the helper. EscapeFormatArgs is removed. After "(key)" the mapping value is the only argument, used once, so "%(a)*d" and "%(a)s %s" raise "not enough arguments" as in Python. Files 0210 for %d/%f of a string argument in Markup's %. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AsAUaeKoPqQBF7sQ1ikEMC
…unconverted (0182, 0106) Verifier findings: markupsafe's helper is not an int, so '*' raises on a Markup format; CPython counts a list as a mapping, so 'x' % [1, 2] is 'x'. CompiledPercentFormat drops the unused markup flag: a Markup format is never parsed at Load. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AsAUaeKoPqQBF7sQ1ikEMC
rmorozov
added a commit
that referenced
this pull request
Oct 17, 2026
Train 17: parity 0182+0106 (#549)
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.
Requested by Ruslan · project thread
Before:
{{ ('%r'|safe) % 'x' }}printedMarkup('x'), and{{ ('%s'|safe) % {'a': '<'} }}printed{'a': Markup('<')}, because Markup's%escaped every argument before formatting.'%(a)s %s' % dand'%(a)*d' % drendered, and'x' % [1, 2]raised.After: these match Python Jinja2. They render
'x'and{'a': '<'}. The two keyed formats raise "not enough arguments for format string", and'x' % [1, 2]rendersx.The change copies markupsafe's
_MarkupEscapeHelper. It escapes thestr()/repr()/ascii()of the original argument, and does so before precision and width apply. Thestr()of a Markup argument is not escaped.How.
PythonPercentFormattakes amarkupflag. With it set,%s,%rand%aescape their text.%c,%x,%X,%oand*raise, as they do on the helper.%, theformatfilter on Markup and gettext under autoescape all pass their arguments through unchanged.EscapeFormatArgsis removed frommarkup.h.python_format.cpp, a(key)leaves its value as the only argument, and that value is used once, as in CPython. A non-tuple list counts as a mapping (PyMapping_Check), so it is never reported as "not all arguments converted".Corpus.
autoescape.markup_percent_reprnow matches. Its line is deleted.autoescape.markup_*(9),filters.format_*(8, the 0106 block) andi18n.gettext_autoescape_repr.%dof 1e30,%r/%aof non-ASCII and dict order already matched; they now have corpus cases.Divergences listed.
autoescape.markup_percent_d_of_string(rejects): filed as 0210. The helper's__int__/__float__lets%d/%ftake a numeric string, which needs Pythonint()/float()string parsing.wide.filters.format_c_surrogate(output, deliberate):%formats in UTF-8. The lone surrogate from%cmatches in narrow templates but becomes U+FFFD on the way back to a wide string.Task files: 0182 and 0106 are marked done with outcomes, and 0210 is new.
Roles and pushes.
*on Markup, list-as-mapping) are fixed in the second commit, and its third (theformatform of 0210) was added to the task file.scripts/preflight.sh --perfis green, including the instruction gate.Generated by Claude Code