aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/coverage/plugins
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2023-12-02 01:45:21 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2023-12-02 02:42:50 +0300
commit9c43d58f75cf086b744cf4fe2ae180e8f37e4a0c (patch)
tree9f88a486917d371d099cd712efd91b4c122d209d /contrib/python/coverage/plugins
parent32fb6dda1feb24f9ab69ece5df0cb9ec238ca5e6 (diff)
downloadydb-9c43d58f75cf086b744cf4fe2ae180e8f37e4a0c.tar.gz
Intermediate changes
Diffstat (limited to 'contrib/python/coverage/plugins')
-rw-r--r--contrib/python/coverage/plugins/coveragerc.txt29
-rw-r--r--contrib/python/coverage/plugins/ya.make19
-rw-r--r--contrib/python/coverage/plugins/yarcadia/plugin.py114
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)