Skip to content

Commit

Permalink
Python 3.9 compatibility
Browse files Browse the repository at this point in the history
Python 3.9 no longer ships the xml.etree.cElementTree module. defusedxml
no longer provides the a fixed module with 3.9 as well.
defusedxml.cElementTree is still available with 3.8.

See: https://bugs.python.org/issue36543
See: python/cpython#19108
Fixes: #50
Signed-off-by: Christian Heimes <christian@python.org>
  • Loading branch information
tiran committed Apr 15, 2020
1 parent f8e3fe8 commit 4339aee
Show file tree
Hide file tree
Showing 12 changed files with 72 additions and 23 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ matrix:
env: TOXENV=py36
- python: 3.7
env: TOXENV=py37
- python: 3.8-dev
- python: 3.8
env: TOXENV=py38
- python: 3.9-dev
env: TOXENV=py39
- python: 3.7
env: TOXENV=black
- python: 2.7
Expand Down
10 changes: 10 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
Changelog
=========

defusedxml 0.7.0
----------------

*Release date: ??-Mar-2020*

- Add support for Python 3.9
- ``defusedxml.cElementTree`` is not available with Python 3.9.
- Python 2 is deprecate. Support for Python 2 will be removed in 0.8.0.


defusedxml 0.6.0
----------------

Expand Down
38 changes: 25 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ properly implement XML specifications. Application developers must not
rely that a library is always configured for security and potential
harmful data by default.

<div class="contents">
<div class="contents" data-depth="2">

Table of Contents

Expand Down Expand Up @@ -275,6 +275,8 @@ defuse\_stdlib() (*experimental*)

### defusedxml.cElementTree

**NOTE** `defusedxml.cElementTree` is not available in Python 3.9+

parse(), iterparse(), fromstring(), XMLParser

### defusedxml.ElementTree
Expand Down Expand Up @@ -304,15 +306,17 @@ parse(), parseString()
### defusedxml.xmlrpc

The fix is implemented as monkey patch for the stdlib's xmlrpc package
(3.x) or xmlrpclib module (2.x). The function monkey\_patch() enables
the fixes, unmonkey\_patch() removes the patch and puts the code in its
former state.
(3.x) or xmlrpclib module (2.x). The function
<span class="title-ref">monkey\_patch()</span> enables the fixes,
<span class="title-ref">unmonkey\_patch()</span> removes the patch and
puts the code in its former state.

The monkey patch protects against XML related attacks as well as
decompression bombs and excessively large requests or responses. The
default setting is 30 MB for requests, responses and gzip decompression.
You can modify the default by changing the module variable MAX\_DATA. A
value of -1 disables the limit.
You can modify the default by changing the module variable
<span class="title-ref">MAX\_DATA</span>. A value of
<span class="title-ref">-1</span> disables the limit.

### defusedxml.lxml

Expand Down Expand Up @@ -379,8 +383,8 @@ new API functions:
expanded. The limit protects the parser against exponential entity
expansion attacks (aka billion laughs attack). When the limit is
exceeded the parser stops and fails with
XML\_ERROR\_ENTITY\_INDIRECTIONS. A value of 0 disables the
protection.
<span class="title-ref">XML\_ERROR\_ENTITY\_INDIRECTIONS</span>. A
value of 0 disables the protection.

- Supported range
0 .. UINT\_MAX
Expand All @@ -394,8 +398,8 @@ new API functions:
parser variable. The setting protects against quadratic blowup
attacks (lots of expansions of a large entity declaration). When the
sum of all entities exceeds the limit, the parser stops and fails
with XML\_ERROR\_ENTITY\_EXPANSION. A value of 0 disables the
protection.
with <span class="title-ref">XML\_ERROR\_ENTITY\_EXPANSION</span>. A
value of 0 disables the protection.

- Supported range
0 .. UINT\_MAX
Expand All @@ -409,7 +413,7 @@ new API functions:
after the endDoctypeDeclHandler has been called. The flag can be set
inside the endDoctypeDeclHandler. Without DTD information any entity
reference in the document body leads to
XML\_ERROR\_UNDEFINED\_ENTITY.
<span class="title-ref">XML\_ERROR\_UNDEFINED\_ENTITY</span>.

- Supported range
0, 1
Expand Down Expand Up @@ -640,8 +644,7 @@ default settings. It also does entity resolving when an
`org.xml.sax.EntityResolver` is configured. I'm not yet sure about the
default setting here.

