Coverage for oc_ds_converter / oc_idmanager / isbn.py: 88%
60 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-25 18:06 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-25 18:06 +0000
1# SPDX-FileCopyrightText: 2023 Arcangelo Massari <arcangelo.massari@unibo.it>
2# SPDX-FileCopyrightText: 2024 Arianna Moretti <arianna.moretti4@unibo.it>
3#
4# SPDX-License-Identifier: ISC
7import re
8from re import match, sub
10from oc_ds_converter.oc_idmanager.base import IdentifierManager
13class ISBNManager(IdentifierManager):
14 """This class implements an identifier manager for isbn identifier"""
15 def __init__(self, data={}):
16 """ISBN manager constructor."""
17 self._p = "isbn:"
18 self._data = data
19 super(ISBNManager, self).__init__()
21 def is_valid(self, id_string, get_extra_info=False):
22 isbn = self.normalise(id_string, include_prefix=True)
23 if isbn is None:
24 return False
25 else:
26 if isbn not in self._data or self._data[isbn] is None:
27 self._data[isbn] = {"valid":self.check_digit(isbn) and self.syntax_ok(isbn)}
28 return (
29 self.check_digit(isbn)
30 and self.syntax_ok(isbn)
31 )
32 return self._data[isbn].get("valid")
34 def normalise(self, id_string, include_prefix=False):
35 try:
36 isbn_string = sub("[^X0-9]", "", id_string.upper())
37 return "%s%s" % (self._p if include_prefix else "", isbn_string)
38 except: # Any error in processing the ISBN will return None
39 return None
41 def check_digit(self, isbn):
42 if isbn.startswith(self._p):
43 spl = isbn.find(self._p) + len(self._p)
44 isbn = isbn[spl:]
46 isbn = isbn.replace("-", "")
47 isbn = isbn.replace(" ", "")
48 check_digit = False
49 if len(isbn) == 13:
50 total = 0
51 val = 1
52 for x in isbn:
53 if x == "X":
54 x = 10
55 total += int(x)*val
56 val = 3 if val == 1 else val == 1
57 if (total % 10) == 0:
58 check_digit = True
59 elif len(isbn) == 10:
60 total = 0
61 val = 10
62 for x in isbn:
63 if x == "X":
64 x = 10
65 total += int(x)*val
66 val -= 1
67 if (total % 11) == 0:
68 check_digit = True
70 return check_digit
72 def syntax_ok(self, id_string):
73 id_string.replace(" ", "")
74 id_string.replace("-", "")
75 if not id_string.startswith(self._p):
76 id_string = self._p+id_string
77 if len(id_string) - len(self._p) == 13:
78 return True if match("^isbn:97[89][0-9X]{10}$", id_string, re.IGNORECASE) else False
79 elif len(id_string) - len(self._p) == 10:
80 return True if match("^isbn:[0-9X]{10}$", id_string, re.IGNORECASE) else False
81 else:
82 return False