Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/backports/configparser/__init__.py: 52%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

713 statements  

1"""Configuration file parser. 

2 

3A configuration file consists of sections, lead by a "[section]" header, 

4and followed by "name: value" entries, with continuations and such in 

5the style of RFC 822. 

6 

7Intrinsic defaults can be specified by passing them into the 

8ConfigParser constructor as a dictionary. 

9 

10class: 

11 

12ConfigParser -- responsible for parsing a list of 

13 configuration files, and managing the parsed database. 

14 

15 methods: 

16 

17 __init__(defaults=None, dict_type=_default_dict, allow_no_value=False, 

18 delimiters=('=', ':'), comment_prefixes=('#', ';'), 

19 inline_comment_prefixes=None, strict=True, 

20 empty_lines_in_values=True, default_section='DEFAULT', 

21 interpolation=<unset>, converters=<unset>, 

22 allow_unnamed_section=False): 

23 Create the parser. When `defaults` is given, it is initialized into the 

24 dictionary or intrinsic defaults. The keys must be strings, the values 

25 must be appropriate for %()s string interpolation. 

26 

27 When `dict_type` is given, it will be used to create the dictionary 

28 objects for the list of sections, for the options within a section, and 

29 for the default values. 

30 

31 When `delimiters` is given, it will be used as the set of substrings 

32 that divide keys from values. 

33 

34 When `comment_prefixes` is given, it will be used as the set of 

35 substrings that prefix comments in empty lines. Comments can be 

36 indented. 

37 

38 When `inline_comment_prefixes` is given, it will be used as the set of 

39 substrings that prefix comments in non-empty lines. 

40 

41 When `strict` is True, the parser won't allow for any section or option 

42 duplicates while reading from a single source (file, string or 

43 dictionary). Default is True. 

44 

45 When `empty_lines_in_values` is False (default: True), each empty line 

46 marks the end of an option. Otherwise, internal empty lines of 

47 a multiline option are kept as part of the value. 

48 

49 When `allow_no_value` is True (default: False), options without 

50 values are accepted; the value presented for these is None. 

51 

52 When `default_section` is given, the name of the special section is 

53 named accordingly. By default it is called ``"DEFAULT"`` but this can 

54 be customized to point to any other valid section name. Its current 

55 value can be retrieved using the ``parser_instance.default_section`` 

56 attribute and may be modified at runtime. 

57 

58 When `interpolation` is given, it should be an Interpolation subclass 

59 instance. It will be used as the handler for option value 

60 pre-processing when using getters. RawConfigParser objects don't do 

61 any sort of interpolation, whereas ConfigParser uses an instance of 

62 BasicInterpolation. The library also provides a ``zc.buildout`` 

63 inspired ExtendedInterpolation implementation. 

64 

65 When `converters` is given, it should be a dictionary where each key 

66 represents the name of a type converter and each value is a callable 

67 implementing the conversion from string to the desired datatype. Every 

68 converter gets its corresponding get*() method on the parser object and 

69 section proxies. 

70 

71 When `allow_unnamed_section` is True (default: False), options 

72 without section are accepted: the section for these is 

73 ``configparser.UNNAMED_SECTION``. 

74 

75 sections() 

76 Return all the configuration section names, sans DEFAULT. 

77 

78 has_section(section) 

79 Return whether the given section exists. 

80 

81 has_option(section, option) 

82 Return whether the given option exists in the given section. 

83 

84 options(section) 

85 Return list of configuration options for the named section. 

86 

87 read(filenames, encoding=None) 

88 Read and parse the iterable of named configuration files, given by 

89 name. A single filename is also allowed. Non-existing files 

90 are ignored. Return list of successfully read files. 

91 

92 read_file(f, filename=None) 

93 Read and parse one configuration file, given as a file object. 

94 The filename defaults to f.name; it is only used in error 

95 messages (if f has no `name` attribute, the string `<???>` is used). 

96 

97 read_string(string) 

98 Read configuration from a given string. 

99 

100 read_dict(dictionary) 

101 Read configuration from a dictionary. Keys are section names, 

102 values are dictionaries with keys and values that should be present 

103 in the section. If the used dictionary type preserves order, sections 

104 and their keys will be added in order. Values are automatically 

105 converted to strings. 

106 

107 get(section, option, raw=False, vars=None, fallback=_UNSET) 

108 Return a string value for the named option. All % interpolations are 

109 expanded in the return values, based on the defaults passed into the 

110 constructor and the DEFAULT section. Additional substitutions may be 

111 provided using the `vars` argument, which must be a dictionary whose 

112 contents override any pre-existing defaults. If `option` is a key in 

113 `vars`, the value from `vars` is used. 

114 

115 getint(section, options, raw=False, vars=None, fallback=_UNSET) 

116 Like get(), but convert value to an integer. 

117 

118 getfloat(section, options, raw=False, vars=None, fallback=_UNSET) 

119 Like get(), but convert value to a float. 

120 

121 getboolean(section, options, raw=False, vars=None, fallback=_UNSET) 

122 Like get(), but convert value to a boolean (currently case 

123 insensitively defined as 0, false, no, off for False, and 1, true, 

124 yes, on for True). Returns False or True. 

125 

126 items(section=_UNSET, raw=False, vars=None) 

127 If section is given, return a list of tuples with (name, value) for 

128 each option in the section. Otherwise, return a list of tuples with 

129 (section_name, section_proxy) for each section, including DEFAULTSECT. 

130 

131 remove_section(section) 

132 Remove the given file section and all its options. 

133 

134 remove_option(section, option) 

135 Remove the given option from the given section. 

136 

137 set(section, option, value) 

138 Set the given option. 

139 

140 write(fp, space_around_delimiters=True) 

141 Write the configuration state in .ini format. If 

142 `space_around_delimiters` is True (the default), delimiters 

143 between keys and values are surrounded by spaces. 

144""" 

145 

146from __future__ import annotations 

147 

148# Do not import dataclasses; overhead is unacceptable (gh-117703) 

149 

150from collections.abc import Iterable, MutableMapping 

151from collections import ChainMap as _ChainMap 

152import contextlib 

153import functools 

154from .compat import io 

155import itertools 

156import os 

157import re 

158import sys 

159import types 

160 

161__all__ = ( 

162 "NoSectionError", 

163 "DuplicateOptionError", 

164 "DuplicateSectionError", 

165 "NoOptionError", 

166 "InterpolationError", 

167 "InterpolationDepthError", 

168 "InterpolationMissingOptionError", 

169 "InterpolationSyntaxError", 

170 "ParsingError", 

171 "MissingSectionHeaderError", 

172 "MultilineContinuationError", 

173 "UnnamedSectionDisabledError", 

174 "ConfigParser", 

175 "RawConfigParser", 

176 "Interpolation", 

177 "BasicInterpolation", 

178 "ExtendedInterpolation", 

179 "SectionProxy", 

180 "ConverterMapping", 

181 "DEFAULTSECT", 

182 "MAX_INTERPOLATION_DEPTH", 

183 "UNNAMED_SECTION", 

184) 

