Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2This module is providing funcionality to validate and compute ISBN checksums. 

3 

4Taken from 

5https://github.com/GLMeece/isbn_validator/blob/master/src/isbn_validator/isbn_validator.py 

6because https://pypi.org/project/isbn_validator/ is not maintained. 

7Adapted for use with Python3 by casting map() to list(). 

8 

9See :func:`is_valid_isbn` for details. 

10 

11API 

12--- 

13""" 

14 

15from functools import wraps 

16 

17 

18# Functions & objects ========================================================= 

19def _clean_isbn(isbn): 

20 """ 

21 Remove all non-digit and non "x" characters from given string. 

22 

23 Args: 

24 isbn (str/list): ISBN number as string or list of digits 

25 

26 Returns: 

27 list: array of numbers (if "x" is found, it is converted to 10). 

28 """ 

29 if isinstance(isbn, str): 

30 isbn = list(isbn.lower()) 

31 

32 # filter digits and "x" 

33 isbn = filter(lambda x: x.isdigit() or x == "x", isbn) 

34 

35 # convert ISBN to numbers 

36 return list(map(lambda x: 10 if x == "x" else int(x), isbn)) 

37 

38 

39def _isbn_cleaner(fn): 

40 """ 

41 Decorator for calling other functions from this module. 

42 

43 Purpose of this decorator is to clean the ISBN string from garbage and 

44 return list of digits. 

45 

46 Args: 

47 fn (function): function in which will be :func:`_clean_isbn(isbn)` call 

48 wrapped. 

49 """ 

50 

51 @wraps(fn) 

52 def wrapper(isbn): 

53 return fn(_clean_isbn(isbn)) 

54 

55 return wrapper 

56 

57 

58@_isbn_cleaner 

59def get_isbn10_checksum(isbn) -> int: 

60 """ 

61 Args: 

62 isbn (str/list): ISBN number as string or list of digits 

63 

64 Warning: 

65 Function expects that `isbn` is only 9 digits long. 

66 

67 Returns: 

68 int: Last (checksum) digit for given `isbn`. 

69 """ 

70 return sum([(i + 1) * x for i, x in enumerate(isbn)]) % 11 

71 

72 

73@_isbn_cleaner 

74def is_isbn10_valid(isbn) -> bool: 

75 """ 

76 Check if given `isbn` 10 is valid. 

77 

78 Args: 

79 isbn (str/list): ISBN number as string or list of digits. 

80 

81 Returns: 

82 bool: ``True`` if ISBN is valid. 

83 """ 

84 if len(isbn) != 10: 

85 return False 

86 

87 return get_isbn10_checksum(isbn[:-1]) == isbn[-1] 

88 

89 

90@_isbn_cleaner 

91def get_isbn13_checksum(isbn) -> int: 

92 """ 

93 Args: 

94 isbn (str/list): ISBN number as string or list of digits. 

95 

96 Warning: 

97 Function expects that `isbn` is only 12 digits long. 

98 

99 Returns: 

100 int: Last checksum digit for given `isbn`. 

101 """ 

102 multipliers = map(lambda x: int(x), list("13" * 6)) 

103 

104 rest = sum([i * x for i, x in zip(multipliers, isbn)]) % 10 

105 

106 if rest == 0: 

107 return rest 

108 

109 return 10 - rest 

110 

111 

112@_isbn_cleaner 

113def is_isbn13_valid(isbn) -> bool: 

114 """ 

115 Check if given `isbn` 13 is valid. 

116 

117 Args: 

118 isbn (str/list): ISBN number as string or list of digits. 

119 

120 Returns: 

121 bool: ``True`` if ISBN is valid. 

122 """ 

123 if len(isbn) != 13: 

124 return False 

125 

126 return get_isbn13_checksum(isbn[:-1]) == isbn[-1] 

127 

128 

129@_isbn_cleaner 

130def is_valid_isbn(isbn) -> bool: 

131 """ 

132 Validate given `isbn`. Wrapper for :func:`is_isbn10_valid`/ 

133 :func:`is_isbn13_valid`. 

134 

135 Args: 

136 isbn (str/map): ISBN number as string or list of digits. 

137 

138 Note: 

139 Function doesn't require `isbn` type to be specified (it can be both 

140 10/13 isbn's versions). 

141 

142 Returns: 

143 bool: ``True`` if ISBN is valid. 

144 """ 

145 length = len(list(isbn)) 

146 

147 if length == 10: 

148 return is_isbn10_valid(list(isbn)) 

149 if length == 13: 

150 return is_isbn13_valid(list(isbn)) 

151 

152 return False