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

506 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 Callable, 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, Optional, TypeAlias, TypeVar 

80 

81if TYPE_CHECKING: 

82 from hypothesis.control import BuildContext 

83 

84T = TypeVar("T") 

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

86 

87__all__ = [ 

88 "IDKey", 

89 "RepresentationPrinter", 

90 "pretty", 

91] 

92 

93 

94def _safe_getattr(obj: object, attr: str, default: Any | None = None) -> Any: 

95 """Safe version of getattr. 

96 

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

98 rather than raising. 

99 

100 """ 

101 try: 

102 return getattr(obj, attr, default) 

103 except Exception: 

104 return default 

105 

106 

107def pretty(obj: object, *, cycle: bool = False) -> str: 

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

109 printer = RepresentationPrinter() 

110 printer.pretty(obj, cycle=cycle) 

111 return printer.getvalue() 

112 

113 

114class IDKey: 

115 def __init__(self, value: object): 

116 self.value = value 

117 

118 def __hash__(self) -> int: 

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

120 

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

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

123 

124 

125class RepresentationPrinter: 

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

127 printer for a python object. 

128 

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

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

131 reinstantiate it. 

132 

133 """ 

134 

135 def __init__( 

136 self, 

137 output: TextIOBase | None = None, 

138 *, 

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

140 ) -> None: 

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

142 

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

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

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

146 """ 

147 self.broken: bool = False 

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

149 self.max_width: int = 79 

150 self.max_seq_length: int = 1000 

151 self.output_width: int = 0 

152 self.buffer_width: int = 0 

153 self.buffer: deque[Breakable | Text] = deque() 

154 

155 root_group = Group(0) 

156 self.group_stack = [root_group] 

157 self.group_queue = GroupQueue(root_group) 

158 self.indentation: int = 0 

159 

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

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

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

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

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

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

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

167 self.singleton_pprinters.update(ipp._singleton_pprinters) 

168 self.type_pprinters.update(ipp._type_pprinters) 

169 self.deferred_pprinters.update(ipp._deferred_type_pprinters) 

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

171 self.singleton_pprinters.update(_singleton_pprinters) 

172 self.type_pprinters.update(_type_pprinters) 

173 self.deferred_pprinters.update(_deferred_type_pprinters) 

174 

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

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

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

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

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

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

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

182 if context is None: 

183 self.known_object_printers = defaultdict(list) 

184 self.slice_comments = {} 

185 else: 

186 self.known_object_printers = context.known_object_printers 

187 self.slice_comments = context.data.slice_comments 

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

189 

190 def pretty(self, obj: object, *, cycle: bool = False) -> None: 

191 """Pretty print the given object.""" 

192 obj_id = id(obj) 

193 cycle = cycle or obj_id in self.stack 

194 self.stack.append(obj_id) 

195 try: 

196 with self.group(): 

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

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

199 try: 

200 printer = self.singleton_pprinters[obj_id] 

201 except (TypeError, KeyError): 

202 pass 

203 else: 

204 return printer(obj, self, cycle) 

205 

206 # Look for the _repr_pretty_ method which allows users 

207 # to define custom pretty printing. 

208 # Some objects automatically create any requested 

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

210 # callability. 

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

212 if callable(pretty_method): 

213 return pretty_method(self, cycle) 

214 

215 # Next walk the mro and check for either: 

216 # 1) a registered printer 

217 # 2) a _repr_pretty_ method 

218 for cls in obj_class.__mro__: 

219 if cls in self.type_pprinters: 

220 # printer registered in self.type_pprinters 

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

222 else: 

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

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

225 key = ( 

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

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

228 ) 

229 if key in self.deferred_pprinters: 

230 # Move the printer over to the regular registry. 

231 printer = self.deferred_pprinters.pop(key) 

232 self.type_pprinters[cls] = printer 

233 return printer(obj, self, cycle) 

234 else: 

235 if hasattr(cls, "__attrs_attrs__"): # pragma: no cover 

236 return pprint_fields( 

237 obj, 

238 self, 

239 cycle, 

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

241 ) 

242 if hasattr(cls, "__dataclass_fields__"): 

243 return pprint_fields( 

244 obj, 

245 self, 

246 cycle, 

247 [ 

248 k 

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

250 if v.init 

251 ], 

252 ) 

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

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

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

256 if len(printers) == 1: 

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

258 elif printers: 

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

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

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

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

263 # 

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

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

266 strs = set() 

267 for f in printers: 

268 p = RepresentationPrinter() 

269 f(obj, p, cycle) 

270 strs.add(p.getvalue()) 

271 if len(strs) == 1: 

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

273 

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

275 return _repr_pprint(obj, self, cycle) 

276 finally: 

277 self.stack.pop() 

278 

279 def _break_outer_groups(self) -> None: 

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

