Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/hypothesis/vendor/pretty.py: 20%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

510 statements  

1# This file is part of Hypothesis, which may be found at 

2# https://github.com/HypothesisWorks/hypothesis/ 

3# 

4# Copyright the Hypothesis Authors. 

5# Individual contributors are listed in AUTHORS.rst and the git log. 

6# 

7# This Source Code Form is subject to the terms of the Mozilla Public License, 

8# v. 2.0. If a copy of the MPL was not distributed with this file, You can 

9# obtain one at https://mozilla.org/MPL/2.0/. 

10 

11""" 

12Python advanced pretty printer. This pretty printer is intended to 

13replace the old `pprint` python module which does not allow developers 

14to provide their own pretty print callbacks. 

15This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`. 

16Example Usage 

17------------- 

18To get a string of the output use `pretty`:: 

19 from pretty import pretty 

20 string = pretty(complex_object) 

21Extending 

22--------- 

23The pretty library allows developers to add pretty printing rules for their 

24own objects. This process is straightforward. All you have to do is to 

25add a `_repr_pretty_` method to your object and call the methods on the 

26pretty printer passed:: 

27 class MyObject(object): 

28 def _repr_pretty_(self, p, cycle): 

29 ... 

30Here is an example implementation of a `_repr_pretty_` method for a list 

31subclass:: 

32 class MyList(list): 

33 def _repr_pretty_(self, p, cycle): 

34 if cycle: 

35 p.text('MyList(...)') 

36 else: 

37 with p.group(8, 'MyList([', '])'): 

38 for idx, item in enumerate(self): 

39 if idx: 

40 p.text(',') 

41 p.breakable() 

42 p.pretty(item) 

43The `cycle` parameter is `True` if pretty detected a cycle. You *have* to 

44react to that or the result is an infinite loop. `p.text()` just adds 

45non breaking text to the output, `p.breakable()` either adds a whitespace 

46or breaks here. If you pass it an argument it's used instead of the 

47default space. `p.pretty` prettyprints another object using the pretty print 

48method. 

49The first parameter to the `group` function specifies the extra indentation 

50of the next line. In this example the next item will either be on the same 

51line (if the items are short enough) or aligned with the right edge of the 

52opening bracket of `MyList`. 

53If you just want to indent something you can use the group function 

54without open / close parameters. You can also use this code:: 

55 with p.indent(2): 

56 ... 

57Inheritance diagram: 

58.. inheritance-diagram:: IPython.lib.pretty 

59 :parts: 3 

60:copyright: 2007 by Armin Ronacher. 

61 Portions (c) 2009 by Robert Kern. 

62:license: BSD License. 

63""" 

64 

65import ast 

66import datetime 

67import re 

68import struct 

69import sys 

70import types 

71import warnings 

72from collections import Counter, OrderedDict, defaultdict, deque 

73from collections.abc import Generator, Iterable, Sequence 

74from contextlib import contextmanager, suppress 

75from enum import Enum, Flag 

76from functools import partial 

77from io import StringIO, TextIOBase 

78from math import copysign, isnan 

79from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, Union 

80 

81if TYPE_CHECKING: 

82 from typing import TypeAlias 

83 

84 from hypothesis.control import BuildContext 

85 

86T = TypeVar("T") 

87PrettyPrintFunction: "TypeAlias" = Callable[[Any, "RepresentationPrinter", bool], None] 

88 

89__all__ = [ 

90 "IDKey", 

91 "RepresentationPrinter", 

92 "pretty", 

93] 

94 

95 

96def _safe_getattr(obj: object, attr: str, default: Optional[Any] = None) -> Any: 

97 """Safe version of getattr. 

98 

99 Same as getattr, but will return ``default`` on any Exception, 

100 rather than raising. 

101 

102 """ 

103 try: 

104 return getattr(obj, attr, default) 

105 except Exception: 

106 return default 

107 

108 

109def pretty(obj: object) -> str: 

110 """Pretty print the object's representation.""" 

111 printer = RepresentationPrinter() 

112 printer.pretty(obj) 

113 return printer.getvalue() 

114 

115 

116class IDKey: 

117 def __init__(self, value: object): 

118 self.value = value 

119 

120 def __hash__(self) -> int: 

121 return hash((type(self), id(self.value))) 

122 

123 def __eq__(self, __o: object) -> bool: 

124 return isinstance(__o, type(self)) and id(self.value) == id(__o.value) 

125 

126 

127class RepresentationPrinter: 

128 """Special pretty printer that has a `pretty` method that calls the pretty 

129 printer for a python object. 

130 

131 This class stores processing data on `self` so you must *never* use 

132 this class in a threaded environment. Always lock it or 

133 reinstantiate it. 

134 

135 """ 

136 

137 def __init__( 

138 self, 

139 output: Optional[TextIOBase] = None, 

140 *, 

141 context: Optional["BuildContext"] = None, 

142 ) -> None: 

143 """Optionally pass the output stream and the current build context. 

144 

145 We use the context to represent objects constructed by strategies by showing 

146 *how* they were constructed, and add annotations showing which parts of the 

147 minimal failing example can vary without changing the test result. 

148 """ 

149 self.broken: bool = False 

150 self.output: TextIOBase = StringIO() if output is None else output 

151 self.max_width: int = 79 

152 self.max_seq_length: int = 1000 

153 self.output_width: int = 0 

154 self.buffer_width: int = 0 

155 self.buffer: deque[Union[Breakable, Text]] = deque() 

156 

157 root_group = Group(0) 

158 self.group_stack = [root_group] 

159 self.group_queue = GroupQueue(root_group) 

160 self.indentation: int = 0 

161 

162 self.stack: list[int] = [] 

163 self.singleton_pprinters: dict[int, PrettyPrintFunction] = {} 

164 self.type_pprinters: dict[type, PrettyPrintFunction] = {} 

165 self.deferred_pprinters: dict[tuple[str, str], PrettyPrintFunction] = {} 

166 # If IPython has been imported, load up their pretty-printer registry 

167 if "IPython.lib.pretty" in sys.modules: 

168 ipp = sys.modules["IPython.lib.pretty"] 

169 self.singleton_pprinters.update(ipp._singleton_pprinters) 

170 self.type_pprinters.update(ipp._type_pprinters) 

171 self.deferred_pprinters.update(ipp._deferred_type_pprinters) 

172 # If there's overlap between our pprinters and IPython's, we'll use ours. 

173 self.singleton_pprinters.update(_singleton_pprinters) 

174 self.type_pprinters.update(_type_pprinters) 

175 self.deferred_pprinters.update(_deferred_type_pprinters) 

176 

177 # for which-parts-matter, we track a mapping from the (start_idx, end_idx) 

178 # of slices into the minimal failing example; this is per-interesting_origin 

179 # but we report each separately so that's someone else's problem here. 

180 # Invocations of self.repr_call() can report the slice for each argument, 

181 # which will then be used to look up the relevant comment if any. 

182 self.known_object_printers: dict[IDKey, list[PrettyPrintFunction]] 

183 self.slice_comments: dict[tuple[int, int], str] 

184 if context is None: 

185 self.known_object_printers = defaultdict(list) 

186 self.slice_comments = {} 

187 else: 

188 self.known_object_printers = context.known_object_printers 

189 self.slice_comments = context.data.slice_comments 

190 assert all(isinstance(k, IDKey) for k in self.known_object_printers) 

191 

192 def pretty(self, obj: object) -> None: 

193 """Pretty print the given object.""" 

194 obj_id = id(obj) 

195 cycle = obj_id in self.stack 

196 self.stack.append(obj_id) 

197 try: 

198 with self.group(): 

199 obj_class = _safe_getattr(obj, "__class__", None) or type(obj) 

200 # First try to find registered singleton printers for the type. 

201 try: 

202 printer = self.singleton_pprinters[obj_id] 

203 except (TypeError, KeyError): 

204 pass 

205 else: 

206 return printer(obj, self, cycle) 

207 

208 # Look for the _repr_pretty_ method which allows users 

209 # to define custom pretty printing. 

210 # Some objects automatically create any requested 

211 # attribute. Try to ignore most of them by checking for 

212 # callability. 

213 pretty_method = _safe_getattr(obj, "_repr_pretty_", None) 

214 if callable(pretty_method): 

215 return pretty_method(self, cycle) 

216 

217 # Next walk the mro and check for either: 

218 # 1) a registered printer 

219 # 2) a _repr_pretty_ method 

220 for cls in obj_class.__mro__: 

221 if cls in self.type_pprinters: 

222 # printer registered in self.type_pprinters 

223 return self.type_pprinters[cls](obj, self, cycle) 

224 else: 

225 # Check if the given class is specified in the deferred type 

226 # registry; move it to the regular type registry if so. 

227 key = ( 

228 _safe_getattr(cls, "__module__", None), 

229 _safe_getattr(cls, "__name__", None), 

230 ) 

231 if key in self.deferred_pprinters: 

232 # Move the printer over to the regular registry. 

233 printer = self.deferred_pprinters.pop(key) 

234 self.type_pprinters[cls] = printer 

235 return printer(obj, self, cycle) 

236 else: 

237 if hasattr(cls, "__attrs_attrs__"): 

