1#!/usr/bin/python 2# Copyright 2014 Google Inc. All rights reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16from __future__ import print_function 17 18import argparse 19import sys 20import textwrap 21 22is_python3 = bool(sys.version_info.major == 3) 23 24 25ALL_PRAGMAS = ['no cover', 'no win32', 'python2', 'python3', 'untested', 26 'win32'] 27DEFAULT_PRAGMAS = ALL_PRAGMAS[:] 28 29if is_python3: 30 DEFAULT_PRAGMAS.remove('python3') 31else: 32 DEFAULT_PRAGMAS.remove('python2') 33 34if sys.platform == 'win32': 35 DEFAULT_PRAGMAS.remove('win32') 36else: 37 DEFAULT_PRAGMAS.remove('no win32') 38 39 40def add_arguments(parser): 41 parser.add_argument('--no-pragmas', action='store_true', default=False, 42 help='Show all uncovered lines (no pragmas).') 43 parser.add_argument('--path', action='append', default=[], 44 help='Prepend given directories to sys.path.') 45 parser.add_argument('--pragma', action='append', default=[], 46 help=('The coverage pragmas to honor ' 47 '(defaults to %s).' % DEFAULT_PRAGMAS)) 48 parser.add_argument('--show', action='append', default=[], 49 help='Show code protected by the specified pragmas ' 50 '(uses all pragmas *except* for the ones ' 51 'specified).') 52 parser.add_argument('--show-missing', action='store_true', 53 default=False, help='Show missing lines.') 54 parser.add_argument('--source', action='append', default=[], 55 help='Limit coverage data to the given directories.') 56 57 parser.formatter_class = argparse.RawTextHelpFormatter 58 parser.epilog = textwrap.dedent(""" 59 Valid pragma values are: 60 'no cover': The default coverage pragma, this now means we 61 truly cannot cover it. 62 'no win32': Code that only executes when not on Windows. 63 'python2': Code that only executes under Python2. 64 'python3': Code that only executees under Python3. 65 'untested': Code that does not yet have tests. 66 'win32': Code that only executes on Windows. 67 68 In typ, we aim for 'no cover' to only apply to code that executes only 69 when coverage is not available (and hence can never be counted). Most 70 code, if annotated at all, should be 'untested', and we should strive 71 for 'untested' to not be used, either. 72 """) 73 74 75def argv_from_args(args): 76 argv = [] 77 if args.no_pragmas: 78 argv.append('--no-pragmas') 79 for arg in args.path: 80 argv.extend(['--path', arg]) 81 for arg in args.show: 82 argv.extend(['--show', arg]) 83 if args.show_missing: 84 argv.append('--show-missing') 85 for arg in args.source: 86 argv.extend(['--source', arg]) 87 for arg in args.pragma: 88 argv.extend(['--pragma', arg]) 89 return argv 90 91 92def main(argv=None): 93 parser = argparse.ArgumentParser() 94 add_arguments(parser) 95 args, remaining_args = parser.parse_known_args(argv) 96 97 for path in args.path: 98 if path not in sys.path: 99 sys.path.append(path) 100 101 try: 102 import coverage 103 from coverage.execfile import run_python_module, run_python_file 104 except ImportError: 105 print("Error: coverage is not available.") 106 sys.exit(1) 107 108 cov = coverage.coverage(source=args.source) 109 cov.erase() 110 cov.clear_exclude() 111 112 if args.no_pragmas: 113 args.pragma = [] 114 115 args.pragma = args.pragma or DEFAULT_PRAGMAS 116 117 if args.show: 118 args.show_missing = True 119 for pragma in args.show: 120 if pragma in args.pragma: 121 args.pragma.remove(pragma) 122 123 for pragma in args.pragma: 124 cov.exclude('pragma: %s' % pragma) 125 126 ret = 0 127 cov.start() 128 try: 129 if remaining_args[0] == '-m': 130 run_python_module(remaining_args[1], remaining_args[1:]) 131 else: 132 run_python_file(remaining_args[0], remaining_args) 133 except SystemExit as e: 134 ret = e.code 135 cov.stop() 136 cov.save() 137 cov.report(show_missing=args.show_missing) 138 return ret 139 140 141if __name__ == '__main__': 142 sys.exit(main()) 143