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,53 @@
from typing import List, Tuple
from faker.providers.sbn.rules import RegistrantRule
from .. import BaseProvider
from .rules import RULES
from .sbn import SBN, SBN9
class Provider(BaseProvider):
"""Generates fake SBNs. These are the precursor to the ISBN and are
largely similar to ISBN-10.
See https://www.isbn-international.org/content/what-isbn for the
format of ISBNs. SBNs have no EAN prefix or Registration Group.
"""
def _body(self) -> List[str]:
"""Generate the information required to create an SBN"""
reg_pub_len: int = SBN.MAX_LENGTH - 1
# Generate a registrant/publication combination
reg_pub: str = self.numerify("#" * reg_pub_len)
# Use rules to separate the registrant from the publication
rules: List[RegistrantRule] = RULES
registrant, publication = self._registrant_publication(reg_pub, rules)
return [registrant, publication]
@staticmethod
def _registrant_publication(reg_pub: str, rules: List[RegistrantRule]) -> 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 RegistrantRules which designate where
to separate the values in the string.
:returns: A (registrant, publication) tuple of strings.
"""
for rule in rules:
if rule.min <= reg_pub[:-1] <= rule.max:
reg_len = rule.registrant_length
break
else:
raise Exception("Registrant/Publication not found in registrant rule list.")
registrant, publication = reg_pub[:reg_len], reg_pub[reg_len:]
return registrant, publication
def sbn9(self, separator: str = "-") -> str:
registrant, publication = self._body()
sbn = SBN9(registrant, publication)
return sbn.format(separator)

View File

@@ -0,0 +1,5 @@
from .. import Provider as SBNProvider
class Provider(SBNProvider):
pass

View File

@@ -0,0 +1,24 @@
"""
This module exists solely to figure how long a registrant/publication
number may be within an SBN. It's the same as the ISBN implementation
for ean 978, reg_group 0.
"""
from collections import namedtuple
from typing import List
RegistrantRule = namedtuple("RegistrantRule", ["min", "max", "registrant_length"])
# Structure: RULES = [Rule1, Rule2, ...]
RULES: List[RegistrantRule] = [
RegistrantRule("0000000", "1999999", 2),
RegistrantRule("2000000", "2279999", 3),
RegistrantRule("2280000", "2289999", 4),
RegistrantRule("2290000", "6479999", 3),
RegistrantRule("6480000", "6489999", 7),
RegistrantRule("6490000", "6999999", 3),
RegistrantRule("7000000", "8499999", 4),
RegistrantRule("8500000", "8999999", 5),
RegistrantRule("9000000", "9499999", 6),
RegistrantRule("9500000", "9999999", 7),
]

View File

@@ -0,0 +1,50 @@
"""
This module is responsible for generating the check digit and formatting
SBN numbers.
"""
from typing import Any, Optional
class SBN:
MAX_LENGTH = 9
def __init__(
self,
registrant: Optional[str] = None,
publication: Optional[str] = None,
) -> None:
self.registrant = registrant
self.publication = publication
class SBN9(SBN):
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 SBN-9.
SBNs use the same check digit calculation as ISBN. See
https://en.wikipedia.org/wiki/International_Standard_Book_Number
for calculation. Only modification is weights range from 1 to 9
instead of 1 to 10.
"""
weights = range(1, 9)
body = "".join([part for part in [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.registrant,
self.publication,
self.check_digit,
]
if part is not None
]
)