238 return pprint_fields( 

239 obj, 

240 self, 

241 cycle, 

242 [at.name for at in cls.__attrs_attrs__ if at.init], 

243 ) 

244 if hasattr(cls, "__dataclass_fields__"): 

245 return pprint_fields( 

246 obj, 

247 self, 

248 cycle, 

249 [ 

250 k 

251 for k, v in cls.__dataclass_fields__.items() 

252 if v.init 

253 ], 

254 ) 

255 # Now check for object-specific printers which show how this 

256 # object was constructed (a Hypothesis special feature). 

257 printers = self.known_object_printers[IDKey(obj)] 

258 if len(printers) == 1: 

259 return printers[0](obj, self, cycle) 

260 elif printers: 

261 # We've ended up with multiple registered functions for the same 

262 # object, which must have been returned from multiple calls due to 

263 # e.g. memoization. If they all return the same string, we'll use 

264 # the first; otherwise we'll pretend that *none* were registered. 

265 # 

266 # It's annoying, but still seems to be the best option for which- 

267 # parts-matter too, as unreportable results aren't very useful. 

268 strs = set() 

269 for f in printers: 

270 p = RepresentationPrinter() 

271 f(obj, p, cycle) 

272 strs.add(p.getvalue()) 

273 if len(strs) == 1: 

274 return printers[0](obj, self, cycle) 

275 

276 # A user-provided repr. Find newlines and replace them with p.break_() 

277 return _repr_pprint(obj, self, cycle) 

278 finally: 

279 self.stack.pop() 

280 

281 def _break_outer_groups(self) -> None: 

282 while self.max_width < self.output_width + self.buffer_width: 

283 group = self.group_queue.deq() 

284 if not group: 

285 return 

286 while group.breakables: 

287 x = self.buffer.popleft() 

288 self.output_width = x.output(self.output, self.output_width) 

289 self.buffer_width -= x.width 

290 while self.buffer and isinstance(self.buffer[0], Text): 

291 x = self.buffer.popleft() 

292 self.output_width = x.output(self.output, self.output_width) 

293 self.buffer_width -= x.width 

294 

295 def text(self, obj: str) -> None: 

296 """Add literal text to the output.""" 

297 width = len(obj) 

298 if self.buffer: 

299 text = self.buffer[-1] 

300 if not isinstance(text, Text): 

301 text = Text() 

302 self.buffer.append(text) 

303 text.add(obj, width) 

304 self.buffer_width += width 

305 self._break_outer_groups() 

306 else: 

307 self.output.write(obj) 

308 self.output_width += width 

309 

310 def breakable(self, sep: str = " ") -> None: 

311 """Add a breakable separator to the output. 

312 

313 This does not mean that it will automatically break here. If no 

314 breaking on this position takes place the `sep` is inserted 

315 which default to one space. 

316 

317 """ 

318 width = len(sep) 

319 group = self.group_stack[-1] 

320 if group.want_break: 

321 self.flush() 

322 self.output.write("\n" + " " * self.indentation) 

323 self.output_width = self.indentation 

324 self.buffer_width = 0 

325 else: 

326 self.buffer.append(Breakable(sep, width, self)) 

327 self.buffer_width += width 

328 self._break_outer_groups() 

329 

330 def break_(self) -> None: 

331 """Explicitly insert a newline into the output, maintaining correct 

332 indentation.""" 

333 self.flush() 

334 self.output.write("\n" + " " * self.indentation) 

335 self.output_width = self.indentation 

336 self.buffer_width = 0 

337 

338 @contextmanager 

339 def indent(self, indent: int) -> Generator[None, None, None]: 

340 """`with`-statement support for indenting/dedenting.""" 

341 self.indentation += indent 

342 try: 

343 yield 

344 finally: 

345 self.indentation -= indent 

346 

347 @contextmanager 

348 def group( 

349 self, indent: int = 0, open: str = "", close: str = "" 

350 ) -> Generator[None, None, None]: 

351 """Context manager for an indented group. 

352 

353 with p.group(1, '{', '}'): 

354 

355 The first parameter specifies the indentation for the next line 

356 (usually the width of the opening text), the second and third the 

357 opening and closing delimiters. 

358 """ 

359 self.begin_group(indent=indent, open=open) 

360 try: 

361 yield 

362 finally: 

363 self.end_group(dedent=indent, close=close) 

364 

365 def begin_group(self, indent: int = 0, open: str = "") -> None: 

366 """Use the `with group(...) context manager instead. 

367 

368 The begin_group() and end_group() methods are for IPython compatibility only; 

369 see https://github.com/HypothesisWorks/hypothesis/issues/3721 for details. 

370 """ 

