Added type annotations to nearly all local variables in Python library code.

pull/118/head
Project Nayuki 3 years ago
parent 3c3aec6b9c
commit 0ff7b57a81

@ -88,7 +88,7 @@ class QrCode:
Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible
QR Code version is automatically chosen for the output. The ECC level of the result may be higher than the QR Code version is automatically chosen for the output. The ECC level of the result may be higher than the
ecl argument if it can be done without increasing the version.""" ecl argument if it can be done without increasing the version."""
segs = QrSegment.make_segments(text) segs: List[QrSegment] = QrSegment.make_segments(text)
return QrCode.encode_segments(segs, ecl) return QrCode.encode_segments(segs, ecl)
@ -120,12 +120,12 @@ class QrCode:
# Find the minimal version number to use # Find the minimal version number to use
for version in range(minversion, maxversion + 1): for version in range(minversion, maxversion + 1):
datacapacitybits = QrCode._get_num_data_codewords(version, ecl) * 8 # Number of data bits available datacapacitybits: int = QrCode._get_num_data_codewords(version, ecl) * 8 # Number of data bits available
datausedbits = QrSegment.get_total_bits(segs, version) datausedbits: Optional[int] = QrSegment.get_total_bits(segs, version)
if datausedbits is not None and datausedbits <= datacapacitybits: if datausedbits is not None and datausedbits <= datacapacitybits:
break # This version number is found to be suitable break # This version number is found to be suitable
if version >= maxversion: # All versions in the range could not fit the given data if version >= maxversion: # All versions in the range could not fit the given data
msg = "Segment too long" msg: str = "Segment too long"
if datausedbits is not None: if datausedbits is not None:
msg = "Data length = {} bits, Max capacity = {} bits".format(datausedbits, datacapacitybits) msg = "Data length = {} bits, Max capacity = {} bits".format(datausedbits, datacapacitybits)
raise DataTooLongError(msg) raise DataTooLongError(msg)
@ -219,12 +219,12 @@ class QrCode:
# Compute ECC, draw modules # Compute ECC, draw modules
self._draw_function_patterns() self._draw_function_patterns()
allcodewords = self._add_ecc_and_interleave(bytearray(datacodewords)) allcodewords: bytes = self._add_ecc_and_interleave(bytearray(datacodewords))
self._draw_codewords(allcodewords) self._draw_codewords(allcodewords)
# Do masking # Do masking
if mask == -1: # Automatically choose best mask if mask == -1: # Automatically choose best mask
minpenalty = 1 << 32 minpenalty: int = 1 << 32
for i in range(8): for i in range(8):
self._apply_mask(i) self._apply_mask(i)
self._draw_format_bits(i) self._draw_format_bits(i)
@ -273,7 +273,7 @@ class QrCode:
of border modules. The string always uses Unix newlines (\n), regardless of the platform.""" of border modules. The string always uses Unix newlines (\n), regardless of the platform."""
if border < 0: if border < 0:
raise ValueError("Border must be non-negative") raise ValueError("Border must be non-negative")
parts = [] parts: List[str] = []
for y in range(self._size): for y in range(self._size):
for x in range(self._size): for x in range(self._size):
if self.get_module(x, y): if self.get_module(x, y):
@ -302,9 +302,9 @@ class QrCode:
self._draw_finder_pattern(3, self._size - 4) self._draw_finder_pattern(3, self._size - 4)
# Draw numerous alignment patterns # Draw numerous alignment patterns
alignpatpos = self._get_alignment_pattern_positions() alignpatpos: List[int] = self._get_alignment_pattern_positions()
numalign = len(alignpatpos) numalign: int = len(alignpatpos)
skips = ((0, 0), (0, numalign - 1), (numalign - 1, 0)) skips: Sequence[Tuple[int,int]] = ((0, 0), (0, numalign - 1), (numalign - 1, 0))
for i in range(numalign): for i in range(numalign):
for j in range(numalign): for j in range(numalign):
if (i, j) not in skips: # Don't draw on the three finder corners if (i, j) not in skips: # Don't draw on the three finder corners
@ -319,11 +319,11 @@ class QrCode:
"""Draws two copies of the format bits (with its own error correction code) """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.""" based on the given mask and this object's error correction level field."""
# Calculate error correction code and pack bits # Calculate error correction code and pack bits
data = self._errcorlvl.formatbits << 3 | mask # errCorrLvl is uint2, mask is uint3 data: int = self._errcorlvl.formatbits << 3 | mask # errCorrLvl is uint2, mask is uint3
rem = data rem: int = data
for _ in range(10): for _ in range(10):
rem = (rem << 1) ^ ((rem >> 9) * 0x537) rem = (rem << 1) ^ ((rem >> 9) * 0x537)
bits = (data << 10 | rem) ^ 0x5412 # uint15 bits: int = (data << 10 | rem) ^ 0x5412 # uint15
assert bits >> 15 == 0 assert bits >> 15 == 0
# Draw first copy # Draw first copy
@ -350,17 +350,17 @@ class QrCode:
return return
# Calculate error correction code and pack bits # Calculate error correction code and pack bits
rem = self._version # version is uint6, in the range [7, 40] rem: int = self._version # version is uint6, in the range [7, 40]
for _ in range(12): for _ in range(12):
rem = (rem << 1) ^ ((rem >> 11) * 0x1F25) rem = (rem << 1) ^ ((rem >> 11) * 0x1F25)
bits = self._version << 12 | rem # uint18 bits: int = self._version << 12 | rem # uint18
assert bits >> 18 == 0 assert bits >> 18 == 0
# Draw two copies # Draw two copies
for i in range(18): for i in range(18):
bit = _get_bit(bits, i) bit: bool = _get_bit(bits, i)
a = self._size - 11 + i % 3 a: int = self._size - 11 + i % 3
b = i // 3 b: int = i // 3
self._set_function_module(a, b, bit) self._set_function_module(a, b, bit)
self._set_function_module(b, a, bit) self._set_function_module(b, a, bit)
@ -397,24 +397,24 @@ class QrCode:
def _add_ecc_and_interleave(self, data: bytearray) -> bytes: def _add_ecc_and_interleave(self, data: bytearray) -> bytes:
"""Returns a new byte string representing the given data with the appropriate error correction """Returns a new byte string representing the given data with the appropriate error correction
codewords appended to it, based on this object's version and error correction level.""" codewords appended to it, based on this object's version and error correction level."""
version = self._version version: int = self._version
assert len(data) == QrCode._get_num_data_codewords(version, self._errcorlvl) assert len(data) == QrCode._get_num_data_codewords(version, self._errcorlvl)
# Calculate parameter numbers # Calculate parameter numbers
numblocks = QrCode._NUM_ERROR_CORRECTION_BLOCKS[self._errcorlvl.ordinal][version] numblocks: int = QrCode._NUM_ERROR_CORRECTION_BLOCKS[self._errcorlvl.ordinal][version]
blockecclen = QrCode._ECC_CODEWORDS_PER_BLOCK [self._errcorlvl.ordinal][version] blockecclen: int = QrCode._ECC_CODEWORDS_PER_BLOCK [self._errcorlvl.ordinal][version]
rawcodewords = QrCode._get_num_raw_data_modules(version) // 8 rawcodewords: int = QrCode._get_num_raw_data_modules(version) // 8
numshortblocks = numblocks - rawcodewords % numblocks numshortblocks: int = numblocks - rawcodewords % numblocks
shortblocklen = rawcodewords // numblocks shortblocklen: int = rawcodewords // numblocks
# Split data into blocks and append ECC to each block # Split data into blocks and append ECC to each block
blocks = [] blocks: List[bytes] = []
rsdiv = QrCode._reed_solomon_compute_divisor(blockecclen) rsdiv: bytes = QrCode._reed_solomon_compute_divisor(blockecclen)
k = 0 k: int = 0
for i in range(numblocks): for i in range(numblocks):
dat = data[k : k + shortblocklen - blockecclen + (0 if i < numshortblocks else 1)] dat: bytearray = data[k : k + shortblocklen - blockecclen + (0 if i < numshortblocks else 1)]
k += len(dat) k += len(dat)
ecc = QrCode._reed_solomon_compute_remainder(dat, rsdiv) ecc: bytes = QrCode._reed_solomon_compute_remainder(dat, rsdiv)
if i < numshortblocks: if i < numshortblocks:
dat.append(0) dat.append(0)
blocks.append(dat + ecc) blocks.append(dat + ecc)
@ -436,16 +436,16 @@ class QrCode:
data area of this QR Code. Function modules need to be marked off before this is called.""" data area of this QR Code. Function modules need to be marked off before this is called."""
assert len(data) == QrCode._get_num_raw_data_modules(self._version) // 8 assert len(data) == QrCode._get_num_raw_data_modules(self._version) // 8
i = 0 # Bit index into the data i: int = 0 # Bit index into the data
# Do the funny zigzag scan # Do the funny zigzag scan
for right in range(self._size - 1, 0, -2): # Index of right column in each column pair for right in range(self._size - 1, 0, -2): # Index of right column in each column pair
if right <= 6: if right <= 6:
right -= 1 right -= 1
for vert in range(self._size): # Vertical counter for vert in range(self._size): # Vertical counter
for j in range(2): for j in range(2):
x = right - j # Actual x coordinate x: int = right - j # Actual x coordinate
upward = (right + 1) & 2 == 0 upward: bool = (right + 1) & 2 == 0
y = (self._size - 1 - vert) if upward else vert # Actual y coordinate y: int = (self._size - 1 - vert) if upward else vert # Actual y coordinate
if not self._isfunction[y][x] and i < len(data) * 8: if not self._isfunction[y][x] and i < len(data) * 8:
self._modules[y][x] = _get_bit(data[i >> 3], 7 - (i & 7)) self._modules[y][x] = _get_bit(data[i >> 3], 7 - (i & 7))
i += 1 i += 1
@ -462,7 +462,7 @@ class QrCode:
QR Code needs exactly one (not zero, two, etc.) mask applied.""" QR Code needs exactly one (not zero, two, etc.) mask applied."""
if not (0 <= mask <= 7): if not (0 <= mask <= 7):
raise ValueError("Mask value out of range") raise ValueError("Mask value out of range")
masker = QrCode._MASK_PATTERNS[mask] masker: Callable[[int,int],int] = QrCode._MASK_PATTERNS[mask]
for y in range(self._size): for y in range(self._size):
for x in range(self._size): for x in range(self._size):
self._modules[y][x] ^= (masker(x, y) == 0) and (not self._isfunction[y][x]) self._modules[y][x] ^= (masker(x, y) == 0) and (not self._isfunction[y][x])
@ -471,14 +471,14 @@ class QrCode:
def _get_penalty_score(self) -> int: def _get_penalty_score(self) -> int:
"""Calculates and returns the penalty score based on state of this QR Code's current modules. """Calculates and returns the penalty score based on state of this QR Code's current modules.
This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.""" This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score."""
result = 0 result: int = 0
size = self._size size: int = self._size
modules = self._modules modules: List[List[bool]] = self._modules
# Adjacent modules in row having same color, and finder-like patterns # Adjacent modules in row having same color, and finder-like patterns
for y in range(size): for y in range(size):
runcolor = False runcolor: bool = False
runx = 0 runx: int = 0
runhistory = collections.deque([0] * 7, 7) runhistory = collections.deque([0] * 7, 7)
for x in range(size): for x in range(size):
if modules[y][x] == runcolor: if modules[y][x] == runcolor:
@ -521,10 +521,10 @@ class QrCode:
result += QrCode._PENALTY_N2 result += QrCode._PENALTY_N2
# Balance of black and white modules # Balance of black and white modules
black = sum((1 if cell else 0) for row in modules for cell in row) black: int = sum((1 if cell else 0) for row in modules for cell in row)
total = size**2 # Note that size is odd, so black/total != 1/2 total: int = size**2 # Note that size is odd, so black/total != 1/2
# Compute the smallest integer k >= 0 such that (45-5k)% <= black/total <= (55+5k)% # Compute the smallest integer k >= 0 such that (45-5k)% <= black/total <= (55+5k)%
k = (abs(black * 20 - total * 10) + total - 1) // total - 1 k: int = (abs(black * 20 - total * 10) + total - 1) // total - 1
result += k * QrCode._PENALTY_N4 result += k * QrCode._PENALTY_N4
return result return result
@ -535,14 +535,14 @@ class QrCode:
"""Returns an ascending list of positions of alignment patterns for this version number. """Returns an ascending list of positions of alignment patterns for this version number.
Each position is in the range [0,177), and are used on both the x and y axes. Each position is in the range [0,177), and are used on both the x and y axes.
This could be implemented as lookup table of 40 variable-length lists of integers.""" This could be implemented as lookup table of 40 variable-length lists of integers."""
ver = self._version ver: int = self._version
if ver == 1: if ver == 1:
return [] return []
else: else:
numalign = ver // 7 + 2 numalign: int = ver // 7 + 2
step = 26 if (ver == 32) else \ step: int = 26 if (ver == 32) else \
(ver*4 + numalign*2 + 1) // (numalign*2 - 2) * 2 (ver*4 + numalign*2 + 1) // (numalign*2 - 2) * 2
result = [(self._size - 7 - i * step) for i in range(numalign - 1)] + [6] result: List[int] = [(self._size - 7 - i * step) for i in range(numalign - 1)] + [6]
return list(reversed(result)) return list(reversed(result))
@ -553,9 +553,9 @@ class QrCode:
The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.""" The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table."""
if not (QrCode.MIN_VERSION <= ver <= QrCode.MAX_VERSION): if not (QrCode.MIN_VERSION <= ver <= QrCode.MAX_VERSION):
raise ValueError("Version number out of range") raise ValueError("Version number out of range")
result = (16 * ver + 128) * ver + 64 result: int = (16 * ver + 128) * ver + 64
if ver >= 2: if ver >= 2:
numalign = ver // 7 + 2 numalign: int = ver // 7 + 2
result -= (25 * numalign - 10) * numalign - 55 result -= (25 * numalign - 10) * numalign - 55
if ver >= 7: if ver >= 7:
result -= 36 result -= 36
@ -586,7 +586,7 @@ class QrCode:
# Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), # Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
# and drop the highest monomial term which is always 1x^degree. # and drop the highest monomial term which is always 1x^degree.
# Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). # Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
root = 1 root: int = 1
for _ in range(degree): # Unused variable i for _ in range(degree): # Unused variable i
# Multiply the current product by (x - r^i) # Multiply the current product by (x - r^i)
for j in range(degree): for j in range(degree):
@ -602,7 +602,7 @@ class QrCode:
"""Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.""" """Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials."""
result = bytearray([0] * len(divisor)) result = bytearray([0] * len(divisor))
for b in data: # Polynomial division for b in data: # Polynomial division
factor = b ^ result.pop(0) factor: int = b ^ result.pop(0)
result.append(0) result.append(0)
for (i, coef) in enumerate(divisor): for (i, coef) in enumerate(divisor):
result[i] ^= QrCode._reed_solomon_multiply(coef, factor) result[i] ^= QrCode._reed_solomon_multiply(coef, factor)
@ -616,7 +616,7 @@ class QrCode:
if x >> 8 != 0 or y >> 8 != 0: if x >> 8 != 0 or y >> 8 != 0:
raise ValueError("Byte out of range") raise ValueError("Byte out of range")
# Russian peasant multiplication # Russian peasant multiplication
z = 0 z: int = 0
for i in reversed(range(8)): for i in reversed(range(8)):
z = (z << 1) ^ ((z >> 7) * 0x11D) z = (z << 1) ^ ((z >> 7) * 0x11D)
z ^= ((y >> i) & 1) * x z ^= ((y >> i) & 1) * x
@ -627,9 +627,9 @@ class QrCode:
def _finder_penalty_count_patterns(self, runhistory: collections.deque) -> int: def _finder_penalty_count_patterns(self, runhistory: collections.deque) -> int:
"""Can only be called immediately after a white run is added, and """Can only be called immediately after a white run is added, and
returns either 0, 1, or 2. A helper function for _get_penalty_score().""" returns either 0, 1, or 2. A helper function for _get_penalty_score()."""
n = runhistory[1] n: int = runhistory[1]
assert n <= self._size * 3 assert n <= self._size * 3
core = n > 0 and (runhistory[2] == runhistory[4] == runhistory[5] == n) and runhistory[3] == n * 3 core: bool = n > 0 and (runhistory[2] == runhistory[4] == runhistory[5] == n) and runhistory[3] == n * 3
return (1 if (core and runhistory[0] >= n * 4 and runhistory[6] >= n) else 0) \ return (1 if (core and runhistory[0] >= n * 4 and runhistory[6] >= n) else 0) \
+ (1 if (core and runhistory[6] >= n * 4 and runhistory[0] >= n) else 0) + (1 if (core and runhistory[6] >= n * 4 and runhistory[0] >= n) else 0)
@ -747,9 +747,9 @@ class QrSegment:
if QrSegment.NUMERIC_REGEX.fullmatch(digits) is None: if QrSegment.NUMERIC_REGEX.fullmatch(digits) is None:
raise ValueError("String contains non-numeric characters") raise ValueError("String contains non-numeric characters")
bb = _BitBuffer() bb = _BitBuffer()
i = 0 i: int = 0
while i < len(digits): # Consume up to 3 digits per iteration while i < len(digits): # Consume up to 3 digits per iteration
n = min(len(digits) - i, 3) n: int = min(len(digits) - i, 3)
bb.append_bits(int(digits[i : i + n]), n * 3 + 1) bb.append_bits(int(digits[i : i + n]), n * 3 + 1)
i += n i += n
return QrSegment(QrSegment.Mode.NUMERIC, len(digits), bb) return QrSegment(QrSegment.Mode.NUMERIC, len(digits), bb)
@ -764,7 +764,7 @@ class QrSegment:
raise ValueError("String contains unencodable characters in alphanumeric mode") raise ValueError("String contains unencodable characters in alphanumeric mode")
bb = _BitBuffer() bb = _BitBuffer()
for i in range(0, len(text) - 1, 2): # Process groups of 2 for i in range(0, len(text) - 1, 2): # Process groups of 2
temp = QrSegment._ALPHANUMERIC_ENCODING_TABLE[text[i]] * 45 temp: int = QrSegment._ALPHANUMERIC_ENCODING_TABLE[text[i]] * 45
temp += QrSegment._ALPHANUMERIC_ENCODING_TABLE[text[i + 1]] temp += QrSegment._ALPHANUMERIC_ENCODING_TABLE[text[i + 1]]
bb.append_bits(temp, 11) bb.append_bits(temp, 11)
if len(text) % 2 > 0: # 1 character remaining if len(text) % 2 > 0: # 1 character remaining
@ -863,7 +863,7 @@ class QrSegment:
returns None if a segment has too many characters to fit its length field.""" returns None if a segment has too many characters to fit its length field."""
result = 0 result = 0
for seg in segs: for seg in segs:
ccbits = seg.get_mode().num_char_count_bits(version) ccbits: int = seg.get_mode().num_char_count_bits(version)
if seg.get_num_chars() >= (1 << ccbits): if seg.get_num_chars() >= (1 << ccbits):
return None # The segment's length doesn't fit the field's bit width return None # The segment's length doesn't fit the field's bit width
result += 4 + ccbits + len(seg._bitdata) result += 4 + ccbits + len(seg._bitdata)

Loading…
Cancel
Save