Skip to content

Commit

Permalink
Ensure PIL is still optional
Browse files Browse the repository at this point in the history
  • Loading branch information
SmileyChris committed Mar 11, 2022
1 parent 49060c4 commit 6877bf4
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 14 deletions.
15 changes: 9 additions & 6 deletions qrcode/image/styles/moduledrawers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# For backwards compatibility, importing the PIL drawers here.
from .pil import CircleModuleDrawer # noqa: F401
from .pil import GappedSquareModuleDrawer # noqa: F401
from .pil import HorizontalBarsDrawer # noqa: F401
from .pil import RoundedModuleDrawer # noqa: F401
from .pil import SquareModuleDrawer # noqa: F401
from .pil import VerticalBarsDrawer # noqa: F401
try:
from .pil import CircleModuleDrawer # noqa: F401
from .pil import GappedSquareModuleDrawer # noqa: F401
from .pil import HorizontalBarsDrawer # noqa: F401
from .pil import RoundedModuleDrawer # noqa: F401
from .pil import SquareModuleDrawer # noqa: F401
from .pil import VerticalBarsDrawer # noqa: F401
except ImportError:
pass
9 changes: 9 additions & 0 deletions qrcode/tests/test_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,17 @@

from qrcode import run_example

try:
from PIL import Image
except ImportError:
try:
import Image
except ImportError:
Image = None


class ExampleTest(unittest.TestCase):
@unittest.skipIf(not Image, "Requires PIL")
@mock.patch("PIL.Image.Image.show")
def runTest(self, mock_show):
run_example()
Expand Down
44 changes: 36 additions & 8 deletions qrcode/tests/test_qrcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,25 @@
from tempfile import mkdtemp
from unittest import mock

import qrcode
import qrcode.util
from qrcode.exceptions import DataOverflowError
from qrcode.image.base import BaseImage
from qrcode.image.styles import moduledrawers
from qrcode.util import MODE_8BIT_BYTE, MODE_ALPHA_NUM, MODE_NUMBER, QRData

try:
import pymaging_png # type: ignore
from qrcode.image.pure import PymagingImage
except ImportError: # pragma: no cover
pymaging_png = None

import qrcode
import qrcode.util
from qrcode.exceptions import DataOverflowError
from qrcode.image.base import BaseImage
from qrcode.image.pil import Image as pil_Image
from qrcode.image.styledpil import StyledPilImage
from qrcode.image.styles import colormasks, moduledrawers
from qrcode.util import MODE_8BIT_BYTE, MODE_ALPHA_NUM, MODE_NUMBER, QRData
try:
from qrcode.image.pil import Image as pil_Image
from qrcode.image.styledpil import StyledPilImage
from qrcode.image.styles import colormasks
except:
pil_Image = None

