From be7c749fe861c7660b1b1ab978d12cc969e74321 Mon Sep 17 00:00:00 2001 From: Oleh Prypin Date: Mon, 16 Mar 2026 22:28:20 +0100 Subject: [PATCH] Add a warning in case the theme is not specified in the config In MkDocs this used to be 'mkdocs' and it was included in the package. Here it still defaults to 'mkdocs' but is *not* included in the package. Now it also prints a warning when no 'theme:' config is specified. --- properdocs/config/config_options.py | 20 +++++++++++++++++++- properdocs/config/defaults.py | 2 +- properdocs/tests/base.py | 4 ++-- properdocs/tests/build_tests.py | 1 + properdocs/tests/config/base_tests.py | 24 ++++++++++++++++-------- properdocs/tests/config/config_tests.py | 20 ++++++++++++++++++-- properdocs/tests/structure/page_tests.py | 1 + 7 files changed, 58 insertions(+), 14 deletions(-) diff --git a/properdocs/config/config_options.py b/properdocs/config/config_options.py index 952efe49..d16faea7 100644 --- a/properdocs/config/config_options.py +++ b/properdocs/config/config_options.py @@ -814,7 +814,10 @@ def run_validation(self, value: object) -> theme.Theme: if theme_config['name'] is not None and theme_config['name'] not in themes: message = f"Unrecognised theme name: '{theme_config['name']}'." if theme_config['name'] in ('mkdocs', 'readthedocs'): - message += f"\nAdditional dependency is needed:\n pip install properdocs-theme-{theme_config['name']}" + message += ( + f"\nAn additional dependency is needed:" + f"\n pip install properdocs-theme-{theme_config['name']}" + ) elif themes: message += f" The available installed themes are: {', '.join(themes)}" else: @@ -842,6 +845,21 @@ def run_validation(self, value: object) -> theme.Theme: return theme.Theme(**theme_config) +class ProperDocsTheme(Theme): + def run_validation(self, value: object) -> theme.Theme: + if value is None: + value = 'mkdocs' + if self.config_file_path: + config_file_name = repr(os.path.basename(self.config_file_path)) + else: + config_file_name = "the configuration file" + log.warning( + f"Please select a theme explicitly in {config_file_name}." + " Defaulted to 'theme: mkdocs', but this may change in the future." + ) + return super().run_validation(value) + + class Nav(OptionallyRequired): """ Nav Config Option. diff --git a/properdocs/config/defaults.py b/properdocs/config/defaults.py index db1f6956..a257a165 100644 --- a/properdocs/config/defaults.py +++ b/properdocs/config/defaults.py @@ -71,7 +71,7 @@ class ProperDocsConfig(base.Config): site_author = c.Optional(c.Type(str)) """The name of the author to add to the HTML meta tags.""" - theme = c.Theme(default='mkdocs') + theme = c.ProperDocsTheme() """The ProperDocs theme for the documentation.""" docs_dir = c.DocsDir(default='docs', exists=True) diff --git a/properdocs/tests/base.py b/properdocs/tests/base.py index 3e6fe14e..d1be0ccb 100644 --- a/properdocs/tests/base.py +++ b/properdocs/tests/base.py @@ -26,8 +26,8 @@ def get_markdown_toc(markdown_source): def load_config(config_file_path: str | None = None, **cfg) -> ProperDocsConfig: """Helper to build a simple config for testing.""" path_base = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'integration', 'minimal') - if 'site_name' not in cfg: - cfg['site_name'] = 'Example' + cfg.setdefault('site_name', 'Example') + cfg.setdefault('theme', 'mkdocs') if 'docs_dir' not in cfg: # Point to an actual dir to avoid a 'does not exist' error on validation. cfg['docs_dir'] = os.path.join(path_base, 'docs') diff --git a/properdocs/tests/build_tests.py b/properdocs/tests/build_tests.py index 07cf45e4..9058b951 100644 --- a/properdocs/tests/build_tests.py +++ b/properdocs/tests/build_tests.py @@ -909,6 +909,7 @@ def test_markdown_extension_with_relative(self, config_dir): with self.subTest(base_path=base_path): cfg = f''' site_name: test + theme: mkdocs use_directory_urls: false markdown_extensions: - properdocs.tests.build_tests: diff --git a/properdocs/tests/config/base_tests.py b/properdocs/tests/config/base_tests.py index 42c3eea7..2463daaf 100644 --- a/properdocs/tests/config/base_tests.py +++ b/properdocs/tests/config/base_tests.py @@ -46,7 +46,7 @@ def test_load_from_file(self, temp_dir): Allows users to specify a config other than the default `properdocs.yml`. """ with open(os.path.join(temp_dir, 'properdocs.yml'), 'w') as config_file: - config_file.write("site_name: ProperDocs Test\n") + config_file.write("site_name: ProperDocs Test\ntheme: mkdocs\n") os.mkdir(os.path.join(temp_dir, 'docs')) cfg = base.load_config(config_file=config_file.name) @@ -57,7 +57,7 @@ def test_load_from_file(self, temp_dir): def test_load_default_file(self, temp_dir): """Test that `properdocs.yml` will be loaded when '--config' is not set.""" with open(os.path.join(temp_dir, 'properdocs.yml'), 'w') as config_file: - config_file.write("site_name: ProperDocs Test\n") + config_file.write("site_name: ProperDocs Test\ntheme: mkdocs\n") os.mkdir(os.path.join(temp_dir, 'docs')) with change_dir(temp_dir): cfg = base.load_config(config_file=None) @@ -68,7 +68,7 @@ def test_load_default_file(self, temp_dir): def test_load_default_file_with_yaml(self, temp_dir): """Test that `properdocs.yml` will be loaded when '--config' is not set.""" with open(os.path.join(temp_dir, 'properdocs.yaml'), 'w') as config_file: - config_file.write("site_name: ProperDocs Test\n") + config_file.write("site_name: ProperDocs Test\ntheme: mkdocs\n") os.mkdir(os.path.join(temp_dir, 'docs')) with change_dir(temp_dir): cfg = base.load_config(config_file=None) @@ -79,9 +79,9 @@ def test_load_default_file_with_yaml(self, temp_dir): def test_load_default_file_prefer_yml(self, temp_dir): """Test that `properdocs.yml` will be loaded when '--config' is not set.""" with open(os.path.join(temp_dir, 'properdocs.yml'), 'w') as config_file1: - config_file1.write("site_name: ProperDocs Test1\n") + config_file1.write("site_name: ProperDocs Test1\ntheme: mkdocs\n") with open(os.path.join(temp_dir, 'properdocs.yaml'), 'w') as config_file2: - config_file2.write("site_name: ProperDocs Test2\n") + config_file2.write("site_name: ProperDocs Test2\ntheme: mkdocs\n") os.mkdir(os.path.join(temp_dir, 'docs')) with change_dir(temp_dir): @@ -104,7 +104,15 @@ def test_load_from_open_file(self, temp_path): config_file.flush() os.mkdir(os.path.join(temp_path, 'docs')) - cfg = base.load_config(config_file=config_file) + with self.assertLogs('properdocs') as cm: + cfg = base.load_config(config_file=config_file) + self.assertEqual( + cm.output, + [ + "WARNING:properdocs.config.config_options:Please select a theme explicitly in 'properdocs.yml'. Defaulted to 'theme: mkdocs', but this may change in the future." + ], + ) + self.assertTrue(isinstance(cfg, defaults.ProperDocsConfig)) self.assertEqual(cfg.site_name, 'ProperDocs Test') # load_config will always close the file @@ -117,7 +125,7 @@ def test_load_from_closed_file(self, temp_dir): Ensure `load_config` reloads the closed file. """ with open(os.path.join(temp_dir, 'properdocs.yml'), 'w') as config_file: - config_file.write("site_name: ProperDocs Test\n") + config_file.write("site_name: ProperDocs Test\ntheme: mkdocs\n") os.mkdir(os.path.join(temp_dir, 'docs')) cfg = base.load_config(config_file=config_file) @@ -248,7 +256,7 @@ def test_load_from_file_with_relative_paths(self, config_dir): """ config_fname = os.path.join(config_dir, 'properdocs.yml') with open(config_fname, 'w') as config_file: - config_file.write("docs_dir: src\nsite_name: ProperDocs Test\n") + config_file.write("docs_dir: src\nsite_name: ProperDocs Test\ntheme: mkdocs\n") docs_dir = os.path.join(config_dir, 'src') os.mkdir(docs_dir) diff --git a/properdocs/tests/config/config_tests.py b/properdocs/tests/config/config_tests.py index b0358b17..4706cf82 100644 --- a/properdocs/tests/config/config_tests.py +++ b/properdocs/tests/config/config_tests.py @@ -29,13 +29,27 @@ def test_missing_config_file(self): def test_missing_site_name(self): conf = defaults.ProperDocsConfig() - conf.load_dict({}) + conf.load_dict({'theme': 'mkdocs'}) errors, warnings = conf.validate() self.assertEqual( errors, [('site_name', ValidationError("Required configuration not provided."))] ) self.assertEqual(warnings, []) + def test_missing_theme(self): + conf = defaults.ProperDocsConfig(config_file_path='a.yml') + conf.load_dict({'site_name': 'Example'}) + with self.assertLogs('properdocs') as cm: + errors, warnings = conf.validate() + self.assertEqual(errors, []) + self.assertEqual(warnings, []) + self.assertEqual( + cm.output, + [ + "WARNING:properdocs.config.config_options:Please select a theme explicitly in 'a.yml'. Defaulted to 'theme: mkdocs', but this may change in the future." + ], + ) + def test_nonexistant_config(self): with self.assertRaises(ConfigurationError): config.load_config(config_file='/path/that/is/not/real') @@ -69,6 +83,7 @@ def test_config_option(self, temp_path): file_contents = dedent( """ site_name: Example + theme: mkdocs nav: - 'Introduction': 'index.md' """ @@ -235,7 +250,7 @@ def test_empty_nav(self): conf = defaults.ProperDocsConfig( config_file_path=os.path.join(os.path.abspath('.'), 'properdocs.yml') ) - conf.load_dict({'site_name': 'Example'}) + conf.load_dict({'site_name': 'Example', 'theme': 'mkdocs'}) conf.validate() self.assertEqual(conf['nav'], None) @@ -244,6 +259,7 @@ def test_error_on_pages(self): conf.load_dict( { 'site_name': 'Example', + 'theme': 'mkdocs', 'pages': ['index.md', 'about.md'], } ) diff --git a/properdocs/tests/structure/page_tests.py b/properdocs/tests/structure/page_tests.py index 6c58385f..4d6810e9 100644 --- a/properdocs/tests/structure/page_tests.py +++ b/properdocs/tests/structure/page_tests.py @@ -20,6 +20,7 @@ def load_config(**cfg) -> ProperDocsConfig: cfg.setdefault('site_name', 'Example') + cfg.setdefault('theme', 'mkdocs') cfg.setdefault( 'docs_dir', os.path.join(