185 

186_default_dict = dict 

187DEFAULTSECT = "DEFAULT" 

188 

189MAX_INTERPOLATION_DEPTH = 10 

190 

191 

192# exception classes 

193class Error(Exception): 

194 """Base class for ConfigParser exceptions.""" 

195 

196 def __init__(self, msg=''): 

197 self.message = msg 

198 Exception.__init__(self, msg) 

199 

200 def __repr__(self): 

201 return self.message 

202 

203 __str__ = __repr__ 

204 

205 

206class NoSectionError(Error): 

207 """Raised when no section matches a requested option.""" 

208 

209 def __init__(self, section): 

210 Error.__init__(self, 'No section: %r' % (section,)) 

211 self.section = section 

212 self.args = (section,) 

213 

214 

215class DuplicateSectionError(Error): 

216 """Raised when a section is repeated in an input source. 

217 

218 Possible repetitions that raise this exception are: multiple creation 

219 using the API or in strict parsers when a section is found more than once 

220 in a single input file, string or dictionary. 

221 """ 

222 

223 def __init__(self, section, source=None, lineno=None): 

224 msg = [repr(section), " already exists"] 

225 if source is not None: 

226 message = ["While reading from ", repr(source)] 

227 if lineno is not None: 

228 message.append(" [line {0:2d}]".format(lineno)) 

229 message.append(": section ") 

230 message.extend(msg) 

231 msg = message 

232 else: 

233 msg.insert(0, "Section ") 

234 Error.__init__(self, "".join(msg)) 

235 self.section = section 

236 self.source = source 

237 self.lineno = lineno 

238 self.args = (section, source, lineno) 

239 

240 

241class DuplicateOptionError(Error): 

242 """Raised by strict parsers when an option is repeated in an input source. 

243 

244 Current implementation raises this exception only when an option is found 

245 more than once in a single file, string or dictionary. 

246 """ 

247 

248 def __init__(self, section, option, source=None, lineno=None): 

249 msg = [repr(option), " in section ", repr(section), " already exists"] 

250 if source is not None: 

251 message = ["While reading from ", repr(source)] 

252 if lineno is not None: 

253 message.append(" [line {0:2d}]".format(lineno)) 

254 message.append(": option ") 

255 message.extend(msg) 

256 msg = message 

257 else: 

258 msg.insert(0, "Option ") 

259 Error.__init__(self, "".join(msg)) 

260 self.section = section 

261 self.option = option 

262 self.source = source 

263 self.lineno = lineno 

264 self.args = (section, option, source, lineno) 

265 

266 

267class NoOptionError(Error): 

268 """A requested option was not found.""" 

269 

270 def __init__(self, option, section): 

271 Error.__init__(self, "No option %r in section: %r" % (option, section)) 

272 self.option = option 

273 self.section = section 

274 self.args = (option, section) 

275 

276 

277class InterpolationError(Error): 

278 """Base class for interpolation-related exceptions.""" 

279 

280 def __init__(self, option, section, msg): 

281 Error.__init__(self, msg) 

282 self.option = option 

283 self.section = section 

284 self.args = (option, section, msg) 

285 

286 

287class InterpolationMissingOptionError(InterpolationError): 

288 """A string substitution required a setting which was not available.""" 

289 

290 def __init__(self, option, section, rawval, reference): 

291 msg = ( 

292 "Bad value substitution: option {!r} in section {!r} contains " 

293 "an interpolation key {!r} which is not a valid option name. " 

294 "Raw value: {!r}".format(option, section, reference, rawval) 

295 ) 

296 InterpolationError.__init__(self, option, section, msg) 

297 self.reference = reference 

298 self.args = (option, section, rawval, reference) 

299 

300 

301class InterpolationSyntaxError(InterpolationError): 

302 """Raised when the source text contains invalid syntax. 

303 

304 Current implementation raises this exception when the source text into 

305 which substitutions are made does not conform to the required syntax. 

306 """ 

307 

308 

309class InterpolationDepthError(InterpolationError): 

310 """Raised when substitutions are nested too deeply.""" 

311 

312 def __init__(self, option, section, rawval): 

313 msg = ( 

314 "Recursion limit exceeded in value substitution: option {!r} " 

315 "in section {!r} contains an interpolation key which " 

316 "cannot be substituted in {} steps. Raw value: {!r}" 

317 "".format(option, section, MAX_INTERPOLATION_DEPTH, rawval) 

318 ) 

319 InterpolationError.__init__(self, option, section, msg) 

320 self.args = (option, section, rawval) 

321 

322 

323class ParsingError(Error): 

324 """Raised when a configuration file does not follow legal syntax.""" 

325 

326 def __init__(self, source, *args): 

327 super().__init__(f'Source contains parsing errors: {source!r}') 

328 self.source = source 

329 self.errors = [] 

330 self.args = (source,) 

331 if args: 

332 self.append(*args) 

333 

334 def append(self, lineno, line): 

335 self.errors.append((lineno, line)) 

336 self.message += '\n\t[line %2d]: %s' % (lineno, repr(line)) 

337 

338 def combine(self, others): 

339 for other in others: 

340 for error in other.errors: 

341 self.append(*error) 

342 return self 

343 

344 @staticmethod 

345 def _raise_all(exceptions: Iterable['ParsingError']): 

346 """ 

347 Combine any number of ParsingErrors into one and raise it. 

348 """ 

349 exceptions = iter(exceptions) 

350 with contextlib.suppress(StopIteration): 

351 raise next(exceptions).combine(exceptions) 

352 

353 

354class MissingSectionHeaderError(ParsingError): 

355 """Raised when a key-value pair is found before any section header.""" 

356 

357 def __init__(self, filename, lineno, line): 

358 Error.__init__( 

359 self, 

360 'File contains no section headers.\nfile: %r, line: %d\n%r' 

361 % (filename, lineno, line), 

362 ) 

363 self.source = filename 

364 self.lineno = lineno 

365 self.line = line 

366 self.args = (filename, lineno, line) 

367 

368 

369class MultilineContinuationError(ParsingError): 

370 """Raised when a key without value is followed by continuation line""" 

371 

372 def __init__(self, filename, lineno, line): 

373 Error.__init__( 

374 self, 

375 "Key without value continued with an indented line.\n" 

376 "file: %r, line: %d\n%r" % (filename, lineno, line), 

377 ) 

