Skip to content

Commit

Permalink
Switch Markdown engine to markdown-it-py (apache#19702)
Browse files Browse the repository at this point in the history
  • Loading branch information
Torbjørn Vatn authored Jun 21, 2022
1 parent 904cc12 commit 88363b5
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 21 deletions.
4 changes: 4 additions & 0 deletions airflow/www/static/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,10 @@ label[for="timezone-other"],
z-index: 1070;
}

details summary {
display: list-item;
}

.menu-scroll {
max-height: 300px;
overflow-y: auto;
Expand Down
5 changes: 3 additions & 2 deletions airflow/www/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from typing import Any, Dict, List, Optional, Union
from urllib.parse import urlencode

import markdown
import sqlalchemy as sqla
from flask import Response, request, url_for
from flask.helpers import flash
Expand All @@ -31,6 +30,7 @@
from flask_appbuilder.models.sqla.filters import get_field_setup_query, set_value_to_type
from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask_babel import lazy_gettext
from markdown_it import MarkdownIt
from markupsafe import Markup
from pendulum.datetime import DateTime
from pygments import highlight, lexers
Expand Down Expand Up @@ -476,10 +476,11 @@ def json_render(obj, lexer):

def wrapped_markdown(s, css_class='rich_doc'):
"""Convert a Markdown string to HTML."""
md = MarkdownIt("gfm-like")
if s is None:
return None
s = textwrap.dedent(s)
return Markup(f'<div class="{css_class}" >' + markdown.markdown(s, extensions=['tables']) + "</div>")
return Markup(f'<div class="{css_class}" >{md.render(s)}</div>')


def get_attr_renderer():
Expand Down
3 changes: 3 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -135,15 +135,18 @@ install_requires =
# we pin to the same upper-bound as connexion.
jsonschema>=3.2.0, <5.0
lazy-object-proxy
linkify-it-py>=2.0.0
lockfile>=0.12.2
markdown>=3.0
# Markupsafe 2.1.0 breaks with error: import name 'soft_unicode' from 'markupsafe'.
# This should be removed when either this issue is closed:
# https://github.com/pallets/markupsafe/issues/284
# or when we will be able to upgrade JINJA to newer version (currently limited due to Flask and
# Flask Application Builder)
markdown-it-py>=2.1.0
markupsafe>=1.1.1,<2.1.0
marshmallow-oneofschema>=2.0.1
mdit-py-plugins>=0.3.0
packaging>=14.0
pathspec~=0.9.0
pendulum>=2.0
Expand Down
112 changes: 93 additions & 19 deletions tests/www/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,29 +184,54 @@ def test_markdown_none(self):
class TestWrappedMarkdown(unittest.TestCase):
def test_wrapped_markdown_with_docstring_curly_braces(self):
rendered = wrapped_markdown("{braces}", css_class="a_class")
assert '<div class="a_class" ><p>{braces}</p></div>' == rendered
assert (
'''<div class="a_class" ><p>{braces}</p>
</div>'''
== rendered
)

def test_wrapped_markdown_with_some_markdown(self):
rendered = wrapped_markdown("*italic*\n**bold**\n", css_class="a_class")
rendered = wrapped_markdown(
"""*italic*
**bold**
""",
css_class="a_class",
)

assert (
'''<div class="a_class" ><p><em>italic</em>
<strong>bold</strong></p></div>'''
<strong>bold</strong></p>
</div>'''
== rendered
)

def test_wrapped_markdown_with_table(self):
rendered = wrapped_markdown(
"""| Job | Duration |
| ----------- | ----------- |
| ETL | 14m |"""
"""
| Job | Duration |
| ----------- | ----------- |
| ETL | 14m |
"""
)

assert (
'<div class="rich_doc" ><table>\n<thead>\n<tr>\n<th>Job</th>\n'
'<th>Duration</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>ETL'
'</td>\n<td>14m</td>\n</tr>\n</tbody>\n'
'</table></div>'
) == rendered
'''<div class="rich_doc" ><table>
<thead>
<tr>
<th>Job</th>
<th>Duration</th>
</tr>
</thead>
<tbody>
<tr>
<td>ETL</td>
<td>14m</td>
</tr>
</tbody>
</table>
</div>'''
== rendered
)

def test_wrapped_markdown_with_indented_lines(self):
rendered = wrapped_markdown(
Expand All @@ -217,7 +242,11 @@ def test_wrapped_markdown_with_indented_lines(self):
"""
)

assert '<div class="rich_doc" ><h1>header</h1>\n<p>1st line\n2nd line</p></div>' == rendered
assert (
'''<div class="rich_doc" ><h1>header</h1>\n<p>1st line\n2nd line</p>
</div>'''
== rendered
)

def test_wrapped_markdown_with_raw_code_block(self):
rendered = wrapped_markdown(
Expand All @@ -235,10 +264,12 @@ def test_wrapped_markdown_with_raw_code_block(self):
)

assert (
'<div class="rich_doc" ><h1>Markdown code block</h1>\n'
'<p>Inline <code>code</code> works well.</p>\n'
'<pre><code>Code block\ndoes not\nrespect\nnewlines\n</code></pre></div>'
) == rendered
'''<div class="rich_doc" ><h1>Markdown code block</h1>
<p>Inline <code>code</code> works well.</p>
<pre><code>Code block\ndoes not\nrespect\nnewlines\n</code></pre>
</div>'''
== rendered
)

def test_wrapped_markdown_with_nested_list(self):
rendered = wrapped_markdown(
Expand All @@ -251,6 +282,49 @@ def test_wrapped_markdown_with_nested_list(self):
)

assert (
'<div class="rich_doc" ><h3>Docstring with a code block</h3>\n'
'<ul>\n<li>And<ul>\n<li>A nested list</li>\n</ul>\n</li>\n</ul></div>'
) == rendered
'''<div class="rich_doc" ><h3>Docstring with a code block</h3>
<ul>
<li>And
<ul>
<li>A nested list</li>
</ul>
</li>
</ul>
</div>'''
== rendered
)

def test_wrapped_markdown_with_collapsible_section(self):
rendered = wrapped_markdown(
"""
# A collapsible section with markdown
<details>
<summary>Click to expand!</summary>
## Heading
1. A numbered
2. list
* With some
* Sub bullets
</details>
"""
)

assert (
'''<div class="rich_doc" ><h1>A collapsible section with markdown</h1>
<details>
<summary>Click to expand!</summary>
<h2>Heading</h2>
<ol>
<li>A numbered</li>
<li>list
<ul>
<li>With some</li>
<li>Sub bullets</li>
</ul>
</li>
</ol>
</details>
</div>'''
== rendered
)

0 comments on commit 88363b5

Please sign in to comment.