diff --git a/propka/hybrid36.py b/propka/hybrid36.py index e0af2dc..67f2c0c 100644 --- a/propka/hybrid36.py +++ b/propka/hybrid36.py @@ -4,16 +4,21 @@ http://cci.lbl.gov/hybrid_36/ """ import string -_hybrid36_upper_chars = set(string.ascii_uppercase) -_hybrid36_lower_chars = set(string.ascii_lowercase) -_hybrid36_digits = set(string.digits) -_hybrid36_upper_set = _hybrid36_upper_chars | _hybrid36_digits -_hybrid36_lower_set = _hybrid36_lower_chars | _hybrid36_digits + +_HYBRID36_UPPER_CHARS = set(string.ascii_uppercase) +_HYBRID36_LOWER_CHARS = set(string.ascii_lowercase) +_HYBRID36_DIGITS = set(string.digits) +_HYBRID36_UPPER_SET = _HYBRID36_UPPER_CHARS | _HYBRID36_DIGITS +_HYBRID36_LOWER_SET = _HYBRID36_LOWER_CHARS | _HYBRID36_DIGITS + def decode(input_string): - """ - Convert an input string of a number in hybrid-36 format to an integer. + """Convert an input string of a number in hybrid-36 format to an integer. + Args: + input_string: input string + Returns: + integer """ value_error_message = "invalid literal for hybrid-36 conversion: '%s'" @@ -27,7 +32,7 @@ def decode(input_string): else: sign = 1 - if not len(input_string): + if len(input_string) == 0: raise ValueError(value_error_message % input_string) # See http://cci.lbl.gov/hybrid_36/ for documentation on the format. @@ -35,21 +40,21 @@ def decode(input_string): num_chars = len(input_string) first_char = input_string[0] - if first_char in _hybrid36_digits: + if first_char in _HYBRID36_DIGITS: return sign * int(input_string) - elif first_char in _hybrid36_upper_chars: + elif first_char in _HYBRID36_UPPER_CHARS: reference = - (10 * 36 ** (num_chars - 1) - 10 ** num_chars) - _hybrid36_set = _hybrid36_upper_set - elif first_char in _hybrid36_lower_chars: + _hybrid36_set = _HYBRID36_UPPER_SET + elif first_char in _HYBRID36_LOWER_CHARS: reference = (16 * 36 ** (num_chars - 1) + 10 ** num_chars) - _hybrid36_set = _hybrid36_lower_set + _hybrid36_set = _HYBRID36_LOWER_SET else: raise ValueError(value_error_message % original_input_string) # Check the validity of the input string: ASCII characters should be # either all uppercase or all lowercase. - for c in input_string[1:]: - if c not in _hybrid36_set: + for char in input_string[1:]: + if char not in _hybrid36_set: raise ValueError(value_error_message % original_input_string) # Convert with the int function. diff --git a/tests/test_hybrid36.py b/tests/test_hybrid36.py new file mode 100644 index 0000000..1af74d0 --- /dev/null +++ b/tests/test_hybrid36.py @@ -0,0 +1,57 @@ +import unittest + +import propka.hybrid36 as hybrid36 + +class Hybrid36Test(unittest.TestCase): + def testDecode(self): + test_values = { + "99999": 99999, + "A0000": 100000, + "0": 0, + "9": 9, + "A": 10, + " ZZZZY": 43770014, + "ZZZZZ": 43770015, # ZZZZZ - A0000 + 100000 + "a0000": 43770016, + "zzzzz": 87440031, + "zzzzy": 87440030, + "99": 99, + "A0": 100, + "ZZ": 1035, + "zz": 1971, + "-99999": -99999, + "-A0000": -100000, + "-0": 0, + "-9": -9, + "-A": -10, + "-ZZZZY": -43770014, + "-ZZZZZ": -43770015, # ZZZZZ - A0000 + 100000 + "-a0000": -43770016, + "-zzzzz": -87440031, + "-zzzzy": -87440030, + "-99": -99, + "-A0": -100, + "-ZZ": -1035, + "-zz": -1971, + "PROPKA": 954495146, + "A001Z": 100071, + "B0000": 1779616, + } + + for k, v in test_values.items(): + self.assertEqual(hybrid36.decode(k), v) + + def testErrors(self): + test_values = [ + "99X99", + "X9-99", + "XYZa", + "", + "-", + "!NotOk", + ] + + for v in test_values: + with self.assertRaises(ValueError) as e: + hybrid36.decode(v) + self.assertTrue(v in str(e.exception)) \ No newline at end of file