UNICODE_TEXT = "\u03b1\u03b2\u03b3"
WHITE = (255, 255, 255)
Expand Down Expand Up @@ -104,31 +109,36 @@ def test_mode_8bit_newline(self):
qr.make()
self.assertEqual(qr.data_list[0].mode, MODE_8BIT_BYTE)

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_pil(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image()
img.save(io.BytesIO())
self.assertIsInstance(img.get_image(), pil_Image.Image)

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_pil_with_transparent_background(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(back_color="TransParent")
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_pil_with_red_background(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(back_color="red")
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_pil_with_rgb_color_tuples(self):
qr = qrcode.QRCode()
qr.add_data(UNICODE_TEXT)
img = qr.make_image(back_color=(255, 195, 235), fill_color=(55, 95, 35))
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_with_pattern(self):
qr = qrcode.QRCode(mask_pattern=3)
qr.add_data(UNICODE_TEXT)
Expand Down Expand Up @@ -195,19 +205,22 @@ def test_render_pymaging_png_bad_kind(self):
with self.assertRaises(ValueError):
img.save(io.BytesIO(), kind="FISH")

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_pil_image(self):
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
img = qr.make_image(image_factory=StyledPilImage)
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_embeded_image(self):
embeded_img = pil_Image.new("RGB", (10, 10), color="red")
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
img = qr.make_image(image_factory=StyledPilImage, embeded_image=embeded_img)
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_embeded_image_path(self):
tmpfile = os.path.join(self.tmpdir, "test.png")
embeded_img = pil_Image.new("RGB", (10, 10), color="red")
Expand All @@ -218,6 +231,7 @@ def test_render_styled_with_embeded_image_path(self):
img.save(io.BytesIO())
os.remove(tmpfile)

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_square_module_drawer(self):
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
Expand All @@ -227,6 +241,7 @@ def test_render_styled_with_square_module_drawer(self):
)
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_gapped_module_drawer(self):
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
Expand All @@ -236,6 +251,7 @@ def test_render_styled_with_gapped_module_drawer(self):
)
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_circle_module_drawer(self):
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
Expand All @@ -245,6 +261,7 @@ def test_render_styled_with_circle_module_drawer(self):
)
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_rounded_module_drawer(self):
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
Expand All @@ -254,6 +271,7 @@ def test_render_styled_with_rounded_module_drawer(self):
)
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_vertical_bars_module_drawer(self):
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
Expand All @@ -263,6 +281,7 @@ def test_render_styled_with_vertical_bars_module_drawer(self):
)
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_horizontal_bars_module_drawer(self):
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
Expand All @@ -272,20 +291,23 @@ def test_render_styled_with_horizontal_bars_module_drawer(self):
)
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_default_solid_color_mask(self):
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
mask = colormasks.SolidFillColorMask()
img = qr.make_image(image_factory=StyledPilImage, color_mask=mask)
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_solid_color_mask(self):
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
mask = colormasks.SolidFillColorMask(back_color=WHITE, front_color=RED)
img = qr.make_image(image_factory=StyledPilImage, color_mask=mask)
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_color_mask_with_transparency(self):
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
Expand All @@ -296,6 +318,7 @@ def test_render_styled_with_color_mask_with_transparency(self):
img.save(io.BytesIO())
assert img.mode == "RGBA"

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_radial_gradient_color_mask(self):
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
Expand All @@ -305,6 +328,7 @@ def test_render_styled_with_radial_gradient_color_mask(self):
img = qr.make_image(image_factory=StyledPilImage, color_mask=mask)
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_square_gradient_color_mask(self):
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
Expand All @@ -314,6 +338,7 @@ def test_render_styled_with_square_gradient_color_mask(self):
img = qr.make_image(image_factory=StyledPilImage, color_mask=mask)
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_horizontal_gradient_color_mask(self):
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
Expand All @@ -323,6 +348,7 @@ def test_render_styled_with_horizontal_gradient_color_mask(self):
img = qr.make_image(image_factory=StyledPilImage, color_mask=mask)
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_vertical_gradient_color_mask(self):
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
qr.add_data(UNICODE_TEXT)
Expand All @@ -332,6 +358,7 @@ def test_render_styled_with_vertical_gradient_color_mask(self):
img = qr.make_image(image_factory=StyledPilImage, color_mask=mask)
img.save(io.BytesIO())

@unittest.skipIf(not pil_Image, "Requires PIL")
def test_render_styled_with_image_color_mask(self):
img_mask = pil_Image.new("RGB", (10, 10), color="red")
qr = qrcode.QRCode(error_correction=qrcode.ERROR_CORRECT_L)
Expand Down Expand Up @@ -465,5 +492,6 @@ def test_negative_size_at_usage(self):


class ShortcutTest(unittest.TestCase):
@unittest.skipIf(not pil_Image, "Requires PIL")
def runTest(self):
qrcode.make("image")
12 changes: 12 additions & 0 deletions qrcode/tests/test_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@

from qrcode.console_scripts import main, commas

try:
from PIL import Image
except ImportError:
try:
import Image
except ImportError:
Image = None


def bad_read():
raise UnicodeDecodeError("utf-8", b"0x80", 0, 1, "invalid start byte")
Expand All @@ -27,6 +35,7 @@ def test_isatty(self, mock_print_ascii):

@mock.patch("os.isatty", lambda *args: False)
@mock.patch("sys.stdout")
@unittest.skipIf(not Image, "Requires PIL")
def test_piped(self, mock_stdout):
main(["testtext"])

Expand Down Expand Up @@ -66,15 +75,18 @@ def test_bad_factory(self, mock_stderr):
self.assertRaises(SystemExit, main, "testtext --factory fish".split())

@mock.patch.object(sys, "argv", "qr testtext output".split())
@unittest.skipIf(not Image, "Requires PIL")
def test_sys_argv(self):
main()

@unittest.skipIf(not Image, "Requires PIL")
def test_output(self):
tmpfile = os.path.join(self.tmpdir, "test.png")
main(["testtext", "--output", tmpfile])
os.remove(tmpfile)

@mock.patch("sys.stderr", new_callable=io.StringIO)
@unittest.skipIf(not Image, "Requires PIL")
def test_factory_drawer_none(self, mock_stderr):
with self.assertRaises(SystemExit):
main("testtext --factory pil --factory-drawer nope".split())
Expand Down

0 comments on commit 6877bf4

Please sign in to comment.