Home | History | Annotate | Download | only in tools
      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 
     16 from __future__ import print_function
     17 
     18 import argparse
     19 import sys
     20 import textwrap
     21 
     22 is_python3 = bool(sys.version_info.major == 3)
     23 
     24 
     25 ALL_PRAGMAS = ['no cover', 'no win32', 'python2', 'python3', 'untested',
     26                'win32']
     27 DEFAULT_PRAGMAS = ALL_PRAGMAS[:]
     28 
     29 if is_python3:
     30     DEFAULT_PRAGMAS.remove('python3')
     31 else:
     32     DEFAULT_PRAGMAS.remove('python2')
     33 
     34 if sys.platform == 'win32':
     35     DEFAULT_PRAGMAS.remove('win32')
     36 else:
     37     DEFAULT_PRAGMAS.remove('no win32')
     38 
     39 
     40 def 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 
     75 def 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 
     92 def 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 
    141 if __name__ == '__main__':
    142     sys.exit(main())
    143