123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- import pprint
- import reprlib
- from typing import Any
- from typing import Dict
- from typing import IO
- from typing import Optional
- def _try_repr_or_str(obj: object) -> str:
- try:
- return repr(obj)
- except (KeyboardInterrupt, SystemExit):
- raise
- except BaseException:
- return f'{type(obj).__name__}("{obj}")'
- def _format_repr_exception(exc: BaseException, obj: object) -> str:
- try:
- exc_info = _try_repr_or_str(exc)
- except (KeyboardInterrupt, SystemExit):
- raise
- except BaseException as exc:
- exc_info = f"unpresentable exception ({_try_repr_or_str(exc)})"
- return "<[{} raised in repr()] {} object at 0x{:x}>".format(
- exc_info, type(obj).__name__, id(obj)
- )
- def _ellipsize(s: str, maxsize: int) -> str:
- if len(s) > maxsize:
- i = max(0, (maxsize - 3) // 2)
- j = max(0, maxsize - 3 - i)
- return s[:i] + "..." + s[len(s) - j :]
- return s
- class SafeRepr(reprlib.Repr):
- """
- repr.Repr that limits the resulting size of repr() and includes
- information on exceptions raised during the call.
- """
- def __init__(self, maxsize: Optional[int]) -> None:
- """
- :param maxsize:
- If not None, will truncate the resulting repr to that specific size, using ellipsis
- somewhere in the middle to hide the extra text.
- If None, will not impose any size limits on the returning repr.
- """
- super().__init__()
- # ``maxstring`` is used by the superclass, and needs to be an int; using a
- # very large number in case maxsize is None, meaning we want to disable
- # truncation.
- self.maxstring = maxsize if maxsize is not None else 1_000_000_000
- self.maxsize = maxsize
- def repr(self, x: object) -> str:
- try:
- s = super().repr(x)
- except (KeyboardInterrupt, SystemExit):
- raise
- except BaseException as exc:
- s = _format_repr_exception(exc, x)
- if self.maxsize is not None:
- s = _ellipsize(s, self.maxsize)
- return s
- def repr_instance(self, x: object, level: int) -> str:
- try:
- s = repr(x)
- except (KeyboardInterrupt, SystemExit):
- raise
- except BaseException as exc:
- s = _format_repr_exception(exc, x)
- if self.maxsize is not None:
- s = _ellipsize(s, self.maxsize)
- return s
- def safeformat(obj: object) -> str:
- """Return a pretty printed string for the given object.
- Failing __repr__ functions of user instances will be represented
- with a short exception info.
- """
- try:
- return pprint.pformat(obj)
- except Exception as exc:
- return _format_repr_exception(exc, obj)
- # Maximum size of overall repr of objects to display during assertion errors.
- DEFAULT_REPR_MAX_SIZE = 240
- def saferepr(obj: object, maxsize: Optional[int] = DEFAULT_REPR_MAX_SIZE) -> str:
- """Return a size-limited safe repr-string for the given object.
- Failing __repr__ functions of user instances will be represented
- with a short exception info and 'saferepr' generally takes
- care to never raise exceptions itself.
- This function is a wrapper around the Repr/reprlib functionality of the
- stdlib.
- """
- return SafeRepr(maxsize).repr(obj)
- class AlwaysDispatchingPrettyPrinter(pprint.PrettyPrinter):
- """PrettyPrinter that always dispatches (regardless of width)."""
- def _format(
- self,
- object: object,
- stream: IO[str],
- indent: int,
- allowance: int,
- context: Dict[int, Any],
- level: int,
- ) -> None:
- # Type ignored because _dispatch is private.
- p = self._dispatch.get(type(object).__repr__, None) # type: ignore[attr-defined]
- objid = id(object)
- if objid in context or p is None:
- # Type ignored because _format is private.
- super()._format( # type: ignore[misc]
- object,
- stream,
- indent,
- allowance,
- context,
- level,
- )
- return
- context[objid] = 1
- p(self, object, stream, indent, allowance, context, level + 1)
- del context[objid]
- def _pformat_dispatch(
- object: object,
- indent: int = 1,
- width: int = 80,
- depth: Optional[int] = None,
- *,
- compact: bool = False,
- ) -> str:
- return AlwaysDispatchingPrettyPrinter(
- indent=indent, width=width, depth=depth, compact=compact
- ).pformat(object)
|