We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Crash in pure_eval
This happened while we were experiencing a DB outage:
```
  File "/usr/local/lib/python3.8/dist-packages/asyncpg/connection.py", line 443, in fetch
    return await self._execute(query, args, 0, timeout)
  File "/usr/local/lib/python3.8/dist-packages/asyncpg/connection.py", line 1445, in _execute
    result, _ = await self.__execute(
  File "/server/athenian/api/db.py", line 191, in _asyncpg_execute
    result = await self._execute_original(query, args, limit, timeout, return_status)
  File "/usr/local/lib/python3.8/dist-packages/asyncpg/connection.py", line 1454, in __execute
    return await self._do_execute(query, executor, timeout)
  File "/usr/local/lib/python3.8/dist-packages/asyncpg/connection.py", line 1476, in _do_execute
    result = await executor(stmt, None)
  File "asyncpg/protocol/protocol.pyx", line 196, in bind_execute
    return await waiter
asyncpg.exceptions.ConnectionDoesNotExistError: connection was closed in the middle of operation

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/sentry_sdk/scope.py", line 353, in apply_to_event
    new_event = event_processor(event, hint)
  File "/usr/local/lib/python3.8/dist-packages/sentry_sdk/integrations/pure_eval.py", line 79, in add_executing_info
    pure_eval_frame(tb.tb_frame) or sentry_frame["vars"]
  File "/usr/local/lib/python3.8/dist-packages/sentry_sdk/integrations/pure_eval.py", line 128, in pure_eval_frame
    expressions.sort(key=closeness, reverse=True)
  File "/usr/local/lib/python3.8/dist-packages/sentry_sdk/integrations/pure_eval.py", line 113, in closeness
    nodes_before_stmt = [
  File "/usr/local/lib/python3.8/dist-packages/sentry_sdk/integrations/pure_eval.py", line 114, in <listcomp>
    node for node in nodes if node.first_token.startpos < stmt.last_token.endpos
AttributeError: 'Name' object has no attribute 'first_token'
```