378 self.source = filename 

379 self.lineno = lineno 

380 self.line = line 

381 self.args = (filename, lineno, line) 

382 

383 

384class UnnamedSectionDisabledError(Error): 

385 """Raised when an attempt to use UNNAMED_SECTION is made with the 

386 feature disabled.""" 

387 

388 def __init__(self): 

389 Error.__init__(self, "Support for UNNAMED_SECTION is disabled.") 

390 

391 

392class _UnnamedSection: 

393 def __repr__(self): 

394 return "<UNNAMED_SECTION>" 

395 

396 

397UNNAMED_SECTION = _UnnamedSection() 

398 

399 

400# Used in parser getters to indicate the default behaviour when a specific 

401# option is not found it to raise an exception. Created to enable `None` as 

402# a valid fallback value. 

403_UNSET = object() 

404 

405 

406class Interpolation: 

407 """Dummy interpolation that passes the value through with no changes.""" 

408 

409 def before_get(self, parser, section, option, value, defaults): 

410 return value 

411 

412 def before_set(self, parser, section, option, value): 

413 return value 

414 

415 def before_read(self, parser, section, option, value): 

416 return value 

417 

418 def before_write(self, parser, section, option, value): 

419 return value 

420 

421 

422class BasicInterpolation(Interpolation): 

423 """Interpolation as implemented in the classic ConfigParser. 

424 

425 The option values can contain format strings which refer to other values in 

426 the same section, or values in the special default section. 

427 

428 For example: 

429 

430 something: %(dir)s/whatever 

431 

432 would resolve the "%(dir)s" to the value of dir. All reference 

433 expansions are done late, on demand. If a user needs to use a bare % in 

434 a configuration file, she can escape it by writing %%. Other % usage 

435 is considered a user error and raises `InterpolationSyntaxError`.""" 

436 

437 _KEYCRE = re.compile(r"%\(([^)]+)\)s") 

438 

439 def before_get(self, parser, section, option, value, defaults): 

440 L = [] 

441 self._interpolate_some(parser, option, L, value, section, defaults, 1) 

442 return ''.join(L) 

443 

444 def before_set(self, parser, section, option, value): 

445 tmp_value = value.replace('%%', '') # escaped percent signs 

446 tmp_value = self._KEYCRE.sub('', tmp_value) # valid syntax 

447 if '%' in tmp_value: 

448 raise ValueError( 

449 "invalid interpolation syntax in %r at " 

450 "position %d" % (value, tmp_value.find('%')) 

451 ) 

452 return value 

453 

454 def _interpolate_some( # noqa: C901 

455 self, parser, option, accum, rest, section, map, depth 

456 ): 

457 rawval = parser.get(section, option, raw=True, fallback=rest) 

458 if depth > MAX_INTERPOLATION_DEPTH: 

459 raise InterpolationDepthError(option, section, rawval) 

460 while rest: 

461 p = rest.find("%") 

462 if p < 0: 

463 accum.append(rest) 

464 return 

465 if p > 0: 

466 accum.append(rest[:p]) 

467 rest = rest[p:] 

468 # p is no longer used 

469 c = rest[1:2] 

470 if c == "%": 

471 accum.append("%") 

472 rest = rest[2:] 

473 elif c == "(": 

474 m = self._KEYCRE.match(rest) 

475 if m is None: 

476 raise InterpolationSyntaxError( 

477 option, 

478 section, 

479 "bad interpolation variable reference %r" % rest, 

480 ) 

481 var = parser.optionxform(m.group(1)) 

482 rest = rest[m.end() :] 

483 try: 

484 v = map[var] 

485 except KeyError: 

486 raise InterpolationMissingOptionError( 

487 option, section, rawval, var 

488 ) from None 

489 if "%" in v: 

490 self._interpolate_some( 

491 parser, option, accum, v, section, map, depth + 1 

492 ) 

493 else: 

494 accum.append(v) 

495 else: 

496 raise InterpolationSyntaxError( 

497 option, 

498 section, 

499 "'%%' must be followed by '%%' or '(', " "found: %r" % (rest,), 

500 ) 

501 

502 

503class ExtendedInterpolation(Interpolation): 

504 """Advanced variant of interpolation, supports the syntax used by 

505 `zc.buildout`. Enables interpolation between sections.""" 

506 

507 _KEYCRE = re.compile(r"\$\{([^}]+)\}") 

508 

509 def before_get(self, parser, section, option, value, defaults): 

510 L = [] 

511 self._interpolate_some(parser, option, L, value, section, defaults, 1) 

512 return ''.join(L) 

513 

514 def before_set(self, parser, section, option, value): 

515 tmp_value = value.replace('$$', '') # escaped dollar signs 

516 tmp_value = self._KEYCRE.sub('', tmp_value) # valid syntax 

517 if '$' in tmp_value: 

518 raise ValueError( 

519 "invalid interpolation syntax in %r at " 

520 "position %d" % (value, tmp_value.find('$')) 

521 ) 

522 return value 

523 

524 def _interpolate_some( # noqa: C901 

525 self, parser, option, accum, rest, section, map, depth 

526 ): 

527 rawval = parser.get(section, option, raw=True, fallback=rest) 

528 if depth > MAX_INTERPOLATION_DEPTH: 

529 raise InterpolationDepthError(option, section, rawval) 

530 while rest: 

531 p = rest.find("$") 

532 if p < 0: 

533 accum.append(rest) 

534 return 

535 if p > 0: 

536 accum.append(rest[:p]) 

537 rest = rest[p:] 

538 # p is no longer used 

539 c = rest[1:2] 

540 if c == "$": 

541 accum.append("$") 

542 rest = rest[2:] 

543 elif c == "{": 

544 m = self._KEYCRE.match(rest) 

545 if m is None: 

546 raise InterpolationSyntaxError( 

547 option, 

548 section, 

549 "bad interpolation variable reference %r" % rest, 

550 ) 

551 path = m.group(1).split(':') 

552 rest = rest[m.end() :] 

553 sect = section 

554 opt = option 

555 try: 

556 if len(path) == 1: 

557 opt = parser.optionxform(path[0]) 

558 v = map[opt] 

559 elif len(path) == 2: 

560 sect = path[0] 

561 opt = parser.optionxform(path[1]) 

562 v = parser.get(sect, opt, raw=True) 

563 else: 

564 raise InterpolationSyntaxError( 

565 option, section, "More than one ':' found: %r" % (rest,) 

566 ) 

567 except (KeyError, NoSectionError, NoOptionError): 

568 raise InterpolationMissingOptionError( 

569 option, section, rawval, ":".join(path) 

570 ) from None 

571 if "$" in v: 

