Calculates Python code heatmap. Class that contains all logic related to calculating code heatmap for a Python program.
| 26 | |
| 27 | |
| 28 | class _CodeHeatmapCalculator: |
| 29 | """Calculates Python code heatmap. |
| 30 | |
| 31 | Class that contains all logic related to calculating code heatmap |
| 32 | for a Python program. |
| 33 | """ |
| 34 | |
| 35 | def __init__(self): |
| 36 | self.original_trace_function = sys.gettrace() |
| 37 | self.prev_lineno = None |
| 38 | self.prev_timestamp = None |
| 39 | self.prev_path = None |
| 40 | self.lines = deque() |
| 41 | self._execution_count = defaultdict(lambda: defaultdict(int)) |
| 42 | self._heatmap = defaultdict(lambda: defaultdict(float)) |
| 43 | |
| 44 | def __enter__(self): |
| 45 | """Enables heatmap calculator.""" |
| 46 | sys.settrace(self.record_line) |
| 47 | return self |
| 48 | |
| 49 | def __exit__(self, exc_type, exc_val, exc_tbf): |
| 50 | """Disables heatmap calculator.""" |
| 51 | sys.settrace(self.original_trace_function) |
| 52 | if self.prev_timestamp: |
| 53 | runtime = time.time() - self.prev_timestamp |
| 54 | self.lines.append([self.prev_path, self.prev_lineno, runtime]) |
| 55 | |
| 56 | def record_line(self, frame, event, arg): # pylint: disable=unused-argument |
| 57 | """Records line execution time.""" |
| 58 | if event == 'line': |
| 59 | if self.prev_timestamp: |
| 60 | runtime = time.time() - self.prev_timestamp |
| 61 | self.lines.append([self.prev_path, self.prev_lineno, runtime]) |
| 62 | self.prev_lineno = frame.f_lineno |
| 63 | self.prev_path = frame.f_code.co_filename |
| 64 | self.prev_timestamp = time.time() |
| 65 | return self.record_line |
| 66 | |
| 67 | @property |
| 68 | def lines_without_stdlib(self): |
| 69 | """Filters code from standard library from self.lines.""" |
| 70 | prev_line = None |
| 71 | current_module_path = inspect.getabsfile(inspect.currentframe()) |
| 72 | for module_path, lineno, runtime in self.lines: |
| 73 | module_abspath = os.path.abspath(module_path) |
| 74 | if not prev_line: |
| 75 | prev_line = [module_abspath, lineno, runtime] |
| 76 | else: |
| 77 | if (not check_standard_dir(module_path) and |
| 78 | module_abspath != current_module_path): |
| 79 | yield prev_line |
| 80 | prev_line = [module_abspath, lineno, runtime] |
| 81 | else: |
| 82 | prev_line[2] += runtime |
| 83 | yield prev_line |
| 84 | |
| 85 | def fill_heatmap(self): |
no outgoing calls
no test coverage detected