From 659a43659c6012df8d8ceb4a3681d2ddb1cb7540 Mon Sep 17 00:00:00 2001 From: Gaige B Paulsen Date: Thu, 5 May 2022 15:32:07 -0400 Subject: 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. --- docs/change_log/index.md | 2 + docs/change_log/release-3.4.md | 44 ++ docs/extensions/tables.md | 22 +- markdown/extensions/tables.py | 19 +- tests/extensions/extra/tables.html | 466 --------------- tests/extensions/extra/tables.txt | 169 ------ tests/test_legacy.py | 2 - tests/test_syntax/extensions/test_tables.py | 860 ++++++++++++++++++++++++++++ 8 files changed, 943 insertions(+), 641 deletions(-) create mode 100644 docs/change_log/release-3.4.md delete mode 100644 tests/extensions/extra/tables.html delete mode 100644 tests/extensions/extra/tables.txt 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'(?Table Tests - - - - - - - - - - - - - - - - - -
First HeaderSecond Header
Content CellContent Cell
Content CellContent Cell
- - - - - - - - - - - - - - - - - -
First HeaderSecond Header
Content CellContent Cell
Content CellContent Cell
- - - - - - - - - - - - - - - - - - - - - -
ItemValue
Computer$1600
Phone$12
Pipe$1
- - - - - - - - - - - - - - - - - -
Function nameDescription
help()Display the help window.
destroy()Destroy your computer!
- - - - - - - - - - - - - - - - - - - - -
foobarbaz
Q
WW
- - - - - - - - - - - - - - - - - - - - -
foobarbaz
Q
WW
-

Three spaces in front of a table:

- - - - - - - - - - - - - - - - - -
First HeaderSecond Header
Content CellContent Cell
Content CellContent Cell
- - - - - - - - - - - - - - - - - -
First HeaderSecond Header
Content CellContent Cell
Content CellContent Cell
-

Four spaces is a code block:

-
First Header | Second Header
------------- | -------------
-Content Cell | Content Cell
-Content Cell | Content Cell
-
- - - - - - - - - - - - - -
First HeaderSecond Header
-

More inline code block tests

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Column 1Column 2Column 3
word 1word 2word 3
word 1word 2word 3
word 1`word 2word 3
word 1`word 2word 3
word 1word |2word 3
wordssome | codemore words
wordssome | codemore words
wordssome | codemore words
wordssome ` | ` codemore words
wordssome ` | ` codemore words
wordssome ` | ` codemore words
-

A test for issue #440:

- - - - - - - - - - - - - -
foobar
foo(bar) and baz.
-

Lists are not tables

- -

Add tests for issue #449

