From 429cc98556bd399268a375a4dfd58e387be9f6e0 Mon Sep 17 00:00:00 2001 From: Maurice van der Pot Date: Fri, 26 Feb 2016 19:32:38 +0100 Subject: [PATCH 1/3] Improve RawHtmlProcessor to have linear iso quadratic performance --- markdown/postprocessors.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/markdown/postprocessors.py b/markdown/postprocessors.py index 2d4dcb589..8b311b268 100644 --- a/markdown/postprocessors.py +++ b/markdown/postprocessors.py @@ -10,6 +10,7 @@ from __future__ import absolute_import from __future__ import unicode_literals +from collections import OrderedDict from . import util from . import odict import re @@ -50,6 +51,7 @@ class RawHtmlPostprocessor(Postprocessor): def run(self, text): """ Iterate over html stash and restore "safe" html. """ + replacements = OrderedDict() for i in range(self.markdown.htmlStash.html_counter): html, safe = self.markdown.htmlStash.rawHtmlBlocks[i] if self.markdown.safeMode and not safe: @@ -61,14 +63,15 @@ def run(self, text): html = self.markdown.html_replacement_text if (self.isblocklevel(html) and (safe or not self.markdown.safeMode)): - text = text.replace( - "

%s

" % - (self.markdown.htmlStash.get_placeholder(i)), + replacements["

%s

" % + (self.markdown.htmlStash.get_placeholder(i))] = \ html + "\n" - ) - text = text.replace( - self.markdown.htmlStash.get_placeholder(i), html - ) + replacements[self.markdown.htmlStash.get_placeholder(i)] = html + + if replacements: + pattern = re.compile("|".join(re.escape(k) for k in replacements)) + text = pattern.sub(lambda m: replacements[m.group(0)], text) + return text def escape(self, html): From e56f0cd9b0c6f934bac62751234c0f4df2050ac6 Mon Sep 17 00:00:00 2001 From: Maurice van der Pot Date: Sat, 27 Feb 2016 00:34:42 +0100 Subject: [PATCH 2/3] Added assertStartsWith to tests to give better failure messages The failure printed when self.assertTrue was used with str.startswith did not show the string that was being searched. --- tests/test_extensions.py | 64 +++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/tests/test_extensions.py b/tests/test_extensions.py index 72ce21256..e9b611222 100644 --- a/tests/test_extensions.py +++ b/tests/test_extensions.py @@ -11,6 +11,15 @@ import unittest import markdown +class TestCaseWithAssertStartsWith(unittest.TestCase): + + def assertStartsWith(self, expectedPrefix, text, msg=None): + if not text.startswith(expectedPrefix): + if len(expectedPrefix) + 5 < len(text): + text = text[:len(expectedPrefix) + 5] + '...' + standardMsg = '%s not found at the start of %s' % (repr(expectedPrefix), + repr(text)) + self.fail(self._formatMessage(msg, standardMsg)) class TestExtensionClass(unittest.TestCase): """ Test markdown.extensions.Extension. """ @@ -85,8 +94,7 @@ def testNestedAbbr(self): 'and ABBR

' ) - -class TestCodeHilite(unittest.TestCase): +class TestCodeHilite(TestCaseWithAssertStartsWith): """ Test codehilite extension. """ def setUp(self): @@ -101,7 +109,7 @@ def testBasicCodeHilite(self): md = markdown.Markdown(extensions=['markdown.extensions.codehilite']) if self.has_pygments: # Pygments can use random lexer here as we did not specify the language - self.assertTrue(md.convert(text).startswith('
'))
+            self.assertStartsWith('
', md.convert(text))
         else:
             self.assertEqual(
                 md.convert(text),
@@ -117,10 +125,9 @@ def testLinenumsTrue(self):
             # Different versions of pygments output slightly different markup.
             # So we use 'startwith' and test just enough to confirm that
             # pygments received and processed linenums.
-            self.assertTrue(
-                md.convert(text).startswith(
-                    '
' - ) + self.assertStartsWith( + '
', + md.convert(text) ) else: self.assertEqual( @@ -134,7 +141,7 @@ def testLinenumsFalse(self): md = markdown.Markdown( extensions=[markdown.extensions.codehilite.CodeHiliteExtension(linenums=False)]) if self.has_pygments: - self.assertTrue(md.convert(text).startswith('
'))
+            self.assertStartsWith('
', md.convert(text))
         else:
             self.assertEqual(
                 md.convert(text),
@@ -164,10 +171,9 @@ def testLinenumsNoneWithShebang(self):
             # Differant versions of pygments output slightly different markup.
             # So we use 'startwith' and test just enough to confirm that
             # pygments received and processed linenums.
-            self.assertTrue(
-                md.convert(text).startswith(
-                    '
' - ) + self.assertStartsWith( + '
', + md.convert(text) ) else: self.assertEqual( @@ -182,7 +188,7 @@ def testLinenumsNoneWithColon(self): extensions=[markdown.extensions.codehilite.CodeHiliteExtension(linenums=None)] ) if self.has_pygments: - self.assertTrue(md.convert(text).startswith('
Header 1\n'
             '

Header 2

' ) - self.assertTrue(md.toc.startswith('
')) + self.assertStartsWith('
', md.toc) def testReset(self): """ Test TOC Reset. """ self.assertEqual(self.md.toc, '') self.md.convert('# Header 1\n\n## Header 2') - self.assertTrue(self.md.toc.startswith('
')) + self.assertStartsWith('
', self.md.toc) self.md.reset() self.assertEqual(self.md.toc, '') @@ -771,7 +778,10 @@ def testTitle(self): extensions=[markdown.extensions.toc.TocExtension(title='Table of Contents')] ) md.convert('# Header 1\n\n## Header 2') - self.assertTrue(md.toc.startswith('
Table of Contents
    ')) + self.assertStartsWith( + '
    Table of Contents
      ', + md.toc + ) def testWithAttrList(self): """ Test TOC with attr_list Extension. """ From 596601380fc2911e25394b7675aa34f1cab761a9 Mon Sep 17 00:00:00 2001 From: Maurice van der Pot Date: Sat, 27 Feb 2016 00:47:55 +0100 Subject: [PATCH 3/3] Added a few empty lines in the test to satisfy flake8 --- tests/test_extensions.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_extensions.py b/tests/test_extensions.py index e9b611222..30b21bb50 100644 --- a/tests/test_extensions.py +++ b/tests/test_extensions.py @@ -11,6 +11,7 @@ import unittest import markdown + class TestCaseWithAssertStartsWith(unittest.TestCase): def assertStartsWith(self, expectedPrefix, text, msg=None): @@ -21,6 +22,7 @@ def assertStartsWith(self, expectedPrefix, text, msg=None): repr(text)) self.fail(self._formatMessage(msg, standardMsg)) + class TestExtensionClass(unittest.TestCase): """ Test markdown.extensions.Extension. """ @@ -94,6 +96,7 @@ def testNestedAbbr(self): 'and ABBR

      ' ) + class TestCodeHilite(TestCaseWithAssertStartsWith): """ Test codehilite extension. """