Skip to content

Commit 21461cd

Browse files
committedNov 15, 2019
Make howitworks current
1 parent 8deaa09 commit 21461cd

File tree

2 files changed

+57
-26
lines changed

2 files changed

+57
-26
lines changed
 

‎coverage/plugin.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ def coverage_init(reg, options):
5757
your importable Python package.
5858
5959
60+
.. _file_tracer_plugins:
61+
6062
File Tracers
6163
============
6264
@@ -69,6 +71,8 @@ def coverage_init(reg, options):
6971
register your file tracer.
7072
7173
74+
.. _configurer_plugins:
75+
7276
Configurers
7377
===========
7478
@@ -81,6 +85,7 @@ def coverage_init(reg, options):
8185
In your ``coverage_init`` function, use the ``add_configurer`` method to
8286
register your configurer.
8387
88+
8489
.. _dynamic_context_plugins:
8590
8691
Dynamic Context Switchers
@@ -121,13 +126,14 @@ def file_tracer(self, filename): # pylint: disable=unused-argument
121126
122127
Every Python source file is offered to your plug-in to give it a chance
123128
to take responsibility for tracing the file. If your plug-in can
124-
handle the file, then return a :class:`FileTracer` object. Otherwise
125-
return None.
129+
handle the file, it should return a :class:`FileTracer` object.
130+
Otherwise return None.
126131
127132
There is no way to register your plug-in for particular files.
128-
Instead, this method is invoked for all files, and the plug-in decides
129-
whether it can trace the file or not. Be prepared for `filename` to
130-
refer to all kinds of files that have nothing to do with your plug-in.
133+
Instead, this method is invoked for all files as they are executed,
134+
and the plug-in decides whether it can trace the file or not.
135+
Be prepared for `filename` to refer to all kinds of files that have
136+
nothing to do with your plug-in.
131137
132138
The file name will be a Python file being executed. There are two
133139
broad categories of behavior for a plug-in, depending on the kind of

‎doc/howitworks.rst

+46-21
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ How coverage.py works
88
=====================
99

1010
For advanced use of coverage.py, or just because you are curious, it helps to
11-
understand what's happening behind the scenes. Coverage.py works in three
12-
phases:
11+
understand what's happening behind the scenes.
12+
13+
Coverage.py works in three phases:
1314

1415
* **Execution**: Coverage.py runs your code, and monitors it to see what lines
1516
were executed.
@@ -24,20 +25,28 @@ The execution phase is handled by the ``coverage run`` command. The analysis
2425
and reporting phases are handled by the reporting commands like ``coverage
2526
report`` or ``coverage html``.
2627

28+
As a short-hand, I say that coverage.py measures what lines were executed. But
29+
it collects more information than that. It can measure what branches were
30+
taken, and if you have contexts enabled, for each line or branch, it will also
31+
measure what contexts they were executed in.
32+
2733
Let's look at each phase in more detail.
2834

2935

3036
Execution
3137
---------
3238

33-
At the heart of the execution phase is a Python trace function. This is a
34-
function that the Python interpreter invokes for each line executed in a
35-
program. Coverage.py implements a trace function that records each file and
36-
line number as it is executed.
39+
At the heart of the execution phase is a trace function. This is a function
40+
that the Python interpreter invokes for each line executed in a program.
41+
Coverage.py implements a trace function that records each file and line number
42+
as it is executed.
43+
44+
For more details of trace functions, see the Python docs for `sys.settrace`_,
45+
or if you are really brave, `How C trace functions really work`_.
3746

3847
Executing a function for every line in your program can make execution very
3948
slow. Coverage.py's trace function is implemented in C to reduce that
40-
slowdown. It also takes care to not trace code that you aren't interested in.
49+
overhead. It also takes care to not trace code that you aren't interested in.
4150

4251
When measuring branch coverage, the same trace function is used, but instead of
4352
recording line numbers, coverage.py records pairs of line numbers. Each
@@ -46,17 +55,39 @@ invocation records the pair `(prev, this)` to indicate that execution
4655
transitioned from the previous line to this line. Internally, these are called
4756
arcs.
4857

49-
For more details of trace functions, see the Python docs for `sys.settrace`_,
50-
or if you are really brave, `How C trace functions really work`_.
51-
52-
At the end of execution, coverage.py writes the data it collected to a data
53-
file, usually named ``.coverage``. This is a JSON-based file containing all of
54-
the recorded file names and line numbers executed.
58+
As the data is being collected, coverage.py writes the data to a file, usually
59+
named ``.coverage``. This is a :ref:`SQLite database <dbschema>` containing
60+
all of the measured data.
5561

5662
.. _sys.settrace: https://docs.python.org/3/library/sys.html#sys.settrace
5763
.. _How C trace functions really work: https://nedbatchelder.com/text/trace-function.html
5864

5965

66+
Plugins
67+
.......
68+
69+
Of course coverage.py mostly measures execution of Python files. But it can
70+
also be used to analyze other kinds of execution. :ref:`File tracer plugins
71+
<file_tracer_plugins>` provide support for non-Python files. For example,
72+
Django HTML templates result in Python code being executed somewhere, but as a
73+
developer, you want that execution mapped back to your .html template file.
74+
75+
During execution, each new Python file encountered is provided to the plugins
76+
to consider. A plugin can claim the file and then convert the runtime Python
77+
execution into source-level data to be recorded.
78+
79+
80+
Dynamic contexts
81+
................
82+
83+
When using :ref:`dynamic contexts <dynamic_contexts>`, there is a current
84+
dynamic context that changes over the course of execution. It starts as empty.
85+
While it is empty, every time a new function is entered, a check is made to see
86+
if the dynamic context should change. While a non-empty dynamic context is
87+
current, the check is skipped until the function that started the context
88+
returns.
89+
90+
6091
Analysis
6192
--------
6293

@@ -67,7 +98,7 @@ reads this table to get the set of executable lines, with a little more source
6798
analysis to leave out things like docstrings.
6899

69100
The data file is read to get the set of lines that were executed. The
70-
difference between the executable lines, and the executed lines, are the lines
101+
difference between the executable lines and the executed lines are the lines
71102
that were not executed.
72103

73104
The same principle applies for branch measurement, though the process for
@@ -81,12 +112,6 @@ Reporting
81112

82113
Once we have the set of executed lines and missing lines, reporting is just a
83114
matter of formatting that information in a useful way. Each reporting method
84-
(text, html, json, annotated source, xml) has a different output format, but
115+
(text, HTML, JSON, annotated source, XML) has a different output format, but
85116
the process is the same: write out the information in the particular format,
86117
possibly including the source code itself.
87-
88-
89-
Plugins
90-
-------
91-
92-
Plugins interact with these phases.

0 commit comments

Comments
 (0)
Please sign in to comment.