diff --git a/python/qrcodegen.py b/python/qrcodegen.py index d4ac1eb..529cb3b 100644 --- a/python/qrcodegen.py +++ b/python/qrcodegen.py @@ -23,7 +23,8 @@ from __future__ import annotations import collections, itertools, re -from typing import List, Optional, Tuple +from collections.abc import Sequence +from typing import Callable, Dict, List, Optional, Tuple """ @@ -260,7 +261,7 @@ class QrCode: """Returns this QR Code's mask, in the range [0, 7].""" return self._mask - def get_module(self, x, y) -> bool: + def get_module(self, x: int, y: int) -> bool: """Returns the color of the module (pixel) at the given coordinates, which is False for white or True for black. The top left corner has the coordinates (x=0, y=0). If the given coordinates are out of bounds, then False (white) is returned.""" @@ -316,7 +317,7 @@ class QrCode: self._draw_version() - def _draw_format_bits(self, mask) -> None: + def _draw_format_bits(self, mask: int) -> None: """Draws two copies of the format bits (with its own error correction code) based on the given mask and this object's error correction level field.""" # Calculate error correction code and pack bits @@ -366,7 +367,7 @@ class QrCode: self._set_function_module(b, a, bit) - def _draw_finder_pattern(self, x, y) -> None: + def _draw_finder_pattern(self, x: int, y: int) -> None: """Draws a 9*9 finder pattern including the border separator, with the center module at (x, y). Modules can be out of bounds.""" for dy in range(-4, 5): @@ -377,7 +378,7 @@ class QrCode: self._set_function_module(xx, yy, max(abs(dx), abs(dy)) not in (2, 4)) - def _draw_alignment_pattern(self, x, y) -> None: + def _draw_alignment_pattern(self, x: int, y: int) -> None: """Draws a 5*5 alignment pattern, with the center module at (x, y). All modules must be in bounds.""" for dy in range(-2, 3): @@ -548,7 +549,7 @@ class QrCode: @staticmethod - def _get_num_raw_data_modules(ver) -> int: + def _get_num_raw_data_modules(ver: int) -> int: """Returns the number of data bits that can be stored in a QR Code of the given version number, after all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.""" @@ -565,7 +566,7 @@ class QrCode: @staticmethod - def _get_num_data_codewords(ver, ecl: QrCode.Ecc) -> int: + def _get_num_data_codewords(ver: int, ecl: QrCode.Ecc) -> int: """Returns the number of 8-bit data (i.e. not error correction) codewords contained in any QR Code of the given version number and error correction level, with remainder bits discarded. This stateless pure function could be implemented as a (40*4)-cell lookup table.""" @@ -653,16 +654,16 @@ class QrCode: # ---- Constants and tables ---- - MIN_VERSION = 1 # The minimum version number supported in the QR Code Model 2 standard - MAX_VERSION = 40 # The maximum version number supported in the QR Code Model 2 standard + MIN_VERSION: int = 1 # The minimum version number supported in the QR Code Model 2 standard + MAX_VERSION: int = 40 # The maximum version number supported in the QR Code Model 2 standard # For use in _get_penalty_score(), when evaluating which mask is best. - _PENALTY_N1 = 3 - _PENALTY_N2 = 3 - _PENALTY_N3 = 40 - _PENALTY_N4 = 10 + _PENALTY_N1: int = 3 + _PENALTY_N2: int = 3 + _PENALTY_N3: int = 40 + _PENALTY_N4: int = 10 - _ECC_CODEWORDS_PER_BLOCK = ( + _ECC_CODEWORDS_PER_BLOCK: Sequence[Sequence[int]] = ( # Version: (note that index 0 is for padding, and is set to an illegal value) # 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level (-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30), # Low @@ -670,7 +671,7 @@ class QrCode: (-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30), # Quartile (-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30)) # High - _NUM_ERROR_CORRECTION_BLOCKS = ( + _NUM_ERROR_CORRECTION_BLOCKS: Sequence[Sequence[int]] = ( # Version: (note that index 0 is for padding, and is set to an illegal value) # 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level (-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25), # Low @@ -678,7 +679,7 @@ class QrCode: (-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68), # Quartile (-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81)) # High - _MASK_PATTERNS = ( + _MASK_PATTERNS: Sequence[Callable[[int,int],int]] = ( (lambda x, y: (x + y) % 2 ), (lambda x, y: y % 2 ), (lambda x, y: x % 3 ), @@ -878,17 +879,16 @@ class QrSegment: # (Public) Describes precisely all strings that are encodable in numeric mode. # To test whether a string s is encodable: ok = NUMERIC_REGEX.fullmatch(s) is not None # A string is encodable iff each character is in the range 0 to 9. - NUMERIC_REGEX = re.compile(r"[0-9]*") + NUMERIC_REGEX: re.Pattern = re.compile(r"[0-9]*") # (Public) Describes precisely all strings that are encodable in alphanumeric mode. # To test whether a string s is encodable: ok = ALPHANUMERIC_REGEX.fullmatch(s) is not None # A string is encodable iff each character is in the following set: 0 to 9, A to Z # (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. - - ALPHANUMERIC_REGEX = re.compile(r"[A-Z0-9 $%*+./:-]*") + ALPHANUMERIC_REGEX: re.Pattern = re.compile(r"[A-Z0-9 $%*+./:-]*") # (Private) Dictionary of "0"->0, "A"->10, "$"->37, etc. - _ALPHANUMERIC_ENCODING_TABLE = {ch: i for (i, ch) in enumerate("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:")} + _ALPHANUMERIC_ENCODING_TABLE: Dict[str,int] = {ch: i for (i, ch) in enumerate("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:")} # ---- Public helper enumeration ----