FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-112632: Add optional keyword-only argument `expand` to `pprint` by donbarbos · Pull Request #136964 · python/cpython · GitHub

Repository navigation

gh-112632: Add optional keyword-only argument expand to pprint - #136964

Merged
hugovk merged 51 commits into
python:mainfrom
donbarbos:issue-112632
Apr 7, 2026
Merged

hugovk merged 51 commits into
python:mainfrom
donbarbos:issue-112632

Conversation

donbarbos commented Jul 22, 2025 •
edited
Loading

Copy link
Copy Markdown
Contributor

cc @tomasr8 as the previous reviewer (tests coverage problem fixed)


📚 Documentation preview 📚: https://cpython-previews--136964.org.readthedocs.build/

stodoran and others added 30 commits January 24, 2025 18:19
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: donBarbos <donbarbos@proton.me>

hugovk commented Mar 24, 2026

Copy link
Copy Markdown
Member

Thanks for working on this, it's looking good!

Is "block style JSON formatting" an established term? Wondering if there's a better explanation. Maybe just "pretty-printed JSON" is better?

I've also opened donbarbos#1 to suggest renaming block_style to expand, as it mirrors compact well.

Black uses the word "explode", which I'm not sure fits here, but "expand" is similar.

And let's update from main after merging donbarbos#1, it's been a while since this ran CI.

donbarbos requested a review from AA-Turner as a code owner March 25, 2026 18:43
hugovk changed the title gh-112632: Add optional keyword-only argument block_style to pprint gh-112632: Add optional keyword-only argument expand to pprint Mar 25, 2026

hugovk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

And see also donbarbos#2.

Comment thread Doc/library/pprint.rst Outdated
Comment thread Doc/library/pprint.rst Outdated
Comment thread Doc/whatsnew/3.15.rst Outdated
Comment thread Lib/pprint.py Outdated

hugovk commented Mar 27, 2026

Copy link
Copy Markdown
Member

Here's a visual test on a bunch of types:

script
import collections
import dataclasses
import pprint
import types

pp = lambda label, obj: print(
    f"--- {label} ---\n{pprint.pformat(obj, width=20, indent=4, expand=True)}\n"
)

pp("dict", {"foo": "bar", "baz": 123, "qux": [1, 2, 3], "quux": {"a": "b"}})

pp("list", ["foo", "bar", "baz", "qux", "quux"])

pp("tuple", ("foo", "bar", "baz", 4, 5, 6))

pp("tuple (single)", ("only",))

pp("set", {"foo", "bar", "baz", "qux", (1, 2, 3)})

pp("frozenset", frozenset({"foo", "bar", "baz", (1, 2, 3)}))

pp("OrderedDict", collections.OrderedDict([("foo", 1), ("bar", 12), ("baz", 123)]))

dd = collections.defaultdict(list)
dd["foo"].extend(["bar", "baz", "qux"])
dd["bar"] = {"a": "b", "c": None}
pp("defaultdict", dd)

pp("Counter", collections.Counter("abcdeabcdabcaba"))

pp("ChainMap", collections.ChainMap({"foo": "bar"}, {"baz": "qux"}, {"a": [1, 2, 3]}))

pp("deque", collections.deque(["foo", 123, {"a": "b"}, [1, 2, 3]]))

pp("deque (maxlen)", collections.deque(["foo", 123, {"a": "b"}], maxlen=10))


@dataclasses.dataclass
class Point:
    x: float
    y: float
    label: str
    tags: list = dataclasses.field(default_factory=list)


pp("dataclass", Point(1.0, 2.5, "origin", ["a", "b", "c"]))

pp(
    "SimpleNamespace",
    types.SimpleNamespace(foo="bar", count=42, nested=types.SimpleNamespace(x=1, y=2)),
)

pp("bytes", b"Hello world! foo bar baz 123 456 789")

pp("bytearray", bytearray(b"Hello world! foo bar baz 123 456 789"))

pp("mappingproxy", types.MappingProxyType({"foo": "bar", "baz": 123, "qux": [1, 2]}))

pp("frozendict", frozendict({"foo": "bar", "baz": 123, "qux": [1, 2]}))

pp("dict_keys", {"foo": 1, "bar": 2, "baz": 3, "qux": 4, "quux": 5}.keys())

pp("dict_values", {"foo": 1, "bar": 2, "baz": 3, "qux": 4, "quux": 5}.values())

pp("dict_items", {"foo": 1, "bar": 2, "baz": 3, "qux": 4, "quux": 5}.items())

pp("str", "The quick brown fox jumped over the lazy dog " * 3)

