summaryrefslogtreecommitdiff
path: root/coverage
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2017-10-21 19:58:37 -0400
committerNed Batchelder <ned@nedbatchelder.com>2017-10-21 19:58:37 -0400
commit13ce8c103251012c99bdd5abc616bbd12d3adc2c (patch)
tree9fec2c37dc3f42c3babfde0f693a1290439d4f05 /coverage
parent0b59a27f6c7cd8984c7a99fb06a07a6cc4e9b1e0 (diff)
downloadpython-coveragepy-13ce8c103251012c99bdd5abc616bbd12d3adc2c.tar.gz
Explicitly specified secondary config files are properly read. #588
Diffstat (limited to 'coverage')
-rw-r--r--coverage/config.py82
1 files changed, 56 insertions, 26 deletions
diff --git a/coverage/config.py b/coverage/config.py
index 75da20f..11b7056 100644
--- a/coverage/config.py
+++ b/coverage/config.py
@@ -17,9 +17,18 @@ os = isolate_module(os)
class HandyConfigParser(configparser.RawConfigParser):
"""Our specialization of ConfigParser."""
- def __init__(self, section_prefix):
+ def __init__(self, our_file):
+ """Create the HandyConfigParser.
+
+ `our_file` is True if this config file is specifically for coverage,
+ False if we are examining another config file (tox.ini, setup.cfg)
+ for possible settings.
+ """
+
configparser.RawConfigParser.__init__(self)
- self.section_prefix = section_prefix
+ self.section_prefixes = ["coverage:"]
+ if our_file:
+ self.section_prefixes.append("")
def read(self, filenames):
"""Read a file name as UTF-8 configuration data."""
@@ -29,16 +38,27 @@ class HandyConfigParser(configparser.RawConfigParser):
return configparser.RawConfigParser.read(self, filenames, **kwargs)
def has_option(self, section, option):
- section = self.section_prefix + section
- return configparser.RawConfigParser.has_option(self, section, option)
+ for section_prefix in self.section_prefixes:
+ real_section = section_prefix + section
+ has = configparser.RawConfigParser.has_option(self, real_section, option)
+ if has:
+ return has
+ return False
def has_section(self, section):
- section = self.section_prefix + section
- return configparser.RawConfigParser.has_section(self, section)
+ for section_prefix in self.section_prefixes:
+ real_section = section_prefix + section
+ has = configparser.RawConfigParser.has_section(self, real_section)
+ if has:
+ return real_section
+ return False
def options(self, section):
- section = self.section_prefix + section
- return configparser.RawConfigParser.options(self, section)
+ for section_prefix in self.section_prefixes:
+ real_section = section_prefix + section
+ if configparser.RawConfigParser.has_section(self, real_section):
+ return configparser.RawConfigParser.options(self, real_section)
+ raise configparser.NoSectionError
def get_section(self, section):
"""Get the contents of a section, as a dictionary."""
@@ -47,7 +67,7 @@ class HandyConfigParser(configparser.RawConfigParser):
d[opt] = self.get(section, opt)
return d
- def get(self, section, *args, **kwargs): # pylint: disable=arguments-differ
+ def get(self, section, option, *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
@@ -57,8 +77,14 @@ class HandyConfigParser(configparser.RawConfigParser):
Returns the finished value.
"""
- section = self.section_prefix + section
- v = configparser.RawConfigParser.get(self, section, *args, **kwargs)
+ for section_prefix in self.section_prefixes:
+ real_section = section_prefix + section
+ if configparser.RawConfigParser.has_option(self, real_section, option):
+ break
+ else:
+ raise configparser.NoOptionError
+
+ v = configparser.RawConfigParser.get(self, real_section, option, *args, **kwargs)
def dollar_replace(m):
"""Called for each $replacement."""
# Only one of the groups will have matched, just get its text.
@@ -203,18 +229,22 @@ class CoverageConfig(object):
setattr(self, k, v)
@contract(filename=str)
- def from_file(self, filename, section_prefix=""):
+ def from_file(self, filename, our_file):
"""Read configuration from a .rc file.
`filename` is a file name to read.
+ `our_file` is True if this config file is specifically for coverage,
+ False if we are examining another config file (tox.ini, setup.cfg)
+ for possible settings.
+
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)
- cp = HandyConfigParser(section_prefix)
+ cp = HandyConfigParser(our_file)
try:
files_read = cp.read(filename)
except configparser.Error as err:
@@ -240,13 +270,12 @@ class CoverageConfig(object):
all_options[section].add(option)
for section, options in iitems(all_options):
- if cp.has_section(section):
+ real_section = cp.has_section(section)
+ if real_section:
for unknown in set(cp.options(section)) - options:
- if section_prefix:
- section = section_prefix + section
raise CoverageException(
"Unrecognized option '[%s] %s=' in config file %s" % (
- section, unknown, filename
+ real_section, unknown, filename
)
)
@@ -262,12 +291,13 @@ class CoverageConfig(object):
self.plugin_options[plugin] = cp.get_section(plugin)
any_set = 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:
+ # Was this file used as a config file? If it's specifically our file,
+ # then it was used. If we're piggybacking on someone else's file,
+ # then it was only used if we found some settings in it.
+ if our_file:
return True
+ else:
+ return any_set
CONFIG_FILE_OPTIONS = [
# These are *args for _set_attr_from_config_option:
@@ -417,10 +447,10 @@ def read_coverage_config(config_file, **kwargs):
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)
+ for fname, our_file in [(config_file, True),
+ ("setup.cfg", False),
+ ("tox.ini", False)]:
+ config_read = config.from_file(fname, our_file=our_file)
is_config_file = fname == config_file
if not config_read and is_config_file and specified_file: