Coverage for tests / test_config.py: 100.000%
413 statements
« prev ^ index » next coverage.py v7.12.1a0.dev1, created at 2025-11-30 17:57 +0000
« prev ^ index » next coverage.py v7.12.1a0.dev1, created at 2025-11-30 17:57 +0000
1# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2# For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt
4"""Test the config file handling for coverage.py"""
6from __future__ import annotations 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
8import os 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
9import tempfile 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
11from pathlib import Path 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
12from unittest import mock 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
14import pytest 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
16import coverage 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
17from coverage import Coverage, env 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
18from coverage.config import CoverageConfig, HandyConfigParser 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
19from coverage.exceptions import ConfigError, CoverageWarning 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
20from coverage.tomlconfig import TomlConfigParser 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
21from coverage.types import FilePathClasses, FilePathType 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
23from tests.coveragetest import CoverageTest, UsingModulesMixin 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
26class ConfigTest(CoverageTest): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
27 """Tests of the different sources of configuration settings."""
29 def test_default_config(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
30 # Just constructing a coverage() object gets the right defaults.
31 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
32 assert not cov.config.timid 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
33 assert not cov.config.branch 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
34 assert cov.config.data_file == ".coverage" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
36 def test_arguments(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
37 # Arguments to the constructor are applied to the configuration.
38 cov = coverage.Coverage(timid=True, data_file="fooey.dat", concurrency="multiprocessing") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
39 assert cov.config.timid 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
40 assert not cov.config.branch 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
41 assert cov.config.data_file == "fooey.dat" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
42 assert cov.config.concurrency == ["multiprocessing"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
44 def test_config_file(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
45 # A .coveragerc file will be read into the configuration.
46 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
47 ".coveragerc",
48 """\
49 # This is just a bogus .rc file for testing.
50 [run]
51 timid = True
52 data_file = .hello_kitty.data
53 """,
54 )
55 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
56 assert cov.config.timid 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
57 assert not cov.config.branch 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
58 assert cov.config.data_file == ".hello_kitty.data" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
60 @pytest.mark.parametrize("file_class", FilePathClasses) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
61 def test_named_config_file(self, file_class: FilePathType) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
62 # You can name the config file what you like.
63 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
64 "my_cov.ini",
65 """\
66 [run]
67 timid = True
68 ; I wouldn't really use this as a data file...
69 data_file = delete.me
70 """,
71 )
72 cov = coverage.Coverage(config_file=file_class("my_cov.ini")) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
73 assert cov.config.timid 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
74 assert not cov.config.branch 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
75 assert cov.config.data_file == "delete.me" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
77 def test_toml_config_file(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
78 # A pyproject.toml file will be read into the configuration.
79 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
80 "pyproject.toml",
81 """\
82 # This is just a bogus toml file for testing.
83 [tool.somethingelse]
84 authors = ["Joe D'Ávila <joe@gmail.com>"]
85 [tool.coverage.run]
86 concurrency = ["thread", "eventlet"]
87 timid = true
88 data_file = ".hello_kitty.data"
89 plugins = ["plugins.a_plugin"]
90 [tool.coverage.report]
91 precision = 3
92 fail_under = 90.5
93 [tool.coverage.html]
94 title = "tabblo & «ταБЬℓσ»"
95 [tool.coverage.plugins.a_plugin]
96 hello = "world"
97 """,
98 )
99 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
100 assert cov.config.timid 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
101 assert not cov.config.branch 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
102 assert cov.config.concurrency == ["thread", "eventlet"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
103 assert cov.config.data_file == ".hello_kitty.data" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
104 assert cov.config.plugins == ["plugins.a_plugin"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
105 assert cov.config.precision == 3 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
106 assert cov.config.html_title == "tabblo & «ταБЬℓσ»" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
107 assert cov.config.fail_under == 90.5 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
108 assert cov.config.get_plugin_options("plugins.a_plugin") == {"hello": "world"} 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
110 def test_toml_ints_can_be_floats(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
111 # Test that our class doesn't reject integers when loading floats
112 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
113 "pyproject.toml",
114 """\
115 # This is just a bogus toml file for testing.
116 [tool.coverage.report]
117 fail_under = 90
118 """,
119 )
120 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
121 assert cov.config.fail_under == 90 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
122 assert isinstance(cov.config.fail_under, float) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
124 def test_ignored_config_file(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
125 # You can disable reading the .coveragerc file.
126 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
127 ".coveragerc",
128 """\
129 [run]
130 timid = True
131 data_file = delete.me
132 """,
133 )
134 cov = coverage.Coverage(config_file=False) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
135 assert not cov.config.timid 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
136 assert not cov.config.branch 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
137 assert cov.config.data_file == ".coverage" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
139 def test_config_file_then_args(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
140 # The arguments override the .coveragerc file.
141 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
142 ".coveragerc",
143 """\
144 [run]
145 timid = True
146 data_file = weirdo.file
147 """,
148 )
149 cov = coverage.Coverage(timid=False, data_file=".mycov") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
150 assert not cov.config.timid 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
151 assert not cov.config.branch 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
152 assert cov.config.data_file == ".mycov" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
154 def test_data_file_from_environment(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
155 # There's an environment variable for the data_file.
156 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
157 ".coveragerc",
158 """\
159 [run]
160 timid = True
161 data_file = weirdo.file
162 """,
163 )
164 self.set_environ("COVERAGE_FILE", "fromenv.dat") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
165 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
166 assert cov.config.data_file == "fromenv.dat" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
167 # But the constructor arguments override the environment variable.
168 cov = coverage.Coverage(data_file="fromarg.dat") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
169 assert cov.config.data_file == "fromarg.dat" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
171 def test_debug_from_environment(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
172 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
173 ".coveragerc",
174 """\
175 [run]
176 debug = dataio, pids
177 """,
178 )
179 self.set_environ("COVERAGE_DEBUG", "callers, fooey") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
180 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
181 assert cov.config.debug == ["dataio", "pids", "callers", "fooey"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
183 def test_rcfile_from_environment(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
184 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
185 "here.ini",
186 """\
187 [run]
188 data_file = overthere.dat
189 """,
190 )
191 self.set_environ("COVERAGE_RCFILE", "here.ini") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
192 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
193 assert cov.config.data_file == "overthere.dat" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
195 def test_missing_rcfile_from_environment(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
196 self.set_environ("COVERAGE_RCFILE", "nowhere.ini") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
197 msg = "Couldn't read 'nowhere.ini' as a config file" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
198 with pytest.raises(ConfigError, match=msg): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
199 coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
201 @pytest.mark.parametrize("force", [False, True]) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
202 def test_force_environment(self, force: bool) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
203 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
204 ".coveragerc",
205 """\
206 [run]
207 debug = dataio, pids
208 """,
209 )
210 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
211 "force.ini",
212 """\
213 [run]
214 debug = callers, fooey
215 """,
216 )
217 if force: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
218 self.set_environ("COVERAGE_FORCE_CONFIG", "force.ini") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
219 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
220 if force: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
221 assert cov.config.debug == ["callers", "fooey"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
222 else:
223 assert cov.config.debug == ["dataio", "pids"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
225 @pytest.mark.parametrize( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
226 "bad_config, msg",
227 [
228 ("[run]\ntimid = maybe?\n", r"maybe[?]"),
229 ("timid = 1\n", r"no section headers"),
230 ("[run\n", r"\[run"),
231 (
232 "[report]\nexclude_lines = foo(\n",
233 r"Invalid \[report\].exclude_lines value 'foo\(': "
234 + r"(unbalanced parenthesis|missing \))",
235 ),
236 (
237 "[report]\nexclude_also = foo(\n",
238 r"Invalid \[report\].exclude_also value 'foo\(': "
239 + r"(unbalanced parenthesis|missing \))",
240 ),
241 (
242 "[report]\npartial_branches = foo[\n",
243 r"Invalid \[report\].partial_branches value 'foo\[': "
244 + r"(unexpected end of regular expression|unterminated character set)",
245 ),
246 (
247 "[report]\npartial_also = foo[\n",
248 r"Invalid \[report\].partial_also value 'foo\[': "
249 + r"(unexpected end of regular expression|unterminated character set)",
250 ),
251 (
252 "[report]\npartial_branches_always = foo***\n",
253 r"Invalid \[report\].partial_branches_always value "
254 + r"'foo\*\*\*': "
255 + r"multiple repeat",
256 ),
257 ],
258 )
259 def test_parse_errors(self, bad_config: str, msg: str) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
260 # Im-parsable values raise ConfigError, with details.
261 self.make_file(".coveragerc", bad_config) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
262 with pytest.raises(ConfigError, match=msg): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
263 coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
265 @pytest.mark.parametrize( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
266 "bad_config, msg",
267 [
268 ('[tool.coverage.run]\ntimid = "maybe?"\n', r"maybe[?]"),
269 ("[tool.coverage.run\n", None),
270 (
271 '[tool.coverage.report]\nexclude_lines = ["foo("]\n',
272 r"Invalid \[tool.coverage.report\].exclude_lines value 'foo\(': "
273 + r"(unbalanced parenthesis|missing \))",
274 ),
275 (
276 '[tool.coverage.report]\nexclude_also = ["foo("]\n',
277 r"Invalid \[tool.coverage.report\].exclude_also value 'foo\(': "
278 + r"(unbalanced parenthesis|missing \))",
279 ),
280 (
281 '[tool.coverage.report]\npartial_branches = ["foo["]\n',
282 r"Invalid \[tool.coverage.report\].partial_branches value 'foo\[': "
283 + r"(unexpected end of regular expression|unterminated character set)",
284 ),
285 (
286 '[tool.coverage.report]\npartial_also = ["foo["]\n',
287 r"Invalid \[tool.coverage.report\].partial_also value 'foo\[': "
288 + r"(unexpected end of regular expression|unterminated character set)",
289 ),
290 (
291 '[tool.coverage.report]\npartial_branches_always = ["foo***"]\n',
292 r"Invalid \[tool.coverage.report\].partial_branches_always value "
293 + r"'foo\*\*\*': "
294 + r"multiple repeat",
295 ),
296 ('[tool.coverage.run]\nconcurrency="foo"', "not a list"),
297 ("[tool.coverage.report]\nprecision=1.23", "not an integer"),
298 ('[tool.coverage.report]\nfail_under="s"', "couldn't convert to a float"),
299 ],
300 )
301 def test_toml_parse_errors(self, bad_config: str, msg: str) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
302 # Im-parsable values raise ConfigError, with details.
303 self.make_file("pyproject.toml", bad_config) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
304 with pytest.raises(ConfigError, match=msg): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
305 coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
307 def test_environment_vars_in_config(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
308 # Config files can have $envvars in them.
309 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
310 ".coveragerc",
311 """\
312 [run]
313 data_file = $DATA_FILE.fooey
314 branch = $OKAY
315 [report]
316 exclude_lines =
317 the_$$one
318 another${THING}
319 x${THING}y
320 x${NOTHING}y
321 huh$${X}what
322 """,
323 )
324 self.set_environ("DATA_FILE", "hello-world") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
325 self.set_environ("THING", "ZZZ") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
326 self.set_environ("OKAY", "yes") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
327 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
328 assert cov.config.data_file == "hello-world.fooey" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
329 assert cov.config.branch is True 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
330 assert cov.config.exclude_list == ["the_$one", "anotherZZZ", "xZZZy", "xy", "huh${X}what"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
332 def test_environment_vars_in_toml_config(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
333 # Config files can have $envvars in them.
334 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
335 "pyproject.toml",
336 """\
337 [tool.coverage.run]
338 data_file = "$DATA_FILE.fooey"
339 branch = "$BRANCH"
340 [tool.coverage.report]
341 precision = "$DIGITS"
342 fail_under = "$FAIL_UNDER"
343 exclude_lines = [
344 "the_$$one",
345 "another${THING}",
346 "x${THING}y",
347 "x${NOTHING}y",
348 "huh$${X}what",
349 ]
350 [othersection]
351 # This reproduces the failure from https://github.com/coveragepy/coveragepy/issues/1481
352 # When OTHER has a backslash that isn't a valid escape, like \\z (see below).
353 something = "if [ $OTHER ]; then printf '%s\\n' 'Hi'; fi"
354 """,
355 )
356 self.set_environ("BRANCH", "true") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
357 self.set_environ("DIGITS", "3") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
358 self.set_environ("FAIL_UNDER", "90.5") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
359 self.set_environ("DATA_FILE", "hello-world") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
360 self.set_environ("THING", "ZZZ") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
361 self.set_environ("OTHER", "hi\\zebra") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
362 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
363 assert cov.config.branch is True 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
364 assert cov.config.precision == 3 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
365 assert cov.config.data_file == "hello-world.fooey" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
366 assert cov.config.exclude_list == ["the_$one", "anotherZZZ", "xZZZy", "xy", "huh${X}what"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
368 def test_tilde_in_config(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
369 # Config entries that are file paths can be tilde-expanded.
370 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
371 ".coveragerc",
372 """\
373 [run]
374 data_file = ~/data.file
376 [html]
377 directory = ~joe/html_dir
379 [json]
380 output = ~/json/output.json
382 [lcov]
383 output = ~/lcov/~foo.lcov
385 [xml]
386 output = ~/somewhere/xml.out
388 [report]
389 # Strings that aren't file paths are not tilde-expanded.
390 exclude_lines =
391 ~/data.file
392 ~joe/html_dir
394 [paths]
395 mapping =
396 ~/src
397 ~joe/source
398 """,
399 )
401 self.assert_tilde_results() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
403 def test_tilde_in_toml_config(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
404 # Config entries that are file paths can be tilde-expanded.
405 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
406 "pyproject.toml",
407 """\
408 [tool.coverage.run]
409 data_file = "~/data.file"
411 [tool.coverage.html]
412 directory = "~joe/html_dir"
414 [tool.coverage.json]
415 output = "~/json/output.json"
417 [tool.coverage.lcov]
418 output = "~/lcov/~foo.lcov"
420 [tool.coverage.xml]
421 output = "~/somewhere/xml.out"
423 [tool.coverage.report]
424 # Strings that aren't file paths are not tilde-expanded.
425 exclude_lines = [
426 "~/data.file",
427 "~joe/html_dir",
428 ]
430 [tool.coverage.paths]
431 mapping = [
432 "~/src",
433 "~joe/source",
434 ]
435 """,
436 )
438 self.assert_tilde_results() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
440 def assert_tilde_results(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
441 """Common assertions for two tilde tests."""
443 def expanduser(s: str) -> str: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
444 """Fake tilde expansion"""
445 s = s.replace("~/", "/Users/me/") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
446 s = s.replace("~joe/", "/Users/joe/") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
447 return s 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
449 with mock.patch.object( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
450 coverage.config.os.path, # type: ignore[attr-defined]
451 "expanduser",
452 new=expanduser,
453 ):
454 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
455 assert cov.config.data_file == "/Users/me/data.file" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
456 assert cov.config.html_dir == "/Users/joe/html_dir" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
457 assert cov.config.json_output == "/Users/me/json/output.json" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
458 assert cov.config.lcov_output == "/Users/me/lcov/~foo.lcov" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
459 assert cov.config.xml_output == "/Users/me/somewhere/xml.out" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
460 assert cov.config.exclude_list == ["~/data.file", "~joe/html_dir"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
461 assert cov.config.paths == {"mapping": ["/Users/me/src", "/Users/joe/source"]} 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
463 def test_tweaks_after_constructor(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
464 # set_option can be used after construction to affect the config.
465 cov = coverage.Coverage(timid=True, data_file="fooey.dat") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
466 cov.set_option("run:timid", False) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
468 assert not cov.config.timid 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
469 assert not cov.config.branch 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
470 assert cov.config.data_file == "fooey.dat" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
472 assert not cov.get_option("run:timid") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
473 assert not cov.get_option("run:branch") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
474 assert cov.get_option("run:data_file") == "fooey.dat" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
476 def test_tweaks_paths_after_constructor(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
477 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
478 ".coveragerc",
479 """\
480 [paths]
481 first =
482 /first/1
483 /first/2
485 second =
486 /second/a
487 /second/b
488 """,
489 )
490 old_paths = { 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
491 "first": ["/first/1", "/first/2"],
492 "second": ["/second/a", "/second/b"],
493 }
494 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
495 paths = cov.get_option("paths") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
496 assert paths == old_paths 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
498 new_paths = { 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
499 "magic": ["src", "ok"],
500 }
501 cov.set_option("paths", new_paths) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
503 assert cov.get_option("paths") == new_paths 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
505 def test_tweak_error_checking(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
506 # Trying to set an unknown config value raises an error.
507 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
508 with pytest.raises(ConfigError, match="No such option: 'run:xyzzy'"): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
509 cov.set_option("run:xyzzy", 12) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
510 with pytest.raises(ConfigError, match="No such option: 'xyzzy:foo'"): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
511 cov.set_option("xyzzy:foo", 12) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
512 with pytest.raises(ConfigError, match="No such option: 'run:xyzzy'"): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
513 _ = cov.get_option("run:xyzzy") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
514 with pytest.raises(ConfigError, match="No such option: 'xyzzy:foo'"): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
515 _ = cov.get_option("xyzzy:foo") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
517 def test_tweak_plugin_options(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
518 # Plugin options have a more flexible syntax.
519 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
520 cov.set_option("run:plugins", ["fooey.plugin", "xyzzy.coverage.plugin"]) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
521 cov.set_option("fooey.plugin:xyzzy", 17) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
522 cov.set_option("xyzzy.coverage.plugin:plugh", ["a", "b"]) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
523 with pytest.raises(ConfigError, match="No such option: 'no_such.plugin:foo'"): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
524 cov.set_option("no_such.plugin:foo", 23) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
526 assert cov.get_option("fooey.plugin:xyzzy") == 17 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
527 assert cov.get_option("xyzzy.coverage.plugin:plugh") == ["a", "b"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
528 with pytest.raises(ConfigError, match="No such option: 'no_such.plugin:foo'"): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
529 _ = cov.get_option("no_such.plugin:foo") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
531 def test_unknown_option(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
532 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
533 ".coveragerc",
534 """\
535 [run]
536 xyzzy = 17
537 """,
538 )
539 msg = r"Unrecognized option '\[run\] xyzzy=' in config file .coveragerc" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
540 with pytest.warns(CoverageWarning, match=msg): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
541 _ = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
543 def test_unknown_option_toml(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
544 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
545 "pyproject.toml",
546 """\
547 [tool.coverage.run]
548 xyzzy = 17
549 """,
550 )
551 msg = r"Unrecognized option '\[tool.coverage.run\] xyzzy=' in config file pyproject.toml" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
552 with pytest.warns(CoverageWarning, match=msg): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
553 _ = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
555 def test_unknown_patch(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
556 self.make_file("foo.py", "a = 1") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
557 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
558 ".coveragerc",
559 """\
560 [run]
561 patch =
562 _exit
563 xyzzy
564 """,
565 )
566 msg = "Unknown patch 'xyzzy'" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
567 with pytest.raises(ConfigError, match=msg): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
568 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
569 self.start_import_stop(cov, "foo") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
571 def test_misplaced_option(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
572 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
573 ".coveragerc",
574 """\
575 [report]
576 branch = True
577 """,
578 )
579 msg = r"Unrecognized option '\[report\] branch=' in config file .coveragerc" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
580 with pytest.warns(CoverageWarning, match=msg): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
581 _ = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
583 def test_unknown_option_in_other_ini_file(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
584 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
585 "setup.cfg",
586 """\
587 [coverage:run]
588 huh = what?
589 """,
590 )
591 msg = r"Unrecognized option '\[coverage:run\] huh=' in config file setup.cfg" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
592 with pytest.warns(CoverageWarning, match=msg): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
593 _ = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
595 def test_exceptions_from_missing_things(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
596 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
597 "config.ini",
598 """\
599 [run]
600 branch = True
601 """,
602 )
603 config = HandyConfigParser(True) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
604 config.read(["config.ini"]) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
605 with pytest.raises(ConfigError, match="No section: 'xyzzy'"): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
606 config.options("xyzzy") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
607 with pytest.raises(ConfigError, match="No option 'foo' in section: 'xyzzy'"): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
608 config.get("xyzzy", "foo") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
610 def test_exclude_also(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
611 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
612 "pyproject.toml",
613 """\
614 [tool.coverage.report]
615 exclude_also = ["foobar", "raise .*Error"]
616 """,
617 )
618 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
620 expected = coverage.config.DEFAULT_EXCLUDE + ["foobar", "raise .*Error"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
621 assert cov.config.exclude_list == expected 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
623 def test_partial_also(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
624 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
625 "pyproject.toml",
626 """\
627 [tool.coverage.report]
628 partial_also = ["foobar", "raise .*Error"]
629 """,
630 )
631 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
633 expected = coverage.config.DEFAULT_PARTIAL + ["foobar", "raise .*Error"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
634 assert cov.config.partial_list == expected 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
636 def test_core_option(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
637 # Test that the core option can be set in the configuration file.
638 self.del_environ("COVERAGE_CORE") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
639 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
640 default_core = cov.config.core 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
641 core_to_set = "ctrace" if default_core == "pytrace" else "pytrace" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
643 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
644 ".coveragerc",
645 f"""\
646 [run]
647 core = {core_to_set}
648 """,
649 )
650 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
651 assert cov.config.core == core_to_set 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
652 os.remove(".coveragerc") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
654 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
655 "pyproject.toml",
656 f"""\
657 [tool.coverage.run]
658 core = "{core_to_set}"
659 """,
660 )
662 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
663 assert cov.config.core == core_to_set 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
666class ConfigFileTest(UsingModulesMixin, CoverageTest): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
667 """Tests of the config file settings in particular."""
669 # This sample file tries to use lots of variation of syntax...
670 # The {section} placeholder lets us nest these settings in another file.
671 LOTSA_SETTINGS = """\ 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
672 # This is a settings file for coverage.py
673 [{section}run]
674 timid = yes
675 data_file = something_or_other.dat
676 branch = 1
677 cover_pylib = TRUE
678 parallel = on
679 concurrency = thread
680 ; this omit is overridden by the omit from [report]
681 omit = twenty
682 source = myapp
683 source_pkgs = ned
684 source_dirs = cooldir
685 plugins =
686 plugins.a_plugin
687 plugins.another
688 debug = callers, pids , dataio
689 disable_warnings = abcd , efgh
691 [{section}report]
692 ; these settings affect reporting.
693 exclude_lines =
694 if 0:
696 pragma:?\\s+no cover
697 another_tab
699 ignore_errors = TRUE
700 omit =
701 one, another, some_more,
702 yet_more
703 include = thirty
704 precision = 3
706 partial_branches =
707 pragma:?\\s+no branch
708 partial_branches_always =
709 if 0:
710 while True:
712 show_missing= TruE
713 skip_covered = TruE
714 skip_empty =TruE
716 include_namespace_packages = TRUE
718 [{section}html]
720 directory = c:\\tricky\\dir.somewhere
721 extra_css=something/extra.css
722 title = Title & nums # nums!
723 [{section}xml]
724 output=mycov.xml
725 package_depth = 17
727 [{section}paths]
728 source =
729 .
730 /home/ned/src/
732 other = other, /home/ned/other, c:\\Ned\\etc
734 [{section}plugins.a_plugin]
735 hello = world
736 ; comments still work.
737 names = Jane/John/Jenny
739 [{section}json]
740 pretty_print = True
741 show_contexts = True
742 """
744 # Just some sample setup.cfg text from the docs.
745 SETUP_CFG = """\ 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
746 [bdist_rpm]
747 release = 1
748 packager = Jane Packager <janep@pysoft.com>
749 doc_files = CHANGES.txt
750 README.txt
751 USAGE.txt
752 doc/
753 examples/
754 """
756 # Just some sample tox.ini text from the docs.
757 TOX_INI = """\ 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
758 [tox]
759 envlist = py{26,27,33,34,35}-{c,py}tracer
760 skip_missing_interpreters = True
762 [testenv]
763 commands =
764 # Create tests/zipmods.zip
765 python igor.py zip_mods
766 """
768 def assert_config_settings_are_correct(self, cov: Coverage) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
769 """Check that `cov` has all the settings from LOTSA_SETTINGS."""
770 assert cov.config.timid 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
771 assert cov.config.data_file == "something_or_other.dat" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
772 assert cov.config.branch 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
773 assert cov.config.cover_pylib 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
774 assert cov.config.debug == ["callers", "pids", "dataio"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
775 assert cov.config.parallel 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
776 assert cov.config.concurrency == ["thread"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
777 assert cov.config.source == ["myapp"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
778 assert cov.config.source_pkgs == ["ned"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
779 assert cov.config.source_dirs == ["cooldir"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
780 assert cov.config.disable_warnings == ["abcd", "efgh"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
782 assert cov.get_exclude_list() == ["if 0:", r"pragma:?\s+no cover", "another_tab"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
783 assert cov.config.ignore_errors 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
784 assert cov.config.run_omit == ["twenty"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
785 assert cov.config.report_omit == ["one", "another", "some_more", "yet_more"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
786 assert cov.config.report_include == ["thirty"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
787 assert cov.config.precision == 3 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
789 assert cov.config.partial_list == [r"pragma:?\s+no branch"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
790 assert cov.config.partial_always_list == ["if 0:", "while True:"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
791 assert cov.config.plugins == ["plugins.a_plugin", "plugins.another"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
792 assert cov.config.show_missing 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
793 assert cov.config.skip_covered 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
794 assert cov.config.skip_empty 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
795 assert cov.config.html_dir == r"c:\tricky\dir.somewhere" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
796 assert cov.config.extra_css == "something/extra.css" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
797 assert cov.config.html_title == "Title & nums # nums!" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
799 assert cov.config.xml_output == "mycov.xml" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
800 assert cov.config.xml_package_depth == 17 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
802 assert cov.config.paths == { 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
803 "source": [".", "/home/ned/src/"],
804 "other": ["other", "/home/ned/other", "c:\\Ned\\etc"],
805 }
807 assert cov.config.get_plugin_options("plugins.a_plugin") == { 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
808 "hello": "world",
809 "names": "Jane/John/Jenny",
810 }
811 assert cov.config.get_plugin_options("plugins.another") == {} 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
812 assert cov.config.json_show_contexts is True 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
813 assert cov.config.json_pretty_print is True 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
814 assert cov.config.include_namespace_packages is True 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
816 def test_config_file_settings(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
817 self.make_file(".coveragerc", self.LOTSA_SETTINGS.format(section="")) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
818 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
819 self.assert_config_settings_are_correct(cov) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
821 def check_config_file_settings_in_other_file(self, fname: str, contents: str) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
822 """Check config will be read from another file, with prefixed sections."""
823 nested = self.LOTSA_SETTINGS.format(section="coverage:") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
824 fname = self.make_file(fname, nested + "\n" + contents) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
825 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
826 self.assert_config_settings_are_correct(cov) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
828 def test_config_file_settings_in_setupcfg(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
829 self.check_config_file_settings_in_other_file("setup.cfg", self.SETUP_CFG) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
831 def test_config_file_settings_in_toxini(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
832 self.check_config_file_settings_in_other_file("tox.ini", self.TOX_INI) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
834 def check_other_config_if_coveragerc_specified(self, fname: str, contents: str) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
835 """Check that config `fname` is read if .coveragerc is missing, but specified."""
836 nested = self.LOTSA_SETTINGS.format(section="coverage:") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
837 self.make_file(fname, nested + "\n" + contents) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
838 cov = coverage.Coverage(config_file=".coveragerc") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
839 self.assert_config_settings_are_correct(cov) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
841 def test_config_file_settings_in_setupcfg_if_coveragerc_specified(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
842 self.check_other_config_if_coveragerc_specified("setup.cfg", self.SETUP_CFG) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
844 def test_config_file_settings_in_tox_if_coveragerc_specified(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
845 self.check_other_config_if_coveragerc_specified("tox.ini", self.TOX_INI) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
847 def check_other_not_read_if_coveragerc(self, fname: str) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
848 """Check config `fname` is not read if .coveragerc exists."""
849 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
850 ".coveragerc",
851 """\
852 [run]
853 include = foo
854 """,
855 )
856 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
857 fname,
858 """\
859 [coverage:run]
860 omit = bar
861 branch = true
862 """,
863 )
864 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
865 assert cov.config.run_include == ["foo"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
866 assert cov.config.run_omit == [] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
867 assert cov.config.branch is False 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
869 def test_setupcfg_only_if_not_coveragerc(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
870 self.check_other_not_read_if_coveragerc("setup.cfg") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
872 def test_toxini_only_if_not_coveragerc(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
873 self.check_other_not_read_if_coveragerc("tox.ini") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
875 def check_other_config_need_prefixes(self, fname: str) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
876 """Check that `fname` sections won't be read if un-prefixed."""
877 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
878 fname,
879 """\
880 [run]
881 omit = bar
882 branch = true
883 """,
884 )
885 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
886 assert cov.config.run_omit == [] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
887 assert cov.config.branch is False 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
889 def test_setupcfg_only_if_prefixed(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
890 self.check_other_config_need_prefixes("setup.cfg") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
892 def test_toxini_only_if_prefixed(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
893 self.check_other_config_need_prefixes("tox.ini") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
895 def test_tox_ini_even_if_setup_cfg(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
896 # There's a setup.cfg, but no coverage settings in it, so tox.ini
897 # is read.
898 nested = self.LOTSA_SETTINGS.format(section="coverage:") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
899 self.make_file("tox.ini", self.TOX_INI + "\n" + nested) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
900 self.make_file("setup.cfg", self.SETUP_CFG) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
901 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
902 self.assert_config_settings_are_correct(cov) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
904 def test_read_prefixed_sections_from_explicit_file(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
905 # You can point to a tox.ini, and it will find [coverage:run] sections
906 nested = self.LOTSA_SETTINGS.format(section="coverage:") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
907 self.make_file("tox.ini", self.TOX_INI + "\n" + nested) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
908 cov = coverage.Coverage(config_file="tox.ini") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
909 self.assert_config_settings_are_correct(cov) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
911 def test_non_ascii(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
912 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
913 ".coveragerc",
914 """\
915 [report]
916 exclude_lines =
917 first
918 ✘${TOX_ENVNAME}
919 third
920 [html]
921 title = tabblo & «ταБЬℓσ» # numbers
922 """,
923 )
924 self.set_environ("TOX_ENVNAME", "weirdo") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
925 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
927 assert cov.config.exclude_list == ["first", "✘weirdo", "third"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
928 assert cov.config.html_title == "tabblo & «ταБЬℓσ» # numbers" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
930 @pytest.mark.parametrize("bad_file", ["nosuchfile.txt", "."]) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
931 def test_unreadable_config(self, bad_file: str) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
932 # If a config file is explicitly specified, then it is an error for it
933 # to not be readable.
934 msg = f"Couldn't read {bad_file!r} as a config file" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
935 with pytest.raises(ConfigError, match=msg): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
936 coverage.Coverage(config_file=bad_file) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
938 def test_nocoveragerc_file_when_specified(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
939 cov = coverage.Coverage(config_file=".coveragerc") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
940 assert not cov.config.timid 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
941 assert not cov.config.branch 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
942 assert cov.config.data_file == ".coverage" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
944 def test_no_toml_installed_no_toml(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
945 # Can't read a toml file that doesn't exist.
946 with mock.patch.object(coverage.tomlconfig, "has_tomllib", False): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
947 msg = "Couldn't read 'cov.toml' as a config file" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
948 with pytest.raises(ConfigError, match=msg): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
949 coverage.Coverage(config_file="cov.toml") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
951 @pytest.mark.skipif(env.PYVERSION >= (3, 11), reason="Python 3.11 has toml in stdlib") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
952 def test_no_toml_installed_explicit_toml(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
953 # Can't specify a toml config file if toml isn't installed.
954 self.make_file("cov.toml", "# A toml file!") 1abcdefg
955 with mock.patch.object(coverage.tomlconfig, "has_tomllib", False): 1abcdefg
956 msg = "Can't read 'cov.toml' without TOML support" 1abcdefg
957 with pytest.raises(ConfigError, match=msg): 1abcdefg
958 coverage.Coverage(config_file="cov.toml") 1abcdefg
960 @pytest.mark.skipif(env.PYVERSION >= (3, 11), reason="Python 3.11 has toml in stdlib") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
961 def test_no_toml_installed_pyproject_toml(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
962 # Can't have coverage config in pyproject.toml without toml installed.
963 self.make_file( 1abcdefg
964 "pyproject.toml",
965 """\
966 # A toml file!
967 [tool.coverage.run]
968 xyzzy = 17
969 """,
970 )
971 with mock.patch.object(coverage.tomlconfig, "has_tomllib", False): 1abcdefg
972 msg = "Can't read 'pyproject.toml' without TOML support" 1abcdefg
973 with pytest.raises(ConfigError, match=msg): 1abcdefg
974 coverage.Coverage() 1abcdefg
976 @pytest.mark.skipif(env.PYVERSION >= (3, 11), reason="Python 3.11 has toml in stdlib") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
977 def test_no_toml_installed_pyproject_toml_shorter_syntax(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
978 # Can't have coverage config in pyproject.toml without toml installed.
979 self.make_file( 1abcdefg
980 "pyproject.toml",
981 """\
982 # A toml file!
983 [tool.coverage]
984 run.parallel = true
985 """,
986 )
987 with mock.patch.object(coverage.tomlconfig, "has_tomllib", False): 1abcdefg
988 msg = "Can't read 'pyproject.toml' without TOML support" 1abcdefg
989 with pytest.raises(ConfigError, match=msg): 1abcdefg
990 coverage.Coverage() 1abcdefg
992 @pytest.mark.skipif(env.PYVERSION >= (3, 11), reason="Python 3.11 has toml in stdlib") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
993 def test_no_toml_installed_pyproject_no_coverage(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
994 # It's ok to have non-coverage pyproject.toml without toml installed.
995 self.make_file( 1abcdefg
996 "pyproject.toml",
997 """\
998 # A toml file!
999 [tool.something]
1000 xyzzy = 17
1001 """,
1002 )
1003 with mock.patch.object(coverage.tomlconfig, "has_tomllib", False): 1abcdefg
1004 cov = coverage.Coverage() 1abcdefg
1005 # We get default settings:
1006 assert not cov.config.timid 1abcdefg
1007 assert not cov.config.branch 1abcdefg
1008 assert cov.config.data_file == ".coverage" 1abcdefg
1010 def test_exceptions_from_missing_toml_things(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1011 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1012 "pyproject.toml",
1013 """\
1014 [tool.coverage.run]
1015 branch = true
1016 """,
1017 )
1018 config = TomlConfigParser(False) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1019 config.read("pyproject.toml") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1020 with pytest.raises(ConfigError, match="No section: 'xyzzy'"): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1021 config.options("xyzzy") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1022 with pytest.raises(ConfigError, match="No section: 'xyzzy'"): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1023 config.get("xyzzy", "foo") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1024 with pytest.raises(ConfigError, match="No option 'foo' in section: 'tool.coverage.run'"): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1025 config.get("run", "foo") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1028class SerializeConfigTest(CoverageTest): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1029 """Tests of serializing the configuration for subprocesses."""
1031 def test_them(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1032 tmpsrc = str(Path(tempfile.gettempdir()) / "more_source") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1033 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1034 ".coveragerc",
1035 f"""\
1036 [run]
1037 timid = True
1038 data_file = somewhere/the_data.db
1039 debug_file = somewhere/debug.out
1040 source = my_src, their_src
1041 source_dirs = my_src, their_src, {tmpsrc}
1042 debug = this_thing, that_thing
1043 """,
1044 )
1045 self.make_file("my_src/__init__.py") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1046 self.make_file("that_thing/__init__.py") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1047 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1048 config2 = CoverageConfig.deserialize(cov.config.serialize()) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1049 assert config2.timid 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1050 assert config2.data_file == os.path.abspath("somewhere/the_data.db") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1051 assert config2.debug_file == os.path.abspath("somewhere/debug.out") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1052 assert config2.source == [ 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1053 os.path.abspath("my_src"),
1054 "their_src",
1055 ]
1056 assert config2.source_dirs == [ 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()
1057 os.path.abspath("my_src"),
1058 os.path.abspath("their_src"),
1059 tmpsrc,
1060 ]
1061 assert config2.debug == ["this_thing", "that_thing"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()