Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Side by Side Diff: tools/telemetry/third_party/coverage/igor.py

Issue 1366913004: Add coverage Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # coding: utf-8
2 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
3 # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
4
1 """Helper for building, testing, and linting coverage.py. 5 """Helper for building, testing, and linting coverage.py.
2 6
3 To get portability, all these operations are written in Python here instead 7 To get portability, all these operations are written in Python here instead
4 of in shell scripts, batch files, or Makefiles. 8 of in shell scripts, batch files, or Makefiles.
5 9
6 """ 10 """
7 11
12 import contextlib
8 import fnmatch 13 import fnmatch
9 import glob 14 import glob
10 import inspect 15 import inspect
11 import os 16 import os
12 import platform 17 import platform
13 import socket
14 import sys 18 import sys
19 import textwrap
20 import warnings
15 import zipfile 21 import zipfile
16 22
17 23
24 # We want to see all warnings while we are running tests. But we also need to
25 # disable warnings for some of the more complex setting up of tests.
26 warnings.simplefilter("default")
27
28
29 @contextlib.contextmanager
30 def ignore_warnings():
31 """Context manager to ignore warning within the with statement."""
32 with warnings.catch_warnings():
33 warnings.simplefilter("ignore")
34 yield
35
36
18 # Functions named do_* are executable from the command line: do_blah is run 37 # Functions named do_* are executable from the command line: do_blah is run
19 # by "python igor.py blah". 38 # by "python igor.py blah".
20 39
21 40
41 def do_show_env():
42 """Show the environment variables."""
43 print("Environment:")
44 for env in sorted(os.environ):
45 print(" %s = %r" % (env, os.environ[env]))
46
47
22 def do_remove_extension(): 48 def do_remove_extension():
23 """Remove the compiled C extension, no matter what its name.""" 49 """Remove the compiled C extension, no matter what its name."""
24 50
25 so_patterns = """ 51 so_patterns = """
26 tracer.so 52 tracer.so
27 tracer.*.so 53 tracer.*.so
28 tracer.pyd 54 tracer.pyd
55 tracer.*.pyd
29 """.split() 56 """.split()
30 57
31 for pattern in so_patterns: 58 for pattern in so_patterns:
32 pattern = os.path.join("coverage", pattern) 59 pattern = os.path.join("coverage", pattern)
33 for filename in glob.glob(pattern): 60 for filename in glob.glob(pattern):
34 try: 61 try:
35 os.remove(filename) 62 os.remove(filename)
36 except OSError: 63 except OSError:
37 pass 64 pass
38 65
39 def run_tests(tracer, *nose_args): 66
40 """The actual running of tests.""" 67 def label_for_tracer(tracer):
41 import nose.core 68 """Get the label for these tests."""
42 if tracer == "py": 69 if tracer == "py":
43 label = "with Python tracer" 70 label = "with Python tracer"
44 else: 71 else:
45 label = "with C tracer" 72 label = "with C tracer"
46 if os.environ.get("COVERAGE_NO_EXTENSION"): 73
47 print("Skipping tests, no C extension in this environment") 74 return label
48 return 75
49 print_banner(label) 76
50 os.environ["COVERAGE_TEST_TRACER"] = tracer 77 def should_skip(tracer):
78 """Is there a reason to skip these tests?"""
79 if tracer == "py":
80 skipper = os.environ.get("COVERAGE_NO_PYTRACER")
81 else:
82 skipper = (
83 os.environ.get("COVERAGE_NO_EXTENSION") or
84 os.environ.get("COVERAGE_NO_CTRACER")
85 )
86
87 if skipper:
88 msg = "Skipping tests " + label_for_tracer(tracer)
89 if len(skipper) > 1:
90 msg += ": " + skipper
91 else:
92 msg = ""
93
94 return msg
95
96
97 def run_tests(tracer, *nose_args):
98 """The actual running of tests."""
99 with ignore_warnings():
100 import nose.core
101
102 if 'COVERAGE_TESTING' not in os.environ:
103 os.environ['COVERAGE_TESTING'] = "True"
104 print_banner(label_for_tracer(tracer))
51 nose_args = ["nosetests"] + list(nose_args) 105 nose_args = ["nosetests"] + list(nose_args)
52 nose.core.main(argv=nose_args) 106 nose.core.main(argv=nose_args)
53 107
108
54 def run_tests_with_coverage(tracer, *nose_args): 109 def run_tests_with_coverage(tracer, *nose_args):
55 """Run tests, but with coverage.""" 110 """Run tests, but with coverage."""
56 import coverage
57 111
112 # Need to define this early enough that the first import of env.py sees it.
113 os.environ['COVERAGE_TESTING'] = "True"
58 os.environ['COVERAGE_PROCESS_START'] = os.path.abspath('metacov.ini') 114 os.environ['COVERAGE_PROCESS_START'] = os.path.abspath('metacov.ini')
59 os.environ['COVERAGE_HOME'] = os.getcwd() 115 os.environ['COVERAGE_HOME'] = os.getcwd()
60 116
61 # Create the .pth file that will let us measure coverage in sub-processes. 117 # Create the .pth file that will let us measure coverage in sub-processes.
118 # The .pth file seems to have to be alphabetically after easy-install.pth
119 # or the sys.path entries aren't created right?
62 import nose 120 import nose
63 pth_dir = os.path.dirname(os.path.dirname(nose.__file__)) 121 pth_dir = os.path.dirname(os.path.dirname(nose.__file__))
64 pth_path = os.path.join(pth_dir, "covcov.pth") 122 pth_path = os.path.join(pth_dir, "zzz_metacov.pth")
65 pth_file = open(pth_path, "w") 123 with open(pth_path, "w") as pth_file:
66 try:
67 pth_file.write("import coverage; coverage.process_startup()\n") 124 pth_file.write("import coverage; coverage.process_startup()\n")
68 finally:
69 pth_file.close()
70 125
126 # Make names for the data files that keep all the test runs distinct.
127 impl = platform.python_implementation().lower()
71 version = "%s%s" % sys.version_info[:2] 128 version = "%s%s" % sys.version_info[:2]
72 suffix = "%s_%s_%s" % (version, tracer, socket.gethostname()) 129 if '__pypy__' in sys.builtin_module_names:
130 version += "_%s%s" % sys.pypy_version_info[:2]
131 suffix = "%s%s_%s_%s" % (impl, version, tracer, platform.platform())
73 132
74 cov = coverage.coverage(config_file="metacov.ini", data_suffix=suffix) 133 os.environ['COVERAGE_METAFILE'] = os.path.abspath(".metacov."+suffix)
75 # Cheap trick: the coverage code itself is excluded from measurement, but 134
76 # if we clobber the cover_prefix in the coverage object, we can defeat the 135 import coverage
77 # self-detection. 136 cov = coverage.Coverage(config_file="metacov.ini", data_suffix=False)
137 # Cheap trick: the coverage.py code itself is excluded from measurement,
138 # but if we clobber the cover_prefix in the coverage object, we can defeat
139 # the self-detection.
78 cov.cover_prefix = "Please measure coverage.py!" 140 cov.cover_prefix = "Please measure coverage.py!"
79 cov.erase() 141 cov._warn_unimported_source = False
80 cov.start() 142 cov.start()
81 143
82 try: 144 try:
83 # Re-import coverage to get it coverage tested! I don't understand all 145 # Re-import coverage to get it coverage tested! I don't understand all
84 # the mechanics here, but if I don't carry over the imported modules 146 # the mechanics here, but if I don't carry over the imported modules
85 # (in covmods), then things go haywire (os == None, eventually). 147 # (in covmods), then things go haywire (os == None, eventually).
86 covmods = {} 148 covmods = {}
87 covdir = os.path.split(coverage.__file__)[0] 149 covdir = os.path.split(coverage.__file__)[0]
88 # We have to make a list since we'll be deleting in the loop. 150 # We have to make a list since we'll be deleting in the loop.
89 modules = list(sys.modules.items()) 151 modules = list(sys.modules.items())
90 for name, mod in modules: 152 for name, mod in modules:
91 if name.startswith('coverage'): 153 if name.startswith('coverage'):
92 if getattr(mod, '__file__', "??").startswith(covdir): 154 if getattr(mod, '__file__', "??").startswith(covdir):
93 covmods[name] = mod 155 covmods[name] = mod
94 del sys.modules[name] 156 del sys.modules[name]
95 import coverage # don't warn about re-import: pylint: disable=W0404 157 import coverage # pylint: disable=reimported
96 sys.modules.update(covmods) 158 sys.modules.update(covmods)
97 159
98 # Run nosetests, with the arguments from our command line. 160 # Run nosetests, with the arguments from our command line.
99 try: 161 try:
100 run_tests(tracer, *nose_args) 162 run_tests(tracer, *nose_args)
101 except SystemExit: 163 except SystemExit:
102 # nose3 seems to raise SystemExit, not sure why? 164 # nose3 seems to raise SystemExit, not sure why?
103 pass 165 pass
104 finally: 166 finally:
105 cov.stop() 167 cov.stop()
106 os.remove(pth_path) 168 os.remove(pth_path)
107 169
170 cov.combine()
108 cov.save() 171 cov.save()
109 172
173
110 def do_combine_html(): 174 def do_combine_html():
111 """Combine data from a meta-coverage run, and make the HTML report.""" 175 """Combine data from a meta-coverage run, and make the HTML and XML reports. """
112 import coverage 176 import coverage
113 os.environ['COVERAGE_HOME'] = os.getcwd() 177 os.environ['COVERAGE_HOME'] = os.getcwd()
114 cov = coverage.coverage(config_file="metacov.ini") 178 os.environ['COVERAGE_METAFILE'] = os.path.abspath(".metacov")
179 cov = coverage.Coverage(config_file="metacov.ini")
115 cov.load() 180 cov.load()
116 cov.combine() 181 cov.combine()
117 cov.save() 182 cov.save()
118 cov.html_report() 183 cov.html_report()
184 cov.xml_report()
185
119 186
120 def do_test_with_tracer(tracer, *noseargs): 187 def do_test_with_tracer(tracer, *noseargs):
121 """Run nosetests with a particular tracer.""" 188 """Run nosetests with a particular tracer."""
189 # If we should skip these tests, skip them.
190 skip_msg = should_skip(tracer)
191 if skip_msg:
192 print(skip_msg)
193 return
194
195 os.environ["COVERAGE_TEST_TRACER"] = tracer
122 if os.environ.get("COVERAGE_COVERAGE", ""): 196 if os.environ.get("COVERAGE_COVERAGE", ""):
123 return run_tests_with_coverage(tracer, *noseargs) 197 return run_tests_with_coverage(tracer, *noseargs)
124 else: 198 else:
125 return run_tests(tracer, *noseargs) 199 return run_tests(tracer, *noseargs)
126 200
201
127 def do_zip_mods(): 202 def do_zip_mods():
128 """Build the zipmods.zip file.""" 203 """Build the zipmods.zip file."""
129 zf = zipfile.ZipFile("tests/zipmods.zip", "w") 204 zf = zipfile.ZipFile("tests/zipmods.zip", "w")
205
206 # Take one file from disk.
130 zf.write("tests/covmodzip1.py", "covmodzip1.py") 207 zf.write("tests/covmodzip1.py", "covmodzip1.py")
208
209 # The others will be various encodings.
210 source = textwrap.dedent(u"""\
211 # coding: {encoding}
212 text = u"{text}"
213 ords = {ords}
214 assert [ord(c) for c in text] == ords
215 print(u"All OK with {encoding}")
216 """)
217 details = [
218 (u'utf8', u'ⓗⓔⓛⓛⓞ, ⓦⓞⓡⓛⓓ'),
219 (u'gb2312', u'你好,世界'),
220 (u'hebrew', u'שלום, עולם'),
221 (u'shift_jis', u'こんにちは世界'),
222 ]
223 for encoding, text in details:
224 filename = 'encoded_{0}.py'.format(encoding)
225 ords = [ord(c) for c in text]
226 source_text = source.format(encoding=encoding, text=text, ords=ords)
227 zf.writestr(filename, source_text.encode(encoding))
228
131 zf.close() 229 zf.close()
132 230
231
133 def do_install_egg(): 232 def do_install_egg():
134 """Install the egg1 egg for tests.""" 233 """Install the egg1 egg for tests."""
135 # I am pretty certain there are easier ways to install eggs... 234 # I am pretty certain there are easier ways to install eggs...
136 # pylint: disable=F0401,E0611,E1101 235 # pylint: disable=import-error,no-name-in-module
137 import distutils.core
138 cur_dir = os.getcwd() 236 cur_dir = os.getcwd()
139 os.chdir("tests/eggsrc") 237 os.chdir("tests/eggsrc")
140 distutils.core.run_setup("setup.py", ["--quiet", "bdist_egg"]) 238 with ignore_warnings():
141 egg = glob.glob("dist/*.egg")[0] 239 import distutils.core
142 distutils.core.run_setup( 240 distutils.core.run_setup("setup.py", ["--quiet", "bdist_egg"])
143 "setup.py", ["--quiet", "easy_install", "--no-deps", "--zip-ok", egg] 241 egg = glob.glob("dist/*.egg")[0]
144 ) 242 distutils.core.run_setup(
243 "setup.py", ["--quiet", "easy_install", "--no-deps", "--zip-ok", egg ]
244 )
145 os.chdir(cur_dir) 245 os.chdir(cur_dir)
146 246
247
147 def do_check_eol(): 248 def do_check_eol():
148 """Check files for incorrect newlines and trailing whitespace.""" 249 """Check files for incorrect newlines and trailing whitespace."""
149 250
150 ignore_dirs = [ 251 ignore_dirs = [
151 '.svn', '.hg', '.tox', '.tox_kits', 'coverage.egg-info', 252 '.svn', '.hg', '.git',
152 '_build', 'covtestegg1.egg-info', 253 '.tox*',
254 '*.egg-info',
255 '_build',
153 ] 256 ]
154 checked = set([]) 257 checked = set()
155 258
156 def check_file(fname, crlf=True, trail_white=True): 259 def check_file(fname, crlf=True, trail_white=True):
157 """Check a single file for whitespace abuse.""" 260 """Check a single file for whitespace abuse."""
158 fname = os.path.relpath(fname) 261 fname = os.path.relpath(fname)
159 if fname in checked: 262 if fname in checked:
160 return 263 return
161 checked.add(fname) 264 checked.add(fname)
162 265
163 line = None 266 line = None
164 for n, line in enumerate(open(fname, "rb")): 267 with open(fname, "rb") as f:
165 if crlf: 268 for n, line in enumerate(f, start=1):
166 if "\r" in line: 269 if crlf:
167 print("%s@%d: CR found" % (fname, n+1)) 270 if "\r" in line:
168 return 271 print("%s@%d: CR found" % (fname, n))
169 if trail_white: 272 return
170 line = line[:-1] 273 if trail_white:
171 if not crlf: 274 line = line[:-1]
172 line = line.rstrip('\r') 275 if not crlf:
173 if line.rstrip() != line: 276 line = line.rstrip('\r')
174 print("%s@%d: trailing whitespace found" % (fname, n+1)) 277 if line.rstrip() != line:
175 return 278 print("%s@%d: trailing whitespace found" % (fname, n))
279 return
176 280
177 if line is not None and not line.strip(): 281 if line is not None and not line.strip():
178 print("%s: final blank line" % (fname,)) 282 print("%s: final blank line" % (fname,))
179 283
180 def check_files(root, patterns, **kwargs): 284 def check_files(root, patterns, **kwargs):
181 """Check a number of files for whitespace abuse.""" 285 """Check a number of files for whitespace abuse."""
182 for root, dirs, files in os.walk(root): 286 for root, dirs, files in os.walk(root):
183 for f in files: 287 for f in files:
184 fname = os.path.join(root, f) 288 fname = os.path.join(root, f)
185 for p in patterns: 289 for p in patterns:
186 if fnmatch.fnmatch(fname, p): 290 if fnmatch.fnmatch(fname, p):
187 check_file(fname, **kwargs) 291 check_file(fname, **kwargs)
188 break 292 break
189 for dir_name in ignore_dirs: 293 for ignore_dir in ignore_dirs:
190 if dir_name in dirs: 294 ignored = []
295 for dir_name in dirs:
296 if fnmatch.fnmatch(dir_name, ignore_dir):
297 ignored.append(dir_name)
298 for dir_name in ignored:
191 dirs.remove(dir_name) 299 dirs.remove(dir_name)
192 300
193 check_files("coverage", ["*.py", "*.c"]) 301 check_files("coverage", ["*.py"])
302 check_files("coverage/ctracer", ["*.c", "*.h"])
194 check_files("coverage/htmlfiles", ["*.html", "*.css", "*.js"]) 303 check_files("coverage/htmlfiles", ["*.html", "*.css", "*.js"])
195 check_file("tests/farm/html/src/bom.py", crlf=False) 304 check_file("tests/farm/html/src/bom.py", crlf=False)
196 check_files("tests", ["*.py"]) 305 check_files("tests", ["*.py"])
197 check_files("tests", ["*,cover"], trail_white=False) 306 check_files("tests", ["*,cover"], trail_white=False)
198 check_files("tests/js", ["*.js", "*.html"]) 307 check_files("tests/js", ["*.js", "*.html"])
199 check_file("setup.py") 308 check_file("setup.py")
200 check_file("igor.py") 309 check_file("igor.py")
201 check_file("Makefile") 310 check_file("Makefile")
202 check_file(".hgignore") 311 check_file(".hgignore")
203 check_file(".travis.yml") 312 check_file(".travis.yml")
204 check_files("doc", ["*.rst"]) 313 check_files(".", ["*.rst", "*.txt"])
205 check_files(".", ["*.txt"]) 314 check_files(".", ["*.pip"])
206 315
207 316
208 def print_banner(label): 317 def print_banner(label):
209 """Print the version of Python.""" 318 """Print the version of Python."""
210 try: 319 try:
211 impl = platform.python_implementation() 320 impl = platform.python_implementation()
212 except AttributeError: 321 except AttributeError:
213 impl = "Python" 322 impl = "Python"
214 323
215 version = platform.python_version() 324 version = platform.python_version()
216 325
217 if '__pypy__' in sys.builtin_module_names: 326 if '__pypy__' in sys.builtin_module_names:
218 pypy_version = sys.pypy_version_info # pylint: disable=E1101 327 version += " (pypy %s)" % ".".join(str(v) for v in sys.pypy_version_info )
219 version += " (pypy %s)" % ".".join([str(v) for v in pypy_version])
220 328
221 print('=== %s %s %s (%s) ===' % (impl, version, label, sys.executable)) 329 which_python = os.path.relpath(sys.executable)
330 print('=== %s %s %s (%s) ===' % (impl, version, label, which_python))
331 sys.stdout.flush()
222 332
223 333
224 def do_help(): 334 def do_help():
225 """List the available commands""" 335 """List the available commands"""
226 items = list(globals().items()) 336 items = list(globals().items())
227 items.sort() 337 items.sort()
228 for name, value in items: 338 for name, value in items:
229 if name.startswith('do_'): 339 if name.startswith('do_'):
230 print("%-20s%s" % (name[3:], value.__doc__)) 340 print("%-20s%s" % (name[3:], value.__doc__))
231 341
232 342
343 def analyze_args(function):
344 """What kind of args does `function` expect?
345
346 Returns:
347 star, num_pos:
348 star(boolean): Does `function` accept *args?
349 num_args(int): How many positional arguments does `function` have?
350 """
351 try:
352 getargspec = inspect.getfullargspec
353 except AttributeError:
354 getargspec = inspect.getargspec
355 argspec = getargspec(function)
356 return bool(argspec[1]), len(argspec[0])
357
358
233 def main(args): 359 def main(args):
234 """Main command-line execution for igor. 360 """Main command-line execution for igor.
235 361
236 Verbs are taken from the command line, and extra words taken as directed 362 Verbs are taken from the command line, and extra words taken as directed
237 by the arguments needed by the handler. 363 by the arguments needed by the handler.
238 364
239 """ 365 """
240 while args: 366 while args:
241 verb = args.pop(0) 367 verb = args.pop(0)
242 handler = globals().get('do_'+verb) 368 handler = globals().get('do_'+verb)
243 if handler is None: 369 if handler is None:
244 print("*** No handler for %r" % verb) 370 print("*** No handler for %r" % verb)
245 return 1 371 return 1
246 argspec = inspect.getargspec(handler) 372 star, num_args = analyze_args(handler)
247 if argspec[1]: 373 if star:
248 # Handler has *args, give it all the rest of the command line. 374 # Handler has *args, give it all the rest of the command line.
249 handler_args = args 375 handler_args = args
250 args = [] 376 args = []
251 else: 377 else:
252 # Handler has specific arguments, give it only what it needs. 378 # Handler has specific arguments, give it only what it needs.
253 num_args = len(argspec[0])
254 handler_args = args[:num_args] 379 handler_args = args[:num_args]
255 args = args[num_args:] 380 args = args[num_args:]
256 ret = handler(*handler_args) 381 ret = handler(*handler_args)
257 # If a handler returns a failure-like value, stop. 382 # If a handler returns a failure-like value, stop.
258 if ret: 383 if ret:
259 return ret 384 return ret
260 385
386
261 if __name__ == '__main__': 387 if __name__ == '__main__':
262 sys.exit(main(sys.argv[1:])) 388 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « tools/telemetry/third_party/coverage/howto.txt ('k') | tools/telemetry/third_party/coverage/lab/branches.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698