update bots

This commit is contained in:
2026-05-18 14:15:59 +07:00
parent b0ce866a2f
commit b9054d178e
5775 changed files with 832577 additions and 38 deletions

View File

@@ -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)

View File

@@ -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),
],
},
}

View File

@@ -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),
],
},
}

View File

@@ -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
]
)