""" Python Markdown A Python implementation of John Gruber's Markdown. Documentation: https://python-markdown.github.io/ GitHub: https://github.com/Python-Markdown/markdown/ PyPI: https://pypi.org/project/Markdown/ Started by Manfred Stienstra (http://www.dwerg.net/). Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org). Currently maintained by Waylan Limberg (https://github.com/waylan), Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser). Copyright 2007-2019 The Python Markdown Project (v. 1.7 and later) Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) Copyright 2004 Manfred Stienstra (the original version) License: BSD (see LICENSE.md for details). """ from markdown.test_tools import TestCase import markdown import markdown.extensions.codehilite import os try: import pygments # noqa import pygments.formatters # noqa has_pygments = True except ImportError: has_pygments = False # The version required by the tests is the version specified and installed in the `pygments` tox environment. # In any environment where the `PYGMENTS_VERSION` environment variable 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 TestFencedCode(TestCase): def testBasicFence(self): self.assertMarkdownRenders( self.dedent( ''' A paragraph before a fenced code block: ``` Fenced code block ``` ''' ), self.dedent( '''
A paragraph before a fenced code block:
Fenced code block
'''
),
extensions=['fenced_code']
)
def testNestedFence(self):
self.assertMarkdownRenders(
self.dedent(
'''
````
```
````
'''
),
self.dedent(
'''
```
'''
),
extensions=['fenced_code']
)
def testFencedTildes(self):
self.assertMarkdownRenders(
self.dedent(
'''
~~~
# Arbitrary code
``` # these backticks will not close the block
~~~
'''
),
self.dedent(
'''
# Arbitrary code
``` # these backticks will not close the block
'''
),
extensions=['fenced_code']
)
def testFencedLanguageNoDot(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` python
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=['fenced_code']
)
def testFencedLanguageWithDot(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` .python
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=['fenced_code']
)
def test_fenced_code_in_raw_html(self):
self.assertMarkdownRenders(
self.dedent(
"""
Begone placeholders!
# Some python code
'''
),
extensions=['fenced_code']
)
def testFencedMultipleClassesInAttr(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` {.python .foo .bar}
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=['fenced_code']
)
def testFencedIdInAttr(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` { #foo }
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=['fenced_code']
)
def testFencedIdAndLangInAttr(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` { .python #foo }
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=['fenced_code']
)
def testFencedIdAndLangAndClassInAttr(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` { .python #foo .bar }
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=['fenced_code']
)
def testFencedLanguageIdAndPygmentsDisabledInAttrNoCodehilite(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` { .python #foo use_pygments=False }
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=['fenced_code']
)
def testFencedLanguageIdAndPygmentsEnabledInAttrNoCodehilite(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` { .python #foo use_pygments=True }
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=['fenced_code']
)
def testFencedLanguageNoCodehiliteWithAttrList(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` { .python foo=bar }
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=['fenced_code', 'attr_list']
)
def testFencedLanguagePygmentsDisabledInAttrNoCodehiliteWithAttrList(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` { .python foo=bar use_pygments=False }
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=['fenced_code', 'attr_list']
)
def testFencedLanguagePygmentsEnabledInAttrNoCodehiliteWithAttrList(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` { .python foo=bar use_pygments=True }
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=['fenced_code', 'attr_list']
)
def testFencedLanguageNoPrefix(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` python
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=[markdown.extensions.fenced_code.FencedCodeExtension(lang_prefix='')]
)
def testFencedLanguageAltPrefix(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` python
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=[markdown.extensions.fenced_code.FencedCodeExtension(lang_prefix='lang-')]
)
def testFencedCodeEscapedAttrs(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` { ."weird #"foo bar=">baz }
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=['fenced_code', 'attr_list']
)
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 test_shebang(self):
if has_pygments:
expected = '''
#!test
#!test
'''
self.assertMarkdownRenders(
self.dedent(
'''
```
#!test
```
'''
),
self.dedent(
expected
),
extensions=[
markdown.extensions.codehilite.CodeHiliteExtension(linenums=None, guess_lang=False),
'fenced_code'
]
)
def testFencedCodeWithHighlightLines(self):
if has_pygments:
expected = self.dedent(
'''
line 1
line 2
line 3
line 1
line 2
line 3
'''
)
self.assertMarkdownRenders(
self.dedent(
'''
```hl_lines="1 3"
line 1
line 2
line 3
```
'''
),
expected,
extensions=[
markdown.extensions.codehilite.CodeHiliteExtension(linenums=None, guess_lang=False),
'fenced_code'
]
)
def testFencedLanguageAndHighlightLines(self):
if has_pygments:
expected = (
''
'line 1\n'
'line 2\n'
'line 3\n'
'
line 1
line 2
line 3
'''
)
self.assertMarkdownRenders(
self.dedent(
'''
``` .python hl_lines="1 3"
line 1
line 2
line 3
```
'''
),
expected,
extensions=[
markdown.extensions.codehilite.CodeHiliteExtension(linenums=None, guess_lang=False),
'fenced_code'
]
)
def testFencedLanguageAndPygmentsDisabled(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` .python
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=[
markdown.extensions.codehilite.CodeHiliteExtension(use_pygments=False),
'fenced_code'
]
)
def testFencedLanguageDoubleEscape(self):
if has_pygments:
expected = (
''
'<span'
'>This&'
'That</span'
'>\n'
'
'
'<span>This&That</span>\n'
'
'
)
self.assertMarkdownRenders(
self.dedent(
'''
```html
This&That
```
'''
),
expected,
extensions=[
markdown.extensions.codehilite.CodeHiliteExtension(),
'fenced_code'
]
)
def testFencedAmps(self):
if has_pygments:
expected = self.dedent(
'''
&
&
&amp;
&
&
&amp;
'''
)
self.assertMarkdownRenders(
self.dedent(
'''
```text
&
&
&
```
'''
),
expected,
extensions=[
markdown.extensions.codehilite.CodeHiliteExtension(),
'fenced_code'
]
)
def testFencedCodeWithHighlightLinesInAttr(self):
if has_pygments:
expected = self.dedent(
'''
line 1
line 2
line 3
line 1
line 2
line 3
'''
)
self.assertMarkdownRenders(
self.dedent(
'''
```{ hl_lines="1 3" }
line 1
line 2
line 3
```
'''
),
expected,
extensions=[
markdown.extensions.codehilite.CodeHiliteExtension(linenums=None, guess_lang=False),
'fenced_code'
]
)
def testFencedLanguageAndHighlightLinesInAttr(self):
if has_pygments:
expected = (
''
'line 1\n'
'line 2\n'
'line 3\n'
'
line 1
line 2
line 3
'''
)
self.assertMarkdownRenders(
self.dedent(
'''
``` { .python hl_lines="1 3" }
line 1
line 2
line 3
```
'''
),
expected,
extensions=[
markdown.extensions.codehilite.CodeHiliteExtension(linenums=None, guess_lang=False),
'fenced_code'
]
)
def testFencedLanguageIdInAttrAndPygmentsDisabled(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` { .python #foo }
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=[
markdown.extensions.codehilite.CodeHiliteExtension(use_pygments=False),
'fenced_code'
]
)
def testFencedLanguageIdAndPygmentsDisabledInAttr(self):
self.assertMarkdownRenders(
self.dedent(
'''
``` { .python #foo use_pygments=False }
# Some python code
```
'''
),
self.dedent(
'''
# Some python code
'''
),
extensions=['codehilite', 'fenced_code']
)
def testFencedLanguageAttrCssclass(self):
if has_pygments:
expected = self.dedent(
'''
# Some python code
# Some python code\n'
'
'
)
self.assertMarkdownRenders(
self.dedent(
'''
``` { .python css_class='pygments' }
# Some python code
```
'''
),
expected,
extensions=['codehilite', 'fenced_code']
)
def testFencedLanguageAttrLinenums(self):
if has_pygments:
expected = (
'1 | '
''
' |
# Some python code\n'
'
'
)
self.assertMarkdownRenders(
self.dedent(
'''
``` { .python linenums=True }
# Some python code
```
'''
),
expected,
extensions=['codehilite', 'fenced_code']
)
def testFencedLanguageAttrGuesslang(self):
if has_pygments:
expected = self.dedent(
'''
# Some python code
# Some python code\n'
'
'
)
self.assertMarkdownRenders(
self.dedent(
'''
``` { guess_lang=False }
# Some python code
```
'''
),
expected,
extensions=['codehilite', 'fenced_code']
)
def testFencedLanguageAttrNoclasses(self):
if has_pygments:
expected = (
''
'# Some python code\n'
'
# Some python code\n'
'
'
)
self.assertMarkdownRenders(
self.dedent(
'''
``` { .python noclasses=True }
# Some python code
```
'''
),
expected,
extensions=['codehilite', 'fenced_code']
)
def testFencedMultipleBlocksSameStyle(self):
if has_pygments:
# See also: https://github.com/Python-Markdown/markdown/issues/1240
expected = (
''
'# First Code Block\n'
'
Normal paragraph
\n' ''
'# Second Code Block\n'
'
# First Code Block
Normal paragraph
# Second Code Block
'''
self.assertMarkdownRenders(
self.dedent(
'''
``` { .python }
# First Code Block
```
Normal paragraph
``` { .python }
# Second Code Block
```
'''
),
self.dedent(
expected
),
extensions=[
markdown.extensions.codehilite.CodeHiliteExtension(pygments_style="native", noclasses=True),
'fenced_code'
]
)
def testCustomPygmentsFormatter(self):
if has_pygments:
class CustomFormatter(pygments.formatters.HtmlFormatter):
def wrap(self, source, outfile):
return self._wrap_div(self._wrap_code(source))
def _wrap_code(self, source):
yield 0, ''
for i, t in source:
if i == 1:
t += '
'
yield i, t
yield 0, '
'
expected = '''
hello world
hello another world
hello world
hello another world
'''
self.assertMarkdownRenders(
self.dedent(
'''
```
hello world
hello another world
```
'''
),
self.dedent(
expected
),
extensions=[
markdown.extensions.codehilite.CodeHiliteExtension(
pygments_formatter=CustomFormatter,
guess_lang=False,
),
'fenced_code'
]
)
def testPygmentsAddLangClassFormatter(self):
if has_pygments:
class CustomAddLangHtmlFormatter(pygments.formatters.HtmlFormatter):
def __init__(self, lang_str='', **options):
super().__init__(**options)
self.lang_str = lang_str
def _wrap_code(self, source):
yield 0, f''
yield from source
yield 0, '
'
expected = '''
hello world
hello another world
hello world
hello another world
'''
self.assertMarkdownRenders(
self.dedent(
'''
```text
hello world
hello another world
```
'''
),
self.dedent(
expected
),
extensions=[
markdown.extensions.codehilite.CodeHiliteExtension(
guess_lang=False,
pygments_formatter=CustomAddLangHtmlFormatter,
),
'fenced_code'
]
)
def testSvgCustomPygmentsFormatter(self):
if has_pygments:
expected = '''
'''
else:
expected = '''
hello world
hello another world
'''
self.assertMarkdownRenders(
self.dedent(
'''
```
hello world
hello another world
```
'''
),
self.dedent(
expected
),
extensions=[
markdown.extensions.codehilite.CodeHiliteExtension(
pygments_formatter='svg',
linenos=False,
guess_lang=False,
),
'fenced_code'
]
)
def testInvalidCustomPygmentsFormatter(self):
if has_pygments:
expected = '''
hello world
hello another world
hello world
hello another world
'''
self.assertMarkdownRenders(
self.dedent(
'''
```
hello world
hello another world
```
'''
),
self.dedent(
expected
),
extensions=[
markdown.extensions.codehilite.CodeHiliteExtension(
pygments_formatter='invalid',
guess_lang=False,
),
'fenced_code'
]
)