From 6d34a038b95283d2db01aa2770e9058186cfea7a Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 27 Oct 2025 22:40:50 +0200 Subject: [PATCH 1/3] Add support for Python 3.14 --- .github/workflows/push.yml | 2 +- pyproject.toml | 1 + tox.ini | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index da4a8526..b24386bf 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -8,7 +8,7 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] steps: - uses: actions/checkout@v4 diff --git a/pyproject.toml b/pyproject.toml index 9d56b383..9ce50ea6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3 :: Only", "Topic :: Multimedia :: Graphics", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tox.ini b/tox.ini index 017cc3f3..c44301c0 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] distribute = False -envlist = py{39,310,311,312,313}-{pil,png,none} +envlist = py{39,310,311,312,313,314}-{pil,png,none} skip_missing_interpreters = True [gh-actions] @@ -10,6 +10,7 @@ python = 3.11: py311 3.12: py312 3.13: py313 + 3.14: py314 [testenv] commands = From d23a7f3e5af8981b34e7135bafab2d3b24e78d66 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 27 Oct 2025 22:43:04 +0200 Subject: [PATCH 2/3] Drop support for EOL Python 3.9 --- .github/workflows/push.yml | 2 +- pyproject.toml | 5 ++--- tox.ini | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index b24386bf..2a96d36c 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -8,7 +8,7 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] steps: - uses: actions/checkout@v4 diff --git a/pyproject.toml b/pyproject.toml index 9ce50ea6..265c2f53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,6 @@ classifiers = [ "Intended Audience :: Developers", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", @@ -29,7 +28,7 @@ classifiers = [ "Topic :: Multimedia :: Graphics", "Topic :: Software Development :: Libraries :: Python Modules", ] -requires-python = "~=3.9" +requires-python = "~=3.10" dependencies = [ "colorama; sys_platform == 'win32'", "deprecation", @@ -98,7 +97,7 @@ exclude_lines = [ skip_covered = true [tool.ruff] -target-version = "py39" +target-version = "py310" exclude = ["migrations"] lint.select = ["ALL"] lint.ignore = [ diff --git a/tox.ini b/tox.ini index c44301c0..bf7d8fa8 100644 --- a/tox.ini +++ b/tox.ini @@ -1,11 +1,10 @@ [tox] distribute = False -envlist = py{39,310,311,312,313,314}-{pil,png,none} +envlist = py{310,311,312,313,314}-{pil,png,none} skip_missing_interpreters = True [gh-actions] python = - 3.9: py39 3.10: py310 3.11: py311 3.12: py312 From c13c3806c165df065646adb8c19554f24754d289 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 27 Oct 2025 22:45:35 +0200 Subject: [PATCH 3/3] Ruff lint and format --- qrcode/base.py | 2 +- qrcode/image/styles/colormasks.py | 3 +-- qrcode/main.py | 8 +++----- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/qrcode/base.py b/qrcode/base.py index 630542d5..95e4d224 100644 --- a/qrcode/base.py +++ b/qrcode/base.py @@ -281,7 +281,7 @@ def __mod__(self, other): num = [ item ^ gexp(glog(other_item) + ratio) - for item, other_item in zip(self, other) + for item, other_item in zip(self, other, strict=False) ] if difference: num.extend(self[-difference:]) diff --git a/qrcode/image/styles/colormasks.py b/qrcode/image/styles/colormasks.py index 01dad916..62c0fb6b 100644 --- a/qrcode/image/styles/colormasks.py +++ b/qrcode/image/styles/colormasks.py @@ -80,7 +80,7 @@ def extrap_num(self, n1, n2, interped_num): # find the interpolation coefficient between two numbers def extrap_color(self, col1, col2, interped_color): normed = [] - for c1, c2, ci in zip(col1, col2, interped_color): + for c1, c2, ci in zip(col1, col2, interped_color, strict=False): extrap = self.extrap_num(c1, c2, ci) if extrap is not None: normed.append(extrap) @@ -221,5 +221,4 @@ def initialize(self, styledPilImage, image): self.color_img = self.color_img.resize(image.size) def get_fg_pixel(self, image, x, y): - width, _ = image.size return self.color_img.getpixel((x, y)) diff --git a/qrcode/main.py b/qrcode/main.py index be62de81..9601ca45 100644 --- a/qrcode/main.py +++ b/qrcode/main.py @@ -3,13 +3,13 @@ import sys import warnings from bisect import bisect_left -from typing import Generic, Literal, NamedTuple, Optional, TypeVar, cast, overload +from typing import Generic, NamedTuple, TypeVar, cast, overload from qrcode import constants, exceptions, util from qrcode.image.base import BaseImage from qrcode.image.pure import PyPNGImage -ModulesType = list[list[Optional[bool]]] +ModulesType = list[list[bool | None]] # Cache modules generated just based on the QR Code version precomputed_qr_blanks: dict[int, ModulesType] = {} @@ -320,9 +320,7 @@ def get_module(x, y) -> int: out.flush() @overload - def make_image( - self, image_factory: Literal[None] = None, **kwargs - ) -> GenericImage: ... + def make_image(self, image_factory: None = None, **kwargs) -> GenericImage: ... @overload def make_image(