From f0ec7095d37f15873919aa6df5769667e8fc54ac Mon Sep 17 00:00:00 2001 From: Martin Mahner Date: Fri, 25 Jul 2025 20:09:25 +0200 Subject: [PATCH 1/6] Fix QRCode.clear() to properly reset the QRCode object. Fixes #392 --- .claude/settings.local.json | 8 ++++ qrcode/main.py | 1 + qrcode/tests/regression/__init__.py | 0 qrcode/tests/regression/test_pil_clear.py | 55 +++++++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 .claude/settings.local.json create mode 100644 qrcode/tests/regression/__init__.py create mode 100644 qrcode/tests/regression/test_pil_clear.py diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 00000000..841c8adf --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "Bash(python -m pytest qrcode/tests/test_qrcode.py::test_qrcode_factory -xvs)" + ], + "deny": [] + } +} \ No newline at end of file diff --git a/qrcode/main.py b/qrcode/main.py index be62de81..6eada091 100644 --- a/qrcode/main.py +++ b/qrcode/main.py @@ -123,6 +123,7 @@ def clear(self): self.modules_count = 0 self.data_cache = None self.data_list = [] + self._version = None def add_data(self, data, optimize=20): """ diff --git a/qrcode/tests/regression/__init__.py b/qrcode/tests/regression/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/qrcode/tests/regression/test_pil_clear.py b/qrcode/tests/regression/test_pil_clear.py new file mode 100644 index 00000000..49f845e5 --- /dev/null +++ b/qrcode/tests/regression/test_pil_clear.py @@ -0,0 +1,55 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +import qrcode + +if TYPE_CHECKING: + from pathlib import Path + + +def test_qrcode_clear_resets_size(tmp_path: Path): + """ + Test that QRCode.clear() properly resets the QRCode object. + + Regression test for: + + QRCode class not resizing down between runs + https://github.com/lincolnloop/python-qrcode/issues/392 + """ + test1_path = tmp_path / "test1.png" + test2_path = tmp_path / "test2.png" + test3_path = tmp_path / "test3.png" + + # Create a QR code instance + qr = qrcode.QRCode(version=None) + + # Generate first QR code + qr.add_data("https://example.com/") + qr.make(fit=True) + img1 = qr.make_image() + img1.save(test1_path) + + # Clear and generate second QR code with different data + qr.clear() + qr.add_data("https://example.net/some/other/path") + qr.make(fit=True) + img2 = qr.make_image() + img2.save(test2_path) + + # Clear and generate third QR code with same data as first + qr.clear() + qr.add_data("https://example.com/") + qr.make(fit=True) + img3 = qr.make_image() + img3.save(test3_path) + + # Compare the images. Image 1 and 3 must be binary identical. + with test1_path.open("rb") as file1, test3_path.open("rb") as file3: + file1_data = file1.read() + file3_data = file3.read() + + # Check that the first and third QR codes are identical + assert file1_data == file3_data, ( + "First and third QR codes should be identical after clearing" + ) From dc74a58c05d41fdc920c0d0771c384ae62ad0ab0 Mon Sep 17 00:00:00 2001 From: Martin Mahner Date: Fri, 25 Jul 2025 20:10:45 +0200 Subject: [PATCH 2/6] Remove Claude config --- .claude/settings.local.json | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index 841c8adf..00000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(python -m pytest qrcode/tests/test_qrcode.py::test_qrcode_factory -xvs)" - ], - "deny": [] - } -} \ No newline at end of file From af63a748694f3a6a42b32806c419749178efe254 Mon Sep 17 00:00:00 2001 From: Martin Mahner Date: Fri, 25 Jul 2025 20:13:39 +0200 Subject: [PATCH 3/6] Shorten up test --- qrcode/tests/regression/test_pil_clear.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/qrcode/tests/regression/test_pil_clear.py b/qrcode/tests/regression/test_pil_clear.py index 49f845e5..896c7cfa 100644 --- a/qrcode/tests/regression/test_pil_clear.py +++ b/qrcode/tests/regression/test_pil_clear.py @@ -44,12 +44,8 @@ def test_qrcode_clear_resets_size(tmp_path: Path): img3 = qr.make_image() img3.save(test3_path) - # Compare the images. Image 1 and 3 must be binary identical. + # Check that the first and third QR codes are identical. with test1_path.open("rb") as file1, test3_path.open("rb") as file3: - file1_data = file1.read() - file3_data = file3.read() - - # Check that the first and third QR codes are identical - assert file1_data == file3_data, ( + assert file1.read() == file3.read(), ( "First and third QR codes should be identical after clearing" ) From d5d8f0c745e6df78bdae44c558505a78ac448c33 Mon Sep 17 00:00:00 2001 From: Martin Mahner Date: Fri, 25 Jul 2025 20:18:19 +0200 Subject: [PATCH 4/6] Move `clear()` call before QRCode attribute initialization --- qrcode/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qrcode/main.py b/qrcode/main.py index 6eada091..28070284 100644 --- a/qrcode/main.py +++ b/qrcode/main.py @@ -81,6 +81,7 @@ def __init__( ): _check_box_size(box_size) _check_border(border) + self.clear() self.version = version self.error_correction = int(error_correction) self.box_size = int(box_size) @@ -91,7 +92,6 @@ def __init__( self.image_factory = image_factory if image_factory is not None: assert issubclass(image_factory, BaseImage) - self.clear() @property def version(self) -> int: From 90dfd341400afe3860d3ca36f7dd5adcfa2b8068 Mon Sep 17 00:00:00 2001 From: Martin Mahner Date: Fri, 25 Jul 2025 20:20:40 +0200 Subject: [PATCH 5/6] Test is a PIL only test --- qrcode/tests/regression/test_pil_clear.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qrcode/tests/regression/test_pil_clear.py b/qrcode/tests/regression/test_pil_clear.py index 896c7cfa..78ffebee 100644 --- a/qrcode/tests/regression/test_pil_clear.py +++ b/qrcode/tests/regression/test_pil_clear.py @@ -2,12 +2,15 @@ from typing import TYPE_CHECKING +import pytest + import qrcode if TYPE_CHECKING: from pathlib import Path +@pytest.mark.parametrize("back_color", ["TransParent", "red", (255, 195, 235)]) def test_qrcode_clear_resets_size(tmp_path: Path): """ Test that QRCode.clear() properly resets the QRCode object. From 915af02ad54192d0cfc8aac4f642810ec2c65c55 Mon Sep 17 00:00:00 2001 From: Martin Mahner Date: Fri, 25 Jul 2025 20:21:20 +0200 Subject: [PATCH 6/6] Test is a PIL only test --- qrcode/tests/regression/test_pil_clear.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qrcode/tests/regression/test_pil_clear.py b/qrcode/tests/regression/test_pil_clear.py index 78ffebee..220284e9 100644 --- a/qrcode/tests/regression/test_pil_clear.py +++ b/qrcode/tests/regression/test_pil_clear.py @@ -5,12 +5,13 @@ import pytest import qrcode +from qrcode.constants import PIL_AVAILABLE if TYPE_CHECKING: from pathlib import Path -@pytest.mark.parametrize("back_color", ["TransParent", "red", (255, 195, 235)]) +@pytest.mark.skipif(not PIL_AVAILABLE, reason="PIL is not installed") def test_qrcode_clear_resets_size(tmp_path: Path): """ Test that QRCode.clear() properly resets the QRCode object.