1 """Config file for coverage.py""" 2 3 import os 4 from coverage.backward import configparser # pylint: disable=W0622 5 6 # The default line exclusion regexes 7 DEFAULT_EXCLUDE = [ 8 '(?i)# *pragma[: ]*no *cover', 9 ] 10 11 # The default partial branch regexes, to be modified by the user. 12 DEFAULT_PARTIAL = [ 13 '(?i)# *pragma[: ]*no *branch', 14 ] 15 16 # The default partial branch regexes, based on Python semantics. 17 # These are any Python branching constructs that can't actually execute all 18 # their branches. 19 DEFAULT_PARTIAL_ALWAYS = [ 20 'while (True|1|False|0):', 21 'if (True|1|False|0):', 22 ] 23 24 25 class CoverageConfig(object): 26 """Coverage.py configuration. 27 28 The attributes of this class are the various settings that control the 29 operation of coverage.py. 30 31 """ 32 33 def __init__(self): 34 """Initialize the configuration attributes to their defaults.""" 35 # Defaults for [run] 36 self.branch = False 37 self.cover_pylib = False 38 self.data_file = ".coverage" 39 self.parallel = False 40 self.timid = False 41 self.source = None 42 43 # Defaults for [report] 44 self.exclude_list = DEFAULT_EXCLUDE[:] 45 self.ignore_errors = False 46 self.include = None 47 self.omit = None 48 self.partial_list = DEFAULT_PARTIAL[:] 49 self.partial_always_list = DEFAULT_PARTIAL_ALWAYS[:] 50 self.precision = 0 51 52 # Defaults for [html] 53 self.html_dir = "htmlcov" 54 55 # Defaults for [xml] 56 self.xml_output = "coverage.xml" 57 58 # Defaults for [paths] 59 self.paths = {} 60 61 def from_environment(self, env_var): 62 """Read configuration from the `env_var` environment variable.""" 63 # Timidity: for nose users, read an environment variable. This is a 64 # cheap hack, since the rest of the command line arguments aren't 65 # recognized, but it solves some users' problems. 66 env = os.environ.get(env_var, '') 67 if env: 68 self.timid = ('--timid' in env) 69 70 def from_args(self, **kwargs): 71 """Read config values from `kwargs`.""" 72 for k, v in kwargs.items(): 73 if v is not None: 74 setattr(self, k, v) 75 76 def from_file(self, *files): 77 """Read configuration from .rc files. 78 79 Each argument in `files` is a file name to read. 80 81 """ 82 cp = configparser.RawConfigParser() 83 cp.read(files) 84 85 # [run] 86 if cp.has_option('run', 'branch'): 87 self.branch = cp.getboolean('run', 'branch') 88 if cp.has_option('run', 'cover_pylib'): 89 self.cover_pylib = cp.getboolean('run', 'cover_pylib') 90 if cp.has_option('run', 'data_file'): 91 self.data_file = cp.get('run', 'data_file') 92 if cp.has_option('run', 'include'): 93 self.include = self.get_list(cp, 'run', 'include') 94 if cp.has_option('run', 'omit'): 95 self.omit = self.get_list(cp, 'run', 'omit') 96 if cp.has_option('run', 'parallel'): 97 self.parallel = cp.getboolean('run', 'parallel') 98 if cp.has_option('run', 'source'): 99 self.source = self.get_list(cp, 'run', 'source') 100 if cp.has_option('run', 'timid'): 101 self.timid = cp.getboolean('run', 'timid') 102 103 # [report] 104 if cp.has_option('report', 'exclude_lines'): 105 self.exclude_list = \ 106 self.get_line_list(cp, 'report', 'exclude_lines') 107 if cp.has_option('report', 'ignore_errors'): 108 self.ignore_errors = cp.getboolean('report', 'ignore_errors') 109 if cp.has_option('report', 'include'): 110 self.include = self.get_list(cp, 'report', 'include') 111 if cp.has_option('report', 'omit'): 112 self.omit = self.get_list(cp, 'report', 'omit') 113 if cp.has_option('report', 'partial_branches'): 114 self.partial_list = \ 115 self.get_line_list(cp, 'report', 'partial_branches') 116 if cp.has_option('report', 'partial_branches_always'): 117 self.partial_always_list = \ 118 self.get_line_list(cp, 'report', 'partial_branches_always') 119 if cp.has_option('report', 'precision'): 120 self.precision = cp.getint('report', 'precision') 121 122 # [html] 123 if cp.has_option('html', 'directory'): 124 self.html_dir = cp.get('html', 'directory') 125 126 # [xml] 127 if cp.has_option('xml', 'output'): 128 self.xml_output = cp.get('xml', 'output') 129 130 # [paths] 131 if cp.has_section('paths'): 132 for option in cp.options('paths'): 133 self.paths[option] = self.get_list(cp, 'paths', option) 134 135 def get_list(self, cp, section, option): 136 """Read a list of strings from the ConfigParser `cp`. 137 138 The value of `section` and `option` is treated as a comma- and newline- 139 separated list of strings. Each value is stripped of whitespace. 140 141 Returns the list of strings. 142 143 """ 144 value_list = cp.get(section, option) 145 values = [] 146 for value_line in value_list.split('\n'): 147 for value in value_line.split(','): 148 value = value.strip() 149 if value: 150 values.append(value) 151 return values 152 153 def get_line_list(self, cp, section, option): 154 """Read a list of full-line strings from the ConfigParser `cp`. 155 156 The value of `section` and `option` is treated as a newline-separated 157 list of strings. Each value is stripped of whitespace. 158 159 Returns the list of strings. 160 161 """ 162 value_list = cp.get(section, option) 163 return list(filter(None, value_list.split('\n'))) 164 165