diff --git a/compose/config/validation.py b/compose/config/validation.py index 946acf149b..36fd03b5f2 100644 --- a/compose/config/validation.py +++ b/compose/config/validation.py @@ -55,6 +55,16 @@ def process_errors(errors): def _clean_error_message(message): return message.replace("u'", "'") + def _parse_valid_types_from_schema(schema): + """ + Our defined types using $ref in the schema require some extra parsing + retrieve a helpful type for error message display. + """ + if '$ref' in schema: + return schema['$ref'].replace("#/definitions/", "").replace("_", " ") + else: + return str(schema['type']) + root_msgs = [] invalid_keys = [] required = [] @@ -93,9 +103,11 @@ def process_errors(errors): required.append(_clean_error_message(error.message)) elif error.validator == 'oneOf': config_key = error.path[0] - valid_types = [context.validator_value for context in error.context] + + valid_types = [_parse_valid_types_from_schema(schema) for schema in error.schema['oneOf']] valid_type_msg = " or ".join(valid_types) - type_errors.append("Service '{}' configuration key '{}' contains an invalid type, it should be either {}".format( + + type_errors.append("Service '{}' configuration key '{}' contains an invalid type, valid types are {}".format( service_name, config_key, valid_type_msg) ) elif error.validator == 'type': diff --git a/tests/unit/config_test.py b/tests/unit/config_test.py index f35010c695..1948e21826 100644 --- a/tests/unit/config_test.py +++ b/tests/unit/config_test.py @@ -160,6 +160,19 @@ class ConfigTest(unittest.TestCase): ) ) + def test_invalid_list_of_strings_format(self): + expected_error_msg = "'command' contains an invalid type, valid types are string or list of strings" + with self.assertRaisesRegexp(ConfigurationError, expected_error_msg): + config.load( + config.ConfigDetails( + { + 'web': {'build': '.', 'command': [1]} + }, + 'tests/fixtures/extends', + 'filename.yml' + ) + ) + class InterpolationTest(unittest.TestCase): @mock.patch.dict(os.environ)