diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fff3aa9..1dad804 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,7 +40,7 @@ jobs: source actions-ci/install.sh - name: Pip install pylint, black, & Sphinx run: | - pip install --force-reinstall pylint==1.9.2 black==19.10b0 Sphinx sphinx-rtd-theme + pip install --force-reinstall pylint black==19.10b0 Sphinx sphinx-rtd-theme - name: Library version run: git describe --dirty --always --tags - name: PyLint diff --git a/adafruit_miniqr.py b/adafruit_miniqr.py index 939bdcd..79e0b9c 100644 --- a/adafruit_miniqr.py +++ b/adafruit_miniqr.py @@ -72,12 +72,14 @@ # Optimized polynomial helpers + def _glog(n): """Lookup log(n) from pre-calculated byte table""" if n < 1: raise ValueError("glog(" + n + ")") return LOG_TABLE[n] + def _gexp(n): """Lookup exp(n) from pre-calculated byte table""" while n < 0: @@ -86,21 +88,24 @@ def _gexp(n): n -= 255 return EXP_TABLE[n] -#pylint: disable=line-too-long -EXP_TABLE = b'\x01\x02\x04\x08\x10 @\x80\x1d:t\xe8\xcd\x87\x13&L\x98-Z\xb4u\xea\xc9\x8f\x03\x06\x0c\x180`\xc0\x9d\'N\x9c%J\x945j\xd4\xb5w\xee\xc1\x9f#F\x8c\x05\n\x14(P\xa0]\xbai\xd2\xb9o\xde\xa1_\xbea\xc2\x99/^\xbce\xca\x89\x0f\x1e|\xf8\xed\xc7\x93;v\xec\xc5\x973f\xcc\x85\x17.\\\xb8m\xda\xa9O\x9e!B\x84\x15*T\xa8M\x9a)R\xa4U\xaaI\x929r\xe4\xd5\xb7s\xe6\xd1\xbfc\xc6\x91?~\xfc\xe5\xd7\xb3{\xf6\xf1\xff\xe3\xdb\xabK\x961b\xc4\x957n\xdc\xa5W\xaeA\x82\x192d\xc8\x8d\x07\x0e\x1c8p\xe0\xdd\xa7S\xa6Q\xa2Y\xb2y\xf2\xf9\xef\xc3\x9b+V\xacE\x8a\t\x12$H\x90=z\xf4\xf5\xf7\xf3\xfb\xeb\xcb\x8b\x0b\x16,X\xb0}\xfa\xe9\xcf\x83\x1b6l\xd8\xadG\x8e\x01' -LOG_TABLE = b'\x00\x00\x01\x19\x022\x1a\xc6\x03\xdf3\xee\x1bh\xc7K\x04d\xe0\x0e4\x8d\xef\x81\x1c\xc1i\xf8\xc8\x08Lq\x05\x8ae/\xe1$\x0f!5\x93\x8e\xda\xf0\x12\x82E\x1d\xb5\xc2}j\'\xf9\xb9\xc9\x9a\txM\xe4r\xa6\x06\xbf\x8bbf\xdd0\xfd\xe2\x98%\xb3\x10\x91"\x886\xd0\x94\xce\x8f\x96\xdb\xbd\xf1\xd2\x13\\\x838F@\x1eB\xb6\xa3\xc3H~nk:(T\xfa\x85\xba=\xca^\x9b\x9f\n\x15y+N\xd4\xe5\xacs\xf3\xa7W\x07p\xc0\xf7\x8c\x80c\rgJ\xde\xed1\xc5\xfe\x18\xe3\xa5\x99w&\xb8\xb4|\x11D\x92\xd9# \x89.7?\xd1[\x95\xbc\xcf\xcd\x90\x87\x97\xb2\xdc\xfc\xbea\xf2V\xd3\xab\x14*]\x9e\x84<9SGmA\xa2\x1f-C\xd8\xb7{\xa4v\xc4\x17I\xec\x7f\x0co\xf6l\xa1;R)\x9dU\xaa\xfb`\x86\xb1\xbb\xcc>Z\xcbY_\xb0\x9c\xa9\xa0Q\x0b\xf5\x16\xebzu,\xd7O\xae\xd5\xe9\xe6\xe7\xad\xe8t\xd6\xf4\xea\xa8PX\xaf' -#pylint: enable=line-too-long +# pylint: disable=line-too-long +EXP_TABLE = b"\x01\x02\x04\x08\x10 @\x80\x1d:t\xe8\xcd\x87\x13&L\x98-Z\xb4u\xea\xc9\x8f\x03\x06\x0c\x180`\xc0\x9d'N\x9c%J\x945j\xd4\xb5w\xee\xc1\x9f#F\x8c\x05\n\x14(P\xa0]\xbai\xd2\xb9o\xde\xa1_\xbea\xc2\x99/^\xbce\xca\x89\x0f\x1e|\xf8\xed\xc7\x93;v\xec\xc5\x973f\xcc\x85\x17.\\\xb8m\xda\xa9O\x9e!B\x84\x15*T\xa8M\x9a)R\xa4U\xaaI\x929r\xe4\xd5\xb7s\xe6\xd1\xbfc\xc6\x91?~\xfc\xe5\xd7\xb3{\xf6\xf1\xff\xe3\xdb\xabK\x961b\xc4\x957n\xdc\xa5W\xaeA\x82\x192d\xc8\x8d\x07\x0e\x1c8p\xe0\xdd\xa7S\xa6Q\xa2Y\xb2y\xf2\xf9\xef\xc3\x9b+V\xacE\x8a\t\x12$H\x90=z\xf4\xf5\xf7\xf3\xfb\xeb\xcb\x8b\x0b\x16,X\xb0}\xfa\xe9\xcf\x83\x1b6l\xd8\xadG\x8e\x01" + +LOG_TABLE = b"\x00\x00\x01\x19\x022\x1a\xc6\x03\xdf3\xee\x1bh\xc7K\x04d\xe0\x0e4\x8d\xef\x81\x1c\xc1i\xf8\xc8\x08Lq\x05\x8ae/\xe1$\x0f!5\x93\x8e\xda\xf0\x12\x82E\x1d\xb5\xc2}j'\xf9\xb9\xc9\x9a\txM\xe4r\xa6\x06\xbf\x8bbf\xdd0\xfd\xe2\x98%\xb3\x10\x91\"\x886\xd0\x94\xce\x8f\x96\xdb\xbd\xf1\xd2\x13\\\x838F@\x1eB\xb6\xa3\xc3H~nk:(T\xfa\x85\xba=\xca^\x9b\x9f\n\x15y+N\xd4\xe5\xacs\xf3\xa7W\x07p\xc0\xf7\x8c\x80c\rgJ\xde\xed1\xc5\xfe\x18\xe3\xa5\x99w&\xb8\xb4|\x11D\x92\xd9# \x89.7?\xd1[\x95\xbc\xcf\xcd\x90\x87\x97\xb2\xdc\xfc\xbea\xf2V\xd3\xab\x14*]\x9e\x84<9SGmA\xa2\x1f-C\xd8\xb7{\xa4v\xc4\x17I\xec\x7f\x0co\xf6l\xa1;R)\x9dU\xaa\xfb`\x86\xb1\xbb\xcc>Z\xcbY_\xb0\x9c\xa9\xa0Q\x0b\xf5\x16\xebzu,\xd7O\xae\xd5\xe9\xe6\xe7\xad\xe8t\xd6\xf4\xea\xa8PX\xaf" +# pylint: enable=line-too-long + class QRCode: """The generator class for QR code matrices""" + def __init__(self, *, qr_type=None, error_correct=L): """Initialize an empty QR code. You can define the `qr_type` (size) of the code matrix, or have the libary auto-select the smallest match. Default `error_correct` is type L (7%), but you can select M, Q or H.""" self.type = qr_type - self.ECC = error_correct #pylint: disable=invalid-name + self.ECC = error_correct # pylint: disable=invalid-name self.matrix = None self.module_count = 0 self.data_cache = None @@ -115,7 +120,7 @@ def add_data(self, data): rs_blocks = _get_rs_blocks(qr_type, self.ECC) total_data_count = 0 for block in rs_blocks: - total_data_count += block['data'] + total_data_count += block["data"] if total_data_count > datalen: self.type = qr_type break @@ -146,26 +151,29 @@ def make(self, *, test=False, mask_pattern=0): def _setup_position_probe_pattern(self, row, col): """Add the positition probe data pixels to the matrix""" for r in range(-1, 8): - if (row + r <= -1 or self.module_count <= row + r): + if row + r <= -1 or self.module_count <= row + r: continue - for c in range(-1, 8): #pylint: disable=invalid-name - if (col + c <= -1 or self.module_count <= col + c): + for c in range(-1, 8): # pylint: disable=invalid-name + if col + c <= -1 or self.module_count <= col + c: continue - test = ((r >= 0 and r <= 6 and (c == 0 or c == 6)) - or (c >= 0 and c <= 6 and (r == 0 or r == 6)) - or (r >= 2 and r <= 4 and c >= 2 and c <= 4)) - self.matrix[row+r, col+c] = test + test = ( + (0 <= r <= 6 and (c in (0, 6))) + or (0 <= c <= 6 and (r in (0, 6))) + or (2 <= r <= 4 and 2 <= c <= 4) + ) + self.matrix[row + r, col + c] = test + def _setup_timing_pattern(self): """Add the timing data pixels to the matrix""" - for r in range(8, self.module_count-8): - if (self.matrix[r, 6] != None): + for r in range(8, self.module_count - 8): + if self.matrix[r, 6] is not None: continue - self.matrix[r, 6] = (r % 2 == 0) + self.matrix[r, 6] = r % 2 == 0 - for c in range(8, self.module_count-8): #pylint: disable=invalid-name - if (self.matrix[6, c] != None): + for c in range(8, self.module_count - 8): # pylint: disable=invalid-name + if self.matrix[6, c] is not None: continue - self.matrix[6, c] = (c % 2 == 0) + self.matrix[6, c] = c % 2 == 0 def _setup_position_adjust_pattern(self): """Add the position adjust data pixels to the matrix""" @@ -173,14 +181,13 @@ def _setup_position_adjust_pattern(self): for row in pos: for col in pos: - if (self.matrix[row, col] != None): + if self.matrix[row, col] is not None: continue for r in range(-2, 3): - for c in range(-2, 3): #pylint: disable=invalid-name - test = (abs(r) == 2 or abs(c) == 2 or - (r == 0 and c == 0)) - self.matrix[row+r, col+c] = test + for c in range(-2, 3): # pylint: disable=invalid-name + test = abs(r) == 2 or abs(c) == 2 or (r == 0 and c == 0) + self.matrix[row + r, col + c] = test def _setup_type_number(self, test): """Add the type number pixels to the matrix""" @@ -199,7 +206,7 @@ def _setup_type_info(self, test, mask_pattern): data = (self.ECC << 3) | mask_pattern bits = QRUtil.get_BCH_type_info(data) - #// vertical + # // vertical for i in range(15): mod = not test and ((bits >> i) & 1) == 1 if i < 6: @@ -209,7 +216,7 @@ def _setup_type_info(self, test, mask_pattern): else: self.matrix[self.module_count - 15 + i, 8] = mod - #// horizontal + # // horizontal for i in range(15): mod = not test and ((bits >> i) & 1) == 1 if i < 8: @@ -219,8 +226,8 @@ def _setup_type_info(self, test, mask_pattern): else: self.matrix[8, 15 - i - 1] = mod - #// fixed module - self.matrix[self.module_count - 8, 8] = (not test) + # // fixed module + self.matrix[self.module_count - 8, 8] = not test def _map_data(self, data, mask_pattern): """Map the data onto the QR code""" @@ -234,7 +241,7 @@ def _map_data(self, data, mask_pattern): col -= 1 while True: - for c in range(2): #pylint: disable=invalid-name + for c in range(2): # pylint: disable=invalid-name if self.matrix[row, col - c] is None: dark = False if byte_idx < len(data): @@ -242,7 +249,7 @@ def _map_data(self, data, mask_pattern): mask = QRUtil.get_mask(mask_pattern, row, col - c) if mask: dark = not dark - self.matrix[row, col-c] = dark + self.matrix[row, col - c] = dark bit_idx -= 1 if bit_idx == -1: byte_idx += 1 @@ -266,35 +273,37 @@ def _create_data(qr_type, ecc, data_list): for byte in data: buffer.put(byte, 8) - #// calc num max data. + # // calc num max data. total_data_count = 0 for block in rs_blocks: - total_data_count += block['data'] + total_data_count += block["data"] if buffer.get_length_bits() > total_data_count * 8: - raise RuntimeError("Code length overflow: %d > %d" % - (buffer.get_length_bits(), total_data_count*8)) + raise RuntimeError( + "Code length overflow: %d > %d" + % (buffer.get_length_bits(), total_data_count * 8) + ) - #// end code + # // end code if buffer.get_length_bits() + 4 <= total_data_count * 8: buffer.put(0, 4) - #// padding + # // padding while buffer.get_length_bits() % 8 != 0: buffer.put_bit(False) - #// padding + # // padding while True: - if buffer.get_length_bits() >= total_data_count*8: + if buffer.get_length_bits() >= total_data_count * 8: break buffer.put(_PAD0, 8) - if buffer.get_length_bits() >= total_data_count*8: + if buffer.get_length_bits() >= total_data_count * 8: break buffer.put(_PAD1, 8) return QRCode._create_bytes(buffer, rs_blocks) - #pylint: disable=too-many-locals,too-many-branches + # pylint: disable=too-many-locals,too-many-branches @staticmethod def _create_bytes(buffer, rs_blocks): """Perform error calculation math on bit buffer""" @@ -307,8 +316,8 @@ def _create_bytes(buffer, rs_blocks): for r, block in enumerate(rs_blocks): - dc_count = block['data'] - ec_count = block['total'] - dc_count + dc_count = block["data"] + ec_count = block["total"] - dc_count max_dc_count = max(max_dc_count, dc_count) max_ec_count = max(max_ec_count, ec_count) @@ -316,7 +325,7 @@ def _create_bytes(buffer, rs_blocks): dcdata[r] = [0] * dc_count for i in range(len(dcdata[r])): - dcdata[r][i] = 0xff & buffer.buffer[i + offset] + dcdata[r][i] = 0xFF & buffer.buffer[i + offset] offset += dc_count rs_poly = QRUtil.get_error_correct_polynomial(ec_count) @@ -333,7 +342,7 @@ def _create_bytes(buffer, rs_blocks): num[i] ^= _gexp(_glog(rs_poly.get(i)) + ratio) mod_poly = QRPolynomial(num, 0) - ecdata[r] = [0 for x in range(rs_poly.get_length()-1)] + ecdata[r] = [0 for x in range(rs_poly.get_length() - 1)] for i in range(len(ecdata[r])): mod_index = i + mod_poly.get_length() - len(ecdata[r]) if mod_index >= 0: @@ -343,7 +352,7 @@ def _create_bytes(buffer, rs_blocks): total_code_count = 0 for block in rs_blocks: - total_code_count += block['total'] + total_code_count += block["total"] data = [None] * total_code_count index = 0 @@ -361,33 +370,52 @@ def _create_bytes(buffer, rs_blocks): index += 1 return data -#pylint: enable=too-many-locals,too-many-branches -class QRUtil(object): + +# pylint: enable=too-many-locals,too-many-branches + + +class QRUtil: """A selection of bit manipulation tools for QR generation and BCH encoding""" - PATTERN_POSITION_TABLE = [b'', b'\x06\x12', b'\x06\x16', b'\x06\x1a', - b'\x06\x1e', b'\x06"', b'\x06\x16&', - b'\x06\x18*', b'\x06\x1a.', b'\x06\x1c2'] + + PATTERN_POSITION_TABLE = [ + b"", + b"\x06\x12", + b"\x06\x16", + b"\x06\x1a", + b"\x06\x1e", + b'\x06"', + b"\x06\x16&", + b"\x06\x18*", + b"\x06\x1a.", + b"\x06\x1c2", + ] G15 = 0b10100110111 G18 = 0b1111100100101 G15_MASK = 0b101010000010010 -#pylint: disable=invalid-name + # pylint: disable=invalid-name @staticmethod def get_BCH_type_info(data): """Encode with G15 BCH mask""" d = data << 10 while QRUtil.get_BCH_digit(d) - QRUtil.get_BCH_digit(QRUtil.G15) >= 0: - d ^= QRUtil.G15 << (QRUtil.get_BCH_digit(d) - QRUtil.get_BCH_digit(QRUtil.G15)) + d ^= QRUtil.G15 << ( + QRUtil.get_BCH_digit(d) - QRUtil.get_BCH_digit(QRUtil.G15) + ) return ((data << 10) | d) ^ QRUtil.G15_MASK + @staticmethod def get_BCH_type_number(data): """Encode with G18 BCH mask""" d = data << 12 while QRUtil.get_BCH_digit(d) - QRUtil.get_BCH_digit(QRUtil.G18) >= 0: - d ^= QRUtil.G18 << (QRUtil.get_BCH_digit(d) - QRUtil.get_BCH_digit(QRUtil.G18)) + d ^= QRUtil.G18 << ( + QRUtil.get_BCH_digit(d) - QRUtil.get_BCH_digit(QRUtil.G18) + ) return (data << 12) | d + @staticmethod def get_BCH_digit(data): """Count digits in data""" @@ -396,25 +424,36 @@ def get_BCH_digit(data): digit += 1 data >>= 1 return digit -#pylint: enable=invalid-name + + # pylint: enable=invalid-name @staticmethod def get_pattern_position(qr_type): """The mask pattern position array for this QR type""" return QRUtil.PATTERN_POSITION_TABLE[qr_type - 1] + @staticmethod def get_mask(mask, i, j): """Perform matching calculation on two vals for given pattern mask""" - #pylint: disable=multiple-statements, too-many-return-statements - if mask == 0: return (i + j) % 2 == 0 - if mask == 1: return i % 2 == 0 - if mask == 2: return j % 3 == 0 - if mask == 3: return (i + j) % 3 == 0 - if mask == 4: return (math.floor(i / 2) + math.floor(j / 3)) % 2 == 0 - if mask == 5: return (i * j) % 2 + (i * j) % 3 == 0 - if mask == 6: return ((i * j) % 2 + (i * j) % 3) % 2 == 0 - if mask == 7: return ((i * j) % 3 + (i + j) % 2) % 2 == 0 + # pylint: disable=multiple-statements, too-many-return-statements + if mask == 0: + return (i + j) % 2 == 0 + if mask == 1: + return i % 2 == 0 + if mask == 2: + return j % 3 == 0 + if mask == 3: + return (i + j) % 3 == 0 + if mask == 4: + return (math.floor(i / 2) + math.floor(j / 3)) % 2 == 0 + if mask == 5: + return (i * j) % 2 + (i * j) % 3 == 0 + if mask == 6: + return ((i * j) % 2 + (i * j) % 3) % 2 == 0 + if mask == 7: + return ((i * j) % 3 + (i + j) % 2) % 2 == 0 raise ValueError("Bad mask pattern:" + mask) - #pylint: enable=multiple-statements, too-many-return-statements + # pylint: enable=multiple-statements, too-many-return-statements + @staticmethod def get_error_correct_polynomial(ecc_length): """ Generate a ecc polynomial""" @@ -423,8 +462,10 @@ def get_error_correct_polynomial(ecc_length): poly = poly.multiply(QRPolynomial([1, _gexp(i)], 0)) return poly + class QRPolynomial: """Structure for creating and manipulating error code polynomials""" + def __init__(self, num, shift): """Create a QR polynomial""" if not num: @@ -432,17 +473,19 @@ def __init__(self, num, shift): offset = 0 while offset < len(num) and num[offset] == 0: offset += 1 - self.num = [0 for x in range(len(num)-offset+shift)] + self.num = [0 for x in range(len(num) - offset + shift)] for i in range(len(num) - offset): self.num[i] = num[i + offset] def get(self, index): """The exponent at the index location""" return self.num[index] + def get_length(self): """Length of the poly""" return len(self.num) - def multiply(self, e): #pylint: disable=invalid-name + + def multiply(self, e): # pylint: disable=invalid-name """Multiply two polynomials, returns a new one""" num = [0 for x in range(self.get_length() + e.get_length() - 1)] @@ -452,7 +495,46 @@ def multiply(self, e): #pylint: disable=invalid-name return QRPolynomial(num, 0) -_QRRS_BLOCK_TABLE = (b'\x01\x1a\x10', b'\x01\x1a\x13', b'\x01\x1a\t', b'\x01\x1a\r', b'\x01,\x1c', b'\x01,"', b'\x01,\x10', b'\x01,\x16', b'\x01F,', b'\x01F7', b'\x02#\r', b'\x02#\x11', b'\x022 ', b'\x01dP', b'\x04\x19\t', b'\x022\x18', b'\x02C+', b'\x01\x86l', b'\x02!\x0b\x02"\x0c', b'\x02!\x0f\x02"\x10', b'\x04+\x1b', b'\x02VD', b'\x04+\x0f', b'\x04+\x13', b'\x041\x1f', b'\x02bN', b"\x04'\r\x01(\x0e", b'\x02 \x0e\x04!\x0f', b"\x02<&\x02='", b'\x02ya', b'\x04(\x0e\x02)\x0f', b'\x04(\x12\x02)\x13', b'\x03:$\x02;%', b'\x02\x92t', b'\x04$\x0c\x04%\r', b'\x04$\x10\x04%\x11') #pylint: disable=line-too-long + +_QRRS_BLOCK_TABLE = ( + b"\x01\x1a\x10", + b"\x01\x1a\x13", + b"\x01\x1a\t", + b"\x01\x1a\r", + b"\x01,\x1c", + b'\x01,"', + b"\x01,\x10", + b"\x01,\x16", + b"\x01F,", + b"\x01F7", + b"\x02#\r", + b"\x02#\x11", + b"\x022 ", + b"\x01dP", + b"\x04\x19\t", + b"\x022\x18", + b"\x02C+", + b"\x01\x86l", + b'\x02!\x0b\x02"\x0c', + b'\x02!\x0f\x02"\x10', + b"\x04+\x1b", + b"\x02VD", + b"\x04+\x0f", + b"\x04+\x13", + b"\x041\x1f", + b"\x02bN", + b"\x04'\r\x01(\x0e", + b"\x02 \x0e\x04!\x0f", + b"\x02<&\x02='", + b"\x02ya", + b"\x04(\x0e\x02)\x0f", + b"\x04(\x12\x02)\x13", + b"\x03:$\x02;%", + b"\x02\x92t", + b"\x04$\x0c\x04%\r", + b"\x04$\x10\x04%\x11", +) # pylint: disable=line-too-long + def _get_rs_blocks(qr_type, ecc): rs_block = _QRRS_BLOCK_TABLE[(qr_type - 1) * 4 + ecc] @@ -463,13 +545,15 @@ def _get_rs_blocks(qr_type, ecc): count = rs_block[i * 3 + 0] total = rs_block[i * 3 + 1] data = rs_block[i * 3 + 2] - block = {'total' : total, 'data' : data} + block = {"total": total, "data": data} for _ in range(count): blocks.append(block) return blocks + class QRBitMatrix: """A bit-packed storage class for matrices""" + def __init__(self, width, height): self.width = width self.height = height @@ -483,17 +567,17 @@ def __repr__(self): for y in range(self.height): for x in range(self.width): if self[x, y]: - b += 'X' + b += "X" else: - b += '.' - b += '\n' + b += "." + b += "\n" return b def __getitem__(self, key): x, y = key if y > self.width: raise ValueError() - i = 2*x + (y // 30) + i = 2 * x + (y // 30) j = y % 30 if not self.used[i] & (1 << j): return None @@ -503,16 +587,18 @@ def __setitem__(self, key, value): x, y = key if y > self.width: raise ValueError() - i = 2*x + (y // 30) + i = 2 * x + (y // 30) j = y % 30 if value: self.buffer[i] |= 1 << j else: self.buffer[i] &= ~(1 << j) - self.used[i] |= 1 << j # buffer item was set + self.used[i] |= 1 << j # buffer item was set + class QRBitBuffer: """Storage class for a length of individual bits""" + def __init__(self): self.buffer = [] self.length = 0 @@ -540,5 +626,5 @@ def put_bit(self, bit): if len(self.buffer) <= i: self.buffer.append(0) if bit: - self.buffer[i] |= (0x80 >> (self.length % 8)) + self.buffer[i] |= 0x80 >> (self.length % 8) self.length += 1 diff --git a/docs/conf.py b/docs/conf.py index 3e2a475..77360ae 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,7 +2,8 @@ import os import sys -sys.path.insert(0, os.path.abspath('..')) + +sys.path.insert(0, os.path.abspath("..")) # -- General configuration ------------------------------------------------ @@ -10,10 +11,10 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.intersphinx', - 'sphinx.ext.napoleon', - 'sphinx.ext.todo', + "sphinx.ext.autodoc", + "sphinx.ext.intersphinx", + "sphinx.ext.napoleon", + "sphinx.ext.todo", ] # TODO: Please Read! @@ -23,29 +24,32 @@ # autodoc_mock_imports = ["digitalio", "busio"] -intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)} +intersphinx_mapping = { + "python": ("https://docs.python.org/3.4", None), + "CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None), +} # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'Adafruit miniQR Library' -copyright = u'2018 ladyada' -author = u'ladyada' +project = u"Adafruit miniQR Library" +copyright = u"2018 ladyada" +author = u"ladyada" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u'1.0' +version = u"1.0" # The full version, including alpha/beta/rc tags. -release = u'1.0' +release = u"1.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -57,7 +61,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '.env', 'CODE_OF_CONDUCT.md'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", ".env", "CODE_OF_CONDUCT.md"] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -69,7 +73,7 @@ add_function_parentheses = True # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False @@ -84,59 +88,62 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +on_rtd = os.environ.get("READTHEDOCS", None) == "True" if not on_rtd: # only import and set the theme if we're building docs locally try: import sphinx_rtd_theme - html_theme = 'sphinx_rtd_theme' - html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), '.'] + + html_theme = "sphinx_rtd_theme" + html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] except: - html_theme = 'default' - html_theme_path = ['.'] + html_theme = "default" + html_theme_path = ["."] else: - html_theme_path = ['.'] + html_theme_path = ["."] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # The name of an image file (relative to this directory) to use as a favicon of # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # -html_favicon = '_static/favicon.ico' +html_favicon = "_static/favicon.ico" # Output file base name for HTML help builder. -htmlhelp_basename = 'AdafruitMiniqrLibrarydoc' +htmlhelp_basename = "AdafruitMiniqrLibrarydoc" # -- Options for LaTeX output --------------------------------------------- latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'AdafruitminiQRLibrary.tex', u'AdafruitminiQR Library Documentation', - author, 'manual'), + ( + master_doc, + "AdafruitminiQRLibrary.tex", + u"AdafruitminiQR Library Documentation", + author, + "manual", + ), ] # -- Options for manual page output --------------------------------------- @@ -144,8 +151,13 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'AdafruitminiQRlibrary', u'Adafruit miniQR Library Documentation', - [author], 1) + ( + master_doc, + "AdafruitminiQRlibrary", + u"Adafruit miniQR Library Documentation", + [author], + 1, + ) ] # -- Options for Texinfo output ------------------------------------------- @@ -154,7 +166,13 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'AdafruitminiQRLibrary', u'Adafruit miniQR Library Documentation', - author, 'AdafruitminiQRLibrary', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "AdafruitminiQRLibrary", + u"Adafruit miniQR Library Documentation", + author, + "AdafruitminiQRLibrary", + "One line description of project.", + "Miscellaneous", + ), ] diff --git a/examples/miniqr_displaytest.py b/examples/miniqr_displaytest.py index 2083d68..3942edd 100644 --- a/examples/miniqr_displaytest.py +++ b/examples/miniqr_displaytest.py @@ -2,24 +2,27 @@ import displayio import adafruit_miniqr + def bitmap_QR(matrix): # monochome (2 color) palette - BORDER_PIXELS = 2 + BORDER_PIXELS = 2 # bitmap the size of the screen, monochrome (2 colors) - bitmap = displayio.Bitmap(matrix.width+2*BORDER_PIXELS, - matrix.height+2*BORDER_PIXELS, 2) + bitmap = displayio.Bitmap( + matrix.width + 2 * BORDER_PIXELS, matrix.height + 2 * BORDER_PIXELS, 2 + ) # raster the QR code - for y in range(matrix.height): # each scanline in the height + for y in range(matrix.height): # each scanline in the height for x in range(matrix.width): if matrix[x, y]: - bitmap[x+BORDER_PIXELS, y+BORDER_PIXELS] = 1 + bitmap[x + BORDER_PIXELS, y + BORDER_PIXELS] = 1 else: - bitmap[x+BORDER_PIXELS, y+BORDER_PIXELS] = 0 + bitmap[x + BORDER_PIXELS, y + BORDER_PIXELS] = 0 return bitmap + qr = adafruit_miniqr.QRCode(qr_type=3, error_correct=adafruit_miniqr.L) -qr.add_data(b'https://www.adafruit.com/circuitpython') +qr.add_data(b"https://www.adafruit.com/circuitpython") qr.make() # generate the 1-pixel-per-bit bitmap @@ -29,10 +32,12 @@ def bitmap_QR(matrix): palette[0] = 0xFFFFFF palette[1] = 0x000000 # we'll scale the QR code as big as the display can handle -scale = min(board.DISPLAY.width//qr_bitmap.width, board.DISPLAY.height//qr_bitmap.height) +scale = min( + board.DISPLAY.width // qr_bitmap.width, board.DISPLAY.height // qr_bitmap.height +) # then center it! -pos_x = int (((board.DISPLAY.width/scale) - qr_bitmap.width) / 2) -pos_y = int (((board.DISPLAY.height/scale) - qr_bitmap.height) / 2) +pos_x = int(((board.DISPLAY.width / scale) - qr_bitmap.width) / 2) +pos_y = int(((board.DISPLAY.height / scale) - qr_bitmap.height) / 2) qr_img = displayio.TileGrid(qr_bitmap, pixel_shader=palette, x=pos_x, y=pos_y) splash = displayio.Group(scale=scale) diff --git a/examples/miniqr_simpletest.py b/examples/miniqr_simpletest.py index 4f63640..b69020c 100644 --- a/examples/miniqr_simpletest.py +++ b/examples/miniqr_simpletest.py @@ -6,29 +6,31 @@ WHITE = "\x1b[1;47m \x1b[40m" BLACK = " " + def prettyprint_QR(matrix): # white 4-pixel border at top for _ in range(4): - for _ in range(matrix.width+8): + for _ in range(matrix.width + 8): out.write(WHITE) print() for y in range(matrix.height): - out.write(WHITE*4) # 4-pixel border to left + out.write(WHITE * 4) # 4-pixel border to left for x in range(matrix.width): if matrix[x, y]: out.write(BLACK) else: out.write(WHITE) - out.write(WHITE*4) # 4-pixel bporder to right + out.write(WHITE * 4) # 4-pixel bporder to right print() # white 4-pixel border at bottom for _ in range(4): - for _ in range(matrix.width+8): + for _ in range(matrix.width + 8): out.write(WHITE) print() + qr = adafruit_miniqr.QRCode(qr_type=3, error_correct=adafruit_miniqr.L) -qr.add_data(b'https://www.adafruit.com') +qr.add_data(b"https://www.adafruit.com") qr.make() print(qr.matrix) prettyprint_QR(qr.matrix) diff --git a/setup.py b/setup.py index eff738b..dbd0ece 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,7 @@ # Always prefer setuptools over distutils from setuptools import setup, find_packages + # To use a consistent encoding from codecs import open from os import path @@ -14,47 +15,38 @@ here = path.abspath(path.dirname(__file__)) # Get the long description from the README file -with open(path.join(here, 'README.rst'), encoding='utf-8') as f: +with open(path.join(here, "README.rst"), encoding="utf-8") as f: long_description = f.read() setup( - name='adafruit-circuitpython-miniqr', - + name="adafruit-circuitpython-miniqr", use_scm_version=True, - setup_requires=['setuptools_scm'], - - description='A non-hardware dependant miniature QR generator library. All native Python!', + setup_requires=["setuptools_scm"], + description="A non-hardware dependant miniature QR generator library. All native Python!", long_description=long_description, - long_description_content_type='text/x-rst', - + long_description_content_type="text/x-rst", # The project's main homepage. - url='https://github.com/adafruit/Adafruit_CircuitPython_miniQR', - + url="https://github.com/adafruit/Adafruit_CircuitPython_miniQR", # Author details - author='Adafruit Industries', - author_email='circuitpython@adafruit.com', - + author="Adafruit Industries", + author_email="circuitpython@adafruit.com", install_requires=[], - # Choose your license - license='MIT', - + license="MIT", # See https://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=[ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'Topic :: Software Development :: Libraries', - 'Topic :: System :: Hardware', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries", + "Topic :: System :: Hardware", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", ], - # What does your project relate to? - keywords='adafruit software miniqr qr generator python micropython circuitpython', - + keywords="adafruit software miniqr qr generator python micropython circuitpython", # You can just specify the packages manually here if your project is # simple. Or you can use find_packages(). - py_modules=['adafruit_miniqr'], -) \ No newline at end of file + py_modules=["adafruit_miniqr"], +)