diff options
-rw-r--r-- | docs/change_log/index.md | 2 | ||||
-rw-r--r-- | docs/change_log/release-3.4.md | 44 | ||||
-rw-r--r-- | docs/extensions/tables.md | 22 | ||||
-rw-r--r-- | markdown/extensions/tables.py | 19 | ||||
-rw-r--r-- | tests/extensions/extra/tables.html | 466 | ||||
-rw-r--r-- | tests/extensions/extra/tables.txt | 169 | ||||
-rw-r--r-- | tests/test_legacy.py | 2 | ||||
-rw-r--r-- | tests/test_syntax/extensions/test_tables.py | 860 |
8 files changed, 943 insertions, 641 deletions
diff --git a/docs/change_log/index.md b/docs/change_log/index.md index 09ace62..fc78087 100644 --- a/docs/change_log/index.md +++ b/docs/change_log/index.md @@ -3,6 +3,8 @@ title: Change Log Python-Markdown Change Log ========================= +Under development: version 3.4.0 ([Notes](release-3.4.md)). + May 5, 2022: version 3.3.7 (a bug-fix release). * Disallow square brackets in reference link ids (#1209). diff --git a/docs/change_log/release-3.4.md b/docs/change_log/release-3.4.md new file mode 100644 index 0000000..0070da9 --- /dev/null +++ b/docs/change_log/release-3.4.md @@ -0,0 +1,44 @@ +title: Release Notes for v3.4 + +# Python-Markdown 3.4 Release Notes + +Python-Markdown version 3.4 supports Python versions 3.6, 3.7, 3.8, 3.9 and PyPy3. + +## Backwards-incompatible changes + +### The `table` extension now uses a `style` attribute instead of `align` attribute for alignment. + +The [HTML4 spec][spec4] specifically +deprecates the use of the `align` attribute and it does not appear at all in the +[HTML5 spec][spec5]. Therefore, by default, the [table] extension will now use the `style` +attribute (setting just the `text-align` property) in `td` and `th` blocks. + +[spec4]: https://www.w3.org/TR/html4/present/graphics.html#h-15.1.2 +[spec5]: https://www.w3.org/TR/html53/tabular-data.html#attributes-common-to-td-and-th-elements + +The former behavior is available by setting the setting `use_align_attribute` configuration +option to `True` when adding the extension. + +For example, to configure the old `align` behavior: + +```python +from markdown.extensions.tables import TableExtension + +markdown.markdown(src, extensions=[TableExtension(use_align_attribute=True)]) +``` + +In addition, tests were moved to the modern test environment. + +## New features + +The following new features have been included in the 3.3 release: + +* Use `style` attribute in tables for alignment instead of `align` for better CSS + inter-operation. The old behavior is available by setting `use_align_attribute=True` when + adding the extension. + +## Bug fixes + +The following bug fixes are included in the 3.4 release: + + diff --git a/docs/extensions/tables.md b/docs/extensions/tables.md index 30b7636..aaffc09 100644 --- a/docs/extensions/tables.md +++ b/docs/extensions/tables.md @@ -58,10 +58,30 @@ Usage See [Extensions](index.md) for general extension usage. Use `tables` as the name of the extension. -This extension does not accept any special configuration options. +See the [Library Reference](../reference.md#extensions) for information about +configuring extensions. + +The following options are provided to change the default behavior: + +* **`use_align_attribute`**: Set to `True` to use `align` instead of an appropriate `style` attribute + + Default: `'False'` + A trivial example: ```python markdown.markdown(some_text, extensions=['tables']) ``` + +### Examples + +For an example, let us suppose that alignment should be controlled by the legacy `align` +attribute. + +```pycon +>>> from markdown.extensions.tables import TableExtension +>>> html = markdown.markdown(text, +... extensions=[TableExtension(use_align_attribute=True)] +... ) +``` diff --git a/markdown/extensions/tables.py b/markdown/extensions/tables.py index 0a9d084..c8b1024 100644 --- a/markdown/extensions/tables.py +++ b/markdown/extensions/tables.py @@ -30,9 +30,11 @@ class TableProcessor(BlockProcessor): RE_CODE_PIPES = re.compile(r'(?:(\\\\)|(\\`+)|(`+)|(\\\|)|(\|))') RE_END_BORDER = re.compile(r'(?<!\\)(?:\\\\)*\|$') - def __init__(self, parser): + def __init__(self, parser, config): self.border = False self.separator = '' + self.config = config + super().__init__(parser) def test(self, parent, block): @@ -126,7 +128,10 @@ class TableProcessor(BlockProcessor): except IndexError: # pragma: no cover c.text = "" if a: - c.set('align', a) + if self.config['use_align_attribute']: + c.set('align', a) + else: + c.set('style', f'text-align: {a};') def _split_row(self, row): """ split a row of text into list of cells. """ @@ -212,11 +217,19 @@ class TableProcessor(BlockProcessor): class TableExtension(Extension): """ Add tables to Markdown. """ + def __init__(self, **kwargs): + self.config = { + 'use_align_attribute': [False, 'True to use align attribute instead of style.'], + } + + super().__init__(**kwargs) + def extendMarkdown(self, md): """ Add an instance of TableProcessor to BlockParser. """ if '|' not in md.ESCAPED_CHARS: md.ESCAPED_CHARS.append('|') - md.parser.blockprocessors.register(TableProcessor(md.parser), 'table', 75) + processor = TableProcessor(md.parser, self.getConfigs()) + md.parser.blockprocessors.register(processor, 'table', 75) def makeExtension(**kwargs): # pragma: no cover diff --git a/tests/extensions/extra/tables.html b/tests/extensions/extra/tables.html deleted file mode 100644 index 25dee48..0000000 --- a/tests/extensions/extra/tables.html +++ /dev/null @@ -1,466 +0,0 @@ -<h2>Table Tests</h2> -<table> -<thead> -<tr> -<th>First Header</th> -<th>Second Header</th> -</tr> -</thead> -<tbody> -<tr> -<td>Content Cell</td> -<td>Content Cell</td> -</tr> -<tr> -<td>Content Cell</td> -<td>Content Cell</td> -</tr> -</tbody> -</table> -<table> -<thead> -<tr> -<th>First Header</th> -<th>Second Header</th> -</tr> -</thead> -<tbody> -<tr> -<td>Content Cell</td> -<td>Content Cell</td> -</tr> -<tr> -<td>Content Cell</td> -<td>Content Cell</td> -</tr> -</tbody> -</table> -<table> -<thead> -<tr> -<th align="left">Item</th> -<th align="right">Value</th> -</tr> -</thead> -<tbody> -<tr> -<td align="left">Computer</td> -<td align="right">$1600</td> -</tr> -<tr> -<td align="left">Phone</td> -<td align="right">$12</td> -</tr> -<tr> -<td align="left">Pipe</td> -<td align="right">$1</td> -</tr> -</tbody> -</table> -<table> -<thead> -<tr> -<th>Function name</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td><code>help()</code></td> -<td>Display the help window.</td> -</tr> -<tr> -<td><code>destroy()</code></td> -<td><strong>Destroy your computer!</strong></td> -</tr> -</tbody> -</table> -<table> -<thead> -<tr> -<th align="left">foo</th> -<th align="center">bar</th> -<th align="right">baz</th> -</tr> -</thead> -<tbody> -<tr> -<td align="left"></td> -<td align="center">Q</td> -<td align="right"></td> -</tr> -<tr> -<td align="left">W</td> -<td align="center"></td> -<td align="right">W</td> -</tr> -</tbody> -</table> -<table> -<thead> -<tr> -<th>foo</th> -<th>bar</th> -<th>baz</th> -</tr> -</thead> -<tbody> -<tr> -<td></td> -<td>Q</td> -<td></td> -</tr> -<tr> -<td>W</td> -<td></td> -<td>W</td> -</tr> -</tbody> -</table> -<p>Three spaces in front of a table:</p> -<table> -<thead> -<tr> -<th>First Header</th> -<th>Second Header</th> -</tr> -</thead> -<tbody> -<tr> -<td>Content Cell</td> -<td>Content Cell</td> -</tr> -<tr> -<td>Content Cell</td> -<td>Content Cell</td> -</tr> -</tbody> -</table> -<table> -<thead> -<tr> -<th>First Header</th> -<th>Second Header</th> -</tr> -</thead> -<tbody> -<tr> -<td>Content Cell</td> -<td>Content Cell</td> -</tr> -<tr> -<td>Content Cell</td> -<td>Content Cell</td> -</tr> -</tbody> -</table> -<p>Four spaces is a code block:</p> -<pre><code>First Header | Second Header ------------- | ------------- -Content Cell | Content Cell -Content Cell | Content Cell -</code></pre> -<table> -<thead> -<tr> -<th>First Header</th> -<th>Second Header</th> -</tr> -</thead> -<tbody> -<tr> -<td></td> -<td></td> -</tr> -</tbody> -</table> -<p>More inline code block tests</p> -<table> -<thead> -<tr> -<th>Column 1</th> -<th>Column 2</th> -<th>Column 3</th> -</tr> -</thead> -<tbody> -<tr> -<td>word 1</td> -<td>word 2</td> -<td>word 3</td> -</tr> -<tr> -<td>word 1</td> -<td><code>word 2</code></td> -<td>word 3</td> -</tr> -<tr> -<td>word 1</td> -<td>`word 2</td> -<td>word 3</td> -</tr> -<tr> -<td>word 1</td> -<td>`word 2</td> -<td>word 3</td> -</tr> -<tr> -<td>word 1</td> -<td><code>word |2</code></td> -<td>word 3</td> -</tr> -<tr> -<td>words</td> -<td><code>some | code</code></td> -<td>more words</td> -</tr> -<tr> -<td>words</td> -<td><code>some | code</code></td> -<td>more words</td> -</tr> -<tr> -<td>words</td> -<td><code>some | code</code></td> -<td>more words</td> -</tr> -<tr> -<td>words</td> -<td><code>some ` | ` code</code></td> -<td>more words</td> -</tr> -<tr> -<td>words</td> -<td><code>some ` | ` code</code></td> -<td>more words</td> -</tr> -<tr> -<td>words</td> -<td><code>some ` | ` code</code></td> -<td>more words</td> -</tr> -</tbody> -</table> -<p>A test for issue #440:</p> -<table> -<thead> -<tr> -<th>foo</th> -<th>bar</th> -</tr> -</thead> -<tbody> -<tr> -<td>foo</td> -<td>(<code>bar</code>) and <code>baz</code>.</td> -</tr> -</tbody> -</table> -<p>Lists are not tables</p> -<ul> -<li>this | should | not</li> -<li>be | a | table</li> -</ul> -<p>Add tests for issue #449</p> -<table> -<thead> -<tr> -<th>Odd backticks</th> -<th>Even backticks</th> -</tr> -</thead> -<tbody> -<tr> -<td><code>[!\"\#$%&'()*+,\-./:;<=>?@\[\\\]^_`{|}~]</code></td> -<td><code>[!\"\#$%&'()*+,\-./:;<=>?@\[\\\]^`_`{|}~]</code></td> -</tr> -</tbody> -</table> -<table> -<thead> -<tr> -<th>Escapes</th> -<th>More Escapes</th> -</tr> -</thead> -<tbody> -<tr> -<td><code>`\</code></td> -<td><code>\</code></td> -</tr> -</tbody> -</table> -<p>Only the first backtick can be escaped</p> -<table> -<thead> -<tr> -<th>Escaped</th> -<th>Bacticks</th> -</tr> -</thead> -<tbody> -<tr> -<td>`<code>\</code></td> -<td>``</td> -</tr> -</tbody> -</table> -<p>Test escaped pipes</p> -<table> -<thead> -<tr> -<th>Column 1</th> -<th>Column 2</th> -</tr> -</thead> -<tbody> -<tr> -<td><code>|</code> |</td> -<td>Pipes are okay in code and escaped. |</td> -</tr> -</tbody> -</table> -<table> -<thead> -<tr> -<th>Column 1</th> -<th>Column 2</th> -</tr> -</thead> -<tbody> -<tr> -<td>row1</td> -<td>row1 |</td> -</tr> -<tr> -<td>row2</td> -<td>row2</td> -</tr> -</tbody> -</table> -<p>Test header escapes</p> -<table> -<thead> -<tr> -<th><code>`\</code> |</th> -<th><code>\</code> |</th> -</tr> -</thead> -<tbody> -<tr> -<td>row1</td> -<td>row1</td> -</tr> -<tr> -<td>row2</td> -<td>row2</td> -</tr> -</tbody> -</table> -<p>Escaped pipes in format row should not be a table</p> -<p>| Column1 | Column2 | -| ------- || ------- | -| row1 | row1 | -| row2 | row2 |</p> -<p>Test escaped code in Table</p> -<table> -<thead> -<tr> -<th>Should not be code</th> -<th>Should be code</th> -</tr> -</thead> -<tbody> -<tr> -<td>`Not code`</td> -<td>\<code>code</code></td> -</tr> -<tr> -<td>\`Not code\`</td> -<td>\\<code>code</code></td> -</tr> -</tbody> -</table> -<p>Single column tables</p> -<table> -<thead> -<tr> -<th>Is a Table</th> -</tr> -</thead> -<tbody> -<tr> -<td></td> -</tr> -</tbody> -</table> -<table> -<thead> -<tr> -<th>Is a Table</th> -</tr> -</thead> -<tbody> -<tr> -<td></td> -</tr> -</tbody> -</table> -<table> -<thead> -<tr> -<th>Is a Table</th> -</tr> -</thead> -<tbody> -<tr> -<td></td> -</tr> -</tbody> -</table> -<table> -<thead> -<tr> -<th>Is a Table</th> -</tr> -</thead> -<tbody> -<tr> -<td>row</td> -</tr> -</tbody> -</table> -<table> -<thead> -<tr> -<th>Is a Table</th> -</tr> -</thead> -<tbody> -<tr> -<td>row</td> -</tr> -</tbody> -</table> -<table> -<thead> -<tr> -<th>Is a Table</th> -</tr> -</thead> -<tbody> -<tr> -<td>row</td> -</tr> -</tbody> -</table> -<h2>| Is not a Table</h2> -<p>| row</p> -<h2>Is not a Table |</h2> -<p>row |</p> -<p>| Is not a Table -| -------------- -row</p> -<p>Is not a Table | --------------- | -row</p>
\ No newline at end of file diff --git a/tests/extensions/extra/tables.txt b/tests/extensions/extra/tables.txt deleted file mode 100644 index 2dc4967..0000000 --- a/tests/extensions/extra/tables.txt +++ /dev/null @@ -1,169 +0,0 @@ -Table Tests ------------ - -First Header | Second Header -------------- | ------------- -Content Cell | Content Cell -Content Cell | Content Cell - -| First Header | Second Header | -| ------------- | ------------- | -| Content Cell | Content Cell | -| Content Cell | Content Cell | - -| Item | Value | -| :-------- | -----:| -| Computer | $1600 | -| Phone | $12 | -| Pipe | $1 | - -| Function name | Description | -| ------------- | ------------------------------ | -| `help()` | Display the help window. | -| `destroy()` | **Destroy your computer!** | - -|foo|bar|baz| -|:--|:-:|--:| -| | Q | | -|W | | W| - -foo|bar|baz ----|---|--- - | Q | - W | | W - -Three spaces in front of a table: - - First Header | Second Header - ------------ | ------------- - Content Cell | Content Cell - Content Cell | Content Cell - - | First Header | Second Header | - | ------------ | ------------- | - | Content Cell | Content Cell | - | Content Cell | Content Cell | - -Four spaces is a code block: - - First Header | Second Header - ------------ | ------------- - Content Cell | Content Cell - Content Cell | Content Cell - -| First Header | Second Header | -| ------------ | ------------- | - -More inline code block tests - -Column 1 | Column 2 | Column 3 ----------|----------|--------- -word 1 | word 2 | word 3 -word 1 | `word 2` | word 3 -word 1 | \`word 2 | word 3 -word 1 | `word 2 | word 3 -word 1 | `word |2` | word 3 -words |`` some | code `` | more words -words |``` some | code ``` | more words -words |```` some | code ```` | more words -words |`` some ` | ` code `` | more words -words |``` some ` | ` code ``` | more words -words |```` some ` | ` code ```` | more words - -A test for issue #440: - -foo | bar ---- | --- -foo | (`bar`) and `baz`. - -Lists are not tables - - - this | should | not - - be | a | table - -Add tests for issue #449 - -Odd backticks | Even backticks ------------- | ------------- -``[!\"\#$%&'()*+,\-./:;<=>?@\[\\\]^_`{|}~]`` | ``[!\"\#$%&'()*+,\-./:;<=>?@\[\\\]^`_`{|}~]`` - -Escapes | More Escapes -------- | ------ -`` `\`` | `\` - -Only the first backtick can be escaped - -Escaped | Bacticks -------- | ------ -\`` \` | \`\` - -Test escaped pipes - -Column 1 | Column 2 --------- | -------- -`|` \| | Pipes are okay in code and escaped. \| - -| Column 1 | Column 2 | -| -------- | -------- | -| row1 | row1 \| -| row2 | row2 | - -Test header escapes - -| `` `\`` \| | `\` \| -| ---------- | ---- | -| row1 | row1 | -| row2 | row2 | - -Escaped pipes in format row should not be a table - -| Column1 | Column2 | -| ------- \|| ------- | -| row1 | row1 | -| row2 | row2 | - -Test escaped code in Table - -Should not be code | Should be code ------------------- | -------------- -\`Not code\` | \\`code` -\\\`Not code\\\` | \\\\`code` - -Single column tables - -| Is a Table | -| ---------- | - -| Is a Table -| ---------- - -Is a Table | ----------- | - -| Is a Table | -| ---------- | -| row | - -| Is a Table -| ---------- -| row - -Is a Table | ----------- | -row | - -| Is not a Table --------------- -| row - -Is not a Table | --------------- -row | - -| Is not a Table -| -------------- -row - -Is not a Table | --------------- | -row diff --git a/tests/test_legacy.py b/tests/test_legacy.py index 363161a..62bc075 100644 --- a/tests/test_legacy.py +++ b/tests/test_legacy.py @@ -182,8 +182,6 @@ class TestExtensionsExtra(LegacyTestCase): footnotes = Kwargs(extensions=['footnotes']) - tables = Kwargs(extensions=['tables']) - extra_config = Kwargs( extensions=['extra'], extension_configs={ diff --git a/tests/test_syntax/extensions/test_tables.py b/tests/test_syntax/extensions/test_tables.py index b01ea0c..cd3fbe4 100644 --- a/tests/test_syntax/extensions/test_tables.py +++ b/tests/test_syntax/extensions/test_tables.py @@ -20,6 +20,7 @@ License: BSD (see LICENSE.md for details). """ from markdown.test_tools import TestCase +from markdown.extensions.tables import TableExtension class TestTableBlocks(TestCase): @@ -60,3 +61,862 @@ Content Cell | ), extensions=['tables'] ) + + def test_no_sides(self): + self.assertMarkdownRenders( + self.dedent( + """ + First Header | Second Header + ------------- | ------------- + Content Cell | Content Cell + Content Cell | Content Cell + """ + ), + self.dedent( + """ + <table> + <thead> + <tr> + <th>First Header</th> + <th>Second Header</th> + </tr> + </thead> + <tbody> + <tr> + <td>Content Cell</td> + <td>Content Cell</td> + </tr> + <tr> + <td>Content Cell</td> + <td>Content Cell</td> + </tr> + </tbody> + </table> + """ + ), + extensions=['tables'] + ) + + def test_both_sides(self): + self.assertMarkdownRenders( + self.dedent( + """ + | First Header | Second Header | + | ------------- | ------------- | + | Content Cell | Content Cell | + | Content Cell | Content Cell | + """ + ), + self.dedent( + """ + <table> + <thead> + <tr> + <th>First Header</th> + <th>Second Header</th> + </tr> + </thead> + <tbody> + <tr> + <td>Content Cell</td> + <td>Content Cell</td> + </tr> + <tr> + <td>Content Cell</td> + <td>Content Cell</td> + </tr> + </tbody> + </table> + """ + ), + extensions=['tables'] + ) + + def test_align_columns(self): + self.assertMarkdownRenders( + self.dedent( + """ + | Item | Value | + | :-------- | -----:| + | Computer | $1600 | + | Phone | $12 | + | Pipe | $1 | + """ + ), + self.dedent( + """ + <table> + <thead> + <tr> + <th style="text-align: left;">Item</th> + <th style="text-align: right;">Value</th> + </tr> + </thead> + <tbody> + <tr> + <td style="text-align: left;">Computer</td> + <td style="text-align: right;">$1600</td> + </tr> + <tr> + <td style="text-align: left;">Phone</td> + <td style="text-align: right;">$12</td> + </tr> + <tr> + <td style="text-align: left;">Pipe</td> + <td style="text-align: right;">$1</td> + </tr> + </tbody> + </table> + """ + ), + extensions=['tables'] + ) + + def test_styles_in_tables(self): + self.assertMarkdownRenders( + self.dedent( + """ + | Function name | Description | + | ------------- | ------------------------------ | + | `help()` | Display the help window. | + | `destroy()` | **Destroy your computer!** | + """ + ), + self.dedent( + """ + <table> + <thead> + <tr> + <th>Function name</th> + <th>Description</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>help()</code></td> + <td>Display the help window.</td> + </tr> + <tr> + <td><code>destroy()</code></td> + <td><strong>Destroy your computer!</strong></td> + </tr> + </tbody> + </table> + """ + ), + extensions=['tables'] + ) + + def test_align_three(self): + self.assertMarkdownRenders( + self.dedent( + """ + |foo|bar|baz| + |:--|:-:|--:| + | | Q | | + |W | | W| + """ + ), + self.dedent( + """ + <table> + <thead> + <tr> + <th style="text-align: left;">foo</th> + <th style="text-align: center;">bar</th> + <th style="text-align: right;">baz</th> + </tr> + </thead> + <tbody> + <tr> + <td style="text-align: left;"></td> + <td style="text-align: center;">Q</td> + <td style="text-align: right;"></td> + </tr> + <tr> + <td style="text-align: left;">W</td> + <td style="text-align: center;"></td> + <td style="text-align: right;">W</td> + </tr> + </tbody> + </table> + """ + ), + extensions=['tables'] + ) + + def test_three_columns(self): + self.assertMarkdownRenders( + self.dedent( + """ + foo|bar|baz + ---|---|--- + | Q | + W | | W + """ + ), + self.dedent( + """ + <table> + <thead> + <tr> + <th>foo</th> + <th>bar</th> + <th>baz</th> + </tr> + </thead> + <tbody> + <tr> + <td></td> + <td>Q</td> + <td></td> + </tr> + <tr> + <td>W</td> + <td></td> + <td>W</td> + </tr> + </tbody> + </table> + """ + ), + extensions=['tables'] + ) + + def test_three_spaces_prefix(self): + self.assertMarkdownRenders( + self.dedent( + """ + Three spaces in front of a table: + + First Header | Second Header + ------------ | ------------- + Content Cell | Content Cell + Content Cell | Content Cell + + | First Header | Second Header | + | ------------ | ------------- | + | Content Cell | Content Cell | + | Content Cell | Content Cell | + """), + self.dedent( + """ + <p>Three spaces in front of a table:</p> + <table> + <thead> + <tr> + <th>First Header</th> + <th>Second Header</th> + </tr> + </thead> + <tbody> + <tr> + <td>Content Cell</td> + <td>Content Cell</td> + </tr> + <tr> + <td>Content Cell</td> + <td>Content Cell</td> + </tr> + </tbody> + </table> + <table> + <thead> + <tr> + <th>First Header</th> + <th>Second Header</th> + </tr> + </thead> + <tbody> + <tr> + <td>Content Cell</td> + <td>Content Cell</td> + </tr> + <tr> + <td>Content Cell</td> + <td>Content Cell</td> + </tr> + </tbody> + </table> + """ + ), + extensions=['tables'] + ) + + def test_code_block_table(self): + self.assertMarkdownRenders( + self.dedent( + """ + Four spaces is a code block: + + First Header | Second Header + ------------ | ------------- + Content Cell | Content Cell + Content Cell | Content Cell + + | First Header | Second Header | + | ------------ | ------------- | + """), + self.dedent( + """ + <p>Four spaces is a code block:</p> + <pre><code>First Header | Second Header + ------------ | ------------- + Content Cell | Content Cell + Content Cell | Content Cell + </code></pre> + <table> + <thead> + <tr> + <th>First Header</th> + <th>Second Header</th> + </tr> + </thead> + <tbody> + <tr> + <td></td> + <td></td> + </tr> + </tbody> + </table> + """ + ), + extensions=['tables'] + ) + + def test_inline_code_blocks(self): + self.assertMarkdownRenders( + self.dedent( + """ + More inline code block tests + + Column 1 | Column 2 | Column 3 + ---------|----------|--------- + word 1 | word 2 | word 3 + word 1 | `word 2` | word 3 + word 1 | \\`word 2 | word 3 + word 1 | `word 2 | word 3 + word 1 | `word |2` | word 3 + words |`` some | code `` | more words + words |``` some | code ``` | more words + words |```` some | code ```` | more words + words |`` some ` | ` code `` | more words + words |``` some ` | ` code ``` | more words + words |```` some ` | ` code ```` | more words + """), + self.dedent( + """ + <p>More inline code block tests</p> + <table> + <thead> + <tr> + <th>Column 1</th> + <th>Column 2</th> + <th>Column 3</th> + </tr> + </thead> + <tbody> + <tr> + <td>word 1</td> + <td>word 2</td> + <td>word 3</td> + </tr> + <tr> + <td>word 1</td> + <td><code>word 2</code></td> + <td>word 3</td> + </tr> + <tr> + <td>word 1</td> + <td>`word 2</td> + <td>word 3</td> + </tr> + <tr> + <td>word 1</td> + <td>`word 2</td> + <td>word 3</td> + </tr> + <tr> + <td>word 1</td> + <td><code>word |2</code></td> + <td>word 3</td> + </tr> + <tr> + <td>words</td> + <td><code>some | code</code></td> + <td>more words</td> + </tr> + <tr> + <td>words</td> + <td><code>some | code</code></td> + <td>more words</td> + </tr> + <tr> + <td>words</td> + <td><code>some | code</code></td> + <td>more words</td> + </tr> + <tr> + <td>words</td> + <td><code>some ` | ` code</code></td> + <td>more words</td> + </tr> + <tr> + <td>words</td> + <td><code>some ` | ` code</code></td> + <td>more words</td> + </tr> + <tr> + <td>words</td> + <td><code>some ` | ` code</code></td> + <td>more words</td> + </tr> + </tbody> + </table> + """ + ), + extensions=['tables'] + ) + + def test_issue_440(self): + self.assertMarkdownRenders( + self.dedent( + """ + A test for issue #440: + + foo | bar + --- | --- + foo | (`bar`) and `baz`. + """), + self.dedent( + """ + <p>A test for issue #440:</p> + <table> + <thead> + <tr> + <th>foo</th> + <th>bar</th> + </tr> + </thead> + <tbody> + <tr> + <td>foo</td> + <td>(<code>bar</code>) and <code>baz</code>.</td> + </tr> + </tbody> + </table> + """ + ), + extensions=['tables'] + ) + + def test_lists_not_tables(self): + self.assertMarkdownRenders( + self.dedent( + """ + Lists are not tables + + - this | should | not + - be | a | table + """), + self.dedent( + """ + <p>Lists are not tables</p> + <ul> + <li>this | should | not</li> + <li>be | a | table</li> + </ul> + """ + ), + extensions=['tables'] + ) + + def test_issue_449(self): + self.assertMarkdownRenders( + self.dedent( + r""" + Add tests for issue #449 + + Odd backticks | Even backticks + ------------ | ------------- + ``[!\"\#$%&'()*+,\-./:;<=>?@\[\\\]^_`{|}~]`` | ``[!\"\#$%&'()*+,\-./:;<=>?@\[\\\]^`_`{|}~]`` + + Escapes | More Escapes + ------- | ------ + `` `\`` | `\` + + Only the first backtick can be escaped + + Escaped | Bacticks + ------- | ------ + \`` \` | \`\` + + Test escaped pipes + + Column 1 | Column 2 + -------- | -------- + `|` \| | Pipes are okay in code and escaped. \| + + | Column 1 | Column 2 | + | -------- | -------- | + | row1 | row1 \| + | row2 | row2 | + + Test header escapes + + | `` `\`` \| | `\` \| + | ---------- | ---- | + | row1 | row1 | + | row2 | row2 | + + Escaped pipes in format row should not be a table + + | Column1 | Column2 | + | ------- \|| ------- | + | row1 | row1 | + | row2 | row2 | + + Test escaped code in Table + + Should not be code | Should be code + ------------------ | -------------- + \`Not code\` | \\`code` + \\\`Not code\\\` | \\\\`code` + """), + self.dedent( + """ + <p>Add tests for issue #449</p> + <table> + <thead> + <tr> + <th>Odd backticks</th> + <th>Even backticks</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>[!\\"\\#$%&'()*+,\\-./:;<=>?@\\[\\\\\\]^_`{|}~]</code></td> + <td><code>[!\\"\\#$%&'()*+,\\-./:;<=>?@\\[\\\\\\]^`_`{|}~]</code></td> + </tr> + </tbody> + </table> + <table> + <thead> + <tr> + <th>Escapes</th> + <th>More Escapes</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>`\\</code></td> + <td><code>\\</code></td> + </tr> + </tbody> + </table> + <p>Only the first backtick can be escaped</p> + <table> + <thead> + <tr> + <th>Escaped</th> + <th>Bacticks</th> + </tr> + </thead> + <tbody> + <tr> + <td>`<code>\\</code></td> + <td>``</td> + </tr> + </tbody> + </table> + <p>Test escaped pipes</p> + <table> + <thead> + <tr> + <th>Column 1</th> + <th>Column 2</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>|</code> |</td> + <td>Pipes are okay in code and escaped. |</td> + </tr> + </tbody> + </table> + <table> + <thead> + <tr> + <th>Column 1</th> + <th>Column 2</th> + </tr> + </thead> + <tbody> + <tr> + <td>row1</td> + <td>row1 |</td> + </tr> + <tr> + <td>row2</td> + <td>row2</td> + </tr> + </tbody> + </table> + <p>Test header escapes</p> + <table> + <thead> + <tr> + <th><code>`\\</code> |</th> + <th><code>\\</code> |</th> + </tr> + </thead> + <tbody> + <tr> + <td>row1</td> + <td>row1</td> + </tr> + <tr> + <td>row2</td> + <td>row2</td> + </tr> + </tbody> + </table> + <p>Escaped pipes in format row should not be a table</p> + <p>| Column1 | Column2 | + | ------- || ------- | + | row1 | row1 | + | row2 | row2 |</p> + <p>Test escaped code in Table</p> + <table> + <thead> + <tr> + <th>Should not be code</th> + <th>Should be code</th> + </tr> + </thead> + <tbody> + <tr> + <td>`Not code`</td> + <td>\\<code>code</code></td> + </tr> + <tr> + <td>\\`Not code\\`</td> + <td>\\\\<code>code</code></td> + </tr> + </tbody> + </table> + """ + ), + extensions=['tables'] + ) + + def test_single_column_tables(self): + self.assertMarkdownRenders( + self.dedent( + """ + Single column tables + + | Is a Table | + | ---------- | + + | Is a Table + | ---------- + + Is a Table | + ---------- | + + | Is a Table | + | ---------- | + | row | + + | Is a Table + | ---------- + | row + + Is a Table | + ---------- | + row | + + | Is not a Table + -------------- + | row + + Is not a Table | + -------------- + row | + + | Is not a Table + | -------------- + row + + Is not a Table | + -------------- | + row + """), + self.dedent( + """ + <p>Single column tables</p> + <table> + <thead> + <tr> + <th>Is a Table</th> + </tr> + </thead> + <tbody> + <tr> + <td></td> + </tr> + </tbody> + </table> + <table> + <thead> + <tr> + <th>Is a Table</th> + </tr> + </thead> + <tbody> + <tr> + <td></td> + </tr> + </tbody> + </table> + <table> + <thead> + <tr> + <th>Is a Table</th> + </tr> + </thead> + <tbody> + <tr> + <td></td> + </tr> + </tbody> + </table> + <table> + <thead> + <tr> + <th>Is a Table</th> + </tr> + </thead> + <tbody> + <tr> + <td>row</td> + </tr> + </tbody> + </table> + <table> + <thead> + <tr> + <th>Is a Table</th> + </tr> + </thead> + <tbody> + <tr> + <td>row</td> + </tr> + </tbody> + </table> + <table> + <thead> + <tr> + <th>Is a Table</th> + </tr> + </thead> + <tbody> + <tr> + <td>row</td> + </tr> + </tbody> + </table> + <h2>| Is not a Table</h2> + <p>| row</p> + <h2>Is not a Table |</h2> + <p>row |</p> + <p>| Is not a Table + | -------------- + row</p> + <p>Is not a Table | + -------------- | + row</p> + """ + ), + extensions=['tables'] + ) + + def test_align_columns_legacy(self): + self.assertMarkdownRenders( + self.dedent( + """ + | Item | Value | + | :-------- | -----:| + | Computer | $1600 | + | Phone | $12 | + | Pipe | $1 | + """ + ), + self.dedent( + """ + <table> + <thead> + <tr> + <th align="left">Item</th> + <th align="right">Value</th> + </tr> + </thead> + <tbody> + <tr> + <td align="left">Computer</td> + <td align="right">$1600</td> + </tr> + <tr> + <td align="left">Phone</td> + <td align="right">$12</td> + </tr> + <tr> + <td align="left">Pipe</td> + <td align="right">$1</td> + </tr> + </tbody> + </table> + """ + ), + extensions=[TableExtension(use_align_attribute=True)] + ) + + def test_align_three_legacy(self): + self.assertMarkdownRenders( + self.dedent( + """ + |foo|bar|baz| + |:--|:-:|--:| + | | Q | | + |W | | W| + """ + ), + self.dedent( + """ + <table> + <thead> + <tr> + <th align="left">foo</th> + <th align="center">bar</th> + <th align="right">baz</th> + </tr> + </thead> + <tbody> + <tr> + <td align="left"></td> + <td align="center">Q</td> + <td align="right"></td> + </tr> + <tr> + <td align="left">W</td> + <td align="center"></td> + <td align="right">W</td> + </tr> + </tbody> + </table> + """ + ), + extensions=[TableExtension(use_align_attribute=True)] + ) |