update bots
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
from .. import BaseProvider
|
||||
from .isbn import ISBN10, ISBN13, MAX_LENGTH
|
||||
|
||||
localized = True
|
||||
|
||||
|
||||
class Provider(BaseProvider):
|
||||
"""Generates fake ISBNs.
|
||||
|
||||
See https://www.isbn-international.org/content/what-isbn for the
|
||||
format of ISBNs.
|
||||
See https://www.isbn-international.org/range_file_generation for the
|
||||
list of rules pertaining to each prefix/registration group.
|
||||
"""
|
||||
|
||||
rules: Dict[str, Dict[str, List[Tuple[str, str, int]]]] = {}
|
||||
|
||||
def _body(self) -> List[str]:
|
||||
"""Generate the information required to create an ISBN-10 or
|
||||
ISBN-13.
|
||||
"""
|
||||
ean: str = self.random_element(self.rules.keys())
|
||||
reg_group: str = self.random_element(self.rules[ean].keys())
|
||||
|
||||
# Given the chosen ean/group, decide how long the
|
||||
# registrant/publication string may be.
|
||||
# We must allocate for the calculated check digit, so
|
||||
# subtract 1
|
||||
reg_pub_len: int = MAX_LENGTH - len(ean) - len(reg_group) - 1
|
||||
|
||||
# Generate a registrant/publication combination
|
||||
reg_pub: str = self.numerify("#" * reg_pub_len)
|
||||
|
||||
# Use rules to separate the registrant from the publication
|
||||
rules = self.rules[ean][reg_group]
|
||||
registrant, publication = self._registrant_publication(reg_pub, rules)
|
||||
return [ean, reg_group, registrant, publication]
|
||||
|
||||
@staticmethod
|
||||
def _registrant_publication(reg_pub: str, rules: List[Tuple[str, str, int]]) -> Tuple[str, str]:
|
||||
"""Separate the registration from the publication in a given
|
||||
string.
|
||||
|
||||
:param reg_pub: A string of digits representing a registration
|
||||
and publication.
|
||||
:param rules: A list of registrant rules which designate where
|
||||
to separate the values in the string.
|
||||
:returns: A (registrant, publication) tuple of strings.
|
||||
"""
|
||||
for rule in rules:
|
||||
if rule[0] <= reg_pub[:-1] <= rule[1]:
|
||||
reg_len = rule[2]
|
||||
break
|
||||
else:
|
||||
raise Exception(f"Registrant/Publication '{reg_pub}' not found in registrant rule list.")
|
||||
registrant, publication = reg_pub[:reg_len], reg_pub[reg_len:]
|
||||
return registrant, publication
|
||||
|
||||
def isbn13(self, separator: str = "-") -> str:
|
||||
"""
|
||||
:sample:
|
||||
"""
|
||||
ean, group, registrant, publication = self._body()
|
||||
isbn = ISBN13(ean, group, registrant, publication)
|
||||
return isbn.format(separator)
|
||||
|
||||
def isbn10(self, separator: str = "-") -> str:
|
||||
"""
|
||||
:sample:
|
||||
"""
|
||||
ean, group, registrant, publication = self._body()
|
||||
isbn = ISBN10(ean, group, registrant, publication)
|
||||
return isbn.format(separator)
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,35 @@
|
||||
from .. import Provider as ISBNProvider
|
||||
|
||||
|
||||
class Provider(ISBNProvider):
|
||||
rules = {
|
||||
# EAN prefix
|
||||
"978": {
|
||||
# Registration group
|
||||
"0": [
|
||||
# Registrant rule (min, max, registrant length)
|
||||
("0000000", "1999999", 2),
|
||||
("2000000", "2279999", 3),
|
||||
("2280000", "2289999", 4),
|
||||
("2290000", "6479999", 3),
|
||||
("6480000", "6489999", 7),
|
||||
("6490000", "6999999", 3),
|
||||
("7000000", "8499999", 4),
|
||||
("8500000", "8999999", 5),
|
||||
("9000000", "9499999", 6),
|
||||
("9500000", "9999999", 7),
|
||||
],
|
||||
"1": [
|
||||
("0000000", "0999999", 2),
|
||||
("1000000", "3999999", 3),
|
||||
("4000000", "5499999", 4),
|
||||
("5500000", "7319999", 5),
|
||||
("7320000", "7399999", 7),
|
||||
("7400000", "8697999", 5),
|
||||
("8698000", "9729999", 6),
|
||||
("9730000", "9877999", 4),
|
||||
("9878000", "9989999", 6),
|
||||
("9990000", "9999999", 7),
|
||||
],
|
||||
},
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,37 @@
|
||||
from .. import Provider as ISBNProvider
|
||||
|
||||
|
||||
class Provider(ISBNProvider):
|
||||
rules = {
|
||||
"978": {
|
||||
"84": [
|
||||
("0000000", "0999999", 2),
|
||||
("1000000", "1049999", 5),
|
||||
("1050000", "1199999", 4),
|
||||
("1200000", "1299999", 6),
|
||||
("1300000", "1399999", 4),
|
||||
("1400000", "1499999", 3),
|
||||
("1500000", "1999999", 5),
|
||||
("2000000", "6999999", 3),
|
||||
("7000000", "8499999", 4),
|
||||
("8500000", "8999999", 5),
|
||||
("9000000", "9199999", 4),
|
||||
("9200000", "9239999", 6),
|
||||
("9240000", "9299999", 5),
|
||||
("9300000", "9499999", 6),
|
||||
("9500000", "9699999", 5),
|
||||
("9700000", "9999999", 4),
|
||||
],
|
||||
"13": [
|
||||
("0000000", "0099999", 2),
|
||||
("0100000", "5999999", 0),
|
||||
("6000000", "6049999", 3),
|
||||
("6050000", "6999999", 0),
|
||||
("7000000", "7349999", 4),
|
||||
("7350000", "8749999", 0),
|
||||
("8750000", "8999999", 5),
|
||||
("9000000", "9899999", 0),
|
||||
("9900000", "9999999", 6),
|
||||
],
|
||||
},
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,86 @@
|
||||
"""
|
||||
This module is responsible for generating the check digit and formatting
|
||||
ISBN numbers.
|
||||
"""
|
||||
|
||||
from typing import Any, Optional
|
||||
|
||||
MAX_LENGTH = 13
|
||||
|
||||
|
||||
class ISBN:
|
||||
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
|
||||
]
|
||||
)
|
||||
Reference in New Issue
Block a user