Skip to content

Commit

Permalink
Simplify xml.etree.ElementTree loading (Python-Markdown#902)
Browse files Browse the repository at this point in the history
cElementTree is a deprecated alias for ElementTree since Python 3.3.

Also drop the recommendation to import etree from markdown.util,
and deprecate markdown.util.etree.
  • Loading branch information
mitya57 authored Feb 3, 2020
1 parent ccf56ed commit a2e4788
Show file tree
Hide file tree
Showing 17 changed files with 131 additions and 143 deletions.
14 changes: 14 additions & 0 deletions docs/change_log/release-3.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ Internally, this change relies on the Pygments 2.4, so you must be using at leas
that version to see this effect. Users with earlier Pygments versions will
continue to see the old behavior.

### `markdown.util.etree` deprecated

Previously, Python-Markdown was using either the `xml.etree.cElementTree` module
or the `xml.etree.ElementTree` module, based on their availability. In modern
Python versions, the former is a deprecated alias for the latter. Thus, the
compatibility layer is deprecated and extensions are advised to use
`xml.etree.ElementTree` directly. Importing `markdown.util.etree` will raise
a `DeprecationWarning` beginning in version 3.2 and may be removed in a future
release.

Therefore, extension developers are encouraged to replace
`from markdown.util import etree` with
`import xml.etree.ElementTree as etree` in their code.

## New features

The following new features have been included in the release:
Expand Down
22 changes: 6 additions & 16 deletions docs/extensions/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ For an example, consider this simplified emphasis pattern:

```python
from markdown.inlinepatterns import Pattern
from markdown.util import etree
import xml.etree.ElementTree as etree

class EmphasisPattern(Pattern):
def handleMatch(self, m):
Expand Down Expand Up @@ -141,7 +141,7 @@ you'll need.

```python
from markdown.inlinepatterns import InlineProcessor
from markdown.util import etree
import xml.etree.ElementTree as etree

# an oversimplified regex
MYPATTERN = r'\*([^*]+)\*'
Expand Down Expand Up @@ -184,7 +184,7 @@ in order to communicate to the parser that no match was found.
if not handled:
return None, None, None

el = util.etree.Element("a")
el = etree.Element("a")
el.text = text

el.set("href", href)
Expand Down Expand Up @@ -429,21 +429,11 @@ As mentioned, the Markdown parser converts a source document to an
Markdown has provided some helpers to ease that manipulation within the context
of the Markdown module.

First, to get access to the ElementTree module import ElementTree from
`markdown` rather than importing it directly. This will ensure you are using
the same version of ElementTree as markdown. The module is found at
`markdown.util.etree` within Markdown.
First, import the ElementTree module:

```python
from markdown.util import etree
import xml.etree.ElementTree as etree
```

`markdown.util.etree` tries to import ElementTree from any known location,
first as a standard library module (from `xml.etree` in Python 2.5), then as
a third party package (ElementTree). In each instance, `cElementTree` is
tried first, then ElementTree if the faster C implementation is not
available on your system.

Sometimes you may want text inserted into an element to be parsed by
[Inline Patterns][]. In such a situation, simply insert the text as you normally
would and the text will be automatically run through the Inline Patterns.
Expand Down Expand Up @@ -482,7 +472,7 @@ def set_link_class(self, element):

For more information about working with ElementTree see the ElementTree
[Documentation](https://effbot.org/zone/element-index.htm)
([Python Docs](http://docs.python.org/lib/module-xml.etree.ElementTree.html)).
([Python Docs](https://docs.python.org/3/library/xml.etree.elementtree.html)).

## Integrating Your Code Into Markdown {: #integrating_into_markdown }

Expand Down
5 changes: 3 additions & 2 deletions markdown/blockparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
License: BSD (see LICENSE.md for details).
"""

import xml.etree.ElementTree as etree
from . import util


Expand Down Expand Up @@ -85,9 +86,9 @@ def parseDocument(self, lines):
"""
# Create a ElementTree from the lines
self.root = util.etree.Element(self.md.doc_tag)
self.root = etree.Element(self.md.doc_tag)
self.parseChunk(self.root, '\n'.join(lines))
return util.etree.ElementTree(self.root)
return etree.ElementTree(self.root)

def parseChunk(self, parent, text):
""" Parse a chunk of markdown text and attach to given etree node.
Expand Down
29 changes: 15 additions & 14 deletions markdown/blockprocessors.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

import logging
import re
import xml.etree.ElementTree as etree
from . import util
from .blockparser import BlockParser

Expand Down Expand Up @@ -194,7 +195,7 @@ def run(self, parent, blocks):
# If the parent li has text, that text needs to be moved to a p
# The p must be 'inserted' at beginning of list in the event
# that other children already exist i.e.; a nested sublist.
p = util.etree.Element('p')
p = etree.Element('p')
p.text = sibling[-1].text
sibling[-1].text = ''
sibling[-1].insert(0, p)
Expand All @@ -205,7 +206,7 @@ def run(self, parent, blocks):

def create_item(self, parent, block):
""" Create a new li and parse the block with it as the parent. """
li = util.etree.SubElement(parent, 'li')
li = etree.SubElement(parent, 'li')
self.parser.parseBlocks(li, [block])

def get_level(self, parent, block):
Expand Down Expand Up @@ -259,8 +260,8 @@ def run(self, parent, blocks):
)
else:
# This is a new codeblock. Create the elements and insert text.
pre = util.etree.SubElement(parent, 'pre')
code = util.etree.SubElement(pre, 'code')
pre = etree.SubElement(parent, 'pre')
code = etree.SubElement(pre, 'code')
block, theRest = self.detab(block)
code.text = util.AtomicString('%s\n' % util.code_escape(block.rstrip()))
if theRest:
Expand Down Expand Up @@ -294,7 +295,7 @@ def run(self, parent, blocks):
quote = sibling
else:
# This is a new blockquote. Create a new parent element.
quote = util.etree.SubElement(parent, 'blockquote')
quote = etree.SubElement(parent, 'blockquote')
# Recursively parse block with blockquote as parent.
# change parser state so blockquotes embedded in lists use p tags
self.parser.state.set('blockquote')
Expand Down Expand Up @@ -354,20 +355,20 @@ def run(self, parent, blocks):
# since it's possible there are other children for this
# sibling, we can't just SubElement the p, we need to
# insert it as the first item.
p = util.etree.Element('p')
p = etree.Element('p')
p.text = lst[-1].text
lst[-1].text = ''
lst[-1].insert(0, p)
# if the last item has a tail, then the tail needs to be put in a p
# likely only when a header is not followed by a blank line
lch = self.lastChild(lst[-1])
if lch is not None and lch.tail:
p = util.etree.SubElement(lst[-1], 'p')
p = etree.SubElement(lst[-1], 'p')
p.text = lch.tail.lstrip()
lch.tail = ''

# parse first block differently as it gets wrapped in a p.
li = util.etree.SubElement(lst, 'li')
li = etree.SubElement(lst, 'li')
self.parser.state.set('looselist')
firstitem = items.pop(0)
self.parser.parseBlocks(li, [firstitem])
Expand All @@ -381,7 +382,7 @@ def run(self, parent, blocks):
lst = parent
else:
# This is a new list so create parent with appropriate tag.
lst = util.etree.SubElement(parent, self.TAG)
lst = etree.SubElement(parent, self.TAG)
# Check if a custom start integer is set
if not self.LAZY_OL and self.STARTSWITH != '1':
lst.attrib['start'] = self.STARTSWITH
Expand All @@ -395,7 +396,7 @@ def run(self, parent, blocks):
self.parser.parseBlocks(lst[-1], [item])
else:
# New item. Create li and parse with it as parent
li = util.etree.SubElement(lst, 'li')
li = etree.SubElement(lst, 'li')
self.parser.parseBlocks(li, [item])
self.parser.state.reset()

Expand Down Expand Up @@ -458,7 +459,7 @@ def run(self, parent, blocks):
# recursively parse this lines as a block.
self.parser.parseBlocks(parent, [before])
# Create header using named groups from RE
h = util.etree.SubElement(parent, 'h%d' % len(m.group('level')))
h = etree.SubElement(parent, 'h%d' % len(m.group('level')))
h.text = m.group('header').strip()
if after:
# Insert remaining lines as first block for future parsing.
Expand All @@ -484,7 +485,7 @@ def run(self, parent, blocks):
level = 1
else:
level = 2
h = util.etree.SubElement(parent, 'h%d' % level)
h = etree.SubElement(parent, 'h%d' % level)
h.text = lines[0].strip()
if len(lines) > 2:
# Block contains additional lines. Add to master blocks for later.
Expand Down Expand Up @@ -518,7 +519,7 @@ def run(self, parent, blocks):
# Recursively parse lines before hr so they get parsed first.
self.parser.parseBlocks(parent, [prelines])
# create hr
util.etree.SubElement(parent, 'hr')
etree.SubElement(parent, 'hr')
# check for lines in block after hr.
postlines = block[match.end():].lstrip('\n')
if postlines:
Expand Down Expand Up @@ -587,5 +588,5 @@ def run(self, parent, blocks):
parent.text = block.lstrip()
else:
# Create a regular paragraph
p = util.etree.SubElement(parent, 'p')
p = etree.SubElement(parent, 'p')
p.text = block.lstrip()
3 changes: 2 additions & 1 deletion markdown/extensions/abbr.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
from . import Extension
from ..preprocessors import Preprocessor
from ..inlinepatterns import InlineProcessor
from ..util import etree, AtomicString
from ..util import AtomicString
import re
import xml.etree.ElementTree as etree

# Global Vars
ABBR_REF_RE = re.compile(r'[*]\[(?P<abbr>[^\]]*)\][ ]?:\s*(?P<title>.*)')
Expand Down
2 changes: 1 addition & 1 deletion markdown/extensions/admonition.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from . import Extension
from ..blockprocessors import BlockProcessor
from ..util import etree
import xml.etree.ElementTree as etree
import re


Expand Down
2 changes: 1 addition & 1 deletion markdown/extensions/def_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

from . import Extension
from ..blockprocessors import BlockProcessor, ListIndentProcessor
from ..util import etree
import xml.etree.ElementTree as etree
import re


Expand Down
19 changes: 10 additions & 9 deletions markdown/extensions/footnotes.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from collections import OrderedDict
import re
import copy
import xml.etree.ElementTree as etree

FN_BACKLINK_TEXT = util.STX + "zz1337820767766393qq" + util.ETX
NBSP_PLACEHOLDER = util.STX + "qq3936677670287331zz" + util.ETX
Expand Down Expand Up @@ -165,14 +166,14 @@ def makeFootnotesDiv(self, root):
if not list(self.footnotes.keys()):
return None

div = util.etree.Element("div")
div = etree.Element("div")
div.set('class', 'footnote')
util.etree.SubElement(div, "hr")
ol = util.etree.SubElement(div, "ol")
surrogate_parent = util.etree.Element("div")
etree.SubElement(div, "hr")
ol = etree.SubElement(div, "ol")
surrogate_parent = etree.Element("div")

for index, id in enumerate(self.footnotes.keys(), start=1):
li = util.etree.SubElement(ol, "li")
li = etree.SubElement(ol, "li")
li.set("id", self.makeFootnoteId(id))
# Parse footnote with surrogate parent as li cannot be used.
# List block handlers have special logic to deal with li.
Expand All @@ -181,7 +182,7 @@ def makeFootnotesDiv(self, root):
for el in list(surrogate_parent):
li.append(el)
surrogate_parent.remove(el)
backlink = util.etree.Element("a")
backlink = etree.Element("a")
backlink.set("href", "#" + self.makeFootnoteRefId(id))
backlink.set("class", "footnote-backref")
backlink.set(
Expand All @@ -196,7 +197,7 @@ def makeFootnotesDiv(self, root):
node.text = node.text + NBSP_PLACEHOLDER
node.append(backlink)
else:
p = util.etree.SubElement(li, "p")
p = etree.SubElement(li, "p")
p.append(backlink)
return div

Expand Down Expand Up @@ -313,8 +314,8 @@ def __init__(self, pattern, footnotes):
def handleMatch(self, m, data):
id = m.group(1)
if id in self.footnotes.footnotes.keys():
sup = util.etree.Element("sup")
a = util.etree.SubElement(sup, "a")
sup = etree.Element("sup")
a = etree.SubElement(sup, "a")
sup.set('id', self.footnotes.makeFootnoteRefId(id, found=True))
a.set('href', '#' + self.footnotes.makeFootnoteId(id))
a.set('class', 'footnote-ref')
Expand Down
3 changes: 2 additions & 1 deletion markdown/extensions/md_in_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from ..blockprocessors import BlockProcessor
from .. import util
import re
import xml.etree.ElementTree as etree


class MarkdownInHtmlProcessor(BlockProcessor):
Expand Down Expand Up @@ -52,7 +53,7 @@ def run(self, parent, blocks, tail=None, nest=False):

# Create Element
markdown_value = tag['attrs'].pop('markdown')
element = util.etree.SubElement(parent, tag['tag'], tag['attrs'])
element = etree.SubElement(parent, tag['tag'], tag['attrs'])

# Slice Off Block
if nest:
Expand Down
2 changes: 1 addition & 1 deletion markdown/extensions/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

from . import Extension
from ..blockprocessors import BlockProcessor
from ..util import etree
import xml.etree.ElementTree as etree
import re
PIPE_NONE = 0
PIPE_LEFT = 1
Expand Down
3 changes: 2 additions & 1 deletion markdown/extensions/toc.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@

from . import Extension
from ..treeprocessors import Treeprocessor
from ..util import etree, parseBoolValue, AMP_SUBSTITUTE, HTML_PLACEHOLDER_RE
from ..util import parseBoolValue, AMP_SUBSTITUTE, HTML_PLACEHOLDER_RE
from ..postprocessors import UnescapePostprocessor
import re
import unicodedata
import xml.etree.ElementTree as etree


def slugify(value, separator):
Expand Down
2 changes: 1 addition & 1 deletion markdown/extensions/wikilinks.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

from . import Extension
from ..inlinepatterns import InlineProcessor
from ..util import etree
import xml.etree.ElementTree as etree
import re


Expand Down
Loading

0 comments on commit a2e4788

Please sign in to comment.