Python-Markdown 3.3 Release Notes

Python-Markdown version 3.3 supports Python versions 3.6, 3.7, 3.8, 3.9 and PyPy3.

Backwards-incompatible changes

The prefix language- is now prepended to all language classes by default on code blocks.

The HTML5 spec recommends that the class defining the language of a code block be prefixed with language-. Therefore, by default, both the fenced_code and codehilite extensions now prepend the prefix when code highlighting is disabled.

If you have previously been including the prefix manually in your fenced code blocks, then you will not want a second instance of the prefix. Similarly, if you are using a third party syntax highlighting tool which does not recognize the prefix, or requires a different prefix, then you will want to redefine the prefix globally using the lang_prefix configuration option of either the fenced_code or codehilite extensions.

For example, to configure fenced_code to not apply any prefix (the previous behavior), set the option to an empty string:

from markdown.extensions.fenced_code import FencedCodeExtension

markdown.markdown(src, extensions=[FencedCodeExtension(lang_prefix='')])


When code highlighting is enabled, the output from Pygments is used unaltered. Currently, Pygments does not provide an option to include the language class in the output, let alone prefix it. Therefore, any language prefix is only applied when syntax highlighting is disabled.

Attribute Lists are more strict (#898).

Empty curly braces are now completely ignored by the Attribute List extension. Previously, the extension would recognize them as attribute lists and remove them from the document. Therefore, it is no longer necessary to backslash escape a set of curly braces which are empty or only contain whitespace.

Despite not being documented, previously an attribute list could be defined anywhere within a table cell and get applied to the cell (<td> element). Now the attribute list must be defined at the end of the cell content and must be separated from the rest of the content by at least one space. This makes it easy to differentiate between attribute lists defined on inline elements within a cell and the attribute list for the cell itself. It is also more consistent with how attribute lists are defined on other types of elements.

The extension has also added support for defining attribute lists on table header cells (<th> elements) in the same manner as data cells (<td> elements).

In addition, the documentation for the extensions received an overhaul. The features (#987) and limitations (#965) of the extension are now fully documented.

New features

The following new features have been included in the 3.3 release:

  • All Pygments’ options are now available for syntax highlighting (#816).

    • The Codehilite extension now accepts any options which Pygments supports as global configuration settings on the extension.
    • Fenced Code Blocks will accept any of the same options on individual code blocks.
    • Any of the previously supported aliases to Pygments’ options continue to be supported at this time. However, it is recommended that the Pygments option names be used directly to ensure continued compatibility in the future.
  • Fenced Code Blocks now work with Attribute Lists when syntax highlighting is disabled. Any random HTML attribute can be defined and set on the <code> tag of fenced code blocks when the attr_list extension is enabled (#816).

  • The HTML parser has been completely replaced. The new HTML parser is built on Python’s html.parser.HTMLParser, which alleviates various bugs and simplify maintenance of the code (#803, #830).

  • The Markdown in HTML extension has been rebuilt on the new HTML Parser, which drastically simplifies it. Note that raw HTML elements with a markdown attribute defined are now converted to ElementTree Elements and are rendered by the serializer. Various bugs have been fixed (#803, #595, #780, and #1012).

  • Link reference parsing, abbreviation reference parsing and footnote reference parsing has all been moved from preprocessors to blockprocessors, which allows them to be nested within other block level elements. Specifically, this change was necessary to maintain the current behavior in the rebuilt Markdown in HTML extension. A few random edge-case bugs (see the included tests) were resolved in the process (#803).

  • An alternate function markdown.extensions.headerid.slugify_unicode has been included with the Table of Contents extension which supports Unicode characters in table of contents slugs. The old markdown.extensions.headerid.slugify method which removes non-ASCII characters remains the default. Import and pass markdown.extensions.headerid.slugify_unicode to the slugify configuration option to use the new behavior.

  • Support was added for Python 3.9 and dropped for Python 3.5.

Bug fixes

The following bug fixes are included in the 3.3 release:

  • Document how to pass configuration options to Extra (#1019).
  • Fix HR which follows strong em (#897).
  • Support short reference image links (#894).
  • Avoid a RecursionError from deeply nested blockquotes (#799).
  • Fix issues with complex emphasis (#979).
  • Fix unescaping of HTML characters <> in CodeHilite (#990).
  • Fix complex scenarios involving lists and admonitions (#1004).
  • Fix complex scenarios with nested ordered and unordered lists in a definition list (#918).