281 group = self.group_queue.deq() 

282 if not group: 

283 return 

284 while group.breakables: 

285 x = self.buffer.popleft() 

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

287 self.buffer_width -= x.width 

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

289 x = self.buffer.popleft() 

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

291 self.buffer_width -= x.width 

292 

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

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

295 width = len(obj) 

296 if self.buffer: 

297 text = self.buffer[-1] 

298 if not isinstance(text, Text): 

299 text = Text() 

300 self.buffer.append(text) 

301 text.add(obj, width) 

302 self.buffer_width += width 

303 self._break_outer_groups() 

304 else: 

305 self.output.write(obj) 

306 self.output_width += width 

307 

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

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

310 

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

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

313 which default to one space. 

314 

315 """ 

316 width = len(sep) 

317 group = self.group_stack[-1] 

318 if group.want_break: 

319 self.flush() 

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

321 self.output_width = self.indentation 

322 self.buffer_width = 0 

323 else: 

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

325 self.buffer_width += width 

326 self._break_outer_groups() 

327 

328 def break_(self) -> None: 

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

330 indentation.""" 

331 self.flush() 

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

333 self.output_width = self.indentation 

334 self.buffer_width = 0 

335 

336 @contextmanager 

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

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

339 self.indentation += indent 

340 try: 

341 yield 

342 finally: 

343 self.indentation -= indent 

344 

345 @contextmanager 

