Skip to content

Commit 602e210

Browse files
authored
feat: unrecognized options are now a warning rather than error. #1035 (#1206)
Because they are warnings issued while parsing the configuration file, it's not possible to suppress them with the coverage configuration.
1 parent 57a691f commit 602e210

File tree

4 files changed

+35
-24
lines changed

4 files changed

+35
-24
lines changed

CHANGES.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,15 @@ want to know what's different in 5.0 since 4.5.x, see :ref:`whatsnew5x`.
2424
Unreleased
2525
----------
2626

27+
- Unrecognized options in the configuration file are no longer errors. They are
28+
now warnings, to ease the use of coverage across versions. Fixes `issue
29+
1035`_.
30+
2731
- Fix another rarer instance of "Error binding parameter 0 - probably
2832
unsupported type." (`issue 1010`_).
2933

34+
.. _issue 1035: https://github.com/nedbat/coveragepy/issues/1035
35+
3036

3137
.. _changes_60b1:
3238

coverage/config.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ def from_args(self, **kwargs):
248248
setattr(self, k, v)
249249

250250
@contract(filename=str)
251-
def from_file(self, filename, our_file):
251+
def from_file(self, filename, warn, our_file):
252252
"""Read configuration from a .rc file.
253253
254254
`filename` is a file name to read.
@@ -297,7 +297,7 @@ def from_file(self, filename, our_file):
297297
real_section = cp.has_section(section)
298298
if real_section:
299299
for unknown in set(cp.options(section)) - options:
300-
raise CoverageException(
300+
warn(
301301
"Unrecognized option '[{}] {}=' in config file {}".format(
302302
real_section, unknown, filename
303303
)
@@ -517,12 +517,13 @@ def config_files_to_try(config_file):
517517
return files_to_try
518518

519519

520-
def read_coverage_config(config_file, **kwargs):
520+
def read_coverage_config(config_file, warn, **kwargs):
521521
"""Read the coverage.py configuration.
522522
523523
Arguments:
524524
config_file: a boolean or string, see the `Coverage` class for the
525525
tricky details.
526+
warn: a function to issue warnings.
526527
all others: keyword arguments from the `Coverage` class, used for
527528
setting values in the configuration.
528529
@@ -541,7 +542,7 @@ def read_coverage_config(config_file, **kwargs):
541542
files_to_try = config_files_to_try(config_file)
542543

543544
for fname, our_file, specified_file in files_to_try:
544-
config_read = config.from_file(fname, our_file=our_file)
545+
config_read = config.from_file(fname, warn, our_file=our_file)
545546
if config_read:
546547
break
547548
if specified_file:

coverage/control.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -192,15 +192,7 @@ def __init__(
192192
if data_file is _DEFAULT_DATAFILE:
193193
data_file = None
194194

195-
# Build our configuration from a number of sources.
196-
self.config = read_coverage_config(
197-
config_file=config_file,
198-
data_file=data_file, cover_pylib=cover_pylib, timid=timid,
199-
branch=branch, parallel=bool_or_none(data_suffix),
200-
source=source, source_pkgs=source_pkgs, run_omit=omit, run_include=include, debug=debug,
201-
report_omit=omit, report_include=include,
202-
concurrency=concurrency, context=context,
203-
)
195+
self.config = None
204196

205197
# This is injectable by tests.
206198
self._debug_file = None
@@ -235,6 +227,16 @@ def __init__(
235227
# Should we write the debug output?
236228
self._should_write_debug = True
237229

230+
# Build our configuration from a number of sources.
231+
self.config = read_coverage_config(
232+
config_file=config_file, warn=self._warn,
233+
data_file=data_file, cover_pylib=cover_pylib, timid=timid,
234+
branch=branch, parallel=bool_or_none(data_suffix),
235+
source=source, source_pkgs=source_pkgs, run_omit=omit, run_include=include, debug=debug,
236+
report_omit=omit, report_include=include,
237+
concurrency=concurrency, context=context,
238+
)
239+
238240
# If we have sub-process measurement happening automatically, then we
239241
# want any explicit creation of a Coverage object to mean, this process
240242
# is already coverage-aware, so don't auto-measure it. By now, the
@@ -352,16 +354,18 @@ def _warn(self, msg, slug=None, once=False):
352354
353355
"""
354356
if self._no_warn_slugs is None:
355-
self._no_warn_slugs = list(self.config.disable_warnings)
357+
if self.config is not None:
358+
self._no_warn_slugs = list(self.config.disable_warnings)
356359

357-
if slug in self._no_warn_slugs:
358-
# Don't issue the warning
359-
return
360+
if self._no_warn_slugs is not None:
361+
if slug in self._no_warn_slugs:
362+
# Don't issue the warning
363+
return
360364

361365
self._warnings.append(msg)
362366
if slug:
363367
msg = f"{msg} ({slug})"
364-
if self._debug.should('pid'):
368+
if self._debug is not None and self._debug.should('pid'):
365369
msg = f"[{os.getpid()}] {msg}"
366370
warnings.warn(msg, category=CoverageWarning, stacklevel=2)
367371

tests/test_config.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
import coverage
1212
from coverage.config import HandyConfigParser
13-
from coverage.exceptions import CoverageException
13+
from coverage.exceptions import CoverageException, CoverageWarning
1414

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

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

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

416416
def test_unknown_option_in_other_ini_file(self):
417417
self.make_file("setup.cfg", """\
418418
[coverage:run]
419419
huh = what?
420420
""")
421-
msg = (r"Unrecognized option '\[coverage:run\] huh=' in config file setup.cfg")
422-
with pytest.raises(CoverageException, match=msg):
421+
msg = r"Unrecognized option '\[coverage:run\] huh=' in config file setup.cfg"
422+
with pytest.warns(CoverageWarning, match=msg):
423423
_ = coverage.Coverage()
424424

425425
def test_exceptions_from_missing_things(self):

0 commit comments

Comments
 (0)