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

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

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

86ArgLabelsT: TypeAlias = dict[str, tuple[int, int]] 

87 

88__all__ = [ 

89 "IDKey", 

90 "RepresentationPrinter", 

91 "_fixeddict_pprinter", 

92 "_tuple_pprinter", 

93 "pretty", 

94] 

95 

96 

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

98 """Safe version of getattr. 

99 

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

101 rather than raising. 

102 

103 """ 

104 try: 

105 return getattr(obj, attr, default) 

106 except Exception: 

107 return default 

108 

109 

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

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

112 printer = RepresentationPrinter() 

113 printer.pretty(obj, cycle=cycle) 

114 return printer.getvalue() 

115 

116 

117class IDKey: 

118 def __init__(self, value: object): 

119 self.value = value 

120 

121 def __hash__(self) -> int: 

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

123 

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

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

126 

127 

128class RepresentationPrinter: 

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

130 printer for a python object. 

131 

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

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

134 reinstantiate it. 

135 

136 """ 

137 

138 def __init__( 

139 self, 

140 output: TextIOBase | None = None, 

141 *, 

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

143 ) -> None: 

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

145 

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

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

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

149 """ 

150 self.broken: bool = False 

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

152 self.max_width: int = 79 

153 self.max_seq_length: int = 1000 

154 self.output_width: int = 0 

155 self.buffer_width: int = 0 

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

157 

158 root_group = Group(0) 

159 self.group_stack = [root_group] 

160 self.group_queue = GroupQueue(root_group) 

161 self.indentation: int = 0 

162 

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

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

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

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

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

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

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

170 self.singleton_pprinters.update(ipp._singleton_pprinters) 

171 self.type_pprinters.update(ipp._type_pprinters) 

172 self.deferred_pprinters.update(ipp._deferred_type_pprinters) 

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

174 self.singleton_pprinters.update(_singleton_pprinters) 

175 self.type_pprinters.update(_type_pprinters) 

176 self.deferred_pprinters.update(_deferred_type_pprinters) 

177 

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

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

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

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

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

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

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

185 if context is None: 

186 self.known_object_printers = defaultdict(list) 

187 self.slice_comments = {} 

188 else: 

189 self.known_object_printers = context.known_object_printers 

190 self.slice_comments = context.data.slice_comments 

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

192 # Track which slices we've already printed comments for, to avoid 

193 # duplicating comments when nested objects share the same slice range. 

194 self._commented_slices: set[tuple[int, int]] = set() 

195 

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

197 """Pretty print the given object.""" 

198 obj_id = id(obj) 

199 cycle = cycle or obj_id in self.stack 

200 self.stack.append(obj_id) 

201 try: 

202 with self.group(): 

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

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

205 try: 

206 printer = self.singleton_pprinters[obj_id] 

207 except (TypeError, KeyError): 

208 pass 

209 else: 

210 return printer(obj, self, cycle) 

211 

212 # Look for the _repr_pretty_ method which allows users 

213 # to define custom pretty printing. 

214 # Some objects automatically create any requested 

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

216 # callability. 

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

218 if callable(pretty_method): 

219 return pretty_method(self, cycle) 

220 

221 # Check for object-specific printers which show how this 

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

223 # This must come before type_pprinters so that sub-argument 

224 # comments are shown for tuples/dicts/etc. 

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

226 if len(printers) == 1: 

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

228 if printers: 

229 # Multiple registered functions for the same object (due to 

230 # caching, small ints, etc). Use the first if all produce 

231 # the same string; otherwise pretend none were registered. 

232 strs = set() 

233 for f in printers: 

234 p = RepresentationPrinter() 

235 f(obj, p, cycle) 

236 strs.add(p.getvalue()) 

237 if len(strs) == 1: 

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

239 

240 # Next walk the mro and check for either: 

241 # 1) a registered printer 

242 # 2) a _repr_pretty_ method 

243 for cls in obj_class.__mro__: 

244 if cls in self.type_pprinters: 

245 # printer registered in self.type_pprinters 

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

247 else: 

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

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

250 key = ( 

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

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

253 ) 

254 if key in self.deferred_pprinters: 

255 # Move the printer over to the regular registry. 

256 printer = self.deferred_pprinters.pop(key) 

257 self.type_pprinters[cls] = printer 

258 return printer(obj, self, cycle) 

259 else: 

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

261 return pprint_fields( 

262 obj, 

263 self, 

264 cycle, 

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

266 ) 

267 if hasattr(cls, "__dataclass_fields__"): 

268 return pprint_fields( 

269 obj, 

270 self, 

271 cycle, 

272 [ 

273 k 

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

275 if v.init 

276 ], 

277 ) 

