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
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
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.
6from __future__ import annotations
8import sys
9import traceback
11from io import StringIO
12from types import FrameType
13from typing import Callable
15from .contextvars import _ASYNC_CALLING_STACK
16from .typing import ExcInfo
19def _format_exception(exc_info: ExcInfo) -> str:
20 """
21 Prettyprint an `exc_info` tuple.
23 Shamelessly stolen from stdlib's logging module.
24 """
25 sio = StringIO()
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]
33 return s
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.
45 Args:
46 additional_ignores:
47 Additional names with which the first frame must not start.
49 stacklevel:
50 After getting out of structlog, skip this many frames.
52 _getframe:
53 Callable to find current frame. Only for testing to avoid
54 monkeypatching of sys._getframe.
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 "?"
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 "?"
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 "?"
77 return f, name
80def _format_stack(frame: FrameType) -> str:
81 """
82 Pretty-print the stack of *frame* like logging would.
83 """
84 sio = StringIO()
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()
93 return sinfo