==============================================================
py2lcov - Translate Python ``Coverage.py`` data to lcov format
==============================================================

:Manual section: 1
:Manual group: |ToolName| Tools

NAME
----

py2lcov
  Translate Python ``Coverage.py`` data to lcov format



SYNOPSIS
--------

::

    py2lcov [--output mydata.info] [--test-name name] [options] coverage.dat+

DESCRIPTION
-----------

``py2lcov`` traverses Python coverage data in one or more coverage data files
(generated by the ``Coverage.py`` module) and translates it into LCOV ``.info``
format.

Note that the ``--no-functions`` argument may result in subtly inconsistent
coverage data if a ``no-functions`` coverage DB is merged with one which
contains derived function data. This is because the ``def myFunc(...)`` line
will acquire a hit count of 1 (the Python interpreter considers the ``def``
to have been executed when the line is interpreted, *i.e.*, when the function
is defined). This will generate an ``inconsistent`` error if the function is
not executed in your tests because the (derived) function will have a zero
hit count but the first line of the function has a non-zero count.

**Best practice**: Either always specify ``--no-functions`` or never specify
``--no-functions``.

``py2lcov`` uses ``Coverage.py`` to extract coverage data. The name of the
``Coverage.py`` executable may differ on your platform. By default, ``py2lcov``
uses ``coverage`` (expected to be in your PATH). You can use a different
executable via the ``COVERAGE_COMMAND`` environment variable or the ``--cmd``
command line option.

``py2lcov`` does not implement the full suite of |ToolName| features (*e.g.*, filtering,
substitutions, etc.). Generate the translated LCOV format file and then read
the data back into ``lcov`` to use those features.

**Branch Coverage Limitations**

Note that the XML coverage data format does not contain enough information
to deduce exactly which branch expressions have been taken or not taken.
It reports the total number of branch expressions associated with a particular
line, and the number of those which have been taken. There is no way to know
(except, possibly by inspection of surrounding code and/or some understanding
of your implementation) exactly which ones.

This is a problem in at least 2 ways:

- It is not straightforward to use the result to improve your regression
  suite because you don't really know what was exercised/not exercised.

- Coverage data merge is problematic. For example: you have two testcase
  XML files, each of which hit 4 of 8 branches on some line. Does that
  mean you hit 4 of them (both tests exercised the same code), all 8
  (tests exercised disjoint subsets), or some number between?

This implementation assumes that the first M branches are the ones which
are hit and the remaining N-M were not hit, in each testcase. Thus, the
combined result in the above example would claim 4 of 8 branches hit.
This definition turns out to be a lower bound.

OPTIONS
-------

``-i``, ``--input`` *file*
   **DEPRECATED**: Specify the input XML file from ``coverage.py``.

``-o``, ``--output`` *file*
   Specify the output LCOV ``.info`` file. Default: ``py2lcov.info``.

``-t``, ``--test-name``, ``--testname`` *name*
   Specify the test name for the ``TN:`` entry in the LCOV ``.info`` file.

``-e``, ``--exclude`` *patterns*
   Specify exclude file patterns separated by commas.

``-v``, ``--verbose``
   Print debug messages.

``--version-script`` *script*
   Version extract callback script.

``--checksum``
   Compute line checksum. See :manpage:`lcov(1)`.

``--no-functions``
   Do not derive function coverpoints.

``--tabwidth`` *n*
   Tab size when computing indent. Default: 8.

``-k``, ``--keep-going``
   Ignore errors and continue processing.

``--cmd`` *executable*
   Executable used to extract Python coverage data (*e.g.*, ``python3-coverage``).
   Default: ``coverage`` (or value from ``COVERAGE_COMMAND`` environment variable).

Note that ``py2lcov`` is a stand-alone Python executable - and so does *not*
directly support the standard |ToolName| command line and RC options - *e.g.*, for filtering, file inclusion and
exclusion, *etc.* 
To use these options, you will have to first use ``py2lcov`` to capture
your coverage DB, and then apply the options you want to use via 
``lcov -a pycov.info <options> ...``. See :manpage:`lcov(1)` for details.

EXAMPLES
--------

Basic workflow:

::

    $ export PYCOV_DATA=path/to/pydata

    # For 'coverage' versions 6.6.1 and higher (support "--data-file"):
    $ coverage run --data-file=${PYCOV_DATA} --append --branch \
        /path/to/myPythonScript.py args_to_my_python_script

    # For older versions without "--data-file" support:
    $ COVERAGE_FILE=${PYCOV_DATA} coverage run --append --branch \
        /path/to/myPythonScript.py args_to_my_python_script

    # Translate to LCOV format:
    $ py2lcov -o pydata.info ${PYCOV_DATA}

    # Apply filtering:
    $ lcov -a pydata.info -o filtered.info --filter branch,blank

    # Generate HTML report:
    $ genhtml -o html_report pydata.info

    # Generate filtered report:
    $ genhtml -o html_filtered filtered.info

    # Use differential coverage to see what filtering did:
    $ genhtml -o html_differential --baseline-file mydata.info filtered.info

Deprecated XML input mode:

::

    # First translate from Python coverage data to XML:
    $ coverage xml --data-file=${PYCOV_DATA} -o pydata.xml

    # Then translate XML to LCOV format:
    $ py2lcov -i pydata.xml -o pydata.info --version-script myCovScript

ENVIRONMENT
-----------

``COVERAGE_COMMAND``
   Override the default ``coverage`` executable used to extract Python coverage
   data.

``COVERAGE_FILE``
   Default input file if no files are specified on the command line.

AUTHOR
------

Henry Cox <henry.cox@mediatek.com>

SEE ALSO
--------

:manpage:`lcov(1)`, :manpage:`genhtml(1)`, :manpage:`geninfo(1)`

- ``Coverage.py`` documentation: https://coverage.readthedocs.io