--- 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/integrations/pure_eval.py`
Content:
```
1 from __future__ import absolute_import
2 
3 import ast
4 
5 from sentry_sdk import Hub, serializer
6 from sentry_sdk._types import MYPY
7 from sentry_sdk.integrations import Integration, DidNotEnable
8 from sentry_sdk.scope import add_global_event_processor
9 from sentry_sdk.utils import walk_exception_chain, iter_stacks
10 
11 if MYPY:
12     from typing import Optional, Dict, Any, Tuple, List
13     from types import FrameType
14 
15     from sentry_sdk._types import Event, Hint
16 
17 try:
18     import executing
19 except ImportError:
20     raise DidNotEnable("executing is not installed")
21 
22 try:
23     import pure_eval
24 except ImportError:
25     raise DidNotEnable("pure_eval is not installed")
26 
27 try:
28     # Used implicitly, just testing it's available
29     import asttokens  # noqa
30 except ImportError:
31     raise DidNotEnable("asttokens is not installed")
32 
33 
34 class PureEvalIntegration(Integration):
35     identifier = "pure_eval"
36 
37     @staticmethod
38     def setup_once():
39         # type: () -> None
40 
41         @add_global_event_processor
42         def add_executing_info(event, hint):
43             # type: (Event, Optional[Hint]) -> Optional[Event]
44             if Hub.current.get_integration(PureEvalIntegration) is None:
45                 return event
46 
47             if hint is None:
48                 return event
49 
50             exc_info = hint.get("exc_info", None)
51 
52             if exc_info is None:
53                 return event
54 
55             exception = event.get("exception", None)
56 
57             if exception is None:
58                 return event
59 
60             values = exception.get("values", None)
61 
62             if values is None:
63                 return event
64 
65             for exception, (_exc_type, _exc_value, exc_tb) in zip(
66                 reversed(values), walk_exception_chain(exc_info)
67             ):
68                 sentry_frames = [
69                     frame
70                     for frame in exception.get("stacktrace", {}).get("frames", [])
71                     if frame.get("function")
72                 ]
73                 tbs = list(iter_stacks(exc_tb))
74                 if len(sentry_frames) != len(tbs):
75                     continue
76 
77                 for sentry_frame, tb in zip(sentry_frames, tbs):
78                     sentry_frame["vars"] = (
79                         pure_eval_frame(tb.tb_frame) or sentry_frame["vars"]
80                     )
81             return event
82 
83 
84 def pure_eval_frame(frame):
85     # type: (FrameType) -> Dict[str, Any]
86     source = executing.Source.for_frame(frame)
87     if not source.tree:
88         return {}
89 
90     statements = source.statements_at_line(frame.f_lineno)
91     if not statements:
92         return {}
93 
94     scope = stmt = list(statements)[0]
95     while True:
96         # Get the parent first in case the original statement is already
97         # a function definition, e.g. if we're calling a decorator
98         # In that case we still want the surrounding scope, not that function
99         scope = scope.parent
100         if isinstance(scope, (ast.FunctionDef, ast.ClassDef, ast.Module)):
101             break
102 
103     evaluator = pure_eval.Evaluator.from_frame(frame)
104     expressions = evaluator.interesting_expressions_grouped(scope)
105 
106     def closeness(expression):
107         # type: (Tuple[List[Any], Any]) -> int
108         # Prioritise expressions with a node closer to the statement executed
109         # without being after that statement
110         # A higher return value is better - the expression will appear
111         # earlier in the list of values and is less likely to be trimmed
112         nodes, _value = expression
113         nodes_before_stmt = [
114             node for node in nodes if node.first_token.startpos < stmt.last_token.endpos
115         ]
116         if nodes_before_stmt:
117             # The position of the last node before or in the statement
118             return max(node.first_token.startpos for node in nodes_before_stmt)
119         else:
120             # The position of the first node after the statement
121             # Negative means it's always lower priority than nodes that come before
122             # Less negative means closer to the statement and higher priority
123             return -min(node.first_token.startpos for node in nodes)
124 
125     # This adds the first_token and last_token attributes to nodes
126     atok = source.asttokens()
127 
128     expressions.sort(key=closeness, reverse=True)
129     return {
130         atok.get_text(nodes[0]): value
131         for nodes, value in expressions[: serializer.MAX_DATABAG_BREADTH]
132     }
133
```
--- 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/integrations/pure_eval.py b/sentry_sdk/integrations/pure_eval.py
--- a/sentry_sdk/integrations/pure_eval.py
+++ b/sentry_sdk/integrations/pure_eval.py
@@ -104,23 +104,29 @@
     expressions = evaluator.interesting_expressions_grouped(scope)
 
     def closeness(expression):
-        # type: (Tuple[List[Any], Any]) -> int
+        # type: (Tuple[List[Any], Any]) -> Tuple[int, int]
         # Prioritise expressions with a node closer to the statement executed
         # without being after that statement
         # A higher return value is better - the expression will appear
         # earlier in the list of values and is less likely to be trimmed
         nodes, _value = expression
+
+        def start(n):
+            # type: (ast.expr) -> Tuple[int, int]
+            return (n.lineno, n.col_offset)
+
         nodes_before_stmt = [
-            node for node in nodes if node.first_token.startpos < stmt.last_token.endpos
+            node for node in nodes if start(node) < stmt.last_token.end
         ]
         if nodes_before_stmt:
             # The position of the last node before or in the statement
-            return max(node.first_token.startpos for node in nodes_before_stmt)
+            return max(start(node) for node in nodes_before_stmt)
         else:
             # The position of the first node after the statement
             # Negative means it's always lower priority than nodes that come before
             # Less negative means closer to the statement and higher priority
-            return -min(node.first_token.startpos for node in nodes)
+            lineno, col_offset = min(start(node) for node in nodes)
+            return (-lineno, -col_offset)
 
     # This adds the first_token and last_token attributes to nodes
     atok = source.asttokens()

{"golden_diff": "diff --git a/sentry_sdk/integrations/pure_eval.py b/sentry_sdk/integrations/pure_eval.py\n--- a/sentry_sdk/integrations/pure_eval.py\n+++ b/sentry_sdk/integrations/pure_eval.py\n@@ -104,23 +104,29 @@\n     expressions = evaluator.interesting_expressions_grouped(scope)\n \n     def closeness(expression):\n-        # type: (Tuple[List[Any], Any]) -> int\n+        # type: (Tuple[List[Any], Any]) -> Tuple[int, int]\n         # Prioritise expressions with a node closer to the statement executed\n         # without being after that statement\n         # A higher return value is better - the expression will appear\n         # earlier in the list of values and is less likely to be trimmed\n         nodes, _value = expression\n+\n+        def start(n):\n+            # type: (ast.expr) -> Tuple[int, int]\n+            return (n.lineno, n.col_offset)\n+\n         nodes_before_stmt = [\n-            node for node in nodes if node.first_token.startpos < stmt.last_token.endpos\n+            node for node in nodes if start(node) < stmt.last_token.end\n         ]\n         if nodes_before_stmt:\n             # The position of the last node before or in the statement\n-            return max(node.first_token.startpos for node in nodes_before_stmt)\n+            return max(start(node) for node in nodes_before_stmt)\n         else:\n             # The position of the first node after the statement\n             # Negative means it's always lower priority than nodes that come before\n             # Less negative means closer to the statement and higher priority\n-            return -min(node.first_token.startpos for node in nodes)\n+            lineno, col_offset = min(start(node) for node in nodes)\n+            return (-lineno, -col_offset)\n \n     # This adds the first_token and last_token attributes to nodes\n     atok = source.asttokens()\n", "issue": "Crash in pure_eval\nThis happened while we were experiencing a DB outage:\r\n```\r\n  File \"/usr/local/lib/python3.8/dist-packages/asyncpg/connection.py\", line 443, in fetch\r\n    return await self._execute(query, args, 0, timeout)\r\n  File \"/usr/local/lib/python3.8/dist-packages/asyncpg/connection.py\", line 1445, in _execute\r\n    result, _ = await self.__execute(\r\n  File \"/server/athenian/api/db.py\", line 191, in _asyncpg_execute\r\n    result = await self._execute_original(query, args, limit, timeout, return_status)\r\n  File \"/usr/local/lib/python3.8/dist-packages/asyncpg/connection.py\", line 1454, in __execute\r\n    return await self._do_execute(query, executor, timeout)\r\n  File \"/usr/local/lib/python3.8/dist-packages/asyncpg/connection.py\", line 1476, in _do_execute\r\n    result = await executor(stmt, None)\r\n  File \"asyncpg/protocol/protocol.pyx\", line 196, in bind_execute\r\n    return await waiter\r\nasyncpg.exceptions.ConnectionDoesNotExistError: connection was closed in the middle of operation\r\n\r\nDuring handling of the above exception, another exception occurred:\r\n\r\nTraceback (most recent call last):\r\n  File \"/usr/local/lib/python3.8/dist-packages/sentry_sdk/scope.py\", line 353, in apply_to_event\r\n    new_event = event_processor(event, hint)\r\n  File \"/usr/local/lib/python3.8/dist-packages/sentry_sdk/integrations/pure_eval.py\", line 79, in add_executing_info\r\n    pure_eval_frame(tb.tb_frame) or sentry_frame[\"vars\"]\r\n  File \"/usr/local/lib/python3.8/dist-packages/sentry_sdk/integrations/pure_eval.py\", line 128, in pure_eval_frame\r\n    expressions.sort(key=closeness, reverse=True)\r\n  File \"/usr/local/lib/python3.8/dist-packages/sentry_sdk/integrations/pure_eval.py\", line 113, in closeness\r\n    nodes_before_stmt = [\r\n  File \"/usr/local/lib/python3.8/dist-packages/sentry_sdk/integrations/pure_eval.py\", line 114, in <listcomp>\r\n    node for node in nodes if node.first_token.startpos < stmt.last_token.endpos\r\nAttributeError: 'Name' object has no attribute 'first_token'\r\n```\n", "before_files": [{"content": "from __future__ import absolute_import\n\nimport ast\n\nfrom sentry_sdk import Hub, serializer\nfrom sentry_sdk._types import MYPY\nfrom sentry_sdk.integrations import Integration, DidNotEnable\nfrom sentry_sdk.scope import add_global_event_processor\nfrom sentry_sdk.utils import walk_exception_chain, iter_stacks\n\nif MYPY:\n    from typing import Optional, Dict, Any, Tuple, List\n    from types import FrameType\n\n    from sentry_sdk._types import Event, Hint\n\ntry:\n    import executing\nexcept ImportError:\n    raise DidNotEnable(\"executing is not installed\")\n\ntry:\n    import pure_eval\nexcept ImportError:\n    raise DidNotEnable(\"pure_eval is not installed\")\n\ntry:\n    # Used implicitly, just testing it's available\n    import asttokens  # noqa\nexcept ImportError:\n    raise DidNotEnable(\"asttokens is not installed\")\n\n\nclass PureEvalIntegration(Integration):\n    identifier = \"pure_eval\"\n\n    @staticmethod\n    def setup_once():\n        # type: () -> None\n\n        @add_global_event_processor\n        def add_executing_info(event, hint):\n            # type: (Event, Optional[Hint]) -> Optional[Event]\n            if Hub.current.get_integration(PureEvalIntegration) is None:\n                return event\n\n            if hint is None:\n                return event\n\n            exc_info = hint.get(\"exc_info\", None)\n\n            if exc_info is None:\n                return event\n\n            exception = event.get(\"exception\", None)\n\n            if exception is None:\n                return event\n\n            values = exception.get(\"values\", None)\n\n            if values is None:\n                return event\n\n            for exception, (_exc_type, _exc_value, exc_tb) in zip(\n                reversed(values), walk_exception_chain(exc_info)\n            ):\n                sentry_frames = [\n                    frame\n                    for frame in exception.get(\"stacktrace\", {}).get(\"frames\", [])\n                    if frame.get(\"function\")\n                ]\n                tbs = list(iter_stacks(exc_tb))\n                if len(sentry_frames) != len(tbs):\n                    continue\n\n                for sentry_frame, tb in zip(sentry_frames, tbs):\n                    sentry_frame[\"vars\"] = (\n                        pure_eval_frame(tb.tb_frame) or sentry_frame[\"vars\"]\n                    )\n            return event\n\n\ndef pure_eval_frame(frame):\n    # type: (FrameType) -> Dict[str, Any]\n    source = executing.Source.for_frame(frame)\n    if not source.tree:\n        return {}\n\n    statements = source.statements_at_line(frame.f_lineno)\n    if not statements:\n        return {}\n\n    scope = stmt = list(statements)[0]\n    while True:\n        # Get the parent first in case the original statement is already\n        # a function definition, e.g. if we're calling a decorator\n        # In that case we still want the surrounding scope, not that function\n        scope = scope.parent\n        if isinstance(scope, (ast.FunctionDef, ast.ClassDef, ast.Module)):\n            break\n\n    evaluator = pure_eval.Evaluator.from_frame(frame)\n    expressions = evaluator.interesting_expressions_grouped(scope)\n\n    def closeness(expression):\n        # type: (Tuple[List[Any], Any]) -> int\n        # Prioritise expressions with a node closer to the statement executed\n        # without being after that statement\n        # A higher return value is better - the expression will appear\n        # earlier in the list of values and is less likely to be trimmed\n        nodes, _value = expression\n        nodes_before_stmt = [\n            node for node in nodes if node.first_token.startpos < stmt.last_token.endpos\n        ]\n        if nodes_before_stmt:\n            # The position of the last node before or in the statement\n            return max(node.first_token.startpos for node in nodes_before_stmt)\n        else:\n            # The position of the first node after the statement\n            # Negative means it's always lower priority than nodes that come before\n            # Less negative means closer to the statement and higher priority\n            return -min(node.first_token.startpos for node in nodes)\n\n    # This adds the first_token and last_token attributes to nodes\n    atok = source.asttokens()\n\n    expressions.sort(key=closeness, reverse=True)\n    return {\n        atok.get_text(nodes[0]): value\n        for nodes, value in expressions[: serializer.MAX_DATABAG_BREADTH]\n    }\n", "path": "sentry_sdk/integrations/pure_eval.py"}], "after_files": [{"content": "from __future__ import absolute_import\n\nimport ast\n\nfrom sentry_sdk import Hub, serializer\nfrom sentry_sdk._types import MYPY\nfrom sentry_sdk.integrations import Integration, DidNotEnable\nfrom sentry_sdk.scope import add_global_event_processor\nfrom sentry_sdk.utils import walk_exception_chain, iter_stacks\n\nif MYPY:\n    from typing import Optional, Dict, Any, Tuple, List\n    from types import FrameType\n\n    from sentry_sdk._types import Event, Hint\n\ntry:\n    import executing\nexcept ImportError:\n    raise DidNotEnable(\"executing is not installed\")\n\ntry:\n    import pure_eval\nexcept ImportError:\n    raise DidNotEnable(\"pure_eval is not installed\")\n\ntry:\n    # Used implicitly, just testing it's available\n    import asttokens  # noqa\nexcept ImportError:\n    raise DidNotEnable(\"asttokens is not installed\")\n\n\nclass PureEvalIntegration(Integration):\n    identifier = \"pure_eval\"\n\n    @staticmethod\n    def setup_once():\n        # type: () -> None\n\n        @add_global_event_processor\n        def add_executing_info(event, hint):\n            # type: (Event, Optional[Hint]) -> Optional[Event]\n            if Hub.current.get_integration(PureEvalIntegration) is None:\n                return event\n\n            if hint is None:\n                return event\n\n            exc_info = hint.get(\"exc_info\", None)\n\n            if exc_info is None:\n                return event\n\n            exception = event.get(\"exception\", None)\n\n            if exception is None:\n                return event\n\n            values = exception.get(\"values\", None)\n\n            if values is None:\n                return event\n\n            for exception, (_exc_type, _exc_value, exc_tb) in zip(\n                reversed(values), walk_exception_chain(exc_info)\n            ):\n                sentry_frames = [\n                    frame\n                    for frame in exception.get(\"stacktrace\", {}).get(\"frames\", [])\n                    if frame.get(\"function\")\n                ]\n                tbs = list(iter_stacks(exc_tb))\n                if len(sentry_frames) != len(tbs):\n                    continue\n\n                for sentry_frame, tb in zip(sentry_frames, tbs):\n                    sentry_frame[\"vars\"] = (\n                        pure_eval_frame(tb.tb_frame) or sentry_frame[\"vars\"]\n                    )\n            return event\n\n\ndef pure_eval_frame(frame):\n    # type: (FrameType) -> Dict[str, Any]\n    source = executing.Source.for_frame(frame)\n    if not source.tree:\n        return {}\n\n    statements = source.statements_at_line(frame.f_lineno)\n    if not statements:\n        return {}\n\n    scope = stmt = list(statements)[0]\n    while True:\n        # Get the parent first in case the original statement is already\n        # a function definition, e.g. if we're calling a decorator\n        # In that case we still want the surrounding scope, not that function\n        scope = scope.parent\n        if isinstance(scope, (ast.FunctionDef, ast.ClassDef, ast.Module)):\n            break\n\n    evaluator = pure_eval.Evaluator.from_frame(frame)\n    expressions = evaluator.interesting_expressions_grouped(scope)\n\n    def closeness(expression):\n        # type: (Tuple[List[Any], Any]) -> Tuple[int, int]\n        # Prioritise expressions with a node closer to the statement executed\n        # without being after that statement\n        # A higher return value is better - the expression will appear\n        # earlier in the list of values and is less likely to be trimmed\n        nodes, _value = expression\n\n        def start(n):\n            # type: (ast.expr) -> Tuple[int, int]\n            return (n.lineno, n.col_offset)\n\n        nodes_before_stmt = [\n            node for node in nodes if start(node) < stmt.last_token.end\n        ]\n        if nodes_before_stmt:\n            # The position of the last node before or in the statement\n            return max(start(node) for node in nodes_before_stmt)\n        else:\n            # The position of the first node after the statement\n            # Negative means it's always lower priority than nodes that come before\n            # Less negative means closer to the statement and higher priority\n            lineno, col_offset = min(start(node) for node in nodes)\n            return (-lineno, -col_offset)\n\n    # This adds the first_token and last_token attributes to nodes\n    atok = source.asttokens()\n\n    expressions.sort(key=closeness, reverse=True)\n    return {\n        atok.get_text(nodes[0]): value\n        for nodes, value in expressions[: serializer.MAX_DATABAG_BREADTH]\n    }\n", "path": "sentry_sdk/integrations/pure_eval.py"}]}