1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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)
|