summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfacelessuser <faceless.shop@gmail.com>2017-11-16 20:55:13 -0700
committerfacelessuser <faceless.shop@gmail.com>2017-11-16 20:55:13 -0700
commit33c53ffe73c1c8d1b771804514c8a3a157434c76 (patch)
tree78c22dcc09f1d7dc4a6c7b723161c5e28c13122f
parentf018b0ede5a49c8d711351d8e9ff437c97cf3acc (diff)
downloadpython-markdown-33c53ffe73c1c8d1b771804514c8a3a157434c76.tar.gz
Initial work on ancestry exclusion
Intial work and tests for excluding a pattern due parental tags.
-rw-r--r--markdown/inlinepatterns.py4
-rw-r--r--markdown/treeprocessors.py51
-rw-r--r--tests/test_apis.py54
3 files changed, 99 insertions, 10 deletions
diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py
index 3658ebd..f483f99 100644
--- a/markdown/inlinepatterns.py
+++ b/markdown/inlinepatterns.py
@@ -207,6 +207,10 @@ class Pattern(object):
if markdown_instance:
self.markdown = markdown_instance
+ def getExcludes(self):
+ """Get tag to exclude."""
+ return []
+
def getCompiledRegExp(self):
""" Return a compiled regular expression. """
return self.compiled_re
diff --git a/markdown/treeprocessors.py b/markdown/treeprocessors.py
index bb76572..ae411e2 100644
--- a/markdown/treeprocessors.py
+++ b/markdown/treeprocessors.py
@@ -54,6 +54,7 @@ class InlineProcessor(Treeprocessor):
self.__placeholder_re = util.INLINE_PLACEHOLDER_RE
self.markdown = md
self.inlinePatterns = md.inlinePatterns
+ self.ancestors = []
def __makePlaceholder(self, type):
""" Generate a placeholder """
@@ -138,7 +139,7 @@ class InlineProcessor(Treeprocessor):
childResult.reverse()
for newChild in childResult:
- node.insert(pos, newChild)
+ node.insert(pos, newChild[0])
def __processPlaceholders(self, data, parent, isText=True):
"""
@@ -155,10 +156,10 @@ class InlineProcessor(Treeprocessor):
def linkText(text):
if text:
if result:
- if result[-1].tail:
- result[-1].tail += text
+ if result[-1][0].tail:
+ result[-1][0].tail += text
else:
- result[-1].tail = text
+ result[-1][0].tail = text
elif not isText:
if parent.tail:
parent.tail += text
@@ -199,7 +200,7 @@ class InlineProcessor(Treeprocessor):
continue
strartIndex = phEndIndex
- result.append(node)
+ result.append((node, self.ancestors[:]))
else: # wrong placeholder
end = index + len(self.__placeholder_prefix)
@@ -230,6 +231,12 @@ class InlineProcessor(Treeprocessor):
Returns: String with placeholders instead of ElementTree elements.
"""
+ # print(self.ancestors)
+ # print(data[startIndex:])
+ for exclude in pattern.getExcludes():
+ if exclude.lower() in self.ancestors:
+ return data, False, 0
+
match = pattern.getCompiledRegExp().match(data[startIndex:])
leftData = data[:startIndex]
@@ -245,15 +252,19 @@ class InlineProcessor(Treeprocessor):
if not isinstance(node.text, util.AtomicString):
# We need to process current node too
for child in [node] + list(node):
+ self.ancestors.append(child.tag.lower())
if not isString(node):
if child.text:
child.text = self.__handleInline(
child.text, patternIndex + 1
)
+ self.ancestors.pop()
if child.tail:
child.tail = self.__handleInline(
child.tail, patternIndex
)
+ else:
+ self.ancestors.pop()
placeholder = self.__stashNode(node, pattern.type())
@@ -261,6 +272,19 @@ class InlineProcessor(Treeprocessor):
match.group(1),
placeholder, match.groups()[-1]), True, 0
+ def __build_ancestors(self, parent, parents):
+ """Build the ancestor list."""
+
+ ancestors = []
+ parent_map = dict((c, p) for p in parent.getiterator() for c in p)
+ ancestors.append(parent.tag.lower())
+ while parent:
+ parent = parent_map.get(parent)
+ if parent:
+ ancestors.append(parent.tag.lower())
+ ancestors.reverse()
+ parents.extend(ancestors)
+
def run(self, tree):
"""Apply inline patterns to a parsed Markdown tree.
@@ -280,12 +304,17 @@ class InlineProcessor(Treeprocessor):
"""
self.stashed_nodes = {}
- stack = [tree]
+ stack = [(tree, [])]
while stack:
- currElement = stack.pop()
+ currElement, parents = stack.pop()
+
+ self.ancestors = parents
+ self.__build_ancestors(currElement, self.ancestors)
+
insertQueue = []
for child in currElement:
+ self.ancestors.append(child.tag.lower())
if child.text and not isinstance(
child.text, util.AtomicString
):
@@ -296,6 +325,7 @@ class InlineProcessor(Treeprocessor):
)
stack += lst
insertQueue.append((child, lst))
+ self.ancestors.pop()
if child.tail:
tail = self.__handleInline(child.tail)
dumby = util.etree.Element('d')
@@ -306,9 +336,9 @@ class InlineProcessor(Treeprocessor):
pos = list(currElement).index(child) + 1
tailResult.reverse()
for newChild in tailResult:
- currElement.insert(pos, newChild)
+ currElement.insert(pos, newChild[0])
if len(child):
- stack.append(child)
+ stack.append((child, self.ancestors[:]))
for element, lst in insertQueue:
if self.markdown.enable_attributes:
@@ -317,7 +347,8 @@ class InlineProcessor(Treeprocessor):
element.text, element
)
i = 0
- for newChild in lst:
+ for obj in lst:
+ newChild = obj[0]
if self.markdown.enable_attributes:
# Processing attributes
if newChild.tail and isString(newChild.tail):
diff --git a/tests/test_apis.py b/tests/test_apis.py
index 7b1214f..cbcb989 100644
--- a/tests/test_apis.py
+++ b/tests/test_apis.py
@@ -770,3 +770,57 @@ class TestEscapeAppend(unittest.TestCase):
self.assertEqual('|' in md.ESCAPED_CHARS, True)
md2 = markdown.Markdown()
self.assertEqual('|' not in md2.ESCAPED_CHARS, True)
+
+
+class TestAncestorExclusion(unittest.TestCase):
+ """ Tests exclusion of tags in ancestor list. """
+
+ class AncestorExample(markdown.inlinepatterns.SimpleTagPattern):
+ """ Ancestor Test. """
+
+ def getExcludes(self):
+ """ Tags to exclude. """
+ return ['a']
+
+ def handleMatch(self, m):
+ """ Handle match. """
+ el = markdown.util.etree.Element(self.tag)
+ el.text = m.group(3)
+ return el
+
+ class AncestorExtension(markdown.Extension):
+
+ def __init__(self, *args, **kwargs):
+ """Initialize."""
+
+ self.config = {}
+
+ def extendMarkdown(self, md, md_globals):
+ """Modify inline patterns."""
+
+ pattern = r'(\+)([^\+]+)\2'
+ md.inlinePatterns["ancestor-test"] = TestAncestorExclusion.AncestorExample(pattern, 'strong')
+
+ def setUp(self):
+ """Setup markdown object."""
+ self.md = markdown.Markdown(extensions=[TestAncestorExclusion.AncestorExtension()])
+
+ def test_ancestors(self):
+ """ Test that an extension can exclude parent tags. """
+ test = """
+Some +test+ and a [+link+](http://test.com)
+"""
+ result = """<p>Some <strong>test</strong> and a <a href="http://test.com">+link+</a></p>"""
+
+ self.md.reset()
+ self.assertEqual(self.md.convert(test), result)
+
+ def test_ancestors_tail(self):
+ """ Test that an extension can exclude parent tags when dealing with a tail. """
+ test = """
+[***+em+*+strong+**](http://test.com)
+"""
+ result = """<p><a href="http://test.com"><strong><em>+em+</em>+strong+</strong></a></p>"""
+
+ self.md.reset()
+ self.assertEqual(self.md.convert(test), result)