summaryrefslogtreecommitdiff
path: root/venv/lib/python3.11/site-packages/faker/providers/isbn
diff options
context:
space:
mode:
Diffstat (limited to 'venv/lib/python3.11/site-packages/faker/providers/isbn')
-rw-r--r--venv/lib/python3.11/site-packages/faker/providers/isbn/__init__.py72
-rw-r--r--venv/lib/python3.11/site-packages/faker/providers/isbn/__pycache__/__init__.cpython-311.pycbin0 -> 4288 bytes
-rw-r--r--venv/lib/python3.11/site-packages/faker/providers/isbn/__pycache__/isbn.cpython-311.pycbin0 -> 6081 bytes
-rw-r--r--venv/lib/python3.11/site-packages/faker/providers/isbn/__pycache__/rules.cpython-311.pycbin0 -> 2263 bytes
-rw-r--r--venv/lib/python3.11/site-packages/faker/providers/isbn/en_US/__init__.py5
-rw-r--r--venv/lib/python3.11/site-packages/faker/providers/isbn/en_US/__pycache__/__init__.cpython-311.pycbin0 -> 490 bytes
-rw-r--r--venv/lib/python3.11/site-packages/faker/providers/isbn/isbn.py85
-rw-r--r--venv/lib/python3.11/site-packages/faker/providers/isbn/rules.py45
8 files changed, 207 insertions, 0 deletions
diff --git a/venv/lib/python3.11/site-packages/faker/providers/isbn/__init__.py b/venv/lib/python3.11/site-packages/faker/providers/isbn/__init__.py
new file mode 100644
index 0000000..cad4e81
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/faker/providers/isbn/__init__.py
@@ -0,0 +1,72 @@
+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)
diff --git a/venv/lib/python3.11/site-packages/faker/providers/isbn/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/faker/providers/isbn/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..946bb55
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/faker/providers/isbn/__pycache__/__init__.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/faker/providers/isbn/__pycache__/isbn.cpython-311.pyc b/venv/lib/python3.11/site-packages/faker/providers/isbn/__pycache__/isbn.cpython-311.pyc
new file mode 100644
index 0000000..46a758f
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/faker/providers/isbn/__pycache__/isbn.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/faker/providers/isbn/__pycache__/rules.cpython-311.pyc b/venv/lib/python3.11/site-packages/faker/providers/isbn/__pycache__/rules.cpython-311.pyc
new file mode 100644
index 0000000..d9f13ba
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/faker/providers/isbn/__pycache__/rules.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/faker/providers/isbn/en_US/__init__.py b/venv/lib/python3.11/site-packages/faker/providers/isbn/en_US/__init__.py
new file mode 100644
index 0000000..3df1adc
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/faker/providers/isbn/en_US/__init__.py
@@ -0,0 +1,5 @@
+from .. import Provider as ISBNProvider
+
+
+class Provider(ISBNProvider):
+ pass
diff --git a/venv/lib/python3.11/site-packages/faker/providers/isbn/en_US/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/faker/providers/isbn/en_US/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..0677340
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/faker/providers/isbn/en_US/__pycache__/__init__.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/faker/providers/isbn/isbn.py b/venv/lib/python3.11/site-packages/faker/providers/isbn/isbn.py
new file mode 100644
index 0000000..b712a83
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/faker/providers/isbn/isbn.py
@@ -0,0 +1,85 @@
+"""
+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
+ ]
+ )
diff --git a/venv/lib/python3.11/site-packages/faker/providers/isbn/rules.py b/venv/lib/python3.11/site-packages/faker/providers/isbn/rules.py
new file mode 100644
index 0000000..db5d126
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/faker/providers/isbn/rules.py
@@ -0,0 +1,45 @@
+"""
+This module exists solely to figure how long a registrant/publication
+number may be within an ISBN. The rules change based on the prefix and
+language/region. This list of rules only encapsulates the 978 prefix
+for English books. 978 is the largest and, until recently, the only
+prefix.
+
+The complete list of prefixes and rules can be found at
+https://www.isbn-international.org/range_file_generation
+"""
+
+from collections import namedtuple
+from typing import Dict, List
+
+RegistrantRule = namedtuple("RegistrantRule", ["min", "max", "registrant_length"])
+
+# Structure: RULES[`EAN Prefix`][`Registration Group`] = [Rule1, Rule2, ...]
+RULES: Dict[str, Dict[str, List[RegistrantRule]]] = {
+ "978": {
+ "0": [
+ 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),
+ ],
+ "1": [
+ RegistrantRule("0000000", "0999999", 2),
+ RegistrantRule("1000000", "3999999", 3),
+ RegistrantRule("4000000", "5499999", 4),
+ RegistrantRule("5500000", "7319999", 5),
+ RegistrantRule("7320000", "7399999", 7),
+ RegistrantRule("7400000", "8697999", 5),
+ RegistrantRule("8698000", "9729999", 6),
+ RegistrantRule("9730000", "9877999", 4),
+ RegistrantRule("9878000", "9989999", 6),
+ RegistrantRule("9990000", "9999999", 7),
+ ],
+ },
+}