Skip to content

gh-151099: Better repr output for template strings.#151104

Open
doerwalter wants to merge 2 commits into
python:mainfrom
doerwalter:main
Open

gh-151099: Better repr output for template strings.#151104
doerwalter wants to merge 2 commits into
python:mainfrom
doerwalter:main

Conversation

@doerwalter

@doerwalter doerwalter commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

This changes the repr ouput for template strings to list the template parts in their original order (which is the same order in which those parts can be passed to the Template constructor to recreate the Template object).

This has been discussed here: https://discuss.python.org/t/repr-output-of-t-strings/107653/8

The issue is here: #151099

@loic-simon loic-simon left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should update pprint functions output accordingly (introduced here, I can lend a hand if needed!)

Comment thread Objects/templateobject.c Outdated

int res = Py_ReprEnter(self);
if (res != 0) {
return (res > 0 ? PyUnicode_FromString("Template(...)") : NULL);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

should we use _PyType_Name(Py_TYPE(self)) instead of hardcoding Template here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've updated the patch to do that.

And I also changed the call to Py_ReprEnter/Py_ReprLeave to pass op instead of self to avoid compiler warnings.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I tried updating pprint.PrettyPrinter._pprint_template() like this

--- a/Lib/pprint.py
+++ b/Lib/pprint.py
@@ -742,13 +742,9 @@ def _pprint_template(self, object, stream, indent, allowance, context, level):
         else:
             indent += len(cls_name) + 1

-        items = (
-            ("strings", object.strings),
-            ("interpolations", object.interpolations),
-        )
         stream.write(self._format_block_start(cls_name + "(", indent))
-        self._format_namespace_items(
-            items, stream, indent, allowance, context, level
+        self._format_items(
+            object, stream, indent, allowance, context, level
         )

but somehow this gives me an extra level of indentation

>>> import pprint
>>> print(pprint.pformat(t'Hello {'world'}', width=40, indent=4, expand=True))
Template(
        'Hello ',
        Interpolation(
            value='world',
            expression="'world'",
            conversion=None,
            format_spec='',
        ),
)
>>> print(pprint.pformat(t'Hello {'world'}', width=40, indent=4, expand=False))
Template(   'Hello ',
             Interpolation(   'world',
                              "'world'",
                              None,
                              ''))

What am I doing wrong?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hm, I believe that's the indented output! If you try

>>> print(pprint.pformat(['Hello', 'foo'*10], width=40, indent=4, expand=False))
[   'Hello',
    'foofoofoofoofoofoofoofoofoofoo']

the extra indentation is the same, even if I would not have expected it either 😅

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The expand=False output is indeed unexpected, but the expand=True output is wrong, since the first indentation level is 8 spaces and the second level is 4.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Okay, I think it's because we don't need the indent += self._indent_per_level with self.format_items, otherwise we ident twice:

--- a/Lib/pprint.py
+++ b/Lib/pprint.py
@@ -739,7 +739,5 @@ def _pprint_template(self, object, stream, indent, allowance, context, level):
         cls_name = object.__class__.__name__
-        if self._expand:
-            indent += self._indent_per_level
-        else:
+        if not self._expand:
             indent += len(cls_name) + 1

That still doesn't look super nice, but not worse than today!

Pass the original `op` to `Py_ReprEnter`/`Py_ReprLeave` to avoid compiler warnings.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants