Skip to content

Support custom repr() defined in classes inheriting from Mapping #1296

@vmarkovtsev

Description

@vmarkovtsev

I noticed that if I define a class like this:

from typing import Mapping

class Foo(Mapping):
    def __repr__(self) -> str:
        return "custom repr() to save space in the stack trace parameters list"

then Sentry does not call my custom repr() and serializes the object like a regular dict. That's because how _serialize_node_impl in serializer.py branches:

if obj is None or isinstance(obj, (bool, number_types)):
    ...
elif isinstance(obj, datetime):
    ...
elif isinstance(obj, Mapping):  # <- this is where all classes inherited from Mapping land
    ...
elif not isinstance(obj, serializable_str_types) and isinstance(obj, (Set, Sequence)):
    ...
obj = safe_repr(obj)  # <- I want to flow here

I need this feature much because I deal with huge dict-likes (custom dataclasses with tens of key-values), they don't fully fit in the stack trace parameters list and thus clobber the rest of the values standing after them. My handcrafted __repr__ summarizes them instead of printing all the contents and significantly reduces the envelope size. My current workaround is:

class OverriddenReprMeta(abc.ABCMeta):
    """Metaclass for OverriddenReprMapping to make isinstance() return False on custom repr()-s."""

    def __instancecheck__(self, instance):
        """Override for isinstance(instance, cls)."""
        if type(instance).__repr__ not in (object.__repr__, dict.__repr__):
            return False
        return super().__instancecheck__(instance)


class OverriddenReprMapping(Mapping, metaclass=OverriddenReprMeta):
    """Mapping that fails isinstance() check if the object contains a custom repr()."""


sentry_sdk.serializer.serialize.__globals__["Mapping"] = OverriddenReprMapping

It's a broken ugly hack, of course, but it works really well for my project.

Would you please add custom __repr__ support for classes that inherit from Mapping?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions