File: pydevd_dont_trace.py

package info (click to toggle)
pydevd 3.3.0%2Bds-4
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 13,892 kB
  • sloc: python: 77,508; cpp: 1,869; sh: 368; makefile: 50; ansic: 4
file content (124 lines) | stat: -rw-r--r-- 3,563 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
"""
Support for a tag that allows skipping over functions while debugging.
"""

import linecache
import re

# To suppress tracing a method, add the tag @DontTrace
# to a comment either preceding or on the same line as
# the method definition
#
# E.g.:
# #@DontTrace
# def test1():
#     pass
#
#  ... or ...
#
# def test2(): #@DontTrace
#     pass
DONT_TRACE_TAG = "@DontTrace"

# Regular expression to match a decorator (at the beginning
# of a line).
RE_DECORATOR = re.compile(r"^\s*@")

# Mapping from code object to bool.
# If the key exists, the value is the cached result of should_trace_hook
_filename_to_ignored_lines = {}


def default_should_trace_hook(code, absolute_filename):
    """
    Return True if this frame should be traced, False if tracing should be blocked.
    """
    # First, check whether this code object has a cached value
    ignored_lines = _filename_to_ignored_lines.get(absolute_filename)
    if ignored_lines is None:
        # Now, look up that line of code and check for a @DontTrace
        # preceding or on the same line as the method.
        # E.g.:
        # #@DontTrace
        # def test():
        #     pass
        #  ... or ...
        # def test(): #@DontTrace
        #     pass
        ignored_lines = {}
        lines = linecache.getlines(absolute_filename)
        for i_line, line in enumerate(lines):
            j = line.find("#")
            if j >= 0:
                comment = line[j:]
                if DONT_TRACE_TAG in comment:
                    ignored_lines[i_line] = 1

                    # Note: when it's found in the comment, mark it up and down for the decorator lines found.
                    k = i_line - 1
                    while k >= 0:
                        if RE_DECORATOR.match(lines[k]):
                            ignored_lines[k] = 1
                            k -= 1
                        else:
                            break

                    k = i_line + 1
                    while k <= len(lines):
                        if RE_DECORATOR.match(lines[k]):
                            ignored_lines[k] = 1
                            k += 1
                        else:
                            break

        _filename_to_ignored_lines[absolute_filename] = ignored_lines

    func_line = code.co_firstlineno - 1  # co_firstlineno is 1-based, so -1 is needed
    return not (
        func_line - 1 in ignored_lines  # -1 to get line before method
        or func_line in ignored_lines
    )  # method line


should_trace_hook = None


def clear_trace_filter_cache():
    """
    Clear the trace filter cache.
    Call this after reloading.
    """
    global should_trace_hook
    try:
        # Need to temporarily disable a hook because otherwise
        # _filename_to_ignored_lines.clear() will never complete.
        old_hook = should_trace_hook
        should_trace_hook = None

        # Clear the linecache
        linecache.clearcache()
        _filename_to_ignored_lines.clear()

    finally:
        should_trace_hook = old_hook


def trace_filter(mode):
    """
    Set the trace filter mode.

    mode: Whether to enable the trace hook.
      True: Trace filtering on (skipping methods tagged @DontTrace)
      False: Trace filtering off (trace methods tagged @DontTrace)
      None/default: Toggle trace filtering.
    """
    global should_trace_hook
    if mode is None:
        mode = should_trace_hook is None

    if mode:
        should_trace_hook = default_should_trace_hook
    else:
        should_trace_hook = None

    return mode