371 if open: 

372 self.text(open) 

373 group = Group(self.group_stack[-1].depth + 1) 

374 self.group_stack.append(group) 

375 self.group_queue.enq(group) 

376 self.indentation += indent 

377 

378 def end_group(self, dedent: int = 0, close: str = "") -> None: 

379 """See begin_group().""" 

380 self.indentation -= dedent 

381 group = self.group_stack.pop() 

382 if not group.breakables: 

383 self.group_queue.remove(group) 

384 if close: 

385 self.text(close) 

386 

387 def _enumerate(self, seq: Iterable[T]) -> Generator[tuple[int, T], None, None]: 

388 """Like enumerate, but with an upper limit on the number of items.""" 

389 for idx, x in enumerate(seq): 

390 if self.max_seq_length and idx >= self.max_seq_length: 

391 self.text(",") 

392 self.breakable() 

393 self.text("...") 

394 return 

395 yield idx, x 

396 

397 def flush(self) -> None: 

398 """Flush data that is left in the buffer.""" 

399 for data in self.buffer: 

400 self.output_width += data.output(self.output, self.output_width) 

401 self.buffer.clear() 

402 self.buffer_width = 0 

403 

404 def getvalue(self) -> str: 

405 assert isinstance(self.output, StringIO) 

406 self.flush() 

407 return self.output.getvalue() 

408 

409 def maybe_repr_known_object_as_call( 

410 self, 

411 obj: object, 

412 cycle: bool, 

413 name: str, 

414 args: Sequence[object], 

415 kwargs: dict[str, object], 

416 ) -> None: 

417 # pprint this object as a call, _unless_ the call would be invalid syntax 

418 # and the repr would be valid and there are not comments on arguments. 

419 if cycle: 

420 return self.text("<...>") 

421 # Since we don't yet track comments for sub-argument parts, we omit the 

422 # "if no comments" condition here for now. Add it when we revive 

423 # https://github.com/HypothesisWorks/hypothesis/pull/3624/ 

424 with suppress(Exception): 

425 # Check whether the repr is valid syntax: 

426 ast.parse(repr(obj)) 

427 # Given that the repr is valid syntax, check the call: 

428 p = RepresentationPrinter() 

429 p.stack = self.stack.copy() 

430 p.known_object_printers = self.known_object_printers 

431 p.repr_call(name, args, kwargs) 

432 # If the call is not valid syntax, use the repr 

433 try: 

434 ast.parse(p.getvalue()) 

435 except Exception: 

436 return _repr_pprint(obj, self, cycle) 

437 return self.repr_call(name, args, kwargs) 

438 

439 def repr_call( 

440 self, 

441 func_name: str, 

442 args: Sequence[object], 

443 kwargs: dict[str, object], 

444 *, 

445 force_split: Optional[bool] = None, 

446 arg_slices: Optional[dict[str, tuple[int, int]]] = None, 

447 leading_comment: Optional[str] = None, 

448 avoid_realization: bool = False, 

449 ) -> None: 

450 """Helper function to represent a function call. 

451 

452 - func_name, args, and kwargs should all be pretty obvious. 

453 - If split_lines, we'll force one-argument-per-line; otherwise we'll place 

454 calls that fit on a single line (and split otherwise). 

455 - arg_slices is a mapping from pos-idx or keyword to (start_idx, end_idx) 

456 of the Conjecture buffer, by which we can look up comments to add. 

457 """ 

458 assert isinstance(func_name, str) 

459 if func_name.startswith(("lambda:", "lambda ")): 

460 func_name = f"({func_name})" 

461 self.text(func_name) 

462 all_args = [(None, v) for v in args] + list(kwargs.items()) 

463 # int indicates the position of a positional argument, rather than a keyword 

464 # argument. Currently no callers use this; see #3624. 

465 comments: dict[Union[int, str], object] = { 

466 k: self.slice_comments[v] 

467 for k, v in (arg_slices or {}).items() 

468 if v in self.slice_comments 

469 } 

470 

471 if leading_comment or any(k in comments for k, _ in all_args): 

472 # We have to split one arg per line in order to leave comments on them. 

473 force_split = True 

474 if force_split is None: 

475 # We're OK with printing this call on a single line, but will it fit? 

476 # If not, we'd rather fall back to one-argument-per-line instead. 

477 p = RepresentationPrinter() 

478 p.stack = self.stack.copy() 

479 p.known_object_printers = self.known_object_printers 

480 p.repr_call("_" * self.output_width, args, kwargs, force_split=False) 

481 s = p.getvalue() 

482 force_split = "\n" in s 

483 

484 with self.group(indent=4, open="(", close=""): 