278 

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

280 return _repr_pprint(obj, self, cycle) 

281 finally: 

282 self.stack.pop() 

283 

284 def _break_outer_groups(self) -> None: 

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

286 group = self.group_queue.deq() 

287 if not group: 

288 return 

289 while group.breakables: 

290 x = self.buffer.popleft() 

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

292 self.buffer_width -= x.width 

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

294 x = self.buffer.popleft() 

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

296 self.buffer_width -= x.width 

297 

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

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

300 width = len(obj) 

301 if self.buffer: 

302 text = self.buffer[-1] 

303 if not isinstance(text, Text): 

304 text = Text() 

305 self.buffer.append(text) 

306 text.add(obj, width) 

307 self.buffer_width += width 

308 self._break_outer_groups() 

309 else: 

310 self.output.write(obj) 

311 self.output_width += width 

312 

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

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

315 

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

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

318 which default to one space. 

319 

320 """ 

321 width = len(sep) 

322 group = self.group_stack[-1] 

323 if group.want_break: 

324 self.flush() 

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

326 self.output_width = self.indentation 

327 self.buffer_width = 0 

328 else: 

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

330 self.buffer_width += width 

331 self._break_outer_groups() 

332 

333 def break_(self) -> None: 

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

335 indentation.""" 

336 self.flush() 

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

338 self.output_width = self.indentation 

339 self.buffer_width = 0 

340 

341 @contextmanager 

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

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

344 self.indentation += indent 

345 try: 

346 yield 

347 finally: 

348 self.indentation -= indent 

349 

350 @contextmanager 

