From eb6d1c02daa52fbd1941ccfba0740e4059a82ed9 Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Fri, 9 Oct 2026 23:09:19 +0200 Subject: [PATCH 1/5] Add some obvious type hints --- barcode/codex.py | 4 ++-- barcode/isxn.py | 2 +- barcode/writer.py | 10 +++++----- tests/test_gs1_128.py | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/barcode/codex.py b/barcode/codex.py index e22fcd1..3837d15 100755 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -112,7 +112,7 @@ def __init__(self, pzn, writer=None) -> None: self.pzn = f"{pzn}{self.calculate_checksum()}" super().__init__(f"PZN-{self.pzn}", writer, add_checksum=False) - def get_fullcode(self): + def get_fullcode(self) -> str: return f"PZN-{self.pzn}" def calculate_checksum(self): @@ -174,7 +174,7 @@ def _new_charset(self, which: Literal["A", "B", "C"]) -> list[int]: return [code] # to be redefined in subclass if required - def _is_char_fnc1_char(self, char): + def _is_char_fnc1_char(self, char) -> bool: """Whether a character is the FNC1 character. May be redefined by subclasses if required. FNC1 char is defined in GS1-128 diff --git a/barcode/isxn.py b/barcode/isxn.py index 58e11cf..710226f 100755 --- a/barcode/isxn.py +++ b/barcode/isxn.py @@ -110,7 +110,7 @@ def _calculate_checksum(self): return tmp - def make_ean(self): + def make_ean(self) -> str: return f"977{self.issn[:7]}00{self._calculate_checksum()}" def __str__(self) -> str: diff --git a/barcode/writer.py b/barcode/writer.py index e5aa647..26dc808 100755 --- a/barcode/writer.py +++ b/barcode/writer.py @@ -323,7 +323,7 @@ def __init__(self) -> None: self._root: xml.dom.minidom.Element self._group: xml.dom.minidom.Element - def _init(self, code: list[str]): + def _init(self, code: list[str]) -> None: if len(code) != 1: raise NotImplementedError("Only one line of code is supported") line = code[0] @@ -354,7 +354,7 @@ def _init(self, code: list[str]): _set_attributes(background, **attributes) self._group.appendChild(background) - def _create_module(self, xpos, ypos, width, color): + def _create_module(self, xpos, ypos, width, color) -> None: # Background rect has been provided already, so skipping "spaces" if color != self.background: element = self._document.createElement("rect") @@ -368,7 +368,7 @@ def _create_module(self, xpos, ypos, width, color): _set_attributes(element, **attributes) self._group.appendChild(element) - def _create_text(self, xpos, ypos): + def _create_text(self, xpos, ypos) -> None: # check option to override self.text with self.human (barcode as # human readable data, can be used to print own formats) barcodetext = self.human if self.human != "" else self.text @@ -461,7 +461,7 @@ def _init(self, code: list[str]) -> None: self._image = Image.new(self.mode, size, self.background) self._draw = ImageDraw.Draw(self._image) - def _paint_module(self, xpos: float, ypos: float, width: float, color): + def _paint_module(self, xpos: float, ypos: float, width: float, color) -> None: size = [ (mm2px(xpos, self.dpi), mm2px(ypos, self.dpi)), ( @@ -471,7 +471,7 @@ def _paint_module(self, xpos: float, ypos: float, width: float, color): ] self._draw.rectangle(size, outline=color, fill=color) - def _paint_text(self, xpos, ypos): + def _paint_text(self, xpos, ypos) -> None: assert ImageFont is not None # check option to override self.text with self.human (barcode as diff --git a/tests/test_gs1_128.py b/tests/test_gs1_128.py index 3352bf0..2fbda92 100644 --- a/tests/test_gs1_128.py +++ b/tests/test_gs1_128.py @@ -205,6 +205,6 @@ @pytest.mark.parametrize(("target", "answer"), CODE_BUILD_TEST) -def test_code_build(target, answer): +def test_code_build(target, answer) -> None: gs1_128 = Gs1_128(target) assert gs1_128._build() == answer From e5f86b4cc718abb4f195d69a9100887b1ceadd9a Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Fri, 9 Oct 2026 23:10:07 +0200 Subject: [PATCH 2/5] Remove unnecessary else --- barcode/writer.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/barcode/writer.py b/barcode/writer.py index 26dc808..75bbfcb 100755 --- a/barcode/writer.py +++ b/barcode/writer.py @@ -267,10 +267,9 @@ def render(self, code: list[str]): xpos, ypos, self.module_width * abs(mod), color ) xpos += self.module_width * abs(mod) - else: - if height_factor != 1: - text["end"].append(xpos) - self.module_height = base_height + if height_factor != 1: + text["end"].append(xpos) + self.module_height = base_height bxe = xpos ypos += self.module_height From c2506288086ee9ded19bc381ae83ed218c4af107 Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Fri, 9 Oct 2026 23:11:40 +0200 Subject: [PATCH 3/5] Make files non-executable None of these are intended to be executed directly. --- barcode/__init__.py | 0 barcode/base.py | 0 barcode/codex.py | 0 barcode/ean.py | 0 barcode/errors.py | 0 barcode/isxn.py | 0 barcode/upc.py | 0 barcode/writer.py | 0 tests/test_builds.py | 0 tests/test_checksums.py | 0 tests/test_manually.py | 0 11 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 barcode/__init__.py mode change 100755 => 100644 barcode/base.py mode change 100755 => 100644 barcode/codex.py mode change 100755 => 100644 barcode/ean.py mode change 100755 => 100644 barcode/errors.py mode change 100755 => 100644 barcode/isxn.py mode change 100755 => 100644 barcode/upc.py mode change 100755 => 100644 barcode/writer.py mode change 100755 => 100644 tests/test_builds.py mode change 100755 => 100644 tests/test_checksums.py mode change 100755 => 100644 tests/test_manually.py diff --git a/barcode/__init__.py b/barcode/__init__.py old mode 100755 new mode 100644 diff --git a/barcode/base.py b/barcode/base.py old mode 100755 new mode 100644 diff --git a/barcode/codex.py b/barcode/codex.py old mode 100755 new mode 100644 diff --git a/barcode/ean.py b/barcode/ean.py old mode 100755 new mode 100644 diff --git a/barcode/errors.py b/barcode/errors.py old mode 100755 new mode 100644 diff --git a/barcode/isxn.py b/barcode/isxn.py old mode 100755 new mode 100644 diff --git a/barcode/upc.py b/barcode/upc.py old mode 100755 new mode 100644 diff --git a/barcode/writer.py b/barcode/writer.py old mode 100755 new mode 100644 diff --git a/tests/test_builds.py b/tests/test_builds.py old mode 100755 new mode 100644 diff --git a/tests/test_checksums.py b/tests/test_checksums.py old mode 100755 new mode 100644 diff --git a/tests/test_manually.py b/tests/test_manually.py old mode 100755 new mode 100644 From a9ce8e0f6ffed3edc5dd526d6ac1783e6e48694e Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Fri, 9 Oct 2026 23:19:25 +0200 Subject: [PATCH 4/5] Add missing type hints --- barcode/base.py | 10 ++++++++-- barcode/codabar.py | 15 +++++++++++++-- barcode/codex.py | 35 +++++++++++++++++++++++++---------- barcode/ean.py | 28 ++++++++++++++++++++++------ barcode/errors.py | 2 +- barcode/isxn.py | 21 ++++++++++++++++----- barcode/itf.py | 23 ++++++++++++++++++++--- barcode/pybarcode.py | 5 +++-- barcode/upc.py | 25 ++++++++++++++++++++----- barcode/writer.py | 36 ++++++++++++++++++++++++------------ pyproject.toml | 5 +++++ tests/test_gs1_128.py | 2 +- tests/test_manually.py | 4 ++-- 13 files changed, 160 insertions(+), 51 deletions(-) diff --git a/barcode/base.py b/barcode/base.py index cfcbe36..e3aa713 100644 --- a/barcode/base.py +++ b/barcode/base.py @@ -11,6 +11,8 @@ if TYPE_CHECKING: from typing import BinaryIO + from PIL.Image import Image as T_Image + class Barcode: name = "" @@ -53,7 +55,7 @@ def build(self) -> list[str]: other characters such as G for guard lines (e.g. in EAN13).""" raise NotImplementedError - def get_fullcode(self): + def get_fullcode(self) -> str: """Returns the full code, encoded in the barcode. :returns: Full human readable code. @@ -92,7 +94,11 @@ def write( output = self.render(options, text) self.writer.write(output, fp) - def render(self, writer_options: dict | None = None, text: str | None = None): + def render( + self, + writer_options: dict | None = None, + text: str | None = None, + ) -> bytes | T_Image: """Renders the barcode using `self.writer`. :param writer_options: Options for `self.writer`, see writer docs for details. diff --git a/barcode/codabar.py b/barcode/codabar.py index df0c68b..3ea73cb 100644 --- a/barcode/codabar.py +++ b/barcode/codabar.py @@ -7,11 +7,16 @@ __docformat__ = "restructuredtext en" +from typing import TYPE_CHECKING + from barcode.base import Barcode from barcode.charsets import codabar from barcode.errors import BarcodeError from barcode.errors import IllegalCharacterError +if TYPE_CHECKING: + from barcode.writer import BaseWriter + class CODABAR(Barcode): """Initializes a new CODABAR instance. @@ -25,7 +30,13 @@ class CODABAR(Barcode): name = "Codabar (NW-7)" - def __init__(self, code, writer=None, narrow=2, wide=5) -> None: + def __init__( + self, + code: str, + writer: BaseWriter | None = None, + narrow: int = 2, + wide: int = 5, + ) -> None: self.code = code self.writer = writer or self.default_writer() self.narrow = narrow @@ -34,7 +45,7 @@ def __init__(self, code, writer=None, narrow=2, wide=5) -> None: def __str__(self) -> str: return self.code - def get_fullcode(self): + def get_fullcode(self) -> str: return self.code def build(self) -> list[str]: diff --git a/barcode/codex.py b/barcode/codex.py index 3837d15..fe82744 100644 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -18,6 +18,8 @@ if TYPE_CHECKING: from collections.abc import Collection + from PIL.Image import Image as T_Image + from barcode.writer import BaseWriter __docformat__ = "restructuredtext en" @@ -45,7 +47,12 @@ class Code39(Barcode): name = "Code 39" - def __init__(self, code: str, writer=None, add_checksum: bool = True) -> None: + def __init__( + self, + code: str, + writer: BaseWriter | None = None, + add_checksum: bool = True, + ) -> None: r""" :param code: Code 39 string without \* and without checksum. :param writer: A ``barcode.writer`` instance used to render the barcode @@ -83,7 +90,11 @@ def build(self) -> list[str]: result = code39.MIDDLE.join(chars) return [result] - def render(self, writer_options=None, text=None): + def render( + self, + writer_options: dict | None = None, + text: str | None = None, + ) -> bytes | T_Image: options = {"module_width": MIN_SIZE, "quiet_zone": MIN_QUIET_ZONE} options.update(writer_options or {}) return super().render(options, text) @@ -100,7 +111,7 @@ class PZN7(Code39): digits = 6 - def __init__(self, pzn, writer=None) -> None: + def __init__(self, pzn: str, writer: BaseWriter | None = None) -> None: pzn = pzn[: self.digits] if not pzn.isdigit(): raise IllegalCharacterError("PZN can only contain numbers.") @@ -115,7 +126,7 @@ def __init__(self, pzn, writer=None) -> None: def get_fullcode(self) -> str: return f"PZN-{self.pzn}" - def calculate_checksum(self): + def calculate_checksum(self) -> int: sum_ = sum(int(x) * int(y) for x, y in enumerate(self.pzn, start=2)) checksum = sum_ % 11 if checksum == 10: @@ -144,7 +155,7 @@ class Code128(Barcode): writer: BaseWriter buffer: str - def __init__(self, code: str, writer=None) -> None: + def __init__(self, code: str, writer: BaseWriter | None = None) -> None: self.code = code self.writer = writer or self.default_writer() self._charset = "C" @@ -174,7 +185,7 @@ def _new_charset(self, which: Literal["A", "B", "C"]) -> list[int]: return [code] # to be redefined in subclass if required - def _is_char_fnc1_char(self, char) -> bool: + def _is_char_fnc1_char(self, char: str) -> bool: """Whether a character is the FNC1 character. May be redefined by subclasses if required. FNC1 char is defined in GS1-128 @@ -307,7 +318,11 @@ def build(self) -> list[str]: code += "11" return [code] - def render(self, writer_options=None, text=None): + def render( + self, + writer_options: dict | None = None, + text: str | None = None, + ) -> bytes | T_Image: options = {"module_width": MIN_SIZE, "quiet_zone": MIN_QUIET_ZONE} options.update(writer_options or {}) return super().render(options, text) @@ -325,14 +340,14 @@ class Gs1_128(Code128): # noqa: N801 FNC1_CHAR = "\xf1" - def __init__(self, code, writer=None) -> None: + def __init__(self, code: str, writer: BaseWriter | None = None) -> None: code = self.FNC1_CHAR + code super().__init__(code, writer) - def get_fullcode(self): + def get_fullcode(self) -> str: return super().get_fullcode()[1:] - def _is_char_fnc1_char(self, char): + def _is_char_fnc1_char(self, char: str) -> bool: return char == self.FNC1_CHAR diff --git a/barcode/ean.py b/barcode/ean.py index e7dc5ef..85a4e4a 100644 --- a/barcode/ean.py +++ b/barcode/ean.py @@ -7,6 +7,7 @@ __docformat__ = "restructuredtext en" +from typing import TYPE_CHECKING from barcode.base import Barcode from barcode.charsets import ean as _ean @@ -14,6 +15,11 @@ from barcode.errors import NumberOfDigitsError from barcode.errors import WrongCountryCodeError +if TYPE_CHECKING: + from PIL.Image import Image as T_Image + + from barcode.writer import BaseWriter + # EAN13 Specs (all sizes in mm) SIZES = { "SC0": 0.27, @@ -44,7 +50,7 @@ class EuropeanArticleNumber13(Barcode): def __init__( self, ean: str, - writer=None, + writer: BaseWriter | None = None, no_checksum: bool = False, guardbar: bool = False, ) -> None: @@ -125,7 +131,11 @@ def to_ascii(self) -> str: code = code_list[0] return code.replace("G", "|").replace("1", "|").replace("0", " ") - def render(self, writer_options: dict | None = None, text: str | None = None): + def render( + self, + writer_options: dict | None = None, + text: str | None = None, + ) -> bytes | T_Image: options = {"module_width": SIZES["SC2"]} options.update(writer_options or {}) return super().render(options, text) @@ -136,7 +146,13 @@ class EuropeanArticleNumber13WithGuard(EuropeanArticleNumber13): name = "EAN-13 with guards" - def __init__(self, ean, writer=None, no_checksum=False, guardbar=True) -> None: + def __init__( + self, + ean: str, + writer: BaseWriter | None = None, + no_checksum: bool = False, + guardbar: bool = True, + ) -> None: super().__init__(ean, writer, no_checksum, guardbar) @@ -151,7 +167,7 @@ class JapanArticleNumber(EuropeanArticleNumber13): valid_country_codes = list(range(450, 460)) + list(range(490, 500)) - def __init__(self, jan, *args, **kwargs) -> None: + def __init__(self, jan: str, *args, **kwargs) -> None: if int(jan[:3]) not in self.valid_country_codes: raise WrongCountryCodeError( "Country code isn't between 450-460 or 490-500." @@ -184,7 +200,7 @@ def build(self) -> list[str]: code += self.EDGE return [code] - def get_fullcode(self): + def get_fullcode(self) -> str: if self.guardbar: return "< " + self.ean[:4] + " " + self.ean[4:] + " >" return self.ean @@ -198,7 +214,7 @@ class EuropeanArticleNumber8WithGuard(EuropeanArticleNumber8): def __init__( self, ean: str, - writer=None, + writer: BaseWriter | None = None, no_checksum: bool = False, guardbar: bool = True, ) -> None: diff --git a/barcode/errors.py b/barcode/errors.py index 4725187..7492161 100644 --- a/barcode/errors.py +++ b/barcode/errors.py @@ -6,7 +6,7 @@ class BarcodeError(Exception): - def __init__(self, msg) -> None: + def __init__(self, msg: str) -> None: self.msg = msg def __str__(self) -> str: diff --git a/barcode/isxn.py b/barcode/isxn.py index 710226f..9405519 100644 --- a/barcode/isxn.py +++ b/barcode/isxn.py @@ -24,10 +24,15 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from barcode.ean import EuropeanArticleNumber13 from barcode.errors import BarcodeError from barcode.errors import WrongCountryCodeError +if TYPE_CHECKING: + from barcode.writer import BaseWriter + __docformat__ = "restructuredtext en" @@ -40,7 +45,13 @@ class InternationalStandardBookNumber13(EuropeanArticleNumber13): name = "ISBN-13" - def __init__(self, isbn, writer=None, no_checksum=False, guardbar=False) -> None: + def __init__( + self, + isbn: str, + writer: BaseWriter | None = None, + no_checksum: bool = False, + guardbar: bool = False, + ) -> None: isbn = isbn.replace("-", "") self.isbn13 = isbn if isbn[:3] not in ("978", "979"): @@ -62,14 +73,14 @@ class InternationalStandardBookNumber10(InternationalStandardBookNumber13): isbn_digits = 9 - def __init__(self, isbn, writer=None) -> None: + def __init__(self, isbn: str, writer: BaseWriter | None = None) -> None: isbn = isbn.replace("-", "") isbn = isbn[: self.isbn_digits] super().__init__("978" + isbn, writer) self.isbn10 = isbn self.isbn10 = f"{isbn}{self._calculate_checksum()}" - def _calculate_checksum(self): + def _calculate_checksum(self) -> int | str: tmp = sum(x * int(y) for x, y in enumerate(self.isbn10[:9], start=1)) % 11 if tmp == 10: return "X" @@ -92,14 +103,14 @@ class InternationalStandardSerialNumber(EuropeanArticleNumber13): issn_digits = 7 - def __init__(self, issn, writer=None) -> None: + def __init__(self, issn: str, writer: BaseWriter | None = None) -> None: issn = issn.replace("-", "") issn = issn[: self.issn_digits] self.issn = issn self.issn = f"{issn}{self._calculate_checksum()}" super().__init__(self.make_ean(), writer) - def _calculate_checksum(self): + def _calculate_checksum(self) -> int | str: tmp = ( 11 - sum(x * int(y) for x, y in enumerate(reversed(self.issn[:7]), start=2)) diff --git a/barcode/itf.py b/barcode/itf.py index 6445d86..0bb0a0a 100644 --- a/barcode/itf.py +++ b/barcode/itf.py @@ -7,10 +7,17 @@ __docformat__ = "restructuredtext en" +from typing import TYPE_CHECKING + from barcode.base import Barcode from barcode.charsets import itf from barcode.errors import IllegalCharacterError +if TYPE_CHECKING: + from PIL.Image import Image as T_Image + + from barcode.writer import BaseWriter + MIN_SIZE = 0.2 MIN_QUIET_ZONE = 6.4 @@ -27,7 +34,13 @@ class ITF(Barcode): name = "ITF" - def __init__(self, code, writer=None, narrow=2, wide=5) -> None: + def __init__( + self, + code: str, + writer: BaseWriter | None = None, + narrow: int = 2, + wide: int = 5, + ) -> None: if not code.isdigit(): raise IllegalCharacterError("ITF code can only contain numbers.") # Length must be even, prepend 0 if necessary @@ -41,7 +54,7 @@ def __init__(self, code, writer=None, narrow=2, wide=5) -> None: def __str__(self) -> str: return self.code - def get_fullcode(self): + def get_fullcode(self) -> str: return self.code def build(self) -> list[str]: @@ -65,7 +78,11 @@ def build(self) -> list[str]: raw += "0" * self.narrow return [raw] - def render(self, writer_options, text=None): + def render( + self, + writer_options: dict | None = None, + text: str | None = None, + ) -> bytes | T_Image: options = { "module_width": MIN_SIZE / self.narrow, "quiet_zone": MIN_QUIET_ZONE, diff --git a/barcode/pybarcode.py b/barcode/pybarcode.py index 35d69b0..7b233d2 100644 --- a/barcode/pybarcode.py +++ b/barcode/pybarcode.py @@ -2,6 +2,7 @@ import os from argparse import ArgumentParser +from argparse import Namespace import barcode from barcode.version import version @@ -12,7 +13,7 @@ IMG_FORMATS = ("BMP", "GIF", "JPEG", "MSP", "PCX", "PNG", "TIFF", "XBM") -def list_types(args, parser=None) -> None: +def list_types(args: Namespace, parser: ArgumentParser | None = None) -> None: print("\npython-barcode available barcode formats:") print(", ".join(barcode.PROVIDED_BARCODES)) print("\n") @@ -25,7 +26,7 @@ def list_types(args, parser=None) -> None: print("\n") -def create_barcode(args, parser) -> None: +def create_barcode(args: Namespace, parser: ArgumentParser) -> None: args.type = args.type.upper() if args.type != "SVG" and args.type not in IMG_FORMATS: parser.error(f"Unknown type {args.type}. Try list action for available types.") diff --git a/barcode/upc.py b/barcode/upc.py index 060f19f..42938d5 100644 --- a/barcode/upc.py +++ b/barcode/upc.py @@ -8,12 +8,18 @@ __docformat__ = "restructuredtext en" from functools import reduce +from typing import TYPE_CHECKING from barcode.base import Barcode from barcode.charsets import upc as _upc from barcode.errors import IllegalCharacterError from barcode.errors import NumberOfDigitsError +if TYPE_CHECKING: + from PIL.Image import Image as T_Image + + from barcode.writer import BaseWriter + class UniversalProductCodeA(Barcode): """Universal Product Code (UPC) barcode. @@ -25,7 +31,12 @@ class UniversalProductCodeA(Barcode): digits = 11 - def __init__(self, upc, writer=None, make_ean=False) -> None: + def __init__( + self, + upc: str, + writer: BaseWriter | None = None, + make_ean: bool = False, + ) -> None: """Initializes new UPC-A barcode. :param str upc: The upc number as string. @@ -53,20 +64,20 @@ def __str__(self) -> str: return self.upc - def get_fullcode(self): + def get_fullcode(self) -> str: if self.ean: return "0" + self.upc return self.upc - def calculate_checksum(self): + def calculate_checksum(self) -> int: """Calculates the checksum for UPCA/UPC codes :return: The checksum for 'self.upc' :rtype: int """ - def sum_(x, y): + def sum_(x: str, y: str) -> int: return int(x) + int(y) upc = self.upc[0 : self.digits] @@ -110,7 +121,11 @@ def to_ascii(self) -> str: code = code_list[0] return code.replace("1", "|").replace("0", "_") - def render(self, writer_options=None, text=None): + def render( + self, + writer_options: dict | None = None, + text: str | None = None, + ) -> bytes | T_Image: options = {"module_width": 0.33} options.update(writer_options or {}) return super().render(options, text) diff --git a/barcode/writer.py b/barcode/writer.py index 75bbfcb..75822a9 100644 --- a/barcode/writer.py +++ b/barcode/writer.py @@ -5,12 +5,12 @@ import xml.dom.minidom from typing import TYPE_CHECKING from typing import BinaryIO -from typing import Callable from typing import TypedDict from barcode.version import version if TYPE_CHECKING: + from collections.abc import Callable from collections.abc import Generator from typing import Literal @@ -164,7 +164,7 @@ def calculate_size(self, modules_per_line: int, number_of_lines: int) -> tuple: height += self.text_line_distance * (number_of_text_lines - 1) return width, height - def save(self, filename: str, output) -> str: + def save(self, filename: str, output: bytes | T_Image) -> str: """Saves the rendered output to `filename`. :param filename: Filename without extension. @@ -222,7 +222,7 @@ def packed(self, line: str) -> Generator[tuple[int, float], str, None]: yield (-c, self.guard_height_factor) c = 1 - def render(self, code: list[str]): + def render(self, code: list[str]) -> bytes | T_Image: """Renders the barcode to whatever the inheriting writer provides, using the registered callbacks. @@ -304,7 +304,7 @@ def render(self, code: list[str]): return self._callbacks["finish"]() - def write(self, content, fp: BinaryIO) -> None: + def write(self, content: bytes | T_Image, fp: BinaryIO) -> None: raise NotImplementedError @@ -353,7 +353,13 @@ def _init(self, code: list[str]) -> None: _set_attributes(background, **attributes) self._group.appendChild(background) - def _create_module(self, xpos, ypos, width, color) -> None: + def _create_module( + self, + xpos: float, + ypos: float, + width: float, + color: str | int, + ) -> None: # Background rect has been provided already, so skipping "spaces" if color != self.background: element = self._document.createElement("rect") @@ -367,7 +373,7 @@ def _create_module(self, xpos, ypos, width, color) -> None: _set_attributes(element, **attributes) self._group.appendChild(element) - def _create_text(self, xpos, ypos) -> None: + def _create_text(self, xpos: float, ypos: float) -> None: # check option to override self.text with self.human (barcode as # human readable data, can be used to print own formats) barcodetext = self.human if self.human != "" else self.text @@ -395,7 +401,7 @@ def _finish(self) -> bytes: indent=4 * " ", newl=os.linesep, encoding="UTF-8" ) - def save(self, filename: str, output) -> str: + def save(self, filename: str, output: bytes) -> str: if self.compress: _filename = f"{filename}.svgz" with gzip.open(_filename, "wb") as f: @@ -407,7 +413,7 @@ def save(self, filename: str, output) -> str: f.write(output) return _filename - def write(self, content, fp: BinaryIO) -> None: + def write(self, content: bytes, fp: BinaryIO) -> None: """Write `content` into a file-like object. Content should be a barcode rendered by this writer. @@ -460,7 +466,13 @@ def _init(self, code: list[str]) -> None: self._image = Image.new(self.mode, size, self.background) self._draw = ImageDraw.Draw(self._image) - def _paint_module(self, xpos: float, ypos: float, width: float, color) -> None: + def _paint_module( + self, + xpos: float, + ypos: float, + width: float, + color: str | int, + ) -> None: size = [ (mm2px(xpos, self.dpi), mm2px(ypos, self.dpi)), ( @@ -470,7 +482,7 @@ def _paint_module(self, xpos: float, ypos: float, width: float, color) -> None: ] self._draw.rectangle(size, outline=color, fill=color) - def _paint_text(self, xpos, ypos) -> None: + def _paint_text(self, xpos: float, ypos: float) -> None: assert ImageFont is not None # check option to override self.text with self.human (barcode as @@ -494,12 +506,12 @@ def _paint_text(self, xpos, ypos) -> None: def _finish(self) -> T_Image: return self._image - def save(self, filename: str, output) -> str: + def save(self, filename: str, output: T_Image) -> str: filename = f"{filename}.{self.format.lower()}" output.save(filename, self.format.upper()) return filename - def write(self, content, fp: BinaryIO) -> None: + def write(self, content: T_Image, fp: BinaryIO) -> None: """Write `content` into a file-like object. Content should be a barcode rendered by this writer. diff --git a/pyproject.toml b/pyproject.toml index fc5d541..13cc895 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ version_scheme = "post-release" [tool.ruff.lint] extend-select = [ + "ANN", "E", "W", "I", @@ -78,6 +79,10 @@ extend-select = [ "PLE", "RUF", ] +ignore = [ + "ANN002", # Annotations for *args + "ANN003", # Annotations for **kwargs +] [tool.ruff.lint.isort] force-single-line = true diff --git a/tests/test_gs1_128.py b/tests/test_gs1_128.py index 2fbda92..aa05d57 100644 --- a/tests/test_gs1_128.py +++ b/tests/test_gs1_128.py @@ -205,6 +205,6 @@ @pytest.mark.parametrize(("target", "answer"), CODE_BUILD_TEST) -def test_code_build(target, answer) -> None: +def test_code_build(target: str, answer: list[int]) -> None: gs1_128 = Gs1_128(target) assert gs1_128._build() == answer diff --git a/tests/test_manually.py b/tests/test_manually.py index 06e9c84..89143fc 100644 --- a/tests/test_manually.py +++ b/tests/test_manually.py @@ -64,10 +64,10 @@ def test_generating_barcodes( image_elements = gather_image_elements_into_html - def append(x, y) -> None: + def append(x: str, y: str) -> None: image_elements.append(OBJECTS.format(filename=x, name=y)) - def append_img(x, y) -> None: + def append_img(x: str, y: str) -> None: image_elements.append(IMAGES.format(filename=x, name=y)) options = {} From 8566b3c1df56416fbf2b6fd92f00bb39223c0c44 Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Fri, 9 Oct 2026 23:20:00 +0200 Subject: [PATCH 5/5] Use explicit strict= for zip() --- barcode/charsets/code39.py | 2 +- barcode/writer.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/barcode/charsets/code39.py b/barcode/charsets/code39.py index dcd80e7..6e37c9a 100644 --- a/barcode/charsets/code39.py +++ b/barcode/charsets/code39.py @@ -60,4 +60,4 @@ MIDDLE = "0" # MAP for assigning every symbol (REF) to (reference number, barcode) -MAP = dict(zip(REF, enumerate(CODES))) +MAP = dict(zip(REF, enumerate(CODES), strict=True)) diff --git a/barcode/writer.py b/barcode/writer.py index 75822a9..ca8a02d 100644 --- a/barcode/writer.py +++ b/barcode/writer.py @@ -288,7 +288,8 @@ def render(self, code: list[str]) -> bytes | T_Image: # Calculates the position of the text by getting the difference # between a guard end and the next start text["start"].pop(0) - for s, e in zip(text["start"], text["end"]): + # Dropping the first start leaves the lists deliberately uneven. + for s, e in zip(text["start"], text["end"], strict=False): text["xpos"].append(e + (s - e) / 2) # The last text block is always put after the last guard end @@ -298,7 +299,7 @@ def render(self, code: list[str]) -> bytes | T_Image: # Split the ean into its blocks blocks = self.text.split(" ") - for text_, xpos in zip(blocks, text["xpos"]): + for text_, xpos in zip(blocks, text["xpos"], strict=True): self.text = text_ self._callbacks["paint_text"](xpos, ypos)