pp("UserDict", collections.UserDict({"foo": "bar", "baz": 123, "qux": [1, 2]}))

pp("UserList", collections.UserList(["foo", "bar", "baz", "qux", "quux"]))

pp(
    "UserString",
    collections.UserString("The quick brown fox jumped over the lazy dog " * 3),
)

The new frozendict, other dict_* and str need updating to support expand:

--- frozendict ---
frozendict({
               'baz': 123,
               'foo': 'bar',
               'qux': [
                   1,
                   2
               ]
           })

--- dict_keys ---
dict_keys([       'bar',
    'baz',
    'foo',
    'quux',
    'qux'])

--- dict_values ---
dict_values([       1,
    2,
    3,
    4,
    5])

--- dict_items ---
dict_items([       ('bar', 2),
    ('baz', 3),
    ('foo', 1),
    ('quux', 5),
    ('qux', 4)])

--- str ---
('The quick brown '
 'fox jumped over '
 'the lazy dog The '
 'quick brown fox '
 'jumped over the '
 'lazy dog The '
 'quick brown fox '
 'jumped over the '
 'lazy dog ')
Full output
--- dict ---
{
    'baz': 123,
    'foo': 'bar',
    'quux': {'a': 'b'},
    'qux': [1, 2, 3]
}

--- list ---
[
    'foo',
    'bar',
    'baz',
    'qux',
    'quux'
]

--- tuple ---
(
    'foo',
    'bar',
    'baz',
    4,
    5,
    6
)

--- tuple (single) ---
('only',)

--- set ---
{
    'bar',
    'baz',
    'foo',
    'qux',
    (1, 2, 3)
}

--- frozenset ---
frozenset({
    'bar',
    'baz',
    'foo',
    (1, 2, 3)
})

--- OrderedDict ---
OrderedDict([
    ('foo', 1),
    ('bar', 12),
    ('baz', 123)
])

--- defaultdict ---
defaultdict(<class 'list'>, {
    'bar': {
        'a': 'b',
        'c': None
    },
    'foo': [
        'bar',
        'baz',
        'qux'
    ]
})

--- Counter ---
Counter({
    'a': 5,
    'b': 4,
    'c': 3,
    'd': 2,
    'e': 1
})

--- ChainMap ---
ChainMap(
    {'foo': 'bar'},
    {'baz': 'qux'},
    {
        'a': [1, 2, 3]
    }
)

--- deque ---
deque([
    'foo',
    123,
    {'a': 'b'},
    [1, 2, 3]
])

--- deque (maxlen) ---
deque([
    'foo',
    123,
    {'a': 'b'}
], maxlen=10)

--- dataclass ---
Point(
    x=1.0,
    y=2.5,
    label='origin',
    tags=['a', 'b', 'c']
)

--- SimpleNamespace ---
namespace(
    foo='bar',
    count=42,
    nested=namespace(
        x=1,
        y=2
    )
)

--- bytes ---
(
    b'Hello world!'
    b' foo bar baz'
    b' 123 456 789'
)

--- bytearray ---
bytearray(
    b'Hello world!'
    b' foo bar baz'
    b' 123 456 789'
)

--- mappingproxy ---
mappingproxy({
    'baz': 123,
    'foo': 'bar',
    'qux': [1, 2]
})

--- frozendict ---
frozendict({
               'baz': 123,
               'foo': 'bar',
               'qux': [
                   1,
                   2
               ]
           })

--- dict_keys ---
dict_keys([       'bar',
    'baz',
    'foo',
    'quux',
    'qux'])

--- dict_values ---
dict_values([       1,
    2,
    3,
    4,
    5])

--- dict_items ---
dict_items([       ('bar', 2),
    ('baz', 3),
    ('foo', 1),
    ('quux', 5),
    ('qux', 4)])

--- str ---
('The quick brown '
 'fox jumped over '
 'the lazy dog The '
 'quick brown fox '
 'jumped over the '
 'lazy dog The '
 'quick brown fox '
 'jumped over the '
 'lazy dog ')

--- UserDict ---
{
    'baz': 123,
    'foo': 'bar',
    'qux': [1, 2]
}

--- UserList ---
[
    'foo',
    'bar',
    'baz',
    'qux',
    'quux'
]

--- UserString ---
('The quick brown '
 'fox jumped over '
 'the lazy dog The '
 'quick brown fox '
 'jumped over the '
 'lazy dog The '
 'quick brown fox '
 'jumped over the '
 'lazy dog ')

