diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2023-12-02 01:45:21 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2023-12-02 02:42:50 +0300 |
commit | 9c43d58f75cf086b744cf4fe2ae180e8f37e4a0c (patch) | |
tree | 9f88a486917d371d099cd712efd91b4c122d209d /contrib/python/coverage/plugins | |
parent | 32fb6dda1feb24f9ab69ece5df0cb9ec238ca5e6 (diff) | |
download | ydb-9c43d58f75cf086b744cf4fe2ae180e8f37e4a0c.tar.gz |
Intermediate changes
Diffstat (limited to 'contrib/python/coverage/plugins')
-rw-r--r-- | contrib/python/coverage/plugins/coveragerc.txt | 29 | ||||
-rw-r--r-- | contrib/python/coverage/plugins/ya.make | 19 | ||||
-rw-r--r-- | contrib/python/coverage/plugins/yarcadia/plugin.py | 114 |
3 files changed, 162 insertions, 0 deletions
diff --git a/contrib/python/coverage/plugins/coveragerc.txt b/contrib/python/coverage/plugins/coveragerc.txt new file mode 100644 index 0000000000..83bfed8690 --- /dev/null +++ b/contrib/python/coverage/plugins/coveragerc.txt @@ -0,0 +1,29 @@ +[report] +skip_empty = True + +exclude_lines = + pragma\s*:\s*no\s*cover + def __repr__ + raise AssertionError + raise NotImplementedError + if 0: + if False: + if __name__ == .__main__.: + if self\.debug: + if settings\.DEBUG + +[run] +suppress_plugin_errors = False +plugins = + contrib.python.coverage.plugins.yarcadia.plugin + contrib.tools.cython.Cython.Coverage + +[contrib.python.coverage.plugins.yarcadia.plugin] +pylib_paths = + # don't trace contrib + contrib/python + contrib/python3 + # don't trace python sources + contrib/tools/python + contrib/tools/python3 + contrib/libs/protobuf diff --git a/contrib/python/coverage/plugins/ya.make b/contrib/python/coverage/plugins/ya.make new file mode 100644 index 0000000000..30be33f72a --- /dev/null +++ b/contrib/python/coverage/plugins/ya.make @@ -0,0 +1,19 @@ +PY23_LIBRARY() + +LICENSE(Apache-2.0) + +PEERDIR( + build/plugins/lib/test_const + contrib/tools/cython/Cython + library/python/testing/coverage_utils +) + +PY_SRCS( + yarcadia/plugin.py +) + +RESOURCE( + coveragerc.txt /coverage_plugins/coveragerc.txt +) + +END() diff --git a/contrib/python/coverage/plugins/yarcadia/plugin.py b/contrib/python/coverage/plugins/yarcadia/plugin.py new file mode 100644 index 0000000000..44d9b003ca --- /dev/null +++ b/contrib/python/coverage/plugins/yarcadia/plugin.py @@ -0,0 +1,114 @@ +# coding: utf-8 + +import os + +import coverage.config +import coverage.files +import coverage.misc +import coverage.parser +import coverage.plugin +import coverage.python + +from build.plugins.lib import test_const +from library.python.testing import coverage_utils + + +SKIP_FILENAME = '__SKIP_FILENAME__' + + +class YarcadiaPlugin( + coverage.plugin.CoveragePlugin, + coverage.plugin.FileTracer +): + + def __init__(self, options): + self.config = coverage.config.CoverageConfig() + self.config.from_args(**options) + + dirs = options.get("pylib_paths", "").split("\n") + dirs = [d for d in dirs if d and not d.startswith("#")] + self.pylib_paths = dirs + + self._filename = None + self._exclude = None + + self._setup_file_filter() + + def _setup_file_filter(self): + prefix_filter = os.environ.get('PYTHON_COVERAGE_PREFIX_FILTER', '') + exclude_regexp = os.environ.get('PYTHON_COVERAGE_EXCLUDE_REGEXP', '') + self.file_filter = coverage_utils.make_filter(prefix_filter, exclude_regexp) + + def configure(self, config): + self._exclude = coverage.misc.join_regex(config.get_option('report:exclude_lines')) + + def get_pylib_paths(self): + return self.pylib_paths + + def file_tracer(self, filename): + if not filename.endswith(test_const.COVERAGE_PYTHON_EXTS): + # Catch all generated modules (__file__ without proper extension) + self._filename = SKIP_FILENAME + return self + + if not self.file_filter(filename): + # we need to catch all filtered out files (including cython) to pass them to get_source + self._filename = SKIP_FILENAME + return self + + if filename.endswith(".py"): + self._filename = filename + return self + + # Let cython plugin register it's own file tracer for pyx/pxi files + return None + + def has_dynamic_source_filename(self): + return False + + def source_filename(self): + return self._filename + + def file_reporter(self, morf): + source_root = os.environ.get("PYTHON_COVERAGE_ARCADIA_SOURCE_ROOT") + if source_root: + return FileReporter(morf, source_root, self, self._exclude) + # use default file reporter + return "python" + + +class FileReporter(coverage.python.PythonFileReporter): + + def __init__(self, morf, source_root, coverage=None, exclude=None): + super(FileReporter, self).__init__(morf, coverage) + self._source = get_source(morf, source_root) + # use custom parser to provide proper way to get required source + self._parser = Parser(morf, self._source, exclude) + self._parser.parse_source() + + +class Parser(coverage.parser.PythonParser): + + def __init__(self, morf, source_code, exclude): + # provide source code to avoid default way to get it + super(Parser, self).__init__(text=source_code, filename=morf, exclude=exclude) + + +def get_source(filename, source_root): + assert source_root + + if filename == SKIP_FILENAME: + return '' + + abs_filename = os.path.join(source_root, filename) + if not os.path.isfile(abs_filename): + # it's fake generated package + return u'' + + return coverage.python.get_python_source(abs_filename, force_fs=True) + + +def coverage_init(reg, options): + plugin = YarcadiaPlugin(options) + reg.add_configurer(plugin) + reg.add_file_tracer(plugin) |