Java specialists suggest to have a custom builder
factory:
Java specialists suggest to have a custom builder factory:

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setXIncludeAware(False);
Expand Down Expand Up @@ -712,6 +715,15 @@ See <https://www.python.org/psf/license> for licensing details.
Injection](https://www.owasp.org/index.php/Testing_for_XML_Injection_\(OWASP-DV-008\))
# Changelog

## defusedxml 0.7.0

*Release date: ??-Mar-2020*

- Add support for Python 3.9
- `defusedxml.cElementTree` is not available with Python 3.9.
- Python 2 is deprecate. Support for Python 2 will be removed in
0.8.0.

## defusedxml 0.6.0

*Release date: 17-Apr-2019*
Expand Down
2 changes: 2 additions & 0 deletions README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,8 @@ defuse_stdlib() (*experimental*)
defusedxml.cElementTree
-----------------------

**NOTE** ``defusedxml.cElementTree`` is not available in Python 3.9+

parse(), iterparse(), fromstring(), XMLParser


Expand Down
1 change: 1 addition & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

| Version | Supported |
| ------- | ------------------ |
| 0.7.0 | :white_check_mark: |
| 0.6.0 | :white_check_mark: |
| < 0.6 | :x: |

Expand Down
17 changes: 12 additions & 5 deletions defusedxml/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
ExternalReferenceForbidden,
NotSupportedError,
_apply_defusing,
_HAVE_CELEMENTTREE,
)


Expand All @@ -24,7 +25,10 @@ def defuse_stdlib():
"""
defused = {}

from . import cElementTree
if _HAVE_CELEMENTTREE:
from . import cElementTree
else:
cElementTree = None
from . import ElementTree
from . import minidom
from . import pulldom
Expand All @@ -36,22 +40,25 @@ def defuse_stdlib():
xmlrpc.monkey_patch()
defused[xmlrpc] = None

for defused_mod in [
cElementTree,
defused_mods = [
ElementTree,
minidom,
pulldom,
sax,
expatbuilder,
expatreader,
]:
]
if _HAVE_CELEMENTTREE:
defused_mods.append(cElementTree)

for defused_mod in defused_mods:
stdlib_mod = _apply_defusing(defused_mod)
defused[defused_mod] = stdlib_mod

return defused


__version__ = "0.6.0"
__version__ = "0.7.0.dev1"

__all__ = [
"DefusedXmlException",
Expand Down
6 changes: 5 additions & 1 deletion defusedxml/cElementTree.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
"""
from __future__ import absolute_import

from .common import _generate_etree_functions, _HAVE_CELEMENTTREE

if not _HAVE_CELEMENTTREE:
raise ImportError("cElementTree has been removed from Python 3.9")

from xml.etree.cElementTree import TreeBuilder as _TreeBuilder
from xml.etree.cElementTree import parse as _parse
from xml.etree.cElementTree import tostring
Expand All @@ -15,7 +20,6 @@
from xml.etree.ElementTree import iterparse as _iterparse

from .ElementTree import DefusedXMLParser
from .common import _generate_etree_functions

__origin__ = "xml.etree.cElementTree"

Expand Down
2 changes: 2 additions & 0 deletions defusedxml/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import xml.parsers.expat

PY3 = sys.version_info[0] == 3
# Python 3.9 removed cElementTree module
_HAVE_CELEMENTTREE = sys.version_info < (3, 9, 0)

# Fail early when pyexpat is not installed correctly
if not hasattr(xml.parsers.expat, "ParserCreate"):
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[tool.black]
line-length = 98
# black does not yet support py39
target-version = ['py27', 'py35', 'py36', 'py37', 'py38']
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def run(self):
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Topic :: Text Processing :: Markup :: XML",
],
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",
Expand Down
11 changes: 9 additions & 2 deletions tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,21 @@
from xml.sax import SAXParseException
from pyexpat import ExpatError

from defusedxml import cElementTree, ElementTree, minidom, pulldom, sax, xmlrpc, expatreader
from defusedxml import ElementTree, minidom, pulldom, sax, xmlrpc, expatreader
from defusedxml import defuse_stdlib
from defusedxml import (
DTDForbidden,
EntitiesForbidden,
ExternalReferenceForbidden,
NotSupportedError,
)
from defusedxml.common import PY3
from defusedxml.common import PY3, _HAVE_CELEMENTTREE


if _HAVE_CELEMENTTREE:
from defusedxml import cElementTree
else:
cElementTree = None


try:
Expand Down Expand Up @@ -205,6 +211,7 @@ def test_aliases(self):
assert self.module.XMLParse is parser


@unittest.skipUnless(_HAVE_CELEMENTTREE, "Python 3.9 has removed cElementTree")
class TestDefusedcElementTree(TestDefusedElementTree):
module = cElementTree

Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tox]
envlist = py27,py35,py36,py37,py38,black,pep8py2,pep8py3,doc
envlist = py27,py35,py36,py37,py38,py39,black,pep8py2,pep8py3,doc
skip_missing_interpreters = true

[testenv]
Expand Down

0 comments on commit 4339aee

Please sign in to comment.