From 1ab0a9f84be910b63c58594f1dd973116748adee Mon Sep 17 00:00:00 2001 From: Oleh Prypin Date: Sat, 20 Aug 2022 23:01:52 +0200 Subject: [PATCH] Use attribute-based access from MkDocsConfig --- mkdocs/commands/build.py | 54 ++++++++++++++-------------- mkdocs/commands/gh_deploy.py | 12 +++---- mkdocs/commands/serve.py | 22 ++++++------ mkdocs/contrib/search/__init__.py | 31 ++++++++-------- mkdocs/structure/files.py | 8 ++--- mkdocs/tests/build_tests.py | 6 ++-- mkdocs/tests/plugin_tests.py | 4 +-- mkdocs/tests/search_tests.py | 12 +++---- mkdocs/tests/structure/file_tests.py | 2 +- 9 files changed, 72 insertions(+), 79 deletions(-) diff --git a/mkdocs/commands/build.py b/mkdocs/commands/build.py index a1bc9b9f..60716656 100644 --- a/mkdocs/commands/build.py +++ b/mkdocs/commands/build.py @@ -48,9 +48,9 @@ def get_context( if page is not None: base_url = utils.get_relative_url('.', page.url) - extra_javascript = utils.create_media_urls(config['extra_javascript'], page, base_url) + extra_javascript = utils.create_media_urls(config.extra_javascript, page, base_url) - extra_css = utils.create_media_urls(config['extra_css'], page, base_url) + extra_css = utils.create_media_urls(config.extra_css, page, base_url) if isinstance(files, Files): files = files.documentation_pages() @@ -75,9 +75,7 @@ def _build_template( Return rendered output for given template as a string. """ # Run `pre_template` plugin events. - template = config['plugins'].run_event( - 'pre_template', template, template_name=name, config=config - ) + template = config.plugins.run_event('pre_template', template, template_name=name, config=config) if utils.is_error_template(name): # Force absolute URLs in the nav of error pages and account for the @@ -85,21 +83,21 @@ def _build_template( # See https://github.com/mkdocs/mkdocs/issues/77. # However, if site_url is not set, assume the docs root and server root # are the same. See https://github.com/mkdocs/mkdocs/issues/1598. - base_url = urlsplit(config['site_url'] or '/').path + base_url = urlsplit(config.site_url or '/').path else: base_url = utils.get_relative_url('.', name) context = get_context(nav, files, config, base_url=base_url) # Run `template_context` plugin events. - context = config['plugins'].run_event( + context = config.plugins.run_event( 'template_context', context, template_name=name, config=config ) output = template.render(context) # Run `post_template` plugin events. - output = config['plugins'].run_event('post_template', output, template_name=name, config=config) + output = config.plugins.run_event('post_template', output, template_name=name, config=config) return output @@ -120,7 +118,7 @@ def _build_theme_template( output = _build_template(template_name, template, files, config, nav) if output.strip(): - output_path = os.path.join(config['site_dir'], template_name) + output_path = os.path.join(config.site_dir, template_name) utils.write_file(output.encode('utf-8'), output_path) if template_name == 'sitemap.xml': @@ -171,19 +169,19 @@ def _populate_page(page: Page, config: MkDocsConfig, files: Files, dirty: bool = return # Run the `pre_page` plugin event - page = config['plugins'].run_event('pre_page', page, config=config, files=files) + page = config.plugins.run_event('pre_page', page, config=config, files=files) page.read_source(config) # Run `page_markdown` plugin events. - page.markdown = config['plugins'].run_event( + page.markdown = config.plugins.run_event( 'page_markdown', page.markdown, page=page, config=config, files=files ) page.render(config, files) # Run `page_content` plugin events. - page.content = config['plugins'].run_event( + page.content = config.plugins.run_event( 'page_content', page.content, page=page, config=config, files=files ) except Exception as e: @@ -225,7 +223,7 @@ def _build_page( template = env.get_template('main.html') # Run `page_context` plugin events. - context = config['plugins'].run_event( + context = config.plugins.run_event( 'page_context', context, page=page, config=config, nav=nav ) @@ -233,7 +231,7 @@ def _build_page( output = template.render(context) # Run `post_page` plugin events. - output = config['plugins'].run_event('post_page', output, page=page, config=config) + output = config.plugins.run_event('post_page', output, page=page, config=config) # Write the output file. if output.strip(): @@ -262,21 +260,21 @@ def build(config: MkDocsConfig, live_server: bool = False, dirty: bool = False) # Add CountHandler for strict mode warning_counter = utils.CountHandler() warning_counter.setLevel(logging.WARNING) - if config['strict']: + if config.strict: logging.getLogger('mkdocs').addHandler(warning_counter) try: start = time.monotonic() # Run `config` plugin events. - config = config['plugins'].run_event('config', config) + config = config.plugins.run_event('config', config) # Run `pre_build` plugin events. - config['plugins'].run_event('pre_build', config=config) + config.plugins.run_event('pre_build', config=config) if not dirty: log.info("Cleaning site directory") - utils.clean_directory(config['site_dir']) + utils.clean_directory(config.site_dir) else: # pragma: no cover # Warn user about problems that may occur with --dirty option log.warning( @@ -285,23 +283,23 @@ def build(config: MkDocsConfig, live_server: bool = False, dirty: bool = False) ) if not live_server: # pragma: no cover - log.info(f"Building documentation to directory: {config['site_dir']}") - if dirty and site_directory_contains_stale_files(config['site_dir']): + log.info(f"Building documentation to directory: {config.site_dir}") + if dirty and site_directory_contains_stale_files(config.site_dir): log.info("The directory contains stale files. Use --clean to remove them.") # First gather all data from all files/pages to ensure all data is consistent across all pages. files = get_files(config) - env = config['theme'].get_env() + env = config.theme.get_env() files.add_files_from_theme(env, config) # Run `files` plugin events. - files = config['plugins'].run_event('files', files, config=config) + files = config.plugins.run_event('files', files, config=config) nav = get_navigation(files, config) # Run `nav` plugin events. - nav = config['plugins'].run_event('nav', nav, config=config, files=files) + nav = config.plugins.run_event('nav', nav, config=config, files=files) log.debug("Reading markdown pages.") for file in files.documentation_pages(): @@ -310,7 +308,7 @@ def build(config: MkDocsConfig, live_server: bool = False, dirty: bool = False) _populate_page(file.page, config, files, dirty) # Run `env` plugin events. - env = config['plugins'].run_event('env', env, config=config, files=files) + env = config.plugins.run_event('env', env, config=config, files=files) # Start writing files to site_dir now that all data is gathered. Note that order matters. Files # with lower precedence get written first so that files with higher precedence can overwrite them. @@ -318,10 +316,10 @@ def build(config: MkDocsConfig, live_server: bool = False, dirty: bool = False) log.debug("Copying static assets.") files.copy_static_files(dirty=dirty) - for template in config['theme'].static_templates: + for template in config.theme.static_templates: _build_theme_template(template, env, files, config, nav) - for template in config['extra_templates']: + for template in config.extra_templates: _build_extra_template(template, files, config, nav) log.debug("Building markdown pages.") @@ -331,7 +329,7 @@ def build(config: MkDocsConfig, live_server: bool = False, dirty: bool = False) _build_page(file.page, config, doc_files, nav, env, dirty) # Run `post_build` plugin events. - config['plugins'].run_event('post_build', config=config) + config.plugins.run_event('post_build', config=config) counts = warning_counter.get_counts() if counts: @@ -342,7 +340,7 @@ def build(config: MkDocsConfig, live_server: bool = False, dirty: bool = False) except Exception as e: # Run `build_error` plugin events. - config['plugins'].run_event('build_error', error=e) + config.plugins.run_event('build_error', error=e) if isinstance(e, BuildError): log.error(str(e)) raise Abort('\nAborted with a BuildError!') diff --git a/mkdocs/commands/gh_deploy.py b/mkdocs/commands/gh_deploy.py index f8070468..5707d82a 100644 --- a/mkdocs/commands/gh_deploy.py +++ b/mkdocs/commands/gh_deploy.py @@ -106,8 +106,8 @@ def gh_deploy( if not _is_cwd_git_repo(): log.error('Cannot deploy - this directory does not appear to be a git repository') - remote_branch = config['remote_branch'] - remote_name = config['remote_name'] + remote_branch = config.remote_branch + remote_name = config.remote_name if not ignore_version: _check_version(remote_branch) @@ -119,13 +119,13 @@ def gh_deploy( log.info( "Copying '%s' to '%s' branch and pushing to GitHub.", - config['site_dir'], - config['remote_branch'], + config.site_dir, + config.remote_branch, ) try: ghp_import.ghp_import( - config['site_dir'], + config.site_dir, mesg=message, remote=remote_name, branch=remote_branch, @@ -139,7 +139,7 @@ def gh_deploy( log.error(f"Failed to deploy to GitHub with error: \n{e.message}") raise Abort('Deployment Aborted!') - cname_file = os.path.join(config['site_dir'], 'CNAME') + cname_file = os.path.join(config.site_dir, 'CNAME') # Does this repository have a CNAME set for GitHub pages? if os.path.isfile(cname_file): # This GitHub pages repository has a CNAME configured. diff --git a/mkdocs/commands/serve.py b/mkdocs/commands/serve.py index 9577f19a..1d3935bc 100644 --- a/mkdocs/commands/serve.py +++ b/mkdocs/commands/serve.py @@ -42,7 +42,7 @@ def serve( site_dir = tempfile.mkdtemp(prefix='mkdocs_') def mount_path(config: MkDocsConfig): - return urlsplit(config['site_url'] or '/').path + return urlsplit(config.site_url or '/').path get_config = functools.partial( load_config, @@ -64,13 +64,13 @@ def serve( config = get_config() # combine CLI watch arguments with config file values - if config["watch"] is None: - config["watch"] = watch + if config.watch is None: + config.watch = watch else: - config["watch"].extend(watch) + config.watch.extend(watch) # Override a few config settings after validation - config['site_url'] = 'http://{}{}'.format(config['dev_addr'], mount_path(config)) + config.site_url = f'http://{config.dev_addr}{mount_path(config)}' build(config, live_server=live_server, dirty=dirty) @@ -81,7 +81,7 @@ def serve( # Perform the initial build builder(config) - host, port = config['dev_addr'] + host, port = config.dev_addr server = LiveReloadServer( builder=builder, host=host, port=port, root=site_dir, mount_path=mount_path(config) ) @@ -97,17 +97,17 @@ def serve( if live_server: # Watch the documentation files, the config file and the theme files. - server.watch(config['docs_dir']) - server.watch(config['config_file_path']) + server.watch(config.docs_dir) + server.watch(config.config_file_path) if watch_theme: - for d in config['theme'].dirs: + for d in config.theme.dirs: server.watch(d) # Run `serve` plugin events. - server = config['plugins'].run_event('serve', server, config=config, builder=builder) + server = config.plugins.run_event('serve', server, config=config, builder=builder) - for item in config['watch']: + for item in config.watch: server.watch(item) try: diff --git a/mkdocs/contrib/search/__init__.py b/mkdocs/contrib/search/__init__.py index b24d48a7..481f44fb 100644 --- a/mkdocs/contrib/search/__init__.py +++ b/mkdocs/contrib/search/__init__.py @@ -61,20 +61,20 @@ class SearchPlugin(BasePlugin[_PluginConfig]): def on_config(self, config: MkDocsConfig, **kwargs) -> MkDocsConfig: "Add plugin templates and scripts to config." - if 'include_search_page' in config['theme'] and config['theme']['include_search_page']: - config['theme'].static_templates.add('search.html') - if not ('search_index_only' in config['theme'] and config['theme']['search_index_only']): + if 'include_search_page' in config.theme and config.theme['include_search_page']: + config.theme.static_templates.add('search.html') + if not ('search_index_only' in config.theme and config.theme['search_index_only']): path = os.path.join(base_path, 'templates') - config['theme'].dirs.append(path) - if 'search/main.js' not in config['extra_javascript']: - config['extra_javascript'].append('search/main.js') - if self.config['lang'] is None: + config.theme.dirs.append(path) + if 'search/main.js' not in config.extra_javascript: + config.extra_javascript.append('search/main.js') + if self.config.lang is None: # lang setting undefined. Set default based on theme locale validate = _PluginConfig.lang.run_validation - self.config['lang'] = validate(config['theme']['locale'].language) + self.config.lang = validate(config.theme['locale'].language) # The `python` method of `prebuild_index` is pending deprecation as of version 1.2. # TODO: Raise a deprecation warning in a future release (1.3?). - if self.config['prebuild_index'] == 'python': + if self.config.prebuild_index == 'python': log.info( "The 'python' method of the search plugin's 'prebuild_index' config option " "is pending deprecation and will not be supported in a future release." @@ -91,22 +91,23 @@ class SearchPlugin(BasePlugin[_PluginConfig]): def on_post_build(self, config: MkDocsConfig, **kwargs) -> None: "Build search index." - output_base_path = os.path.join(config['site_dir'], 'search') + output_base_path = os.path.join(config.site_dir, 'search') search_index = self.search_index.generate_search_index() json_output_path = os.path.join(output_base_path, 'search_index.json') utils.write_file(search_index.encode('utf-8'), json_output_path) - if not ('search_index_only' in config['theme'] and config['theme']['search_index_only']): + assert self.config.lang is not None + if not ('search_index_only' in config.theme and config.theme['search_index_only']): # Include language support files in output. Copy them directly # so that only the needed files are included. files = [] - if len(self.config['lang']) > 1 or 'en' not in self.config['lang']: + if len(self.config.lang) > 1 or 'en' not in self.config.lang: files.append('lunr.stemmer.support.js') - if len(self.config['lang']) > 1: + if len(self.config.lang) > 1: files.append('lunr.multi.js') - if 'ja' in self.config['lang'] or 'jp' in self.config['lang']: + if 'ja' in self.config.lang or 'jp' in self.config.lang: files.append('tinyseg.js') - for lang in self.config['lang']: + for lang in self.config.lang: if lang != 'en': files.append(f'lunr.{lang}.js') diff --git a/mkdocs/structure/files.py b/mkdocs/structure/files.py index 131590d3..e469c9e4 100644 --- a/mkdocs/structure/files.py +++ b/mkdocs/structure/files.py @@ -113,7 +113,7 @@ class Files: # Exclude translation files patterns.append("locales/*") patterns.extend(f'*{x}' for x in utils.markdown_extensions) - patterns.extend(config['theme'].static_templates) + patterns.extend(config.theme.static_templates) for pattern in patterns: if fnmatch.fnmatch(name.lower(), pattern): return False @@ -123,12 +123,10 @@ class Files: # Theme files do not override docs_dir files path = PurePath(path).as_posix() if path not in self.src_uris: - for dir in config['theme'].dirs: + for dir in config.theme.dirs: # Find the first theme dir which contains path if os.path.isfile(os.path.join(dir, path)): - self.append( - File(path, dir, config['site_dir'], config['use_directory_urls']) - ) + self.append(File(path, dir, config.site_dir, config.use_directory_urls)) break diff --git a/mkdocs/tests/build_tests.py b/mkdocs/tests/build_tests.py index 3e649ef5..1861ba3b 100644 --- a/mkdocs/tests/build_tests.py +++ b/mkdocs/tests/build_tests.py @@ -15,9 +15,7 @@ from mkdocs.utils import meta def build_page(title, path, config, md_src=''): """Helper which returns a Page object.""" - files = Files( - [File(path, config['docs_dir'], config['site_dir'], config['use_directory_urls'])] - ) + files = Files([File(path, config.docs_dir, config.site_dir, config.use_directory_urls)]) page = Page(title, list(files)[0], config) # Fake page.read_source() page.markdown, page.meta = meta.get_data(md_src) @@ -26,7 +24,7 @@ def build_page(title, path, config, md_src=''): class BuildTests(PathAssertionMixin, unittest.TestCase): def _get_env_with_null_translations(self, config): - env = config['theme'].get_env() + env = config.theme.get_env() env.add_extension('jinja2.ext.i18n') env.install_null_translations() return env diff --git a/mkdocs/tests/plugin_tests.py b/mkdocs/tests/plugin_tests.py index 8027fce1..bd88bd98 100644 --- a/mkdocs/tests/plugin_tests.py +++ b/mkdocs/tests/plugin_tests.py @@ -25,7 +25,7 @@ class DummyPlugin(plugins.BasePlugin[_DummyPluginConfig]): def on_pre_page(self, content, **kwargs): """modify page content by prepending `foo` config value.""" - return f'{self.config["foo"]} {content}' + return f'{self.config.foo} {content}' def on_nav(self, item, **kwargs): """do nothing (return None) to not modify item.""" @@ -33,7 +33,7 @@ class DummyPlugin(plugins.BasePlugin[_DummyPluginConfig]): def on_page_read_source(self, **kwargs): """create new source by prepending `foo` config value to 'source'.""" - return f'{self.config["foo"]} source' + return f'{self.config.foo} source' def on_pre_build(self, **kwargs): """do nothing (return None).""" diff --git a/mkdocs/tests/search_tests.py b/mkdocs/tests/search_tests.py index e5d63258..ada861ca 100644 --- a/mkdocs/tests/search_tests.py +++ b/mkdocs/tests/search_tests.py @@ -168,7 +168,7 @@ class SearchPluginTests(unittest.TestCase): self.assertEqual(result['theme'].static_templates, {'404.html', 'sitemap.xml'}) self.assertEqual(len(result['theme'].dirs), 3) self.assertEqual(result['extra_javascript'], ['search/main.js']) - self.assertEqual(plugin.config['lang'], [result['theme']['locale'].language]) + self.assertEqual(plugin.config.lang, [result['theme']['locale'].language]) def test_event_on_config_lang(self): plugin = search.SearchPlugin() @@ -179,7 +179,7 @@ class SearchPluginTests(unittest.TestCase): self.assertEqual(result['theme'].static_templates, {'404.html', 'sitemap.xml'}) self.assertEqual(len(result['theme'].dirs), 3) self.assertEqual(result['extra_javascript'], ['search/main.js']) - self.assertEqual(plugin.config['lang'], ['es']) + self.assertEqual(plugin.config.lang, ['es']) def test_event_on_config_theme_locale(self): plugin = search.SearchPlugin() @@ -192,7 +192,7 @@ class SearchPluginTests(unittest.TestCase): self.assertEqual(result['theme'].static_templates, {'404.html', 'sitemap.xml'}) self.assertEqual(len(result['theme'].dirs), 3) self.assertEqual(result['extra_javascript'], ['search/main.js']) - self.assertEqual(plugin.config['lang'], [result['theme']['locale'].language]) + self.assertEqual(plugin.config.lang, [result['theme']['locale'].language]) def test_event_on_config_include_search_page(self): plugin = search.SearchPlugin() @@ -421,9 +421,7 @@ class SearchIndexTests(unittest.TestCase): def test_page(title, filename, config): test_page = Page( title, - File( - filename, config['docs_dir'], config['site_dir'], config['use_directory_urls'] - ), + File(filename, config.docs_dir, config.site_dir, config.use_directory_urls), config, ) test_page.content = """ @@ -479,7 +477,7 @@ class SearchIndexTests(unittest.TestCase): self.assertEqual(warnings, []) base_cfg = load_config() - base_cfg['plugins']['search'].config['indexing'] = option + base_cfg['plugins']['search'].config.indexing = option pages = [ test_page('Home', 'index.md', base_cfg), diff --git a/mkdocs/tests/structure/file_tests.py b/mkdocs/tests/structure/file_tests.py index 020da859..7f5fd1ee 100644 --- a/mkdocs/tests/structure/file_tests.py +++ b/mkdocs/tests/structure/file_tests.py @@ -389,7 +389,7 @@ class TestFiles(PathAssertionMixin, unittest.TestCase): ) def test_add_files_from_theme(self, tdir, ddir): config = load_config(docs_dir=ddir, theme={'name': None, 'custom_dir': tdir}) - env = config['theme'].get_env() + env = config.theme.get_env() files = get_files(config) self.assertEqual( [file.src_path for file in files],