3
3
from collections import OrderedDict
4
4
from collections .abc import Generator
5
5
6
- from .utils import DataClassType , LaxMapping , env_true , isatty
6
+ from .utils import DataClassType , LaxMapping , SQLAlchemyClassType , env_true , isatty
7
7
8
8
__all__ = 'PrettyFormat' , 'pformat' , 'pprint'
9
9
MYPY = False
10
10
if MYPY :
11
- from typing import Any , Iterable , Union
11
+ from typing import Any , Iterable , Tuple , Union
12
12
13
13
PARENTHESES_LOOKUP = [
14
14
(list , '[' , ']' ),
@@ -69,6 +69,7 @@ def __init__(
69
69
# put this last as the check can be slow
70
70
(LaxMapping , self ._format_dict ),
71
71
(DataClassType , self ._format_dataclass ),
72
+ (SQLAlchemyClassType , self ._format_sqlalchemy_class ),
72
73
]
73
74
74
75
def __call__ (self , value : 'Any' , * , indent : int = 0 , indent_first : bool = False , highlight : bool = False ):
@@ -169,15 +170,7 @@ def _format_tuples(self, value: tuple, value_repr: str, indent_current: int, ind
169
170
fields = getattr (value , '_fields' , None )
170
171
if fields :
171
172
# named tuple
172
- self ._stream .write (value .__class__ .__name__ + '(\n ' )
173
- for field , v in zip (fields , value ):
174
- self ._stream .write (indent_new * self ._c )
175
- if field : # field is falsy sometimes for odd things like call_args
176
- self ._stream .write (str (field ))
177
- self ._stream .write ('=' )
178
- self ._format (v , indent_new , False )
179
- self ._stream .write (',\n ' )
180
- self ._stream .write (indent_current * self ._c + ')' )
173
+ self ._format_fields (value , zip (fields , value ), indent_current , indent_new )
181
174
else :
182
175
# normal tuples are just like other similar iterables
183
176
return self ._format_list_like (value , value_repr , indent_current , indent_new )
@@ -231,13 +224,15 @@ def _format_bytearray(self, value: 'Any', _: str, indent_current: int, indent_ne
231
224
def _format_dataclass (self , value : 'Any' , _ : str , indent_current : int , indent_new : int ):
232
225
from dataclasses import asdict
233
226
234
- before_ = indent_new * self ._c
235
- self ._stream .write (f'{ value .__class__ .__name__ } (\n ' )
236
- for k , v in asdict (value ).items ():
237
- self ._stream .write (f'{ before_ } { k } =' )
238
- self ._format (v , indent_new , False )
239
- self ._stream .write (',\n ' )
240
- self ._stream .write (indent_current * self ._c + ')' )
227
+ self ._format_fields (value , asdict (value ).items (), indent_current , indent_new )
228
+
229
+ def _format_sqlalchemy_class (self , value : 'Any' , _ : str , indent_current : int , indent_new : int ):
230
+ fields = [
231
+ (field , getattr (value , field ))
232
+ for field in dir (value )
233
+ if not (field .startswith ('_' ) or field in ['metadata' , 'registry' ])
234
+ ]
235
+ self ._format_fields (value , fields , indent_current , indent_new )
241
236
242
237
def _format_raw (self , _ : 'Any' , value_repr : str , indent_current : int , indent_new : int ):
243
238
lines = value_repr .splitlines (True )
@@ -256,6 +251,18 @@ def _format_raw(self, _: 'Any', value_repr: str, indent_current: int, indent_new
256
251
else :
257
252
self ._stream .write (value_repr )
258
253
254
+ def _format_fields (
255
+ self , value : 'Any' , fields : 'Iterable[Tuple[str, Any]]' , indent_current : int , indent_new : int
256
+ ) -> None :
257
+ self ._stream .write (f'{ value .__class__ .__name__ } (\n ' )
258
+ for field , v in fields :
259
+ self ._stream .write (indent_new * self ._c )
260
+ if field : # field is falsy sometimes for odd things like call_args
261
+ self ._stream .write (f'{ field } =' )
262
+ self ._format (v , indent_new , False )
263
+ self ._stream .write (',\n ' )
264
+ self ._stream .write (indent_current * self ._c + ')' )
265
+
259
266
260
267
pformat = PrettyFormat ()
261
268
force_highlight = env_true ('PY_DEVTOOLS_HIGHLIGHT' , None )
0 commit comments