From 5d9ba4bb147075e74dda7fbffc9ccaa90183dfe5 Mon Sep 17 00:00:00 2001 From: schlamar Date: Fri, 18 Apr 2014 14:07:36 +0200 Subject: [PATCH 1/3] Use pytest_load_initial_conftest to start collecting. --- pytest_cov.py | 79 ++++++++++++++++++++++++++++----------------------- setup.py | 2 +- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/pytest_cov.py b/pytest_cov.py index 233b38a5..1b03b3eb 100644 --- a/pytest_cov.py +++ b/pytest_cov.py @@ -1,6 +1,11 @@ """Coverage plugin for pytest.""" +import pytest + +import cov_core + + def pytest_addoption(parser): """Add options to control coverage.""" @@ -25,11 +30,21 @@ def pytest_addoption(parser): 'default: False') +@pytest.mark.try_last +def pytest_load_initial_conftests(early_config, parser, args): + ns = parser.parse_known_args(args) + if ns.cov_source: + plugin = CovPlugin(ns, early_config.pluginmanager) + early_config.pluginmanager.register(plugin, '_cov') + + def pytest_configure(config): """Activate coverage plugin if appropriate.""" - if config.getvalue('cov_source'): - config.pluginmanager.register(CovPlugin(), '_cov') + if not config.pluginmanager.hasplugin('_cov'): + plugin = CovPlugin(config.option, config.pluginmanager, + start=False) + config.pluginmanager.register(plugin, '_cov') class CovPlugin(object): @@ -40,7 +55,7 @@ class CovPlugin(object): distributed slave. """ - def __init__(self): + def __init__(self, options, pluginmanager, start=True): """Creates a coverage pytest plugin. We read the rc file that coverage uses to get the data file @@ -50,49 +65,42 @@ def __init__(self): # Our implementation is unknown at this time. self.cov_controller = None - self.no_cov_on_fail = None self.failed = False + self.options = options + + is_dist = (getattr(options, 'numprocesses', False) or + getattr(options, 'distload', False) or + getattr(options, 'dist', 'no') != 'no') + if is_dist and start: + self.start(cov_core.DistMaster) + elif start: + self.start(cov_core.Central) + + # slave is started in pytest hook + + def start(self, controller_cls, config=None, nodeid=None): + self.cov_controller = controller_cls( + self.options.cov_source, + self.options.cov_report or ['term'], + self.options.cov_config, + config, + nodeid + ) + self.cov_controller.start() def pytest_sessionstart(self, session): """At session start determine our implementation and delegate to it.""" - - import cov_core - - cov_source = session.config.getvalue('cov_source') - cov_report = session.config.getvalue('cov_report') or ['term'] - cov_config = session.config.getvalue('cov_config') - self.no_cov_on_fail = session.config.getvalue('no_cov_on_fail') - - session_name = session.__class__.__name__ - is_master = (session.config.pluginmanager.hasplugin('dsession') or - session_name == 'DSession') - is_slave = (hasattr(session.config, 'slaveinput') or - session_name == 'SlaveSession') - nodeid = None - - if is_master: - controller_cls = cov_core.DistMaster - elif is_slave: - controller_cls = cov_core.DistSlave + is_slave = hasattr(session.config, 'slaveinput') + if is_slave: nodeid = session.config.slaveinput.get('slaveid', getattr(session, 'nodeid')) - else: - controller_cls = cov_core.Central - - self.cov_controller = controller_cls(cov_source, - cov_report, - cov_config, - session.config, - nodeid) - - self.cov_controller.start() + self.start(cov_core.DistSlave, session.config, nodeid) def pytest_configure_node(self, node): """Delegate to our implementation. Mark this hook as optional in case xdist is not installed. """ - self.cov_controller.configure_node(node) pytest_configure_node.optionalhook = True @@ -101,7 +109,6 @@ def pytest_testnodedown(self, node, error): Mark this hook as optional in case xdist is not installed. """ - self.cov_controller.testnodedown(node, error) pytest_testnodedown.optionalhook = True @@ -112,7 +119,7 @@ def pytest_sessionfinish(self, session, exitstatus): def pytest_terminal_summary(self, terminalreporter): """Delegate to our implementation.""" - if not (self.failed and self.no_cov_on_fail): + if not (self.failed and self.options.no_cov_on_fail): self.cov_controller.summary(terminalreporter._tw) diff --git a/setup.py b/setup.py index b8bb56f7..f25ae423 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ author_email='marc.schlaich@gmail.com', url='https://github.com/schlamar/pytest-cov', py_modules=['pytest_cov'], - install_requires=['pytest>=2.2.3', + install_requires=['pytest>=2.5.2', 'cov-core>=1.6'], entry_points={'pytest11': ['pytest_cov = pytest_cov']}, license='MIT License', From e6b30db144af2abc1bfe0c9336c29c800a07a6c8 Mon Sep 17 00:00:00 2001 From: schlamar Date: Thu, 24 Apr 2014 11:41:48 +0200 Subject: [PATCH 2/3] Set cov-core dependency to 1.8 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f25ae423..d17a6e71 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ url='https://github.com/schlamar/pytest-cov', py_modules=['pytest_cov'], install_requires=['pytest>=2.5.2', - 'cov-core>=1.6'], + 'cov-core>=1.8'], entry_points={'pytest11': ['pytest_cov = pytest_cov']}, license='MIT License', zip_safe=False, From 2212e9898298d1a03e0682717fb808d49b48e06b Mon Sep 17 00:00:00 2001 From: schlamar Date: Thu, 24 Apr 2014 12:49:55 +0200 Subject: [PATCH 3/3] Added test case for conftest coverage. --- test_pytest_cov.py | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test_pytest_cov.py b/test_pytest_cov.py index 993c2ca9..9b8326bb 100644 --- a/test_pytest_cov.py +++ b/test_pytest_cov.py @@ -326,3 +326,52 @@ def test_multiprocessing_subprocess(testdir): '*1 passed*' ]) assert result.ret == 0 + + +MODULE = ''' +def func(): + return 1 + +''' + +CONFTEST = ''' + +import mod +mod.func() + +''' + +BASIC_TEST = ''' + +def test_basic(): + assert True + +''' + +CONF_RESULT = 'mod * 2 * 100% *' + + +def test_cover_conftest(testdir): + testdir.makepyfile(mod=MODULE) + testdir.makeconftest(CONFTEST) + script = testdir.makepyfile(BASIC_TEST) + result = testdir.runpytest('-v', + '--cov=%s' % script.dirpath(), + '--cov-report=term-missing', + script) + assert result.ret == 0 + result.stdout.fnmatch_lines([CONF_RESULT]) + + +def test_cover_conftest_dist(testdir): + testdir.makepyfile(mod=MODULE) + testdir.makeconftest(CONFTEST) + script = testdir.makepyfile(BASIC_TEST) + result = testdir.runpytest('-v', + '--cov=%s' % script.dirpath(), + '--cov-report=term-missing', + '--dist=load', + '--tx=2*popen', + script) + assert result.ret == 0 + result.stdout.fnmatch_lines([CONF_RESULT])