refactoring: moving markdown parsing to utils

This commit is contained in:
Ugo Cupcic
2015-04-23 11:08:55 +02:00
parent 3fe8bbe46e
commit c5d3555594
4 changed files with 74 additions and 69 deletions

View File

@@ -2,59 +2,22 @@
from __future__ import print_function
from datetime import datetime
from jinja2.exceptions import TemplateNotFound
import mkdocs
from mkdocs import nav, toc, utils
from mkdocs.compat import urljoin
from mkdocs.relative_path_ext import RelativePathExtension
import jinja2
import json
import markdown
import os
import logging
from io import open
from jinja2.exceptions import TemplateNotFound
import jinja2
import mkdocs
from mkdocs import nav, utils
from mkdocs.compat import urljoin
from mkdocs.utils import convert_markdown
log = logging.getLogger('mkdocs')
def convert_markdown(markdown_source, site_navigation=None, extensions=(), strict=False):
"""
Convert the Markdown source file to HTML content, and additionally
return the parsed table of contents, and a dictionary of any metadata
that was specified in the Markdown file.
`extensions` is an optional sequence of Python Markdown extensions to add
to the default set.
"""
# Generate the HTML from the markdown source
if isinstance(extensions, dict):
user_extensions = list(extensions.keys())
extension_configs = dict([(k, v) for k, v in extensions.items() if isinstance(v, dict)])
else:
user_extensions = list(extensions)
extension_configs = {}
builtin_extensions = ['meta', 'toc', 'tables', 'fenced_code']
mkdocs_extensions = [RelativePathExtension(site_navigation, strict), ]
extensions = set(builtin_extensions + mkdocs_extensions + user_extensions)
md = markdown.Markdown(
extensions=extensions,
extension_configs=extension_configs
)
html_content = md.convert(markdown_source)
# On completely blank markdown files, no Meta or tox properties are added
# to the generated document.
meta = getattr(md, 'Meta', {})
toc_html = getattr(md, 'toc', '')
# Post process the generated table of contents into a data structure
table_of_contents = toc.TableOfContents(toc_html)
return (html_content, table_of_contents, meta)
def get_global_context(nav, config):
"""
Given the SiteNavigation and config, generate the context which is relevant

View File

@@ -17,12 +17,13 @@ log = logging.getLogger(__name__)
def file_to_tile(filename):
"""
Automatically generate a default title, given a filename.
The method parses the file to check for a title, uses the filename
as a title otherwise.
"""
if utils.is_homepage(filename):
return 'Home'
#todo check if there's a header in the doc first
title = os.path.splitext(filename)[0]
title = title.replace('-', ' ').replace('_', ' ')
# Capitalize if the filename was all lowercase, otherwise leave it as-is.

View File

@@ -10,12 +10,13 @@ from mkdocs import build, nav, config
from mkdocs.compat import zip
from mkdocs.exceptions import MarkdownNotFound
from mkdocs.tests.base import dedent
from mkdocs.utils import convert_markdown
class BuildTests(unittest.TestCase):
def test_empty_document(self):
html, toc, meta = build.convert_markdown("")
html, toc, meta = convert_markdown("")
self.assertEqual(html, '')
self.assertEqual(len(list(toc)), 0)
@@ -26,7 +27,7 @@ class BuildTests(unittest.TestCase):
Ensure that basic Markdown -> HTML and TOC works.
"""
html, toc, meta = build.convert_markdown(dedent("""
html, toc, meta = convert_markdown(dedent("""
page_title: custom title
# Heading 1
@@ -59,25 +60,25 @@ class BuildTests(unittest.TestCase):
def test_convert_internal_link(self):
md_text = 'An [internal link](internal.md) to another document.'
expected = '<p>An <a href="internal/">internal link</a> to another document.</p>'
html, toc, meta = build.convert_markdown(md_text)
html, toc, meta = convert_markdown(md_text)
self.assertEqual(html.strip(), expected.strip())
def test_convert_multiple_internal_links(self):
md_text = '[First link](first.md) [second link](second.md).'
expected = '<p><a href="first/">First link</a> <a href="second/">second link</a>.</p>'
html, toc, meta = build.convert_markdown(md_text)
html, toc, meta = convert_markdown(md_text)
self.assertEqual(html.strip(), expected.strip())
def test_convert_internal_link_differing_directory(self):
md_text = 'An [internal link](../internal.md) to another document.'
expected = '<p>An <a href="../internal/">internal link</a> to another document.</p>'
html, toc, meta = build.convert_markdown(md_text)
html, toc, meta = convert_markdown(md_text)
self.assertEqual(html.strip(), expected.strip())
def test_convert_internal_link_with_anchor(self):
md_text = 'An [internal link](internal.md#section1.1) to another document.'
expected = '<p>An <a href="internal/#section1.1">internal link</a> to another document.</p>'
html, toc, meta = build.convert_markdown(md_text)
html, toc, meta = convert_markdown(md_text)
self.assertEqual(html.strip(), expected.strip())
def test_convert_internal_media(self):
@@ -100,7 +101,7 @@ class BuildTests(unittest.TestCase):
for (page, expected) in zip(site_navigation.walk_pages(), expected_results):
md_text = '![The initial MkDocs layout](img/initial-layout.png)'
html, _, _ = build.convert_markdown(md_text, site_navigation=site_navigation)
html, _, _ = convert_markdown(md_text, site_navigation=site_navigation)
self.assertEqual(html, template % expected)
def test_convert_internal_asbolute_media(self):
@@ -123,7 +124,7 @@ class BuildTests(unittest.TestCase):
for (page, expected) in zip(site_navigation.walk_pages(), expected_results):
md_text = '![The initial MkDocs layout](/img/initial-layout.png)'
html, _, _ = build.convert_markdown(md_text, site_navigation=site_navigation)
html, _, _ = convert_markdown(md_text, site_navigation=site_navigation)
self.assertEqual(html, template % expected)
def test_dont_convert_code_block_urls(self):
@@ -143,7 +144,7 @@ class BuildTests(unittest.TestCase):
for page in site_navigation.walk_pages():
markdown = 'An HTML Anchor::\n\n <a href="index.md">My example link</a>\n'
html, _, _ = build.convert_markdown(markdown, site_navigation=site_navigation)
html, _, _ = convert_markdown(markdown, site_navigation=site_navigation)
self.assertEqual(dedent(html), expected)
def test_anchor_only_link(self):
@@ -158,13 +159,13 @@ class BuildTests(unittest.TestCase):
for page in site_navigation.walk_pages():
markdown = '[test](#test)'
html, _, _ = build.convert_markdown(markdown, site_navigation=site_navigation)
html, _, _ = convert_markdown(markdown, site_navigation=site_navigation)
self.assertEqual(html, '<p><a href="#test">test</a></p>')
def test_ignore_external_link(self):
md_text = 'An [external link](http://example.com/external.md).'
expected = '<p>An <a href="http://example.com/external.md">external link</a>.</p>'
html, toc, meta = build.convert_markdown(md_text)
html, toc, meta = convert_markdown(md_text)
self.assertEqual(html.strip(), expected.strip())
def test_not_use_directory_urls(self):
@@ -174,7 +175,7 @@ class BuildTests(unittest.TestCase):
('internal.md',)
]
site_navigation = nav.SiteNavigation(pages, use_directory_urls=False)
html, toc, meta = build.convert_markdown(md_text, site_navigation=site_navigation)
html, toc, meta = convert_markdown(md_text, site_navigation=site_navigation)
self.assertEqual(html.strip(), expected.strip())
def test_markdown_table_extension(self):
@@ -182,7 +183,7 @@ class BuildTests(unittest.TestCase):
Ensure that the table extension is supported.
"""
html, toc, meta = build.convert_markdown(dedent("""
html, toc, meta = convert_markdown(dedent("""
First Header | Second Header
-------------- | --------------
Content Cell 1 | Content Cell 2
@@ -217,7 +218,7 @@ class BuildTests(unittest.TestCase):
Ensure that the fenced code extension is supported.
"""
html, toc, meta = build.convert_markdown(dedent("""
html, toc, meta = convert_markdown(dedent("""
```
print 'foo'
```
@@ -238,12 +239,12 @@ class BuildTests(unittest.TestCase):
# Check that the plugin is not active when not requested.
expected_without_smartstrong = "<p>foo<strong>bar</strong>baz</p>"
html_base, _, _ = build.convert_markdown(md_input)
html_base, _, _ = convert_markdown(md_input)
self.assertEqual(html_base.strip(), expected_without_smartstrong)
# Check that the plugin is active when requested.
expected_with_smartstrong = "<p>foo__bar__baz</p>"
html_ext, _, _ = build.convert_markdown(md_input, extensions=['smart_strong'])
html_ext, _, _ = convert_markdown(md_input, extensions=['smart_strong'])
self.assertEqual(html_ext.strip(), expected_with_smartstrong)
def test_markdown_duplicate_custom_extension(self):
@@ -251,7 +252,7 @@ class BuildTests(unittest.TestCase):
Duplicated extension names should not cause problems.
"""
md_input = "foo"
html_ext, _, _ = build.convert_markdown(md_input, ['toc'])
html_ext, _, _ = convert_markdown(md_input, ['toc'])
self.assertEqual(html_ext.strip(), '<p>foo</p>')
def test_copying_media(self):
@@ -303,8 +304,8 @@ class BuildTests(unittest.TestCase):
site_nav = nav.SiteNavigation(pages)
valid = "[test](internal.md)"
build.convert_markdown(valid, site_nav, strict=False)
build.convert_markdown(valid, site_nav, strict=True)
convert_markdown(valid, site_nav, strict=False)
convert_markdown(valid, site_nav, strict=True)
def test_strict_mode_invalid(self):
pages = [
@@ -315,11 +316,11 @@ class BuildTests(unittest.TestCase):
site_nav = nav.SiteNavigation(pages)
invalid = "[test](bad_link.md)"
build.convert_markdown(invalid, site_nav, strict=False)
convert_markdown(invalid, site_nav, strict=False)
self.assertRaises(
MarkdownNotFound,
build.convert_markdown, invalid, site_nav, strict=True)
convert_markdown, invalid, site_nav, strict=True)
def test_extension_config(self):
"""
@@ -330,7 +331,7 @@ class BuildTests(unittest.TestCase):
'toc': {'permalink': True},
'meta': None # This gets ignored as it is an invalid config
}
html, toc, meta = build.convert_markdown(dedent("""
html, toc, meta = convert_markdown(dedent("""
# A Header
"""), extensions=markdown_extensions)

View File

@@ -9,8 +9,11 @@ and structure of the site and pages in the site.
import os
import shutil
import markdown
from mkdocs import toc
from mkdocs.compat import urlparse, pathname2url
from mkdocs.relative_path_ext import RelativePathExtension
def copy_file(source_path, output_path):
@@ -226,3 +229,40 @@ def path_to_url(path):
return path
return pathname2url(path)
def convert_markdown(markdown_source, site_navigation=None, extensions=(), strict=False):
"""
Convert the Markdown source file to HTML content, and additionally
return the parsed table of contents, and a dictionary of any metadata
that was specified in the Markdown file.
`extensions` is an optional sequence of Python Markdown extensions to add
to the default set.
"""
# Generate the HTML from the markdown source
if isinstance(extensions, dict):
user_extensions = list(extensions.keys())
extension_configs = dict([(k, v) for k, v in extensions.items() if isinstance(v, dict)])
else:
user_extensions = list(extensions)
extension_configs = {}
builtin_extensions = ['meta', 'toc', 'tables', 'fenced_code']
mkdocs_extensions = [RelativePathExtension(site_navigation, strict), ]
extensions = set(builtin_extensions + mkdocs_extensions + user_extensions)
md = markdown.Markdown(
extensions=extensions,
extension_configs=extension_configs
)
html_content = md.convert(markdown_source)
# On completely blank markdown files, no Meta or tox properties are added
# to the generated document.
meta = getattr(md, 'Meta', {})
toc_html = getattr(md, 'toc', '')
# Post process the generated table of contents into a data structure
table_of_contents = toc.TableOfContents(toc_html)
return (html_content, table_of_contents, meta)