From 1e7fd3f236f63f9ca9b85de9cd172b77e7f9be80 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Tue, 31 Jul 2018 14:12:49 -0400 Subject: Move isBlockLevel to class. (#693) Allows users and/or extensions to alter the list of block level elements. The old implementation remains with a DeprecationWarning. Fixes #575. --- markdown/core.py | 19 +++++++++++++++++++ markdown/extensions/attr_list.py | 3 +-- markdown/postprocessors.py | 2 +- markdown/preprocessors.py | 6 +++--- markdown/treeprocessors.py | 6 +++--- markdown/util.py | 39 ++++++++++++++++++++------------------- tests/test_apis.py | 7 ++++--- 7 files changed, 51 insertions(+), 31 deletions(-) diff --git a/markdown/core.py b/markdown/core.py index 98c9252..f2bd2fb 100644 --- a/markdown/core.py +++ b/markdown/core.py @@ -52,6 +52,18 @@ class Markdown(object): 'xhtml': to_xhtml_string, } + block_level_elements = [ + # Elements which are invalid to wrap in a `

` tag. + # See http://w3c.github.io/html/grouping-content.html#the-p-element + 'address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl', + 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', + 'h4', 'h5', 'h6', 'header', 'hr', 'main', 'menu', 'nav', 'ol', 'p', 'pre', + 'section', 'table', 'ul', + # Other elements which Markdown should not be mucking up the contents of. + 'canvas', 'dd', 'dt', 'group', 'iframe', 'li', 'math', 'noscript', 'output', + 'progress', 'script', 'style', 'tbody', 'td', 'th', 'thead', 'tr', 'video' + ] + def __init__(self, **kwargs): """ Creates a new Markdown instance. @@ -207,6 +219,13 @@ class Markdown(object): raise return self + def is_block_level(self, tag): + """Check if the tag is a block level HTML tag.""" + if isinstance(tag, util.string_type): + return tag.lower().rstrip('/') in self.block_level_elements + # Some ElementTree tags are not strings, so return False. + return False + def convert(self, source): """ Convert markdown to serialized XHTML or HTML. diff --git a/markdown/extensions/attr_list.py b/markdown/extensions/attr_list.py index 84b852d..ab7d6b9 100644 --- a/markdown/extensions/attr_list.py +++ b/markdown/extensions/attr_list.py @@ -21,7 +21,6 @@ from __future__ import absolute_import from __future__ import unicode_literals from . import Extension from ..treeprocessors import Treeprocessor -from ..util import isBlockLevel import re @@ -79,7 +78,7 @@ class AttrListTreeprocessor(Treeprocessor): def run(self, doc): for elem in doc.iter(): - if isBlockLevel(elem.tag): + if self.md.is_block_level(elem.tag): # Block level: check for attrs on last line of text RE = self.BLOCK_RE if isheader(elem) or elem.tag == 'dt': diff --git a/markdown/postprocessors.py b/markdown/postprocessors.py index 541da5d..cecb4ad 100644 --- a/markdown/postprocessors.py +++ b/markdown/postprocessors.py @@ -91,7 +91,7 @@ class RawHtmlPostprocessor(Postprocessor): if m.group(1)[0] in ('!', '?', '@', '%'): # Comment, php etc... return True - return util.isBlockLevel(m.group(1)) + return self.md.is_block_level(m.group(1)) return False diff --git a/markdown/preprocessors.py b/markdown/preprocessors.py index 50537dd..89f4baa 100644 --- a/markdown/preprocessors.py +++ b/markdown/preprocessors.py @@ -235,11 +235,11 @@ class HtmlBlockPreprocessor(Preprocessor): block) # keep checking conditions below and maybe just append - if data_index < len(block) and (util.isBlockLevel(left_tag) or left_tag == '--'): + if data_index < len(block) and (self.md.is_block_level(left_tag) or left_tag == '--'): text.insert(0, block[data_index:]) block = block[:data_index] - if not (util.isBlockLevel(left_tag) or block[1] in ["!", "?", "@", "%"]): + if not (self.md.is_block_level(left_tag) or block[1] in ["!", "?", "@", "%"]): new_blocks.append(block) continue @@ -261,7 +261,7 @@ class HtmlBlockPreprocessor(Preprocessor): else: # if is block level tag and is not complete if (not self._equal_tags(left_tag, right_tag)) and \ - (util.isBlockLevel(left_tag) or left_tag == "--"): + (self.md.is_block_level(left_tag) or left_tag == "--"): items.append(block.strip()) in_tag = True else: diff --git a/markdown/treeprocessors.py b/markdown/treeprocessors.py index 353826e..5c2be2d 100644 --- a/markdown/treeprocessors.py +++ b/markdown/treeprocessors.py @@ -406,12 +406,12 @@ class PrettifyTreeprocessor(Treeprocessor): """ Recursively add linebreaks to ElementTree children. """ i = "\n" - if util.isBlockLevel(elem.tag) and elem.tag not in ['code', 'pre']: + if self.md.is_block_level(elem.tag) and elem.tag not in ['code', 'pre']: if (not elem.text or not elem.text.strip()) \ - and len(elem) and util.isBlockLevel(elem[0].tag): + and len(elem) and self.md.is_block_level(elem[0].tag): elem.text = i for e in elem: - if util.isBlockLevel(e.tag): + if self.md.is_block_level(e.tag): self._prettifyETree(e) if not elem.tail or not elem.tail.strip(): elem.tail = i diff --git a/markdown/util.py b/markdown/util.py index b40c010..262521c 100644 --- a/markdown/util.py +++ b/markdown/util.py @@ -113,6 +113,26 @@ AUXILIARY GLOBAL FUNCTIONS """ +def deprecated(message): + """ + Raise a DeprecationWarning when wrapped function/method is called. + + Borrowed from https://stackoverflow.com/a/48632082/866026 + """ + def deprecated_decorator(func): + @wraps(func) + def deprecated_func(*args, **kwargs): + warnings.warn( + "'{}' is deprecated. {}".format(func.__name__, message), + category=DeprecationWarning, + stacklevel=2 + ) + return func(*args, **kwargs) + return deprecated_func + return deprecated_decorator + + +@deprecated("Use 'Markdown.is_block_level' instead.") def isBlockLevel(tag): """Check if the tag is a block level HTML tag.""" if isinstance(tag, string_type): @@ -151,25 +171,6 @@ def code_escape(text): return text -def deprecated(message): - """ - Raise a DeprecationWarning when wrapped function/method is called. - - Borrowed from https://stackoverflow.com/a/48632082/866026 - """ - def deprecated_decorator(func): - @wraps(func) - def deprecated_func(*args, **kwargs): - warnings.warn( - "'{}' is deprecated. {}".format(func.__name__, message), - category=DeprecationWarning, - stacklevel=2 - ) - return func(*args, **kwargs) - return deprecated_func - return deprecated_decorator - - """ MISC AUXILIARY CLASSES ============================================================================= diff --git a/tests/test_apis.py b/tests/test_apis.py index 834299b..71a8555 100644 --- a/tests/test_apis.py +++ b/tests/test_apis.py @@ -510,7 +510,8 @@ class testETreeComments(unittest.TestCase): def testCommentIsBlockLevel(self): """ Test that an ElementTree Comment is recognized as BlockLevel. """ - self.assertFalse(markdown.util.isBlockLevel(self.comment.tag)) + md = markdown.Markdown() + self.assertFalse(md.is_block_level(self.comment.tag)) def testCommentSerialization(self): """ Test that an ElementTree Comment serializes properly. """ @@ -521,7 +522,7 @@ class testETreeComments(unittest.TestCase): def testCommentPrettify(self): """ Test that an ElementTree Comment is prettified properly. """ - pretty = markdown.treeprocessors.PrettifyTreeprocessor() + pretty = markdown.treeprocessors.PrettifyTreeprocessor(markdown.Markdown()) pretty.run(self.comment) self.assertEqual( markdown.serializers.to_html_string(self.comment), @@ -532,7 +533,7 @@ class testETreeComments(unittest.TestCase): class testElementTailTests(unittest.TestCase): """ Element Tail Tests """ def setUp(self): - self.pretty = markdown.treeprocessors.PrettifyTreeprocessor() + self.pretty = markdown.treeprocessors.PrettifyTreeprocessor(markdown.Markdown()) def testBrTailNoNewline(self): """ Test that last
in tree has a new line tail """ -- cgit v1.2.3