|  | 
| 15 | 15 | 
 | 
| 16 | 16 | from __future__ import annotations | 
| 17 | 17 | 
 | 
|  | 18 | +import ast | 
| 18 | 19 | import re | 
| 19 |  | -from ast import literal_eval | 
| 20 |  | -from typing import Callable, List, Optional, cast | 
|  | 20 | +import sys | 
|  | 21 | +from typing import Any, Callable, List, Optional, cast | 
| 21 | 22 | 
 | 
| 22 | 23 | from griffe import Docstring, Object | 
| 23 | 24 | from mkdocstrings import get_logger | 
| @@ -353,7 +354,7 @@ def doc_value_offset_to_location(doc: Docstring, offset: int) -> tuple[int,int]: | 
| 353 | 354 |         try: | 
| 354 | 355 |             source = doc.source | 
| 355 | 356 |             # compute docstring without cleaning up spaces and indentation | 
| 356 |  | -            rawvalue = str(literal_eval(source)) | 
|  | 357 | +            rawvalue = str(safe_eval(source)) | 
| 357 | 358 | 
 | 
| 358 | 359 |             # adjust line offset by number of lines removed from front of docstring | 
| 359 | 360 |             lineoffset += leading_space(rawvalue).count("\n") | 
| @@ -388,3 +389,13 @@ def leading_space(s: str) -> str: | 
| 388 | 389 |     if m := re.match(r"\s*", s): | 
| 389 | 390 |         return m[0] | 
| 390 | 391 |     return "" # pragma: no cover | 
|  | 392 | + | 
|  | 393 | +if sys.version_info < (3, 10) or True: | 
|  | 394 | +    # TODO: remove when 3.9 support is dropped | 
|  | 395 | +    # In 3.9, literal_eval cannot handle comments in input | 
|  | 396 | +    def safe_eval(s: str) -> Any: | 
|  | 397 | +        """Safely evaluate a string expression.""" | 
|  | 398 | +        return eval(s) #eval(s, dict(__builtins__={}), {}) | 
|  | 399 | +else: | 
|  | 400 | +    save_eval = ast.literal_eval | 
|  | 401 | + | 
0 commit comments