11 |
11 |
12 * File tracers implement tracing of non-Python file types. |
12 * File tracers implement tracing of non-Python file types. |
13 |
13 |
14 * Configurers add custom configuration, using Python code to change the |
14 * Configurers add custom configuration, using Python code to change the |
15 configuration. |
15 configuration. |
|
16 |
|
17 * Dynamic context switchers decide when the dynamic context has changed, for |
|
18 example, to record what test function produced the coverage. |
16 |
19 |
17 To write a coverage.py plug-in, create a module with a subclass of |
20 To write a coverage.py plug-in, create a module with a subclass of |
18 :class:`~coverage.CoveragePlugin`. You will override methods in your class to |
21 :class:`~coverage.CoveragePlugin`. You will override methods in your class to |
19 participate in various aspects of coverage.py's processing. |
22 participate in various aspects of coverage.py's processing. |
20 Different types of plug-ins have to override different methods. |
23 Different types of plug-ins have to override different methods. |
52 |
55 |
53 One solution is to put your plugins in your project tree, but not in |
56 One solution is to put your plugins in your project tree, but not in |
54 your importable Python package. |
57 your importable Python package. |
55 |
58 |
56 |
59 |
|
60 .. _file_tracer_plugins: |
|
61 |
57 File Tracers |
62 File Tracers |
58 ============ |
63 ============ |
59 |
64 |
60 File tracers implement measurement support for non-Python files. File tracers |
65 File tracers implement measurement support for non-Python files. File tracers |
61 implement the :meth:`~coverage.CoveragePlugin.file_tracer` method to claim |
66 implement the :meth:`~coverage.CoveragePlugin.file_tracer` method to claim |
76 change the configuration. |
83 change the configuration. |
77 |
84 |
78 In your ``coverage_init`` function, use the ``add_configurer`` method to |
85 In your ``coverage_init`` function, use the ``add_configurer`` method to |
79 register your configurer. |
86 register your configurer. |
80 |
87 |
|
88 |
|
89 .. _dynamic_context_plugins: |
|
90 |
|
91 Dynamic Context Switchers |
|
92 ========================= |
|
93 |
|
94 .. versionadded:: 5.0 |
|
95 |
|
96 Dynamic context switcher plugins implement the |
|
97 :meth:`~coverage.CoveragePlugin.dynamic_context` method to dynamically compute |
|
98 the context label for each measured frame. |
|
99 |
|
100 Computed context labels are useful when you want to group measured data without |
|
101 modifying the source code. |
|
102 |
|
103 For example, you could write a plugin that checks `frame.f_code` to inspect |
|
104 the currently executed method, and set the context label to a fully qualified |
|
105 method name if it's an instance method of `unittest.TestCase` and the method |
|
106 name starts with 'test'. Such a plugin would provide basic coverage grouping |
|
107 by test and could be used with test runners that have no built-in coveragepy |
|
108 support. |
|
109 |
|
110 In your ``coverage_init`` function, use the ``add_dynamic_context`` method to |
|
111 register your dynamic context switcher. |
|
112 |
81 """ |
113 """ |
82 |
114 |
83 from coverage import files |
115 from coverage import files |
84 from coverage.misc import contract, _needs_to_implement |
116 from coverage.misc import contract, _needs_to_implement |
85 |
117 |
92 |
124 |
93 Plug-in type: file tracer. |
125 Plug-in type: file tracer. |
94 |
126 |
95 Every Python source file is offered to your plug-in to give it a chance |
127 Every Python source file is offered to your plug-in to give it a chance |
96 to take responsibility for tracing the file. If your plug-in can |
128 to take responsibility for tracing the file. If your plug-in can |
97 handle the file, then return a :class:`FileTracer` object. Otherwise |
129 handle the file, it should return a :class:`FileTracer` object. |
98 return None. |
130 Otherwise return None. |
99 |
131 |
100 There is no way to register your plug-in for particular files. |
132 There is no way to register your plug-in for particular files. |
101 Instead, this method is invoked for all files, and the plug-in decides |
133 Instead, this method is invoked for all files as they are executed, |
102 whether it can trace the file or not. Be prepared for `filename` to |
134 and the plug-in decides whether it can trace the file or not. |
103 refer to all kinds of files that have nothing to do with your plug-in. |
135 Be prepared for `filename` to refer to all kinds of files that have |
|
136 nothing to do with your plug-in. |
104 |
137 |
105 The file name will be a Python file being executed. There are two |
138 The file name will be a Python file being executed. There are two |
106 broad categories of behavior for a plug-in, depending on the kind of |
139 broad categories of behavior for a plug-in, depending on the kind of |
107 files your plug-in supports: |
140 files your plug-in supports: |
108 |
141 |
132 Plug-in type: file tracer. |
165 Plug-in type: file tracer. |
133 |
166 |
134 This will only be invoked if `filename` returns non-None from |
167 This will only be invoked if `filename` returns non-None from |
135 :meth:`file_tracer`. It's an error to return None from this method. |
168 :meth:`file_tracer`. It's an error to return None from this method. |
136 |
169 |
137 Returns a :class:`FileReporter` object to use to report on `filename`. |
170 Returns a :class:`FileReporter` object to use to report on `filename`, |
|
171 or the string `"python"` to have coverage.py treat the file as Python. |
138 |
172 |
139 """ |
173 """ |
140 _needs_to_implement(self, "file_reporter") |
174 _needs_to_implement(self, "file_reporter") |
|
175 |
|
176 def dynamic_context(self, frame): # pylint: disable=unused-argument |
|
177 """Get the dynamically computed context label for `frame`. |
|
178 |
|
179 Plug-in type: dynamic context. |
|
180 |
|
181 This method is invoked for each frame when outside of a dynamic |
|
182 context, to see if a new dynamic context should be started. If it |
|
183 returns a string, a new context label is set for this and deeper |
|
184 frames. The dynamic context ends when this frame returns. |
|
185 |
|
186 Returns a string to start a new dynamic context, or None if no new |
|
187 context should be started. |
|
188 |
|
189 """ |
|
190 return None |
141 |
191 |
142 def find_executable_files(self, src_dir): # pylint: disable=unused-argument |
192 def find_executable_files(self, src_dir): # pylint: disable=unused-argument |
143 """Yield all of the executable files in `src_dir`, recursively. |
193 """Yield all of the executable files in `src_dir`, recursively. |
144 |
194 |
145 Plug-in type: file tracer. |
195 Plug-in type: file tracer. |