Как я могу совместить результаты покрытия с tox?

Для моего пакета mpu у меня есть код, зависящий от среды выполнения, например

if sys.version_info < (3, 0):
   pass  # do something
else:
   pass  # do something else

и файл tox

[tox]
envlist = py27,py36

[testenv]
deps =
    pytest
    pytest-cov
    pytest-pep8
    pydocstyle
commands =
    pip install -r test-requirements.txt
    pip install -e .[all]
    pytest .
    pydocstyle

и setup.cfg

[metadata]
description-file = README.md

[tool:pytest]
addopts = ./tests/ --doctest-modules --cov=./mpu --cov-report html:tests/reports/coverage-html --cov-report xml:tests/reports/coverage.xml --pep8 --ignore=docs/
doctest_encoding = utf-8

[pydocstyle]
ignore = D104, D105, D107, D301, D413, D203, D212, D100
match_dir = mpu

Похоже, что файл tox делает то, что я хочу, но покрытие доступно только для одной из протестированных сред. Я видел отчет о совокупном покрытии по нескольким версиям Python в ветвь coverage-combinedcoverage-комбинированный, но это не работает. При первом запуске кажется, что он не выполнил все тесты, поскольку тестовое покрытие было намного ниже, чем раньше. Полагаю, что доктесты не проводились. Для второго прогона я получаю

ERROR: InvocationError: '/home/moose/GitHub/mpu/.tox/py27/bin/coverage run --source=mpu/ setup.py test'

Система

$ coverage --version
Coverage.py, version 4.5.1 with C extension
Documentation at https://coverage.readthedocs.io

Ошибки

Теперь я получаю такую ​​ошибку:

======================================================================
ERROR: test_pd (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: test_pd
Traceback (most recent call last):
  File "/usr/lib/python3.6/unittest/loader.py", line 428, in _find_test_path
    module = self._get_module_from_name(name)
  File "/usr/lib/python3.6/unittest/loader.py", line 369, in _get_module_from_name
    __import__(name)
  File "/home/moose/GitHub/mpu/tests/test_pd.py", line 8, in <module>
    from mpu.pd import example_df
  File "/home/moose/GitHub/mpu/mpu/pd.py", line 10, in <module>
    import pandas as pd
  File "/home/moose/.local/lib/python3.6/site-packages/pandas/__init__.py", line 42, in <module>
    from pandas.core.api import *
  File "/home/moose/.local/lib/python3.6/site-packages/pandas/core/api.py", line 10, in <module>
    from pandas.core.groupby.groupby import Grouper
  File "/home/moose/.local/lib/python3.6/site-packages/pandas/core/groupby/__init__.py", line 2, in <module>
    from pandas.core.groupby.groupby import (
  File "/home/moose/.local/lib/python3.6/site-packages/pandas/core/groupby/groupby.py", line 49, in <module>
    from pandas.core.frame import DataFrame
  File "/home/moose/.local/lib/python3.6/site-packages/pandas/core/frame.py", line 74, in <module>
    from pandas.core.series import Series
  File "/home/moose/.local/lib/python3.6/site-packages/pandas/core/series.py", line 80, in <module>
    import pandas.plotting._core as gfx
  File "/home/moose/.local/lib/python3.6/site-packages/pandas/plotting/__init__.py", line 11, in <module>
    from pandas.plotting._core import boxplot
  File "/home/moose/.local/lib/python3.6/site-packages/pandas/plotting/_core.py", line 45, in <module>
    from pandas.plotting import _converter
  File "/home/moose/.local/lib/python3.6/site-packages/pandas/plotting/_converter.py", line 8, in <module>
    import matplotlib.units as units
  File "/home/moose/.local/lib/python3.6/site-packages/matplotlib/__init__.py", line 131, in <module>
    from matplotlib.rcsetup import defaultParams, validate_backend, cycler
  File "/home/moose/.local/lib/python3.6/site-packages/matplotlib/rcsetup.py", line 29, in <module>
    from matplotlib.fontconfig_pattern import parse_fontconfig_pattern
  File "/home/moose/.local/lib/python3.6/site-packages/matplotlib/fontconfig_pattern.py", line 22, in <module>
    from pyparsing import (Literal, ZeroOrMore, Optional, Regex, StringEnd,
  File "/home/moose/.local/lib/python3.6/site-packages/pyparsing.py", line 943, in <module>
    collections.MutableMapping.register(ParseResults)
  File "/usr/lib/python3.6/abc.py", line 158, in register
    if issubclass(subclass, cls):
  File "/usr/lib/python3.6/abc.py", line 228, in __subclasscheck__
    if issubclass(subclass, scls):
  File "/usr/lib/python3.6/abc.py", line 228, in __subclasscheck__
    if issubclass(subclass, scls):
  File "/usr/lib/python3.6/typing.py", line 1154, in __subclasscheck__
    return super().__subclasscheck__(cls)
  File "/usr/lib/python3.6/abc.py", line 209, in __subclasscheck__
    ok = cls.__subclasshook__(subclass)
  File "/usr/lib/python3.6/typing.py", line 884, in __extrahook__
    if issubclass(subclass, scls):
  File "/usr/lib/python3.6/typing.py", line 1154, in __subclasscheck__
    return super().__subclasscheck__(cls)
  File "/usr/lib/python3.6/abc.py", line 209, in __subclasscheck__
    ok = cls.__subclasshook__(subclass)
  File "/usr/lib/python3.6/typing.py", line 884, in __extrahook__
[...]
  File "/usr/lib/python3.6/typing.py", line 884, in __extrahook__
    if issubclass(subclass, scls):
  File "/usr/lib/python3.6/abc.py", line 206, in __subclasscheck__
    elif subclass in cls._abc_negative_cache:
  File "/usr/lib/python3.6/_weakrefset.py", line 75, in __contains__
    return wr in self.data
RecursionError: maximum recursion depth exceeded in comparison

person Martin Thoma    schedule 17.06.2018    source источник
comment
Это решено? Непонятно из раздела в конце. Можете просто уточнить?   -  person Tarun Lalwani    schedule 22.06.2018
comment
Нет, это не решено. Меня просто сбивает с толку тот факт, что --parallel-mode должен быть перед setup.py, и я хотел это отметить. Может мне стоит убрать эту часть из вопроса.   -  person Martin Thoma    schedule 22.06.2018
comment
Посмотрите, поможет ли это репо? github.com/avara1986/gozokia   -  person Tarun Lalwani    schedule 22.06.2018
comment
А, хорошо, это другой способ. Но я надеялся, что смогу сделать это с помощью tox. Я бы предпочел использовать tox в качестве команды для выполнения всего, что связано с тестами.   -  person Martin Thoma    schedule 22.06.2018
comment
Я думаю, что шаблон с begin,py{...},end подходит для этого, но я не понимаю, почему / как это вызывает ERROR: InvocationError   -  person Martin Thoma    schedule 22.06.2018


Ответы (1)


Я предполагаю, что у вас установлен pytest-cov. В этом случае довольно просто добавить покрытие. Вам просто нужно добавить --cov-append в раздел [tool:pytest].addopts.

[tool:pytest]
addopts = tests/ --doctest-modules --cov=./mpu --cov-append --cov-report html:tests/reports/coverage-html --cov-report xml:tests/reports/coverage.xml --pep8 --ignore=docs/
doctest_encoding = utf-8

Это объединит охват нескольких тестовых прогонов вместе. Это также полезно, если вы разделите интеграционные / модульные тесты.

person Tim Martin    schedule 25.06.2018
comment
Хотя я ценю ваш ответ (+1), похоже, он не решает проблемы. Смотрите ошибку, которую я добавил к вопросу. - person Martin Thoma; 25.06.2018
comment
@MartinThoma опубликованная вами ошибка не связана с параметром --cov-append - по какой-то причине тесты запускаются с unittest вместо pytest. Вы, должно быть, изменили что-то еще, чтобы вызвать это. - person hoefling; 26.06.2018
comment
Расскажите, пожалуйста, как вы выяснили, что проблема в unittest. Я мог бы исправить это сейчас: я позвонил coverage напрямую, вместо того, чтобы использовать pytest, и разрешил pytest-cov переадресацию вызовов. Спасибо! - person Martin Thoma; 26.06.2018