diff --git a/debug_toolbar/_stubs.py b/debug_toolbar/_stubs.py new file mode 100644 index 000000000..01d0b8637 --- /dev/null +++ b/debug_toolbar/_stubs.py @@ -0,0 +1,24 @@ +from typing import Any, List, NamedTuple, Optional, Tuple + +from django import template as dj_template + + +class InspectStack(NamedTuple): + frame: Any + filename: str + lineno: int + function: str + code_context: str + index: int + + +TidyStackTrace = List[Tuple[str, int, str, str, Optional[Any]]] + + +class RenderContext(dj_template.context.RenderContext): + template: dj_template.Template + + +class RequestContext(dj_template.RequestContext): + template: dj_template.Template + render_context: RenderContext diff --git a/debug_toolbar/utils.py b/debug_toolbar/utils.py index bd74e6eed..16727e7c8 100644 --- a/debug_toolbar/utils.py +++ b/debug_toolbar/utils.py @@ -4,13 +4,15 @@ import sys import warnings from pprint import pformat +from typing import Any, Dict, List, Optional, Sequence, Tuple, Union from asgiref.local import Local +from django.http import QueryDict from django.template import Node from django.utils.html import format_html -from django.utils.safestring import mark_safe +from django.utils.safestring import SafeString, mark_safe -from debug_toolbar import settings as dt_settings +from debug_toolbar import _stubs as stubs, settings as dt_settings try: import threading @@ -21,7 +23,7 @@ _local_data = Local() -def _is_excluded_frame(frame, excluded_modules): +def _is_excluded_frame(frame: Any, excluded_modules: Optional[Sequence[str]]) -> bool: if not excluded_modules: return False frame_module = frame.f_globals.get("__name__") @@ -34,7 +36,7 @@ def _is_excluded_frame(frame, excluded_modules): ) -def _stack_trace_deprecation_warning(): +def _stack_trace_deprecation_warning() -> None: warnings.warn( "get_stack() and tidy_stacktrace() are deprecated in favor of" " get_stack_trace()", @@ -43,7 +45,7 @@ def _stack_trace_deprecation_warning(): ) -def tidy_stacktrace(stack): +def tidy_stacktrace(stack: List[stubs.InspectStack]) -> stubs.TidyStackTrace: """ Clean up stacktrace and remove all entries that are excluded by the HIDE_IN_STACKTRACES setting. @@ -68,7 +70,7 @@ def tidy_stacktrace(stack): return trace -def render_stacktrace(trace): +def render_stacktrace(trace: stubs.TidyStackTrace) -> SafeString: show_locals = dt_settings.get_config()["ENABLE_STACKTRACES_LOCALS"] html = "" for abspath, lineno, func, code, locals_ in trace: @@ -103,7 +105,7 @@ def render_stacktrace(trace): return mark_safe(html) -def get_template_info(): +def get_template_info() -> Optional[Dict[str, Any]]: template_info = None cur_frame = sys._getframe().f_back try: @@ -131,7 +133,9 @@ def get_template_info(): return template_info -def get_template_context(node, context, context_lines=3): +def get_template_context( + node: Node, context: stubs.RequestContext, context_lines: int = 3 +) -> Dict[str, Any]: line, source_lines, name = get_template_source_from_exception_info(node, context) debug_context = [] start = max(1, line - context_lines) @@ -146,7 +150,9 @@ def get_template_context(node, context, context_lines=3): return {"name": name, "context": debug_context} -def get_template_source_from_exception_info(node, context): +def get_template_source_from_exception_info( + node: Node, context: stubs.RequestContext +) -> Tuple[int, List[Tuple[int, str]], str]: if context.template.origin == node.origin: exception_info = context.template.get_exception_info( Exception("DDT"), node.token @@ -161,7 +167,7 @@ def get_template_source_from_exception_info(node, context): return line, source_lines, name -def get_name_from_obj(obj): +def get_name_from_obj(obj: Any) -> str: if hasattr(obj, "__name__"): name = obj.__name__ else: @@ -174,7 +180,7 @@ def get_name_from_obj(obj): return name -def getframeinfo(frame, context=1): +def getframeinfo(frame: Any, context: int = 1) -> inspect.Traceback: """ Get information about a frame or traceback object. @@ -213,7 +219,9 @@ def getframeinfo(frame, context=1): return inspect.Traceback(filename, lineno, frame.f_code.co_name, lines, index) -def get_sorted_request_variable(variable): +def get_sorted_request_variable( + variable: Union[Dict[str, Any], QueryDict] +) -> Dict[str, Union[List[Tuple[str, Any]], Any]]: """ Get a data structure for showing a sorted list of variables from the request data. @@ -227,7 +235,7 @@ def get_sorted_request_variable(variable): return {"raw": variable} -def get_stack(context=1): +def get_stack(context=1) -> List[stubs.InspectStack]: """ Get a list of records for a frame and all higher (calling) frames. @@ -280,7 +288,13 @@ def get_source_file(self, frame): return value - def get_stack_trace(self, *, excluded_modules=None, include_locals=False, skip=0): + def get_stack_trace( + self, + *, + excluded_modules: Optional[Sequence[str]] = None, + include_locals: bool = False, + skip: int = 0, + ): trace = [] skip += 1 # Skip the frame for this method. for frame in _stack_frames(skip=skip):