def test_subprocess_testmon(self): testmon = CoreTestmon("") testmon.setup_coverage(subprocess=True) path1 = self.make_file( "subprocesstest.py", """\ a=1 """, ) self.run_command(f"python {path1}") assert testmon.sub_cov_file in "{}".format( os.listdir(os.path.join(os.getcwd(), ".tmontmp"))) testmon.close()
class TestmonDeselect(object): def __init__(self, config, testmon_data): self.testmon_data = testmon_data self.testmon = Testmon(config.project_dirs, testmon_labels=testmon_options(config)) self.collection_ignored = set() self.testmon_save = True self.config = config self.reports = defaultdict(lambda: {}) self.selected, self.deselected = [], set() self.file_data = self.testmon_data.file_data() self.f_to_ignore = self.testmon_data.stable_files if self.config.getoption('tlf'): self.f_to_ignore -= self.testmon_data.f_last_failed def test_should_run(self, nodeid): if self.config.getoption('tlf'): if nodeid in self.testmon_data.fail_reports: return True if nodeid in self.testmon_data.stable_nodeids: return False else: return True def report_if_failed(self, nodeid): node_reports = self.testmon_data.fail_reports.get(nodeid, {}) for phase in ('setup', 'call', 'teardown'): if phase in node_reports: test_report = runner.TestReport(**node_reports[phase]) self.config.hook.pytest_runtest_logreport(report=test_report) def pytest_report_header(self, config): changed_files = ",".join(self.testmon_data.source_tree.changed_files) if changed_files == '' or len(changed_files) > 100: changed_files = len(self.testmon_data.source_tree.changed_files) active_message = "testmon={}, changed files: {}, skipping collection of {} files".format( config.getoption('testmon'), changed_files, len(self.testmon_data.stable_files)) if self.testmon_data.variant: return active_message + ", run variant: {}".format( self.testmon_data.variant) else: return active_message + "." def pytest_ignore_collect(self, path, config): strpath = os.path.relpath(path.strpath, config.rootdir.strpath) if strpath in (self.f_to_ignore): self.collection_ignored.update(self.testmon_data.f_tests[strpath]) return True @pytest.mark.trylast def pytest_collection_modifyitems(self, session, config, items): self.testmon_data.collect_garbage(retain=self.collection_ignored.union( set([item.nodeid for item in items]))) for item in items: assert item.nodeid not in self.collection_ignored, ( item.nodeid, self.collection_ignored) for item in items: if self.test_should_run(item.nodeid): self.selected.append(item) else: self.deselected.add(item.nodeid) items[:] = self.selected session.config.hook.pytest_deselected( items=([self.FakeItemFromTestmon(session.config)] * len(self.collection_ignored.union(self.deselected)))) def pytest_runtestloop(self, session): ignored_deselected = self.collection_ignored.union(self.deselected) for nodeid in ignored_deselected: self.report_if_failed(nodeid) @pytest.mark.hookwrapper def pytest_runtest_protocol(self, item, nextitem): if self.config.getoption('testmon') == u'readonly': yield else: self.testmon.start() result = yield if result.excinfo and issubclass(result.excinfo[0], KeyboardInterrupt): self.testmon.stop() else: self.testmon.stop_and_save(self.testmon_data, item.config.rootdir.strpath, item.nodeid, self.reports[item.nodeid]) def pytest_runtest_logreport(self, report): assert report.when not in self.reports, \ "{} {} {}".format(report.nodeid, report.when, self.reports) self.reports[report.nodeid][report.when] = serialize_report(report) class FakeItemFromTestmon(object): def __init__(self, config): self.config = config def pytest_internalerror(self, excrepr, excinfo): self.testmon_save = False def pytest_keyboard_interrupt(self, excinfo): self.testmon_save = False def pytest_sessionfinish(self, session): if self.testmon_save: self.testmon_data.write_data() self.testmon.close()
class TestmonDeselect(object): def __init__(self, config, testmon_data): self.testmon_data = testmon_data self.testmon = Testmon(config.project_dirs, testmon_labels=testmon_options(config) ) self.testmon_save = True self.config = config self.lastfailed = self.testmon_data.lastfailed def pytest_report_header(self, config): changed_files = ",".join([os.path.relpath(path, config.rootdir.strpath) for path in self.testmon_data.modules_cache]) if changed_files=='' or len(changed_files)>100: changed_files = len(self.testmon_data.modules_cache) active_message = "testmon={}, changed files: {}, skipping collection of {} items".format(config.getoption('testmon'), changed_files, sum(self.testmon_data.unaffected_paths.values())) if self.testmon_data.variant: return active_message + ", run variant: {}".format(self.testmon_data.variant) else: return active_message + "." def pytest_collection_modifyitems(self, session, config, items): selected, deselected = [], [] self.testmon_data.collect_garbage(allnodeids=[item.nodeid for item in items]) for item in items: if item.nodeid in self.lastfailed or self.testmon_data.test_should_run(item.nodeid): selected.append(item) else: deselected.append(item) items[:] = selected if deselected: config.hook.pytest_deselected(items=deselected) def pytest_runtest_protocol(self, __multicall__, item, nextitem): if self.config.getoption('testmon') == u'readonly': return __multicall__.execute() result, coverage_data = self.testmon.track_dependencies(__multicall__.execute, item.nodeid) self.testmon_data.set_dependencies(item.nodeid, coverage_data, item.config.rootdir.strpath) return result def pytest_runtest_logreport(self, report): if report.failed and "xfail" not in report.keywords: if report.nodeid not in self.lastfailed: self.lastfailed.append(report.nodeid) elif not report.failed: if report.when == "call": try: if report.nodeid in self.lastfailed: self.lastfailed.remove(report.nodeid) except KeyError: pass def pytest_ignore_collect(self, path, config): strpath = path.strpath if strpath in self.testmon_data.unaffected_paths: config.hook.pytest_deselected(items=['1'] * self.testmon_data.unaffected_paths[strpath]) return True def pytest_internalerror(self, excrepr, excinfo): self.testmon_save = False def pytest_keyboard_interrupt(self, excinfo): self.testmon_save = False def pytest_sessionfinish(self, session): if self.testmon_save: self.testmon_data.write_data() self.testmon.close()
class TestmonDeselect(object): def __init__(self, config, testmon_data): self.testmon_data = testmon_data self.testmon = Testmon(config.project_dirs, testmon_labels=testmon_options(config)) self.testmon_save = True self.config = config self.lastfailed = self.testmon_data.lastfailed def pytest_report_header(self, config): changed_files = ",".join([os.path.relpath(path, config.rootdir.strpath) for path in self.testmon_data.modules_cache]) if changed_files == '' or len(changed_files) > 100: changed_files = len(self.testmon_data.modules_cache) active_message = "testmon={}, changed files: {}, skipping collection of {} items".format( config.getoption('testmon'), changed_files, sum(self.testmon_data.unaffected_paths.values())) if self.testmon_data.variant: return active_message + ", run variant: {}".format(self.testmon_data.variant) else: return active_message + "." def pytest_collection_modifyitems(self, session, config, items): selected, deselected = [], [] self.testmon_data.collect_garbage(allnodeids=[item.nodeid for item in items]) for item in items: if item.nodeid in self.lastfailed or self.testmon_data.test_should_run(item.nodeid): selected.append(item) else: deselected.append(item) items[:] = selected if deselected: config.hook.pytest_deselected(items=deselected) @pytest.mark.hookwrapper def pytest_runtest_protocol(self, item, nextitem): if self.config.getoption('testmon') == u'readonly': yield self.testmon.start() result = yield # NOTE: pytest-watch also sends KeyboardInterrupt when changes are # detected. This should still save the collected data up until then. if result.excinfo and issubclass(result.excinfo[0], KeyboardInterrupt): self.testmon.stop() else: self.testmon.stop_and_save(self.testmon_data, item.config.rootdir.strpath, item.nodeid) def pytest_runtest_logreport(self, report): if report.failed and "xfail" not in report.keywords: if report.nodeid not in self.lastfailed: self.lastfailed.append(report.nodeid) elif not report.failed: if report.when == "call": try: if report.nodeid in self.lastfailed: self.lastfailed.remove(report.nodeid) except KeyError: pass class FakeItemFromTestmon(object): def __init__(self, config): self.config = config def pytest_ignore_collect(self, path, config): strpath = path.strpath if strpath in self.testmon_data.unaffected_paths: config.hook.pytest_deselected( items=([self.FakeItemFromTestmon(config)] * self.testmon_data.unaffected_paths[strpath])) return True def pytest_internalerror(self, excrepr, excinfo): self.testmon_save = False def pytest_sessionfinish(self, session): if self.testmon_save: self.testmon_data.write_data() self.testmon.close() def pytest_terminal_summary(self, terminalreporter, exitstatus=None): if (not self.testmon_save and terminalreporter.config.getvalue('verbose')): terminalreporter.line('testmon: not saving data')
class TestmonDeselect(object): def __init__(self, config, testmon_data): self.testmon_data = testmon_data self.testmon = Testmon(config.project_dirs, testmon_labels=testmon_options(config)) self.collection_ignored = set() self.testmon_save = True self.config = config def pytest_report_header(self, config): changed_files = ",".join(self.testmon_data.source_tree.changed_files) if changed_files == '' or len(changed_files) > 100: changed_files = len(self.testmon_data.source_tree.changed_files) active_message = "testmon={}, changed files: {}, skipping collection of {} items".format( config.getoption('testmon'), changed_files, len(self.testmon_data.unaffected_nodeids)) if self.testmon_data.variant: return active_message + ", run variant: {}".format( self.testmon_data.variant) else: return active_message + "." def report_if_failed(self, nodeid): if nodeid in self.testmon_data.fail_reports: for report in self.testmon_data.fail_reports[nodeid]: test_report = unserialize_report('testreport', report) self.config.hook.pytest_runtest_logreport(report=test_report) def pytest_collection_modifyitems(self, session, config, items): removed_nodeids = set( self.testmon_data.node_data) - self.collection_ignored - set( [item.nodeid for item in items]) if removed_nodeids: self.testmon_data.collect_garbage(removed_nodeids) selected, deselected = [], [] for item in items: assert item.nodeid not in self.collection_ignored if self.testmon_data.test_should_run(item.nodeid): selected.append(item) else: self.report_if_failed(item.nodeid) deselected.append(item) for nodeid in self.collection_ignored: self.report_if_failed(nodeid) items[:] = selected if deselected: config.hook.pytest_deselected(items=deselected) @pytest.mark.hookwrapper def pytest_runtest_protocol(self, item, nextitem): if self.config.getoption('testmon') == u'readonly': yield self.testmon.start() result = yield if result.excinfo and issubclass(result.excinfo[0], KeyboardInterrupt): self.testmon.stop() else: self.testmon.stop_and_save(self.testmon_data, item.config.rootdir.strpath, item.nodeid, self.testmon_data.reports[item.nodeid]) del self.testmon_data.reports[item.nodeid] def pytest_runtest_logreport(self, report): self.testmon_data.reports[report.nodeid].append( serialize_report(report)) class FakeItemFromTestmon(object): def __init__(self, config): self.config = config def pytest_ignore_collect(self, path, config): strpath = os.path.relpath(path.strpath, config.rootdir.strpath) if strpath in self.testmon_data.unaffected_files: if os.path.split(strpath)[1].startswith('test_'): for nodeid in self.testmon_data.file_data()[strpath]: self.collection_ignored.add(nodeid) config.hook.pytest_deselected( items=([self.FakeItemFromTestmon(config)] * len(self.testmon_data.file_data()[strpath]))) return True def pytest_internalerror(self, excrepr, excinfo): self.testmon_save = False def pytest_keyboard_interrupt(self, excinfo): self.testmon_save = False def pytest_sessionfinish(self, session): if self.testmon_save: self.testmon_data.write_data() self.testmon.close()
class TestmonDeselect(object): def __init__(self, config, testmon_data): self.testmon_data = testmon_data self.testmon = Testmon(config.project_dirs, testmon_labels=testmon_options(config)) self.testmon_save = True self.config = config self.lastfailed = self.testmon_data.lastfailed def pytest_report_header(self, config): changed_files = ",".join([ os.path.relpath(path, config.rootdir.strpath) for path in self.testmon_data.modules_cache ]) if changed_files == '' or len(changed_files) > 100: changed_files = len(self.testmon_data.modules_cache) active_message = "testmon={}, changed files: {}, skipping collection of {} items".format( config.getoption('testmon'), changed_files, sum(self.testmon_data.unaffected_paths.values())) if self.testmon_data.variant: return active_message + ", run variant: {}".format( self.testmon_data.variant) else: return active_message + "." def pytest_collection_modifyitems(self, session, config, items): selected, deselected = [], [] self.testmon_data.collect_garbage( allnodeids=[item.nodeid for item in items]) for item in items: if item.nodeid in self.lastfailed or self.testmon_data.test_should_run( item.nodeid): selected.append(item) else: deselected.append(item) items[:] = selected if deselected: config.hook.pytest_deselected(items=deselected) @pytest.mark.hookwrapper def pytest_runtest_protocol(self, item, nextitem): if self.config.getoption('testmon') == u'readonly': yield self.testmon.start() result = yield # NOTE: pytest-watch also sends KeyboardInterrupt when changes are # detected. This should still save the collected data up until then. if result.excinfo and issubclass(result.excinfo[0], KeyboardInterrupt): self.testmon.stop() else: self.testmon.stop_and_save(self.testmon_data, item.config.rootdir.strpath, item.nodeid) def pytest_runtest_logreport(self, report): if report.failed and "xfail" not in report.keywords: if report.nodeid not in self.lastfailed: self.lastfailed.append(report.nodeid) elif not report.failed: if report.when == "call": try: if report.nodeid in self.lastfailed: self.lastfailed.remove(report.nodeid) except KeyError: pass class FakeItemFromTestmon(object): def __init__(self, config): self.config = config def pytest_ignore_collect(self, path, config): strpath = path.strpath if strpath in self.testmon_data.unaffected_paths: config.hook.pytest_deselected( items=([self.FakeItemFromTestmon(config)] * self.testmon_data.unaffected_paths[strpath])) return True def pytest_internalerror(self, excrepr, excinfo): self.testmon_save = False def pytest_sessionfinish(self, session): if self.testmon_save: self.testmon_data.write_data() self.testmon.close() def pytest_terminal_summary(self, terminalreporter, exitstatus=None): if (not self.testmon_save and terminalreporter.config.getvalue('verbose')): terminalreporter.line('testmon: not saving data')