Improved messaging for simple type validator

English language is a tricky old thing and I've pulled out the validator type
parsing so that we can prefix our validator types with the correct article,
'an' or 'a'.

Doing a bit of extra hard work to ensure the error message is clear and
well constructed english.

Signed-off-by: Mazz Mosley <mazz@houseofmnowster.com>
This commit is contained in:
Mazz Mosley 2015-09-08 12:01:47 +01:00
parent 32cd404c8c
commit 418ec5336b
2 changed files with 50 additions and 6 deletions

View File

@ -117,6 +117,38 @@ def process_errors(errors, service_name=None):
else: else:
return str(schema['type']) return str(schema['type'])
def _parse_valid_types_from_validator(validator):
"""
A validator value can be either an array of valid types or a string of
a valid type. Parse the valid types and prefix with the correct article.
"""
pre_msg_type_prefix = "a"
last_msg_type_prefix = "a"
types_requiring_an = ["array", "object"]
if isinstance(validator, list):
last_type = validator.pop()
types_from_validator = ", ".join(validator)
if validator[0] in types_requiring_an:
pre_msg_type_prefix = "an"
if last_type in types_requiring_an:
last_msg_type_prefix = "an"
msg = "{} {} or {} {}".format(
pre_msg_type_prefix,
types_from_validator,
last_msg_type_prefix,
last_type
)
else:
if validator in types_requiring_an:
pre_msg_type_prefix = "an"
msg = "{} {}".format(pre_msg_type_prefix, validator)
return msg
root_msgs = [] root_msgs = []
invalid_keys = [] invalid_keys = []
required = [] required = []
@ -176,19 +208,16 @@ def process_errors(errors, service_name=None):
service_name, config_key, valid_type_msg) service_name, config_key, valid_type_msg)
) )
elif error.validator == 'type': elif error.validator == 'type':
msg = "a" msg = _parse_valid_types_from_validator(error.validator_value)
if error.validator_value == "array":
msg = "an"
if len(error.path) > 0: if len(error.path) > 0:
config_key = " ".join(["'%s'" % k for k in error.path]) config_key = " ".join(["'%s'" % k for k in error.path])
type_errors.append( type_errors.append(
"Service '{}' configuration key {} contains an invalid " "Service '{}' configuration key {} contains an invalid "
"type, it should be {} {}".format( "type, it should be {}".format(
service_name, service_name,
config_key, config_key,
msg, msg))
error.validator_value))
else: else:
root_msgs.append( root_msgs.append(
"Service '{}' doesn\'t have any configuration options. " "Service '{}' doesn\'t have any configuration options. "

View File

@ -269,6 +269,21 @@ class ConfigTest(unittest.TestCase):
) )
self.assertEqual(service[0]['entrypoint'], entrypoint) self.assertEqual(service[0]['entrypoint'], entrypoint)
def test_validation_message_for_invalid_type_when_multiple_types_allowed(self):
expected_error_msg = "Service 'web' configuration key 'mem_limit' contains an invalid type, it should be a number or a string"
with self.assertRaisesRegexp(ConfigurationError, expected_error_msg):
config.load(
config.ConfigDetails(
{'web': {
'image': 'busybox',
'mem_limit': ['incorrect']
}},
'working_dir',
'filename.yml'
)
)
class InterpolationTest(unittest.TestCase): class InterpolationTest(unittest.TestCase):
@mock.patch.dict(os.environ) @mock.patch.dict(os.environ)