Replaced xml.etree.ElementTree with defusedxml.ElementTree

This commit is contained in:
Andrew Murray 2021-06-30 11:28:00 +10:00
parent 41b58f4b16
commit d9d811ff21
11 changed files with 68 additions and 36 deletions

View File

@ -24,6 +24,7 @@ sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\
python3 -m pip install --upgrade pip python3 -m pip install --upgrade pip
PYTHONOPTIMIZE=0 python3 -m pip install cffi PYTHONOPTIMIZE=0 python3 -m pip install cffi
python3 -m pip install coverage python3 -m pip install coverage
python3 -m pip install defusedxml
python3 -m pip install olefile python3 -m pip install olefile
python3 -m pip install -U pytest python3 -m pip install -U pytest
python3 -m pip install -U pytest-cov python3 -m pip install -U pytest-cov

View File

@ -6,6 +6,7 @@ brew install libtiff libjpeg openjpeg libimagequant webp little-cms2 freetype op
PYTHONOPTIMIZE=0 python3 -m pip install cffi PYTHONOPTIMIZE=0 python3 -m pip install cffi
python3 -m pip install coverage python3 -m pip install coverage
python3 -m pip install defusedxml
python3 -m pip install olefile python3 -m pip install olefile
python3 -m pip install -U pytest python3 -m pip install -U pytest
python3 -m pip install -U pytest-cov python3 -m pip install -U pytest-cov

View File

@ -51,8 +51,8 @@ jobs:
- name: Print build system information - name: Print build system information
run: python .github/workflows/system-info.py run: python .github/workflows/system-info.py
- name: python -m pip install wheel pytest pytest-cov pytest-timeout - name: python -m pip install wheel pytest pytest-cov pytest-timeout defusedxml
run: python -m pip install wheel pytest pytest-cov pytest-timeout run: python -m pip install wheel pytest pytest-cov pytest-timeout defusedxml
- name: Install dependencies - name: Install dependencies
id: install id: install

View File

@ -28,6 +28,11 @@ from .helper import (
skip_unless_feature, skip_unless_feature,
) )
try:
import defusedxml.ElementTree as ElementTree
except ImportError:
ElementTree = None
TEST_FILE = "Tests/images/hopper.jpg" TEST_FILE = "Tests/images/hopper.jpg"
@ -825,26 +830,28 @@ class TestFileJpeg:
def test_getxmp(self): def test_getxmp(self):
with Image.open("Tests/images/xmp_test.jpg") as im: with Image.open("Tests/images/xmp_test.jpg") as im:
xmp = im.getxmp() if ElementTree is None:
assert xmp == {}
else:
xmp = im.getxmp()
assert isinstance(xmp, dict) description = xmp["xmpmeta"]["RDF"]["Description"]
assert description["DerivedFrom"] == {
"documentID": "8367D410E636EA95B7DE7EBA1C43A412",
"originalDocumentID": "8367D410E636EA95B7DE7EBA1C43A412",
}
assert description["Look"]["Description"]["Group"]["Alt"]["li"] == {
"lang": "x-default",
"text": "Profiles",
}
assert description["ToneCurve"]["Seq"]["li"] == ["0, 0", "255, 255"]
description = xmp["xmpmeta"]["RDF"]["Description"] # Attribute
assert description["DerivedFrom"] == { assert description["Version"] == "10.4"
"documentID": "8367D410E636EA95B7DE7EBA1C43A412",
"originalDocumentID": "8367D410E636EA95B7DE7EBA1C43A412",
}
assert description["Look"]["Description"]["Group"]["Alt"]["li"] == {
"lang": "x-default",
"text": "Profiles",
}
assert description["ToneCurve"]["Seq"]["li"] == ["0, 0", "255, 255"]
# Attribute if ElementTree is not None:
assert description["Version"] == "10.4" with Image.open("Tests/images/hopper.jpg") as im:
assert im.getxmp() == {}
with Image.open("Tests/images/hopper.jpg") as im:
assert im.getxmp() == {}
@pytest.mark.skipif(not is_win32(), reason="Windows only") @pytest.mark.skipif(not is_win32(), reason="Windows only")

View File

