Skip to content

Commit 092f01b

Browse files
author
Alexander Smishlajev
committed
fix: Option defaults were applied as strings...
...not converted to internal representation; add Option methods str2value and value2str for value conversion from and to the strings kept in .ini file; options MAIL_USERNAME, MAIL_TLS_KEYFILE and MAIL_TLS_CERTFILE default to empty strings: NODEFAULT value is a configuration error, and for these options it is ok to keep them unset.
1 parent f16014e commit 092f01b

File tree

1 file changed

+60
-46
lines changed

1 file changed

+60
-46
lines changed

roundup/configuration.py

Lines changed: 60 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Roundup Issue Tracker configuration support
22
#
3-
# $Id: configuration.py,v 1.4 2004-07-25 13:21:38 a1s Exp $
3+
# $Id: configuration.py,v 1.5 2004-07-25 14:36:50 a1s Exp $
44
#
55
__docformat__ = "restructuredtext"
66

@@ -136,8 +136,34 @@ def __init__(self, config, section, setting,
136136
else:
137137
self.aliases = []
138138
self.aliases.insert(0, self.name)
139+
# convert default to internal representation
140+
if default is NODEFAULT:
141+
_value = default
142+
else:
143+
_value = self.str2value(default)
139144
# value is private. use get() and set() to access
140-
self._value = default
145+
self._value = self._default_value = _value
146+
147+
def str2value(self, value):
148+
"""Return 'value' argument converted to internal representation"""
149+
return value
150+
151+
def _value2str(self, value):
152+
"""Return 'value' argument converted to external representation
153+
154+
This is actual conversion method called only when value
155+
is not NODEFAULT. Heirs with different conversion rules
156+
override this method, not the public .value2str().
157+
158+
"""
159+
return str(value)
160+
161+
def value2str(self, value):
162+
"""Return 'value' argument converted to external representation"""
163+
if value is NODEFAULT:
164+
return str(value)
165+
else:
166+
return self._value2str(value)
141167

142168
def get(self):
143169
"""Return current option value"""
@@ -147,34 +173,22 @@ def get(self):
147173

148174
def set(self, value):
149175
"""Update the value"""
150-
self._value = value
176+
self._value = self.str2value(value)
151177

152178
def reset(self):
153179
"""Reset the value to default"""
154-
self._value = self.default
180+
self._value = self._default_value
155181

156182
def isdefault(self):
157183
"""Return True if current value is the default one"""
158-
return self._value == self.default
184+
return self._value == self._default_value
159185

160186
def isset(self):
161187
"""Return True if the value is avaliable (either set or default)"""
162188
return self._value != NODEFAULT
163189

164-
def str(self, default=0):
165-
"""Return string representation of the value
166-
167-
If 'default' argument is set, format the default value.
168-
Otherwise format current value.
169-
170-
"""
171-
if default:
172-
return str(self.default)
173-
else:
174-
return str(self._value)
175-
176190
def __str__(self):
177-
return self.str()
191+
return self.value2str(self._value)
178192

179193
def __repr__(self):
180194
if self.isdefault():
@@ -184,8 +198,8 @@ def __repr__(self):
184198
return _format % {
185199
"class": self.__class__.__name__,
186200
"name": self.name,
187-
"default": self.str(default=1),
188-
"value": str(self),
201+
"default": self.value2str(self._default_value),
202+
"value": self.value2str(self._value),
189203
}
190204

191205
def format(self):
@@ -202,9 +216,9 @@ def format(self):
202216
_rv = "# %(description)s\n# Default: %(default)s\n" \
203217
"%(is_set)s%(name)s = %(value)s\n" % {
204218
"description": "\n# ".join(_desc_lines),
205-
"default": self.str(default=1),
219+
"default": self.value2str(self._default_value),
206220
"name": self.setting,
207-
"value": str(self),
221+
"value": self.value2str(self._value),
208222
"is_set": _is_set
209223
}
210224
return _rv
@@ -227,17 +241,13 @@ class BooleanOption(Option):
227241

228242
class_description = "Allowed values: yes, no"
229243

230-
def str(self, default=0):
231-
if default:
232-
_val = self.default
233-
else:
234-
_val = self._value
235-
if _val:
244+
def _value2str(self, value):
245+
if value:
236246
return "yes"
237247
else:
238248
return "no"
239249

240-
def set(self, value):
250+
def str2value(self, value):
241251
if type(value) == type(""):
242252
_val = value.lower()
243253
if _val in ("yes", "true", "on", "1"):
@@ -248,18 +258,18 @@ def set(self, value):
248258
raise OptionValueError(self, value, self.class_description)
249259
else:
250260
_val = value and 1 or 0
251-
Option.set(self, _val)
261+
return _val
252262

253263
class RunDetectorOption(Option):
254264

255265
"""When a detector is run: always, never or for new items only"""
256266

257267
class_description = "Allowed values: yes, no, new"
258268

259-
def set(self, value):
269+
def str2value(self, value):
260270
_val = value.lower()
261271
if _val in ("yes", "no", "new"):
262-
Option.set(self, _val)
272+
return _val
263273
else:
264274
raise OptionValueError(self, value, self.class_description)
265275

@@ -296,26 +306,29 @@ class FloatNumberOption(Option):
296306

297307
"""Floating point numbers"""
298308

299-
def set(self, value):
309+
def str2value(self, value):
300310
try:
301-
_val = float(value)
311+
return float(value)
302312
except ValueError:
303313
raise OptionValueError(self, value,
304314
"Floating point number required")
305-
else:
306-
Option.set(self, _val)
315+
316+
def _value2str(self, value):
317+
_val = str(value)
318+
# strip fraction part from integer numbers
319+
if _val.endswith(".0"):
320+
_val = _val[:-2]
321+
return _val
307322

308323
class IntegerNumberOption(Option):
309324

310325
"""Integer numbers"""
311326

312-
def set(self, value):
327+
def str2value(self, value):
313328
try:
314-
_val = int(value)
329+
return int(value)
315330
except ValueError:
316331
raise OptionValueError(self, value, "Integer number required")
317-
else:
318-
Option.set(self, _val)
319332

320333
### Main configuration layout.
321334
# Config is described as a sequence of sections,
@@ -407,20 +420,21 @@ def set(self, value):
407420
# In addition, 'charset' option is used in nosy messages only,
408421
# so this option actually belongs to the 'nosy' section.
409422
("mail", (
410-
(Option, "domain", NODEFAULT, "Domain name used for email addresses"),
423+
(Option, "domain", NODEFAULT, "Domain name used for email addresses."),
411424
(Option, "host", NODEFAULT,
412425
"SMTP mail host that roundup will use to send mail"),
413-
(Option, "username", NODEFAULT, "SMTP login name\n"
414-
"Set this if your mail host requires authenticated access"),
426+
(Option, "username", "", "SMTP login name\n"
427+
"Set this if your mail host requires authenticated access.\n"
428+
"If username is not empty, password (below) MUST be set!"),
415429
(Option, "password", NODEFAULT, "SMTP login password\n"
416-
"Set this if your mail host requires authenticated access"),
430+
"Set this if your mail host requires authenticated access."),
417431
(BooleanOption, "tls", "no",
418432
"If your SMTP mail host provides or requires TLS\n"
419433
"(Transport Layer Security) then set this option to 'yes'"),
420-
(FilePathOption, "tls_keyfile", NODEFAULT,
434+
(FilePathOption, "tls_keyfile", "",
421435
"If TLS is used, you may set this option to the name\n"
422436
"of a PEM formatted file that contains your private key"),
423-
(FilePathOption, "tls_certfile", NODEFAULT,
437+
(FilePathOption, "tls_certfile", "",
424438
"If TLS is used, you may set this option to the name\n"
425439
"of a PEM formatted certificate chain file"),
426440
(BooleanOption, "keep_quoted_text", "yes",

0 commit comments

Comments
 (0)