From dee4a3536eb26028321478be533f6963ad9ce0b4 Mon Sep 17 00:00:00 2001 From: Martin Mahner Date: Tue, 13 Aug 2024 17:27:45 +0200 Subject: [PATCH] Make PNG library optional. Refs #338 --- qrcode/compat/png.py | 7 +++++++ qrcode/image/pure.py | 9 ++++----- qrcode/tests/test_qrcode.py | 8 +++++--- tox.ini | 3 ++- 4 files changed, 18 insertions(+), 9 deletions(-) create mode 100644 qrcode/compat/png.py diff --git a/qrcode/compat/png.py b/qrcode/compat/png.py new file mode 100644 index 00000000..8d7b9056 --- /dev/null +++ b/qrcode/compat/png.py @@ -0,0 +1,7 @@ +# Try to import png library. +PngWriter = None + +try: + from png import Writer as PngWriter # type: ignore # noqa: F401 +except ImportError: # pragma: no cover + pass diff --git a/qrcode/image/pure.py b/qrcode/image/pure.py index 690ebe0c..2b995376 100644 --- a/qrcode/image/pure.py +++ b/qrcode/image/pure.py @@ -1,11 +1,10 @@ from itertools import chain -import png +from qrcode.compat.png import PngWriter +from qrcode.image.base import BaseImage -import qrcode.image.base - -class PyPNGImage(qrcode.image.base.BaseImage): +class PyPNGImage(BaseImage): """ pyPNG image builder. """ @@ -15,7 +14,7 @@ class PyPNGImage(qrcode.image.base.BaseImage): needs_drawrect = False def new_image(self, **kwargs): - return png.Writer(self.pixel_size, self.pixel_size, greyscale=True, bitdepth=1) + return PngWriter(self.pixel_size, self.pixel_size, greyscale=True, bitdepth=1) def drawrect(self, row, col): """ diff --git a/qrcode/tests/test_qrcode.py b/qrcode/tests/test_qrcode.py index 8d768bd9..63eaca9f 100644 --- a/qrcode/tests/test_qrcode.py +++ b/qrcode/tests/test_qrcode.py @@ -4,11 +4,11 @@ from tempfile import mkdtemp from unittest import mock -import png import qrcode import qrcode.util from qrcode.compat.pil import Image as pil_Image +from qrcode.compat.png import PngWriter from qrcode.exceptions import DataOverflowError from qrcode.image.base import BaseImage from qrcode.image.pure import PyPNGImage @@ -174,20 +174,22 @@ class MockFactory(BaseImage): self.assertTrue(MockFactory.new_image.called) self.assertTrue(MockFactory.drawrect.called) + @unittest.skipIf(not PngWriter, "Requires PNG") def test_render_pypng(self): qr = qrcode.QRCode() qr.add_data(UNICODE_TEXT) img = qr.make_image(image_factory=PyPNGImage) - self.assertIsInstance(img.get_image(), png.Writer) + self.assertIsInstance(img.get_image(), PngWriter) print(img.width, img.box_size, img.border) img.save(io.BytesIO()) + @unittest.skipIf(not PngWriter, "Requires PNG") def test_render_pypng_to_str(self): qr = qrcode.QRCode() qr.add_data(UNICODE_TEXT) img = qr.make_image(image_factory=PyPNGImage) - self.assertIsInstance(img.get_image(), png.Writer) + self.assertIsInstance(img.get_image(), PngWriter) mock_open = mock.mock_open() with mock.patch("qrcode.image.pure.open", mock_open, create=True): diff --git a/tox.ini b/tox.ini index c89f4787..0b46e48f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] distribute = False -envlist = py{39,310,311,312}-{pil,nopil} +envlist = py{39,310,311,312}-{pil,png,none} skip_missing_interpreters = True [gh-actions] @@ -15,5 +15,6 @@ commands = pytest {envsitepackagesdir}/qrcode deps = pil: pillow>=9.1.0 + png: pypng pytest pytest-cov