Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/pandas/io/formats/printing.py: 7%
202 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1"""
2Printing tools.
3"""
4from __future__ import annotations
6import sys
7from typing import (
8 Any,
9 Callable,
10 Dict,
11 Iterable,
12 Mapping,
13 Sequence,
14 TypeVar,
15 Union,
16)
18from pandas._config import get_option
20from pandas.core.dtypes.inference import is_sequence
22EscapeChars = Union[Mapping[str, str], Iterable[str]]
23_KT = TypeVar("_KT")
24_VT = TypeVar("_VT")
27def adjoin(space: int, *lists: list[str], **kwargs) -> str:
28 """
29 Glues together two sets of strings using the amount of space requested.
30 The idea is to prettify.
32 ----------
33 space : int
34 number of spaces for padding
35 lists : str
36 list of str which being joined
37 strlen : callable
38 function used to calculate the length of each str. Needed for unicode
39 handling.
40 justfunc : callable
41 function used to justify str. Needed for unicode handling.
42 """
43 strlen = kwargs.pop("strlen", len)
44 justfunc = kwargs.pop("justfunc", justify)
46 out_lines = []
47 newLists = []
48 lengths = [max(map(strlen, x)) + space for x in lists[:-1]]
49 # not the last one
50 lengths.append(max(map(len, lists[-1])))
51 maxLen = max(map(len, lists))
52 for i, lst in enumerate(lists):
53 nl = justfunc(lst, lengths[i], mode="left")
54 nl.extend([" " * lengths[i]] * (maxLen - len(lst)))
55 newLists.append(nl)
56 toJoin = zip(*newLists)
57 for lines in toJoin:
58 out_lines.append("".join(lines))
59 return "\n".join(out_lines)
62def justify(texts: Iterable[str], max_len: int, mode: str = "right") -> list[str]:
63 """
64 Perform ljust, center, rjust against string or list-like
65 """
66 if mode == "left":
67 return [x.ljust(max_len) for x in texts]
68 elif mode == "center":
69 return [x.center(max_len) for x in texts]
70 else:
71 return [x.rjust(max_len) for x in texts]
74# Unicode consolidation
75# ---------------------
76#
77# pprinting utility functions for generating Unicode text or
78# bytes(3.x)/str(2.x) representations of objects.
79# Try to use these as much as possible rather than rolling your own.
80#
81# When to use
82# -----------
83#
84# 1) If you're writing code internal to pandas (no I/O directly involved),
85# use pprint_thing().
86#
87# It will always return unicode text which can handled by other
88# parts of the package without breakage.
89#
90# 2) if you need to write something out to file, use
91# pprint_thing_encoded(encoding).
92#
93# If no encoding is specified, it defaults to utf-8. Since encoding pure
94# ascii with utf-8 is a no-op you can safely use the default utf-8 if you're
95# working with straight ascii.
98def _pprint_seq(
99 seq: Sequence, _nest_lvl: int = 0, max_seq_items: int | None = None, **kwds
100) -> str:
101 """
102 internal. pprinter for iterables. you should probably use pprint_thing()
103 rather than calling this directly.
105 bounds length of printed sequence, depending on options
106 """
107 if isinstance(seq, set):
108 fmt = "{{{body}}}"
109 else:
110 fmt = "[{body}]" if hasattr(seq, "__setitem__") else "({body})"
112 if max_seq_items is False:
113 nitems = len(seq)
114 else:
115 nitems = max_seq_items or get_option("max_seq_items") or len(seq)
117 s = iter(seq)
118 # handle sets, no slicing
119 r = [
120 pprint_thing(next(s), _nest_lvl + 1, max_seq_items=max_seq_items, **kwds)
121 for i in range(min(nitems, len(seq)))
122 ]
123 body = ", ".join(r)
125 if nitems < len(seq):
126 body += ", ..."
127 elif isinstance(seq, tuple) and len(seq) == 1:
128 body += ","
130 return fmt.format(body=body)
133def _pprint_dict(
134 seq: Mapping, _nest_lvl: int = 0, max_seq_items: int | None = None, **kwds
135) -> str:
136 """
137 internal. pprinter for iterables. you should probably use pprint_thing()
138 rather than calling this directly.
139 """
140 fmt = "{{{things}}}"
141 pairs = []
143 pfmt = "{key}: {val}"
145 if max_seq_items is False:
146 nitems = len(seq)
147 else:
148 nitems = max_seq_items or get_option("max_seq_items") or len(seq)
150 for k, v in list(seq.items())[:nitems]:
151 pairs.append(
152 pfmt.format(
153 key=pprint_thing(k, _nest_lvl + 1, max_seq_items=max_seq_items, **kwds),
154 val=pprint_thing(v, _nest_lvl + 1, max_seq_items=max_seq_items, **kwds),
155 )
156 )
158 if nitems < len(seq):
159 return fmt.format(things=", ".join(pairs) + ", ...")
160 else:
161 return fmt.format(things=", ".join(pairs))
164def pprint_thing(
165 thing: Any,
166 _nest_lvl: int = 0,
167 escape_chars: EscapeChars | None = None,
168 default_escapes: bool = False,
169 quote_strings: bool = False,
170 max_seq_items: int | None = None,
171) -> str:
172 """
173 This function is the sanctioned way of converting objects
174 to a string representation and properly handles nested sequences.
176 Parameters
177 ----------
178 thing : anything to be formatted
179 _nest_lvl : internal use only. pprint_thing() is mutually-recursive
180 with pprint_sequence, this argument is used to keep track of the
181 current nesting level, and limit it.
182 escape_chars : list or dict, optional
183 Characters to escape. If a dict is passed the values are the
184 replacements
185 default_escapes : bool, default False
186 Whether the input escape characters replaces or adds to the defaults
187 max_seq_items : int or None, default None
188 Pass through to other pretty printers to limit sequence printing
190 Returns
191 -------
192 str
193 """
195 def as_escaped_string(
196 thing: Any, escape_chars: EscapeChars | None = escape_chars
197 ) -> str:
198 translate = {"\t": r"\t", "\n": r"\n", "\r": r"\r"}
199 if isinstance(escape_chars, dict):
200 if default_escapes:
201 translate.update(escape_chars)
202 else:
203 translate = escape_chars
204 escape_chars = list(escape_chars.keys())
205 else:
206 escape_chars = escape_chars or ()
208 result = str(thing)
209 for c in escape_chars:
210 result = result.replace(c, translate[c])
211 return result
213 if hasattr(thing, "__next__"):
214 return str(thing)
215 elif isinstance(thing, dict) and _nest_lvl < get_option(
216 "display.pprint_nest_depth"
217 ):
218 result = _pprint_dict(
219 thing, _nest_lvl, quote_strings=True, max_seq_items=max_seq_items
220 )
221 elif is_sequence(thing) and _nest_lvl < get_option("display.pprint_nest_depth"):
222 result = _pprint_seq(
223 thing,
224 _nest_lvl,
225 escape_chars=escape_chars,
226 quote_strings=quote_strings,
227 max_seq_items=max_seq_items,
228 )
229 elif isinstance(thing, str) and quote_strings:
230 result = f"'{as_escaped_string(thing)}'"
231 else:
232 result = as_escaped_string(thing)
234 return result
237def pprint_thing_encoded(
238 object, encoding: str = "utf-8", errors: str = "replace"
239) -> bytes:
240 value = pprint_thing(object) # get unicode representation of object
241 return value.encode(encoding, errors)
244def enable_data_resource_formatter(enable: bool) -> None:
245 if "IPython" not in sys.modules:
246 # definitely not in IPython
247 return
248 from IPython import get_ipython
250 ip = get_ipython()
251 if ip is None:
252 # still not in IPython
253 return
255 formatters = ip.display_formatter.formatters
256 mimetype = "application/vnd.dataresource+json"
258 if enable:
259 if mimetype not in formatters:
260 # define tableschema formatter
261 from IPython.core.formatters import BaseFormatter
263 class TableSchemaFormatter(BaseFormatter):
264 print_method = "_repr_data_resource_"
265 _return_type = (dict,)
267 # register it:
268 formatters[mimetype] = TableSchemaFormatter()
269 # enable it if it's been disabled:
270 formatters[mimetype].enabled = True
271 else:
272 # unregister tableschema mime-type
273 if mimetype in formatters:
274 formatters[mimetype].enabled = False
277def default_pprint(thing: Any, max_seq_items: int | None = None) -> str:
278 return pprint_thing(
279 thing,
280 escape_chars=("\t", "\r", "\n"),
281 quote_strings=True,
282 max_seq_items=max_seq_items,
283 )
286def format_object_summary(
287 obj,
288 formatter: Callable,
289 is_justify: bool = True,
290 name: str | None = None,
291 indent_for_name: bool = True,
292 line_break_each_value: bool = False,
293) -> str:
294 """
295 Return the formatted obj as a unicode string
297 Parameters
298 ----------
299 obj : object
300 must be iterable and support __getitem__
301 formatter : callable
302 string formatter for an element
303 is_justify : bool
304 should justify the display
305 name : name, optional
306 defaults to the class name of the obj
307 indent_for_name : bool, default True
308 Whether subsequent lines should be indented to
309 align with the name.
310 line_break_each_value : bool, default False
311 If True, inserts a line break for each value of ``obj``.
312 If False, only break lines when the a line of values gets wider
313 than the display width.
315 .. versionadded:: 0.25.0
317 Returns
318 -------
319 summary string
320 """
321 from pandas.io.formats.console import get_console_size
322 from pandas.io.formats.format import get_adjustment
324 display_width, _ = get_console_size()
325 if display_width is None:
326 display_width = get_option("display.width") or 80
327 if name is None:
328 name = type(obj).__name__
330 if indent_for_name:
331 name_len = len(name)
332 space1 = f'\n{(" " * (name_len + 1))}'
333 space2 = f'\n{(" " * (name_len + 2))}'
334 else:
335 space1 = "\n"
336 space2 = "\n " # space for the opening '['
338 n = len(obj)
339 if line_break_each_value:
340 # If we want to vertically align on each value of obj, we need to
341 # separate values by a line break and indent the values
342 sep = ",\n " + " " * len(name)
343 else:
344 sep = ","
345 max_seq_items = get_option("display.max_seq_items") or n
347 # are we a truncated display
348 is_truncated = n > max_seq_items
350 # adj can optionally handle unicode eastern asian width
351 adj = get_adjustment()
353 def _extend_line(
354 s: str, line: str, value: str, display_width: int, next_line_prefix: str
355 ) -> tuple[str, str]:
357 if adj.len(line.rstrip()) + adj.len(value.rstrip()) >= display_width:
358 s += line.rstrip()
359 line = next_line_prefix
360 line += value
361 return s, line
363 def best_len(values: list[str]) -> int:
364 if values:
365 return max(adj.len(x) for x in values)
366 else:
367 return 0
369 close = ", "
371 if n == 0:
372 summary = f"[]{close}"
373 elif n == 1 and not line_break_each_value:
374 first = formatter(obj[0])
375 summary = f"[{first}]{close}"
376 elif n == 2 and not line_break_each_value:
377 first = formatter(obj[0])
378 last = formatter(obj[-1])
379 summary = f"[{first}, {last}]{close}"
380 else:
382 if max_seq_items == 1:
383 # If max_seq_items=1 show only last element
384 head = []
385 tail = [formatter(x) for x in obj[-1:]]
386 elif n > max_seq_items:
387 n = min(max_seq_items // 2, 10)
388 head = [formatter(x) for x in obj[:n]]
389 tail = [formatter(x) for x in obj[-n:]]
390 else:
391 head = []
392 tail = [formatter(x) for x in obj]
394 # adjust all values to max length if needed
395 if is_justify:
396 if line_break_each_value:
397 # Justify each string in the values of head and tail, so the
398 # strings will right align when head and tail are stacked
399 # vertically.
400 head, tail = _justify(head, tail)
401 elif is_truncated or not (
402 len(", ".join(head)) < display_width
403 and len(", ".join(tail)) < display_width
404 ):
405 # Each string in head and tail should align with each other
406 max_length = max(best_len(head), best_len(tail))
407 head = [x.rjust(max_length) for x in head]
408 tail = [x.rjust(max_length) for x in tail]
409 # If we are not truncated and we are only a single
410 # line, then don't justify
412 if line_break_each_value:
413 # Now head and tail are of type List[Tuple[str]]. Below we
414 # convert them into List[str], so there will be one string per
415 # value. Also truncate items horizontally if wider than
416 # max_space
417 max_space = display_width - len(space2)
418 value = tail[0]
419 for max_items in reversed(range(1, len(value) + 1)):
420 pprinted_seq = _pprint_seq(value, max_seq_items=max_items)
421 if len(pprinted_seq) < max_space:
422 break
423 head = [_pprint_seq(x, max_seq_items=max_items) for x in head]
424 tail = [_pprint_seq(x, max_seq_items=max_items) for x in tail]
426 summary = ""
427 line = space2
429 for max_items in range(len(head)):
430 word = head[max_items] + sep + " "
431 summary, line = _extend_line(summary, line, word, display_width, space2)
433 if is_truncated:
434 # remove trailing space of last line
435 summary += line.rstrip() + space2 + "..."
436 line = space2
438 for max_items in range(len(tail) - 1):
439 word = tail[max_items] + sep + " "
440 summary, line = _extend_line(summary, line, word, display_width, space2)
442 # last value: no sep added + 1 space of width used for trailing ','
443 summary, line = _extend_line(summary, line, tail[-1], display_width - 2, space2)
444 summary += line
446 # right now close is either '' or ', '
447 # Now we want to include the ']', but not the maybe space.
448 close = "]" + close.rstrip(" ")
449 summary += close
451 if len(summary) > (display_width) or line_break_each_value:
452 summary += space1
453 else: # one row
454 summary += " "
456 # remove initial space
457 summary = "[" + summary[len(space2) :]
459 return summary
462def _justify(
463 head: list[Sequence[str]], tail: list[Sequence[str]]
464) -> tuple[list[tuple[str, ...]], list[tuple[str, ...]]]:
465 """
466 Justify items in head and tail, so they are right-aligned when stacked.
468 Parameters
469 ----------
470 head : list-like of list-likes of strings
471 tail : list-like of list-likes of strings
473 Returns
474 -------
475 tuple of list of tuples of strings
476 Same as head and tail, but items are right aligned when stacked
477 vertically.
479 Examples
480 --------
481 >>> _justify([['a', 'b']], [['abc', 'abcd']])
482 ([(' a', ' b')], [('abc', 'abcd')])
483 """
484 combined = head + tail
486 # For each position for the sequences in ``combined``,
487 # find the length of the largest string.
488 max_length = [0] * len(combined[0])
489 for inner_seq in combined:
490 length = [len(item) for item in inner_seq]
491 max_length = [max(x, y) for x, y in zip(max_length, length)]
493 # justify each item in each list-like in head and tail using max_length
494 head = [
495 tuple(x.rjust(max_len) for x, max_len in zip(seq, max_length)) for seq in head
496 ]
497 tail = [
498 tuple(x.rjust(max_len) for x, max_len in zip(seq, max_length)) for seq in tail
499 ]
500 # https://github.com/python/mypy/issues/4975
501 # error: Incompatible return value type (got "Tuple[List[Sequence[str]],
502 # List[Sequence[str]]]", expected "Tuple[List[Tuple[str, ...]],
503 # List[Tuple[str, ...]]]")
504 return head, tail # type: ignore[return-value]
507class PrettyDict(Dict[_KT, _VT]):
508 """Dict extension to support abbreviated __repr__"""
510 def __repr__(self) -> str:
511 return pprint_thing(self)