diff --git a/mkdocs/config/config_options.py b/mkdocs/config/config_options.py index 9aa498ec..3b4fa9ad 100644 --- a/mkdocs/config/config_options.py +++ b/mkdocs/config/config_options.py @@ -139,7 +139,7 @@ class ListOfItems(Generic[T], BaseConfigOption[List[T]]): required: Union[bool, None] = None # Only for subclasses to set. - def __init__(self, option_type: BaseConfigOption[T], default: List[T] = []): + def __init__(self, option_type: BaseConfigOption[T], default=None): super().__init__() self.default = default self.option_type = option_type @@ -153,11 +153,14 @@ class ListOfItems(Generic[T], BaseConfigOption[List[T]]): self._key_name = key_name def run_validation(self, value): - if value is None and not self.required: - return self.default - + if value is None: + if self.required or self.default is None: + raise ValidationError("Required configuration not provided.") + value = self.default if not isinstance(value, list): raise ValidationError(f'Expected a list of items, but a {type(value)} was given.') + if not value: # Optimization for empty list + return value fake_config = Config(()) try: @@ -198,7 +201,7 @@ class ConfigItems(ListOfItems[LegacyConfig]): ... def __init__(self, *config_options: PlainConfigSchemaItem, required=None): - super().__init__(SubConfig(*config_options)) + super().__init__(SubConfig(*config_options), default=[]) self._legacy_required = required self.required = bool(required) diff --git a/mkdocs/tests/config/config_options_tests.py b/mkdocs/tests/config/config_options_tests.py index 0f795d4c..221ddb60 100644 --- a/mkdocs/tests/config/config_options_tests.py +++ b/mkdocs/tests/config/config_options_tests.py @@ -606,7 +606,7 @@ class ListOfItemsTest(TestCase): def test_list_default(self): class Schema: - option = c.ListOfItems(c.Type(int)) + option = c.ListOfItems(c.Type(int), default=[]) conf = self.get_config(Schema, {}) self.assertEqual(conf['option'], []) @@ -614,15 +614,15 @@ class ListOfItemsTest(TestCase): conf = self.get_config(Schema, {'option': None}) self.assertEqual(conf['option'], []) - def test_none_default(self): + def test_none_without_default(self): class Schema: - option = c.ListOfItems(c.Type(str), default=None) + option = c.ListOfItems(c.Type(str)) - conf = self.get_config(Schema, {}) - self.assertEqual(conf['option'], None) + with self.expect_error(option="Required configuration not provided."): + conf = self.get_config(Schema, {}) - conf = self.get_config(Schema, {'option': None}) - self.assertEqual(conf['option'], None) + with self.expect_error(option="Required configuration not provided."): + conf = self.get_config(Schema, {'option': None}) conf = self.get_config(Schema, {'option': ['foo']}) self.assertEqual(conf['option'], ['foo']) @@ -1279,7 +1279,8 @@ class ConfigItemsTest(TestCase): c.SubConfig( ('opt', c.Type(int)), validate=True, - ) + ), + default=[], ) conf = self.get_config(Schema, {}) @@ -1305,11 +1306,11 @@ class ConfigItemsTest(TestCase): ) ) - conf = self.get_config(Schema, {}) - self.assertEqual(conf['sub'], []) + with self.expect_error(sub="Required configuration not provided."): + conf = self.get_config(Schema, {}) - conf = self.get_config(Schema, {'sub': None}) - self.assertEqual(conf['sub'], []) + with self.expect_error(sub="Required configuration not provided."): + conf = self.get_config(Schema, {'sub': None}) with self.expect_error( sub="Sub-option 'opt' configuration error: Expected type: but received: "