485 for i, (k, v) in enumerate(all_args): 

486 if force_split: 

487 if i == 0 and leading_comment: 

488 self.break_() 

489 self.text(leading_comment) 

490 self.break_() 

491 else: 

492 assert leading_comment is None # only passed by top-level report 

493 self.breakable(" " if i else "") 

494 if k: 

495 self.text(f"{k}=") 

496 if avoid_realization: 

497 self.text("<symbolic>") 

498 else: 

499 self.pretty(v) 

500 if force_split or i + 1 < len(all_args): 

501 self.text(",") 

502 comment = None 

503 if k is not None: 

504 comment = comments.get(i) or comments.get(k) 

505 if comment: 

506 self.text(f" # {comment}") 

507 if all_args and force_split: 

508 self.break_() 

509 self.text(")") # after dedent 

510 

511 

512class Printable: 

513 def output(self, stream: TextIOBase, output_width: int) -> int: # pragma: no cover 

514 raise NotImplementedError 

515 

516 

517class Text(Printable): 

518 def __init__(self) -> None: 

519 self.objs: list[str] = [] 

520 self.width: int = 0 

521 

522 def output(self, stream: TextIOBase, output_width: int) -> int: 

523 for obj in self.objs: 

524 stream.write(obj) 

525 return output_width + self.width 

526 

527 def add(self, obj: str, width: int) -> None: 

528 self.objs.append(obj) 

529 self.width += width 

530 

531 

532class Breakable(Printable): 

533 def __init__(self, seq: str, width: int, pretty: RepresentationPrinter) -> None: 

534 self.obj = seq 

535 self.width = width 

536 self.pretty = pretty 

537 self.indentation = pretty.indentation 

538 self.group = pretty.group_stack[-1] 

539 self.group.breakables.append(self) 

540 

541 def output(self, stream: TextIOBase, output_width: int) -> int: 

542 self.group.breakables.popleft() 

543 if self.group.want_break: 

544 stream.write("\n" + " " * self.indentation) 

545 return self.indentation 

546 if not self.group.breakables: 

547 self.pretty.group_queue.remove(self.group) 

548 stream.write(self.obj) 

549 return output_width + self.width 

550 

551 

552class Group(Printable): 

553 def __init__(self, depth: int) -> None: 

554 self.depth = depth 

555 self.breakables: deque[Breakable] = deque() 

556 self.want_break: bool = False 

557 

558 

559class GroupQueue: 

560 def __init__(self, *groups: Group) -> None: 

561 self.queue: list[list[Group]] = [] 

562 for group in groups: 

563 self.enq(group) 

564 

565 def enq(self, group: Group) -> None: 

566 depth = group.depth 

567 while depth > len(self.queue) - 1: 

568 self.queue.append([]) 

569 self.queue[depth].append(group) 

570 

571 def deq(self) -> Optional[Group]: 

572 for stack in self.queue: 

573 for idx, group in enumerate(reversed(stack)): 

574 if group.breakables: 

575 del stack[idx] 

576 group.want_break = True 

577 return group 

578 for group in stack: 

579 group.want_break = True 

580 del stack[:] 

581 return None 

582 

583 def remove(self, group: Group) -> None: 

584 try: 

585 self.queue[group.depth].remove(group) 

586 except ValueError: 

587 pass 

588 

589 

590def _seq_pprinter_factory(start: str, end: str, basetype: type) -> PrettyPrintFunction: 

591 """Factory that returns a pprint function useful for sequences. 

592 

593 Used by the default pprint for tuples, dicts, and lists. 

594 """ 

595 

596 def inner( 

597 obj: Union[tuple[object], list[object]], p: RepresentationPrinter, cycle: bool 

598 ) -> None: 

599 typ = type(obj) 

600 if ( 

601 basetype is not None 

602 and typ is not basetype 

603 and typ.__repr__ != basetype.__repr__ # type: ignore[comparison-overlap] 

604 ): 

605 # If the subclass provides its own repr, use it instead. 

606 return p.text(typ.__repr__(obj)) 

607 

608 if cycle: 

609 return p.text(start + "..." + end) 

610 step = len(start) 

611 with p.group(step, start, end): 

612 for idx, x in p._enumerate(obj): 

613 if idx: 

614 p.text(",") 

615 p.breakable() 

616 p.pretty(x) 

617 if len(obj) == 1 and type(obj) is tuple: 

618 # Special case for 1-item tuples. 

619 p.text(",") 

620 

621 return inner 

622 

623 

624def get_class_name(cls: type[object]) -> str: 

625 class_name = _safe_getattr(cls, "__qualname__", cls.__name__) 

626 assert isinstance(class_name, str) 

