Skip to content

Commit

Permalink
feat: unrecognized options are now a warning rather than error. #1035 (
Browse files Browse the repository at this point in the history
…#1206)

Because they are warnings issued while parsing the configuration file, it's not
possible to suppress them with the coverage configuration.
  • Loading branch information
nedbat committed Aug 5, 2021
1 parent 57a691f commit 602e210
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 24 deletions.
6 changes: 6 additions & 0 deletions CHANGES.rst
Expand Up @@ -24,9 +24,15 @@ want to know what's different in 5.0 since 4.5.x, see :ref:`whatsnew5x`.
Unreleased
----------

- Unrecognized options in the configuration file are no longer errors. They are
now warnings, to ease the use of coverage across versions. Fixes `issue
1035`_.

- Fix another rarer instance of "Error binding parameter 0 - probably
unsupported type." (`issue 1010`_).

.. _issue 1035: https://github.com/nedbat/coveragepy/issues/1035


.. _changes_60b1:

Expand Down
9 changes: 5 additions & 4 deletions coverage/config.py
Expand Up @@ -248,7 +248,7 @@ def from_args(self, **kwargs):
setattr(self, k, v)

@contract(filename=str)
def from_file(self, filename, our_file):
def from_file(self, filename, warn, our_file):
"""Read configuration from a .rc file.
`filename` is a file name to read.
Expand Down Expand Up @@ -297,7 +297,7 @@ def from_file(self, filename, our_file):
real_section = cp.has_section(section)
if real_section:
for unknown in set(cp.options(section)) - options:
raise CoverageException(
warn(
"Unrecognized option '[{}] {}=' in config file {}".format(
real_section, unknown, filename
)
Expand Down Expand Up @@ -517,12 +517,13 @@ def config_files_to_try(config_file):
return files_to_try


def read_coverage_config(config_file, **kwargs):
def read_coverage_config(config_file, warn, **kwargs):
"""Read the coverage.py configuration.
Arguments:
config_file: a boolean or string, see the `Coverage` class for the
tricky details.
warn: a function to issue warnings.
all others: keyword arguments from the `Coverage` class, used for
setting values in the configuration.
Expand All @@ -541,7 +542,7 @@ def read_coverage_config(config_file, **kwargs):
files_to_try = config_files_to_try(config_file)

for fname, our_file, specified_file in files_to_try:
config_read = config.from_file(fname, our_file=our_file)
config_read = config.from_file(fname, warn, our_file=our_file)
if config_read:
break
if specified_file:
Expand Down
32 changes: 18 additions & 14 deletions coverage/control.py
Expand Up @@ -192,15 +192,7 @@ def __init__(
if data_file is _DEFAULT_DATAFILE:
data_file = None

# Build our configuration from a number of sources.
self.config = read_coverage_config(
config_file=config_file,
data_file=data_file, cover_pylib=cover_pylib, timid=timid,
branch=branch, parallel=bool_or_none(data_suffix),
source=source, source_pkgs=source_pkgs, run_omit=omit, run_include=include, debug=debug,
report_omit=omit, report_include=include,
concurrency=concurrency, context=context,
)
self.config = None

# This is injectable by tests.
self._debug_file = None
Expand Down Expand Up @@ -235,6 +227,16 @@ def __init__(
# Should we write the debug output?
self._should_write_debug = True

# Build our configuration from a number of sources.
self.config = read_coverage_config(
config_file=config_file, warn=self._warn,
data_file=data_file, cover_pylib=cover_pylib, timid=timid,
branch=branch, parallel=bool_or_none(data_suffix),
source=source, source_pkgs=source_pkgs, run_omit=omit, run_include=include, debug=debug,
report_omit=omit, report_include=include,
concurrency=concurrency, context=context,
)

# If we have sub-process measurement happening automatically, then we
# want any explicit creation of a Coverage object to mean, this process
# is already coverage-aware, so don't auto-measure it. By now, the
Expand Down Expand Up @@ -352,16 +354,18 @@ def _warn(self, msg, slug=None, once=False):
"""
if self._no_warn_slugs is None:
self._no_warn_slugs = list(self.config.disable_warnings)
if self.config is not None:
self._no_warn_slugs = list(self.config.disable_warnings)

if slug in self._no_warn_slugs:
# Don't issue the warning
return
if self._no_warn_slugs is not None:
if slug in self._no_warn_slugs:
# Don't issue the warning
return

self._warnings.append(msg)
if slug:
msg = f"{msg} ({slug})"
if self._debug.should('pid'):
if self._debug is not None and self._debug.should('pid'):
msg = f"[{os.getpid()}] {msg}"
warnings.warn(msg, category=CoverageWarning, stacklevel=2)

Expand Down
12 changes: 6 additions & 6 deletions tests/test_config.py
Expand Up @@ -10,7 +10,7 @@

import coverage
from coverage.config import HandyConfigParser
from coverage.exceptions import CoverageException
from coverage.exceptions import CoverageException, CoverageWarning

from tests.coveragetest import CoverageTest, UsingModulesMixin
from tests.helpers import without_module
Expand Down Expand Up @@ -392,7 +392,7 @@ def test_unknown_option(self):
xyzzy = 17
""")
msg = r"Unrecognized option '\[run\] xyzzy=' in config file .coveragerc"
with pytest.raises(CoverageException, match=msg):
with pytest.warns(CoverageWarning, match=msg):
_ = coverage.Coverage()

def test_unknown_option_toml(self):
Expand All @@ -401,7 +401,7 @@ def test_unknown_option_toml(self):
xyzzy = 17
""")
msg = r"Unrecognized option '\[tool.coverage.run\] xyzzy=' in config file pyproject.toml"
with pytest.raises(CoverageException, match=msg):
with pytest.warns(CoverageWarning, match=msg):
_ = coverage.Coverage()

def test_misplaced_option(self):
Expand All @@ -410,16 +410,16 @@ def test_misplaced_option(self):
branch = True
""")
msg = r"Unrecognized option '\[report\] branch=' in config file .coveragerc"
with pytest.raises(CoverageException, match=msg):
with pytest.warns(CoverageWarning, match=msg):
_ = coverage.Coverage()

def test_unknown_option_in_other_ini_file(self):
self.make_file("setup.cfg", """\
[coverage:run]
huh = what?
""")
msg = (r"Unrecognized option '\[coverage:run\] huh=' in config file setup.cfg")
with pytest.raises(CoverageException, match=msg):
msg = r"Unrecognized option '\[coverage:run\] huh=' in config file setup.cfg"
with pytest.warns(CoverageWarning, match=msg):
_ = coverage.Coverage()

def test_exceptions_from_missing_things(self):
Expand Down

0 comments on commit 602e210

Please sign in to comment.