選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

130 行
3.7KB

  1. import pprint
  2. import reprlib
  3. from typing import Any
  4. from typing import Dict
  5. from typing import IO
  6. from typing import Optional
  7. def _try_repr_or_str(obj: object) -> str:
  8. try:
  9. return repr(obj)
  10. except (KeyboardInterrupt, SystemExit):
  11. raise
  12. except BaseException:
  13. return '{}("{}")'.format(type(obj).__name__, obj)
  14. def _format_repr_exception(exc: BaseException, obj: object) -> str:
  15. try:
  16. exc_info = _try_repr_or_str(exc)
  17. except (KeyboardInterrupt, SystemExit):
  18. raise
  19. except BaseException as exc:
  20. exc_info = "unpresentable exception ({})".format(_try_repr_or_str(exc))
  21. return "<[{} raised in repr()] {} object at 0x{:x}>".format(
  22. exc_info, type(obj).__name__, id(obj)
  23. )
  24. def _ellipsize(s: str, maxsize: int) -> str:
  25. if len(s) > maxsize:
  26. i = max(0, (maxsize - 3) // 2)
  27. j = max(0, maxsize - 3 - i)
  28. return s[:i] + "..." + s[len(s) - j :]
  29. return s
  30. class SafeRepr(reprlib.Repr):
  31. """repr.Repr that limits the resulting size of repr() and includes
  32. information on exceptions raised during the call."""
  33. def __init__(self, maxsize: int) -> None:
  34. super().__init__()
  35. self.maxstring = maxsize
  36. self.maxsize = maxsize
  37. def repr(self, x: object) -> str:
  38. try:
  39. s = super().repr(x)
  40. except (KeyboardInterrupt, SystemExit):
  41. raise
  42. except BaseException as exc:
  43. s = _format_repr_exception(exc, x)
  44. return _ellipsize(s, self.maxsize)
  45. def repr_instance(self, x: object, level: int) -> str:
  46. try:
  47. s = repr(x)
  48. except (KeyboardInterrupt, SystemExit):
  49. raise
  50. except BaseException as exc:
  51. s = _format_repr_exception(exc, x)
  52. return _ellipsize(s, self.maxsize)
  53. def safeformat(obj: object) -> str:
  54. """Return a pretty printed string for the given object.
  55. Failing __repr__ functions of user instances will be represented
  56. with a short exception info.
  57. """
  58. try:
  59. return pprint.pformat(obj)
  60. except Exception as exc:
  61. return _format_repr_exception(exc, obj)
  62. def saferepr(obj: object, maxsize: int = 240) -> str:
  63. """Return a size-limited safe repr-string for the given object.
  64. Failing __repr__ functions of user instances will be represented
  65. with a short exception info and 'saferepr' generally takes
  66. care to never raise exceptions itself.
  67. This function is a wrapper around the Repr/reprlib functionality of the
  68. standard 2.6 lib.
  69. """
  70. return SafeRepr(maxsize).repr(obj)
  71. class AlwaysDispatchingPrettyPrinter(pprint.PrettyPrinter):
  72. """PrettyPrinter that always dispatches (regardless of width)."""
  73. def _format(
  74. self,
  75. object: object,
  76. stream: IO[str],
  77. indent: int,
  78. allowance: int,
  79. context: Dict[int, Any],
  80. level: int,
  81. ) -> None:
  82. # Type ignored because _dispatch is private.
  83. p = self._dispatch.get(type(object).__repr__, None) # type: ignore[attr-defined]
  84. objid = id(object)
  85. if objid in context or p is None:
  86. # Type ignored because _format is private.
  87. super()._format( # type: ignore[misc]
  88. object, stream, indent, allowance, context, level,
  89. )
  90. return
  91. context[objid] = 1
  92. p(self, object, stream, indent, allowance, context, level + 1)
  93. del context[objid]
  94. def _pformat_dispatch(
  95. object: object,
  96. indent: int = 1,
  97. width: int = 80,
  98. depth: Optional[int] = None,
  99. *,
  100. compact: bool = False,
  101. ) -> str:
  102. return AlwaysDispatchingPrettyPrinter(
  103. indent=indent, width=width, depth=depth, compact=compact
  104. ).pformat(object)