@ -19,6 +19,11 @@ from .helper import (
skip_unless_feature, skip_unless_feature,
) )
try:
import defusedxml.ElementTree as ElementTree
except ImportError:
ElementTree = None
# sample png stream # sample png stream
TEST_PNG_FILE = "Tests/images/hopper.png" TEST_PNG_FILE = "Tests/images/hopper.png"
@ -651,15 +656,16 @@ class TestFilePng:
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
assert len(reloaded.png.im_palette[1]) == 3 assert len(reloaded.png.im_palette[1]) == 3
def test_xmp(self): def test_getxmp(self):
with Image.open("Tests/images/color_snakes.png") as im: with Image.open("Tests/images/color_snakes.png") as im:
xmp = im.getxmp() if ElementTree is None:
assert im.getxmp() == {}
else:
xmp = im.getxmp()
assert isinstance(xmp, dict) description = xmp["xmpmeta"]["RDF"]["Description"]
assert description["PixelXDimension"] == "10"
description = xmp["xmpmeta"]["RDF"]["Description"] assert description["subject"]["Seq"] is None
assert description["PixelXDimension"] == "10"
assert description["subject"]["Seq"] is None
def test_exif(self): def test_exif(self):
# With an EXIF chunk # With an EXIF chunk

View File

@ -16,6 +16,11 @@ from .helper import (
is_win32, is_win32,
) )
try:
import defusedxml.ElementTree as ElementTree
except ImportError:
ElementTree = None
class TestFileTiff: class TestFileTiff:
def test_sanity(self, tmp_path): def test_sanity(self, tmp_path):
@ -643,15 +648,16 @@ class TestFileTiff:
with Image.open(outfile) as reloaded: with Image.open(outfile) as reloaded:
assert "icc_profile" not in reloaded.info assert "icc_profile" not in reloaded.info
def test_xmp(self): def test_getxmp(self):
with Image.open("Tests/images/lab.tif") as im: with Image.open("Tests/images/lab.tif") as im:
xmp = im.getxmp() if ElementTree is None:
assert im.getxmp() == {}
else:
xmp = im.getxmp()
assert isinstance(xmp, dict) description = xmp["xmpmeta"]["RDF"]["Description"]
assert description[0]["format"] == "image/tiff"
description = xmp["xmpmeta"]["RDF"]["Description"] assert description[3]["BitsPerSample"]["Seq"]["li"] == ["8", "8", "8"]
assert description[0]["format"] == "image/tiff"
assert description[3]["BitsPerSample"]["Seq"]["li"] == ["8", "8", "8"]
def test_close_on_load_exclusive(self, tmp_path): def test_close_on_load_exclusive(self, tmp_path):
# similar to test_fd_leak, but runs on unixlike os # similar to test_fd_leak, but runs on unixlike os

View File

@ -2,6 +2,7 @@
black black
check-manifest check-manifest
coverage coverage
defusedxml
markdown2 markdown2
olefile olefile
packaging packaging

View File

@ -36,10 +36,14 @@ import struct
import sys import sys
import tempfile import tempfile
import warnings import warnings
import xml.etree.ElementTree
from collections.abc import Callable, MutableMapping from collections.abc import Callable, MutableMapping
from pathlib import Path from pathlib import Path
try:
import defusedxml.ElementTree as ElementTree
except ImportError:
ElementTree = None
# VERSION was removed in Pillow 6.0.0. # VERSION was removed in Pillow 6.0.0.
# PILLOW_VERSION is deprecated and will be removed in a future release. # PILLOW_VERSION is deprecated and will be removed in a future release.
# Use __version__ instead. # Use __version__ instead.
@ -1359,8 +1363,11 @@ class Image:
return element.text return element.text
return value return value
root = xml.etree.ElementTree.fromstring(xmp_tags) if ElementTree is None:
return {get_name(root.tag): get_value(root)} return {}
else:
root = ElementTree.fromstring(xmp_tags)
return {get_name(root.tag): get_value(root)}
def getexif(self): def getexif(self):
if self._exif is None: if self._exif is None:

View File

@ -480,6 +480,7 @@ class JpegImageFile(ImageFile.ImageFile):
def getxmp(self): def getxmp(self):
""" """
Returns a dictionary containing the XMP tags. Returns a dictionary containing the XMP tags.
Requires defusedxml to be installed.
:returns: XMP tags in a dictionary. :returns: XMP tags in a dictionary.
""" """

View File

@ -981,6 +981,7 @@ class PngImageFile(ImageFile.ImageFile):
def getxmp(self): def getxmp(self):
""" """
Returns a dictionary containing the XMP tags. Returns a dictionary containing the XMP tags.
Requires defusedxml to be installed.
:returns: XMP tags in a dictionary. :returns: XMP tags in a dictionary.
""" """
return ( return (

View File

@ -1112,6 +1112,7 @@ class TiffImageFile(ImageFile.ImageFile):
def getxmp(self): def getxmp(self):
""" """
Returns a dictionary containing the XMP tags. Returns a dictionary containing the XMP tags.
Requires defusedxml to be installed.
:returns: XMP tags in a dictionary. :returns: XMP tags in a dictionary.
""" """
return self._getxmp(self.tag_v2[700]) if 700 in self.tag_v2 else {} return self._getxmp(self.tag_v2[700]) if 700 in self.tag_v2 else {}