572 self._interpolate_some( 

573 parser, 

574 opt, 

575 accum, 

576 v, 

577 sect, 

578 dict(parser.items(sect, raw=True)), 

579 depth + 1, 

580 ) 

581 else: 

582 accum.append(v) 

583 else: 

584 raise InterpolationSyntaxError( 

585 option, 

586 section, 

587 "'$' must be followed by '$' or '{', " "found: %r" % (rest,), 

588 ) 

589 

590 

591class _ReadState: 

592 elements_added: set[str] 

593 cursect: dict[str, str] | None = None 

594 sectname: str | None = None 

595 optname: str | None = None 

596 lineno: int = 0 

597 indent_level: int = 0 

598 errors: list[ParsingError] 

599 

600 def __init__(self): 

601 self.elements_added = set() 

602 self.errors = list() 

603 

604 

605class _Line(str): 

606 def __new__(cls, val, *args, **kwargs): 

607 return super().__new__(cls, val) 

608 

609 def __init__(self, val, prefixes): 

610 self.prefixes = prefixes 

611 

612 @functools.cached_property 

613 def clean(self): 

614 return self._strip_full() and self._strip_inline() 

615 

616 @property 

617 def has_comments(self): 

618 return self.strip() != self.clean 

619 

620 def _strip_inline(self): 

621 """ 

622 Search for the earliest prefix at the beginning of the line or following a space. 

623 """ 

624 matcher = re.compile( 

625 '|'.join(rf'(^|\s)({re.escape(prefix)})' for prefix in self.prefixes.inline) 

626 # match nothing if no prefixes 

627 or '(?!)' 

628 ) 

629 match = matcher.search(self) 

630 return self[: match.start() if match else None].strip() 

631 

632 def _strip_full(self): 

633 return '' if any(map(self.strip().startswith, self.prefixes.full)) else True 

634 

635 

636class RawConfigParser(MutableMapping): 

637 """ConfigParser that does not do interpolation.""" 

638 

639 # Regular expressions for parsing section headers and options 

640 _SECT_TMPL = r""" 

641 \[ # [ 

642 (?P<header>.+) # very permissive! 

643 \] # ] 

644 """ 

645 _OPT_TMPL = r""" 

646 (?P<option>.*?) # very permissive! 

647 \s*(?P<vi>{delim})\s* # any number of space/tab, 

648 # followed by any of the 

649 # allowed delimiters, 

650 # followed by any space/tab 

651 (?P<value>.*)$ # everything up to eol 

652 """ 

653 _OPT_NV_TMPL = r""" 

654 (?P<option>.*?) # very permissive! 

655 \s*(?: # any number of space/tab, 

656 (?P<vi>{delim})\s* # optionally followed by 

657 # any of the allowed 

658 # delimiters, followed by any 

659 # space/tab 

660 (?P<value>.*))?$ # everything up to eol 

661 """ 

662 # Interpolation algorithm to be used if the user does not specify another 

663 _DEFAULT_INTERPOLATION = Interpolation() 

664 # Compiled regular expression for matching sections 

665 SECTCRE = re.compile(_SECT_TMPL, re.VERBOSE) 

666 # Compiled regular expression for matching options with typical separators 

667 OPTCRE = re.compile(_OPT_TMPL.format(delim="=|:"), re.VERBOSE) 

668 # Compiled regular expression for matching options with optional values 

669 # delimited using typical separators 

670 OPTCRE_NV = re.compile(_OPT_NV_TMPL.format(delim="=|:"), re.VERBOSE) 

671 # Compiled regular expression for matching leading whitespace in a line 

672 NONSPACECRE = re.compile(r"\S") 

673 # Possible boolean values in the configuration. 

674 BOOLEAN_STATES = { 

675 '1': True, 

676 'yes': True, 

677 'true': True, 

678 'on': True, 

679 '0': False, 

680 'no': False, 

681 'false': False, 

682 'off': False, 

683 } 

684 

685 def __init__( 

686 self, 

687 defaults=None, 

688 dict_type=_default_dict, 

689 allow_no_value=False, 

690 *, 

691 delimiters=('=', ':'), 

692 comment_prefixes=('#', ';'), 

693 inline_comment_prefixes=None, 

694 strict=True, 

695 empty_lines_in_values=True, 

696 default_section=DEFAULTSECT, 

697 interpolation=_UNSET, 

698 converters=_UNSET, 

699 allow_unnamed_section=False, 

700 ): 

701 self._dict = dict_type 

702 self._sections = self._dict() 

703 self._defaults = self._dict() 

704 self._converters = ConverterMapping(self) 

705 self._proxies = self._dict() 

706 self._proxies[default_section] = SectionProxy(self, default_section) 

707 self._delimiters = tuple(delimiters) 

708 if delimiters == ('=', ':'): 

709 self._optcre = self.OPTCRE_NV if allow_no_value else self.OPTCRE 

710 else: 

711 d = "|".join(re.escape(d) for d in delimiters) 

712 if allow_no_value: 

713 self._optcre = re.compile(self._OPT_NV_TMPL.format(delim=d), re.VERBOSE) 

714 else: 

715 self._optcre = re.compile(self._OPT_TMPL.format(delim=d), re.VERBOSE) 

716 self._prefixes = types.SimpleNamespace( 

717 full=tuple(comment_prefixes or ()), 

718 inline=tuple(inline_comment_prefixes or ()), 

719 ) 

720 self._strict = strict 

721 self._allow_no_value = allow_no_value 

722 self._empty_lines_in_values = empty_lines_in_values 

723 self.default_section = default_section 

724 self._interpolation = interpolation 

725 if self._interpolation is _UNSET: 

726 self._interpolation = self._DEFAULT_INTERPOLATION 

727 if self._interpolation is None: 

728 self._interpolation = Interpolation() 

729 if not isinstance(self._interpolation, Interpolation): 

730 raise TypeError( 

731 f"interpolation= must be None or an instance of Interpolation;" 

732 f" got an object of type {type(self._interpolation)}" 

733 ) 

734 if converters is not _UNSET: 

735 self._converters.update(converters) 

736 if defaults: 

737 self._read_defaults(defaults) 

738 self._allow_unnamed_section = allow_unnamed_section 

739 

740 def defaults(self): 

741 return self._defaults 

742 

743 def sections(self): 

744 """Return a list of section names, excluding [DEFAULT]""" 

745 # self._sections will never have [DEFAULT] in it 

746 return list(self._sections.keys()) 

747 

748 def add_section(self, section): 

749 """Create a new section in the configuration. 

750 

751 Raise DuplicateSectionError if a section by the specified name 

752 already exists. Raise ValueError if name is DEFAULT. 

753 """ 

754 if section == self.default_section: 

