From 1d1d8111133c90d906a580e1dedb8e1a32243044 Mon Sep 17 00:00:00 2001 From: Vitaliy <160263432+vitalivo@users.noreply.github.com> Date: Sat, 12 Sep 2026 18:04:23 +0300 Subject: [PATCH] Accept uppercase X as the ISBN-10 check digit --- string_utils/validation.py | 3 ++- tests/test_is_isbn_10.py | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/string_utils/validation.py b/string_utils/validation.py index 9124cbb..90eed42 100644 --- a/string_utils/validation.py +++ b/string_utils/validation.py @@ -68,7 +68,8 @@ def is_isbn_10(self) -> bool: try: for index, digit in enumerate(self.input_string): - product += int(digit) * (index + 1) + value = 10 if index == 9 and digit == 'X' else int(digit) + product += value * (index + 1) return product % 11 == 0 diff --git a/tests/test_is_isbn_10.py b/tests/test_is_isbn_10.py index d440e8c..925289c 100644 --- a/tests/test_is_isbn_10.py +++ b/tests/test_is_isbn_10.py @@ -1,7 +1,7 @@ from unittest import TestCase from string_utils.errors import InvalidInputError -from string_utils.validation import is_isbn_10 +from string_utils.validation import is_isbn, is_isbn_10 class IsISBN10TestCase(TestCase): @@ -26,6 +26,20 @@ def test_returns_true_for_valid_isbn_10(self): self.assertTrue(is_isbn_10('0718079183')) self.assertTrue(is_isbn_10('8830102180')) + def test_x_check_digit(self): + for isbn in ('080442957X', '0-8044-2957-X', '097522980X'): + with self.subTest(isbn=isbn): + self.assertTrue(is_isbn_10(isbn)) + self.assertTrue(is_isbn(isbn)) + self.assertTrue(is_isbn_10('080442957X', normalize=False)) + self.assertFalse(is_isbn_10('0-8044-2957-X', normalize=False)) + + def test_invalid_x_check_digit(self): + for isbn in ('080442958X', 'X804429570', '08044295XX', '080442957x'): + with self.subTest(isbn=isbn): + self.assertFalse(is_isbn_10(isbn)) + self.assertFalse(is_isbn(isbn)) + def test_dashes_are_not_considered_by_default(self): # isbn numbers have been taken from actual books on amazon self.assertTrue(is_isbn_10('150-6715214'))