Imported Upstream version 3.3.1 upstream/3.3.1
authorDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 15 Jul 2022 00:02:35 +0000 (09:02 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 15 Jul 2022 00:02:35 +0000 (09:02 +0900)
docs/change_log/index.md
docs/contributing.md
docs/extensions/fenced_code_blocks.md
markdown/__meta__.py
markdown/extensions/fenced_code.py
markdown/htmlparser.py
markdown/test_tools.py
tests/test_syntax/blocks/test_html_blocks.py
tests/test_syntax/extensions/test_code_hilite.py
tests/test_syntax/extensions/test_fenced_code.py
tox.ini

index 40f017e5e93c38aaf2810d8a348e7eccaa380c55..58e456d05537e7d86fc83335cbef0652846c7f2c 100644 (file)
@@ -3,6 +3,11 @@ title: Change Log
 Python-Markdown Change Log
 =========================
 
+Oct 12, 2020: version 3.3.1 (a bug-fix release).
+
+* Correctly parse raw `script` and `style` tags (#1036).
+* Ensure consistent class handling by `fenced_code` and `codehilite` (#1032).
+
 Oct 6, 2020: version 3.3 ([Notes](release-3.3.md)).
 
 May 8, 2020: version 3.2.2 (a bug-fix release).
index 1dbdd4bec0fcafa9771785a11a11022cf1a690fa..20f21c252d5c6f050b8a6a3b313ac7547b88c077 100644 (file)
@@ -346,7 +346,7 @@ with no arguments. See help (`tox -h`) for more options.
 Python-Markdown follows [Semantic Versioning] and uses the
 `MAJOR.MINOR.PATCH[.dev#|a#|b#|rc#]` format for identifying releases. The status
 of the `master` branch should always be identified in the `__version_info__`
-tuple defined in [`markdown/__init__.py`][markdown/__init__.py]. The contents of
+tuple defined in [`markdown/__meta__.py`][markdown/__meta__.py]. The contents of
 that tuple will automatically be converted into a normalized version which
 conforms to [PEP 440]. An invalid `__version_info__` tuple will raise an error,
 preventing the library from running and the package from building.
@@ -398,7 +398,7 @@ following steps:
 2. Confirm that the release notes and change log have been updated and indicate
    the date of the new release.
 
-3. Update the version defined in [`markdown/__init__.py`][markdown/__init__.py].
+3. Update the version defined in [`markdown/__meta__.py`][markdown/__meta__.py].
 
 4. Build a local copy of the documentation, browse through the pages and
    confirm that no obvious issues exist with the documentation.
@@ -509,7 +509,7 @@ label from the same group.
 [aspell]: http://aspell.net/
 [test tools]: test_tools.md
 [Semantic Versioning]: https://semver.org/
-[markdown/__init__.py]: https://github.com/Python-Markdown/markdown/blob/master/markdown/__init__.py#L43
+[markdown/__meta__.py]: https://github.com/Python-Markdown/markdown/blob/master/markdown/__meta__.py#L29
 [PEP 440]: https://www.python.org/dev/peps/pep-0440/
 [PyPI]: https://pypi.org/project/Markdown/
 [Python-Markdown/Python-Markdown.github.io]: https://github.com/Python-Markdown/Python-Markdown.github.io
index c495475d14283f6d4a3c817962b99ea2e9001b6b..fc5c9ca2d70e825b312b1a0e3c3e4e01f5f47690 100644 (file)
@@ -130,13 +130,13 @@ In addition to the language, additional classes may be defined by prefixing them
 ````
 
 When defining multiple classes, only the first class will be used as the "language" for the code block. All others are
-assigned to the `<code>` tag unaltered. Additionally, the curly braces and dot are required for all classes, including
+assigned to the `<pre>` tag unaltered. Additionally, the curly braces and dot are required for all classes, including
 the language class if more than one class is defined.
 
 The above example will output the following HTML:
 
 ```html
-<pre><code class="language-html foo bar">&lt;p&gt;HTML Document&lt;/p&gt;
+<pre class="foo bar"><code class="language-html">&lt;p&gt;HTML Document&lt;/p&gt;
 </code></pre>
 ```
 
index a6f6e48adb8147eb60eb58cd54d0a339aca82d81..09ce6e7064579b921116100452ac4a0c80823882 100644 (file)
@@ -26,7 +26,7 @@ License: BSD (see LICENSE.md for details).
 # (1, 2, 0, 'beta', 2) => "1.2b2"
 # (1, 2, 0, 'rc', 4) => "1.2rc4"
 # (1, 2, 0, 'final', 0) => "1.2"
-__version_info__ = (3, 3, 0, 'final', 0)
+__version_info__ = (3, 3, 1, 'final', 0)
 
 
 def _get_version(version_info):
index e3b3f1bb87f709d84ae5f7563c2805a4ba647e92..716b46772bdfceb35bcb0a0e4e150899f210dd60 100644 (file)
@@ -88,11 +88,10 @@ class FencedBlockPreprocessor(Preprocessor):
                 if m.group('attrs'):
                     id, classes, config = self.handle_attrs(get_attrs(m.group('attrs')))
                     if len(classes):
-                        lang = classes[0]
+                        lang = classes.pop(0)
                 else:
                     if m.group('lang'):
                         lang = m.group('lang')
-                        classes.append(lang)
                     if m.group('hl_lines'):
                         # Support hl_lines outside of attrs for backward-compatibility
                         config['hl_lines'] = parse_hl_lines(m.group('hl_lines'))
@@ -119,12 +118,11 @@ class FencedBlockPreprocessor(Preprocessor):
 
                     code = highliter.hilite()
                 else:
-                    id_attr = class_attr = kv_pairs = ''
+                    id_attr = lang_attr = class_attr = kv_pairs = ''
+                    if lang:
+                        lang_attr = ' class="{}{}"'.format(self.config.get('lang_prefix', 'language-'), lang)
                     if classes:
-                        class_attr = ' class="{}{}"'.format(
-                            self.config.get('lang_prefix', 'language-'),
-                            ' '.join(classes)
-                        )
+                        class_attr = ' class="{}"'.format(' '.join(classes))
                     if id:
                         id_attr = ' id="{}"'.format(id)
                     if self.use_attr_list and config and not config.get('use_pygments', False):
@@ -134,9 +132,10 @@ class FencedBlockPreprocessor(Preprocessor):
                         kv_pairs = ' ' + ' '.join(
                             '{k}="{v}"'.format(k=k, v=v) for k, v in config.items() if k != 'use_pygments'
                         )
-                    code = '<pre{id}><code{cls}{kv}>{code}</code></pre>'.format(
+                    code = '<pre{id}{cls}><code{lang}{kv}>{code}</code></pre>'.format(
                         id=id_attr,
                         cls=class_attr,
+                        lang=lang_attr,
                         kv=kv_pairs,
                         code=self._escape(m.group('code'))
                     )
index f83ddeace1bed0240dba071a3fb03a3e1eeae222..6776d340fc536f3d1d0cb4c1a96bac947f207d50 100644 (file)
@@ -72,6 +72,13 @@ class HTMLExtractor(htmlparser.HTMLParser):
     def close(self):
         """Handle any buffered data."""
         super().close()
+        if len(self.rawdata):
+            # Temp fix for https://bugs.python.org/issue41989
+            # TODO: remove this when the bug is fixed in all supported Python versions.
+            if self.convert_charrefs and not self.cdata_elem:  # pragma: no cover
+                self.handle_data(htmlparser.unescape(self.rawdata))
+            else:
+                self.handle_data(self.rawdata)
         # Handle any unclosed tags.
         if len(self._cache):
             self.cleandoc.append(self.md.htmlStash.store(''.join(self._cache)))
@@ -124,6 +131,9 @@ class HTMLExtractor(htmlparser.HTMLParser):
             self._cache.append(text)
         else:
             self.cleandoc.append(text)
+            if tag in self.CDATA_CONTENT_ELEMENTS:
+                # This is presumably a standalone tag in a code span (see #1036).
+                self.clear_cdata_mode()
 
     def handle_endtag(self, tag):
         text = self.get_endtag_text(tag)
@@ -200,3 +210,63 @@ class HTMLExtractor(htmlparser.HTMLParser):
     def unknown_decl(self, data):
         end = ']]>' if data.startswith('CDATA[') else ']>'
         self.handle_empty_tag('<![{}{}'.format(data, end), is_block=True)
+
+    # The rest has been copied from base class in standard lib to address #1036.
+    # As __startag_text is private, all references to it must be in this subclass.
+    # The last few lines of parse_starttag are reversed so that handle_starttag
+    # can override cdata_mode in certain situations (in a code span).
+    __starttag_text = None
+
+    def get_starttag_text(self):
+        """Return full source of start tag: '<...>'."""
+        return self.__starttag_text
+
+    def parse_starttag(self, i):  # pragma: no cover
+        self.__starttag_text = None
+        endpos = self.check_for_whole_start_tag(i)
+        if endpos < 0:
+            return endpos
+        rawdata = self.rawdata
+        self.__starttag_text = rawdata[i:endpos]
+
+        # Now parse the data between i+1 and j into a tag and attrs
+        attrs = []
+        match = htmlparser.tagfind_tolerant.match(rawdata, i+1)
+        assert match, 'unexpected call to parse_starttag()'
+        k = match.end()
+        self.lasttag = tag = match.group(1).lower()
+        while k < endpos:
+            m = htmlparser.attrfind_tolerant.match(rawdata, k)
+            if not m:
+                break
+            attrname, rest, attrvalue = m.group(1, 2, 3)
+            if not rest:
+                attrvalue = None
+            elif attrvalue[:1] == '\'' == attrvalue[-1:] or \
+                 attrvalue[:1] == '"' == attrvalue[-1:]:  # noqa: E127
+                attrvalue = attrvalue[1:-1]
+            if attrvalue:
+                attrvalue = htmlparser.unescape(attrvalue)
+            attrs.append((attrname.lower(), attrvalue))
+            k = m.end()
+
+        end = rawdata[k:endpos].strip()
+        if end not in (">", "/>"):
+            lineno, offset = self.getpos()
+            if "\n" in self.__starttag_text:
+                lineno = lineno + self.__starttag_text.count("\n")
+                offset = len(self.__starttag_text) \
+                         - self.__starttag_text.rfind("\n")  # noqa: E127
+            else:
+                offset = offset + len(self.__starttag_text)
+            self.handle_data(rawdata[i:endpos])
+            return endpos
+        if end.endswith('/>'):
+            # XHTML-style empty tag: <span attr="value" />
+            self.handle_startendtag(tag, attrs)
+        else:
+            # *** set cdata_mode first so we can override it in handle_starttag (see #1036) ***
+            if tag in self.CDATA_CONTENT_ELEMENTS:
+                self.set_cdata_mode(tag)
+            self.handle_starttag(tag, attrs)
+        return endpos
index fb407bb65ccddbb5870855de974717bb0023db61..5f33619953c8523b6704d01c4255a7d749d2747a 100644 (file)
@@ -140,8 +140,11 @@ class LegacyTestMeta(type):
                     expected = f.read().replace("\r\n", "\n")
                 output = markdown(input, **kwargs)
                 if tidylib and normalize:
-                    expected = _normalize_whitespace(expected)
-                    output = _normalize_whitespace(output)
+                    try:
+                        expected = _normalize_whitespace(expected)
+                        output = _normalize_whitespace(output)
+                    except OSError:
+                        self.skipTest("Tidylib's c library not available.")
                 elif normalize:
                     self.skipTest('Tidylib not available.')
                 self.assertMultiLineEqual(output, expected)
index 0a2092d3f7fa41ea658cadfb8f2915d693d5ef16..3fea7667585feb6d5b72272d87e2f74bba150911 100644 (file)
@@ -1317,3 +1317,88 @@ class TestHTMLBlocks(TestCase):
                 """
             )
         )
+
+    def test_script_tags(self):
+        self.assertMarkdownRenders(
+            self.dedent(
+                """
+                <script>
+                *random stuff* <div> &amp;
+                </script>
+
+                <style>
+                **more stuff**
+                </style>
+                """
+            ),
+            self.dedent(
+                """
+                <script>
+                *random stuff* <div> &amp;
+                </script>
+
+                <style>
+                **more stuff**
+                </style>
+                """
+            )
+        )
+
+    def test_unclosed_script_tag(self):
+        # Ensure we have a working fix for https://bugs.python.org/issue41989
+        self.assertMarkdownRenders(
+            self.dedent(
+                """
+                <script>
+                *random stuff* <div> &amp;
+
+                Still part of the *script* tag
+                """
+            ),
+            self.dedent(
+                """
+                <script>
+                *random stuff* <div> &amp;
+
+                Still part of the *script* tag
+                """
+            )
+        )
+
+    def test_inline_script_tags(self):
+        # Ensure inline script tags doesn't cause the parser to eat content (see #1036).
+        self.assertMarkdownRenders(
+            self.dedent(
+                """
+                Text `<script>` more *text*.
+
+                <div>
+                *foo*
+                </div>
+
+                <div>
+
+                bar
+
+                </div>
+
+                A new paragraph with a closing `</script>` tag.
+                """
+            ),
+            self.dedent(
+                """
+                <p>Text <code>&lt;script&gt;</code> more <em>text</em>.</p>
+                <div>
+                *foo*
+                </div>
+
+                <div>
+
+                bar
+
+                </div>
+
+                <p>A new paragraph with a closing <code>&lt;/script&gt;</code> tag.</p>
+                """
+            )
+        )
index 8d5512d2fe501eebabc3dad2d53bdcd6559a685b..709aa963d59c79036dba98ef27fe8b5986dacca8 100644 (file)
@@ -21,6 +21,7 @@ License: BSD (see LICENSE.md for details).
 
 from markdown.test_tools import TestCase
 from markdown.extensions.codehilite import CodeHiliteExtension, CodeHilite
+import os
 
 try:
     import pygments  # noqa
@@ -28,10 +29,19 @@ try:
 except ImportError:
     has_pygments = False
 
+# The version required by the tests is the version specified and installed in the 'pygments' tox env.
+# In any environment where the PYGMENTS_VERSION environment variabe is either not defined or doesn't
+# match the version of Pygments installed, all tests which rely in pygments will be skipped.
+required_pygments_version = os.environ.get('PYGMENTS_VERSION', '')
+
 
 class TestCodeHiliteClass(TestCase):
     """ Test the markdown.extensions.codehilite.CodeHilite class. """
 
+    def setUp(self):
+        if has_pygments and pygments.__version__ != required_pygments_version:
+            self.skipTest(f'Pygments=={required_pygments_version} is required')
+
     maxDiff = None
 
     def assertOutputEquals(self, source, expected, **options):
@@ -205,7 +215,7 @@ class TestCodeHiliteClass(TestCase):
     def test_codehilite_linenos_inline(self):
         if has_pygments:
             expected = (
-                '<div class="codehilite"><pre><span></span><code><span class="lineno">1 </span>plain text\n'
+                '<div class="codehilite"><pre><span></span><code><span class="linenos">1</span>plain text\n'
                 '</code></pre></div>'
             )
         else:
@@ -259,7 +269,7 @@ class TestCodeHiliteClass(TestCase):
     def test_codehilite_linenostart(self):
         if has_pygments:
             expected = (
-                '<div class="codehilite"><pre><span></span><code><span class="lineno">42 </span>plain text\n'
+                '<div class="codehilite"><pre><span></span><code><span class="linenos">42</span>plain text\n'
                 '</code></pre></div>'
             )
         else:
@@ -274,9 +284,9 @@ class TestCodeHiliteClass(TestCase):
         if has_pygments:
             expected = (
                 '<div class="codehilite"><pre><span></span><code>'
-                '<span class="lineno">1 </span><span class="hll">line 1\n'
-                '</span><span class="lineno">2 </span>line 2\n'
-                '<span class="lineno">3 </span><span class="hll">line 3\n'
+                '<span class="linenos">1</span><span class="hll">line 1\n'
+                '</span><span class="linenos">2</span>line 2\n'
+                '<span class="linenos">3</span><span class="hll">line 3\n'
                 '</span></code></pre></div>'
             )
         else:
@@ -291,9 +301,9 @@ class TestCodeHiliteClass(TestCase):
     def test_codehilite_linenos_linenostep(self):
         if has_pygments:
             expected = (
-                '<div class="codehilite"><pre><span></span><code><span class="lineno">  </span>line 1\n'
-                '<span class="lineno">2 </span>line 2\n'
-                '<span class="lineno">  </span>line 3\n'
+                '<div class="codehilite"><pre><span></span><code><span class="linenos"> </span>line 1\n'
+                '<span class="linenos">2</span>line 2\n'
+                '<span class="linenos"> </span>line 3\n'
                 '</code></pre></div>'
             )
         else:
@@ -308,9 +318,9 @@ class TestCodeHiliteClass(TestCase):
     def test_codehilite_linenos_linenospecial(self):
         if has_pygments:
             expected = (
-                '<div class="codehilite"><pre><span></span><code><span class="lineno">1 </span>line 1\n'
-                '<span class="lineno special">2 </span>line 2\n'
-                '<span class="lineno">3 </span>line 3\n'
+                '<div class="codehilite"><pre><span></span><code><span class="linenos">1</span>line 1\n'
+                '<span class="linenos special">2</span>line 2\n'
+                '<span class="linenos">3</span>line 3\n'
                 '</code></pre></div>'
             )
         else:
@@ -340,6 +350,10 @@ class TestCodeHiliteClass(TestCase):
 class TestCodeHiliteExtension(TestCase):
     """ Test codehilite extension. """
 
+    def setUp(self):
+        if has_pygments and pygments.__version__ != required_pygments_version:
+            self.skipTest(f'Pygments=={required_pygments_version} is required')
+
     maxDiff = None
 
     def testBasicCodeHilite(self):
index e5de0b7f2223e4c9479d4779f2ff4d37edafe3b2..ac6ce17ab9ef86da6177999302a9914398fedf69 100644 (file)
@@ -21,16 +21,21 @@ License: BSD (see LICENSE.md for details).
 
 from markdown.test_tools import TestCase
 import markdown
+import os
 
+try:
+    import pygments  # noqa
+    has_pygments = True
+except ImportError:
+    has_pygments = False
 
-class TestFencedCode(TestCase):
+# The version required by the tests is the version specified and installed in the 'pygments' tox env.
+# In any environment where the PYGMENTS_VERSION environment variabe is either not defined or doesn't
+# match the version of Pygments installed, all tests which rely in pygments will be skipped.
+required_pygments_version = os.environ.get('PYGMENTS_VERSION', '')
 
-    def setUp(self):
-        self.has_pygments = True
-        try:
-            import pygments  # noqa
-        except ImportError:
-            self.has_pygments = False
+
+class TestFencedCode(TestCase):
 
     def testBasicFence(self):
         self.assertMarkdownRenders(
@@ -129,8 +134,255 @@ class TestFencedCode(TestCase):
             extensions=['fenced_code']
         )
 
+    def test_fenced_code_in_raw_html(self):
+        self.assertMarkdownRenders(
+            self.dedent(
+                """
+                <details>
+                ```
+                Begone placeholders!
+                ```
+                </details>
+                """
+            ),
+            self.dedent(
+                """
+                <details>
+
+                <pre><code>Begone placeholders!
+                </code></pre>
+
+                </details>
+                """
+            ),
+            extensions=['fenced_code']
+        )
+
+    def testFencedLanguageInAttr(self):
+        self.assertMarkdownRenders(
+            self.dedent(
+                '''
+                ``` {.python}
+                # Some python code
+                ```
+                '''
+            ),
+            self.dedent(
+                '''
+                <pre><code class="language-python"># Some python code
+                </code></pre>
+                '''
+            ),
+            extensions=['fenced_code']
+        )
+
+    def testFencedMultipleClassesInAttr(self):
+        self.assertMarkdownRenders(
+            self.dedent(
+                '''
+                ``` {.python .foo .bar}
+                # Some python code
+                ```
+                '''
+            ),
+            self.dedent(
+                '''
+                <pre class="foo bar"><code class="language-python"># Some python code
+                </code></pre>
+                '''
+            ),
+            extensions=['fenced_code']
+        )
+
+    def testFencedIdInAttr(self):
+        self.assertMarkdownRenders(
+            self.dedent(
+                '''
+                ``` { #foo }
+                # Some python code
+                ```
+                '''
+            ),
+            self.dedent(
+                '''
+                <pre id="foo"><code># Some python code
+                </code></pre>
+                '''
+            ),
+            extensions=['fenced_code']
+        )
+
+    def testFencedIdAndLangInAttr(self):
+        self.assertMarkdownRenders(
+            self.dedent(
+                '''
+                ``` { .python #foo }
+                # Some python code
+                ```
+                '''
+            ),
+            self.dedent(
+                '''
+                <pre id="foo"><code class="language-python"># Some python code
+                </code></pre>
+                '''
+            ),
+            extensions=['fenced_code']
+        )
+
+    def testFencedIdAndLangAndClassInAttr(self):
+        self.assertMarkdownRenders(
+            self.dedent(
+                '''
+                ``` { .python #foo .bar }
+                # Some python code
+                ```
+                '''
+            ),
+            self.dedent(
+                '''
+                <pre id="foo" class="bar"><code class="language-python"># Some python code
+                </code></pre>
+                '''
+            ),
+            extensions=['fenced_code']
+        )
+
+    def testFencedLanguageIdAndPygmentsDisabledInAttrNoCodehilite(self):
+        self.assertMarkdownRenders(
+            self.dedent(
+                '''
+                ``` { .python #foo use_pygments=False }
+                # Some python code
+                ```
+                '''
+            ),
+            self.dedent(
+                '''
+                <pre id="foo"><code class="language-python"># Some python code
+                </code></pre>
+                '''
+            ),
+            extensions=['fenced_code']
+        )
+
+    def testFencedLanguageIdAndPygmentsEnabledInAttrNoCodehilite(self):
+        self.assertMarkdownRenders(
+            self.dedent(
+                '''
+                ``` { .python #foo use_pygments=True }
+                # Some python code
+                ```
+                '''
+            ),
+            self.dedent(
+                '''
+                <pre id="foo"><code class="language-python"># Some python code
+                </code></pre>
+                '''
+            ),
+            extensions=['fenced_code']
+        )
+
+    def testFencedLanguageNoCodehiliteWithAttrList(self):
+        self.assertMarkdownRenders(
+            self.dedent(
+                '''
+                ``` { .python foo=bar }
+                # Some python code
+                ```
+                '''
+            ),
+            self.dedent(
+                '''
+                <pre><code class="language-python" foo="bar"># Some python code
+                </code></pre>
+                '''
+            ),
+            extensions=['fenced_code', 'attr_list']
+        )
+
+    def testFencedLanguagePygmentsDisabledInAttrNoCodehiliteWithAttrList(self):
+        self.assertMarkdownRenders(
+            self.dedent(
+                '''
+                ``` { .python foo=bar use_pygments=False }
+                # Some python code
+                ```
+                '''
+            ),
+            self.dedent(
+                '''
+                <pre><code class="language-python" foo="bar"># Some python code
+                </code></pre>
+                '''
+            ),
+            extensions=['fenced_code', 'attr_list']
+        )
+
+    def testFencedLanguagePygmentsEnabledInAttrNoCodehiliteWithAttrList(self):
+        self.assertMarkdownRenders(
+            self.dedent(
+                '''
+                ``` { .python foo=bar use_pygments=True }
+                # Some python code
+                ```
+                '''
+            ),
+            self.dedent(
+                '''
+                <pre><code class="language-python"># Some python code
+                </code></pre>
+                '''
+            ),
+            extensions=['fenced_code', 'attr_list']
+        )
+
+    def testFencedLanguageNoPrefix(self):
+        self.assertMarkdownRenders(
+            self.dedent(
+                '''
+                ``` python
+                # Some python code
+                ```
+                '''
+            ),
+            self.dedent(
+                '''
+                <pre><code class="python"># Some python code
+                </code></pre>
+                '''
+            ),
+            extensions=[markdown.extensions.fenced_code.FencedCodeExtension(lang_prefix='')]
+        )
+
+    def testFencedLanguageAltPrefix(self):
+        self.assertMarkdownRenders(
+            self.dedent(
+                '''
+                ``` python
+                # Some python code
+                ```
+                '''
+            ),
+            self.dedent(
+                '''
+                <pre><code class="lang-python"># Some python code
+                </code></pre>
+                '''
+            ),
+            extensions=[markdown.extensions.fenced_code.FencedCodeExtension(lang_prefix='lang-')]
+        )
+
+
+class TestFencedCodeWithCodehilite(TestCase):
+
+    def setUp(self):
+        if has_pygments and pygments.__version__ != required_pygments_version:
+            self.skipTest(f'Pygments=={required_pygments_version} is required')
+
     def testFencedCodeWithHighlightLines(self):
-        if self.has_pygments:
+        if has_pygments:
             expected = self.dedent(
                 '''
                 <div class="codehilite"><pre><span></span><code><span class="hll">line 1
@@ -166,9 +418,9 @@ class TestFencedCode(TestCase):
         )
 
     def testFencedLanguageAndHighlightLines(self):
-        if self.has_pygments:
+        if has_pygments:
             expected = (
-                '<div class="python codehilite"><pre><span></span><code>'
+                '<div class="codehilite"><pre><span></span><code>'
                 '<span class="hll"><span class="n">line</span> <span class="mi">1</span>\n'
                 '</span><span class="n">line</span> <span class="mi">2</span>\n'
                 '<span class="hll"><span class="n">line</span> <span class="mi">3</span>\n'
@@ -177,7 +429,7 @@ class TestFencedCode(TestCase):
         else:
             expected = self.dedent(
                     '''
-                    <pre class="python codehilite"><code class="language-python">line 1
+                    <pre class="codehilite"><code class="language-python">line 1
                     line 2
                     line 3
                     </code></pre>
@@ -222,9 +474,9 @@ class TestFencedCode(TestCase):
         )
 
     def testFencedLanguageDoubleEscape(self):
-        if self.has_pygments:
+        if has_pygments:
             expected = (
-                '<div class="html codehilite"><pre><span></span><code>'
+                '<div class="codehilite"><pre><span></span><code>'
                 '<span class="p">&lt;</span><span class="nt">span</span>'
                 '<span class="p">&gt;</span>This<span class="ni">&amp;amp;</span>'
                 'That<span class="p">&lt;/</span><span class="nt">span</span>'
@@ -233,7 +485,7 @@ class TestFencedCode(TestCase):
             )
         else:
             expected = (
-                '<pre class="html codehilite"><code class="language-html">'
+                '<pre class="codehilite"><code class="language-html">'
                 '&lt;span&gt;This&amp;amp;That&lt;/span&gt;\n'
                 '</code></pre>'
             )
@@ -253,10 +505,10 @@ class TestFencedCode(TestCase):
         )
 
     def testFencedAmps(self):
-        if self.has_pygments:
+        if has_pygments:
             expected = self.dedent(
                 '''
-                <div class="text codehilite"><pre><span></span><code>&amp;
+                <div class="codehilite"><pre><span></span><code>&amp;
                 &amp;amp;
                 &amp;amp;amp;
                 </code></pre></div>
@@ -265,7 +517,7 @@ class TestFencedCode(TestCase):
         else:
             expected = self.dedent(
                 '''
-                <pre class="text codehilite"><code class="language-text">&amp;
+                <pre class="codehilite"><code class="language-text">&amp;
                 &amp;amp;
                 &amp;amp;amp;
                 </code></pre>
@@ -288,122 +540,8 @@ class TestFencedCode(TestCase):
             ]
         )
 
-    def test_fenced_code_in_raw_html(self):
-        self.assertMarkdownRenders(
-            self.dedent(
-                """
-                <details>
-                ```
-                Begone placeholders!
-                ```
-                </details>
-                """
-            ),
-            self.dedent(
-                """
-                <details>
-
-                <pre><code>Begone placeholders!
-                </code></pre>
-
-                </details>
-                """
-            ),
-            extensions=['fenced_code']
-        )
-
-    def testFencedLanguageInAttr(self):
-        self.assertMarkdownRenders(
-            self.dedent(
-                '''
-                ``` {.python}
-                # Some python code
-                ```
-                '''
-            ),
-            self.dedent(
-                '''
-                <pre><code class="language-python"># Some python code
-                </code></pre>
-                '''
-            ),
-            extensions=['fenced_code']
-        )
-
-    def testFencedMultipleClassesInAttr(self):
-        self.assertMarkdownRenders(
-            self.dedent(
-                '''
-                ``` {.python .foo .bar}
-                # Some python code
-                ```
-                '''
-            ),
-            self.dedent(
-                '''
-                <pre><code class="language-python foo bar"># Some python code
-                </code></pre>
-                '''
-            ),
-            extensions=['fenced_code']
-        )
-
-    def testFencedIdInAttr(self):
-        self.assertMarkdownRenders(
-            self.dedent(
-                '''
-                ``` { #foo }
-                # Some python code
-                ```
-                '''
-            ),
-            self.dedent(
-                '''
-                <pre id="foo"><code># Some python code
-                </code></pre>
-                '''
-            ),
-            extensions=['fenced_code']
-        )
-
-    def testFencedIdAndLangInAttr(self):
-        self.assertMarkdownRenders(
-            self.dedent(
-                '''
-                ``` { .python #foo }
-                # Some python code
-                ```
-                '''
-            ),
-            self.dedent(
-                '''
-                <pre id="foo"><code class="language-python"># Some python code
-                </code></pre>
-                '''
-            ),
-            extensions=['fenced_code']
-        )
-
-    def testFencedIdAndLangAndClassInAttr(self):
-        self.assertMarkdownRenders(
-            self.dedent(
-                '''
-                ``` { .python #foo .bar }
-                # Some python code
-                ```
-                '''
-            ),
-            self.dedent(
-                '''
-                <pre id="foo"><code class="language-python bar"># Some python code
-                </code></pre>
-                '''
-            ),
-            extensions=['fenced_code']
-        )
-
     def testFencedCodeWithHighlightLinesInAttr(self):
-        if self.has_pygments:
+        if has_pygments:
             expected = self.dedent(
                 '''
                 <div class="codehilite"><pre><span></span><code><span class="hll">line 1
@@ -439,9 +577,9 @@ class TestFencedCode(TestCase):
         )
 
     def testFencedLanguageAndHighlightLinesInAttr(self):
-        if self.has_pygments:
+        if has_pygments:
             expected = (
-                '<div class="python codehilite"><pre><span></span><code>'
+                '<div class="codehilite"><pre><span></span><code>'
                 '<span class="hll"><span class="n">line</span> <span class="mi">1</span>\n'
                 '</span><span class="n">line</span> <span class="mi">2</span>\n'
                 '<span class="hll"><span class="n">line</span> <span class="mi">3</span>\n'
@@ -450,7 +588,7 @@ class TestFencedCode(TestCase):
         else:
             expected = self.dedent(
                     '''
-                    <pre class="python codehilite"><code class="language-python">line 1
+                    <pre class="codehilite"><code class="language-python">line 1
                     line 2
                     line 3
                     </code></pre>
@@ -512,53 +650,17 @@ class TestFencedCode(TestCase):
             extensions=['codehilite', 'fenced_code']
         )
 
-    def testFencedLanguageIdAndPygmentsDisabledInAttrNoCodehilite(self):
-        self.assertMarkdownRenders(
-            self.dedent(
-                '''
-                ``` { .python #foo use_pygments=False }
-                # Some python code
-                ```
-                '''
-            ),
-            self.dedent(
-                '''
-                <pre id="foo"><code class="language-python"># Some python code
-                </code></pre>
-                '''
-            ),
-            extensions=['fenced_code']
-        )
-
-    def testFencedLanguageIdAndPygmentsEnabledInAttrNoCodehilite(self):
-        self.assertMarkdownRenders(
-            self.dedent(
-                '''
-                ``` { .python #foo use_pygments=True }
-                # Some python code
-                ```
-                '''
-            ),
-            self.dedent(
-                '''
-                <pre id="foo"><code class="language-python"># Some python code
-                </code></pre>
-                '''
-            ),
-            extensions=['fenced_code']
-        )
-
     def testFencedLanguageAttrCssclass(self):
-        if self.has_pygments:
+        if has_pygments:
             expected = self.dedent(
                 '''
-                <div class="python pygments"><pre><span></span><code><span class="c1"># Some python code</span>
+                <div class="pygments"><pre><span></span><code><span class="c1"># Some python code</span>
                 </code></pre></div>
                 '''
             )
         else:
             expected = (
-                '<pre class="python pygments"><code class="language-python"># Some python code\n'
+                '<pre class="pygments"><code class="language-python"># Some python code\n'
                 '</code></pre>'
             )
         self.assertMarkdownRenders(
@@ -574,18 +676,18 @@ class TestFencedCode(TestCase):
         )
 
     def testFencedLanguageAttrLinenums(self):
-        if self.has_pygments:
+        if has_pygments:
             expected = (
-                '<table class="python codehilitetable"><tr>'
+                '<table class="codehilitetable"><tr>'
                 '<td class="linenos"><div class="linenodiv"><pre>1</pre></div></td>'
-                '<td class="code"><div class="python codehilite"><pre><span></span>'
+                '<td class="code"><div class="codehilite"><pre><span></span>'
                 '<code><span class="c1"># Some python code</span>\n'
                 '</code></pre></div>\n'
                 '</td></tr></table>'
             )
         else:
             expected = (
-                '<pre class="python codehilite"><code class="language-python linenums"># Some python code\n'
+                '<pre class="codehilite"><code class="language-python linenums"># Some python code\n'
                 '</code></pre>'
             )
         self.assertMarkdownRenders(
@@ -601,7 +703,7 @@ class TestFencedCode(TestCase):
         )
 
     def testFencedLanguageAttrGuesslang(self):
-        if self.has_pygments:
+        if has_pygments:
             expected = self.dedent(
                 '''
                 <div class="codehilite"><pre><span></span><code># Some python code
@@ -626,16 +728,16 @@ class TestFencedCode(TestCase):
         )
 
     def testFencedLanguageAttrNoclasses(self):
-        if self.has_pygments:
+        if has_pygments:
             expected = (
-                '<div class="python codehilite" style="background: #f8f8f8">'
-                '<pre style="line-height: 125%"><span></span><code>'
+                '<div class="codehilite" style="background: #f8f8f8">'
+                '<pre style="line-height: 125%; margin: 0;"><span></span><code>'
                 '<span style="color: #408080; font-style: italic"># Some python code</span>\n'
                 '</code></pre></div>'
             )
         else:
             expected = (
-                '<pre class="python codehilite"><code class="language-python"># Some python code\n'
+                '<pre class="codehilite"><code class="language-python"># Some python code\n'
                 '</code></pre>'
             )
         self.assertMarkdownRenders(
@@ -649,93 +751,3 @@ class TestFencedCode(TestCase):
             expected,
             extensions=['codehilite', 'fenced_code']
         )
-
-    def testFencedLanguageNoCodehiliteWithAttrList(self):
-        self.assertMarkdownRenders(
-            self.dedent(
-                '''
-                ``` { .python foo=bar }
-                # Some python code
-                ```
-                '''
-            ),
-            self.dedent(
-                '''
-                <pre><code class="language-python" foo="bar"># Some python code
-                </code></pre>
-                '''
-            ),
-            extensions=['fenced_code', 'attr_list']
-        )
-
-    def testFencedLanguagePygmentsDisabledInAttrNoCodehiliteWithAttrList(self):
-        self.assertMarkdownRenders(
-            self.dedent(
-                '''
-                ``` { .python foo=bar use_pygments=False }
-                # Some python code
-                ```
-                '''
-            ),
-            self.dedent(
-                '''
-                <pre><code class="language-python" foo="bar"># Some python code
-                </code></pre>
-                '''
-            ),
-            extensions=['fenced_code', 'attr_list']
-        )
-
-    def testFencedLanguagePygmentsEnabledInAttrNoCodehiliteWithAttrList(self):
-        self.assertMarkdownRenders(
-            self.dedent(
-                '''
-                ``` { .python foo=bar use_pygments=True }
-                # Some python code
-                ```
-                '''
-            ),
-            self.dedent(
-                '''
-                <pre><code class="language-python"># Some python code
-                </code></pre>
-                '''
-            ),
-            extensions=['fenced_code', 'attr_list']
-        )
-
-    def testFencedLanguageNoPrefix(self):
-        self.assertMarkdownRenders(
-            self.dedent(
-                '''
-                ``` python
-                # Some python code
-                ```
-                '''
-            ),
-            self.dedent(
-                '''
-                <pre><code class="python"># Some python code
-                </code></pre>
-                '''
-            ),
-            extensions=[markdown.extensions.fenced_code.FencedCodeExtension(lang_prefix='')]
-        )
-
-    def testFencedLanguageAltPrefix(self):
-        self.assertMarkdownRenders(
-            self.dedent(
-                '''
-                ``` python
-                # Some python code
-                ```
-                '''
-            ),
-            self.dedent(
-                '''
-                <pre><code class="lang-python"># Some python code
-                </code></pre>
-                '''
-            ),
-            extensions=[markdown.extensions.fenced_code.FencedCodeExtension(lang_prefix='lang-')]
-        )
diff --git a/tox.ini b/tox.ini
index a36c7ee68a59ad8c18fe388b54088f178f88e2bc..851826ae2be16f7fc95a6488d70afe2f5c17a620 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -12,9 +12,11 @@ commands =
 
 [testenv:pygments]
 # Run tests with pygments installed (override deps only).
+setenv =
+    PYGMENTS_VERSION = 2.7.1
 deps =
     pytidylib
-    pygments==2.5.2
+    pygments=={env:PYGMENTS_VERSION}
 
 [testenv:flake8]
 deps = flake8