summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2019-11-15 07:39:43 -0500
committerNed Batchelder <ned@nedbatchelder.com>2019-11-15 07:39:43 -0500
commit21461cde236b8d3c33661295183253d47447ebdb (patch)
tree1469653d5fb69f22133afed566014e202544e38d
parent8deaa090297bf378a1738d64002163246e84d913 (diff)
downloadpython-coveragepy-git-21461cde236b8d3c33661295183253d47447ebdb.tar.gz
Make howitworks current
-rw-r--r--coverage/plugin.py16
-rw-r--r--doc/howitworks.rst67
2 files changed, 57 insertions, 26 deletions
diff --git a/coverage/plugin.py b/coverage/plugin.py
index 5f66dfb9..b9cb7238 100644
--- a/coverage/plugin.py
+++ b/coverage/plugin.py
@@ -57,6 +57,8 @@ attributes whose names start with ``_coverage_``. Don't be startled.
your importable Python package.
+.. _file_tracer_plugins:
+
File Tracers
============
@@ -69,6 +71,8 @@ In your ``coverage_init`` function, use the ``add_file_tracer`` method to
register your file tracer.
+.. _configurer_plugins:
+
Configurers
===========
@@ -81,6 +85,7 @@ change the configuration.
In your ``coverage_init`` function, use the ``add_configurer`` method to
register your configurer.
+
.. _dynamic_context_plugins:
Dynamic Context Switchers
@@ -121,13 +126,14 @@ class CoveragePlugin(object):
Every Python source file is offered to your plug-in to give it a chance
to take responsibility for tracing the file. If your plug-in can
- handle the file, then return a :class:`FileTracer` object. Otherwise
- return None.
+ handle the file, it should return a :class:`FileTracer` object.
+ Otherwise return None.
There is no way to register your plug-in for particular files.
- Instead, this method is invoked for all files, and the plug-in decides
- whether it can trace the file or not. Be prepared for `filename` to
- refer to all kinds of files that have nothing to do with your plug-in.
+ Instead, this method is invoked for all files as they are executed,
+ and the plug-in decides whether it can trace the file or not.
+ Be prepared for `filename` to refer to all kinds of files that have
+ nothing to do with your plug-in.
The file name will be a Python file being executed. There are two
broad categories of behavior for a plug-in, depending on the kind of
diff --git a/doc/howitworks.rst b/doc/howitworks.rst
index e25f88d5..f1599dc7 100644
--- a/doc/howitworks.rst
+++ b/doc/howitworks.rst
@@ -8,8 +8,9 @@ How coverage.py works
=====================
For advanced use of coverage.py, or just because you are curious, it helps to
-understand what's happening behind the scenes. Coverage.py works in three
-phases:
+understand what's happening behind the scenes.
+
+Coverage.py works in three phases:
* **Execution**: Coverage.py runs your code, and monitors it to see what lines
were executed.
@@ -24,20 +25,28 @@ The execution phase is handled by the ``coverage run`` command. The analysis
and reporting phases are handled by the reporting commands like ``coverage
report`` or ``coverage html``.
+As a short-hand, I say that coverage.py measures what lines were executed. But
+it collects more information than that. It can measure what branches were
+taken, and if you have contexts enabled, for each line or branch, it will also
+measure what contexts they were executed in.
+
Let's look at each phase in more detail.
Execution
---------
-At the heart of the execution phase is a Python trace function. This is a
-function that the Python interpreter invokes for each line executed in a
-program. Coverage.py implements a trace function that records each file and
-line number as it is executed.
+At the heart of the execution phase is a trace function. This is a function
+that the Python interpreter invokes for each line executed in a program.
+Coverage.py implements a trace function that records each file and line number
+as it is executed.
+
+For more details of trace functions, see the Python docs for `sys.settrace`_,
+or if you are really brave, `How C trace functions really work`_.
Executing a function for every line in your program can make execution very
slow. Coverage.py's trace function is implemented in C to reduce that
-slowdown. It also takes care to not trace code that you aren't interested in.
+overhead. It also takes care to not trace code that you aren't interested in.
When measuring branch coverage, the same trace function is used, but instead of
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
transitioned from the previous line to this line. Internally, these are called
arcs.
-For more details of trace functions, see the Python docs for `sys.settrace`_,
-or if you are really brave, `How C trace functions really work`_.
-
-At the end of execution, coverage.py writes the data it collected to a data
-file, usually named ``.coverage``. This is a JSON-based file containing all of
-the recorded file names and line numbers executed.
+As the data is being collected, coverage.py writes the data to a file, usually
+named ``.coverage``. This is a :ref:`SQLite database <dbschema>` containing
+all of the measured data.
.. _sys.settrace: https://docs.python.org/3/library/sys.html#sys.settrace
.. _How C trace functions really work: https://nedbatchelder.com/text/trace-function.html
+Plugins
+.......
+
+Of course coverage.py mostly measures execution of Python files. But it can
+also be used to analyze other kinds of execution. :ref:`File tracer plugins
+<file_tracer_plugins>` provide support for non-Python files. For example,
+Django HTML templates result in Python code being executed somewhere, but as a
+developer, you want that execution mapped back to your .html template file.
+
+During execution, each new Python file encountered is provided to the plugins
+to consider. A plugin can claim the file and then convert the runtime Python
+execution into source-level data to be recorded.
+
+
+Dynamic contexts
+................
+
+When using :ref:`dynamic contexts <dynamic_contexts>`, there is a current
+dynamic context that changes over the course of execution. It starts as empty.
+While it is empty, every time a new function is entered, a check is made to see
+if the dynamic context should change. While a non-empty dynamic context is
+current, the check is skipped until the function that started the context
+returns.
+
+
Analysis
--------
@@ -67,7 +98,7 @@ reads this table to get the set of executable lines, with a little more source
analysis to leave out things like docstrings.
The data file is read to get the set of lines that were executed. The
-difference between the executable lines, and the executed lines, are the lines
+difference between the executable lines and the executed lines are the lines
that were not executed.
The same principle applies for branch measurement, though the process for
@@ -81,12 +112,6 @@ Reporting
Once we have the set of executed lines and missing lines, reporting is just a
matter of formatting that information in a useful way. Each reporting method
-(text, html, json, annotated source, xml) has a different output format, but
+(text, HTML, JSON, annotated source, XML) has a different output format, but
the process is the same: write out the information in the particular format,
possibly including the source code itself.
-
-
-Plugins
--------
-
-Plugins interact with these phases.