Enables reuse of get*() methods between the parser and section proxies. If a parser class implements a getter directly, the value for the given key will be ``None``. The presence of the converter name here enables section proxies to find and use the implementation on the parser class.
| 1357 | |
| 1358 | |
| 1359 | class ConverterMapping(MutableMapping): |
| 1360 | """Enables reuse of get*() methods between the parser and section proxies. |
| 1361 | |
| 1362 | If a parser class implements a getter directly, the value for the given |
| 1363 | key will be ``None``. The presence of the converter name here enables |
| 1364 | section proxies to find and use the implementation on the parser class. |
| 1365 | """ |
| 1366 | |
| 1367 | GETTERCRE = re.compile(r"^get(?P<name>.+)$") |
| 1368 | |
| 1369 | def __init__(self, parser): |
| 1370 | self._parser = parser |
| 1371 | self._data = {} |
| 1372 | for getter in dir(self._parser): |
| 1373 | m = self.GETTERCRE.match(getter) |
| 1374 | if not m or not callable(getattr(self._parser, getter)): |
| 1375 | continue |
| 1376 | self._data[m.group('name')] = None # See class docstring. |
| 1377 | |
| 1378 | def __getitem__(self, key): |
| 1379 | return self._data[key] |
| 1380 | |
| 1381 | def __setitem__(self, key, value): |
| 1382 | try: |
| 1383 | k = 'get' + key |
| 1384 | except TypeError: |
| 1385 | raise ValueError('Incompatible key: {} (type: {})' |
| 1386 | ''.format(key, type(key))) |
| 1387 | if k == 'get': |
| 1388 | raise ValueError('Incompatible key: cannot use "" as a name') |
| 1389 | self._data[key] = value |
| 1390 | func = functools.partial(self._parser._get_conv, conv=value) |
| 1391 | func.converter = value |
| 1392 | setattr(self._parser, k, func) |
| 1393 | for proxy in self._parser.values(): |
| 1394 | getter = functools.partial(proxy.get, _impl=func) |
| 1395 | setattr(proxy, k, getter) |
| 1396 | |
| 1397 | def __delitem__(self, key): |
| 1398 | try: |
| 1399 | k = 'get' + (key or None) |
| 1400 | except TypeError: |
| 1401 | raise KeyError(key) |
| 1402 | del self._data[key] |
| 1403 | for inst in itertools.chain((self._parser,), self._parser.values()): |
| 1404 | try: |
| 1405 | delattr(inst, k) |
| 1406 | except AttributeError: |
| 1407 | # don't raise since the entry was present in _data, silently |
| 1408 | # clean up |
| 1409 | continue |
| 1410 | |
| 1411 | def __iter__(self): |
| 1412 | return iter(self._data) |
| 1413 | |
| 1414 | def __len__(self): |
| 1415 | return len(self._data) |