We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Sets are not breadth-limited
I've got huge repr-s of sets that are included in the stack trace variables without truncation. As I see in `serializer.py`, `Mapping` and `Sequence` are limited to 10 items, but `typing.Set` is not handled yet.

![image](https://user-images.githubusercontent.com/2793551/90019532-d5f14300-dcae-11ea-9011-2d7e6a13d477.png)



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sentry_sdk/serializer.py`
Content:
```
1 import sys
2 
3 from datetime import datetime
4 
5 from sentry_sdk.utils import (
6     AnnotatedValue,
7     capture_internal_exception,
8     disable_capture_event,
9     safe_repr,
10     strip_string,
11     format_timestamp,
12 )
13 
14 from sentry_sdk._compat import text_type, PY2, string_types, number_types, iteritems
15 
16 from sentry_sdk._types import MYPY
17 
18 if MYPY:
19     from types import TracebackType
20 
21     from typing import Any
22     from typing import Dict
23     from typing import List
24     from typing import Optional
25     from typing import Callable
26     from typing import Union
27     from typing import ContextManager
28     from typing import Type
29 
30     from sentry_sdk._types import NotImplementedType, Event
31 
32     ReprProcessor = Callable[[Any, Dict[str, Any]], Union[NotImplementedType, str]]
33     Segment = Union[str, int]
34 
35 
36 if PY2:
37     # Importing ABCs from collections is deprecated, and will stop working in 3.8
38     # https://github.com/python/cpython/blob/master/Lib/collections/__init__.py#L49
39     from collections import Mapping, Sequence
40 
41     serializable_str_types = string_types
42 
43 else:
44     # New in 3.3
45     # https://docs.python.org/3/library/collections.abc.html
46     from collections.abc import Mapping, Sequence
47 
48     # Bytes are technically not strings in Python 3, but we can serialize them
49     serializable_str_types = (str, bytes)
50 
51 MAX_DATABAG_DEPTH = 5
52 MAX_DATABAG_BREADTH = 10
53 CYCLE_MARKER = u"<cyclic>"
54 
55 
56 global_repr_processors = []  # type: List[ReprProcessor]
57 
58 
59 def add_global_repr_processor(processor):
60     # type: (ReprProcessor) -> None
61     global_repr_processors.append(processor)
62 
63 
64 class Memo(object):
65     __slots__ = ("_ids", "_objs")
66 
67     def __init__(self):
68         # type: () -> None
69         self._ids = {}  # type: Dict[int, Any]
70         self._objs = []  # type: List[Any]
71 
72     def memoize(self, obj):
73         # type: (Any) -> ContextManager[bool]
74         self._objs.append(obj)
75         return self
76 
77     def __enter__(self):
78         # type: () -> bool
79         obj = self._objs[-1]
80         if id(obj) in self._ids:
81             return True
82         else:
83             self._ids[id(obj)] = obj
84             return False
85 
86     def __exit__(
87         self,
88         ty,  # type: Optional[Type[BaseException]]
89         value,  # type: Optional[BaseException]
90         tb,  # type: Optional[TracebackType]
91     ):
92         # type: (...) -> None
93         self._ids.pop(id(self._objs.pop()), None)
94 
95 
96 def serialize(event, **kwargs):
97     # type: (Event, **Any) -> Event
98     memo = Memo()
99     path = []  # type: List[Segment]
100     meta_stack = []  # type: List[Dict[str, Any]]
101 
102     def _annotate(**meta):
103         # type: (**Any) -> None
104         while len(meta_stack) <= len(path):
105             try:
106                 segment = path[len(meta_stack) - 1]
107                 node = meta_stack[-1].setdefault(text_type(segment), {})
108             except IndexError:
109                 node = {}
110 
111             meta_stack.append(node)
112 
113         meta_stack[-1].setdefault("", {}).update(meta)
114 
115     def _should_repr_strings():
116         # type: () -> Optional[bool]
117         """
118         By default non-serializable objects are going through
119         safe_repr(). For certain places in the event (local vars) we
120         want to repr() even things that are JSON-serializable to
121         make their type more apparent. For example, it's useful to
122         see the difference between a unicode-string and a bytestring
123         when viewing a stacktrace.
124 
125         For container-types we still don't do anything different.
126         Generally we just try to make the Sentry UI present exactly
127         what a pretty-printed repr would look like.
128 
129         :returns: `True` if we are somewhere in frame variables, and `False` if
130             we are in a position where we will never encounter frame variables
131             when recursing (for example, we're in `event.extra`). `None` if we
132             are not (yet) in frame variables, but might encounter them when
133             recursing (e.g.  we're in `event.exception`)
134         """
135         try:
136             p0 = path[0]
137             if p0 == "stacktrace" and path[1] == "frames" and path[3] == "vars":
138                 return True
139 
140             if (
141                 p0 in ("threads", "exception")
142                 and path[1] == "values"
143                 and path[3] == "stacktrace"
144                 and path[4] == "frames"
145                 and path[6] == "vars"
146             ):
147                 return True
148         except IndexError:
149             return None
150 
151         return False
152 
153     def _is_databag():
154         # type: () -> Optional[bool]
155         """
156         A databag is any value that we need to trim.
157 
158         :returns: Works like `_should_repr_strings()`. `True` for "yes",
159             `False` for :"no", `None` for "maybe soon".
160         """
161         try:
162             rv = _should_repr_strings()
163             if rv in (True, None):
164                 return rv
165 
166             p0 = path[0]
167             if p0 == "request" and path[1] == "data":
168                 return True
169 
170             if p0 == "breadcrumbs":
171                 path[1]
172                 return True
173 
174             if p0 == "extra":
175                 return True
176 
177         except IndexError:
178             return None
179 
180         return False
181 
182     def _serialize_node(
183         obj,  # type: Any
184         is_databag=None,  # type: Optional[bool]
185         should_repr_strings=None,  # type: Optional[bool]
186         segment=None,  # type: Optional[Segment]
187         remaining_breadth=None,  # type: Optional[int]
188         remaining_depth=None,  # type: Optional[int]
189     ):
190         # type: (...) -> Any
191         if segment is not None:
192             path.append(segment)
193 
194         try:
195             with memo.memoize(obj) as result:
196                 if result:
197                     return CYCLE_MARKER
198 
199                 return _serialize_node_impl(
200                     obj,
201                     is_databag=is_databag,
202                     should_repr_strings=should_repr_strings,
203                     remaining_depth=remaining_depth,
204                     remaining_breadth=remaining_breadth,
205                 )
206         except BaseException:
207             capture_internal_exception(sys.exc_info())
208 
209             if is_databag:
210                 return u"<failed to serialize, use init(debug=True) to see error logs>"
211 
212             return None
213         finally:
214             if segment is not None:
215                 path.pop()
216                 del meta_stack[len(path) + 1 :]
217 
218     def _flatten_annotated(obj):
219         # type: (Any) -> Any
220         if isinstance(obj, AnnotatedValue):
221             _annotate(**obj.metadata)
222             obj = obj.value
223         return obj
224 
225     def _serialize_node_impl(
226         obj, is_databag, should_repr_strings, remaining_depth, remaining_breadth
227     ):
228         # type: (Any, Optional[bool], Optional[bool], Optional[int], Optional[int]) -> Any
229         if should_repr_strings is None:
230             should_repr_strings = _should_repr_strings()
231 
232         if is_databag is None:
233             is_databag = _is_databag()
234 
235         if is_databag and remaining_depth is None:
236             remaining_depth = MAX_DATABAG_DEPTH
237         if is_databag and remaining_breadth is None:
238             remaining_breadth = MAX_DATABAG_BREADTH
239 
240         obj = _flatten_annotated(obj)
241 
242         if remaining_depth is not None and remaining_depth <= 0:
243             _annotate(rem=[["!limit", "x"]])
244             if is_databag:
245                 return _flatten_annotated(strip_string(safe_repr(obj)))
246             return None
247 
248         if is_databag and global_repr_processors:
249             hints = {"memo": memo, "remaining_depth": remaining_depth}
250             for processor in global_repr_processors:
251                 result = processor(obj, hints)
252                 if result is not NotImplemented:
253                     return _flatten_annotated(result)
254 
255         if obj is None or isinstance(obj, (bool, number_types)):
256             return obj if not should_repr_strings else safe_repr(obj)
257 
258         elif isinstance(obj, datetime):
259             return (
260                 text_type(format_timestamp(obj))
261                 if not should_repr_strings
262                 else safe_repr(obj)
263             )
264 
265         elif isinstance(obj, Mapping):
266             # Create temporary copy here to avoid calling too much code that
267             # might mutate our dictionary while we're still iterating over it.
268             obj = dict(iteritems(obj))
269 
270             rv_dict = {}  # type: Dict[str, Any]
271             i = 0
272 
273             for k, v in iteritems(obj):
274                 if remaining_breadth is not None and i >= remaining_breadth:
275                     _annotate(len=len(obj))
276                     break
277 
278                 str_k = text_type(k)
279                 v = _serialize_node(
280                     v,
281                     segment=str_k,
282                     should_repr_strings=should_repr_strings,
283                     is_databag=is_databag,
284                     remaining_depth=remaining_depth - 1
285                     if remaining_depth is not None
286                     else None,
287                     remaining_breadth=remaining_breadth,
288                 )
289                 rv_dict[str_k] = v
290                 i += 1
291 
292             return rv_dict
293 
294         elif not isinstance(obj, serializable_str_types) and isinstance(obj, Sequence):
295             rv_list = []
296 
297             for i, v in enumerate(obj):
298                 if remaining_breadth is not None and i >= remaining_breadth:
299                     _annotate(len=len(obj))
300                     break
301 
302                 rv_list.append(
303                     _serialize_node(
304                         v,
305                         segment=i,
306                         should_repr_strings=should_repr_strings,
307                         is_databag=is_databag,
308                         remaining_depth=remaining_depth - 1
309                         if remaining_depth is not None
310                         else None,
311                         remaining_breadth=remaining_breadth,
312                     )
313                 )
314 
315             return rv_list
316 
317         if should_repr_strings:
318             obj = safe_repr(obj)
319         else:
320             if isinstance(obj, bytes):
321                 obj = obj.decode("utf-8", "replace")
322 
323             if not isinstance(obj, string_types):
324                 obj = safe_repr(obj)
325 
326         return _flatten_annotated(strip_string(obj))
327 
328     disable_capture_event.set(True)
329     try:
330         rv = _serialize_node(event, **kwargs)
331         if meta_stack and isinstance(rv, dict):
332             rv["_meta"] = meta_stack[0]
333 
334         return rv
335     finally:
336         disable_capture_event.set(False)
337
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/sentry_sdk/serializer.py b/sentry_sdk/serializer.py
--- a/sentry_sdk/serializer.py
+++ b/sentry_sdk/serializer.py
@@ -36,14 +36,14 @@
 if PY2:
     # Importing ABCs from collections is deprecated, and will stop working in 3.8
     # https://github.com/python/cpython/blob/master/Lib/collections/__init__.py#L49
-    from collections import Mapping, Sequence
+    from collections import Mapping, Sequence, Set
 
     serializable_str_types = string_types
 
 else:
     # New in 3.3
     # https://docs.python.org/3/library/collections.abc.html
-    from collections.abc import Mapping, Sequence
+    from collections.abc import Mapping, Sequence, Set
 
     # Bytes are technically not strings in Python 3, but we can serialize them
     serializable_str_types = (str, bytes)
@@ -291,7 +291,9 @@
 
             return rv_dict
 
-        elif not isinstance(obj, serializable_str_types) and isinstance(obj, Sequence):
+        elif not isinstance(obj, serializable_str_types) and isinstance(
+            obj, (Set, Sequence)
+        ):
             rv_list = []
 
             for i, v in enumerate(obj):

{"golden_diff": "diff --git a/sentry_sdk/serializer.py b/sentry_sdk/serializer.py\n--- a/sentry_sdk/serializer.py\n+++ b/sentry_sdk/serializer.py\n@@ -36,14 +36,14 @@\n if PY2:\n     # Importing ABCs from collections is deprecated, and will stop working in 3.8\n     # https://github.com/python/cpython/blob/master/Lib/collections/__init__.py#L49\n-    from collections import Mapping, Sequence\n+    from collections import Mapping, Sequence, Set\n \n     serializable_str_types = string_types\n \n else:\n     # New in 3.3\n     # https://docs.python.org/3/library/collections.abc.html\n-    from collections.abc import Mapping, Sequence\n+    from collections.abc import Mapping, Sequence, Set\n \n     # Bytes are technically not strings in Python 3, but we can serialize them\n     serializable_str_types = (str, bytes)\n@@ -291,7 +291,9 @@\n \n             return rv_dict\n \n-        elif not isinstance(obj, serializable_str_types) and isinstance(obj, Sequence):\n+        elif not isinstance(obj, serializable_str_types) and isinstance(\n+            obj, (Set, Sequence)\n+        ):\n             rv_list = []\n \n             for i, v in enumerate(obj):\n", "issue": "Sets are not breadth-limited\nI've got huge repr-s of sets that are included in the stack trace variables without truncation. As I see in `serializer.py`, `Mapping` and `Sequence` are limited to 10 items, but `typing.Set` is not handled yet.\r\n\r\n![image](https://user-images.githubusercontent.com/2793551/90019532-d5f14300-dcae-11ea-9011-2d7e6a13d477.png)\r\n\r\n\n", "before_files": [{"content": "import sys\n\nfrom datetime import datetime\n\nfrom sentry_sdk.utils import (\n    AnnotatedValue,\n    capture_internal_exception,\n    disable_capture_event,\n    safe_repr,\n    strip_string,\n    format_timestamp,\n)\n\nfrom sentry_sdk._compat import text_type, PY2, string_types, number_types, iteritems\n\nfrom sentry_sdk._types import MYPY\n\nif MYPY:\n    from types import TracebackType\n\n    from typing import Any\n    from typing import Dict\n    from typing import List\n    from typing import Optional\n    from typing import Callable\n    from typing import Union\n    from typing import ContextManager\n    from typing import Type\n\n    from sentry_sdk._types import NotImplementedType, Event\n\n    ReprProcessor = Callable[[Any, Dict[str, Any]], Union[NotImplementedType, str]]\n    Segment = Union[str, int]\n\n\nif PY2:\n    # Importing ABCs from collections is deprecated, and will stop working in 3.8\n    # https://github.com/python/cpython/blob/master/Lib/collections/__init__.py#L49\n    from collections import Mapping, Sequence\n\n    serializable_str_types = string_types\n\nelse:\n    # New in 3.3\n    # https://docs.python.org/3/library/collections.abc.html\n    from collections.abc import Mapping, Sequence\n\n    # Bytes are technically not strings in Python 3, but we can serialize them\n    serializable_str_types = (str, bytes)\n\nMAX_DATABAG_DEPTH = 5\nMAX_DATABAG_BREADTH = 10\nCYCLE_MARKER = u\"<cyclic>\"\n\n\nglobal_repr_processors = []  # type: List[ReprProcessor]\n\n\ndef add_global_repr_processor(processor):\n    # type: (ReprProcessor) -> None\n    global_repr_processors.append(processor)\n\n\nclass Memo(object):\n    __slots__ = (\"_ids\", \"_objs\")\n\n    def __init__(self):\n        # type: () -> None\n        self._ids = {}  # type: Dict[int, Any]\n        self._objs = []  # type: List[Any]\n\n    def memoize(self, obj):\n        # type: (Any) -> ContextManager[bool]\n        self._objs.append(obj)\n        return self\n\n    def __enter__(self):\n        # type: () -> bool\n        obj = self._objs[-1]\n        if id(obj) in self._ids:\n            return True\n        else:\n            self._ids[id(obj)] = obj\n            return False\n\n    def __exit__(\n        self,\n        ty,  # type: Optional[Type[BaseException]]\n        value,  # type: Optional[BaseException]\n        tb,  # type: Optional[TracebackType]\n    ):\n        # type: (...) -> None\n        self._ids.pop(id(self._objs.pop()), None)\n\n\ndef serialize(event, **kwargs):\n    # type: (Event, **Any) -> Event\n    memo = Memo()\n    path = []  # type: List[Segment]\n    meta_stack = []  # type: List[Dict[str, Any]]\n\n    def _annotate(**meta):\n        # type: (**Any) -> None\n        while len(meta_stack) <= len(path):\n            try:\n                segment = path[len(meta_stack) - 1]\n                node = meta_stack[-1].setdefault(text_type(segment), {})\n            except IndexError:\n                node = {}\n\n            meta_stack.append(node)\n\n        meta_stack[-1].setdefault(\"\", {}).update(meta)\n\n    def _should_repr_strings():\n        # type: () -> Optional[bool]\n        \"\"\"\n        By default non-serializable objects are going through\n        safe_repr(). For certain places in the event (local vars) we\n        want to repr() even things that are JSON-serializable to\n        make their type more apparent. For example, it's useful to\n        see the difference between a unicode-string and a bytestring\n        when viewing a stacktrace.\n\n        For container-types we still don't do anything different.\n        Generally we just try to make the Sentry UI present exactly\n        what a pretty-printed repr would look like.\n\n        :returns: `True` if we are somewhere in frame variables, and `False` if\n            we are in a position where we will never encounter frame variables\n            when recursing (for example, we're in `event.extra`). `None` if we\n            are not (yet) in frame variables, but might encounter them when\n            recursing (e.g.  we're in `event.exception`)\n        \"\"\"\n        try:\n            p0 = path[0]\n            if p0 == \"stacktrace\" and path[1] == \"frames\" and path[3] == \"vars\":\n                return True\n\n            if (\n                p0 in (\"threads\", \"exception\")\n                and path[1] == \"values\"\n                and path[3] == \"stacktrace\"\n                and path[4] == \"frames\"\n                and path[6] == \"vars\"\n            ):\n                return True\n        except IndexError:\n            return None\n\n        return False\n\n    def _is_databag():\n        # type: () -> Optional[bool]\n        \"\"\"\n        A databag is any value that we need to trim.\n\n        :returns: Works like `_should_repr_strings()`. `True` for \"yes\",\n            `False` for :\"no\", `None` for \"maybe soon\".\n        \"\"\"\n        try:\n            rv = _should_repr_strings()\n            if rv in (True, None):\n                return rv\n\n            p0 = path[0]\n            if p0 == \"request\" and path[1] == \"data\":\n                return True\n\n            if p0 == \"breadcrumbs\":\n                path[1]\n                return True\n\n            if p0 == \"extra\":\n                return True\n\n        except IndexError:\n            return None\n\n        return False\n\n    def _serialize_node(\n        obj,  # type: Any\n        is_databag=None,  # type: Optional[bool]\n        should_repr_strings=None,  # type: Optional[bool]\n        segment=None,  # type: Optional[Segment]\n        remaining_breadth=None,  # type: Optional[int]\n        remaining_depth=None,  # type: Optional[int]\n    ):\n        # type: (...) -> Any\n        if segment is not None:\n            path.append(segment)\n\n        try:\n            with memo.memoize(obj) as result:\n                if result:\n                    return CYCLE_MARKER\n\n                return _serialize_node_impl(\n                    obj,\n                    is_databag=is_databag,\n                    should_repr_strings=should_repr_strings,\n                    remaining_depth=remaining_depth,\n                    remaining_breadth=remaining_breadth,\n                )\n        except BaseException:\n            capture_internal_exception(sys.exc_info())\n\n            if is_databag:\n                return u\"<failed to serialize, use init(debug=True) to see error logs>\"\n\n            return None\n        finally:\n            if segment is not None:\n                path.pop()\n                del meta_stack[len(path) + 1 :]\n\n    def _flatten_annotated(obj):\n        # type: (Any) -> Any\n        if isinstance(obj, AnnotatedValue):\n            _annotate(**obj.metadata)\n            obj = obj.value\n        return obj\n\n    def _serialize_node_impl(\n        obj, is_databag, should_repr_strings, remaining_depth, remaining_breadth\n    ):\n        # type: (Any, Optional[bool], Optional[bool], Optional[int], Optional[int]) -> Any\n        if should_repr_strings is None:\n            should_repr_strings = _should_repr_strings()\n\n        if is_databag is None:\n            is_databag = _is_databag()\n\n        if is_databag and remaining_depth is None:\n            remaining_depth = MAX_DATABAG_DEPTH\n        if is_databag and remaining_breadth is None:\n            remaining_breadth = MAX_DATABAG_BREADTH\n\n        obj = _flatten_annotated(obj)\n\n        if remaining_depth is not None and remaining_depth <= 0:\n            _annotate(rem=[[\"!limit\", \"x\"]])\n            if is_databag:\n                return _flatten_annotated(strip_string(safe_repr(obj)))\n            return None\n\n        if is_databag and global_repr_processors:\n            hints = {\"memo\": memo, \"remaining_depth\": remaining_depth}\n            for processor in global_repr_processors:\n                result = processor(obj, hints)\n                if result is not NotImplemented:\n                    return _flatten_annotated(result)\n\n        if obj is None or isinstance(obj, (bool, number_types)):\n            return obj if not should_repr_strings else safe_repr(obj)\n\n        elif isinstance(obj, datetime):\n            return (\n                text_type(format_timestamp(obj))\n                if not should_repr_strings\n                else safe_repr(obj)\n            )\n\n        elif isinstance(obj, Mapping):\n            # Create temporary copy here to avoid calling too much code that\n            # might mutate our dictionary while we're still iterating over it.\n            obj = dict(iteritems(obj))\n\n            rv_dict = {}  # type: Dict[str, Any]\n            i = 0\n\n            for k, v in iteritems(obj):\n                if remaining_breadth is not None and i >= remaining_breadth:\n                    _annotate(len=len(obj))\n                    break\n\n                str_k = text_type(k)\n                v = _serialize_node(\n                    v,\n                    segment=str_k,\n                    should_repr_strings=should_repr_strings,\n                    is_databag=is_databag,\n                    remaining_depth=remaining_depth - 1\n                    if remaining_depth is not None\n                    else None,\n                    remaining_breadth=remaining_breadth,\n                )\n                rv_dict[str_k] = v\n                i += 1\n\n            return rv_dict\n\n        elif not isinstance(obj, serializable_str_types) and isinstance(obj, Sequence):\n            rv_list = []\n\n            for i, v in enumerate(obj):\n                if remaining_breadth is not None and i >= remaining_breadth:\n                    _annotate(len=len(obj))\n                    break\n\n                rv_list.append(\n                    _serialize_node(\n                        v,\n                        segment=i,\n                        should_repr_strings=should_repr_strings,\n                        is_databag=is_databag,\n                        remaining_depth=remaining_depth - 1\n                        if remaining_depth is not None\n                        else None,\n                        remaining_breadth=remaining_breadth,\n                    )\n                )\n\n            return rv_list\n\n        if should_repr_strings:\n            obj = safe_repr(obj)\n        else:\n            if isinstance(obj, bytes):\n                obj = obj.decode(\"utf-8\", \"replace\")\n\n            if not isinstance(obj, string_types):\n                obj = safe_repr(obj)\n\n        return _flatten_annotated(strip_string(obj))\n\n    disable_capture_event.set(True)\n    try:\n        rv = _serialize_node(event, **kwargs)\n        if meta_stack and isinstance(rv, dict):\n            rv[\"_meta\"] = meta_stack[0]\n\n        return rv\n    finally:\n        disable_capture_event.set(False)\n", "path": "sentry_sdk/serializer.py"}], "after_files": [{"content": "import sys\n\nfrom datetime import datetime\n\nfrom sentry_sdk.utils import (\n    AnnotatedValue,\n    capture_internal_exception,\n    disable_capture_event,\n    safe_repr,\n    strip_string,\n    format_timestamp,\n)\n\nfrom sentry_sdk._compat import text_type, PY2, string_types, number_types, iteritems\n\nfrom sentry_sdk._types import MYPY\n\nif MYPY:\n    from types import TracebackType\n\n    from typing import Any\n    from typing import Dict\n    from typing import List\n    from typing import Optional\n    from typing import Callable\n    from typing import Union\n    from typing import ContextManager\n    from typing import Type\n\n    from sentry_sdk._types import NotImplementedType, Event\n\n    ReprProcessor = Callable[[Any, Dict[str, Any]], Union[NotImplementedType, str]]\n    Segment = Union[str, int]\n\n\nif PY2:\n    # Importing ABCs from collections is deprecated, and will stop working in 3.8\n    # https://github.com/python/cpython/blob/master/Lib/collections/__init__.py#L49\n    from collections import Mapping, Sequence, Set\n\n    serializable_str_types = string_types\n\nelse:\n    # New in 3.3\n    # https://docs.python.org/3/library/collections.abc.html\n    from collections.abc import Mapping, Sequence, Set\n\n    # Bytes are technically not strings in Python 3, but we can serialize them\n    serializable_str_types = (str, bytes)\n\nMAX_DATABAG_DEPTH = 5\nMAX_DATABAG_BREADTH = 10\nCYCLE_MARKER = u\"<cyclic>\"\n\n\nglobal_repr_processors = []  # type: List[ReprProcessor]\n\n\ndef add_global_repr_processor(processor):\n    # type: (ReprProcessor) -> None\n    global_repr_processors.append(processor)\n\n\nclass Memo(object):\n    __slots__ = (\"_ids\", \"_objs\")\n\n    def __init__(self):\n        # type: () -> None\n        self._ids = {}  # type: Dict[int, Any]\n        self._objs = []  # type: List[Any]\n\n    def memoize(self, obj):\n        # type: (Any) -> ContextManager[bool]\n        self._objs.append(obj)\n        return self\n\n    def __enter__(self):\n        # type: () -> bool\n        obj = self._objs[-1]\n        if id(obj) in self._ids:\n            return True\n        else:\n            self._ids[id(obj)] = obj\n            return False\n\n    def __exit__(\n        self,\n        ty,  # type: Optional[Type[BaseException]]\n        value,  # type: Optional[BaseException]\n        tb,  # type: Optional[TracebackType]\n    ):\n        # type: (...) -> None\n        self._ids.pop(id(self._objs.pop()), None)\n\n\ndef serialize(event, **kwargs):\n    # type: (Event, **Any) -> Event\n    memo = Memo()\n    path = []  # type: List[Segment]\n    meta_stack = []  # type: List[Dict[str, Any]]\n\n    def _annotate(**meta):\n        # type: (**Any) -> None\n        while len(meta_stack) <= len(path):\n            try:\n                segment = path[len(meta_stack) - 1]\n                node = meta_stack[-1].setdefault(text_type(segment), {})\n            except IndexError:\n                node = {}\n\n            meta_stack.append(node)\n\n        meta_stack[-1].setdefault(\"\", {}).update(meta)\n\n    def _should_repr_strings():\n        # type: () -> Optional[bool]\n        \"\"\"\n        By default non-serializable objects are going through\n        safe_repr(). For certain places in the event (local vars) we\n        want to repr() even things that are JSON-serializable to\n        make their type more apparent. For example, it's useful to\n        see the difference between a unicode-string and a bytestring\n        when viewing a stacktrace.\n\n        For container-types we still don't do anything different.\n        Generally we just try to make the Sentry UI present exactly\n        what a pretty-printed repr would look like.\n\n        :returns: `True` if we are somewhere in frame variables, and `False` if\n            we are in a position where we will never encounter frame variables\n            when recursing (for example, we're in `event.extra`). `None` if we\n            are not (yet) in frame variables, but might encounter them when\n            recursing (e.g.  we're in `event.exception`)\n        \"\"\"\n        try:\n            p0 = path[0]\n            if p0 == \"stacktrace\" and path[1] == \"frames\" and path[3] == \"vars\":\n                return True\n\n            if (\n                p0 in (\"threads\", \"exception\")\n                and path[1] == \"values\"\n                and path[3] == \"stacktrace\"\n                and path[4] == \"frames\"\n                and path[6] == \"vars\"\n            ):\n                return True\n        except IndexError:\n            return None\n\n        return False\n\n    def _is_databag():\n        # type: () -> Optional[bool]\n        \"\"\"\n        A databag is any value that we need to trim.\n\n        :returns: Works like `_should_repr_strings()`. `True` for \"yes\",\n            `False` for :\"no\", `None` for \"maybe soon\".\n        \"\"\"\n        try:\n            rv = _should_repr_strings()\n            if rv in (True, None):\n                return rv\n\n            p0 = path[0]\n            if p0 == \"request\" and path[1] == \"data\":\n                return True\n\n            if p0 == \"breadcrumbs\":\n                path[1]\n                return True\n\n            if p0 == \"extra\":\n                return True\n\n        except IndexError:\n            return None\n\n        return False\n\n    def _serialize_node(\n        obj,  # type: Any\n        is_databag=None,  # type: Optional[bool]\n        should_repr_strings=None,  # type: Optional[bool]\n        segment=None,  # type: Optional[Segment]\n        remaining_breadth=None,  # type: Optional[int]\n        remaining_depth=None,  # type: Optional[int]\n    ):\n        # type: (...) -> Any\n        if segment is not None:\n            path.append(segment)\n\n        try:\n            with memo.memoize(obj) as result:\n                if result:\n                    return CYCLE_MARKER\n\n                return _serialize_node_impl(\n                    obj,\n                    is_databag=is_databag,\n                    should_repr_strings=should_repr_strings,\n                    remaining_depth=remaining_depth,\n                    remaining_breadth=remaining_breadth,\n                )\n        except BaseException:\n            capture_internal_exception(sys.exc_info())\n\n            if is_databag:\n                return u\"<failed to serialize, use init(debug=True) to see error logs>\"\n\n            return None\n        finally:\n            if segment is not None:\n                path.pop()\n                del meta_stack[len(path) + 1 :]\n\n    def _flatten_annotated(obj):\n        # type: (Any) -> Any\n        if isinstance(obj, AnnotatedValue):\n            _annotate(**obj.metadata)\n            obj = obj.value\n        return obj\n\n    def _serialize_node_impl(\n        obj, is_databag, should_repr_strings, remaining_depth, remaining_breadth\n    ):\n        # type: (Any, Optional[bool], Optional[bool], Optional[int], Optional[int]) -> Any\n        if should_repr_strings is None:\n            should_repr_strings = _should_repr_strings()\n\n        if is_databag is None:\n            is_databag = _is_databag()\n\n        if is_databag and remaining_depth is None:\n            remaining_depth = MAX_DATABAG_DEPTH\n        if is_databag and remaining_breadth is None:\n            remaining_breadth = MAX_DATABAG_BREADTH\n\n        obj = _flatten_annotated(obj)\n\n        if remaining_depth is not None and remaining_depth <= 0:\n            _annotate(rem=[[\"!limit\", \"x\"]])\n            if is_databag:\n                return _flatten_annotated(strip_string(safe_repr(obj)))\n            return None\n\n        if is_databag and global_repr_processors:\n            hints = {\"memo\": memo, \"remaining_depth\": remaining_depth}\n            for processor in global_repr_processors:\n                result = processor(obj, hints)\n                if result is not NotImplemented:\n                    return _flatten_annotated(result)\n\n        if obj is None or isinstance(obj, (bool, number_types)):\n            return obj if not should_repr_strings else safe_repr(obj)\n\n        elif isinstance(obj, datetime):\n            return (\n                text_type(format_timestamp(obj))\n                if not should_repr_strings\n                else safe_repr(obj)\n            )\n\n        elif isinstance(obj, Mapping):\n            # Create temporary copy here to avoid calling too much code that\n            # might mutate our dictionary while we're still iterating over it.\n            obj = dict(iteritems(obj))\n\n            rv_dict = {}  # type: Dict[str, Any]\n            i = 0\n\n            for k, v in iteritems(obj):\n                if remaining_breadth is not None and i >= remaining_breadth:\n                    _annotate(len=len(obj))\n                    break\n\n                str_k = text_type(k)\n                v = _serialize_node(\n                    v,\n                    segment=str_k,\n                    should_repr_strings=should_repr_strings,\n                    is_databag=is_databag,\n                    remaining_depth=remaining_depth - 1\n                    if remaining_depth is not None\n                    else None,\n                    remaining_breadth=remaining_breadth,\n                )\n                rv_dict[str_k] = v\n                i += 1\n\n            return rv_dict\n\n        elif not isinstance(obj, serializable_str_types) and isinstance(\n            obj, (Set, Sequence)\n        ):\n            rv_list = []\n\n            for i, v in enumerate(obj):\n                if remaining_breadth is not None and i >= remaining_breadth:\n                    _annotate(len=len(obj))\n                    break\n\n                rv_list.append(\n                    _serialize_node(\n                        v,\n                        segment=i,\n                        should_repr_strings=should_repr_strings,\n                        is_databag=is_databag,\n                        remaining_depth=remaining_depth - 1\n                        if remaining_depth is not None\n                        else None,\n                        remaining_breadth=remaining_breadth,\n                    )\n                )\n\n            return rv_list\n\n        if should_repr_strings:\n            obj = safe_repr(obj)\n        else:\n            if isinstance(obj, bytes):\n                obj = obj.decode(\"utf-8\", \"replace\")\n\n            if not isinstance(obj, string_types):\n                obj = safe_repr(obj)\n\n        return _flatten_annotated(strip_string(obj))\n\n    disable_capture_event.set(True)\n    try:\n        rv = _serialize_node(event, **kwargs)\n        if meta_stack and isinstance(rv, dict):\n            rv[\"_meta\"] = meta_stack[0]\n\n        return rv\n    finally:\n        disable_capture_event.set(False)\n", "path": "sentry_sdk/serializer.py"}]}