better error messages

This commit is contained in:
Emmanuel Garette 2016-09-11 20:41:36 +02:00
parent c21949c637
commit 408e4cf088
3 changed files with 85 additions and 79 deletions

View File

@ -11,15 +11,18 @@ from tiramisu.error import ValueWarning
from tiramisu.i18n import _ from tiramisu.i18n import _
msg_err = _("attention, {0} could be an invalid {1} for option {2}, {3}")
def return_true(value, param=None): def return_true(value, param=None):
if value == 'val' and param in [None, 'yes']: if value == 'val' and param in [None, 'yes']:
return True return True
return ValueError('error') return ValueError('test error')
def return_false(value, param=None): def return_false(value, param=None):
if value == 'val' and param in [None, 'yes']: if value == 'val' and param in [None, 'yes']:
return ValueError('error') return ValueError('test error')
def return_val(value, param=None): def return_val(value, param=None):
@ -28,7 +31,7 @@ def return_val(value, param=None):
def return_if_val(value): def return_if_val(value):
if value != 'val': if value != 'val':
return ValueError('error') return ValueError('test error')
def test_validator(): def test_validator():
@ -96,7 +99,7 @@ def test_validator_warning():
cfg.opt2 = 'val' cfg.opt2 = 'val'
assert len(w) == 1 assert len(w) == 1
assert w[0].message.opt == opt2 assert w[0].message.opt == opt2
assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('opt2', 'error') assert str(w[0].message) == msg_err.format('val', opt2.display_name, 'opt2', 'test error')
# #
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
cfg.opt3.append('val') cfg.opt3.append('val')
@ -106,7 +109,7 @@ def test_validator_warning():
cfg.opt3.append('val1') cfg.opt3.append('val1')
assert len(w) == 1 assert len(w) == 1
assert w[0].message.opt == opt3 assert w[0].message.opt == opt3
assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('opt3', 'error') assert str(w[0].message) == msg_err.format('val1', opt3.display_name, 'opt3', 'test error')
raises(ValueError, "cfg.opt2 = 1") raises(ValueError, "cfg.opt2 = 1")
# #
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
@ -114,9 +117,9 @@ def test_validator_warning():
cfg.opt3.append('val') cfg.opt3.append('val')
assert len(w) == 2 assert len(w) == 2
assert w[0].message.opt == opt2 assert w[0].message.opt == opt2
assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('opt2', 'error') assert str(w[0].message) == msg_err.format('val', opt2.display_name, 'opt2', 'test error')
assert w[1].message.opt == opt3 assert w[1].message.opt == opt3
assert str(w[1].message) == _("warning on the value of the option {0}: {1}").format('opt3', 'error') assert str(w[0].message) == msg_err.format('val', opt2.display_name, 'opt2', 'test error')
def test_validator_warning_disabled(): def test_validator_warning_disabled():
@ -168,29 +171,29 @@ def test_validator_warning_master_slave():
cfg.ip_admin_eth0.netmask_admin_eth0 = ['val1'] cfg.ip_admin_eth0.netmask_admin_eth0 = ['val1']
assert len(w) == 1 assert len(w) == 1
assert w[0].message.opt == netmask_admin_eth0 assert w[0].message.opt == netmask_admin_eth0
assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('netmask_admin_eth0', 'error') assert str(w[0].message) == msg_err.format('val1', netmask_admin_eth0.display_name, 'netmask_admin_eth0', 'test error')
# #
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
cfg.ip_admin_eth0.ip_admin_eth0 = ['val'] cfg.ip_admin_eth0.ip_admin_eth0 = ['val']
assert len(w) == 1 assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0 assert w[0].message.opt == ip_admin_eth0
assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('ip_admin_eth0', 'error') assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.display_name, 'ip_admin_eth0', 'test error')
# #
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
cfg.ip_admin_eth0.ip_admin_eth0 = ['val', 'val1', 'val1'] cfg.ip_admin_eth0.ip_admin_eth0 = ['val', 'val1', 'val1']
assert len(w) == 1 assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0 assert w[0].message.opt == ip_admin_eth0
assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('ip_admin_eth0', 'error') assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.display_name, 'ip_admin_eth0', 'test error')
# #
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val', 'val1'] cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val', 'val1']
assert len(w) == 1 assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0 assert w[0].message.opt == ip_admin_eth0
assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('ip_admin_eth0', 'error') assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.display_name, 'ip_admin_eth0', 'test error')
# #
warnings.resetwarnings() warnings.resetwarnings()
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val1', 'val'] cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val1', 'val']
assert len(w) == 1 assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0 assert w[0].message.opt == ip_admin_eth0
assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('ip_admin_eth0', 'error') assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.display_name, 'ip_admin_eth0', 'test error')

