Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions mkdocs/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,17 +232,15 @@ def callback(ctx, param, value):
),
)

PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}"

PKG_DIR = os.path.dirname(os.path.abspath(__file__))


@click.group(context_settings=dict(help_option_names=['-h', '--help'], max_content_width=120))
@click.version_option(
__version__,
'-V',
'--version',
message=f'%(prog)s, version %(version)s from { PKG_DIR } (Python { PYTHON_VERSION })',
message='%(version)s',
)
@common_options
@color_option
Expand Down
26 changes: 23 additions & 3 deletions mkdocs/config/config_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,26 @@
log = logging.getLogger(__name__)


def _required_config_error_message(option, key_fallback="value"):
missing_key = (
getattr(option, "_name", None)
or getattr(option, "_key_name", None)
or key_fallback
)
example = f"{missing_key}: Example"
docs_url = (
"https://www.mkdocs.org/user-guide/configuration/#"
f"{missing_key}"
)
return (
"Required configuration not provided. "
f"Missing key: {missing_key}. "
f"Example: {example}. "
f"See {docs_url}"
)



class SubConfig(Generic[SomeConfig], BaseConfigOption[SomeConfig]):
"""
Subconfig Config Option.
Expand Down Expand Up @@ -181,7 +201,7 @@ def validate(self, value):
elif not self.required:
return None
elif self.required:
raise ValidationError("Required configuration not provided.")
raise ValidationError(_required_config_error_message(self))

return self.run_validation(value)

Expand Down Expand Up @@ -211,7 +231,7 @@ def pre_validation(self, config: Config, key_name: str):
def run_validation(self, value: object) -> list[T]:
if value is None:
if self.required or self.default is None:
raise ValidationError("Required configuration not provided.")
raise ValidationError(_required_config_error_message(self))
value = self.default
if not isinstance(value, list):
raise ValidationError(f'Expected a list of items, but a {type(value)} was given.')
Expand Down Expand Up @@ -266,7 +286,7 @@ def pre_validation(self, config: Config, key_name: str):
def run_validation(self, value: object) -> dict[str, T]:
if value is None:
if self.required or self.default is None:
raise ValidationError("Required configuration not provided.")
raise ValidationError(_required_config_error_message(self))
value = self.default
if not isinstance(value, dict):
raise ValidationError(f"Expected a dict of items, but a {type(value)} was given.")
Expand Down
7 changes: 7 additions & 0 deletions mkdocs/tests/cli_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@
from click.testing import CliRunner

from mkdocs import __main__ as cli
from mkdocs import __version__


class CLITests(unittest.TestCase):
def setUp(self):
self.runner = CliRunner()

def test_version(self):
result = self.runner.invoke(cli.cli, ["--version"], catch_exceptions=False)

self.assertEqual(result.exit_code, 0)
self.assertEqual(result.output.strip(), __version__)

@mock.patch('mkdocs.commands.serve.serve', autospec=True)
def test_serve_default(self, mock_serve):
result = self.runner.invoke(cli.cli, ["serve"], catch_exceptions=False)
Expand Down
4 changes: 2 additions & 2 deletions mkdocs/tests/config/base_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def test_missing_required(self):
errors, warnings = conf.validate()

self.assertEqual(
errors, [('site_name', ValidationError('Required configuration not provided.'))]
errors, [('site_name', ValidationError('Required configuration not provided. Missing key: site_name. Example: site_name: Example. See https://www.mkdocs.org/user-guide/configuration/#site_name'))]
)
self.assertEqual(warnings, [])

Expand Down Expand Up @@ -137,7 +137,7 @@ def test_load_missing_required(self, temp_dir):
base.load_config(config_file=config_file.name)
self.assertEqual(
'\n'.join(cm.output),
"ERROR:mkdocs.config:Config value 'site_name': Required configuration not provided.",
"ERROR:mkdocs.config:Config value 'site_name': Required configuration not provided. Missing key: site_name. Example: site_name: Example. See https://www.mkdocs.org/user-guide/configuration/#site_name",
)

def test_pre_validation_error(self):
Expand Down
12 changes: 6 additions & 6 deletions mkdocs/tests/config/config_options_legacy_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def test_required(self):
class Schema:
option = c.OptionallyRequired(required=True)

with self.expect_error(option="Required configuration not provided."):
with self.expect_error(option="Required configuration not provided. Missing key: option. Example: option: Example. See https://www.mkdocs.org/user-guide/configuration/#option"):
self.get_config(Schema, {'option': None})

self.assertEqual(Schema.option.required, True)
Expand Down Expand Up @@ -439,7 +439,7 @@ def test_invalid_url(self):
class Schema:
option = c.URL(required=True)

with self.expect_error(option="Required configuration not provided."):
with self.expect_error(option="Required configuration not provided. Missing key: option. Example: option: Example. See https://www.mkdocs.org/user-guide/configuration/#option"):
self.get_config(Schema, {'option': None})

for url in "www.mkdocs.org", "//mkdocs.org/test", "http:/mkdocs.org/", "/hello/":
Expand Down Expand Up @@ -624,10 +624,10 @@ def test_none_without_default(self):
class Schema:
option = c.ListOfItems(c.Type(str))

with self.expect_error(option="Required configuration not provided."):
with self.expect_error(option="Required configuration not provided. Missing key: option. Example: option: Example. See https://www.mkdocs.org/user-guide/configuration/#option"):
conf = self.get_config(Schema, {})

with self.expect_error(option="Required configuration not provided."):
with self.expect_error(option="Required configuration not provided. Missing key: option. Example: option: Example. See https://www.mkdocs.org/user-guide/configuration/#option"):
conf = self.get_config(Schema, {'option': None})

conf = self.get_config(Schema, {'option': ['foo']})
Expand Down Expand Up @@ -1321,10 +1321,10 @@ class Schema:
)
)

with self.expect_error(sub="Required configuration not provided."):
with self.expect_error(sub="Required configuration not provided. Missing key: sub. Example: sub: Example. See https://www.mkdocs.org/user-guide/configuration/#sub"):
conf = self.get_config(Schema, {})

with self.expect_error(sub="Required configuration not provided."):
with self.expect_error(sub="Required configuration not provided. Missing key: sub. Example: sub: Example. See https://www.mkdocs.org/user-guide/configuration/#sub"):
conf = self.get_config(Schema, {'sub': None})

with self.expect_error(
Expand Down
26 changes: 13 additions & 13 deletions mkdocs/tests/config/config_options_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ def test_invalid_url(self) -> None:
class Schema(Config):
option = c.URL()

with self.expect_error(option="Required configuration not provided."):
with self.expect_error(option="Required configuration not provided. Missing key: option. Example: option: Example. See https://www.mkdocs.org/user-guide/configuration/#option"):
self.get_config(Schema, {'option': None})

for url in "www.mkdocs.org", "//mkdocs.org/test", "http:/mkdocs.org/", "/hello/":
Expand Down Expand Up @@ -612,17 +612,17 @@ class Schema(Config):
assert_type(conf.option, List[int])
self.assertEqual(conf.option, [])

with self.expect_error(option="Required configuration not provided."):
with self.expect_error(option="Required configuration not provided. Missing key: option. Example: option: Example. See https://www.mkdocs.org/user-guide/configuration/#option"):
conf = self.get_config(Schema, {'option': None})

def test_none_without_default(self) -> None:
class Schema(Config):
option = c.ListOfItems(c.Type(str))

with self.expect_error(option="Required configuration not provided."):
with self.expect_error(option="Required configuration not provided. Missing key: option. Example: option: Example. See https://www.mkdocs.org/user-guide/configuration/#option"):
conf = self.get_config(Schema, {})

with self.expect_error(option="Required configuration not provided."):
with self.expect_error(option="Required configuration not provided. Missing key: option. Example: option: Example. See https://www.mkdocs.org/user-guide/configuration/#option"):
conf = self.get_config(Schema, {'option': None})

conf = self.get_config(Schema, {'option': ['foo']})
Expand Down Expand Up @@ -778,17 +778,17 @@ class Schema(Config):
assert_type(conf.option, Dict[str, int])
self.assertEqual(conf.option, {})

with self.expect_error(option="Required configuration not provided."):
with self.expect_error(option="Required configuration not provided. Missing key: option. Example: option: Example. See https://www.mkdocs.org/user-guide/configuration/#option"):
conf = self.get_config(Schema, {'option': None})

def test_none_without_default(self) -> None:
class Schema(Config):
option = c.DictOfItems(c.Type(str))

with self.expect_error(option="Required configuration not provided."):
with self.expect_error(option="Required configuration not provided. Missing key: option. Example: option: Example. See https://www.mkdocs.org/user-guide/configuration/#option"):
conf = self.get_config(Schema, {})

with self.expect_error(option="Required configuration not provided."):
with self.expect_error(option="Required configuration not provided. Missing key: option. Example: option: Example. See https://www.mkdocs.org/user-guide/configuration/#option"):
conf = self.get_config(Schema, {'option': None})

conf = self.get_config(Schema, {'option': {"foo": "bar"}})
Expand Down Expand Up @@ -1021,7 +1021,7 @@ def test_none(self) -> None:
class Schema(Config):
option = c.ListOfPaths()

with self.expect_error(option="Required configuration not provided."):
with self.expect_error(option="Required configuration not provided. Missing key: option. Example: option: Example. See https://www.mkdocs.org/user-guide/configuration/#option"):
self.get_config(Schema, {'option': None})

def test_non_list(self) -> None:
Expand Down Expand Up @@ -1496,10 +1496,10 @@ class Sub(Config):
class Schema(Config):
sub = c.ListOfItems(c.SubConfig(Sub))

with self.expect_error(sub="Required configuration not provided."):
with self.expect_error(sub="Required configuration not provided. Missing key: sub. Example: sub: Example. See https://www.mkdocs.org/user-guide/configuration/#sub"):
conf = self.get_config(Schema, {})

with self.expect_error(sub="Required configuration not provided."):
with self.expect_error(sub="Required configuration not provided. Missing key: sub. Example: sub: Example. See https://www.mkdocs.org/user-guide/configuration/#sub"):
conf = self.get_config(Schema, {'sub': None})

with self.expect_error(
Expand Down Expand Up @@ -1542,7 +1542,7 @@ class Schema(Config):
assert_type(conf.sub, List[Sub])
self.assertEqual(conf.sub, [])

with self.expect_error(sub="Required configuration not provided."):
with self.expect_error(sub="Required configuration not provided. Missing key: sub. Example: sub: Example. See https://www.mkdocs.org/user-guide/configuration/#sub"):
conf = self.get_config(Schema, {'sub': None})

def test_config_file_path_pass_through(self) -> None:
Expand Down Expand Up @@ -2409,9 +2409,9 @@ class B(A):
assert_type(conf.baz, List[str])
self.assertEqual(conf.baz, ['b'])

with self.expect_error(baz="Required configuration not provided."):
with self.expect_error(baz="Required configuration not provided. Missing key: baz. Example: baz: Example. See https://www.mkdocs.org/user-guide/configuration/#baz"):
self.get_config(B, {'foo': 1})
with self.expect_error(foo="Required configuration not provided."):
with self.expect_error(foo="Required configuration not provided. Missing key: foo. Example: foo: Example. See https://www.mkdocs.org/user-guide/configuration/#foo"):
self.get_config(B, {'baz': ['b']})

bconf = self.get_config(A, {'foo': 2, 'bar': 'a'})
Expand Down
2 changes: 1 addition & 1 deletion mkdocs/tests/config/config_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def test_missing_site_name(self):
conf.load_dict({})
errors, warnings = conf.validate()
self.assertEqual(
errors, [('site_name', ValidationError("Required configuration not provided."))]
errors, [('site_name', ValidationError("Required configuration not provided. Missing key: site_name. Example: site_name: Example. See https://www.mkdocs.org/user-guide/configuration/#site_name"))]
)
self.assertEqual(warnings, [])

Expand Down
Loading