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.

73 lines
3.0 KiB

from typing import List, Tuple
from faker.providers.isbn.rules import RegistrantRule
from .. import BaseProvider
from .isbn import ISBN, ISBN10, ISBN13
from .rules import RULES
class Provider(BaseProvider):
"""Generates fake ISBNs. ISBN rules vary across languages/regions
so this class makes no attempt at replicating all of the rules. It
only replicates the 978 EAN prefix for the English registration
groups, meaning the first 4 digits of the ISBN-13 will either be
978-0 or 978-1. Since we are only replicating 978 prefixes, every
ISBN-13 will have a direct mapping to an ISBN-10.
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.
"""
def _body(self) -> List[str]:
"""Generate the information required to create an ISBN-10 or
ISBN-13.
"""
ean: str = self.random_element(RULES.keys())
reg_group: str = self.random_element(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 = ISBN.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: List[RegistrantRule] = 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[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 isbn13(self, separator: str = "-") -> str:
ean, group, registrant, publication = self._body()
isbn = ISBN13(ean, group, registrant, publication)
return isbn.format(separator)
def isbn10(self, separator: str = "-") -> str:
ean, group, registrant, publication = self._body()
isbn = ISBN10(ean, group, registrant, publication)
return isbn.format(separator)