mirror of
https://github.com/mkdocs/mkdocs.git
synced 2026-03-27 09:58:31 +07:00
Ensure each instance of Config is unique
Replace the global variable `mkdocs.config.DEFAULT_SCHEMA` with the function `mkdocs.config.defaults.get_schema()`. An instance is no longer created on import (eliminating circular imports under certain circumstances) and each call to `get_schema()` builds a new instance of each object. Fixes #2289.
This commit is contained in:
@@ -108,6 +108,10 @@ option. (#2092).
|
||||
The `mkdocs` theme now removes the sidebar when printing a page. This frees
|
||||
up horizontal space for better rendering of content like tables (#2193).
|
||||
|
||||
The `mkdocs.config.DEFAULT_SCHEMA` global variable has been replaced with the
|
||||
function `mkdocs.config.defaults.get_schema()`, which ensures that each
|
||||
instance of the configuration is unique (#2289).
|
||||
|
||||
### Other Changes and Additions to Version 1.2
|
||||
|
||||
* Bugfix: Properly process navigation child items in `_get_by_type` when
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
from mkdocs.config.base import load_config, Config
|
||||
from mkdocs.config.defaults import DEFAULT_SCHEMA
|
||||
|
||||
__all__ = [load_config.__name__,
|
||||
Config.__name__,
|
||||
'DEFAULT_SCHEMA']
|
||||
Config.__name__]
|
||||
|
||||
@@ -187,8 +187,8 @@ def load_config(config_file=None, **kwargs):
|
||||
options['config_file_path'] = getattr(config_file, 'name', '')
|
||||
|
||||
# Initialise the config with the default schema .
|
||||
from mkdocs import config
|
||||
cfg = Config(schema=config.DEFAULT_SCHEMA, config_file_path=options['config_file_path'])
|
||||
from mkdocs.config.defaults import get_schema
|
||||
cfg = Config(schema=get_schema(), config_file_path=options['config_file_path'])
|
||||
# First load the config file
|
||||
cfg.load_file(config_file)
|
||||
# Then load the options to overwrite anything in the config.
|
||||
|
||||
@@ -8,107 +8,109 @@ from mkdocs.config import config_options
|
||||
# isn't really needed either as we always sequentially process the schema other
|
||||
# than at initialisation when we grab the full set of keys for convenience.
|
||||
|
||||
DEFAULT_SCHEMA = (
|
||||
|
||||
# Reserved for internal use, stores the mkdocs.yml config file.
|
||||
('config_file_path', config_options.Type(str)),
|
||||
def get_schema():
|
||||
return (
|
||||
|
||||
# The title to use for the documentation
|
||||
('site_name', config_options.Type(str, required=True)),
|
||||
# Reserved for internal use, stores the mkdocs.yml config file.
|
||||
('config_file_path', config_options.Type(str)),
|
||||
|
||||
# Defines the structure of the navigation.
|
||||
('nav', config_options.Nav()),
|
||||
# TODO: remove this when the `pages` config setting is fully deprecated.
|
||||
('pages', config_options.Nav()),
|
||||
# The title to use for the documentation
|
||||
('site_name', config_options.Type(str, required=True)),
|
||||
|
||||
# The full URL to where the documentation will be hosted
|
||||
('site_url', config_options.URL()),
|
||||
# Defines the structure of the navigation.
|
||||
('nav', config_options.Nav()),
|
||||
# TODO: remove this when the `pages` config setting is fully deprecated.
|
||||
('pages', config_options.Nav()),
|
||||
|
||||
# A description for the documentation project that will be added to the
|
||||
# HTML meta tags.
|
||||
('site_description', config_options.Type(str)),
|
||||
# The name of the author to add to the HTML meta tags
|
||||
('site_author', config_options.Type(str)),
|
||||
# The full URL to where the documentation will be hosted
|
||||
('site_url', config_options.URL()),
|
||||
|
||||
# The MkDocs theme for the documentation.
|
||||
('theme', config_options.Theme(default='mkdocs')),
|
||||
# A description for the documentation project that will be added to the
|
||||
# HTML meta tags.
|
||||
('site_description', config_options.Type(str)),
|
||||
# The name of the author to add to the HTML meta tags
|
||||
('site_author', config_options.Type(str)),
|
||||
|
||||
# The directory containing the documentation markdown.
|
||||
('docs_dir', config_options.Dir(default='docs', exists=True)),
|
||||
# The MkDocs theme for the documentation.
|
||||
('theme', config_options.Theme(default='mkdocs')),
|
||||
|
||||
# The directory where the site will be built to
|
||||
('site_dir', config_options.SiteDir(default='site')),
|
||||
# The directory containing the documentation markdown.
|
||||
('docs_dir', config_options.Dir(default='docs', exists=True)),
|
||||
|
||||
# A copyright notice to add to the footer of documentation.
|
||||
('copyright', config_options.Type(str)),
|
||||
# The directory where the site will be built to
|
||||
('site_dir', config_options.SiteDir(default='site')),
|
||||
|
||||
# set of values for Google analytics containing the account IO and domain,
|
||||
# this should look like, ['UA-27795084-5', 'mkdocs.org']
|
||||
('google_analytics', config_options.Type(list, length=2)),
|
||||
# A copyright notice to add to the footer of documentation.
|
||||
('copyright', config_options.Type(str)),
|
||||
|
||||
# The address on which to serve the live reloading docs server.
|
||||
('dev_addr', config_options.IpAddress(default='127.0.0.1:8000')),
|
||||
# set of values for Google analytics containing the account IO and domain,
|
||||
# this should look like, ['UA-27795084-5', 'mkdocs.org']
|
||||
('google_analytics', config_options.Type(list, length=2)),
|
||||
|
||||
# If `True`, use `<page_name>/index.hmtl` style files with hyperlinks to
|
||||
# the directory.If `False`, use `<page_name>.html style file with
|
||||
# hyperlinks to the file.
|
||||
# True generates nicer URLs, but False is useful if browsing the output on
|
||||
# a filesystem.
|
||||
('use_directory_urls', config_options.Type(bool, default=True)),
|
||||
# The address on which to serve the live reloading docs server.
|
||||
('dev_addr', config_options.IpAddress(default='127.0.0.1:8000')),
|
||||
|
||||
# Specify a link to the project source repo to be included
|
||||
# in the documentation pages.
|
||||
('repo_url', config_options.RepoURL()),
|
||||
# If `True`, use `<page_name>/index.hmtl` style files with hyperlinks to
|
||||
# the directory.If `False`, use `<page_name>.html style file with
|
||||
# hyperlinks to the file.
|
||||
# True generates nicer URLs, but False is useful if browsing the output on
|
||||
# a filesystem.
|
||||
('use_directory_urls', config_options.Type(bool, default=True)),
|
||||
|
||||
# A name to use for the link to the project source repo.
|
||||
# Default, If repo_url is unset then None, otherwise
|
||||
# "GitHub", "Bitbucket" or "GitLab" for known url or Hostname
|
||||
# for unknown urls.
|
||||
('repo_name', config_options.Type(str)),
|
||||
# Specify a link to the project source repo to be included
|
||||
# in the documentation pages.
|
||||
('repo_url', config_options.RepoURL()),
|
||||
|
||||
# Specify a URI to the docs dir in the project source repo, relative to the
|
||||
# repo_url. When set, a link directly to the page in the source repo will
|
||||
# be added to the generated HTML. If repo_url is not set also, this option
|
||||
# is ignored.
|
||||
('edit_uri', config_options.Type(str)),
|
||||
# A name to use for the link to the project source repo.
|
||||
# Default, If repo_url is unset then None, otherwise
|
||||
# "GitHub", "Bitbucket" or "GitLab" for known url or Hostname
|
||||
# for unknown urls.
|
||||
('repo_name', config_options.Type(str)),
|
||||
|
||||
# Specify which css or javascript files from the docs directory should be
|
||||
# additionally included in the site.
|
||||
('extra_css', config_options.Type(list, default=[])),
|
||||
('extra_javascript', config_options.Type(list, default=[])),
|
||||
# Specify a URI to the docs dir in the project source repo, relative to the
|
||||
# repo_url. When set, a link directly to the page in the source repo will
|
||||
# be added to the generated HTML. If repo_url is not set also, this option
|
||||
# is ignored.
|
||||
('edit_uri', config_options.Type(str)),
|
||||
|
||||
# Similar to the above, but each template (HTML or XML) will be build with
|
||||
# Jinja2 and the global context.
|
||||
('extra_templates', config_options.Type(list, default=[])),
|
||||
# Specify which css or javascript files from the docs directory should be
|
||||
# additionally included in the site.
|
||||
('extra_css', config_options.Type(list, default=[])),
|
||||
('extra_javascript', config_options.Type(list, default=[])),
|
||||
|
||||
# PyMarkdown extension names.
|
||||
('markdown_extensions', config_options.MarkdownExtensions(
|
||||
builtins=['toc', 'tables', 'fenced_code'],
|
||||
configkey='mdx_configs', default=[])),
|
||||
# Similar to the above, but each template (HTML or XML) will be build with
|
||||
# Jinja2 and the global context.
|
||||
('extra_templates', config_options.Type(list, default=[])),
|
||||
|
||||
# PyMarkdown Extension Configs. For internal use only.
|
||||
('mdx_configs', config_options.Private()),
|
||||
# PyMarkdown extension names.
|
||||
('markdown_extensions', config_options.MarkdownExtensions(
|
||||
builtins=['toc', 'tables', 'fenced_code'],
|
||||
configkey='mdx_configs', default=[])),
|
||||
|
||||
# enabling strict mode causes MkDocs to stop the build when a problem is
|
||||
# encountered rather than display an error.
|
||||
('strict', config_options.Type(bool, default=False)),
|
||||
# PyMarkdown Extension Configs. For internal use only.
|
||||
('mdx_configs', config_options.Private()),
|
||||
|
||||
# the remote branch to commit to when using gh-deploy
|
||||
('remote_branch', config_options.Type(
|
||||
str, default='gh-pages')),
|
||||
# enabling strict mode causes MkDocs to stop the build when a problem is
|
||||
# encountered rather than display an error.
|
||||
('strict', config_options.Type(bool, default=False)),
|
||||
|
||||
# the remote name to push to when using gh-deploy
|
||||
('remote_name', config_options.Type(str, default='origin')),
|
||||
# the remote branch to commit to when using gh-deploy
|
||||
('remote_branch', config_options.Type(
|
||||
str, default='gh-pages')),
|
||||
|
||||
# extra is a mapping/dictionary of data that is passed to the template.
|
||||
# This allows template authors to require extra configuration that not
|
||||
# relevant to all themes and doesn't need to be explicitly supported by
|
||||
# MkDocs itself. A good example here would be including the current
|
||||
# project version.
|
||||
('extra', config_options.SubConfig()),
|
||||
# the remote name to push to when using gh-deploy
|
||||
('remote_name', config_options.Type(str, default='origin')),
|
||||
|
||||
# a list of plugins. Each item may contain a string name or a key value pair.
|
||||
# A key value pair should be the string name (as the key) and a dict of config
|
||||
# options (as the value).
|
||||
('plugins', config_options.Plugins(default=['search'])),
|
||||
)
|
||||
# extra is a mapping/dictionary of data that is passed to the template.
|
||||
# This allows template authors to require extra configuration that not
|
||||
# relevant to all themes and doesn't need to be explicitly supported by
|
||||
# MkDocs itself. A good example here would be including the current
|
||||
# project version.
|
||||
('extra', config_options.SubConfig()),
|
||||
|
||||
# a list of plugins. Each item may contain a string name or a key value pair.
|
||||
# A key value pair should be the string name (as the key) and a dict of config
|
||||
# options (as the value).
|
||||
('plugins', config_options.Plugins(default=['search'])),
|
||||
)
|
||||
|
||||
@@ -32,7 +32,7 @@ def load_config(**cfg):
|
||||
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')
|
||||
conf = config.Config(schema=config.DEFAULT_SCHEMA, config_file_path=cfg['config_file_path'])
|
||||
conf = config.Config(schema=config.defaults.get_schema(), config_file_path=cfg['config_file_path'])
|
||||
conf.load_dict(cfg)
|
||||
|
||||
errors_warnings = conf.validate()
|
||||
|
||||
@@ -12,7 +12,7 @@ class ConfigBaseTests(unittest.TestCase):
|
||||
|
||||
def test_unrecognised_keys(self):
|
||||
|
||||
c = base.Config(schema=defaults.DEFAULT_SCHEMA)
|
||||
c = base.Config(schema=defaults.get_schema())
|
||||
c.load_dict({
|
||||
'not_a_valid_config_option': "test"
|
||||
})
|
||||
@@ -26,7 +26,7 @@ class ConfigBaseTests(unittest.TestCase):
|
||||
|
||||
def test_missing_required(self):
|
||||
|
||||
c = base.Config(schema=defaults.DEFAULT_SCHEMA)
|
||||
c = base.Config(schema=defaults.get_schema())
|
||||
|
||||
errors, warnings = c.validate()
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ from tempfile import TemporaryDirectory
|
||||
import mkdocs
|
||||
from mkdocs import config
|
||||
from mkdocs.config import config_options
|
||||
from mkdocs.config import defaults
|
||||
from mkdocs.exceptions import ConfigurationError
|
||||
from mkdocs.tests.base import dedent
|
||||
|
||||
@@ -20,7 +21,7 @@ class ConfigTests(unittest.TestCase):
|
||||
self.assertRaises(ConfigurationError, load_missing_config)
|
||||
|
||||
def test_missing_site_name(self):
|
||||
c = config.Config(schema=config.DEFAULT_SCHEMA)
|
||||
c = config.Config(schema=defaults.get_schema())
|
||||
c.load_dict({})
|
||||
errors, warnings = c.validate()
|
||||
self.assertEqual(len(errors), 1)
|
||||
@@ -201,7 +202,7 @@ class ConfigTests(unittest.TestCase):
|
||||
self.assertEqual({k: c['theme'][k] for k in iter(c['theme'])}, result['vars'])
|
||||
|
||||
def test_empty_nav(self):
|
||||
conf = config.Config(schema=config.DEFAULT_SCHEMA)
|
||||
conf = config.Config(schema=defaults.get_schema())
|
||||
conf.load_dict({
|
||||
'site_name': 'Example',
|
||||
'config_file_path': os.path.join(os.path.abspath('.'), 'mkdocs.yml')
|
||||
@@ -211,7 +212,7 @@ class ConfigTests(unittest.TestCase):
|
||||
|
||||
def test_copy_pages_to_nav(self):
|
||||
# TODO: remove this when pages config setting is fully deprecated.
|
||||
conf = config.Config(schema=config.DEFAULT_SCHEMA)
|
||||
conf = config.Config(schema=defaults.get_schema())
|
||||
conf.load_dict({
|
||||
'site_name': 'Example',
|
||||
'pages': ['index.md', 'about.md'],
|
||||
@@ -222,7 +223,7 @@ class ConfigTests(unittest.TestCase):
|
||||
|
||||
def test_dont_overwrite_nav_with_pages(self):
|
||||
# TODO: remove this when pages config setting is fully deprecated.
|
||||
conf = config.Config(schema=config.DEFAULT_SCHEMA)
|
||||
conf = config.Config(schema=defaults.get_schema())
|
||||
conf.load_dict({
|
||||
'site_name': 'Example',
|
||||
'pages': ['index.md', 'about.md'],
|
||||
@@ -266,3 +267,19 @@ class ConfigTests(unittest.TestCase):
|
||||
|
||||
self.assertEqual(len(errors), 1)
|
||||
self.assertEqual(warnings, [])
|
||||
|
||||
def testConfigInstancesUnique(self):
|
||||
conf = mkdocs.config.Config(mkdocs.config.defaults.get_schema())
|
||||
conf.load_dict({'site_name': 'foo'})
|
||||
conf.validate()
|
||||
self.assertIsNone(conf['mdx_configs'].get('toc'))
|
||||
|
||||
conf = mkdocs.config.Config(mkdocs.config.defaults.get_schema())
|
||||
conf.load_dict({'site_name': 'foo', 'markdown_extensions': [{"toc": {"permalink": "aaa"}}]})
|
||||
conf.validate()
|
||||
self.assertEqual(conf['mdx_configs'].get('toc'), {'permalink': 'aaa'})
|
||||
|
||||
conf = mkdocs.config.Config(mkdocs.config.defaults.get_schema())
|
||||
conf.load_dict({'site_name': 'foo'})
|
||||
conf.validate()
|
||||
self.assertIsNone(conf['mdx_configs'].get('toc'))
|
||||
|
||||
Reference in New Issue
Block a user