Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
with pytest.raises(ValueError):
encoder.normalize_errorlevel('g')
def test_normalize_errorlevel_illegal2():
with pytest.raises(ValueError) as ex:
encoder.normalize_errorlevel(None)
assert 'error' in str(ex.value)
_test_find_version_test_data = (
# data, error, micro, expected version
('12345', None, True, consts.VERSION_M1),
('12345', consts.ERROR_LEVEL_L, True, consts.VERSION_M2),
# Error level Q isn't suppoted by M1 - M3
('12345', consts.ERROR_LEVEL_Q, True, consts.VERSION_M4),
# Error level H isn't supported by Micro QR Codes
('12345', consts.ERROR_LEVEL_H, None, 1),
('12345', None, False, 1),
(12345, None, True, consts.VERSION_M1),
(-12345, None, True, consts.VERSION_M2), # Negative number
(-12345, consts.ERROR_LEVEL_M, True, consts.VERSION_M3), # Negative number
(12345, None, False, 1),
('123456', None, True, consts.VERSION_M2),
('123456', None, False, 1),
(123456, None, True, consts.VERSION_M2),
(123456, None, False, 1),
('ABCDE', None, True, consts.VERSION_M2), # Alphanumeric isn't supported by M1
('ABCDEF', consts.ERROR_LEVEL_L, True, consts.VERSION_M2),
('ABCDEF', consts.ERROR_LEVEL_M, True, consts.VERSION_M3), # Too much data for error level M and version M2
('ABCDEF', consts.ERROR_LEVEL_L, False, 1),
('ABCDEF', consts.ERROR_LEVEL_L, False, 1),
('12345', consts.ERROR_LEVEL_L, True, consts.VERSION_M2),
# Error level Q isn't suppoted by M1 - M3
('12345', consts.ERROR_LEVEL_Q, True, consts.VERSION_M4),
# Error level H isn't supported by Micro QR Codes
('12345', consts.ERROR_LEVEL_H, None, 1),
('12345', None, False, 1),
(12345, None, True, consts.VERSION_M1),
(-12345, None, True, consts.VERSION_M2), # Negative number
(-12345, consts.ERROR_LEVEL_M, True, consts.VERSION_M3), # Negative number
(12345, None, False, 1),
('123456', None, True, consts.VERSION_M2),
('123456', None, False, 1),
(123456, None, True, consts.VERSION_M2),
(123456, None, False, 1),
('ABCDE', None, True, consts.VERSION_M2), # Alphanumeric isn't supported by M1
('ABCDEF', consts.ERROR_LEVEL_L, True, consts.VERSION_M2),
('ABCDEF', consts.ERROR_LEVEL_M, True, consts.VERSION_M3), # Too much data for error level M and version M2
('ABCDEF', consts.ERROR_LEVEL_L, False, 1),
('ABCDEF', consts.ERROR_LEVEL_L, False, 1),
('Märchenbuch', None, True, consts.VERSION_M4),
('Märchenbücher', None, False, 1),
('Märchenbücherei', None, None, consts.VERSION_M4),
('Märchenbücherei', consts.ERROR_LEVEL_M, None, 2),
)
@pytest.mark.parametrize('data, error, micro, expected_version', _test_find_version_test_data)
def test_find_version(data, error, micro, expected_version):
segments = encoder.prepare_data(data, None, None)
assert expected_version == encoder.find_version(segments, error, eci=False, micro=micro)
('M3', 15),
('M4', 17),
(1, 21),
(27, 125),
(40, 177)])
def test_get_matrix_size(version, expected):
try:
v = consts.MICRO_VERSION_MAPPING[version]
except KeyError:
v = version
assert expected == encoder.calc_matrix_size(v)
# See ISO/IEC 18004:2006(E) - Table 2 (page 22)
_test_is_mode_supported_micro_data = (
(consts.MODE_NUMERIC, 'M1', True),
(consts.MODE_NUMERIC, 'M2', True),
(consts.MODE_NUMERIC, 'M3', True),
(consts.MODE_NUMERIC, 'M4', True),
(consts.MODE_ALPHANUMERIC, 'M1', False),
(consts.MODE_ALPHANUMERIC, 'M2', True),
(consts.MODE_ALPHANUMERIC, 'M3', True),
(consts.MODE_ALPHANUMERIC, 'M4', True),
(consts.MODE_ECI, 'M1', False),
(consts.MODE_ECI, 'M2', False),
(consts.MODE_ECI, 'M3', False),
(consts.MODE_ECI, 'M4', False),
(consts.MODE_BYTE, 'M1', False),
(consts.MODE_BYTE, 'M2', False),
(consts.MODE_BYTE, 'M3', True),
(consts.MODE_BYTE, 'M4', True),
(consts.MODE_KANJI, 'M3', True),
def boost_error_level(version, error, segments, eci, is_sa=False):
"""\
Increases the error correction level if possible.
Returns either the provided or a better error correction level which works
while keeping the (Micro) QR Code version.
:param int version: Version constant.
:param int|None error: Error level constant or ``None``
:param Segments segments: Instance of :py:class:`Segments`
:param bool eci: Indicates if ECI designator should be written.
:param bool is_sa: Indicates if Structured Append mode is used.
"""
if error not in (consts.ERROR_LEVEL_H, None) and len(segments) == 1:
levels = [consts.ERROR_LEVEL_L, consts.ERROR_LEVEL_M,
consts.ERROR_LEVEL_Q, consts.ERROR_LEVEL_H]
if version < 1:
levels.pop() # H isn't support by Micro QR Codes
if version < consts.VERSION_M4:
levels.pop() # Error level Q isn't supported by M2 and M3
data_length = segments.bit_length_with_overhead(version, eci, is_sa=is_sa)
for error_level in levels[levels.index(error)+1:]:
if consts.SYMBOL_CAPACITY[version][error_level] >= data_length:
error = error_level
else:
break
return error
def write_segment(buff, segment, ver, ver_range, eci=False):
"""\
Writes a segment.
:param buff: The byte buffer.
:param _Segment segment: The segment to serialize.
:param ver: ``None`` if a QR Code is written, "M1", "M2", "M3", or "M4" if a
Micro QR Code is written.
:param ver_range: "M1", "M2", "M3", or "M4" if a Micro QR Code is written,
otherwise a constant representing a range of QR Code versions.
"""
mode = segment.mode
append_bits = buff.append_bits
# Write ECI header if requested
if eci and mode == consts.MODE_BYTE \
and segment.encoding != consts.DEFAULT_BYTE_ENCODING:
append_bits(consts.MODE_ECI, 4)
append_bits(get_eci_assignment_number(segment.encoding), 8)
if ver is None: # QR Code
append_bits(mode, 4)
elif ver > consts.VERSION_M1: # Micro QR Code (M1 has no mode indicator)
append_bits(consts.MODE_TO_MICRO_MODE_MAPPING[mode], ver + 3)
# Character count indicator
append_bits(segment.char_count,
consts.CHAR_COUNT_INDICATOR_LENGTH[mode][ver_range])
buff.extend(segment.bits)
:param int version: Version constant
:param int error: Error level constant.
:param int mask_pattern: Mask pattern number.
"""
fmt = mask_pattern
if version > 0:
if error == consts.ERROR_LEVEL_L:
fmt += 0x08
elif error == consts.ERROR_LEVEL_H:
fmt += 0x10
elif error == consts.ERROR_LEVEL_Q:
fmt += 0x18
format_info = consts.FORMAT_INFO[fmt]
else:
fmt += consts.ERROR_LEVEL_TO_MICRO_MAPPING[version][error] << 2
format_info = consts.FORMAT_INFO_MICRO[fmt]
return format_info
For version 1 .. 40 it returns the version as integer, for Micro QR Codes
it returns a string like ``M1`` etc.
:raises: :py:exc:`VersionError`: In case the `version_constant` is unknown.
"""
if 0 < version_const < 41:
return version_const
for name, v in consts.MICRO_VERSION_MAPPING.items():
if v == version_const:
return name
raise ValueError('Unknown version constant "{0}"'.format(version_const))
_ALPHANUMERIC_PATTERN = re.compile(br'^[' + re.escape(consts.ALPHANUMERIC_CHARS) + br']+\Z')
def is_alphanumeric(data):
"""\
Returns if the provided `data` can be encoded in "alphanumeric" mode.
:param bytes data: The data to check.
:rtype: bool
"""
return _ALPHANUMERIC_PATTERN.match(data)
def is_kanji(data):
"""\
Returns if the `data` can be encoded in "kanji" mode.
:param bytes data: The data to check.
:rtype: bool
def is_mode_supported(mode, ver):
"""\
Returns if `mode` is supported by `version`.
Note: This function does not check if `version` is actually a valid
(Micro) QR Code version. Invalid versions like ``41`` may return an illegal
value.
:param int mode: Canonicalized mode.
:param int or None ver: (Micro) QR Code version constant.
:rtype: bool
"""
ver = None if ver > 0 else ver
try:
return ver in consts.SUPPORTED_MODES[mode]
except KeyError:
raise ValueError('Unknown mode "{0}"'.format(mode))
:param timing_dark: Color of the dark modules of the timing patterns.
:param timing_light: Color of the light modules of the timing patterns.
:param separator: Color of the separator.
:param dark_module: Color of the dark module.
:param quiet_zone: Color of the quiet zone / border.
:rtype: dict
"""
unsupported = ()
if version < 7:
unsupported = [consts.TYPE_VERSION_DARK, consts.TYPE_VERSION_LIGHT]
if version < 1: # Micro QR Code
unsupported.extend([consts.TYPE_DARKMODULE,
consts.TYPE_ALIGNMENT_PATTERN_DARK,
consts.TYPE_ALIGNMENT_PATTERN_LIGHT])
mt2color = {
consts.TYPE_FINDER_PATTERN_DARK: finder_dark if finder_dark is not False else dark,
consts.TYPE_FINDER_PATTERN_LIGHT: finder_light if finder_light is not False else light,
consts.TYPE_DATA_DARK: data_dark if data_dark is not False else dark,
consts.TYPE_DATA_LIGHT: data_light if data_light is not False else light,
consts.TYPE_VERSION_DARK: version_dark if version_dark is not False else dark,
consts.TYPE_VERSION_LIGHT: version_light if version_light is not False else light,
consts.TYPE_ALIGNMENT_PATTERN_DARK: alignment_dark if alignment_dark is not False else dark,
consts.TYPE_ALIGNMENT_PATTERN_LIGHT: alignment_light if alignment_light is not False else light,
consts.TYPE_TIMING_DARK: timing_dark if timing_dark is not False else dark,
consts.TYPE_TIMING_LIGHT: timing_light if timing_light is not False else light,
consts.TYPE_FORMAT_DARK: format_dark if format_dark is not False else dark,
consts.TYPE_FORMAT_LIGHT: format_light if format_light is not False else light,
consts.TYPE_SEPARATOR: separator if separator is not False else light,
consts.TYPE_DARKMODULE: dark_module if dark_module is not False else dark,
consts.TYPE_QUIET_ZONE: quiet_zone if quiet_zone is not False else light,
}
return {mt: val for mt, val in mt2color.items() if mt not in unsupported}
ISO/IEC 18004:2015(E) -- 7.9 Format information (page 55)
ISO/IEC 18004:2015(E) -- Table C.1 — Valid format information bit sequences (page 80)
:param int version: Version constant
:param int error: Error level constant.
:param int mask_pattern: Mask pattern number.
"""
fmt = mask_pattern
if version > 0:
if error == consts.ERROR_LEVEL_L:
fmt += 0x08
elif error == consts.ERROR_LEVEL_H:
fmt += 0x10
elif error == consts.ERROR_LEVEL_Q:
fmt += 0x18
format_info = consts.FORMAT_INFO[fmt]
else:
fmt += consts.ERROR_LEVEL_TO_MICRO_MAPPING[version][error] << 2
format_info = consts.FORMAT_INFO_MICRO[fmt]
return format_info