File indexing completed on 2024-11-03 05:12:54
0001 # -*- coding: UTF-8 -*- 0002 0003 """ 0004 Access the user configuration of Pology. 0005 0006 The location and the syntax of the configuration file is described 0007 in the user manual, at C{doc/user/common.docbook#sec-cmconfig}. 0008 0009 At every place where the user configuration is sourced, the API documentation 0010 should state which sections and fields (with their types) are accessed, 0011 how they are used, and what is the behavior when they are not set. 0012 0013 @author: Chusslove Illich (Часлав Илић) <caslav.ilic@gmx.net> 0014 @license: GPLv3 0015 """ 0016 0017 import codecs 0018 import os 0019 from configparser import ConfigParser 0020 0021 from pology import _, n_ 0022 from pology.report import error 0023 0024 0025 _config = ConfigParser() 0026 0027 def _parse_config (): 0028 0029 # Try to correctly resolve the config file location across systems. 0030 cfgbase = "pologyrc" 0031 if os.name=="nt": 0032 cfgpath = os.path.join(os.environ.get("APPDATA", ""), cfgbase) 0033 else: 0034 cfgbase = "." + cfgbase 0035 cfgpath = os.path.join(os.environ.get("HOME", ""), cfgbase) 0036 0037 # Parse the config if available. 0038 if os.path.isfile(cfgpath): 0039 ifl = codecs.open(cfgpath, "r", "UTF-8") 0040 _config.read_file(ifl) 0041 ifl.close() 0042 0043 # Parse configuration on first import. 0044 _parse_config() 0045 0046 0047 def has_section (name): 0048 """ 0049 Check if the section of the configuration exists already. 0050 0051 @param name: name of the section 0052 @type name: string 0053 0054 @returns: C{True} if the section exists, C{False} otherwise 0055 @rtype: bool 0056 """ 0057 0058 return _config.has_section(name) 0059 0060 0061 class section: 0062 """ 0063 Section of the configuration. 0064 0065 All getter methods take the field name and the default value, 0066 which is returned when the field is not set. 0067 If the configuration field is set but cannot be converted into 0068 a value of requested type, execution aborts with an error message. 0069 0070 @ivar name: name of the section 0071 @type name: string 0072 """ 0073 0074 def __init__ (self, name): 0075 """ 0076 Retrieve a section of the configuration. 0077 0078 Constructed section object is valid even when the configuration does 0079 not contain the requested section (in that case, all field queries 0080 on the section are going to return default values). 0081 0082 @param name: name of the section 0083 @type name: string 0084 """ 0085 0086 self.name = name 0087 0088 0089 def fields (self): 0090 """ 0091 Get all configuration field names in this section. 0092 0093 @rtype: set(string) 0094 """ 0095 0096 if not _config.has_section(self.name): 0097 return set() 0098 0099 return set(_config.options(self.name)) 0100 0101 0102 def _value (self, typ, name, default=None, typename=None): 0103 0104 if not _config.has_option(self.name, name): 0105 return default 0106 0107 value = _config.get(self.name, name) 0108 if typ is not bool: 0109 try: 0110 cvalue = typ(value) 0111 except: 0112 cvalue = None 0113 else: 0114 cvalue = strbool(value) 0115 0116 if cvalue is None: 0117 if typename: 0118 error(_("@info", 0119 "User configuration: value '%(val)s' " 0120 "of field '%(field)s' in section '%(sec)s' " 0121 "cannot be converted into '%(type)s' type.", 0122 val=value, field=name, sec=self.name, 0123 type=typename)) 0124 else: 0125 error(_("@info", 0126 "User configuration: value '%(val)s' " 0127 "of field '%(field)s' in section '%(sec)s' " 0128 "cannot be converted into requested type.", 0129 val=value, field=name, sec=self.name)) 0130 0131 return cvalue 0132 0133 0134 def string (self, name, default=None): 0135 """ 0136 Get a configuration field as a string. 0137 0138 @rtype: unicode or as C{default} 0139 """ 0140 0141 return self._value(str, name, default, "string") 0142 0143 0144 def integer (self, name, default=None): 0145 """ 0146 Get a configuration field as an integer number. 0147 0148 @rtype: int or as C{default} 0149 """ 0150 0151 return self._value(int, name, default, "integer") 0152 0153 0154 def real (self, name, default=None): 0155 """ 0156 Get a configuration field as a real number. 0157 0158 @rtype: float or as C{default} 0159 """ 0160 0161 return self._value(float, name, default, "real") 0162 0163 0164 def boolean (self, name, default=None): 0165 """ 0166 Get a configuration field as a boolean. 0167 0168 @rtype: bool or as C{default} 0169 """ 0170 0171 return self._value(bool, name, default, "boolean") 0172 0173 0174 def strslist (self, name, default=None, sep=","): 0175 """ 0176 Get a configuration field as a list of separated strings. 0177 0178 Separator character or string is used to split the field value 0179 into substrings:: 0180 0181 afield = foo, bar, baz 0182 0183 Leading and trailing whitespace in list elements is stripped. 0184 0185 If list elements should be able to contain any characters 0186 or whitespace is significant, use delimited list instead (L{strdlist}). 0187 0188 @param sep: the separator 0189 @type sep: string 0190 0191 @rtype: unicode or as C{default} 0192 """ 0193 0194 value = self._value(str, name, None, "string") 0195 if value is None: 0196 return default 0197 lst = value.split(sep) 0198 lst = [x.strip() for x in lst] 0199 0200 return lst 0201 0202 0203 def strdlist (self, name, default=None): 0204 """ 0205 Get a configuration field as a list of delimited strings. 0206 0207 Delimiter is taken to be the non-alphanumeric character with 0208 which the field value starts. In this example:: 0209 0210 afield = /foo/bar/baz/ 0211 0212 the delimiter is C{/}. 0213 0214 If the field value does not start with a non-alphanumeric, 0215 or it does not end with the delimiter, error is signalled. 0216 0217 @rtype: unicode or as C{default} 0218 """ 0219 0220 value = self._value(str, name, None, "string") 0221 if value is None: 0222 return default 0223 value = value.strip() 0224 0225 if len(value) < 2: 0226 error(_("@info", 0227 "User configuration: value '%(val)s' of field '%(field)s' " 0228 "in section '%(sec)s' is too short for a delimited list.", 0229 val=value, field=name, sec=self.name)) 0230 if value[0].isalnum(): 0231 error(_("@info", 0232 "User configuration: value '%(val)s' of field '%(field)s' " 0233 "in section '%(sec)s' does not start with " 0234 "a non-alphanumeric delimiter character.", 0235 val=value, field=name, sec=self.name)) 0236 0237 delim = value[0] 0238 0239 if value[-1] != delim: 0240 error(_("@info", 0241 "User configuration: value '%(val)s' of field '%(field)s' " 0242 "in section '%(sec)s' does not end with " 0243 "the delimiter character with which it starts.", 0244 val=value, field=name, sec=self.name)) 0245 0246 lst = value[1:-1].split(delim) 0247 0248 return lst 0249 0250 0251 def strbool (value): 0252 """ 0253 Parse the string specification of a boolean value. 0254 0255 Values considered C{false} are: C{"0"}, C{"no"}, C{"false"}, C{"off"}; 0256 and C{True}: C{1}, C{"yes"}, C{"true"}, C{"on"}. 0257 String is stripped of leading and trailing whitespace and lowercased 0258 before matching. 0259 0260 If the string matches none of the expected logical specifiers, 0261 C{None} is returned. 0262 0263 @param value: string to parse 0264 @type value: string 0265 0266 @return: parsed boolean 0267 @rtype: bool 0268 """ 0269 0270 value = value.strip().lower() 0271 if value in ("0", "no", "false", "off"): 0272 return False 0273 elif value in ("1", "yes", "true", "on"): 0274 return True 0275 else: 0276 return None 0277