Skip to content

fix(finance): isin() actually validates the check digit#468

Open
Jordan-Bourillot wants to merge 1 commit into
python-validators:masterfrom
Jordan-Bourillot:fix/isin-checksum
Open

fix(finance): isin() actually validates the check digit#468
Jordan-Bourillot wants to merge 1 commit into
python-validators:masterfrom
Jordan-Bourillot:fix/isin-checksum

Conversation

@Jordan-Bourillot

Copy link
Copy Markdown

Summary

isin() accepted any 12-character string — the check digit was never actually verified.

Root cause

_isin_checksum initialised check = 0 and then never updated it inside the loop (the check += (val // 10) + (val % 10) line that exists in _cusip_checksum was missing). It also reused the per-character CUSIP scheme, which is not the ISIN algorithm. So check stayed 0 and (check % 10) == 0 was always true.

>>> import validators
>>> validators.isin('US0378331004')   # wrong check digit
True                                   # should be invalid
>>> validators.isin('XX0000000000')
True                                   # should be invalid

Fix

Reimplement with the documented ISIN scheme: expand letters to digits (A=10 … Z=35) and run the Luhn algorithm over the result. Verified against real ISINs (US0378331005, AU0000XVGZA3, GB0002634946, …).

Tests

  • One existing "valid" fixture, JP000K0VF054, was itself invalid — its correct check digit is 5, and only the broken checksum let it pass. Corrected to JP000K0VF055.
  • Added a wrong-check-digit case (US0378331004) to the invalid fixtures, plus a valid example in the docstring.

The full test suite passes and ruff is clean.

_isin_checksum never accumulated into `check` (the accumulation line
present in _cusip_checksum was missing), and the per-character loop it
copied is not the ISIN scheme anyway. `check` stayed 0, so isin()
returned True for every 12-character string -- e.g. isin('US0378331004')
(wrong check digit) and isin('XX0000000000').

Reimplement with the documented ISIN algorithm: expand letters to digits
(A=10..Z=35) and run Luhn over the result. Verified against real ISINs
(US0378331005, AU0000XVGZA3, GB0002634946).

The existing 'valid' fixture 'JP000K0VF054' was itself invalid (its
correct check digit is 5) -- corrected to 'JP000K0VF055'. Added a
wrong-check-digit case to the invalid fixtures and a valid example to
the docstring.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant