summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGaige B Paulsen <github@gbp.gaige.net>2022-05-05 15:32:07 -0400
committerGitHub <noreply@github.com>2022-05-05 15:32:07 -0400
commit659a43659c6012df8d8ceb4a3681d2ddb1cb7540 (patch)
tree2f523c0b1de1a402141407ef80e22844c71a45c5
parentdb98a2632447387cd5c965b324904ee780809b81 (diff)
downloadpython-markdown-659a43659c6012df8d8ceb4a3681d2ddb1cb7540.tar.gz
Update th/td to use style attribute
This allows better interoperation with CSS style sheets, as the align object on the TH is skipped if the css uses 'text-align: inherit' and the previous 'text-align' is used instead (or the default: left). Added an override to restore the original `align` behavior Moved existing tests to the new test infrastructure Added new tests to test the configuration parameter Updated documentation to document the configuration parameter.
-rw-r--r--docs/change_log/index.md2
-rw-r--r--docs/change_log/release-3.4.md44
-rw-r--r--docs/extensions/tables.md22
-rw-r--r--markdown/extensions/tables.py19
-rw-r--r--tests/extensions/extra/tables.html466
-rw-r--r--tests/extensions/extra/tables.txt169
-rw-r--r--tests/test_legacy.py2
-rw-r--r--tests/test_syntax/extensions/test_tables.py860
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>[!\"\#$%&amp;'()*+,\-./:;&lt;=&gt;?@\[\\\]^_`{|}~]</code></td>
-<td><code>[!\"\#$%&amp;'()*+,\-./:;&lt;=&gt;?@\[\\\]^`_`{|}~]</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>[!\\"\\#$%&amp;'()*+,\\-./:;&lt;=&gt;?@\\[\\\\\\]^_`{|}~]</code></td>
+ <td><code>[!\\"\\#$%&amp;'()*+,\\-./:;&lt;=&gt;?@\\[\\\\\\]^`_`{|}~]</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)]
+ )