755 raise ValueError('Invalid section name: %r' % section) 

756 

757 if section is UNNAMED_SECTION: 

758 if not self._allow_unnamed_section: 

759 raise UnnamedSectionDisabledError 

760 

761 if section in self._sections: 

762 raise DuplicateSectionError(section) 

763 self._sections[section] = self._dict() 

764 self._proxies[section] = SectionProxy(self, section) 

765 

766 def has_section(self, section): 

767 """Indicate whether the named section is present in the configuration. 

768 

769 The DEFAULT section is not acknowledged. 

770 """ 

771 return section in self._sections 

772 

773 def options(self, section): 

774 """Return a list of option names for the given section name.""" 

775 try: 

776 opts = self._sections[section].copy() 

777 except KeyError: 

778 raise NoSectionError(section) from None 

779 opts.update(self._defaults) 

780 return list(opts.keys()) 

781 

782 def read(self, filenames, encoding=None): 

783 """Read and parse a filename or an iterable of filenames. 

784 

785 Files that cannot be opened are silently ignored; this is 

786 designed so that you can specify an iterable of potential 

787 configuration file locations (e.g. current directory, user's 

788 home directory, systemwide directory), and all existing 

789 configuration files in the iterable will be read. A single 

790 filename may also be given. 

791 

792 Return list of successfully read files. 

793 """ 

794 if isinstance(filenames, (str, bytes, os.PathLike)): 

795 filenames = [filenames] 

796 encoding = io.text_encoding(encoding) 

797 read_ok = [] 

798 for filename in filenames: 

799 try: 

800 with open(filename, encoding=encoding) as fp: 

801 self._read(fp, filename) 

802 except OSError: 

803 continue 

804 if isinstance(filename, os.PathLike): 

805 filename = os.fspath(filename) 

806 read_ok.append(filename) 

807 return read_ok 

808 

809 def read_file(self, f, source=None): 

810 """Like read() but the argument must be a file-like object. 

811 

812 The `f` argument must be iterable, returning one line at a time. 

813 Optional second argument is the `source` specifying the name of the 

814 file being read. If not given, it is taken from f.name. If `f` has no 

815 `name` attribute, `<???>` is used. 

816 """ 

817 if source is None: 

818 try: 

819 source = f.name 

820 except AttributeError: 

821 source = '<???>' 

822 self._read(f, source) 

823 

824 def read_string(self, string, source='<string>'): 

825 """Read configuration from a given string.""" 

826 sfile = io.StringIO(string) 

827 self.read_file(sfile, source) 

828 

829 def read_dict(self, dictionary, source='<dict>'): 

830 """Read configuration from a dictionary. 

831 

832 Keys are section names, values are dictionaries with keys and values 

833 that should be present in the section. If the used dictionary type 

834 preserves order, sections and their keys will be added in order. 

835 

836 All types held in the dictionary are converted to strings during 

837 reading, including section names, option names and keys. 

838 

839 Optional second argument is the `source` specifying the name of the 

840 dictionary being read. 

841 """ 

842 elements_added = set() 

843 for section, keys in dictionary.items(): 

844 section = str(section) 

845 try: 

846 self.add_section(section) 

847 except (DuplicateSectionError, ValueError): 

848 if self._strict and section in elements_added: 

849 raise 

850 elements_added.add(section) 

851 for key, value in keys.items(): 

852 key = self.optionxform(str(key)) 

853 if value is not None: 

854 value = str(value) 

855 if self._strict and (section, key) in elements_added: 

856 raise DuplicateOptionError(section, key, source) 

857 elements_added.add((section, key)) 

858 self.set(section, key, value) 

859 

860 def get(self, section, option, *, raw=False, vars=None, fallback=_UNSET): 

861 """Get an option value for a given section. 

862 

863 If `vars` is provided, it must be a dictionary. The option is looked up 

864 in `vars` (if provided), `section`, and in `DEFAULTSECT` in that order. 

865 If the key is not found and `fallback` is provided, it is used as 

866 a fallback value. `None` can be provided as a `fallback` value. 

867 

868 If interpolation is enabled and the optional argument `raw` is False, 

869 all interpolations are expanded in the return values. 

870 

871 Arguments `raw`, `vars`, and `fallback` are keyword only. 

872 

873 The section DEFAULT is special. 

874 """ 

875 try: 

876 d = self._unify_values(section, vars) 

877 except NoSectionError: 

878 if fallback is _UNSET: 

879 raise 

880 else: 

881 return fallback 

882 option = self.optionxform(option) 

883 try: 

884 value = d[option] 

885 except KeyError: 

886 if fallback is _UNSET: 

887 raise NoOptionError(option, section) 

888 else: 

889 return fallback 

890 

891 if raw or value is None: 

892 return value 

893 else: 

894 return self._interpolation.before_get(self, section, option, value, d) 

895 

896 def _get(self, section, conv, option, **kwargs): 

897 return conv(self.get(section, option, **kwargs)) 

898 

899 def _get_conv( 

900 self, section, option, conv, *, raw=False, vars=None, fallback=_UNSET, **kwargs 

901 ): 

902 try: 

903 return self._get(section, conv, option, raw=raw, vars=vars, **kwargs) 

904 except (NoSectionError, NoOptionError): 

905 if fallback is _UNSET: 

906 raise 

907 return fallback 

908 

909 # getint, getfloat and getboolean provided directly for backwards compat 

910 def getint( 

911 self, section, option, *, raw=False, vars=None, fallback=_UNSET, **kwargs 

912 ): 

913 return self._get_conv( 

914 section, option, int, raw=raw, vars=vars, fallback=fallback, **kwargs 

915 ) 

916 

917 def getfloat( 

918 self, section, option, *, raw=False, vars=None, fallback=_UNSET, **kwargs 

919 ): 

920 return self._get_conv( 

921 section, option, float, raw=raw, vars=vars, fallback=fallback, **kwargs 

922 ) 

923 

924 def getboolean( 

925 self, section, option, *, raw=False, vars=None, fallback=_UNSET, **kwargs 

926 ): 

927 return self._get_conv( 

928 section, 

929 option, 

930 self._convert_to_boolean, 

931 raw=raw, 

932 vars=vars, 

933 fallback=fallback, 

934 **kwargs, 

935 ) 

936 

937 def items(self, section=_UNSET, raw=False, vars=None): 

938 """Return a list of (name, value) tuples for each option in a section. 

939 

940 All % interpolations are expanded in the return values, based on the 

941 defaults passed into the constructor, unless the optional argument 

942 `raw` is true. Additional substitutions may be provided using the 

943 `vars` argument, which must be a dictionary whose contents overrides 

944 any pre-existing defaults. 

945 

946 The section DEFAULT is special. 

947 """ 

