From 1c9cd99ae556cb0ee7f6e30db77cbe14b95e2976 Mon Sep 17 00:00:00 2001 From: Sarbajit Sengupta Date: Sun, 1 Nov 2026 12:21:50 +0530 Subject: [PATCH] Accept 19-digit Visa card numbers --- src/validators/card.py | 4 ++-- tests/test_card.py | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/validators/card.py b/src/validators/card.py index 484a9dc0..7eae89de 100644 --- a/src/validators/card.py +++ b/src/validators/card.py @@ -42,7 +42,7 @@ def card_number(value: str, /): @validator def visa(value: str, /): - """Return whether or not given value is a valid Visa card number. + """Return whether or not given value is a valid 16- or 19-digit Visa card number. Examples: >>> visa('4242424242424242') @@ -59,7 +59,7 @@ def visa(value: str, /): (ValidationError): If `value` is an invalid Visa card number. """ pattern = re.compile(r"^4") - return card_number(value) and len(value) == 16 and pattern.match(value) + return card_number(value) and len(value) in (16, 19) and pattern.match(value) @validator diff --git a/tests/test_card.py b/tests/test_card.py index c17f5d95..1859d885 100644 --- a/tests/test_card.py +++ b/tests/test_card.py @@ -17,7 +17,7 @@ visa, ) -visa_cards = ["4242424242424242", "4000002760003184"] +visa_cards = ["4242424242424242", "4000002760003184", "4000000000000000006"] mastercard_cards = ["5555555555554444", "2223003122003222"] amex_cards = ["378282246310005", "371449635398431"] unionpay_cards = ["6200000000000005"] @@ -63,6 +63,22 @@ def test_returns_true_on_valid_visa(value: str): assert visa(value) +@pytest.mark.parametrize( + "value", + ["400000000000006", "40000000000000006", "400000000000000002", "40000000000000000002"], +) +def test_visa_rejects_unsupported_lengths(value: str): + """Reject unsupported lengths even when the checksum and prefix match.""" + assert card_number(value) is True + assert isinstance(visa(value), ValidationError) + + +@pytest.mark.parametrize("value", ["4000000000000000000", "4000000000000000007"]) +def test_visa_rejects_bad_checksum_at_nineteen_digits(value: str): + """A supported length must not bypass the Luhn check.""" + assert isinstance(visa(value), ValidationError) + + @pytest.mark.parametrize( "value", mastercard_cards + amex_cards + unionpay_cards + diners_cards + jcb_cards + discover_cards,