1- from io import StringIO as _StringIO
2- from sys import stdout as _stdout
3- from machine import const as _const
1+ import io as _io
2+ import sys as _sys
3+
4+ try :
5+ from micropython import const as _const
6+ except ImportError :
7+ _const = lambda x : x
48
59
610class PrettyPrinter :
@@ -10,27 +14,34 @@ class PrettyPrinter:
1014 call. For parameter descriptions, look at pprint() documentation.
1115 """
1216
13- def __init__ (self , indent = 1 , stream = None , sort_dicts = True ):
14- self .indent = indent
15- self .stream = stream if stream else _stdout
16- self .sort_dicts = sort_dicts
17+ def __init__ (self , indent = 1 , depth = 1 , stream = None , sort_dicts = True ):
18+ self ._indent = indent
19+ self ._depth = depth
20+ self ._stream = stream if stream else _sys .stdout
21+ self ._sort_dicts = sort_dicts
1722
1823 def pformat (self , obj ):
1924 """Call pformat() function with cached constructor values"""
20- return pformat (obj , indent = self .indent , sort_dicts = self .sort_dicts )
25+ return pformat (obj , indent = self ._indent , depth = self ._depth , sort_dicts = self . _sort_dicts )
2126
2227 def pprint (self , obj ):
2328 """Call pprint() function with cached constructor values"""
24- pprint (obj , stream = self .stream , indent = self .indent , sort_dicts = self .sort_dicts )
29+ pprint (
30+ obj ,
31+ stream = self ._stream ,
32+ indent = self ._indent ,
33+ depth = self ._depth ,
34+ sort_dicts = self ._sort_dicts ,
35+ )
2536
2637
27- def pformat (obj , indent = 1 , sort_dicts = True ):
38+ def pformat (obj , indent = 1 , depth = 1 , sort_dicts = True ):
2839 """Simply calls pprint() but capturing prints into a string and returning.
2940
3041 Does not add a newline to the end like pprint() does.
3142 """
32- stream = _StringIO ()
33- _pprint_impl (obj , stream = stream , indent = indent , sort_dicts = sort_dicts )
43+ stream = _io . StringIO ()
44+ _pprint_impl (obj , stream , 0 , sort_dicts , depth , 0 , indent )
3445 return stream .getvalue ()
3546
3647
@@ -39,7 +50,7 @@ def pp(obj, *args, sort_dicts=False, **kwargs):
3950 pprint (obj , * args , sort_dicts = sort_dicts , ** kwargs )
4051
4152
42- def pprint (obj , stream = None , indent = 1 , sort_dicts = True ):
53+ def pprint (obj , stream = None , indent = 1 , depth = 1 , sort_dicts = True ):
4354 """Simple implementation of a pretty-printer.
4455
4556 For simplicity, this does not recurse down. It does not produce the same
@@ -49,13 +60,26 @@ def pprint(obj, stream=None, indent=1, sort_dicts=True):
4960 Only expands containers. Currently supported containers are set, list,
5061 dict, and tuple.
5162
63+ The depth parameter defaults to 1 which is different from the CPython
64+ implementation which defaults to None, meaning infinite recursion. This
65+ implementation is significantly simpler and does not have safety checks
66+ against recursive structures (i.e., structures that contain a copy of
67+ themselves somewhere) or costly overexpansion. This simplicity gains speed
68+ and memory efficiency at the potential cost of expanding too far. Increase
69+ the depth parameter cautiously.
70+
5271 stream
5372 The desired output stream. If omitted (or False), the standard output
5473 stream will be used.
5574
5675 indent
5776 Number of space to indent for each level of nesting.
5877
78+ depth
79+ The maximum depth to print out nested structures. Set to None for
80+ infinite depth. Warning: be careful of infinite depth as infinite
81+ recursion and overexpansion checks are not performed.
82+
5983 sort_dicts
6084 If true, dict keys are sorted. You must ensure that the dicts
6185 encountered can be sorted against each other (for example, int cannot
@@ -65,8 +89,8 @@ def pprint(obj, stream=None, indent=1, sort_dicts=True):
6589 mismatch
6690 """
6791 if not stream :
68- stream = _stdout
69- _pprint_impl (obj , stream , indent , sort_dicts )
92+ stream = _sys . stdout
93+ _pprint_impl (obj , stream , 0 , sort_dicts , depth , 0 , indent )
7094 stream .write ("\n " ) # end in a newline
7195
7296
@@ -85,16 +109,36 @@ def ppdir(obj, *args, hidden=False, **kwargs):
85109# Private implementation
86110
87111
88- def _pprint_impl (obj , stream , indent , sort_dicts ):
112+ def _pprint_impl (obj , stream , indent , sort_dicts , maxlevel , level , indent_per_level ):
89113 type_code = _container_type (obj )
90- if type_code != _NONCONTAINER and len (obj ) > 1 :
114+ if (maxlevel is not None and level >= maxlevel ) or type_code == _NONCONTAINER or not obj :
115+ # directly print noncontainers, empty containers, or if we have reached
116+ # the max level.
117+ stream .write (repr (obj ))
118+ else :
119+ # expand the container
91120 if type_code & _SIMPLE :
92- _pprint_simple_container (obj , type_code , stream , indent , sort_dicts )
121+ _pprint_simple_container (
122+ obj ,
123+ type_code ,
124+ stream ,
125+ indent + indent_per_level ,
126+ sort_dicts ,
127+ maxlevel ,
128+ level + 1 ,
129+ indent_per_level ,
130+ )
93131 else : # type_code & _DICT:
94- _pprint_dict (obj , type_code , stream , indent , sort_dicts )
95- else :
96- # directly print noncontainers or containers with one or fewer elements
97- stream .write (repr (obj ))
132+ _pprint_dict (
133+ obj ,
134+ type_code ,
135+ stream ,
136+ indent + indent_per_level ,
137+ sort_dicts ,
138+ maxlevel ,
139+ level + 1 ,
140+ indent_per_level ,
141+ )
98142
99143
100144_NONCONTAINER = _const (0 )
@@ -118,37 +162,55 @@ def _container_type(obj):
118162 return _NONCONTAINER
119163
120164
121- def _pprint_simple_container (obj , type_code , stream , indent , sort_dicts ):
165+ def _pprint_simple_container (
166+ obj , type_code , stream , indent , sort_dicts , maxlevel , level , indent_per_level
167+ ):
122168 if type_code & _LIST :
123169 chars = "[]"
124170 elif type_code & _TUPLE :
125171 chars = "()"
126172 else : # type_code & _SET:
127173 chars = "{}"
128174
129- stream .write (chars [0 ] + " " * (indent - 1 ))
175+ indent_string = " " * indent
176+
177+ stream .write (chars [0 ])
178+ stream .write (" " * (indent_per_level - 1 ))
130179 first = True
131180 for item in obj :
132181 if not first :
133- stream .write (",\n " + " " * indent )
182+ stream .write (",\n " )
183+ stream .write (indent_string )
134184 first = False
135- # TODO: would recurse here
136- stream .write (repr (item ))
185+ # recurse here
186+ _pprint_impl (item , stream , indent , sort_dicts , maxlevel , level , indent_per_level )
187+ if type_code & _TUPLE and len (obj ) == 1 :
188+ stream .write ("," )
137189 stream .write (chars [1 ])
138190
139191
140- def _pprint_dict (obj , type_code , stream , indent , sort_dicts ):
141- stream .write ("{" + " " * (indent - 1 ))
192+ def _pprint_dict (obj , type_code , stream , indent , sort_dicts , maxlevel , level , indent_per_level ):
193+ indent_string = " " * indent
194+ stream .write ("{" )
195+ stream .write (" " * (indent_per_level - 1 ))
142196 first = True
143197 items = obj .items ()
144198 if sort_dicts :
145199 items = sorted (items , key = lambda x : x [0 ])
146200 for key , val in items :
147201 if not first :
148- stream .write (",\n " + " " * indent )
202+ stream .write (",\n " )
203+ stream .write (indent_string )
149204 first = False
150- # TODO: would recurse here
151- stream .write (repr (key ))
205+ # python's implementation does not multiline keys, then offsets the
206+ # value by the key's length. They still do safety checks such as
207+ # recursiveness and checking that it can be printed within the
208+ # specified width, which we skip in this implementation.
209+ keystr = repr (key )
210+ stream .write (keystr )
152211 stream .write (": " )
153- stream .write (repr (val ))
212+ # recurse on the value, lined up to wrap in front of the colon.
213+ _pprint_impl (
214+ val , stream , indent + len (keystr ) + 2 , sort_dicts , maxlevel , level , indent_per_level
215+ )
154216 stream .write ("}" )
0 commit comments