summaryrefslogtreecommitdiff
path: root/coverage/config.py
diff options
context:
space:
mode:
Diffstat (limited to 'coverage/config.py')
-rw-r--r--coverage/config.py98
1 files changed, 87 insertions, 11 deletions
diff --git a/coverage/config.py b/coverage/config.py
index c7d6555c..3fa64495 100644
--- a/coverage/config.py
+++ b/coverage/config.py
@@ -21,12 +21,12 @@ class HandyConfigParser(configparser.RawConfigParser):
configparser.RawConfigParser.__init__(self)
self.section_prefix = section_prefix
- def read(self, filename): # pylint: disable=arguments-differ
+ def read(self, filenames):
"""Read a file name as UTF-8 configuration data."""
kwargs = {}
if sys.version_info >= (3, 2):
kwargs['encoding'] = "utf-8"
- return configparser.RawConfigParser.read(self, filename, **kwargs)
+ return configparser.RawConfigParser.read(self, filenames, **kwargs)
def has_option(self, section, option):
section = self.section_prefix + section
@@ -47,7 +47,7 @@ class HandyConfigParser(configparser.RawConfigParser):
d[opt] = self.get(section, opt)
return d
- def get(self, section, *args, **kwargs):
+ def get(self, section, *args, **kwargs): # pylint: disable=arguments-differ
"""Get a value, replacing environment variables also.
The arguments are the same as `RawConfigParser.get`, but in the found
@@ -122,12 +122,12 @@ class HandyConfigParser(configparser.RawConfigParser):
# The default line exclusion regexes.
DEFAULT_EXCLUDE = [
- r'(?i)#\s*pragma[:\s]?\s*no\s*cover',
+ r'#\s*(pragma|PRAGMA)[:\s]?\s*(no|NO)\s*(cover|COVER)',
]
# The default partial branch regexes, to be modified by the user.
DEFAULT_PARTIAL = [
- r'(?i)#\s*pragma[:\s]?\s*no\s*branch',
+ r'#\s*(pragma|PRAGMA)[:\s]?\s*(no|NO)\s*(branch|BRANCH)',
]
# The default partial branch regexes, based on Python semantics.
@@ -158,6 +158,7 @@ class CoverageConfig(object):
self.cover_pylib = False
self.data_file = ".coverage"
self.debug = []
+ self.disable_warnings = []
self.note = None
self.parallel = False
self.plugins = []
@@ -191,7 +192,7 @@ class CoverageConfig(object):
# Options for plugins
self.plugin_options = {}
- MUST_BE_LIST = ["omit", "include", "debug", "plugins", "concurrency"]
+ MUST_BE_LIST = ["concurrency", "debug", "disable_warnings", "include", "omit", "plugins"]
def from_args(self, **kwargs):
"""Read config values from `kwargs`."""
@@ -207,7 +208,8 @@ class CoverageConfig(object):
`filename` is a file name to read.
- Returns True or False, whether the file could be read.
+ Returns True or False, whether the file could be read, and it had some
+ coverage.py settings in it.
"""
self.attempted_config_files.append(filename)
@@ -222,9 +224,12 @@ class CoverageConfig(object):
self.config_files.extend(files_read)
+ any_set = False
try:
for option_spec in self.CONFIG_FILE_OPTIONS:
- self._set_attr_from_config_option(cp, *option_spec)
+ was_set = self._set_attr_from_config_option(cp, *option_spec)
+ if was_set:
+ any_set = True
except ValueError as err:
raise CoverageException("Couldn't read config file %s: %s" % (filename, err))
@@ -249,13 +254,20 @@ class CoverageConfig(object):
if cp.has_section('paths'):
for option in cp.options('paths'):
self.paths[option] = cp.getlist('paths', option)
+ any_set = True
# plugins can have options
for plugin in self.plugins:
if cp.has_section(plugin):
self.plugin_options[plugin] = cp.get_section(plugin)
+ any_set = True
- return True
+ # Was this file used as a config file? If no prefix, then it was used.
+ # If a prefix, then it was only used if we found some settings in it.
+ if section_prefix:
+ return any_set
+ else:
+ return True
CONFIG_FILE_OPTIONS = [
# These are *args for _set_attr_from_config_option:
@@ -272,6 +284,7 @@ class CoverageConfig(object):
('cover_pylib', 'run:cover_pylib', 'boolean'),
('data_file', 'run:data_file'),
('debug', 'run:debug', 'list'),
+ ('disable_warnings', 'run:disable_warnings', 'list'),
('include', 'run:include', 'list'),
('note', 'run:note'),
('omit', 'run:omit', 'list'),
@@ -304,11 +317,17 @@ class CoverageConfig(object):
]
def _set_attr_from_config_option(self, cp, attr, where, type_=''):
- """Set an attribute on self if it exists in the ConfigParser."""
+ """Set an attribute on self if it exists in the ConfigParser.
+
+ Returns True if the attribute was set.
+
+ """
section, option = where.split(":")
if cp.has_option(section, option):
method = getattr(cp, 'get' + type_)
setattr(self, attr, method(section, option))
+ return True
+ return False
def get_plugin_options(self, plugin):
"""Get a dictionary of options for the plugin named `plugin`."""
@@ -351,7 +370,6 @@ class CoverageConfig(object):
Returns the value of the option.
"""
-
# Check all the hard-coded options.
for option_spec in self.CONFIG_FILE_OPTIONS:
attr, where = option_spec[:2]
@@ -365,3 +383,61 @@ class CoverageConfig(object):
# If we get here, we didn't find the option.
raise CoverageException("No such option: %r" % option_name)
+
+
+def read_coverage_config(config_file, **kwargs):
+ """Read the coverage.py configuration.
+
+ Arguments:
+ config_file: a boolean or string, see the `Coverage` class for the
+ tricky details.
+ all others: keyword arguments from the `Coverage` class, used for
+ setting values in the configuration.
+
+ Returns:
+ config_file, config:
+ config_file is the value to use for config_file in other
+ invocations of coverage.
+
+ config is a CoverageConfig object read from the appropriate
+ configuration file.
+
+ """
+ # Build the configuration from a number of sources:
+ # 1) defaults:
+ config = CoverageConfig()
+
+ # 2) from a file:
+ if config_file:
+ # Some API users were specifying ".coveragerc" to mean the same as
+ # True, so make it so.
+ if config_file == ".coveragerc":
+ config_file = True
+ specified_file = (config_file is not True)
+ if not specified_file:
+ config_file = ".coveragerc"
+
+ for fname, prefix in [(config_file, ""),
+ ("setup.cfg", "coverage:"),
+ ("tox.ini", "coverage:")]:
+ config_read = config.from_file(fname, section_prefix=prefix)
+ is_config_file = fname == config_file
+
+ if not config_read and is_config_file and specified_file:
+ raise CoverageException("Couldn't read '%s' as a config file" % fname)
+
+ if config_read:
+ break
+
+ # 3) from environment variables:
+ env_data_file = os.environ.get('COVERAGE_FILE')
+ if env_data_file:
+ config.data_file = env_data_file
+ debugs = os.environ.get('COVERAGE_DEBUG')
+ if debugs:
+ config.debug.extend(d.strip() for d in debugs.split(","))
+
+ # 4) from constructor arguments:
+ config.from_args(**kwargs)
+
+ return config_file, config