Skip to content

Commit 493a4c8

Browse files
authored
Added cmd2.Cmd.ppretty() pretty print output method (#1433)
This method provides a way to pretty-print arbitrary Python structures similar to the pprint.pprint method in the standard library.
1 parent e3e5113 commit 493a4c8

File tree

7 files changed

+74
-0
lines changed

7 files changed

+74
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- `cmd2` 2.6 supports Python 3.9+ (removed support for Python 3.8)
55
- Enhancements
66
- Add support for Python 3.14
7+
- Added new `Cmd.ppretty()` method for pretty printing arbitrary Python data structures
78

89
## 2.5.11 (January 25, 2025)
910

cmd2/cmd2.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import glob
3737
import inspect
3838
import os
39+
import pprint
3940
import pydoc
4041
import re
4142
import sys
@@ -1338,6 +1339,17 @@ def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False) -> None:
13381339
else:
13391340
self.poutput(msg, end=end)
13401341

1342+
def ppretty(self, data: Any, *, indent: int = 2, width: int = 80, depth: Optional[int] = None, end: str = '\n') -> None:
1343+
"""Pretty print arbitrary Python data structures to self.stdout and appends a newline by default.
1344+
1345+
:param data: object to print
1346+
:param indent: the amount of indentation added for each nesting level
1347+
:param width: the desired maximum number of characters per line in the output, a best effort will be made for long data
1348+
:param depth: the number of nesting levels which may be printed, if data is too deep, the next level replaced by ...
1349+
:param end: string appended after the end of the message, default a newline
1350+
"""
1351+
self.print_to(self.stdout, pprint.pformat(data, indent, width, depth), end=end)
1352+
13411353
# ----- Methods related to tab completion -----
13421354

13431355
def _reset_completion_defaults(self) -> None:

docs/features/generating_output.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,14 @@ These functions differ from Python's string justifying functions in that they su
8080
When generating output in multiple columns, you often need to calculate the width of each item so you can pad it appropriately with spaces. However, there are categories of Unicode characters that occupy 2 cells, and other that occupy 0. To further complicate matters, you might have included ANSI escape sequences in the output to generate colors on the terminal.
8181

8282
The `cmd2.ansi.style_aware_wcswidth` function solves both of these problems. Pass it a string, and regardless of which Unicode characters and ANSI text style escape sequences it contains, it will tell you how many characters on the screen that string will consume when printed.
83+
84+
## Pretty Printing Data Structures
85+
86+
The `cmd2.Cmd.ppretty` method is similar to the Python [pprint](https://docs.python.org/3/library/pprint.html) function from the standard `pprint` module. `cmd2.Cmd.pprint` adds the same conveniences as `cmd2.Cmd.poutput`.
87+
88+
This method provides a capability to “pretty-print” arbitrary Python data structures in a form which can be used as input to the interpreter and is easy for humans
89+
to read.
90+
91+
The formatted representation keeps objects on a single line if it can, and breaks them onto multiple lines if they don’t fit within the allowed width, adjustable by the width parameter defaulting to 80 characters.
92+
93+
Dictionaries are sorted by key before the display is computed.

docs/features/settings.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Output generated by `cmd2` programs may contain ANSI escape sequences which inst
1616
- **`cmd2.Cmd.pexcept`**
1717
- **`cmd2.Cmd.pfeedback`**
1818
- **`cmd2.Cmd.ppaged`**
19+
- **`cmd2.Cmd.ppretty`**
1920

2021
This setting can be one of three values:
2122

examples/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ Here is the list of examples in alphabetical order by filename along with a brie
6868
- Shows how to enable persistent history in your `cmd2` application
6969
- [pirate.py](https://github.com/python-cmd2/cmd2/blob/master/examples/pirate.py)
7070
- Demonstrates many features including colorized output, multiline commands, shorcuts, defaulting to shell, etc.
71+
- [pretty_print.py](https://github.com/python-cmd2/cmd2/blob/master/examples/pretty_print.py)
72+
- Demonstrates use of cmd2.Cmd.ppretty() for pretty-printing arbitrary Python data structures like dictionaries.
7173
- [python_scripting.py](https://github.com/python-cmd2/cmd2/blob/master/examples/python_scripting.py)
7274
- Shows how cmd2's built-in `run_pyscript` command can provide advanced Python scripting of cmd2 applications
7375
- [read_input.py](https://github.com/python-cmd2/cmd2/blob/master/examples/read_input.py)

examples/pretty_print.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env python3
2+
"""A simple example demonstrating use of cmd2.Cmd.ppretty()."""
3+
4+
import cmd2
5+
6+
data = {
7+
"name": "John Doe",
8+
"age": 30,
9+
"address": {"street": "123 Main St", "city": "Anytown", "state": "CA"},
10+
"hobbies": ["reading", "hiking", "coding"],
11+
}
12+
13+
14+
class Cmd2App(cmd2.Cmd):
15+
def __init__(self) -> None:
16+
super().__init__()
17+
18+
def do_normal(self, _) -> None:
19+
"""Display the data using the normal poutput method."""
20+
self.poutput(data)
21+
22+
def do_pretty(self, _) -> None:
23+
"""Display the data using the ppretty method."""
24+
self.ppretty(data)
25+
26+
27+
if __name__ == '__main__':
28+
app = Cmd2App()
29+
app.cmdloop()

tests/test_cmd2.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,6 +1962,24 @@ def test_poutput_none(outsim_app) -> None:
19621962
assert out == expected
19631963

19641964

1965+
def test_ppretty_dict(outsim_app) -> None:
1966+
data = {
1967+
"name": "John Doe",
1968+
"age": 30,
1969+
"address": {"street": "123 Main St", "city": "Anytown", "state": "CA"},
1970+
"hobbies": ["reading", "hiking", "coding"],
1971+
}
1972+
outsim_app.ppretty(data)
1973+
out = outsim_app.stdout.getvalue()
1974+
expected = """
1975+
{ 'address': {'city': 'Anytown', 'state': 'CA', 'street': '123 Main St'},
1976+
'age': 30,
1977+
'hobbies': ['reading', 'hiking', 'coding'],
1978+
'name': 'John Doe'}
1979+
"""
1980+
assert out == expected.lstrip()
1981+
1982+
19651983
@with_ansi_style(ansi.AllowStyle.ALWAYS)
19661984
def test_poutput_ansi_always(outsim_app) -> None:
19671985
msg = 'Hello World'

0 commit comments

Comments
 (0)