Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/structlog/_frames.py: 26%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

43 statements  

1# SPDX-License-Identifier: MIT OR Apache-2.0 

2# This file is dual licensed under the terms of the Apache License, Version 

3# 2.0, and the MIT License. See the LICENSE file in the root of this 

4# repository for complete details. 

5 

6from __future__ import annotations 

7 

8import sys 

9import traceback 

10 

11from io import StringIO 

12from types import FrameType 

13from typing import Callable 

14 

15from .contextvars import _ASYNC_CALLING_STACK 

16from .typing import ExcInfo 

17 

18 

19def _format_exception(exc_info: ExcInfo) -> str: 

20 """ 

21 Prettyprint an `exc_info` tuple. 

22 

23 Shamelessly stolen from stdlib's logging module. 

24 """ 

25 sio = StringIO() 

26 

27 traceback.print_exception(exc_info[0], exc_info[1], exc_info[2], None, sio) 

28 s = sio.getvalue() 

29 sio.close() 

30 if s[-1:] == "\n": 

31 s = s[:-1] 

32 

33 return s 

34 

35 

36def _find_first_app_frame_and_name( 

37 additional_ignores: list[str] | None = None, 

38 *, 

39 stacklevel: int | None = None, 

40 _getframe: Callable[[], FrameType] = sys._getframe, 

41) -> tuple[FrameType, str]: 

42 """ 

43 Remove all intra-structlog calls and return the relevant app frame. 

44 

45 Args: 

46 additional_ignores: 

47 Additional names with which the first frame must not start. 

48 

49 stacklevel: 

50 After getting out of structlog, skip this many frames. 

51 

52 _getframe: 

53 Callable to find current frame. Only for testing to avoid 

54 monkeypatching of sys._getframe. 

55 

56 Returns: 

57 tuple of (frame, name) 

58 """ 

59 ignores = ("structlog", *tuple(additional_ignores or ())) 

60 f = _ASYNC_CALLING_STACK.get(_getframe()) 

61 name = f.f_globals.get("__name__") or "?" 

62 

63 while name.startswith(ignores): 

64 if f.f_back is None: 

65 name = "?" 

66 break 

67 f = f.f_back 

68 name = f.f_globals.get("__name__") or "?" 

69 

70 if stacklevel is not None: 

71 for _ in range(stacklevel): 

72 if f.f_back is None: 

73 break 

74 f = f.f_back 

75 name = f.f_globals.get("__name__") or "?" 

76 

77 return f, name 

78 

79 

80def _format_stack(frame: FrameType) -> str: 

81 """ 

82 Pretty-print the stack of *frame* like logging would. 

83 """ 

84 sio = StringIO() 

85 

86 sio.write("Stack (most recent call last):\n") 

87 traceback.print_stack(frame, file=sio) 

88 sinfo = sio.getvalue() 

89 if sinfo[-1] == "\n": 

90 sinfo = sinfo[:-1] 

91 sio.close() 

92 

93 return sinfo