ext_configobj.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. """
  2. The ConfigObj Extension provides configuration handling based on
  3. `configobj <http://www.voidspace.org.uk/python/configobj.html>`_. It is a
  4. drop-in replacement for the default config handler
  5. :class:`cement.ext.ext_configparser.ConfigParserConfigHandler`.
  6. One of the primary features of ConfigObj is that you can access the
  7. application configuration as a dictionary object.
  8. Requirements
  9. ------------
  10. * ConfigObj (``pip install configobj``)
  11. Configuration
  12. -------------
  13. This extension does not honor any application configuration settings.
  14. Usage
  15. -----
  16. .. code-block:: python
  17. from cement.core.foundation import CementApp
  18. class MyApp(CementApp):
  19. class Meta:
  20. label = 'myapp'
  21. extensions = ['configobj']
  22. config_handler = 'configobj'
  23. with MyApp() as app:
  24. app.run()
  25. # get a config setting
  26. app.config['myapp']['foo']
  27. # set a config setting
  28. app.config['myapp']['foo'] = 'bar2'
  29. # etc.
  30. """
  31. import os
  32. import sys
  33. from ..core import config, exc
  34. from ..utils.misc import minimal_logger
  35. from configobj import ConfigObj
  36. LOG = minimal_logger(__name__)
  37. class ConfigObjConfigHandler(config.CementConfigHandler, ConfigObj):
  38. """
  39. This class implements the :ref:`IConfig <cement.core.config>`
  40. interface, and sub-classes from `configobj.ConfigObj
  41. <http://www.voidspace.org.uk/python/configobj.html>`_,
  42. which is an external library and not included with Python. Please
  43. reference the ConfigObj documentation for full usage of the class.
  44. Arguments and keyword arguments are passed directly to ConfigObj
  45. on initialization.
  46. """
  47. class Meta:
  48. """Handler meta-data."""
  49. interface = config.IConfig
  50. label = 'configobj'
  51. def __init__(self, *args, **kw):
  52. super(ConfigObjConfigHandler, self).__init__(*args, **kw)
  53. self.app = None
  54. def _setup(self, app_obj):
  55. self.app = app_obj
  56. def get_sections(self):
  57. """
  58. Return a list of [section] that exist in the configuration.
  59. :returns: list
  60. """
  61. return self.sections
  62. def get_section_dict(self, section):
  63. """
  64. Return a dict representation of a section.
  65. :param section: The section of the configuration.
  66. I.e. ``[block_section]``
  67. :returns: dict
  68. """
  69. dict_obj = dict()
  70. for key in self.keys(section):
  71. dict_obj[key] = self.get(section, key)
  72. return dict_obj
  73. def _parse_file(self, file_path):
  74. """
  75. Parse a configuration file at `file_path` and store it.
  76. :param file_path: The file system path to the configuration file.
  77. :returns: boolean (True if file was read properly, False otherwise)
  78. """
  79. _c = ConfigObj(file_path)
  80. self.merge(_c.dict())
  81. # FIX ME: Should check that file was read properly, however if not it
  82. # will likely raise an exception anyhow.
  83. return True
  84. def keys(self, section):
  85. """
  86. Return a list of keys for a given section.
  87. :param section: The configuration [section].
  88. """
  89. return self[section].keys()
  90. def get(self, section, key):
  91. """
  92. Get a value for a given key under section.
  93. :param section: The configuration [section].
  94. :param key: The configuration key under the section.
  95. :returns: unknown (the value of the key)
  96. """
  97. return self[section][key]
  98. def set(self, section, key, value):
  99. """
  100. Set a configuration key value under [section].
  101. :param section: The configuration [section].
  102. :param key: The configuration key under the section.
  103. :param value: The value to set the key to.
  104. :returns: None
  105. """
  106. self[section][key] = value
  107. def has_section(self, section):
  108. """
  109. Return True/False whether the configuration [section] exists.
  110. :param section: The section to check for.
  111. :returns: bool
  112. """
  113. if section in self.get_sections():
  114. return True
  115. else:
  116. return False
  117. def add_section(self, section):
  118. """
  119. Add a section to the configuration.
  120. :param section: The configuration [section] to add.
  121. """
  122. if not self.has_section(section):
  123. self[section] = dict()
  124. def merge(self, dict_obj, override=True):
  125. """
  126. Merge a dictionary into our config. If override is True then
  127. existing config values are overridden by those passed in.
  128. :param dict_obj: A dictionary of configuration keys/values to merge
  129. into our existing config (self).
  130. :param override: Whether or not to override existing values in the
  131. config.
  132. :returns: None
  133. """
  134. for section in list(dict_obj.keys()):
  135. if type(dict_obj[section]) == dict:
  136. if section not in self.get_sections():
  137. self.add_section(section)
  138. for key in list(dict_obj[section].keys()):
  139. if override:
  140. self.set(section, key, dict_obj[section][key])
  141. else:
  142. # only set it if the key doesn't exist
  143. if key not in self.keys(section):
  144. self.set(section, key, dict_obj[section][key])
  145. # we don't support nested config blocks, so no need to go
  146. # further down to more nested dicts.
  147. def load(app):
  148. app.handler.register(ConfigObjConfigHandler)