@@ -8,8 +8,9 @@ How coverage.py works
8
8
=====================
9
9
10
10
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:
13
14
14
15
* **Execution **: Coverage.py runs your code, and monitors it to see what lines
15
16
were executed.
@@ -24,20 +25,28 @@ The execution phase is handled by the ``coverage run`` command. The analysis
24
25
and reporting phases are handled by the reporting commands like ``coverage
25
26
report `` or ``coverage html ``.
26
27
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
+
27
33
Let's look at each phase in more detail.
28
34
29
35
30
36
Execution
31
37
---------
32
38
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 `_.
37
46
38
47
Executing a function for every line in your program can make execution very
39
48
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.
41
50
42
51
When measuring branch coverage, the same trace function is used, but instead of
43
52
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
46
55
transitioned from the previous line to this line. Internally, these are called
47
56
arcs.
48
57
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.
55
61
56
62
.. _sys.settrace : https://docs.python.org/3/library/sys.html#sys.settrace
57
63
.. _How C trace functions really work : https://nedbatchelder.com/text/trace-function.html
58
64
59
65
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
+
60
91
Analysis
61
92
--------
62
93
@@ -67,7 +98,7 @@ reads this table to get the set of executable lines, with a little more source
67
98
analysis to leave out things like docstrings.
68
99
69
100
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
71
102
that were not executed.
72
103
73
104
The same principle applies for branch measurement, though the process for
@@ -81,12 +112,6 @@ Reporting
81
112
82
113
Once we have the set of executed lines and missing lines, reporting is just a
83
114
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
85
116
the process is the same: write out the information in the particular format,
86
117
possibly including the source code itself.
87
-
88
-
89
- Plugins
90
- -------
91
-
92
- Plugins interact with these phases.
0 commit comments