346 def group( 

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

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

349 """Context manager for an indented group. 

350 

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

352 

353 The first parameter specifies the indentation for the next line 

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

355 opening and closing delimiters. 

356 """ 

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

358 try: 

359 yield 

360 finally: 

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

362 

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

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

365 

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

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

368 """ 

369 if open: 

370 self.text(open) 

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

372 self.group_stack.append(group) 

373 self.group_queue.enq(group) 

374 self.indentation += indent 

375 

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

377 """See begin_group().""" 

378 self.indentation -= dedent 

379 group = self.group_stack.pop() 

380 if not group.breakables: 

381 self.group_queue.remove(group) 

382 if close: 

383 self.text(close) 

384 

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

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

387 for idx, x in enumerate(seq): 

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

389 self.text(",") 

390 self.breakable() 

391 self.text("...") 

392 return 

393 yield idx, x 

394 

395 def flush(self) -> None: 

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

397 for data in self.buffer: 

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

399 self.buffer.clear() 

400 self.buffer_width = 0 

401 

402 def getvalue(self) -> str: 

403 assert isinstance(self.output, StringIO) 

404 self.flush() 

405 return self.output.getvalue() 

406 

407 def maybe_repr_known_object_as_call( 

408 self, 

409 obj: object, 

410 cycle: bool, 

411 name: str, 

412 args: Sequence[object], 

413 kwargs: dict[str, object], 

414 ) -> None: 

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

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

417 if cycle: 

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

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

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

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

422 with suppress(Exception): 

423 # Check whether the repr is valid syntax: 

424 ast.parse(repr(obj)) 

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

426 p = RepresentationPrinter() 

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

428 p.known_object_printers = self.known_object_printers 

429 p.repr_call(name, args, kwargs) 

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

431 try: 

432 ast.parse(p.getvalue()) 

433 except Exception: 

434 return _repr_pprint(obj, self, cycle) 

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

436 

437 def repr_call( 

438 self, 

439 func_name: str, 

440 args: Sequence[object], 

441 kwargs: dict[str, object], 

442 *, 

443 force_split: bool | None = None, 

444 arg_slices: dict[str, tuple[int, int]] | None = None, 

445 leading_comment: str | None = None, 

446 avoid_realization: bool = False, 

447 ) -> None: 

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

449 

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

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

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

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

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

455 """ 

456 assert isinstance(func_name, str) 

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

458 func_name = f"({func_name})" 

459 self.text(func_name) 

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

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

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

463 comments: dict[int | str, object] = { 

464 k: self.slice_comments[v] 

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

466 if v in self.slice_comments 

467 } 

468 

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

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

471 force_split = True 

472 if force_split is None: 

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

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

475 p = RepresentationPrinter() 

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

477 p.known_object_printers = self.known_object_printers 

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

479 s = p.getvalue() 

480 force_split = "\n" in s 

481 

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

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

484 if force_split: 

485 if i == 0 and leading_comment: 

486 self.break_() 

487 self.text(leading_comment) 

488 self.break_() 

489 else: 

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

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

492 if k: 

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

494 if avoid_realization: 

495 self.text("<symbolic>") 

496 else: 

497 self.pretty(v) 

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

499 self.text(",") 

500 comment = None 

501 if k is not None: 

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

503 if comment: 

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

505 if all_args and force_split: 

506 self.break_() 

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

508 

509 

510class Printable: 

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

512 raise NotImplementedError 

513 

514 

515class Text(Printable): 

516 def __init__(self) -> None: 

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

518 self.width: int = 0 

519 

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

521 for obj in self.objs: 

522 stream.write(obj) 

523 return output_width + self.width 

524 

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

526 self.objs.append(obj) 

527 self.width += width 

528 

529 

530class Breakable(Printable): 

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

532 self.obj = seq 

533 self.width = width 

534 self.pretty = pretty 

535 self.indentation = pretty.indentation 

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

537 self.group.breakables.append(self) 

538 

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

540 self.group.breakables.popleft() 

541 if self.group.want_break: 

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

543 return self.indentation 

544 if not self.group.breakables: 

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

546 stream.write(self.obj) 

547 return output_width + self.width 

548 

549 

550class Group(Printable): 

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

552 self.depth = depth 

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

554 self.want_break: bool = False 

555 

556 

557class GroupQueue: 

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

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

560 for group in groups: 

561 self.enq(group) 

562 

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

564 depth = group.depth 

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

566 self.queue.append([]) 

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

568 

569 def deq(self) -> Group | None: 

570 for stack in self.queue: 

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

572 if group.breakables: 

573 del stack[idx] 

574 group.want_break = True 

575 return group 

576 for group in stack: 

577 group.want_break = True 

578 del stack[:] 

579 return None 

580 

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

582 try: 

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

584 except ValueError: 

585 pass 

586 

587 

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

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

590 

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

592 """ 

593 

594 def inner( 

595 obj: tuple[object] | list[object], p: RepresentationPrinter, cycle: bool 

596 ) -> None: 

597 typ = type(obj) 

598 if ( 

599 basetype is not None 

600 and typ is not basetype 

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

602 ): 

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

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

605 

606 if cycle: 

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

608 step = len(start) 

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

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

611 if idx: 

612 p.text(",") 

613 p.breakable() 

614 p.pretty(x) 

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

616 # Special case for 1-item tuples. 

617 p.text(",") 

618 

619 return inner 

620 

621 

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

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

624 assert isinstance(class_name, str) 

625 return class_name 

626 

627 

628def _set_pprinter_factory( 

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

630) -> PrettyPrintFunction: 

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

632 frozensets.""" 

633 

634 def inner( 

635 obj: set[Any] | frozenset[Any], 

636 p: RepresentationPrinter, 

637 cycle: bool, 

638 ) -> None: 

639 typ = type(obj) 

640 if ( 

641 basetype is not None 

642 and typ is not basetype 

643 and typ.__repr__ != basetype.__repr__ 

644 ): 

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

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

647 

648 if cycle: 

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

650 if not obj: 

651 # Special case. 

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

653 else: 

654 step = len(start) 

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

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

657 items: Iterable[object] = obj 

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

659 try: 

660 items = sorted(obj) 

661 except Exception: 

662 # Sometimes the items don't sort. 

663 pass 

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

665 if idx: 

666 p.text(",") 

667 p.breakable() 

668 p.pretty(x) 

669 

670 return inner 

671 

672 

673def _dict_pprinter_factory( 

674 start: str, end: str, basetype: type[object] | None = None 

675) -> PrettyPrintFunction: 

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

677 dicts and dict proxies.""" 

678 

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

680 typ = type(obj) 

681 if ( 

682 basetype is not None 

683 and typ is not basetype 

684 and typ.__repr__ != basetype.__repr__ 

685 ): 

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

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

688 

689 if cycle: 

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

691 with ( 

692 p.group(1, start, end), 

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

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

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

696 warnings.catch_warnings(), 

697 ): 

698 warnings.simplefilter("ignore", BytesWarning) 

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

700 if idx: 

701 p.text(",") 

702 p.breakable() 

703 p.pretty(key) 

704 p.text(": ") 

705 p.pretty(obj[key]) 

706 

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

708 return inner 

709 

710 

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

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

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

714 p.pretty(obj.__thisclass__) 

715 p.text(",") 

716 p.breakable() 

717 p.pretty(obj.__self__) 

718 

719 

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

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

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

723 pattern = repr(obj.pattern) 

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

725 pattern = pattern[1:] 

726 prefix = "ur" 

727 else: 

728 prefix = "r" 

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

730 p.text(pattern) 

731 if obj.flags: 

732 p.text(",") 

733 p.breakable() 

734 done_one = False 

735 for flag in ( 

736 "TEMPLATE", 

737 "IGNORECASE", 

738 "LOCALE", 

739 "MULTILINE", 

740 "DOTALL", 

741 "UNICODE", 

742 "VERBOSE", 

743 "DEBUG", 

744 ): 

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

746 if done_one: 

747 p.text("|") 

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

749 done_one = True 

750 p.text(")") 

751 

752 

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

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

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

756 # and others may set it to None. 

757 

758 # Checks for a __repr__ override in the metaclass 

759 # != rather than is not because pypy compatibility 

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

761 _repr_pprint(obj, p, cycle) 

762 return 

763 

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

765 try: 

766 name = obj.__qualname__ 

767 except Exception: # pragma: no cover 

768 name = obj.__name__ 

769 if not isinstance(name, str): 

770 name = "<unknown type>" 

771 

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

773 p.text(name) 

774 else: 

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

776 

777 

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

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

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

781 output = repr(obj) 

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

783 if idx: 

784 p.break_() 

785 p.text(output_line) 

786 

787 

788def pprint_fields( 

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

790) -> None: 

791 name = get_class_name(obj.__class__) 

792 if cycle: 

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

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

795 for idx, field in enumerate(fields): 

796 if idx: 

797 p.text(",") 

798 p.breakable() 

799 p.text(field) 

800 p.text("=") 

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

802 

803 

804def _function_pprint( 

805 obj: types.FunctionType | types.BuiltinFunctionType | types.MethodType, 

806 p: RepresentationPrinter, 

807 cycle: bool, 

808) -> None: 

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

810 from hypothesis.internal.reflection import get_pretty_function_description 

811 

812 p.text(get_pretty_function_description(obj)) 

813 

814 

815def _exception_pprint( 

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

817) -> None: 

818 """Base pprint for all exceptions.""" 

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

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

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

822 step = len(name) + 1 

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

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

825 if idx: 

826 p.text(",") 

827 p.breakable() 

828 p.pretty(arg) 

829 

830 

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

832 if abs(obj) < 1_000_000_000: 

833 p.text(repr(obj)) 

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

835 # add underscores for integers over ten decimal digits 

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

837 else: 

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

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

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

841 

842 

843def _repr_float_counting_nans( 

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

845) -> None: 

846 if isnan(obj): 

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

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

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

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

851 return p.text("-nan") 

852 p.text(repr(obj)) 

853 

854 

855#: printers for builtin types 

856_type_pprinters: dict[type, PrettyPrintFunction] = { 

857 int: _repr_integer, 

858 float: _repr_float_counting_nans, 

859 str: _repr_pprint, 

860 tuple: _seq_pprinter_factory("(", ")", tuple), 

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

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

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

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

865 super: _super_pprint, 

866 re.Pattern: _re_pattern_pprint, 

867 type: _type_pprint, 

868 types.FunctionType: _function_pprint, 

869 types.BuiltinFunctionType: _function_pprint, 

870 types.MethodType: _function_pprint, 

871 datetime.datetime: _repr_pprint, 

872 datetime.timedelta: _repr_pprint, 

873 BaseException: _exception_pprint, 

874 slice: _repr_pprint, 

875 range: _repr_pprint, 

876 bytes: _repr_pprint, 

877} 

878 

879#: printers for types specified by name 

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

881 

882 

883def for_type_by_name( 

884 type_module: str, type_name: str, func: PrettyPrintFunction 

885) -> PrettyPrintFunction | None: 

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

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

888 key = (type_module, type_name) 

889 oldfunc = _deferred_type_pprinters.get(key) 

890 _deferred_type_pprinters[key] = func 

891 return oldfunc 

892 

893 

894#: printers for the default singletons 

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

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

897) 

898 

899 

900def _defaultdict_pprint( 

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

902) -> None: 

903 name = obj.__class__.__name__ 

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

905 if cycle: 

906 p.text("...") 

907 else: 

908 p.pretty(obj.default_factory) 

909 p.text(",") 

910 p.breakable() 

911 p.pretty(dict(obj)) 

912 

913 

914def _ordereddict_pprint( 

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

916) -> None: 

917 name = obj.__class__.__name__ 

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

919 if cycle: 

920 p.text("...") 

921 elif obj: 

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

923 

924 

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

926 name = obj.__class__.__name__ 

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

928 if cycle: 

929 p.text("...") 

930 else: 

931 p.pretty(list(obj)) 

932 

933 

934def _counter_pprint( 

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

936) -> None: 

937 name = obj.__class__.__name__ 

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

939 if cycle: 

940 p.text("...") 

941 elif obj: 

942 p.pretty(dict(obj)) 

943 

944 

945def _repr_dataframe( 

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

947) -> None: # pragma: no cover 

948 with p.indent(4): 

949 p.break_() 

950 _repr_pprint(obj, p, cycle) 

951 p.break_() 

952 

953 

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

955 tname = get_class_name(type(obj)) 

956 if isinstance(obj, Flag): 

957 p.text( 

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

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

960 ) 

961 else: 

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

963 

964 

965class _ReprDots: 

966 def __repr__(self) -> str: 

967 return "..." 

968 

969 

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

971 args, kw = obj.args, obj.keywords 

972 if cycle: 

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

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

975 

976 

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

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

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

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

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

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

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

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