1# issn.py - functions for handling ISSNs 2# 3# Copyright (C) 2010-2015 Arthur de Jong 4# 5# This library is free software; you can redistribute it and/or 6# modify it under the terms of the GNU Lesser General Public 7# License as published by the Free Software Foundation; either 8# version 2.1 of the License, or (at your option) any later version. 9# 10# This library is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13# Lesser General Public License for more details. 14# 15# You should have received a copy of the GNU Lesser General Public 16# License along with this library; if not, write to the Free Software 17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18# 02110-1301 USA 19 20"""ISSN (International Standard Serial Number). 21 22The ISSN (International Standard Serial Number) is the standard code to 23identify periodical publications (e.g. magazines). 24 25An ISSN has 8 digits and is formatted in two pairs of 4 digits separated by a 26hyphen. The last digit is a check digit and may be 0-9 or X (similar to 27ISBN-10). 28 29More information: 30 31* https://en.wikipedia.org/wiki/International_Standard_Serial_Number 32* http://www.issn.org/ 33 34>>> validate('0024-9319') 35'00249319' 36>>> validate('0032147X') 37Traceback (most recent call last): 38 ... 39InvalidChecksum: ... 40>>> validate('003214712') 41Traceback (most recent call last): 42 ... 43InvalidLength: ... 44>>> compact('0032-1478') 45'00321478' 46>>> format('00249319') 47'0024-9319' 48>>> to_ean('0264-3596') 49'9770264359008' 50""" 51 52from stdnum import ean 53from stdnum.exceptions import * 54from stdnum.util import clean, isdigits 55 56 57def compact(number): 58 """Convert the ISSN to the minimal representation. This strips the number 59 of any valid ISSN separators and removes surrounding whitespace.""" 60 return clean(number, ' -').strip().upper() 61 62 63def calc_check_digit(number): 64 """Calculate the ISSN check digit for 10-digit numbers. The number passed 65 should not have the check bit included.""" 66 check = (11 - sum((8 - i) * int(n) 67 for i, n in enumerate(number))) % 11 68 return 'X' if check == 10 else str(check) 69 70 71def validate(number): 72 """Check if the number is a valid ISSN. This checks the length and 73 whether the check digit is correct.""" 74 number = compact(number) 75 if not isdigits(number[:-1]): 76 raise InvalidFormat() 77 if len(number) != 8: 78 raise InvalidLength() 79 if calc_check_digit(number[:-1]) != number[-1]: 80 raise InvalidChecksum() 81 return number 82 83 84def is_valid(number): 85 """Check if the number provided is a valid ISSN.""" 86 try: 87 return bool(validate(number)) 88 except ValidationError: 89 return False 90 91 92def format(number): 93 """Reformat the number to the standard presentation format.""" 94 number = compact(number) 95 return number[:4] + '-' + number[4:] 96 97 98def to_ean(number, issue_code='00'): 99 """Convert the number to EAN-13 format.""" 100 number = '977' + validate(number)[:-1] + issue_code 101 return number + ean.calc_check_digit(number) 102