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

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 

3 

4"""Test the config file handling for coverage.py""" 

5 

6from __future__ import annotations 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

7 

8import os 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

9import tempfile 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

10 

11from pathlib import Path 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

12from unittest import mock 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

13 

14import pytest 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

15 

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()

22 

23from tests.coveragetest import CoverageTest, UsingModulesMixin 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

24 

25 

26class ConfigTest(CoverageTest): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

27 """Tests of the different sources of configuration settings.""" 

28 

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()

35 

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()

43 

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()

59 

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()

76 

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()

109 

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()

123 

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()

138 

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()

153 

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()

170 

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()

182 

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()

194 

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()

200 

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()

224 

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()

264 

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()

306 

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()

331 

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()

367 

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 

375 

376 [html] 

377 directory = ~joe/html_dir 

378 

379 [json] 

380 output = ~/json/output.json 

381 

382 [lcov] 

383 output = ~/lcov/~foo.lcov 

384 

385 [xml] 

386 output = ~/somewhere/xml.out 

387 

388 [report] 

389 # Strings that aren't file paths are not tilde-expanded. 

390 exclude_lines = 

391 ~/data.file 

392 ~joe/html_dir 

393 

394 [paths] 

395 mapping = 

396 ~/src 

397 ~joe/source 

398 """, 

399 ) 

400 

401 self.assert_tilde_results() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

402 

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" 

410 

411 [tool.coverage.html] 

412 directory = "~joe/html_dir" 

413 

414 [tool.coverage.json] 

415 output = "~/json/output.json" 

416 

417 [tool.coverage.lcov] 

418 output = "~/lcov/~foo.lcov" 

419 

420 [tool.coverage.xml] 

421 output = "~/somewhere/xml.out" 

422 

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 ] 

429 

430 [tool.coverage.paths] 

431 mapping = [ 

432 "~/src", 

433 "~joe/source", 

434 ] 

435 """, 

436 ) 

437 

438 self.assert_tilde_results() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

439 

440 def assert_tilde_results(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

441 """Common assertions for two tilde tests.""" 

442 

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()

448 

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()

462 

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()

467 

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()

471 

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()

475 

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 

484 

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()

497 

498 new_paths = { 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

499 "magic": ["src", "ok"], 

500 } 

501 cov.set_option("paths", new_paths) 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

502 

503 assert cov.get_option("paths") == new_paths 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

504 

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()

516 

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()

525 

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()

530 

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()

542 

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()

554 

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()

570 

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()

582 

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()

594 

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()

609 

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()

619 

620 expected = coverage.config.DEFAULT_EXCLUDE + ["foobar", "raise .*Error"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

621 assert cov.config.exclude_list == expected 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

622 

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()

632 

633 expected = coverage.config.DEFAULT_PARTIAL + ["foobar", "raise .*Error"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

634 assert cov.config.partial_list == expected 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

635 

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()

642 

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()

653 

654 self.make_file( 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

655 "pyproject.toml", 

656 f"""\ 

657 [tool.coverage.run] 

658 core = "{core_to_set}" 

659 """, 

660 ) 

661 

662 cov = coverage.Coverage() 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

663 assert cov.config.core == core_to_set 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

664 

665 

666class ConfigFileTest(UsingModulesMixin, CoverageTest): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

667 """Tests of the config file settings in particular.""" 

668 

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 

690 

691 [{section}report] 

692 ; these settings affect reporting. 

693 exclude_lines = 

694 if 0: 

695 

696 pragma:?\\s+no cover 

697 another_tab 

698 

699 ignore_errors = TRUE 

700 omit = 

701 one, another, some_more, 

702 yet_more 

703 include = thirty 

704 precision = 3 

705 

706 partial_branches = 

707 pragma:?\\s+no branch 

708 partial_branches_always = 

709 if 0: 

710 while True: 

711 

712 show_missing= TruE 

713 skip_covered = TruE 

714 skip_empty =TruE 

715 

716 include_namespace_packages = TRUE 

717 

718 [{section}html] 

719 

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 

726 

727 [{section}paths] 

728 source = 

729 . 

730 /home/ned/src/ 

731 

732 other = other, /home/ned/other, c:\\Ned\\etc 

733 

734 [{section}plugins.a_plugin] 

735 hello = world 

736 ; comments still work. 

737 names = Jane/John/Jenny 

738 

739 [{section}json] 

740 pretty_print = True 

741 show_contexts = True 

742 """ 

743 

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 """ 

755 

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 

761 

762 [testenv] 

763 commands = 

764 # Create tests/zipmods.zip 

765 python igor.py zip_mods 

766 """ 

767 

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()

781 

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()

788 

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()

798 

799 assert cov.config.xml_output == "mycov.xml" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

800 assert cov.config.xml_package_depth == 17 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

801 

802 assert cov.config.paths == { 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

803 "source": [".", "/home/ned/src/"], 

804 "other": ["other", "/home/ned/other", "c:\\Ned\\etc"], 

805 } 

806 

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()

815 

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()

820 

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()

827 

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()

830 

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()

833 

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()

840 

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()

843 

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()

846 

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()

868 

869 def test_setupcfg_only_if_not_coveragerc(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

870 self.check_other_not_read_if_coveragerc("setup.cfg") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

871 

872 def test_toxini_only_if_not_coveragerc(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

873 self.check_other_not_read_if_coveragerc("tox.ini") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

874 

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()

888 

889 def test_setupcfg_only_if_prefixed(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

890 self.check_other_config_need_prefixes("setup.cfg") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

891 

892 def test_toxini_only_if_prefixed(self) -> None: 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

893 self.check_other_config_need_prefixes("tox.ini") 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

894 

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()

903 

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()

910 

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()

926 

927 assert cov.config.exclude_list == ["first", "✘weirdo", "third"] 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

928 assert cov.config.html_title == "tabblo & «ταБЬℓσ» # numbers" 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

929 

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()

937 

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()

943 

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()

950 

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

959 

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

975 

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

991 

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

1009 

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()

1026 

1027 

1028class SerializeConfigTest(CoverageTest): 1abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%'g()

1029 """Tests of serializing the configuration for subprocesses.""" 

1030 

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()