diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index 4c152484d1..d2b2c41ddf 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -260,11 +260,25 @@ def safe_repr(value): rv = repr(value) if isinstance(rv, bytes): rv = rv.decode("utf-8", "replace") + + # At this point `rv` contains a bunch of literal escape codes, like + # this (exaggerated example): + # + # u"\\x2f" + # + # But we want to show this string as: + # + # u"/" try: - return rv.encode("utf-8").decode("unicode-escape") + # unicode-escape does this job, but can only decode latin1. So we + # attempt to encode in latin1. + return rv.encode("latin1").decode("unicode-escape") except Exception: + # Since usually strings aren't latin1 this can break. In those + # cases we just give up. return rv except Exception: + # If e.g. the call to `repr` already fails return u"" diff --git a/tests/test_utils.py b/tests/test_utils.py index d272669d5a..3f4ef916f3 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,7 +1,8 @@ +# coding: utf-8 import sys import os -from hypothesis import given, assume +from hypothesis import given import hypothesis.strategies as st from sentry_sdk.utils import safe_repr, exceptions_from_error_tuple @@ -17,15 +18,8 @@ def test_safe_repr_never_broken_for_strings(x): assert u"broken repr" not in r -@given(x=any_string) -def test_safe_repr_never_leaves_escapes_in(x): - if isinstance(x, bytes): - assume(b"\\u" not in x and b"\\x" not in x) - else: - assume(u"\\u" not in x and u"\\x" not in x) - r = safe_repr(x) - assert isinstance(r, text_type) - assert u"\\u" not in r and u"\\x" not in r +def test_safe_repr_regressions(): + assert u"лошадь" in safe_repr(u"лошадь") def test_abs_path():