You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

86 lines
2.6 KiB

"""
This module is responsible for generating the check digit and formatting
ISBN numbers.
"""
from typing import Any, Optional
class ISBN:
MAX_LENGTH = 13
def __init__(
self,
ean: Optional[str] = None,
group: Optional[str] = None,
registrant: Optional[str] = None,
publication: Optional[str] = None,
) -> None:
self.ean = ean
self.group = group
self.registrant = registrant
self.publication = publication
class ISBN13(ISBN):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.check_digit = self._check_digit()
def _check_digit(self) -> str:
"""Calculate the check digit for ISBN-13.
See https://en.wikipedia.org/wiki/International_Standard_Book_Number
for calculation.
"""
weights = (1 if x % 2 == 0 else 3 for x in range(12))
body = "".join([part for part in [self.ean, self.group, self.registrant, self.publication] if part is not None])
remainder = sum(int(b) * w for b, w in zip(body, weights)) % 10
diff = 10 - remainder
check_digit = 0 if diff == 10 else diff
return str(check_digit)
def format(self, separator: str = "") -> str:
return separator.join(
[
part
for part in [
self.ean,
self.group,
self.registrant,
self.publication,
self.check_digit,
]
if part is not None
]
)
class ISBN10(ISBN):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.check_digit = self._check_digit()
def _check_digit(self) -> str:
"""Calculate the check digit for ISBN-10.
See https://en.wikipedia.org/wiki/International_Standard_Book_Number
for calculation.
"""
weights = range(1, 10)
body = "".join([part for part in [self.group, self.registrant, self.publication] if part is not None])
remainder = sum(int(b) * w for b, w in zip(body, weights)) % 11
check_digit = "X" if remainder == 10 else str(remainder)
return str(check_digit)
def format(self, separator: str = "") -> str:
return separator.join(
[
part
for part in [
self.group,
self.registrant,
self.publication,
self.check_digit,
]
if part is not None
]
)