From 9bc62536abed09d01443ed8024b52e17bdfb4eac Mon Sep 17 00:00:00 2001 From: Huanyi Xie <74809554+xiehuanyi@users.noreply.github.com> Date: Thu, 8 Oct 2026 14:25:47 +0300 Subject: [PATCH] Require numeric check digits in CUSIP and SEDOL identifiers --- src/validators/finance.py | 4 ++-- tests/test_finance.py | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/validators/finance.py b/src/validators/finance.py index 9df5a970..38c76d70 100644 --- a/src/validators/finance.py +++ b/src/validators/finance.py @@ -71,7 +71,7 @@ def cusip(value: str): (Literal[True]): If `value` is a valid CUSIP string. (ValidationError): If `value` is an invalid CUSIP string. """ - return len(value) == 9 and _cusip_checksum(value) + return len(value) == 9 and value[-1] in "0123456789" and _cusip_checksum(value) @validator @@ -117,7 +117,7 @@ def sedol(value: str): (Literal[True]): If `value` is a valid SEDOL string. (ValidationError): If `value` is an invalid SEDOL string. """ - if len(value) != 7: + if len(value) != 7 or value[-1] not in "0123456789": return False weights = [1, 3, 1, 7, 3, 9, 1] diff --git a/tests/test_finance.py b/tests/test_finance.py index a40fd333..ce221a73 100644 --- a/tests/test_finance.py +++ b/tests/test_finance.py @@ -1,5 +1,8 @@ """Test Finance.""" +# standard +from typing import Callable + # external import pytest @@ -49,3 +52,27 @@ def test_returns_true_on_valid_sedol(value: str): def test_returns_failed_validation_on_invalid_sedol(value: str): """Test returns failed validation on invalid sedol.""" assert isinstance(sedol(value), ValidationError) + + +@pytest.mark.parametrize( + "validate, value", + [ + (cusip, "03783310J"), + (cusip, "03783310j"), + (cusip, "03783310@"), + (sedol, "293692L"), + (sedol, "B12345G"), + (sedol, "B12345Q"), + ], +) +def test_rejects_non_numeric_check_digit(validate: Callable[[str], object], value: str): + """Reject letters and symbols that accidentally satisfy the checksum.""" + assert isinstance(validate(value), ValidationError) + + +@pytest.mark.parametrize( + "validate, value", [(cusip, "037833100"), (sedol, "2936921"), (sedol, "B123456")] +) +def test_accepts_numeric_check_digit(validate: Callable[[str], object], value: str): + """Keep valid numeric check digits, including alphanumeric identifiers.""" + assert validate(value) is True