948 if section is _UNSET: 

949 return super(RawConfigParser, self).items() 

950 d = self._defaults.copy() 

951 try: 

952 d.update(self._sections[section]) 

953 except KeyError: 

954 if section != self.default_section: 

955 raise NoSectionError(section) 

956 orig_keys = list(d.keys()) 

957 # Update with the entry specific variables 

958 if vars: 

959 for key, value in vars.items(): 

960 d[self.optionxform(key)] = value 

961 

962 def value_getter_interp(option): 

963 return self._interpolation.before_get(self, section, option, d[option], d) 

964 

965 def value_getter_raw(option): 

966 return d[option] 

967 

968 value_getter = value_getter_raw if raw else value_getter_interp 

969 

970 return [(option, value_getter(option)) for option in orig_keys] 

971 

972 def popitem(self): 

973 """Remove a section from the parser and return it as 

974 a (section_name, section_proxy) tuple. If no section is present, raise 

975 KeyError. 

976 

977 The section DEFAULT is never returned because it cannot be removed. 

978 """ 

979 for key in self.sections(): 

980 value = self[key] 

981 del self[key] 

982 return key, value 

983 raise KeyError 

984 

985 def optionxform(self, optionstr): 

986 return optionstr.lower() 

987 

988 def has_option(self, section, option): 

989 """Check for the existence of a given option in a given section. 

990 If the specified `section` is None or an empty string, DEFAULT is 

991 assumed. If the specified `section` does not exist, returns False.""" 

992 if not section or section == self.default_section: 

993 option = self.optionxform(option) 

994 return option in self._defaults 

995 elif section not in self._sections: 

996 return False 

997 else: 

998 option = self.optionxform(option) 

999 return option in self._sections[section] or option in self._defaults 

1000 

1001 def set(self, section, option, value=None): 

1002 """Set an option.""" 

1003 if value: 

1004 value = self._interpolation.before_set(self, section, option, value) 

1005 if not section or section == self.default_section: 

1006 sectdict = self._defaults 

1007 else: 

1008 try: 

1009 sectdict = self._sections[section] 

1010 except KeyError: 

1011 raise NoSectionError(section) from None 

1012 sectdict[self.optionxform(option)] = value 

1013 

1014 def write(self, fp, space_around_delimiters=True): 

1015 """Write an .ini-format representation of the configuration state. 

1016 

1017 If `space_around_delimiters` is True (the default), delimiters 

1018 between keys and values are surrounded by spaces. 

1019 

1020 Please note that comments in the original configuration file are not 

1021 preserved when writing the configuration back. 

1022 """ 

1023 if space_around_delimiters: 

1024 d = " {} ".format(self._delimiters[0]) 

1025 else: 

1026 d = self._delimiters[0] 

1027 if self._defaults: 

1028 self._write_section(fp, self.default_section, self._defaults.items(), d) 

1029 if UNNAMED_SECTION in self._sections: 

1030 self._write_section( 

1031 fp, 

1032 UNNAMED_SECTION, 

1033 self._sections[UNNAMED_SECTION].items(), 

1034 d, 

1035 unnamed=True, 

1036 ) 

1037 

1038 for section in self._sections: 

1039 if section is UNNAMED_SECTION: 

1040 continue 

1041 self._write_section(fp, section, self._sections[section].items(), d) 

1042 

1043 def _write_section(self, fp, section_name, section_items, delimiter, unnamed=False): 

1044 """Write a single section to the specified 'fp'.""" 

1045 if not unnamed: 

1046 fp.write("[{}]\n".format(section_name)) 

1047 for key, value in section_items: 

1048 value = self._interpolation.before_write(self, section_name, key, value) 

1049 if value is not None or not self._allow_no_value: 

1050 value = delimiter + str(value).replace('\n', '\n\t') 

1051 else: 

1052 value = "" 

1053 fp.write("{}{}\n".format(key, value)) 

1054 fp.write("\n") 

1055 

1056 def remove_option(self, section, option): 

1057 """Remove an option.""" 

1058 if not section or section == self.default_section: 

1059 sectdict = self._defaults 

1060 else: 

1061 try: 

1062 sectdict = self._sections[section] 

1063 except KeyError: 

1064 raise NoSectionError(section) from None 

1065 option = self.optionxform(option) 

1066 existed = option in sectdict 

1067 if existed: 

1068 del sectdict[option] 

1069 return existed 

1070 

1071 def remove_section(self, section): 

1072 """Remove a file section.""" 

1073 existed = section in self._sections 

1074 if existed: 

1075 del self._sections[section] 

1076 del self._proxies[section] 

1077 return existed 

1078 

1079 def __getitem__(self, key): 

1080 if key != self.default_section and not self.has_section(key): 

1081 raise KeyError(key) 

1082 return self._proxies[key] 

1083 

1084 def __setitem__(self, key, value): 

1085 # To conform with the mapping protocol, overwrites existing values in 

1086 # the section. 

1087 if key in self and self[key] is value: 

1088 return 

1089 # XXX this is not atomic if read_dict fails at any point. Then again, 

1090 # no update method in configparser is atomic in this implementation. 

1091 if key == self.default_section: 

1092 self._defaults.clear() 

1093 elif key in self._sections: 

1094 self._sections[key].clear() 

1095 self.read_dict({key: value}) 

1096 

1097 def __delitem__(self, key): 

1098 if key == self.default_section: 

1099 raise ValueError("Cannot remove the default section.") 

1100 if not self.has_section(key): 

1101 raise KeyError(key) 

1102 self.remove_section(key) 

1103 

1104 def __contains__(self, key): 

1105 return key == self.default_section or self.has_section(key) 

1106 

1107 def __len__(self): 

1108 return len(self._sections) + 1 # the default section 

1109 

1110 def __iter__(self): 

1111 # XXX does it break when underlying container state changed? 

1112 return itertools.chain((self.default_section,), self._sections.keys()) 

1113 

1114 def _read(self, fp, fpname): # noqa: C901 

1115 """Parse a sectioned configuration file. 

1116 

1117 Each section in a configuration file contains a header, indicated by 

1118 a name in square brackets (`[]`), plus key/value options, indicated by 

1119 `name` and `value` delimited with a specific substring (`=` or `:` by 

1120 default). 

1121 

1122 Values can span multiple lines, as long as they are indented deeper 

1123 than the first line of the value. Depending on the parser's mode, blank 

1124 lines may be treated as parts of multiline values or ignored. 

1125 

1126 Configuration files may include comments, prefixed by specific 

1127 characters (`#` and `;` by default). Comments may appear on their own 

1128 in an otherwise empty line or may be entered in lines holding values or 

1129 section names. Please note that comments get stripped off when reading 

1130 configuration files. 

1131 """ 