351 def group( 

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

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

354 """Context manager for an indented group. 

355 

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

357 

358 The first parameter specifies the indentation for the next line 

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

360 opening and closing delimiters. 

361 """ 

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

363 try: 

364 yield 

365 finally: 

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

367 

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

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

370 

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

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

373 """ 

374 if open: 

375 self.text(open) 

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

377 self.group_stack.append(group) 

378 self.group_queue.enq(group) 

379 self.indentation += indent 

380 

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

382 """See begin_group().""" 

383 self.indentation -= dedent 

384 group = self.group_stack.pop() 

385 if not group.breakables: 

386 self.group_queue.remove(group) 

387 if close: 

388 self.text(close) 

389 

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

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

392 for idx, x in enumerate(seq): 

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

394 self.text(",") 

395 self.breakable() 

396 self.text("...") 

397 return 

398 yield idx, x 

399 

400 def flush(self) -> None: 

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

402 for data in self.buffer: 

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

404 self.buffer.clear() 

405 self.buffer_width = 0 

406 

407 def getvalue(self) -> str: 

408 assert isinstance(self.output, StringIO) 

409 self.flush() 

410 return self.output.getvalue() 

411 

412 def maybe_repr_known_object_as_call( 

413 self, 

414 obj: object, 

415 cycle: bool, 

416 name: str, 

417 args: Sequence[object], 

418 kwargs: dict[str, object], 

419 arg_labels: ArgLabelsT | None = None, 

420 ) -> None: 

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

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

423 if cycle: 

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

425 # Look up comments from slice_comments if we have arg_labels 

426 comments = {} 

427 if arg_labels is not None: 

428 for key, sr in arg_labels.items(): 

429 if sr in self.slice_comments: 

430 comments[key] = self.slice_comments[sr] 

431 # If there are comments, we must use our call-style repr regardless of syntax 

432 if not comments: 

433 with suppress(Exception): 

434 # Check whether the repr is valid syntax: 

435 ast.parse(repr(obj)) 

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

437 p = RepresentationPrinter() 

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

439 p.known_object_printers = self.known_object_printers 

440 p.repr_call(name, args, kwargs) 

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

442 try: 

443 ast.parse(p.getvalue()) 

444 except Exception: 

445 return _repr_pprint(obj, self, cycle) 

446 return self.repr_call(name, args, kwargs, arg_slices=arg_labels) 

447 

448 def repr_call( 

449 self, 

450 func_name: str, 

451 args: Sequence[object], 

452 kwargs: dict[str, object], 

453 *, 

454 force_split: bool | None = None, 

455 arg_slices: ArgLabelsT | None = None, 

456 leading_comment: str | None = None, 

457 avoid_realization: bool = False, 

458 ) -> None: 

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

460 

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

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

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

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

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

466 """ 

467 assert isinstance(func_name, str) 

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

469 func_name = f"({func_name})" 

470 self.text(func_name) 

471 # Build list of (label, value) pairs. Labels are "arg[i]" for positional 

472 # args, or the keyword name. Skip slices already commented at a higher level. 

473 all_args = [(f"arg[{i}]", v) for i, v in enumerate(args)] 

474 all_args += list(kwargs.items()) 

475 arg_slices = arg_slices or {} 

476 comments: dict[str, tuple[str, tuple[int, int]]] = {} 

477 for label, sr in arg_slices.items(): 

478 if sr in self.slice_comments and sr not in self._commented_slices: 

479 comments[label] = (self.slice_comments[sr], sr) 

480 

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

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

483 force_split = True 

484 if force_split is None: 

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

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

487 p = RepresentationPrinter() 

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

489 p.known_object_printers = self.known_object_printers 

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

491 s = p.getvalue() 

492 force_split = "\n" in s 

493 

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

495 for i, (label, v) in enumerate(all_args): 

496 if force_split: 

497 if i == 0 and leading_comment: 

498 self.break_() 

499 self.text(leading_comment) 

500 self.break_() 

501 else: 

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

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

504 if not label.startswith("arg["): 

505 self.text(f"{label}=") 

506 # Mark slice as commented BEFORE printing value, so nested printers skip it 

507 entry = comments.get(label) 

508 if entry: 

509 self._commented_slices.add(entry[1]) 

510 if avoid_realization: 

511 self.text("<symbolic>") 

512 else: 

513 self.pretty(v) 

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

515 self.text(",") 

516 if entry: 

517 self.text(f" # {entry[0]}") 

518 if all_args and force_split: 

519 self.break_() 

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

521 

522 

523class Printable: 

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

525 raise NotImplementedError 

526 

527 

528class Text(Printable): 

529 def __init__(self) -> None: 

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

531 self.width: int = 0 

532 

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

534 for obj in self.objs: 

535 stream.write(obj) 

536 return output_width + self.width 

537 

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

539 self.objs.append(obj) 

540 self.width += width 

541 

542 

543class Breakable(Printable): 

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

545 self.obj = seq 

546 self.width = width 

547 self.pretty = pretty 

548 self.indentation = pretty.indentation 

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

550 self.group.breakables.append(self) 

551 

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

553 self.group.breakables.popleft() 

554 if self.group.want_break: 

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

556 return self.indentation 

557 if not self.group.breakables: 

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

559 stream.write(self.obj) 

560 return output_width + self.width 

561 

562 

563class Group(Printable): 

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

565 self.depth = depth 

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

567 self.want_break: bool = False 

568 

569 

570class GroupQueue: 

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

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

573 for group in groups: 

574 self.enq(group) 

575 

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

577 depth = group.depth 

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

579 self.queue.append([]) 

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

581 

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

583 for stack in self.queue: 

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

585 if group.breakables: 

586 del stack[idx] 

587 group.want_break = True 

588 return group 

589 for group in stack: 

590 group.want_break = True 

591 del stack[:] 

592 return None 

593 

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

595 try: 

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

597 except ValueError: 

598 pass 

599 

600 

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

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

603 

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

605 """ 

606 

607 def inner( 

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

609 ) -> None: 

610 typ = type(obj) 

611 if ( 

612 basetype is not None 

613 and typ is not basetype 

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

615 ): 

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

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

618 

619 if cycle: 

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

621 step = len(start) 

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

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

624 if idx: 

625 p.text(",") 

626 p.breakable() 

627 p.pretty(x) 

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

629 # Special case for 1-item tuples. 

630 p.text(",") 

631 

632 return inner 

633 

634 

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

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

637 assert isinstance(class_name, str) 

638 return class_name 

639 

640 

641def _set_pprinter_factory( 

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

643) -> PrettyPrintFunction: 

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

645 frozensets.""" 

646 

647 def inner( 

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

649 p: RepresentationPrinter, 

650 cycle: bool, 

651 ) -> None: 

652 typ = type(obj) 

653 if ( 

654 basetype is not None 

655 and typ is not basetype 

656 and typ.__repr__ != basetype.__repr__ 

657 ): 

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

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

660 

661 if cycle: 

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

663 if not obj: 

664 # Special case. 

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

666 else: 

667 step = len(start) 

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

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

670 items: Iterable[object] = obj 

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

672 try: 

673 items = sorted(obj) 

674 except Exception: 

675 # Sometimes the items don't sort. 

676 pass 

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

678 if idx: 

679 p.text(",") 

680 p.breakable() 

681 p.pretty(x) 

682 

683 return inner 

684 

685 

686def _dict_pprinter_factory( 

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

688) -> PrettyPrintFunction: 

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

690 dicts and dict proxies.""" 

691 

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

693 typ = type(obj) 

694 if ( 

695 basetype is not None 

696 and typ is not basetype 

697 and typ.__repr__ != basetype.__repr__ 

698 ): 

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

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

701 

702 if cycle: 

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

704 with ( 

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

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

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

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

709 warnings.catch_warnings(), 

710 ): 

711 warnings.simplefilter("ignore", BytesWarning) 

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

713 if idx: 

714 p.text(",") 

715 p.breakable() 

716 p.pretty(key) 

717 p.text(": ") 

718 p.pretty(obj[key]) 

719 

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

721 return inner 

722 

723 

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

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

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

727 p.pretty(obj.__thisclass__) 

728 p.text(",") 

729 p.breakable() 

730 p.pretty(obj.__self__) 

731 

732 

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

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

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

736 pattern = repr(obj.pattern) 

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

738 pattern = pattern[1:] 

739 prefix = "ur" 

740 else: 

741 prefix = "r" 

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

743 p.text(pattern) 

744 if obj.flags: 

745 p.text(",") 

746 p.breakable() 

747 done_one = False 

748 for flag in ( 

749 "TEMPLATE", 

750 "IGNORECASE", 

751 "LOCALE", 

752 "MULTILINE", 

753 "DOTALL", 

754 "UNICODE", 

755 "VERBOSE", 

756 "DEBUG", 

757 ): 

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

759 if done_one: 

760 p.text("|") 

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

762 done_one = True 

763 p.text(")") 

764 

765 

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

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

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

769 # and others may set it to None. 

770 

771 # Checks for a __repr__ override in the metaclass 

772 # != rather than is not because pypy compatibility 

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

774 _repr_pprint(obj, p, cycle) 

775 return 

776 

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

778 try: 

779 name = obj.__qualname__ 

780 except Exception: # pragma: no cover 

781 name = obj.__name__ 

782 if not isinstance(name, str): 

783 name = "<unknown type>" 

784 

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

786 p.text(name) 

787 else: 

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

789 

790 

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

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

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

794 output = repr(obj) 

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

796 if idx: 

797 p.break_() 

798 p.text(output_line) 

799 

800 

801def pprint_fields( 

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

803) -> None: 

804 name = get_class_name(obj.__class__) 

805 if cycle: 

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

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

808 for idx, field in enumerate(fields): 

809 if idx: 

810 p.text(",") 

811 p.breakable() 

812 p.text(field) 

813 p.text("=") 

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

815 

816 

817def _get_slice_comment( 

818 p: RepresentationPrinter, 

819 arg_labels: ArgLabelsT, 

820 key: Any, 

821) -> tuple[str, tuple[int, int]] | None: 

822 """Look up a comment for a slice, if not already printed at a higher level.""" 

823 if (sr := arg_labels.get(key)) and sr in p.slice_comments: 

824 if sr not in p._commented_slices: 

825 return (p.slice_comments[sr], sr) 

826 return None 

827 

828 

829def _tuple_pprinter(arg_labels: ArgLabelsT) -> PrettyPrintFunction: 

830 """Pretty printer for tuples that shows sub-argument comments.""" 

831 

832 def inner(obj: tuple, p: RepresentationPrinter, cycle: bool) -> None: 

833 if cycle: 

834 return p.text("(...)") 

835 

836 get = lambda i: _get_slice_comment(p, arg_labels, f"arg[{i}]") 

837 has_comments = any(get(i) for i in range(len(obj))) 

838 

839 with p.group(indent=4, open="(", close=""): 

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

841 p.break_() if has_comments else (p.breakable() if idx else None) 

842 p.pretty(x) 

843 if has_comments or idx + 1 < len(obj) or len(obj) == 1: 

844 p.text(",") 

845 if entry := get(idx): 

846 p._commented_slices.add(entry[1]) 

847 p.text(f" # {entry[0]}") 

848 if has_comments and obj: 

849 p.break_() 

850 p.text(")") 

851 

852 return inner 

853 

854 

855def _fixeddict_pprinter( 

856 arg_labels: ArgLabelsT, 

857 mapping: dict[Any, Any], 

858) -> PrettyPrintFunction: 

859 """Pretty printer for fixed_dictionaries that shows sub-argument comments.""" 

860 

861 def inner(obj: dict, p: RepresentationPrinter, cycle: bool) -> None: 

862 if cycle: 

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

864 

865 get = lambda k: _get_slice_comment(p, arg_labels, k) 

866 # Preserve mapping key order, then any optional keys (deduped) 

867 keys = list(dict.fromkeys(k for k in [*mapping, *obj] if k in obj)) 

868 has_comments = any(get(k) for k in keys) 

869 

870 with p.group(indent=4, open="{", close=""): 

871 for idx, key in p._enumerate(keys): 

872 p.break_() if has_comments else (p.breakable() if idx else None) 

873 p.pretty(key) 

874 p.text(": ") 

875 p.pretty(obj[key]) 

876 if has_comments or idx + 1 < len(keys): 

877 p.text(",") 

878 if entry := get(key): 

879 p._commented_slices.add(entry[1]) 

880 p.text(f" # {entry[0]}") 

881 if has_comments and obj: 

882 p.break_() 

883 p.text("}") 

884 

885 return inner 

886 

887 

888def _function_pprint( 

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

890 p: RepresentationPrinter, 

891 cycle: bool, 

892) -> None: 

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

894 from hypothesis.internal.reflection import get_pretty_function_description 

895 

896 p.text(get_pretty_function_description(obj)) 

897 

898 

899def _exception_pprint( 

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

901) -> None: 

902 """Base pprint for all exceptions.""" 

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

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

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

906 step = len(name) + 1 

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

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

909 if idx: 

910 p.text(",") 

911 p.breakable() 

912 p.pretty(arg) 

913 

914 

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

916 if abs(obj) < 1_000_000_000: 

917 p.text(repr(obj)) 

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

919 # add underscores for integers over ten decimal digits 

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

921 else: 

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

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

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

925 

926 

927def _repr_float_counting_nans( 

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

929) -> None: 

930 if isnan(obj): 

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

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

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

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

935 return p.text("-nan") 

936 p.text(repr(obj)) 

937 

938 

939#: printers for builtin types 

940_type_pprinters: dict[type, PrettyPrintFunction] = { 

941 int: _repr_integer, 

942 float: _repr_float_counting_nans, 

943 str: _repr_pprint, 

944 tuple: _seq_pprinter_factory("(", ")", tuple), 

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

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

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

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

949 super: _super_pprint, 

950 re.Pattern: _re_pattern_pprint, 

951 type: _type_pprint, 

952 types.FunctionType: _function_pprint, 

953 types.BuiltinFunctionType: _function_pprint, 

954 types.MethodType: _function_pprint, 

955 datetime.datetime: _repr_pprint, 

956 datetime.timedelta: _repr_pprint, 

957 BaseException: _exception_pprint, 

958 slice: _repr_pprint, 

959 range: _repr_pprint, 

960 bytes: _repr_pprint, 

961} 

962 

963#: printers for types specified by name 

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

965 

966 

967def for_type_by_name( 

968 type_module: str, type_name: str, func: PrettyPrintFunction 

969) -> PrettyPrintFunction | None: 

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

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

972 key = (type_module, type_name) 

973 oldfunc = _deferred_type_pprinters.get(key) 

974 _deferred_type_pprinters[key] = func 

975 return oldfunc 

976 

977 

978#: printers for the default singletons 

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

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

981) 

982 

983 

984def _defaultdict_pprint( 

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

986) -> None: 

987 name = obj.__class__.__name__ 

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

989 if cycle: 

990 p.text("...") 

991 else: 

992 p.pretty(obj.default_factory) 

993 p.text(",") 

994 p.breakable() 

995 p.pretty(dict(obj)) 

996 

997 

998def _ordereddict_pprint( 

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

1000) -> None: 

1001 name = obj.__class__.__name__ 

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

1003 if cycle: 

1004 p.text("...") 

1005 elif obj: 

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

1007 

1008 

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

1010 name = obj.__class__.__name__ 

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

1012 if cycle: 

1013 p.text("...") 

1014 else: 

1015 p.pretty(list(obj)) 

1016 

1017 

1018def _counter_pprint( 

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

1020) -> None: 

1021 name = obj.__class__.__name__ 

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

1023 if cycle: 

1024 p.text("...") 

1025 elif obj: 

1026 p.pretty(dict(obj)) 

1027 

1028 

1029def _repr_dataframe( 

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

1031) -> None: # pragma: no cover 

1032 with p.indent(4): 

1033 p.break_() 

1034 _repr_pprint(obj, p, cycle) 

1035 p.break_() 

1036 

1037 

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

1039 tname = get_class_name(type(obj)) 

1040 if isinstance(obj, Flag): 

1041 p.text( 

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

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

1044 ) 

1045 else: 

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

1047 

1048 

1049class _ReprDots: 

1050 def __repr__(self) -> str: 

1051 return "..." 

1052 

1053 

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

1055 args, kw = obj.args, obj.keywords 

1056 if cycle: 

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

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

1059 

1060 

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

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

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

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

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

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

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

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