Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
repr.py283 linesDownload Raw Back to debug
1"""Object representations for debugging purposes. Unlike the default2repr, these expose more information and produce HTML instead of ASCII.3 4Together with the CSS and JavaScript of the debugger this gives a5colorful and more compact output.6"""7 8from __future__ import annotations9 10import codecs11import re12import sys13import typing as t14from collections import deque15from traceback import format_exception_only16 17from markupsafe import escape18 19missing = object()20_paragraph_re = re.compile(r"(?:\r\n|\r|\n){2,}")21RegexType = type(_paragraph_re)22 23HELP_HTML = """\24<div class=box>25  <h3>%(title)s</h3>26  <pre class=help>%(text)s</pre>27</div>\28"""29OBJECT_DUMP_HTML = """\30<div class=box>31  <h3>%(title)s</h3>32  %(repr)s33  <table>%(items)s</table>34</div>\35"""36 37 38def debug_repr(obj: object) -> str:39    """Creates a debug repr of an object as HTML string."""40    return DebugReprGenerator().repr(obj)41 42 43def dump(obj: object = missing) -> None:44    """Print the object details to stdout._write (for the interactive45    console of the web debugger.46    """47    gen = DebugReprGenerator()48    if obj is missing:49        rv = gen.dump_locals(sys._getframe(1).f_locals)50    else:51        rv = gen.dump_object(obj)52    sys.stdout._write(rv)  # type: ignore53 54 55class _Helper:56    """Displays an HTML version of the normal help, for the interactive57    debugger only because it requires a patched sys.stdout.58    """59 60    def __repr__(self) -> str:61        return "Type help(object) for help about object."62 63    def __call__(self, topic: t.Any | None = None) -> None:64        if topic is None:65            sys.stdout._write(f"<span class=help>{self!r}</span>")  # type: ignore66            return67        import pydoc68 69        pydoc.help(topic)70        rv = sys.stdout.reset()  # type: ignore71        paragraphs = _paragraph_re.split(rv)72        if len(paragraphs) > 1:73            title = paragraphs[0]74            text = "\n\n".join(paragraphs[1:])75        else:76            title = "Help"77            text = paragraphs[0]78        sys.stdout._write(HELP_HTML % {"title": title, "text": text})  # type: ignore79 80 81helper = _Helper()82 83 84def _add_subclass_info(inner: str, obj: object, base: type | tuple[type, ...]) -> str:85    if isinstance(base, tuple):86        for cls in base:87            if type(obj) is cls:88                return inner89    elif type(obj) is base:90        return inner91    module = ""92    if obj.__class__.__module__ not in ("__builtin__", "exceptions"):93        module = f'<span class="module">{obj.__class__.__module__}.</span>'94    return f"{module}{type(obj).__name__}({inner})"95 96 97def _sequence_repr_maker(98    left: str, right: str, base: type, limit: int = 899) -> t.Callable[[DebugReprGenerator, t.Iterable[t.Any], bool], str]:100    def proxy(self: DebugReprGenerator, obj: t.Iterable[t.Any], recursive: bool) -> str:101        if recursive:102            return _add_subclass_info(f"{left}...{right}", obj, base)103        buf = [left]104        have_extended_section = False105        for idx, item in enumerate(obj):106            if idx:107                buf.append(", ")108            if idx == limit:109                buf.append('<span class="extended">')110                have_extended_section = True111            buf.append(self.repr(item))112        if have_extended_section:113            buf.append("</span>")114        buf.append(right)115        return _add_subclass_info("".join(buf), obj, base)116 117    return proxy118 119 120class DebugReprGenerator:121    def __init__(self) -> None:122        self._stack: list[t.Any] = []123 124    list_repr = _sequence_repr_maker("[", "]", list)125    tuple_repr = _sequence_repr_maker("(", ")", tuple)126    set_repr = _sequence_repr_maker("set([", "])", set)127    frozenset_repr = _sequence_repr_maker("frozenset([", "])", frozenset)128    deque_repr = _sequence_repr_maker(129        '<span class="module">collections.</span>deque([', "])", deque130    )131 132    def regex_repr(self, obj: t.Pattern[t.AnyStr]) -> str:133        pattern = repr(obj.pattern)134        pattern = codecs.decode(pattern, "unicode-escape", "ignore")135        pattern = f"r{pattern}"136        return f're.compile(<span class="string regex">{pattern}</span>)'137 138    def string_repr(self, obj: str | bytes, limit: int = 70) -> str:139        buf = ['<span class="string">']140        r = repr(obj)141 142        # shorten the repr when the hidden part would be at least 3 chars143        if len(r) - limit > 2:144            buf.extend(145                (146                    escape(r[:limit]),147                    '<span class="extended">',148                    escape(r[limit:]),149                    "</span>",150                )151            )152        else:153            buf.append(escape(r))154 155        buf.append("</span>")156        out = "".join(buf)157 158        # if the repr looks like a standard string, add subclass info if needed159        if r[0] in "'\"" or (r[0] == "b" and r[1] in "'\""):160            return _add_subclass_info(out, obj, (bytes, str))161 162        # otherwise, assume the repr distinguishes the subclass already163        return out164 165    def dict_repr(166        self,167        d: dict[int, None] | dict[str, int] | dict[str | int, int],168        recursive: bool,169        limit: int = 5,170    ) -> str:171        if recursive:172            return _add_subclass_info("{...}", d, dict)173        buf = ["{"]174        have_extended_section = False175        for idx, (key, value) in enumerate(d.items()):176            if idx:177                buf.append(", ")178            if idx == limit - 1:179                buf.append('<span class="extended">')180                have_extended_section = True181            buf.append(182                f'<span class="pair"><span class="key">{self.repr(key)}</span>:'183                f' <span class="value">{self.repr(value)}</span></span>'184            )185        if have_extended_section:186            buf.append("</span>")187        buf.append("}")188        return _add_subclass_info("".join(buf), d, dict)189 190    def object_repr(self, obj: t.Any) -> str:191        r = repr(obj)192        return f'<span class="object">{escape(r)}</span>'193 194    def dispatch_repr(self, obj: t.Any, recursive: bool) -> str:195        if obj is helper:196            return f'<span class="help">{helper!r}</span>'197        if isinstance(obj, (int, float, complex)):198            return f'<span class="number">{obj!r}</span>'199        if isinstance(obj, str) or isinstance(obj, bytes):200            return self.string_repr(obj)201        if isinstance(obj, RegexType):202            return self.regex_repr(obj)203        if isinstance(obj, list):204            return self.list_repr(obj, recursive)205        if isinstance(obj, tuple):206            return self.tuple_repr(obj, recursive)207        if isinstance(obj, set):208            return self.set_repr(obj, recursive)209        if isinstance(obj, frozenset):210            return self.frozenset_repr(obj, recursive)211        if isinstance(obj, dict):212            return self.dict_repr(obj, recursive)213        if isinstance(obj, deque):214            return self.deque_repr(obj, recursive)215        return self.object_repr(obj)216 217    def fallback_repr(self) -> str:218        try:219            info = "".join(format_exception_only(*sys.exc_info()[:2]))220        except Exception:221            info = "?"222        return (223            '<span class="brokenrepr">'224            f"&lt;broken repr ({escape(info.strip())})&gt;</span>"225        )226 227    def repr(self, obj: object) -> str:228        recursive = False229        for item in self._stack:230            if item is obj:231                recursive = True232                break233        self._stack.append(obj)234        try:235            try:236                return self.dispatch_repr(obj, recursive)237            except Exception:238                return self.fallback_repr()239        finally:240            self._stack.pop()241 242    def dump_object(self, obj: object) -> str:243        repr = None244        items: list[tuple[str, str]] | None = None245 246        if isinstance(obj, dict):247            title = "Contents of"248            items = []249            for key, value in obj.items():250                if not isinstance(key, str):251                    items = None252                    break253                items.append((key, self.repr(value)))254        if items is None:255            items = []256            repr = self.repr(obj)257            for key in dir(obj):258                try:259                    items.append((key, self.repr(getattr(obj, key))))260                except Exception:261                    pass262            title = "Details for"263        title += f" {object.__repr__(obj)[1:-1]}"264        return self.render_object_dump(items, title, repr)265 266    def dump_locals(self, d: dict[str, t.Any]) -> str:267        items = [(key, self.repr(value)) for key, value in d.items()]268        return self.render_object_dump(items, "Local variables in frame")269 270    def render_object_dump(271        self, items: list[tuple[str, str]], title: str, repr: str | None = None272    ) -> str:273        html_items = []274        for key, value in items:275            html_items.append(f"<tr><th>{escape(key)}<td><pre class=repr>{value}</pre>")276        if not html_items:277            html_items.append("<tr><td><em>Nothing</em>")278        return OBJECT_DUMP_HTML % {279            "title": escape(title),280            "repr": f"<pre class=repr>{repr if repr else ''}</pre>",281            "items": "\n".join(html_items),282        }283 
codekingpro/portable-devtools · Team Ai