627 return class_name 

628 

629 

630def _set_pprinter_factory( 

631 start: str, end: str, basetype: type[object] 

632) -> PrettyPrintFunction: 

633 """Factory that returns a pprint function useful for sets and 

634 frozensets.""" 

635 

636 def inner( 

637 obj: Union[set[Any], frozenset[Any]], 

638 p: RepresentationPrinter, 

639 cycle: bool, 

640 ) -> None: 

641 typ = type(obj) 

642 if ( 

643 basetype is not None 

644 and typ is not basetype 

645 and typ.__repr__ != basetype.__repr__ 

646 ): 

647 # If the subclass provides its own repr, use it instead. 

648 return p.text(typ.__repr__(obj)) 

649 

650 if cycle: 

651 return p.text(start + "..." + end) 

652 if not obj: 

653 # Special case. 

654 p.text(get_class_name(basetype) + "()") 

655 else: 

656 step = len(start) 

657 with p.group(step, start, end): 

658 # Like dictionary keys, try to sort the items if there aren't too many 

659 items: Iterable[object] = obj 

660 if not (p.max_seq_length and len(obj) >= p.max_seq_length): 

661 try: 

662 items = sorted(obj) 

663 except Exception: 

664 # Sometimes the items don't sort. 

665 pass 

666 for idx, x in p._enumerate(items): 

667 if idx: 

668 p.text(",") 

669 p.breakable() 

670 p.pretty(x) 

671 

672 return inner 

673 

674 

675def _dict_pprinter_factory( 

676 start: str, end: str, basetype: Optional[type[object]] = None 

677) -> PrettyPrintFunction: 

678 """Factory that returns a pprint function used by the default pprint of 

679 dicts and dict proxies.""" 

680 

681 def inner(obj: dict[object, object], p: RepresentationPrinter, cycle: bool) -> None: 

682 typ = type(obj) 

683 if ( 

684 basetype is not None 

685 and typ is not basetype 

686 and typ.__repr__ != basetype.__repr__ 

687 ): 

688 # If the subclass provides its own repr, use it instead. 

689 return p.text(typ.__repr__(obj)) 

690 

691 if cycle: 

692 return p.text("{...}") 

693 # NOTE: For compatibility with Python 3.9's LL(1) 

694 # parser, this is written as a nested with-statement, 

695 # instead of a compound one. 

696 with p.group(1, start, end): 

697 # If the dict contains both "" and b"" (empty string and empty bytes), we 

698 # ignore the BytesWarning raised by `python -bb` mode. We can't use 

699 # `.items()` because it might be a non-`dict` type of mapping. 

700 with warnings.catch_warnings(): 

701 warnings.simplefilter("ignore", BytesWarning) 

702 for idx, key in p._enumerate(obj): 

703 if idx: 

704 p.text(",") 

705 p.breakable() 

706 p.pretty(key) 

707 p.text(": ") 

708 p.pretty(obj[key]) 

709 

710 inner.__name__ = f"_dict_pprinter_factory({start!r}, {end!r}, {basetype!r})" 

711 return inner 

712 

713 

714def _super_pprint(obj: Any, p: RepresentationPrinter, cycle: bool) -> None: 

715 """The pprint for the super type.""" 

716 with p.group(8, "<super: ", ">"): 

717 p.pretty(obj.__thisclass__) 

718 p.text(",") 

719 p.breakable() 

720 p.pretty(obj.__self__) 

721 

722 

723def _re_pattern_pprint(obj: re.Pattern, p: RepresentationPrinter, cycle: bool) -> None: 

724 """The pprint function for regular expression patterns.""" 

725 p.text("re.compile(") 

726 pattern = repr(obj.pattern) 

727 if pattern[:1] in "uU": # pragma: no cover 

728 pattern = pattern[1:] 

729 prefix = "ur" 

730 else: 

731 prefix = "r" 

732 pattern = prefix + pattern.replace("\\\\", "\\") 

733 p.text(pattern) 

734 if obj.flags: 

735 p.text(",") 

736 p.breakable() 

737 done_one = False 

738 for flag in ( 

739 "TEMPLATE", 

740 "IGNORECASE", 

741 "LOCALE", 

742 "MULTILINE", 

743 "DOTALL", 

744 "UNICODE", 

745 "VERBOSE", 

746 "DEBUG", 

747 ): 

748 if obj.flags & getattr(re, flag, 0): 

749 if done_one: 

750 p.text("|") 

751 p.text("re." + flag) 

752 done_one = True 

753 p.text(")") 

754 

755 

756def _type_pprint(obj: type[object], p: RepresentationPrinter, cycle: bool) -> None: 

757 """The pprint for classes and types.""" 