hugovk and others added 2 commits March 27, 2026 14:37
* Move recursive_indent calculation into helper
* Move indent padding into helper
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>

hugovk commented Mar 28, 2026

Copy link
Copy Markdown
Member

Would you like to have a go at adding support for frozendict, dict_* and str or shall I have a look?

Copy link
Copy Markdown
Contributor Author

Would you like to have a go at adding support for frozendict, dict_* and str or shall I have a look?

I'd like to do it myself, but I don't think I'll be able to devote enough time to it in the near future. So I'd be grateful for help

hugovk commented Mar 29, 2026

Copy link
Copy Markdown
Member

I've also added a trailing comma when expanded, similar to modern Black/Ruff style:

Full output
--- dict ---
{
 'baz': 123,
 'foo': 'bar',
 'quux': {'a': 'b'},
 'qux': [1, 2, 3],
}

--- list ---
[
 'foo',
 'bar',
 'baz',
 'qux',
 'quux',
]

--- tuple ---
(
 'foo',
 'bar',
 'baz',
 4,
 5,
 6,
)

--- tuple (single) ---
('only',)

--- set ---
{
 'bar',
 'baz',
 'foo',
 'qux',
 (1, 2, 3),
}

--- frozenset ---
frozenset({
 'bar',
 'baz',
 'foo',
 (1, 2, 3),
})

--- OrderedDict ---
OrderedDict([
 ('foo', 1),
 ('bar', 12),
 ('baz', 123),
])

--- defaultdict ---
defaultdict(<class 'list'>, {
 'bar': {
  'a': 'b',
  'c': None,
 },
 'foo': [
  'bar',
  'baz',
  'qux',
 ],
})

--- Counter ---
Counter({
 'a': 5,
 'b': 4,
 'c': 3,
 'd': 2,
 'e': 1,
})

--- ChainMap ---
ChainMap(
 {'foo': 'bar'},
 {'baz': 'qux'},
 {'a': [1, 2, 3]},
)

--- deque ---
deque([
 'foo',
 123,
 {'a': 'b'},
 [1, 2, 3],
])

--- deque (maxlen) ---
deque([
 'foo',
 123,
 {'a': 'b'},
], maxlen=10)

--- dataclass ---
Point(
 x=1.0,
 y=2.5,
 label='origin',
 tags=['a', 'b', 'c'],
)

--- SimpleNamespace ---
namespace(
 foo='bar',
 count=42,
 nested=namespace(x=1, y=2),
)

--- bytes ---
(
 b'Hello world! foo'
 b' bar baz 123 456'
 b' 789'
)

--- bytearray ---
bytearray(
 b'Hello world! foo'
 b' bar baz 123 456'
 b' 789'
)

--- mappingproxy ---
mappingproxy({
 'baz': 123,
 'foo': 'bar',
 'qux': [1, 2],
})

--- frozendict ---
frozendict({
 'baz': 123,
 'foo': 'bar',
 'qux': [1, 2],
})

--- dict_keys ---
dict_keys([
 'bar',
 'baz',
 'foo',
 'quux',
 'qux',
])

--- dict_values ---
dict_values([
 1,
 2,
 3,
 4,
 5,
])

--- dict_items ---
dict_items([
 ('bar', 2),
 ('baz', 3),
 ('foo', 1),
 ('quux', 5),
 ('qux', 4),
])

--- str ---
(
 'The quick brown '
 'fox jumped over '
 'the lazy dog The '
 'quick brown fox '
 'jumped over the '
 'lazy dog The '
 'quick brown fox '
 'jumped over the '
 'lazy dog '
)

--- UserDict ---
{
 'baz': 123,
 'foo': 'bar',
 'qux': [1, 2],
}

--- UserList ---
[
 'foo',
 'bar',
 'baz',
 'qux',
 'quux',
]

--- UserString ---
(
 'The quick brown '
 'fox jumped over '
 'the lazy dog The '
 'quick brown fox '
 'jumped over the '
 'lazy dog The '
 'quick brown fox '
 'jumped over the '
 'lazy dog '
)

hugovk merged commit 132abfd into python:main Apr 7, 2026
52 checks passed

hugovk commented Apr 7, 2026

Copy link
Copy Markdown
Member

Thank you!

Copy link
Copy Markdown
Contributor Author

Big thanks!

ljfp pushed a commit to ljfp/cpython that referenced this pull request Apr 25, 2026
…nt` (python#136964)

Co-authored-by: stodoran <stefan.todoran@uipath.com>
Co-authored-by: StefanTodoran <stefan.alex4@gmail.com>
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants


Back | FazBrowse Home | New Git URL