1import py 2import pytest 3from iniconfig import IniConfig, ParseError, __all__ as ALL 4from iniconfig import iscommentline 5from textwrap import dedent 6 7 8check_tokens = { 9 'section': ( 10 '[section]', 11 [(0, 'section', None, None)] 12 ), 13 'value': ( 14 'value = 1', 15 [(0, None, 'value', '1')] 16 ), 17 'value in section': ( 18 '[section]\nvalue=1', 19 [(0, 'section', None, None), (1, 'section', 'value', '1')] 20 ), 21 'value with continuation': ( 22 'names =\n Alice\n Bob', 23 [(0, None, 'names', 'Alice\nBob')] 24 ), 25 'value with aligned continuation': ( 26 'names = Alice\n' 27 ' Bob', 28 [(0, None, 'names', 'Alice\nBob')] 29 ), 30 'blank line': ( 31 '[section]\n\nvalue=1', 32 [(0, 'section', None, None), (2, 'section', 'value', '1')] 33 ), 34 'comment': ( 35 '# comment', 36 [] 37 ), 38 'comment on value': ( 39 'value = 1', 40 [(0, None, 'value', '1')] 41 ), 42 43 'comment on section': ( 44 '[section] #comment', 45 [(0, 'section', None, None)] 46 ), 47 'comment2': ( 48 '; comment', 49 [] 50 ), 51 52 'comment2 on section': ( 53 '[section] ;comment', 54 [(0, 'section', None, None)] 55 ), 56 'pseudo section syntax in value': ( 57 'name = value []', 58 [(0, None, 'name', 'value []')] 59 ), 60 'assignment in value': ( 61 'value = x = 3', 62 [(0, None, 'value', 'x = 3')] 63 ), 64 'use of colon for name-values': ( 65 'name: y', 66 [(0, None, 'name', 'y')] 67 ), 68 'use of colon without space': ( 69 'value:y=5', 70 [(0, None, 'value', 'y=5')] 71 ), 72 'equality gets precedence': ( 73 'value=xyz:5', 74 [(0, None, 'value', 'xyz:5')] 75 ), 76 77} 78 79 80@pytest.fixture(params=sorted(check_tokens)) 81def input_expected(request): 82 return check_tokens[request.param] 83 84 85@pytest.fixture 86def input(input_expected): 87 return input_expected[0] 88 89 90@pytest.fixture 91def expected(input_expected): 92 return input_expected[1] 93 94 95def parse(input): 96 # only for testing purposes - _parse() does not use state except path 97 ini = object.__new__(IniConfig) 98 ini.path = "sample" 99 return ini._parse(input.splitlines(True)) 100 101 102def parse_a_error(input): 103 return py.test.raises(ParseError, parse, input) 104 105 106def test_tokenize(input, expected): 107 parsed = parse(input) 108 assert parsed == expected 109 110 111def test_parse_empty(): 112 parsed = parse("") 113 assert not parsed 114 ini = IniConfig("sample", "") 115 assert not ini.sections 116 117 118def test_ParseError(): 119 e = ParseError("filename", 0, "hello") 120 assert str(e) == "filename:1: hello" 121 122 123def test_continuation_needs_perceeding_token(): 124 excinfo = parse_a_error(' Foo') 125 assert excinfo.value.lineno == 0 126 127 128def test_continuation_cant_be_after_section(): 129 excinfo = parse_a_error('[section]\n Foo') 130 assert excinfo.value.lineno == 1 131 132 133def test_section_cant_be_empty(): 134 excinfo = parse_a_error('[]') 135 assert excinfo.value.lineno == 0 136 137 138@py.test.mark.parametrize('line', [ 139 '!!', 140 ]) 141def test_error_on_weird_lines(line): 142 parse_a_error(line) 143 144 145def test_iniconfig_from_file(tmpdir): 146 path = tmpdir/'test.txt' 147 path.write('[metadata]\nname=1') 148 149 config = IniConfig(path=path) 150 assert list(config.sections) == ['metadata'] 151 config = IniConfig(path, "[diff]") 152 assert list(config.sections) == ['diff'] 153 with pytest.raises(TypeError): 154 IniConfig(data=path.read()) 155 156 157def test_iniconfig_section_first(tmpdir): 158 with pytest.raises(ParseError) as excinfo: 159 IniConfig("x", data='name=1') 160 assert excinfo.value.msg == "no section header defined" 161 162 163def test_iniconig_section_duplicate_fails(): 164 with pytest.raises(ParseError) as excinfo: 165 IniConfig("x", data='[section]\n[section]') 166 assert 'duplicate section' in str(excinfo.value) 167 168 169def test_iniconfig_duplicate_key_fails(): 170 with pytest.raises(ParseError) as excinfo: 171 IniConfig("x", data='[section]\nname = Alice\nname = bob') 172 173 assert 'duplicate name' in str(excinfo.value) 174 175 176def test_iniconfig_lineof(): 177 config = IniConfig("x.ini", data=( 178 '[section]\n' 179 'value = 1\n' 180 '[section2]\n' 181 '# comment\n' 182 'value =2' 183 )) 184 185 assert config.lineof('missing') is None 186 assert config.lineof('section') == 1 187 assert config.lineof('section2') == 3 188 assert config.lineof('section', 'value') == 2 189 assert config.lineof('section2', 'value') == 5 190 191 assert config['section'].lineof('value') == 2 192 assert config['section2'].lineof('value') == 5 193 194 195def test_iniconfig_get_convert(): 196 config = IniConfig("x", data='[section]\nint = 1\nfloat = 1.1') 197 assert config.get('section', 'int') == '1' 198 assert config.get('section', 'int', convert=int) == 1 199 200 201def test_iniconfig_get_missing(): 202 config = IniConfig("x", data='[section]\nint = 1\nfloat = 1.1') 203 assert config.get('section', 'missing', default=1) == 1 204 assert config.get('section', 'missing') is None 205 206 207def test_section_get(): 208 config = IniConfig("x", data='[section]\nvalue=1') 209 section = config['section'] 210 assert section.get('value', convert=int) == 1 211 assert section.get('value', 1) == "1" 212 assert section.get('missing', 2) == 2 213 214 215def test_missing_section(): 216 config = IniConfig("x", data='[section]\nvalue=1') 217 with pytest.raises(KeyError): 218 config["other"] 219 220 221def test_section_getitem(): 222 config = IniConfig("x", data='[section]\nvalue=1') 223 assert config['section']['value'] == '1' 224 assert config['section']['value'] == '1' 225 226 227def test_section_iter(): 228 config = IniConfig("x", data='[section]\nvalue=1') 229 names = list(config['section']) 230 assert names == ['value'] 231 items = list(config['section'].items()) 232 assert items == [('value', '1')] 233 234 235def test_config_iter(): 236 config = IniConfig("x.ini", data=dedent(''' 237 [section1] 238 value=1 239 [section2] 240 value=2 241 ''')) 242 l = list(config) 243 assert len(l) == 2 244 assert l[0].name == 'section1' 245 assert l[0]['value'] == '1' 246 assert l[1].name == 'section2' 247 assert l[1]['value'] == '2' 248 249 250def test_config_contains(): 251 config = IniConfig("x.ini", data=dedent(''' 252 [section1] 253 value=1 254 [section2] 255 value=2 256 ''')) 257 assert 'xyz' not in config 258 assert 'section1' in config 259 assert 'section2' in config 260 261 262def test_iter_file_order(): 263 config = IniConfig("x.ini", data=""" 264[section2] #cpython dict ordered before section 265value = 1 266value2 = 2 # dict ordered before value 267[section] 268a = 1 269b = 2 270""") 271 l = list(config) 272 secnames = [x.name for x in l] 273 assert secnames == ['section2', 'section'] 274 assert list(config['section2']) == ['value', 'value2'] 275 assert list(config['section']) == ['a', 'b'] 276 277 278def test_example_pypirc(): 279 config = IniConfig("pypirc", data=dedent(''' 280 [distutils] 281 index-servers = 282 pypi 283 other 284 285 [pypi] 286 repository: <repository-url> 287 username: <username> 288 password: <password> 289 290 [other] 291 repository: http://example.com/pypi 292 username: <username> 293 password: <password> 294 ''')) 295 distutils, pypi, other = list(config) 296 assert distutils["index-servers"] == "pypi\nother" 297 assert pypi['repository'] == '<repository-url>' 298 assert pypi['username'] == '<username>' 299 assert pypi['password'] == '<password>' 300 assert ['repository', 'username', 'password'] == list(other) 301 302 303def test_api_import(): 304 assert ALL == ['IniConfig', 'ParseError'] 305 306 307@pytest.mark.parametrize("line", [ 308 "#qwe", 309 " #qwe", 310 ";qwe", 311 " ;qwe", 312]) 313def test_iscommentline_true(line): 314 assert iscommentline(line) 315