758 # Heap allocated types might not have the module attribute, 

759 # and others may set it to None. 

760 

761 # Checks for a __repr__ override in the metaclass 

762 # != rather than is not because pypy compatibility 

763 if type(obj).__repr__ != type.__repr__: # type: ignore[comparison-overlap] 

764 _repr_pprint(obj, p, cycle) 

765 return 

766 

767 mod = _safe_getattr(obj, "__module__", None) 

768 try: 

769 name = obj.__qualname__ 

770 except Exception: # pragma: no cover 

771 name = obj.__name__ 

772 if not isinstance(name, str): 

773 name = "<unknown type>" 

774 

775 if mod in (None, "__builtin__", "builtins", "exceptions"): 

776 p.text(name) 

777 else: 

778 p.text(mod + "." + name) 

779 

780 

781def _repr_pprint(obj: object, p: RepresentationPrinter, cycle: bool) -> None: 

782 """A pprint that just redirects to the normal repr function.""" 

783 # Find newlines and replace them with p.break_() 

784 output = repr(obj) 

785 for idx, output_line in enumerate(output.splitlines()): 

786 if idx: 

787 p.break_() 

788 p.text(output_line) 

789 

790 

791def pprint_fields( 

792 obj: object, p: RepresentationPrinter, cycle: bool, fields: Iterable[str] 

793) -> None: 

794 name = get_class_name(obj.__class__) 

795 if cycle: 

796 return p.text(f"{name}(...)") 

797 with p.group(1, name + "(", ")"): 

798 for idx, field in enumerate(fields): 

799 if idx: 

800 p.text(",") 

801 p.breakable() 

802 p.text(field) 

803 p.text("=") 

804 p.pretty(getattr(obj, field)) 

805 

806 

807def _function_pprint( 

808 obj: Union[types.FunctionType, types.BuiltinFunctionType, types.MethodType], 

809 p: RepresentationPrinter, 

810 cycle: bool, 

811) -> None: 

812 """Base pprint for all functions and builtin functions.""" 

813 from hypothesis.internal.reflection import get_pretty_function_description 

814 

815 p.text(get_pretty_function_description(obj)) 

816 

817 

818def _exception_pprint( 

819 obj: BaseException, p: RepresentationPrinter, cycle: bool 

820) -> None: 

821 """Base pprint for all exceptions.""" 

822 name = getattr(obj.__class__, "__qualname__", obj.__class__.__name__) 

823 if obj.__class__.__module__ not in ("exceptions", "builtins"): 

824 name = f"{obj.__class__.__module__}.{name}" 

825 step = len(name) + 1 

826 with p.group(step, name + "(", ")"): 

827 for idx, arg in enumerate(getattr(obj, "args", ())): 

828 if idx: 

829 p.text(",") 

830 p.breakable() 

831 p.pretty(arg) 

832 

833 

834def _repr_integer(obj: int, p: RepresentationPrinter, cycle: bool) -> None: 

835 if abs(obj) < 1_000_000_000: 

836 p.text(repr(obj)) 

837 elif abs(obj) < 10**640: 

838 # add underscores for integers over ten decimal digits 

839 p.text(f"{obj:#_d}") 

840 else: 

841 # for very very large integers, use hex because power-of-two bases are cheaper 

842 # https://docs.python.org/3/library/stdtypes.html#integer-string-conversion-length-limitation 

843 p.text(f"{obj:#_x}") 

844 

845 

846def _repr_float_counting_nans( 

847 obj: float, p: RepresentationPrinter, cycle: bool 

848) -> None: 

849 if isnan(obj): 

850 if struct.pack("!d", abs(obj)) != struct.pack("!d", float("nan")): 

851 show = hex(*struct.unpack("Q", struct.pack("d", obj))) 

852 return p.text(f"struct.unpack('d', struct.pack('Q', {show}))[0]") 

853 elif copysign(1.0, obj) == -1.0: 

854 return p.text("-nan") 

855 p.text(repr(obj)) 

856 

857 

858#: printers for builtin types 

859_type_pprinters: dict[type, PrettyPrintFunction] = { 

860 int: _repr_integer, 

861 float: _repr_float_counting_nans, 

862 str: _repr_pprint, 

863 tuple: _seq_pprinter_factory("(", ")", tuple), 

864 list: _seq_pprinter_factory("[", "]", list), 

865 dict: _dict_pprinter_factory("{", "}", dict), 

866 set: _set_pprinter_factory("{", "}", set), 

867 frozenset: _set_pprinter_factory("frozenset({", "})", frozenset), 

868 super: _super_pprint, 

869 re.Pattern: _re_pattern_pprint, 

870 type: _type_pprint, 

871 types.FunctionType: _function_pprint, 

872 types.BuiltinFunctionType: _function_pprint, 

873 types.MethodType: _function_pprint, 

874 datetime.datetime: _repr_pprint, 

875 datetime.timedelta: _repr_pprint, 

876 BaseException: _exception_pprint, 

877 slice: _repr_pprint, 

878 range: _repr_pprint, 

879 bytes: _repr_pprint, 

880} 

