_repr_html_ not showing when custom __getattr__ implemented

  Kiến thức lập trình

I’m trying to implement _repr_html_ on a python class (docs).

The class is a read-only facade for navigating a JSON-like object using attribute notation (based on example 19-5 from Fluent Python, Rahmalho (O’Reilly)). It has a custom __getatrr__ method to achieve this behavior:

from collections import abc


class FrozenJSON:
    """
    Read-only facade for navigating a JSON-like object using attribute notation.

    Notes:
        Based on example 19-5 from Fluent Python, Rahmalho (O'Reilly).
    """

    def __init__(self, mapping):
        self._data = dict(mapping)

    def __repr__(self):
        return "FrozenJSON({})".format(repr(self._data))

    def _repr_html_(self):
        return (
            "<ul>"
            + "n".join(
                f"<li><strong>{k}:</strong> {v}</li>" for k, v in self._data.items()
            )
            + "</ul>"
        )

    def __getattr__(self, name):
        if hasattr(self._data, name):
            return getattr(self._data, name)
        else:
            return FrozenJSON.build(self._data[name])

    def __dir__(self):
        return list(self._data.keys())

    @classmethod
    def build(cls, obj):
        if isinstance(obj, abc.Mapping):
            return cls(obj)
        elif isinstance(obj, abc.MutableSequence):
            return [cls.build(item) for item in obj]
        else:
            return obj

The class behaves like this:

>>> record = FrozenJSON({"name": "waldo", "age": 32, "occupation": "lost"})
>>> record.occupation
'lost'

However the _repr_html_ doesn’t get displayed in an IPython environment (I’ve tried vscode and a jupyter lab).

Commenting out the __getattr__ method causes the HTML representation to be displayed, so I’m fairly confident the issue is something to do with that.

(_repr_html_ on other objects work fine in my environments (e.g. pandas DataFrames).)

The following doesn’t help:

    def __getattr__(self, name):
        if hasattr(self._data, name):
            return getattr(self._data, name)
        elif name == "_repr_html_":
            return self._repr_html_
        else:
            return FrozenJSON.build(self._data[name])

I don’t know enough about how vscode / juptyer lab knows to call _repr_html_ rather than __repr__, and how this __getattr__ is breaking that.

Thanks in advance for any help!

LEAVE A COMMENT