summaryrefslogtreecommitdiff
path: root/coverage/config.py
diff options
context:
space:
mode:
Diffstat (limited to 'coverage/config.py')
-rw-r--r--coverage/config.py80
1 files changed, 46 insertions, 34 deletions
diff --git a/coverage/config.py b/coverage/config.py
index 7b142671..9939d6c0 100644
--- a/coverage/config.py
+++ b/coverage/config.py
@@ -1,22 +1,21 @@
-"""Config file for coverage.py"""
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
-import os, re, sys
-from coverage.backward import string_class, iitems
-from coverage.misc import CoverageException
+"""Config file for coverage.py"""
+import collections
+import os
+import re
+import sys
-# In py3, ConfigParser was renamed to the more-standard configparser
-try:
- import configparser
-except ImportError:
- import ConfigParser as configparser
+from coverage.backward import configparser, iitems, string_class
+from coverage.misc import CoverageException
class HandyConfigParser(configparser.RawConfigParser):
"""Our specialization of ConfigParser."""
def __init__(self, section_prefix):
- # pylint: disable=super-init-not-called
configparser.RawConfigParser.__init__(self)
self.section_prefix = section_prefix
@@ -61,7 +60,7 @@ class HandyConfigParser(configparser.RawConfigParser):
def dollar_replace(m):
"""Called for each $replacement."""
# Only one of the groups will have matched, just get its text.
- word = next(w for w in m.groups() if w is not None)
+ word = next(w for w in m.groups() if w is not None) # pragma: part covered
if word == "$":
return "$"
else:
@@ -112,10 +111,8 @@ class HandyConfigParser(configparser.RawConfigParser):
re.compile(value)
except re.error as e:
raise CoverageException(
- "Invalid [%s].%s value %r: %s" % (
- section, option, value, e
- )
- )
+ "Invalid [%s].%s value %r: %s" % (section, option, value, e)
+ )
if value:
value_list.append(value)
return value_list
@@ -124,12 +121,12 @@ class HandyConfigParser(configparser.RawConfigParser):
# The default line exclusion regexes.
DEFAULT_EXCLUDE = [
r'(?i)#\s*pragma[:\s]?\s*no\s*cover',
- ]
+]
# The default partial branch regexes, to be modified by the user.
DEFAULT_PARTIAL = [
r'(?i)#\s*pragma[:\s]?\s*no\s*branch',
- ]
+]
# The default partial branch regexes, based on Python semantics.
# These are any Python branching constructs that can't actually execute all
@@ -137,7 +134,7 @@ DEFAULT_PARTIAL = [
DEFAULT_PARTIAL_ALWAYS = [
'while (True|1|False|0):',
'if (True|1|False|0):',
- ]
+]
class CoverageConfig(object):
@@ -158,11 +155,12 @@ class CoverageConfig(object):
self.concurrency = None
self.cover_pylib = False
self.data_file = ".coverage"
- self.parallel = False
- self.timid = False
- self.source = None
self.debug = []
+ self.note = None
+ self.parallel = False
self.plugins = []
+ self.source = None
+ self.timid = False
# Defaults for [report]
self.exclude_list = DEFAULT_EXCLUDE[:]
@@ -170,15 +168,15 @@ class CoverageConfig(object):
self.ignore_errors = False
self.include = None
self.omit = None
- self.partial_list = DEFAULT_PARTIAL[:]
self.partial_always_list = DEFAULT_PARTIAL_ALWAYS[:]
+ self.partial_list = DEFAULT_PARTIAL[:]
self.precision = 0
self.show_missing = False
self.skip_covered = False
# Defaults for [html]
- self.html_dir = "htmlcov"
self.extra_css = None
+ self.html_dir = "htmlcov"
self.html_title = "Coverage report"
# Defaults for [xml]
@@ -215,9 +213,7 @@ class CoverageConfig(object):
try:
files_read = cp.read(filename)
except configparser.Error as err:
- raise CoverageException(
- "Couldn't read config file %s: %s" % (filename, err)
- )
+ raise CoverageException("Couldn't read config file %s: %s" % (filename, err))
if not files_read:
return False
@@ -227,9 +223,24 @@ class CoverageConfig(object):
for option_spec in self.CONFIG_FILE_OPTIONS:
self._set_attr_from_config_option(cp, *option_spec)
except ValueError as err:
- raise CoverageException(
- "Couldn't read config file %s: %s" % (filename, err)
- )
+ raise CoverageException("Couldn't read config file %s: %s" % (filename, err))
+
+ # Check that there are no unrecognized options.
+ all_options = collections.defaultdict(set)
+ for option_spec in self.CONFIG_FILE_OPTIONS:
+ section, option = option_spec[1].split(":")
+ all_options[section].add(option)
+
+ for section, options in iitems(all_options):
+ if cp.has_section(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
+ )
+ )
# [paths] is special
if cp.has_section('paths'):
@@ -258,10 +269,11 @@ class CoverageConfig(object):
('cover_pylib', 'run:cover_pylib', 'boolean'),
('data_file', 'run:data_file'),
('debug', 'run:debug', 'list'),
- ('plugins', 'run:plugins', 'list'),
('include', 'run:include', 'list'),
+ ('note', 'run:note'),
('omit', 'run:omit', 'list'),
('parallel', 'run:parallel', 'boolean'),
+ ('plugins', 'run:plugins', 'list'),
('source', 'run:source', 'list'),
('timid', 'run:timid', 'boolean'),
@@ -271,27 +283,27 @@ class CoverageConfig(object):
('ignore_errors', 'report:ignore_errors', 'boolean'),
('include', 'report:include', 'list'),
('omit', 'report:omit', 'list'),
- ('partial_list', 'report:partial_branches', 'regexlist'),
('partial_always_list', 'report:partial_branches_always', 'regexlist'),
+ ('partial_list', 'report:partial_branches', 'regexlist'),
('precision', 'report:precision', 'int'),
('show_missing', 'report:show_missing', 'boolean'),
('skip_covered', 'report:skip_covered', 'boolean'),
# [html]
- ('html_dir', 'html:directory'),
('extra_css', 'html:extra_css'),
+ ('html_dir', 'html:directory'),
('html_title', 'html:title'),
# [xml]
('xml_output', 'xml:output'),
('xml_package_depth', 'xml:package_depth', 'int'),
- ]
+ ]
def _set_attr_from_config_option(self, cp, attr, where, type_=''):
"""Set an attribute on self if it exists in the ConfigParser."""
section, option = where.split(":")
if cp.has_option(section, option):
- method = getattr(cp, 'get'+type_)
+ method = getattr(cp, 'get' + type_)
setattr(self, attr, method(section, option))
def get_plugin_options(self, plugin):