View File

@ -38,6 +38,13 @@ forbidden_names = frozenset(['iter_all', 'iter_group', 'find', 'find_first',
'read_write', 'getowner', 'set_contexts']) 'read_write', 'getowner', 'set_contexts'])
def display_list(list_):
if len(list_) == 1:
return list_[0]
else:
return ', '.join(list_[:-1]) + _(' and ') + list_[-1]
def valid_name(name): def valid_name(name):
"an option's name is a str and does not start with 'impl' or 'cfgimpl'" "an option's name is a str and does not start with 'impl' or 'cfgimpl'"
if not isinstance(name, str): # pragma: optional cover if not isinstance(name, str): # pragma: optional cover
@ -490,10 +497,11 @@ class Option(OnlyOption):
'submulti_index: {2}'.format(_value, _index, 'submulti_index: {2}'.format(_value, _index,
submulti_index), submulti_index),
exc_info=True) exc_info=True)
if '{0}'.format(err): err_msg = '{0}'.format(err)
msg = _('{0} is an invalid {1} for option {2}: {3}' if err_msg:
msg = _('{0} is an invalid {1} for option {2}, {3}'
'').format(_value, self.display_name, '').format(_value, self.display_name,
self.impl_getname(), err) self.impl_getname(), err_msg)
else: else:
msg = _('{0} is an invalid {1} for option {2}' msg = _('{0} is an invalid {1} for option {2}'
'').format(_value, self.display_name, '').format(_value, self.display_name,
@ -522,7 +530,7 @@ class Option(OnlyOption):
else: else:
return ret return ret
if warning: if warning:
msg = _("attention, {0} could be an invalid {1} for option {2}: {3}").format( msg = _("attention, {0} could be an invalid {1} for option {2}, {3}").format(
_value, self.display_name, self.impl_getname(), warning) _value, self.display_name, self.impl_getname(), warning)
if context is undefined or 'warnings' in \ if context is undefined or 'warnings' in \
context.cfgimpl_get_settings(): context.cfgimpl_get_settings():
@ -530,10 +538,11 @@ class Option(OnlyOption):
ValueWarning, ValueWarning,
self.__class__.__name__, 0) self.__class__.__name__, 0)
elif error: elif error:
if '{0}'.format(err): err_msg = '{0}'.format(error)
msg = _("{0} is an invalid {1} for option {2}: {3}" if err_msg:
msg = _("{0} is an invalid {1} for option {2}, {3}"
"").format(_value, self.display_name, "").format(_value, self.display_name,
self.impl_getname(), error) self.impl_getname(), err_msg)
else: else:
msg = _("{0} is an invalid {1} for option {2}" msg = _("{0} is an invalid {1} for option {2}"
"").format(_value, self.display_name, "").format(_value, self.display_name,
@ -706,9 +715,9 @@ class Option(OnlyOption):
for idx_sup, val_sup in enumerate(vals[idx_inf + 1:]): for idx_sup, val_sup in enumerate(vals[idx_inf + 1:]):
if val_inf == val_sup is not None: if val_inf == val_sup is not None:
if warnings_only: if warnings_only:
msg = _("same value for {0} and {1}, should be different") msg = _("value for {0} and {1} should be different")
else: else:
msg = _("same value for {0} and {1}, must be different") msg = _("value for {0} and {1} must be different")
log.debug('_cons_not_equal: {0} and {1} are not different'.format(val_inf, val_sup)) log.debug('_cons_not_equal: {0} and {1} are not different'.format(val_inf, val_sup))
return ValueError(msg.format(opts[idx_inf].impl_getname(), return ValueError(msg.format(opts[idx_inf].impl_getname(),
opts[idx_inf + idx_sup + 1].impl_getname())) opts[idx_inf + idx_sup + 1].impl_getname()))

View File

@ -27,7 +27,7 @@ from ..setting import undefined
from ..error import ConfigError from ..error import ConfigError
from ..i18n import _ from ..i18n import _
from .baseoption import Option, validate_callback from .baseoption import Option, validate_callback, display_list
from ..autolib import carry_out_calculation from ..autolib import carry_out_calculation
@ -100,10 +100,12 @@ class ChoiceOption(Option):
if isinstance(values, Exception): if isinstance(values, Exception):
return values return values
if values is not undefined and not value in values: # pragma: optional cover if values is not undefined and not value in values: # pragma: optional cover
return ValueError(_('value {0} is not permitted, ' if len(values) == 1:
'only {1} is allowed' return ValueError(_('only {0} is allowed'
'').format(value, '').format(values[0]))
values)) else:
return ValueError(_('only {0} are allowed'
'').format(display_list(values)))
class BoolOption(Option): class BoolOption(Option):
@ -114,7 +116,7 @@ class BoolOption(Option):
def _validate(self, value, context=undefined, current_opt=undefined, def _validate(self, value, context=undefined, current_opt=undefined,
returns_raise=False): returns_raise=False):
if not isinstance(value, bool): if not isinstance(value, bool):
return ValueError(_('invalid boolean')) # pragma: optional cover return ValueError() # pragma: optional cover
class IntOption(Option): class IntOption(Option):
@ -125,7 +127,7 @@ class IntOption(Option):
def _validate(self, value, context=undefined, current_opt=undefined, def _validate(self, value, context=undefined, current_opt=undefined,
returns_raise=False): returns_raise=False):
if not isinstance(value, int): if not isinstance(value, int):
return ValueError(_('invalid integer')) # pragma: optional cover return ValueError() # pragma: optional cover
class FloatOption(Option): class FloatOption(Option):
@ -136,7 +138,7 @@ class FloatOption(Option):
def _validate(self, value, context=undefined, current_opt=undefined, def _validate(self, value, context=undefined, current_opt=undefined,
returns_raise=False): returns_raise=False):
if not isinstance(value, float): if not isinstance(value, float):
return ValueError(_('invalid float')) # pragma: optional cover return ValueError() # pragma: optional cover
class StrOption(Option): class StrOption(Option):
@ -147,7 +149,7 @@ class StrOption(Option):
def _validate(self, value, context=undefined, current_opt=undefined, def _validate(self, value, context=undefined, current_opt=undefined,
returns_raise=False): returns_raise=False):
if not isinstance(value, str): if not isinstance(value, str):
return ValueError(_('invalid string')) # pragma: optional cover return ValueError() # pragma: optional cover
if sys.version_info[0] >= 3: # pragma: optional cover if sys.version_info[0] >= 3: # pragma: optional cover
@ -160,12 +162,12 @@ else:
"represents the choice of a unicode string" "represents the choice of a unicode string"
__slots__ = tuple() __slots__ = tuple()
_empty = u'' _empty = u''
display_name = _('string') display_name = _('unicode string')
def _validate(self, value, context=undefined, current_opt=undefined, def _validate(self, value, context=undefined, current_opt=undefined,
returns_raise=False): returns_raise=False):
if not isinstance(value, unicode): if not isinstance(value, unicode):
return ValueError(_('invalid unicode')) # pragma: optional cover return ValueError() # pragma: optional cover
class PasswordOption(Option): class PasswordOption(Option):
@ -245,13 +247,11 @@ class IPOption(Option):
ip, network, netmask = vals ip, network, netmask = vals
if IP(ip) not in IP('{0}/{1}'.format(network, netmask)): # pragma: optional cover if IP(ip) not in IP('{0}/{1}'.format(network, netmask)): # pragma: optional cover
if warnings_only: if warnings_only:
msg = _('IP {0} ({1}) not in network {2} ({3}) with netmask {4}' msg = _('should be in network {0}/{1} ({2}/{3})')
' ({5})')
else: else:
msg = _('invalid IP {0} ({1}) not in network {2} ({3}) with ' msg = _('must be in network {0}/{1} ({2}/{3})')
'netmask {4} ({5})') return ValueError(msg.format(network, netmask,
return ValueError(msg.format(ip, opts[0].impl_getname(), network, opts[1].impl_getname(), opts[2].impl_getname()))
opts[1].impl_getname(), netmask, opts[2].impl_getname()))
# test if ip is not network/broadcast IP # test if ip is not network/broadcast IP
return opts[2]._cons_ip_netmask((opts[2], opts[0]), (netmask, ip), warnings_only) return opts[2]._cons_ip_netmask((opts[2], opts[0]), (netmask, ip), warnings_only)
@ -324,20 +324,19 @@ class PortOption(Option):
if self._get_extra('_allow_range') and ":" in str(value): # pragma: optional cover if self._get_extra('_allow_range') and ":" in str(value): # pragma: optional cover
value = str(value).split(':') value = str(value).split(':')
if len(value) != 2: if len(value) != 2:
return ValueError(_('invalid port, range must have two values ' return ValueError(_('range must have two values only'))
'only'))
if not value[0] < value[1]: if not value[0] < value[1]:
return ValueError(_('invalid port, first port in range must be' return ValueError(_('first port in range must be'
' smaller than the second one')) ' smaller than the second one'))
else: else:
value = [value] value = [value]
for val in value: for val in value:
if not self.port_re.search(val): if not self.port_re.search(val):
return ValueError(_('invalid port')) return ValueError()
val = int(val) val = int(val)
if not self._get_extra('_min_value') <= val <= self._get_extra('_max_value'): # pragma: optional cover if not self._get_extra('_min_value') <= val <= self._get_extra('_max_value'): # pragma: optional cover
return ValueError(_('invalid port, must be an integer between {0} ' return ValueError(_('must be an integer between {0} '
'and {1}').format(self._get_extra('_min_value'), 'and {1}').format(self._get_extra('_min_value'),
self._get_extra('_max_value'))) self._get_extra('_max_value')))
@ -345,7 +344,7 @@ class PortOption(Option):
class NetworkOption(Option): class NetworkOption(Option):
"represents the choice of a network" "represents the choice of a network"
__slots__ = tuple() __slots__ = tuple()
display_name = _('network') display_name = _('network address')
def _validate(self, value, context=undefined, current_opt=undefined, def _validate(self, value, context=undefined, current_opt=undefined,
returns_raise=False): returns_raise=False):
@ -353,29 +352,29 @@ class NetworkOption(Option):
if err: if err:
return err return err
if value.count('.') != 3: if value.count('.') != 3:
return ValueError(_('invalid network address')) return ValueError()
for val in value.split('.'): for val in value.split('.'):
if val.startswith("0") and len(val) > 1: if val.startswith("0") and len(val) > 1:
return ValueError(_('invalid network address')) return ValueError()
try: try:
IP(value) IP(value)
except ValueError: # pragma: optional cover except ValueError: # pragma: optional cover
return ValueError(_('invalid network address')) return ValueError()
def _second_level_validation(self, value, warnings_only): def _second_level_validation(self, value, warnings_only):
ip = IP(value) ip = IP(value)
if ip.iptype() == 'RESERVED': # pragma: optional cover if ip.iptype() == 'RESERVED': # pragma: optional cover
if warnings_only: if warnings_only:
msg = _("network address is in reserved class") msg = _("shouldn't be in reserved class")
else: else:
msg = _("invalid network address, mustn't be in reserved class") msg = _("mustn't be in reserved class")
return ValueError(msg) return ValueError(msg)
class NetmaskOption(Option): class NetmaskOption(Option):
"represents the choice of a netmask" "represents the choice of a netmask"
__slots__ = tuple() __slots__ = tuple()
display_name = _('netmask') display_name = _('netmask address')
def _validate(self, value, context=undefined, current_opt=undefined, def _validate(self, value, context=undefined, current_opt=undefined,
returns_raise=False): returns_raise=False):
@ -383,14 +382,14 @@ class NetmaskOption(Option):
if err: if err:
return err return err
if value.count('.') != 3: if value.count('.') != 3:
return ValueError(_('invalid netmask address')) return ValueError()
for val in value.split('.'): for val in value.split('.'):
if val.startswith("0") and len(val) > 1: if val.startswith("0") and len(val) > 1:
return ValueError(_('invalid netmask address')) return ValueError()
try: try:
IP('0.0.0.0/{0}'.format(value)) IP('0.0.0.0/{0}'.format(value))
except ValueError: # pragma: optional cover except ValueError: # pragma: optional cover
return ValueError(_('invalid netmask address')) return ValueError()
def _cons_network_netmask(self, opts, vals, warnings_only): def _cons_network_netmask(self, opts, vals, warnings_only):
#opts must be (netmask, network) options #opts must be (netmask, network) options
@ -416,23 +415,20 @@ class NetmaskOption(Option):
if make_net and ip.prefixlen() != 32: if make_net and ip.prefixlen() != 32:
val_ip = IP(val_ipnetwork) val_ip = IP(val_ipnetwork)
if ip.net() == val_ip: if ip.net() == val_ip:
msg = _("invalid IP {0} ({1}) with netmask {2}," msg = _("this is a network with netmask {0} ({1})")
" this IP is a network")
if ip.broadcast() == val_ip: if ip.broadcast() == val_ip:
msg = _("invalid IP {0} ({1}) with netmask {2}," msg = _("this is a broadcast with netmask {0} ({1})")
" this IP is a broadcast")
except ValueError: # pragma: optional cover except ValueError: # pragma: optional cover
if not make_net: if not make_net:
msg = _('invalid network {0} ({1}) with netmask {2}') msg = _('with netmask {0} ({1})')
if msg is not None: # pragma: optional cover if msg is not None: # pragma: optional cover
return ValueError(msg.format(val_ipnetwork, opts[1].impl_getname(), return ValueError(msg.format(val_netmask, opts[1].impl_getname()))
val_netmask))
class BroadcastOption(Option): class BroadcastOption(Option):
__slots__ = tuple() __slots__ = tuple()
display_name = _('broadcast') display_name = _('broadcast address')
def _validate(self, value, context=undefined, current_opt=undefined, def _validate(self, value, context=undefined, current_opt=undefined,
returns_raise=False): returns_raise=False):
@ -442,7 +438,7 @@ class BroadcastOption(Option):
try: try:
IP('{0}/32'.format(value)) IP('{0}/32'.format(value))
except ValueError: # pragma: optional cover except ValueError: # pragma: optional cover
return ValueError(_('invalid broadcast address')) return ValueError()
def _cons_broadcast(self, opts, vals, warnings_only): def _cons_broadcast(self, opts, vals, warnings_only):
if len(vals) != 3: if len(vals) != 3:
@ -451,10 +447,8 @@ class BroadcastOption(Option):
return return
broadcast, network, netmask = vals broadcast, network, netmask = vals
if IP('{0}/{1}'.format(network, netmask)).broadcast() != IP(broadcast): if IP('{0}/{1}'.format(network, netmask)).broadcast() != IP(broadcast):
return ValueError(_('invalid broadcast {0} ({1}) with network {2} ' return ValueError(_('with network {0}/{1} ({2}/{3})').format(
'({3}) and netmask {4} ({5})').format( network, netmask, opts[1].impl_getname(), opts[2].impl_getname())) # pragma: optional cover
broadcast, opts[0].impl_getname(), network,
opts[1].impl_getname(), netmask, opts[2].impl_getname())) # pragma: optional cover
class DomainnameOption(Option): class DomainnameOption(Option):
@ -504,9 +498,9 @@ class DomainnameOption(Option):
def _valid_length(val): def _valid_length(val):
if len(val) < 1: if len(val) < 1:
return ValueError(_("invalid domainname's length (min 1)")) return ValueError(_("invalid length (min 1)"))
if len(val) > part_name_length: if len(val) > part_name_length:
return ValueError(_("invalid domainname's length (max {0})" return ValueError(_("invalid length (max {0})"
"").format(part_name_length)) "").format(part_name_length))
if self._get_extra('_allow_ip') is True: # pragma: optional cover if self._get_extra('_allow_ip') is True: # pragma: optional cover
@ -521,16 +515,16 @@ class DomainnameOption(Option):
except ValueError: except ValueError:
pass pass
else: else:
raise ValueError(_('invalid domainname, must not be an IP')) raise ValueError(_('must not be an IP'))
if self._get_extra('_dom_type') == 'netbios': if self._get_extra('_dom_type') == 'netbios':
part_name_length = 15 part_name_length = 15
else: else:
part_name_length = 63 part_name_length = 63
if self._get_extra('_dom_type') == 'domainname': if self._get_extra('_dom_type') == 'domainname':
if not self._get_extra('_allow_without_dot') and not "." in value: if not self._get_extra('_allow_without_dot') and not "." in value:
return ValueError(_("invalid domainname, must have dot")) return ValueError(_("must have dot"))
if len(value) > 255: if len(value) > 255:
return ValueError(_("invalid domainname's length (max 255)")) return ValueError(_("invalid length (max 255)"))
for dom in value.split('.'): for dom in value.split('.'):
err = _valid_length(dom) err = _valid_length(dom)
if err: if err:
@ -546,7 +540,7 @@ class DomainnameOption(Option):
if warnings_only: if warnings_only:
return ValueError(_('some characters may cause problems')) return ValueError(_('some characters may cause problems'))
else: else:
return ValueError(_('invalid domainname')) return ValueError()
#not for IP #not for IP
if self._get_extra('_allow_ip') is True: if self._get_extra('_allow_ip') is True:
try: try:
@ -564,7 +558,7 @@ class DomainnameOption(Option):
class EmailOption(DomainnameOption): class EmailOption(DomainnameOption):
__slots__ = tuple() __slots__ = tuple()
username_re = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$") username_re = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$")
display_name = _('email') display_name = _('email address')
def _validate(self, value, context=undefined, current_opt=undefined, def _validate(self, value, context=undefined, current_opt=undefined,
returns_raise=False): returns_raise=False):
@ -573,7 +567,7 @@ class EmailOption(DomainnameOption):
return err return err
splitted = value.split('@', 1) splitted = value.split('@', 1)
if len(splitted) == 1: if len(splitted) == 1:
return ValueError(_('invalid email address, must contains one @')) return ValueError(_('must contains one @'))
username, domain = value.split('@', 1) username, domain = value.split('@', 1)
if not self.username_re.search(username): if not self.username_re.search(username):
return ValueError(_('invalid username in email address')) # pragma: optional cover return ValueError(_('invalid username in email address')) # pragma: optional cover
@ -599,7 +593,7 @@ class URLOption(DomainnameOption):
return err return err
match = self.proto_re.search(value) match = self.proto_re.search(value)
if not match: # pragma: optional cover if not match: # pragma: optional cover
return ValueError(_('invalid url, must start with http:// or ' return ValueError(_('must start with http:// or '
'https://')) 'https://'))
value = value[len(match.group(0)):] value = value[len(match.group(0)):]
# get domain/files # get domain/files
@ -617,7 +611,7 @@ class URLOption(DomainnameOption):
else: else:
domain, port = splitted domain, port = splitted
if not 0 <= int(port) <= 65535: if not 0 <= int(port) <= 65535:
return ValueError(_('invalid url, port must be an between 0 and ' return ValueError(_('port must be an between 0 and '
'65536')) # pragma: optional cover '65536')) # pragma: optional cover
# validate domainname # validate domainname
err = super(URLOption, self)._validate(domain) err = super(URLOption, self)._validate(domain)
@ -628,7 +622,7 @@ class URLOption(DomainnameOption):
return err return err
# validate file # validate file
if files is not None and files != '' and not self.path_re.search(files): if files is not None and files != '' and not self.path_re.search(files):
return ValueError(_('invalid url, must ends with a valid resource name')) # pragma: optional cover return ValueError(_('must ends with a valid resource name')) # pragma: optional cover
def _second_level_validation(self, value, warnings_only): def _second_level_validation(self, value, warnings_only):
pass pass
@ -647,7 +641,7 @@ class UsernameOption(Option):
return err return err
match = self.username_re.search(value) match = self.username_re.search(value)
if not match: if not match:
return ValueError(_('invalid username')) # pragma: optional cover return ValueError() # pragma: optional cover
class FilenameOption(Option): class FilenameOption(Option):
@ -662,4 +656,4 @@ class FilenameOption(Option):
return err return err
match = self.path_re.search(value) match = self.path_re.search(value)
if not match: if not match:
return ValueError(_('invalid filename')) # pragma: optional cover return ValueError('some characters are not allowed') # pragma: optional cover