881 

882#: printers for types specified by name 

883_deferred_type_pprinters: dict[tuple[str, str], PrettyPrintFunction] = {} 

884 

885 

886def for_type_by_name( 

887 type_module: str, type_name: str, func: PrettyPrintFunction 

888) -> Optional[PrettyPrintFunction]: 

889 """Add a pretty printer for a type specified by the module and name of a 

890 type rather than the type object itself.""" 

891 key = (type_module, type_name) 

892 oldfunc = _deferred_type_pprinters.get(key) 

893 _deferred_type_pprinters[key] = func 

894 return oldfunc 

895 

896 

897#: printers for the default singletons 

898_singleton_pprinters: dict[int, PrettyPrintFunction] = dict.fromkeys( 

899 map(id, [None, True, False, Ellipsis, NotImplemented]), _repr_pprint 

900) 

901 

902 

903def _defaultdict_pprint( 

904 obj: defaultdict[object, object], p: RepresentationPrinter, cycle: bool 

905) -> None: 

906 name = obj.__class__.__name__ 

907 with p.group(len(name) + 1, name + "(", ")"): 

908 if cycle: 

909 p.text("...") 

910 else: 

911 p.pretty(obj.default_factory) 

912 p.text(",") 

913 p.breakable() 

914 p.pretty(dict(obj)) 

915 

916 

917def _ordereddict_pprint( 

918 obj: OrderedDict[object, object], p: RepresentationPrinter, cycle: bool 

919) -> None: 

920 name = obj.__class__.__name__ 

921 with p.group(len(name) + 1, name + "(", ")"): 

922 if cycle: 

923 p.text("...") 

924 elif obj: 

925 p.pretty(list(obj.items())) 

926 

927 

928def _deque_pprint(obj: deque[object], p: RepresentationPrinter, cycle: bool) -> None: 

929 name = obj.__class__.__name__ 

930 with p.group(len(name) + 1, name + "(", ")"): 

931 if cycle: 

932 p.text("...") 

933 else: 

934 p.pretty(list(obj)) 

935 

936 

937def _counter_pprint( 

938 obj: Counter[object], p: RepresentationPrinter, cycle: bool 

939) -> None: 

940 name = obj.__class__.__name__ 

941 with p.group(len(name) + 1, name + "(", ")"): 

942 if cycle: 

943 p.text("...") 

944 elif obj: 

945 p.pretty(dict(obj)) 

946 

947 

948def _repr_dataframe( 

949 obj: object, p: RepresentationPrinter, cycle: bool 

950) -> None: # pragma: no cover 

951 with p.indent(4): 

952 p.break_() 

953 _repr_pprint(obj, p, cycle) 

954 p.break_() 

955 

956 

957def _repr_enum(obj: Enum, p: RepresentationPrinter, cycle: bool) -> None: 

958 tname = get_class_name(type(obj)) 

959 if isinstance(obj, Flag): 

960 p.text( 

961 " | ".join(f"{tname}.{x.name}" for x in type(obj) if x & obj == x) 

962 or f"{tname}({obj.value!r})" # if no matching members 

963 ) 

964 else: 

965 p.text(f"{tname}.{obj.name}") 

966 

967 

968class _ReprDots: 

969 def __repr__(self) -> str: 

970 return "..." 

971 

972 

973def _repr_partial(obj: partial[Any], p: RepresentationPrinter, cycle: bool) -> None: 

974 args, kw = obj.args, obj.keywords 

975 if cycle: 

976 args, kw = (_ReprDots(),), {} 

977 p.repr_call(pretty(type(obj)), (obj.func, *args), kw) 

978 

979 

980for_type_by_name("collections", "defaultdict", _defaultdict_pprint) 

981for_type_by_name("collections", "OrderedDict", _ordereddict_pprint) 

982for_type_by_name("ordereddict", "OrderedDict", _ordereddict_pprint) 

983for_type_by_name("collections", "deque", _deque_pprint) 

984for_type_by_name("collections", "Counter", _counter_pprint) 

985for_type_by_name("pandas.core.frame", "DataFrame", _repr_dataframe) 

986for_type_by_name("enum", "Enum", _repr_enum) 

987for_type_by_name("functools", "partial", _repr_partial)