- - - - - - - - - - - - - -
Odd backticksEven backticks
[!\"\#$%&'()*+,\-./:;<=>?@\[\\\]^_`{|}~][!\"\#$%&'()*+,\-./:;<=>?@\[\\\]^`_`{|}~]
- - - - - - - - - - - - - -
EscapesMore Escapes
`\\
-

Only the first backtick can be escaped

- - - - - - - - - - - - - -
EscapedBacticks
`\``
-

Test escaped pipes

- - - - - - - - - - - - - -
Column 1Column 2
| |Pipes are okay in code and escaped. |
- - - - - - - - - - - - - - - - - -
Column 1Column 2
row1row1 |
row2row2
-

Test header escapes

- - - - - - - - - - - - - - - - - -
`\ |\ |
row1row1
row2row2
-

Escaped pipes in format row should not be a table

-

| Column1 | Column2 | -| ------- || ------- | -| row1 | row1 | -| row2 | row2 |

-

Test escaped code in Table

- - - - - - - - - - - - - - - - - -
Should not be codeShould 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

\ 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( + """ + + + + + + + + + + + + + + + + + +
First HeaderSecond Header
Content CellContent Cell
Content CellContent Cell
+ """ + ), + 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( + """ + + + + + + + + + + + + + + + + + +
First HeaderSecond Header
Content CellContent Cell
Content CellContent Cell
+ """ + ), + extensions=['tables'] + ) + + def test_align_columns(self): + self.assertMarkdownRenders( + self.dedent( + """ + | Item | Value | + | :-------- | -----:| + | Computer | $1600 | + | Phone | $12 | + | Pipe | $1 | + """ + ), + self.dedent( + """ + + + + + + + + + + + + + + + + + + + + + +
ItemValue
Computer$1600
Phone$12
Pipe$1
+ """ + ), + 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( + """ + + + + + + + + + + + + + + + + + +
Function nameDescription
help()Display the help window.
destroy()Destroy your computer!
+ """ + ), + extensions=['tables'] + ) + + def test_align_three(self): + self.assertMarkdownRenders( + self.dedent( + """ + |foo|bar|baz| + |:--|:-:|--:| + | | Q | | + |W | | W| + """ + ), + self.dedent( + """ + + + + + + + + + + + + + + + + + + + + +
foobarbaz
Q
WW
+ """ + ), + extensions=['tables'] + ) + + def test_three_columns(self): + self.assertMarkdownRenders( + self.dedent( + """ + foo|bar|baz + ---|---|--- + | Q | + W | | W + """ + ), + self.dedent( + """ + + + + + + + + + + + + + + + + + + + + +
foobarbaz
Q
WW
+ """ + ), + 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( + """ +

Three spaces in front of a table:

+ + + + + + + + + + + + + + + + + +
First HeaderSecond Header
Content CellContent Cell
Content CellContent Cell
+ + + + + + + + + + + + + + + + + +
First HeaderSecond Header
Content CellContent Cell
Content CellContent Cell
+ """ + ), + 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( + """ +

Four spaces is a code block:

+
First Header | Second Header
+                ------------ | -------------
+                Content Cell | Content Cell
+                Content Cell | Content Cell
+                
+ + + + + + + + + + + + + +
First HeaderSecond Header
+ """ + ), + 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( + """ +

More inline code block tests

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Column 1Column 2Column 3
word 1word 2word 3
word 1word 2word 3
word 1`word 2word 3
word 1`word 2word 3
word 1word |2word 3
wordssome | codemore words
wordssome | codemore words
wordssome | codemore words
wordssome ` | ` codemore words
wordssome ` | ` codemore words
wordssome ` | ` codemore words
+ """ + ), + extensions=['tables'] + ) + + def test_issue_440(self): + self.assertMarkdownRenders( + self.dedent( + """ + A test for issue #440: + + foo | bar + --- | --- + foo | (`bar`) and `baz`. + """), + self.dedent( + """ +

A test for issue #440:

+ + + + + + + + + + + + + +
foobar
foo(bar) and baz.
+ """ + ), + extensions=['tables'] + ) + + def test_lists_not_tables(self): + self.assertMarkdownRenders( + self.dedent( + """ + Lists are not tables + + - this | should | not + - be | a | table + """), + self.dedent( + """ +

Lists are not tables

+ + """ + ), + 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( + """ +

Add tests for issue #449

+ + + + + + + + + + + + + +
Odd backticksEven backticks
[!\\"\\#$%&'()*+,\\-./:;<=>?@\\[\\\\\\]^_`{|}~][!\\"\\#$%&'()*+,\\-./:;<=>?@\\[\\\\\\]^`_`{|}~]
+ + + + + + + + + + + + + +
EscapesMore Escapes
`\\\\
+

Only the first backtick can be escaped

+ + + + + + + + + + + + + +
EscapedBacticks
`\\``
+

Test escaped pipes

+ + + + + + + + + + + + + +
Column 1Column 2
| |Pipes are okay in code and escaped. |
+ + + + + + + + + + + + + + + + + +
Column 1Column 2
row1row1 |
row2row2
+

Test header escapes

+ + + + + + + + + + + + + + + + + +
`\\ |\\ |
row1row1
row2row2
+

Escaped pipes in format row should not be a table

+

| Column1 | Column2 | + | ------- || ------- | + | row1 | row1 | + | row2 | row2 |

+

Test escaped code in Table

+ + + + + + + + + + + + + + + + + +
Should not be codeShould be code
`Not code`\\code
\\`Not code\\`\\\\code
+ """ + ), + 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( + """ +

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

+ """ + ), + extensions=['tables'] + ) + + def test_align_columns_legacy(self): + self.assertMarkdownRenders( + self.dedent( + """ + | Item | Value | + | :-------- | -----:| + | Computer | $1600 | + | Phone | $12 | + | Pipe | $1 | + """ + ), + self.dedent( + """ + + + + + + + + + + + + + + + + + + + + + +
ItemValue
Computer$1600
Phone$12
Pipe$1
+ """ + ), + extensions=[TableExtension(use_align_attribute=True)] + ) + + def test_align_three_legacy(self): + self.assertMarkdownRenders( + self.dedent( + """ + |foo|bar|baz| + |:--|:-:|--:| + | | Q | | + |W | | W| + """ + ), + self.dedent( + """ + + + + + + + + + + + + + + + + + + + + +
foobarbaz
Q
WW
+ """ + ), + extensions=[TableExtension(use_align_attribute=True)] + ) -- cgit v1.2.1