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

1""" 

2Printing tools. 

3""" 

4from __future__ import annotations 

5 

6import sys 

7from typing import ( 

8 Any, 

9 Callable, 

10 Dict, 

11 Iterable, 

12 Mapping, 

13 Sequence, 

14 TypeVar, 

15 Union, 

16) 

17 

18from pandas._config import get_option 

19 

20from pandas.core.dtypes.inference import is_sequence 

21 

22EscapeChars = Union[Mapping[str, str], Iterable[str]] 

23_KT = TypeVar("_KT") 

24_VT = TypeVar("_VT") 

25 

26 

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. 

31 

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) 

45 

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) 

60 

61 

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] 

72 

73 

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. 

96 

97 

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. 

104 

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})" 

111 

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) 

116 

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) 

124 

125 if nitems < len(seq): 

126 body += ", ..." 

127 elif isinstance(seq, tuple) and len(seq) == 1: 

128 body += "," 

129 

130 return fmt.format(body=body) 

131 

132 

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 = [] 

142 

143 pfmt = "{key}: {val}" 

144 

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) 

149 

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 ) 

157 

158 if nitems < len(seq): 

159 return fmt.format(things=", ".join(pairs) + ", ...") 

160 else: 

161 return fmt.format(things=", ".join(pairs)) 

162 

163 

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. 

175 

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 

189 

190 Returns 

191 ------- 

192 str 

193 """ 

194 

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 () 

207 

208 result = str(thing) 

209 for c in escape_chars: 

210 result = result.replace(c, translate[c]) 

211 return result 

212 

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) 

233 

234 return result 

235 

236 

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) 

242 

243 

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 

249 

250 ip = get_ipython() 

251 if ip is None: 

252 # still not in IPython 

253 return 

254 

255 formatters = ip.display_formatter.formatters 

256 mimetype = "application/vnd.dataresource+json" 

257 

258 if enable: 

259 if mimetype not in formatters: 

260 # define tableschema formatter 

261 from IPython.core.formatters import BaseFormatter 

262 

263 class TableSchemaFormatter(BaseFormatter): 

264 print_method = "_repr_data_resource_" 

265 _return_type = (dict,) 

266 

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 

275 

276 

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 ) 

284 

285 

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 

296 

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. 

314 

315 .. versionadded:: 0.25.0 

316 

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 

323 

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__ 

329 

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 '[' 

337 

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 

346 

347 # are we a truncated display 

348 is_truncated = n > max_seq_items 

349 

350 # adj can optionally handle unicode eastern asian width 

351 adj = get_adjustment() 

352 

353 def _extend_line( 

354 s: str, line: str, value: str, display_width: int, next_line_prefix: str 

355 ) -> tuple[str, str]: 

356 

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 

362 

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 

368 

369 close = ", " 

370 

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: 

381 

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] 

393 

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 

411 

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] 

425 

426 summary = "" 

427 line = space2 

428 

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) 

432 

433 if is_truncated: 

434 # remove trailing space of last line 

435 summary += line.rstrip() + space2 + "..." 

436 line = space2 

437 

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) 

441 

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 

445 

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 

450 

451 if len(summary) > (display_width) or line_break_each_value: 

452 summary += space1 

453 else: # one row 

454 summary += " " 

455 

456 # remove initial space 

457 summary = "[" + summary[len(space2) :] 

458 

459 return summary 

460 

461 

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. 

467 

468 Parameters 

469 ---------- 

470 head : list-like of list-likes of strings 

471 tail : list-like of list-likes of strings 

472 

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. 

478 

479 Examples 

480 -------- 

481 >>> _justify([['a', 'b']], [['abc', 'abcd']]) 

482 ([(' a', ' b')], [('abc', 'abcd')]) 

483 """ 

484 combined = head + tail 

485 

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)] 

492 

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] 

505 

506 

507class PrettyDict(Dict[_KT, _VT]): 

508 """Dict extension to support abbreviated __repr__""" 

509 

510 def __repr__(self) -> str: 

511 return pprint_thing(self)