1132 

1133 try: 

1134 ParsingError._raise_all(self._read_inner(fp, fpname)) 

1135 finally: 

1136 self._join_multiline_values() 

1137 

1138 def _read_inner(self, fp, fpname): 

1139 st = _ReadState() 

1140 

1141 Line = functools.partial(_Line, prefixes=self._prefixes) 

1142 for st.lineno, line in enumerate(map(Line, fp), start=1): 

1143 if not line.clean: 

1144 if self._empty_lines_in_values: 

1145 # add empty line to the value, but only if there was no 

1146 # comment on the line 

1147 if ( 

1148 not line.has_comments 

1149 and st.cursect is not None 

1150 and st.optname 

1151 and st.cursect[st.optname] is not None 

1152 ): 

1153 st.cursect[st.optname].append('') # newlines added at join 

1154 else: 

1155 # empty line marks end of value 

1156 st.indent_level = sys.maxsize 

1157 continue 

1158 

1159 first_nonspace = self.NONSPACECRE.search(line) 

1160 st.cur_indent_level = first_nonspace.start() if first_nonspace else 0 

1161 

1162 if self._handle_continuation_line(st, line, fpname): 

1163 continue 

1164 

1165 self._handle_rest(st, line, fpname) 

1166 

1167 return st.errors 

1168 

1169 def _handle_continuation_line(self, st, line, fpname): 

1170 # continuation line? 

1171 is_continue = ( 

1172 st.cursect is not None 

1173 and st.optname 

1174 and st.cur_indent_level > st.indent_level 

1175 ) 

1176 if is_continue: 

1177 if st.cursect[st.optname] is None: 

1178 raise MultilineContinuationError(fpname, st.lineno, line) 

1179 st.cursect[st.optname].append(line.clean) 

1180 return is_continue 

1181 

1182 def _handle_rest(self, st, line, fpname): 

1183 # a section header or option header? 

1184 if self._allow_unnamed_section and st.cursect is None: 

1185 st.sectname = UNNAMED_SECTION 

1186 st.cursect = self._dict() 

1187 self._sections[st.sectname] = st.cursect 

1188 self._proxies[st.sectname] = SectionProxy(self, st.sectname) 

1189 st.elements_added.add(st.sectname) 

1190 

1191 st.indent_level = st.cur_indent_level 

1192 # is it a section header? 

1193 mo = self.SECTCRE.match(line.clean) 

1194 

1195 if not mo and st.cursect is None: 

1196 raise MissingSectionHeaderError(fpname, st.lineno, line) 

1197 

1198 self._handle_header(st, mo, fpname) if mo else self._handle_option( 

1199 st, line, fpname 

1200 ) 

1201 

1202 def _handle_header(self, st, mo, fpname): 

1203 st.sectname = mo.group('header') 

1204 if st.sectname in self._sections: 

1205 if self._strict and st.sectname in st.elements_added: 

1206 raise DuplicateSectionError(st.sectname, fpname, st.lineno) 

1207 st.cursect = self._sections[st.sectname] 

1208 st.elements_added.add(st.sectname) 

1209 elif st.sectname == self.default_section: 

1210 st.cursect = self._defaults 

1211 else: 

1212 st.cursect = self._dict() 

1213 self._sections[st.sectname] = st.cursect 

1214 self._proxies[st.sectname] = SectionProxy(self, st.sectname) 

1215 st.elements_added.add(st.sectname) 

1216 # So sections can't start with a continuation line 

1217 st.optname = None 

1218 

1219 def _handle_option(self, st, line, fpname): 

1220 # an option line? 

1221 st.indent_level = st.cur_indent_level 

1222 

1223 mo = self._optcre.match(line.clean) 

1224 if not mo: 

1225 # a non-fatal parsing error occurred. set up the 

1226 # exception but keep going. the exception will be 

1227 # raised at the end of the file and will contain a 

1228 # list of all bogus lines 

1229 st.errors.append(ParsingError(fpname, st.lineno, line)) 

1230 return 

1231 

1232 st.optname, vi, optval = mo.group('option', 'vi', 'value') 

1233 if not st.optname: 

1234 st.errors.append(ParsingError(fpname, st.lineno, line)) 

1235 st.optname = self.optionxform(st.optname.rstrip()) 

1236 if self._strict and (st.sectname, st.optname) in st.elements_added: 

1237 raise DuplicateOptionError(st.sectname, st.optname, fpname, st.lineno) 

1238 st.elements_added.add((st.sectname, st.optname)) 

1239 # This check is fine because the OPTCRE cannot 

1240 # match if it would set optval to None 

1241 if optval is not None: 

1242 optval = optval.strip() 

1243 st.cursect[st.optname] = [optval] 

1244 else: 

1245 # valueless option handling 

1246 st.cursect[st.optname] = None 

1247 

1248 def _join_multiline_values(self): 

1249 defaults = self.default_section, self._defaults 

1250 all_sections = itertools.chain((defaults,), self._sections.items()) 

1251 for section, options in all_sections: 

1252 for name, val in options.items(): 

1253 if isinstance(val, list): 

1254 val = '\n'.join(val).rstrip() 

1255 options[name] = self._interpolation.before_read( 

1256 self, section, name, val 

1257 ) 

1258 

1259 def _read_defaults(self, defaults): 

1260 """Read the defaults passed in the initializer. 

1261 Note: values can be non-string.""" 

1262 for key, value in defaults.items(): 

1263 self._defaults[self.optionxform(key)] = value 

1264 

1265 def _unify_values(self, section, vars): 

1266 """Create a sequence of lookups with 'vars' taking priority over 

1267 the 'section' which takes priority over the DEFAULTSECT. 

1268 

1269 """ 

1270 sectiondict = {} 

1271 try: 

1272 sectiondict = self._sections[section] 

1273 except KeyError: 

1274 if section != self.default_section: 

1275 raise NoSectionError(section) 

1276 # Update with the entry specific variables 

1277 vardict = {} 

1278 if vars: 

1279 for key, value in vars.items(): 

1280 if value is not None: 

1281 value = str(value) 

1282 vardict[self.optionxform(key)] = value 

1283 return _ChainMap(vardict, sectiondict, self._defaults) 

1284 

1285 def _convert_to_boolean(self, value): 

1286 """Return a boolean value translating from other types if necessary.""" 

1287 if value.lower() not in self.BOOLEAN_STATES: 

1288 raise ValueError('Not a boolean: %s' % value) 

1289 return self.BOOLEAN_STATES[value.lower()] 

1290 

1291 def _validate_value_types(self, *, section="", option="", value=""): 

