File: base.py

package info (click to toggle)
python-pyinstrument 5.1.2%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,672 kB
  • sloc: python: 6,907; ansic: 897; makefile: 46; sh: 26; javascript: 18
file content (121 lines) | stat: -rw-r--r-- 3,798 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
from __future__ import annotations

import contextlib
from typing import Any, List

from pyinstrument import processors
from pyinstrument.frame import Frame
from pyinstrument.session import Session

# pyright: strict


ProcessorList = List[processors.ProcessorType]


class Renderer:
    """
    Abstract base class for renderers.
    """

    output_file_extension: str = "txt"
    """
    Renderer output file extension without dot prefix. The default value is `txt`
    """

    output_is_binary: bool = False
    """
    Whether the output of this renderer is binary data. The default value is `False`.
    """

    def __init__(self):
        pass

    def render(self, session: Session) -> str:
        """
        Return a string that contains the rendered form of `frame`.
        """
        raise NotImplementedError()

    class MisconfigurationError(Exception):
        pass


class FrameRenderer(Renderer):
    """
    An abstract base class for renderers that process Frame objects using
    processor functions. Provides a common interface to manipulate the
    processors before rendering.
    """

    processors: ProcessorList
    """
    Processors installed on this renderer. This property is defined on the
    base class to provide a common way for users to add and
    manipulate them before calling :func:`render`.
    """

    processor_options: dict[str, Any]
    """
    Dictionary containing processor options, passed to each processor.
    """

    show_all: bool
    timeline: bool

    def __init__(
        self,
        show_all: bool = False,
        timeline: bool = False,
        processor_options: dict[str, Any] | None = None,
    ):
        """
        :param show_all: Don't hide or filter frames - show everything that pyinstrument captures.
        :param timeline: Instead of aggregating time, leave the samples in chronological order.
        :param processor_options: A dictionary of processor options.
        """
        # processors is defined on the base class to provide a common way for users to
        # add to and manipulate them before calling render()
        self.processors = self.default_processors()
        self.processor_options = processor_options or {}

        self.show_all = show_all
        self.timeline = timeline

        if show_all:
            for p in (
                processors.group_library_frames_processor,
                processors.remove_importlib,
                processors.remove_irrelevant_nodes,
                processors.remove_tracebackhide,
                # note: we're not removing these processors
                # processors.remove_unnecessary_self_time_nodes,
                #    (still hide the inner pyinstrument synthetic frames)
                # processors.remove_first_pyinstrument_frames_processor,
                #    (still hide the outer pyinstrument calling frames)
            ):
                with contextlib.suppress(ValueError):
                    # don't care if the processor isn't in the list
                    self.processors.remove(p)

        if timeline:
            with contextlib.suppress(ValueError):
                self.processors.remove(processors.aggregate_repeated_calls)

    def default_processors(self) -> ProcessorList:
        """
        Return a list of processors that this renderer uses by default.
        """
        raise NotImplementedError()

    def preprocess(self, root_frame: Frame | None) -> Frame | None:
        frame = root_frame
        for processor in self.processors:
            frame = processor(frame, options=self.processor_options)
        return frame

    def render(self, session: Session) -> str:
        """
        Return a string that contains the rendered form of `frame`.
        """
        raise NotImplementedError()