1
2 """
3 Simple configuration file/line parser.
4 """
5 import shlex
6
8 """
9 Exception raised when a config file is not found.
10 """
11 pass
12
14 """
15 Exception raised when a specified option is not found.
16 """
17 pass
18
20 """
21 Exception raised when errors occur attempting to parse a file.
22 """
23 pass
24
25
26
27
28
29
30
31
32
33
34
36 """
37 Parses flat key-value pairs in a text file.
38
39 Removes quotes from quoted strings.
40
41 A list of tuples makes possible the use of many times the same key.
42 That is lost if you convert the result to a dict.
43
44 This ConfigParser is different from the one from the ConfigParser module,
45 since it does not use the concept of sections. Also, there can be many options
46 with the same key name. This class is partly insprired from ConfigParser.
47 """
48 STRIPPED = "\"' "
49 ASSIGNATION_OPERATORS = "=:"
50 COMMENTERS = "#"
51
53 self.file_name = None
54 self._options = []
55 self.verbose = False
56
57 - def read(self, file_name):
58 """
59 Attempts to read a file and parse its configuration entries.
60 It might throw a ParsingError.
61 """
62 self._read(file_name)
63
65 """
66 Returns a list of options available.
67 """
68 return dict(self._options).keys()
69
71 """
72 Checks for the existence of a given option.
73 """
74 return option in self.options()
75
76 - def get(self, option, cast=str):
77 """
78 Get an option value as a string.
79
80 The cast argument allows you to cast the type of the value to int, float or bool.
81 Just pass it a type.
82
83 Might raise a NoSuchOptionError if the option is not found.
84 Might raise a ValueError if the value is not of the given type.
85
86 If a key is defined many times, behavious is undefined. It it likely to return
87 the last item with that key.
88
89 Note that the accepted values for the option are "1", "yes", "true", and "on", which cause this method to return True, and "0", "no", "false", and "off", which cause it to return False. These string values are checked in a case-insensitive manner. Any other value will cause it to raise ValueError.
90 """
91 try:
92 value = dict(self._options)[option]
93 except KeyError, e:
94 raise NoSuchOptionError("Could not find option named %s." % (e.message))
95 return self.cast(value, cast)
96
97 _boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True,
98 '0': False, 'no': False, 'false': False, 'off': False}
99
101 """
102 Returns a list of values for a given key name.
103 """
104 ret = []
105 for k, v in self._options:
106 if k == option:
107 ret.append(self.cast(v, cast))
108 if len(ret) == 0:
109 raise NoSuchOptionError("Could not find option named %s." % (option))
110 return ret
111
112 - def cast(self, value, cast):
113 """
114 Casts a value to a given type.
115 Type can be int, float, str or bool.
116 """
117 if cast in [float, int]:
118 return cast(value)
119 elif cast is bool:
120 if value.lower() not in self._boolean_states:
121 raise ValueError("Value %s is not a valid boolean." % (value))
122 return self._boolean_states[value.lower()]
123 else:
124 return value
125
127 """
128 Return a list of tuples with (name, value) for each option.
129 """
130 return self._options
131
132 - def _read(self, file_name):
133 self.file_name = file_name
134 self._options = []
135 try:
136 f = open(file_name, 'r')
137 except IOError, e:
138 raise FileNotFoundError("Could not open file '%s': %s" % (file_name, e.message))
139 try:
140 lexer = shlex.shlex(f, file_name, posix=False)
141 lexer.commenters = self.COMMENTERS
142
143 key = None
144 for token in lexer:
145 if token in self.ASSIGNATION_OPERATORS:
146 if key is None:
147 raise ParsingError("No key defined, but found '%s' in file '%s' on line %d. Try using quotes." % (token, file_name, lexer.lineno))
148 else:
149 if key is None:
150 key = token.strip(self.STRIPPED)
151
152
153 if self.verbose:
154 print("Found key '%s'" % (key))
155 else:
156 value = token.strip(self.STRIPPED)
157
158 self._options.append((key, value))
159 if self.verbose:
160 print("Found value '%s' for key '%s'" % (value, key))
161 key = None
162 if key is not None:
163 raise ParsingError("No value for key %s" % (key))
164 except ValueError, e:
165 raise ParsingError("Error parsing file '%s': %s" % (file_name, e.message))
166 f.close()
167 return self._options
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184