1292 """Raises a TypeError for illegal non-string values. 

1293 

1294 Legal non-string values are UNNAMED_SECTION and falsey values if 

1295 they are allowed. 

1296 

1297 For compatibility reasons this method is not used in classic set() 

1298 for RawConfigParsers. It is invoked in every case for mapping protocol 

1299 access and in ConfigParser.set(). 

1300 """ 

1301 if section is UNNAMED_SECTION: 

1302 if not self._allow_unnamed_section: 

1303 raise UnnamedSectionDisabledError 

1304 elif not isinstance(section, str): 

1305 raise TypeError("section names must be strings or UNNAMED_SECTION") 

1306 if not isinstance(option, str): 

1307 raise TypeError("option keys must be strings") 

1308 if not self._allow_no_value or value: 

1309 if not isinstance(value, str): 

1310 raise TypeError("option values must be strings") 

1311 

1312 @property 

1313 def converters(self): 

1314 return self._converters 

1315 

1316 

1317class ConfigParser(RawConfigParser): 

1318 """ConfigParser implementing interpolation.""" 

1319 

1320 _DEFAULT_INTERPOLATION = BasicInterpolation() 

1321 

1322 def set(self, section, option, value=None): 

1323 """Set an option. Extends RawConfigParser.set by validating type and 

1324 interpolation syntax on the value.""" 

1325 self._validate_value_types(option=option, value=value) 

1326 super().set(section, option, value) 

1327 

1328 def add_section(self, section): 

1329 """Create a new section in the configuration. Extends 

1330 RawConfigParser.add_section by validating if the section name is 

1331 a string.""" 

1332 self._validate_value_types(section=section) 

1333 super().add_section(section) 

1334 

1335 def _read_defaults(self, defaults): 

1336 """Reads the defaults passed in the initializer, implicitly converting 

1337 values to strings like the rest of the API. 

1338 

1339 Does not perform interpolation for backwards compatibility. 

1340 """ 

1341 try: 

1342 hold_interpolation = self._interpolation 

1343 self._interpolation = Interpolation() 

1344 self.read_dict({self.default_section: defaults}) 

1345 finally: 

1346 self._interpolation = hold_interpolation 

1347 

1348 

1349class SectionProxy(MutableMapping): 

1350 """A proxy for a single section from a parser.""" 

1351 

1352 def __init__(self, parser, name): 

1353 """Creates a view on a section of the specified `name` in `parser`.""" 

1354 self._parser = parser 

1355 self._name = name 

1356 for conv in parser.converters: 

1357 key = 'get' + conv 

1358 getter = functools.partial(self.get, _impl=getattr(parser, key)) 

1359 setattr(self, key, getter) 

1360 

1361 def __repr__(self): 

1362 return '<Section: {}>'.format(self._name) 

1363 

1364 def __getitem__(self, key): 

1365 if not self._parser.has_option(self._name, key): 

1366 raise KeyError(key) 

1367 return self._parser.get(self._name, key) 

1368 

1369 def __setitem__(self, key, value): 

1370 self._parser._validate_value_types(option=key, value=value) 

1371 return self._parser.set(self._name, key, value) 

1372 

1373 def __delitem__(self, key): 

1374 if not ( 

1375 self._parser.has_option(self._name, key) 

1376 and self._parser.remove_option(self._name, key) 

1377 ): 

1378 raise KeyError(key) 

1379 

1380 def __contains__(self, key): 

1381 return self._parser.has_option(self._name, key) 

1382 

1383 def __len__(self): 

1384 return len(self._options()) 

1385 

1386 def __iter__(self): 

1387 return self._options().__iter__() 

1388 

1389 def _options(self): 

1390 if self._name != self._parser.default_section: 

1391 return self._parser.options(self._name) 

1392 else: 

1393 return self._parser.defaults() 

1394 

1395 @property 

1396 def parser(self): 

1397 # The parser object of the proxy is read-only. 

1398 return self._parser 

1399 

1400 @property 

1401 def name(self): 

1402 # The name of the section on a proxy is read-only. 

1403 return self._name 

1404 

1405 def get(self, option, fallback=None, *, raw=False, vars=None, _impl=None, **kwargs): 

1406 """Get an option value. 

1407 

1408 Unless `fallback` is provided, `None` will be returned if the option 

1409 is not found. 

1410 

1411 """ 

1412 # If `_impl` is provided, it should be a getter method on the parser 

1413 # object that provides the desired type conversion. 

1414 if not _impl: 

1415 _impl = self._parser.get 

1416 return _impl( 

1417 self._name, option, raw=raw, vars=vars, fallback=fallback, **kwargs 

1418 ) 

1419 

1420 

1421class ConverterMapping(MutableMapping): 

1422 """Enables reuse of get*() methods between the parser and section proxies. 

1423 

1424 If a parser class implements a getter directly, the value for the given 

1425 key will be ``None``. The presence of the converter name here enables 

1426 section proxies to find and use the implementation on the parser class. 

1427 """ 

1428 

1429 GETTERCRE = re.compile(r"^get(?P<name>.+)$") 

1430 

1431 def __init__(self, parser): 

1432 self._parser = parser 

1433 self._data = {} 

1434 for getter in dir(self._parser): 

1435 m = self.GETTERCRE.match(getter) 

1436 if not m or not callable(getattr(self._parser, getter)): 

1437 continue 

1438 self._data[m.group('name')] = None # See class docstring. 

1439 

1440 def __getitem__(self, key): 

1441 return self._data[key] 

1442 

1443 def __setitem__(self, key, value): 

1444 try: 

1445 k = 'get' + key 

1446 except TypeError: 

1447 raise ValueError( 

1448 'Incompatible key: {} (type: {})' ''.format(key, type(key)) 

1449 ) 

1450 if k == 'get': 

1451 raise ValueError('Incompatible key: cannot use "" as a name') 

1452 self._data[key] = value 

1453 func = functools.partial(self._parser._get_conv, conv=value) 

1454 func.converter = value 

1455 setattr(self._parser, k, func) 

1456 for proxy in self._parser.values(): 

1457 getter = functools.partial(proxy.get, _impl=func) 

1458 setattr(proxy, k, getter) 

1459 

1460 def __delitem__(self, key): 

1461 try: 

1462 k = 'get' + (key or None) 

1463 except TypeError: 

1464 raise KeyError(key) 

1465 del self._data[key] 

1466 for inst in itertools.chain((self._parser,), self._parser.values()): 

1467 try: 

1468 delattr(inst, k) 

1469 except AttributeError: 

1470 # don't raise since the entry was present in _data, silently 

1471 # clean up 

1472 continue 

1473 

1474 def __iter__(self): 

1475 return iter(self._data) 

1476 

1477 def __len__(self): 

1478 return len(self._data)