def test_convert(self): self.maxDiff = None pages_yaml_old = """ pages: - ['index.md', 'Home'] - ['user-guide/writing-your-docs.md', 'User Guide'] - ['user-guide/styling-your-docs.md', 'User Guide'] - ['about/license.md', 'About', 'License'] - ['about/release-notes.md', 'About'] - ['about/contributing.md', 'About', 'Contributing'] - ['help/contributing.md', 'Help', 'Contributing'] - ['support.md'] - ['cli.md', 'CLI Guide'] """ pages_yaml_new = """ pages: - Home: index.md - User Guide: - user-guide/writing-your-docs.md - user-guide/styling-your-docs.md - About: - License: about/license.md - about/release-notes.md - Contributing: about/contributing.md - Help: - Contributing: help/contributing.md - support.md - CLI Guide: cli.md """ self.assertEqual( legacy.pages_compat_shim(utils.yaml_load(pages_yaml_old)['pages']), utils.yaml_load(pages_yaml_new)['pages'])
def _load_theme_config(self, name): """ Recursively load theme and any parent themes. """ theme_dir = utils.get_theme_dir(name) self.dirs.append(theme_dir) try: file_path = os.path.join(theme_dir, 'mkdocs_theme.yml') with open(file_path, 'rb') as f: theme_config = utils.yaml_load(f) except IOError as e: log.debug(e) raise ValidationError( "The theme '{0}' does not appear to have a configuration file. " "Please upgrade to a current version of the theme.".format(name) ) log.debug("Loaded theme configuration for '%s' from '%s': %s", name, file_path, theme_config) parent_theme = theme_config.pop('extends', None) if parent_theme: themes = utils.get_theme_names() if parent_theme not in themes: raise ValidationError( "The theme '{0}' inherits from '{1}', which does not appear to be installed. " "The available installed themes are: {2}".format(name, parent_theme, ', '.join(themes)) ) self._load_theme_config(parent_theme) self.static_templates.update(theme_config.pop('static_templates', [])) self._vars.update(theme_config)
def test_yaml_load(self): try: from collections import OrderedDict except ImportError: # Don't test if can't import OrderdDict # Exception can be removed when Py26 support is removed return yaml_text = dedent(''' test: key1: 1 key2: 2 key3: 3 key4: 4 key5: 5 key5: 6 key3: 7 ''') self.assertEqual( utils.yaml_load(yaml_text), OrderedDict([('test', OrderedDict([('key1', 1), ('key2', 2), ('key3', 7), ('key4', 4), ('key5', 6)]))]) )
def __load_page_config_file(self, file): config = yaml_load(file) root_docs_dir = self.__get_root_docs_dir() root_repo_url = self.config.get('repo_url') root_edit_uri = self.config.get('edit_uri', '') page_docs_dir = self.__get_page_docs_dir() page_repo_url = config.get('repo_url', root_repo_url) page_edit_uri = config.get( 'edit_uri', root_edit_uri.replace(root_docs_dir, page_docs_dir)) # ensure a well-formed edit_uri if page_edit_uri: if not page_edit_uri.startswith(('?', '#')) \ and not page_repo_url.endswith('/'): page_repo_url += '/' if not page_edit_uri.endswith('/'): page_edit_uri += '/' config['docs_dir'] = page_docs_dir config['edit_uri'] = page_edit_uri config['repo_url'] = page_repo_url return config
def _load_theme_config(self, name): """ Recursively load theme and any parent themes. """ theme_dir = utils.get_theme_dir(name) self.dirs.append(theme_dir) try: file_path = os.path.join(theme_dir, 'mkdocs_theme.yml') with open(file_path, 'rb') as f: theme_config = utils.yaml_load(f) if theme_config is None: theme_config = {} except IOError as e: log.debug(e) raise ValidationError( "The theme '{0}' does not appear to have a configuration file. " "Please upgrade to a current version of the theme.".format(name) ) log.debug("Loaded theme configuration for '%s' from '%s': %s", name, file_path, theme_config) parent_theme = theme_config.pop('extends', None) if parent_theme: themes = utils.get_theme_names() if parent_theme not in themes: raise ValidationError( "The theme '{0}' inherits from '{1}', which does not appear to be installed. " "The available installed themes are: {2}".format(name, parent_theme, ', '.join(themes)) ) self._load_theme_config(parent_theme) self.static_templates.update(theme_config.pop('static_templates', [])) self._vars.update(theme_config)
def load_file(self, config_file): try: return self.load_dict(utils.yaml_load(config_file)) except YAMLError as e: # MkDocs knows and understands ConfigurationErrors raise exceptions.ConfigurationError( "MkDocs encountered an error parsing the configuration file: {}".format(e) )
def load_file(self, config_file): try: return self.load_dict(utils.yaml_load(config_file)) except YAMLError as e: # MkDocs knows and understands ConfigurationErrors raise exceptions.ConfigurationError( "MkDocs encountered as error parsing the configuration file: {}".format(e) )
def load_file(self, config_file): """ Load config options from the open file descriptor of a YAML file. """ try: return self.load_dict(utils.yaml_load(config_file)) except YAMLError as e: # MkDocs knows and understands ConfigurationErrors raise exceptions.ConfigurationError( f"MkDocs encountered an error parsing the configuration file: {e}" )
def test_convert_no_home(self): self.maxDiff = None pages_yaml_old = """ pages: - ['index.md'] - ['about.md', 'About'] """ pages_yaml_new = """ pages: - index.md - About: about.md """ self.assertEqual( legacy.pages_compat_shim(utils.yaml_load(pages_yaml_old)['pages']), utils.yaml_load(pages_yaml_new)['pages'])
def test_unicode_yaml(self): yaml_src = dedent(''' key: value key2: - value ''') config = utils.yaml_load(yaml_src) self.assertTrue(isinstance(config['key'], utils.text_type)) self.assertTrue(isinstance(config['key2'][0], utils.text_type))
def test_normal_nav(self): nav = yaml_load(textwrap.dedent('''\ - Home: index.md - getting-started.md - User Guide: - Overview: user-guide/index.md - Installation: user-guide/installation.md ''').encode()) option = config_options.Nav() self.assertEqual(option.validate(nav), nav) self.assertEqual(option.warnings, [])
def test_unicode_yaml(self): yaml_src = dedent( ''' key: value key2: - value ''' ).encode('utf-8') config = utils.yaml_load(yaml_src) self.assertTrue(isinstance(config['key'], str)) self.assertTrue(isinstance(config['key2'][0], str))
def test_unicode_yaml(self): yaml_src = dedent( ''' key: value key2: - value ''' ) config = utils.yaml_load(yaml_src) self.assertTrue(isinstance(config['key'], utils.text_type)) self.assertTrue(isinstance(config['key2'][0], utils.text_type))
def merge(self): self.temp_docs_dir = TemporaryDirectory("", "docs_") aliases = list( filter( lambda docs_dir: len(docs_dir) > 0, map(lambda docs_dir: docs_dir[0], self.docs_dirs), )) if len(aliases) != len(set(aliases)): log.critical( "[mkdocs-monorepo] You cannot have duplicated site names. " + "Current registered site names in the monorepository: {}". format(", ".join(aliases))) raise SystemExit(1) for alias, docs_dir in self.docs_dirs: if len(alias) == 0: source_dir = docs_dir dest_dir = self.temp_docs_dir.name else: with open(os.path.join(docs_dir, "mkdocs.yml"), "rb") as f: navYaml = yaml_load(f) sub_docs_dir = navYaml.get("docs_dir", "docs") source_dir = os.path.join(docs_dir, "docs") split_alias = alias.split("/") dest_dir = os.path.join(self.temp_docs_dir.name, *split_alias) if os.path.exists(source_dir): copy_tree(source_dir, dest_dir) for file_abs_path in Path(source_dir).rglob('*.md'): file_abs_path = str( file_abs_path) # python 3.5 compatibility if os.path.isfile(file_abs_path): file_rel_path = os.path.relpath( file_abs_path, source_dir) dest = join(dest_dir, file_rel_path) self.files_source_dir[dest] = file_abs_path else: log.critical("[mkdocs-monorepo] The {} path is not valid. ". format(source_dir) + "Please update your 'nav' with a valid path.") raise SystemExit(1) return str(self.temp_docs_dir.name)
def test_env_var_in_yaml(self): yaml_src = dedent(''' key1: !ENV VARNAME key2: !ENV UNDEFINED key3: !ENV [UNDEFINED, default] key4: !ENV [UNDEFINED, VARNAME, default] key5: !ENV BOOLVAR ''') config = utils.yaml_load(yaml_src) self.assertIsInstance(config['key1'], str) self.assertEqual(config['key1'], 'Hello, World!') self.assertIsNone(config['key2']) self.assertIsInstance(config['key3'], str) self.assertEqual(config['key3'], 'default') self.assertIsInstance(config['key4'], str) self.assertEqual(config['key4'], 'Hello, World!') self.assertIs(config['key5'], False)
def test_yaml_inheritance(self, tdir): expected = { 'foo': 'bar', 'baz': { 'sub1': 'replaced', 'sub2': 2, 'sub3': 'new' }, 'deep1': { 'deep2-1': { 'deep3-1': 'replaced', 'deep3-2': 'bar' }, 'deep2-2': 'baz' } } with open(os.path.join(tdir, 'base.yml')) as fd: result = utils.yaml_load(fd) self.assertEqual(result, expected)
def read(self): if not self.absNavPath.endswith("/mkdocs.yml"): log.critical( "[mkdocs-monorepo] The included file path {} does not point to a mkdocs.yml" .format(self.absNavPath)) raise SystemExit(1) if not self.absNavPath.startswith(self.rootDir): log.critical( "[mkdocs-monorepo] The mkdocs file {} is outside of the current directory. " .format(self.absNavPath) + "Please move the file and try again.") raise SystemExit(1) try: with open(self.absNavPath, 'rb') as f: self.navYaml = yaml_load(f) except OSError: log.critical( "[mkdocs-monorepo] The file path {} does not exist, ".format( self.absNavPath) + "is not valid YAML, " + "or does not contain a valid 'site_name' and 'nav' keys.") raise SystemExit(1) if self.navYaml and 'site_name' not in self.navYaml: log.critical( "[mkdocs-monorepo] The file path {} does not contain a valid 'site_name' key " .format(self.absNavPath) + "in the YAML file. Please include it to indicate where your documentation " + "should be moved to.") raise SystemExit(1) if self.navYaml and 'nav' not in self.navYaml: log.critical( "[mkdocs-monorepo] The file path {} ".format(self.absNavPath) + "does not contain a valid 'nav' key in the YAML file. " + "Please include it to indicate how your documentation should be presented in the navigation." ) raise SystemExit(1) return self
def load_config(config_file=None, **kwargs): options = dict((k, v) for k, v in kwargs.items() if v is not None) if config_file is None: config_file = 'mkdocs.yml' if os.path.exists(config_file): config_file = open(config_file, 'rb') else: raise ConfigurationError( "Config file '{0}' does not exist.".format(config_file)) options['config'] = config_file user_config = utils.yaml_load(config_file) if not isinstance(user_config, dict): raise ConfigurationError( "The mkdocs.yml file is invalid. For more information see: " "http://www.mkdocs.org/user-guide/configuration/ ({0})".format( user_config)) user_config.update(options) return validate_config(user_config)
def read(self): if not self.absNavPath.endswith(tuple([".yml", ".yaml"])): log.critical( "[mkdocs-monorepo] The included file path {} does not point to a .yml (or .yaml) file" .format(self.absNavPath)) raise SystemExit(1) if not self.absNavPath.startswith(self.rootDir): log.critical( "[mkdocs-monorepo] The mkdocs file {} is outside of the current directory. " .format(self.absNavPath) + "Please move the file and try again.") raise SystemExit(1) try: with open(self.absNavPath, 'rb') as f: self.navYaml = yaml_load(f) # This will check if there is a `docs_dir` property on the `mkdocs.yml` file of # the sub folder and scaffold the `nav` property from it if self.navYaml and 'nav' not in self.navYaml and "docs_dir" in self.navYaml: docsDirPath = os.path.join(os.path.dirname(self.absNavPath), self.navYaml["docs_dir"]) def navFromDir(path): directory = {} for dirname, dirnames, filenames in os.walk(path): dirnames.sort() filenames.sort() if dirname == docsDirPath: dn = os.path.basename(dirname) else: dn = dirname_to_title(os.path.basename(dirname)) directory[dn] = [] for dirItem in dirnames: subNav = navFromDir( path=os.path.join(path, dirItem)) if subNav: directory[dn].append(subNav) for fileItem in filenames: fileName, fileExt = os.path.splitext(fileItem) if fileExt == '.md': fileTitle = get_markdown_title(fileName) filePath = os.path.join( os.path.relpath(path, docsDirPath), fileItem) directory[dn].append({fileTitle: filePath}) if len(directory[dn]) == 0 or directory[dn] == [{}]: del directory[dn] return directory navYaml = navFromDir(docsDirPath) if navYaml: self.navYaml["nav"] = navYaml[os.path.basename( docsDirPath)] except OSError: log.critical( "[mkdocs-monorepo] The file path {} does not exist, ".format( self.absNavPath) + "is not valid YAML, " + "or does not contain a valid 'site_name' and 'nav' keys.") raise SystemExit(1) if self.navYaml and 'site_name' not in self.navYaml: log.critical( "[mkdocs-monorepo] The file path {} does not contain a valid 'site_name' key " .format(self.absNavPath) + "in the YAML file. Please include it to indicate where your documentation " + "should be moved to.") raise SystemExit(1) if self.navYaml and 'nav' not in self.navYaml: log.critical( "[mkdocs-monorepo] The file path {} ".format(self.absNavPath) + "does not contain a valid 'nav' key in the YAML file. " + "Please include it to indicate how your documentation should be presented in the navigation, " + "or include a 'docs_dir' to indicate that automatic nav generation should be used." ) raise SystemExit(1) return self
def load_file(self, config_file): return self.load_dict(utils.yaml_load(config_file))
def test_yaml_inheritance_missing_parent(self, tdir): with open(os.path.join(tdir, 'base.yml')) as fd: with self.assertRaises(exceptions.ConfigurationError): utils.yaml_load(fd)
def resolve(self, nav=None): if nav is None: nav = copy.deepcopy(self.initialNav) for index, item in enumerate(nav): if type(item) is str: key = None value = item elif type(item) is dict: key = list(item.keys())[0] value = list(item.values())[0] if type(value) is str and value.startswith( WILDCARD_INCLUDE_STATEMENT): root_dir = Path(self.config['config_file_path']).parent mkdocs_path = value[len(WILDCARD_INCLUDE_STATEMENT):] if not mkdocs_path.endswith(tuple([".yml", ".yaml"])): log.critical( "[mkdocs-monorepo] The wildcard include path {} does not end with .yml (or .yaml)" .format(mkdocs_path)) raise SystemExit(1) dirs = sorted(root_dir.glob(mkdocs_path)) if dirs: value = [] for mkdocs_config in dirs: site = {} try: with open(mkdocs_config, 'rb') as f: site_yaml = yaml_load(f) site_name = site_yaml["site_name"] site[ site_name] = f"{INCLUDE_STATEMENT}{mkdocs_config.resolve()}" value.append(site) except OSError: log.error( f"[mkdocs-monorepo] The {mkdocs_config} path is not valid." ) except KeyError: log.critical( "[mkdocs-monorepo] The file path {} does not contain a valid 'site_name' key " .format(mkdocs_config) + "in the YAML file. Please include it to indicate where your documentation " + "should be moved to.") raise SystemExit(1) if not value: return None else: return None else: key = None value = None if type(value) is str and value.startswith(INCLUDE_STATEMENT): nav[index] = {} nav[index][key] = IncludeNavLoader( self.config, value[len(INCLUDE_STATEMENT):]).read().getNav() if nav[index][key] is None: return None elif type(value) is list: nav[index] = {} nav[index][key] = self.resolve(value) if nav[index][key] is None: return None return nav