config.py 2.8KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. # coding: utf-8
  2. import typing
  3. import re
  4. import yaml
  5. from synergine2.exceptions import SynergineException
  6. DEFAULT_VALUE = '__DEFAULT_VALUE__'
  7. class Config(dict):
  8. def __init__(
  9. self,
  10. seq: typing.Union[dict, None]=None,
  11. **kwargs: typing.Any
  12. ) -> None:
  13. seq = seq or {}
  14. super().__init__(seq, **kwargs)
  15. """
  16. Regular expression used to find key access, example of matching
  17. strings:
  18. * foo[0]
  19. * bar.buz[1]
  20. Not working strings (see blsi.common.config.Config#get TODO):
  21. * bad[0][1]
  22. Literal translation of expression is:
  23. * Group "(.+)" Everything with minimum 1 char
  24. * Group "(\[([0-9])+\])" numeric number into brackets
  25. """
  26. self._index_re = re.compile(r'(.+)(\[([0-9])+\])')
  27. def resolve(
  28. self,
  29. k: str,
  30. d: object=DEFAULT_VALUE,
  31. ) -> typing.Union[None, str, float, int, bool, dict, list]:
  32. """
  33. Allow to get dict value with following expression:
  34. config.get('foo[0].bar.baz'), so '.' for dict keys, and [x] for
  35. list index.
  36. TODO BS 20170124: Actually don't work with multiple indexes "foo[0][0]"
  37. :param k: key
  38. :param d: default value
  39. :return:
  40. """
  41. if '.' in k:
  42. try:
  43. parts = k.split('.')
  44. value = self
  45. for part in parts:
  46. index_search = re.search(self._index_re, part)
  47. if index_search is not None:
  48. groups = index_search.groups()
  49. part = groups[0]
  50. index = int(groups[2])
  51. value = value.get(part) # type: ignore
  52. value = value[index]
  53. else:
  54. value = value.get(part, d) # type: ignore
  55. return value
  56. except IndexError:
  57. value = d # type: ignore
  58. except KeyError:
  59. value = d # type: ignore
  60. except AttributeError:
  61. value = d # type: ignore
  62. if value == DEFAULT_VALUE:
  63. raise SynergineException(
  64. 'No configuration found for "{}"'.format(k)
  65. )
  66. elif value == DEFAULT_VALUE:
  67. return None
  68. return value
  69. else:
  70. value = super().get(k, d)
  71. if value == DEFAULT_VALUE:
  72. raise SynergineException(
  73. 'No configuration found for "{}"'.format(k)
  74. )
  75. elif value == DEFAULT_VALUE:
  76. return None
  77. return value
  78. def load_yaml(self, yaml_file_path) -> None:
  79. with open(yaml_file_path, 'r') as yaml_file:
  80. self.update(yaml.load(yaml_file))