Repository: identique/idnumbers (language: python)

Issue:
id number for Spain
https://en.wikipedia.org/wiki/National_identification_number#Spain


Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index 2182c236..b0261b88 100644
--- a/README.md
+++ b/README.md
@@ -56,6 +56,7 @@ print(id_data['citizenship'])
 * CAN - Canada
 * CHL - Chile
 * CHN - China
+* ESP - Spain
 * FRA - France
 * GBR - United Kingdom of Great Britain and Northern Ireland
 * HKG - Hong Kong
diff --git a/idnumbers/nationalid/ESP.py b/idnumbers/nationalid/ESP.py
new file mode 100644
index 00000000..cef305af
--- /dev/null
+++ b/idnumbers/nationalid/ESP.py
@@ -0,0 +1,38 @@
+import re
+from types import SimpleNamespace
+from .util import validate_regexp
+
+
+class NationalID:
+    """
+    Spain National ID number
+    Documento Nacional de Identidad (DNI)
+    https://en.wikipedia.org/wiki/National_identification_number#Spain
+    https://es.wikipedia.org/wiki/C%C3%B3digo_de_identificaci%C3%B3n_fiscal
+    https://gist.github.com/afgomez/5691823
+    """
+    METADATA = SimpleNamespace(**{
+        'iso3166_alpha2': 'ES',
+        # length without insignificant chars
+        'min_length': 9,
+        'max_length': 9,
+        'parsable': False,
+        'checksum': True,
+        'regexp': re.compile(r'^(\d{8})([A-Z])$')
+    })
+
+    @staticmethod
+    def validate(id_number: str) -> bool:
+        """
+        Validate the Spain national id number
+        """
+        if not validate_regexp(id_number, NationalID.METADATA.regexp):
+            return False
+        return NationalID.checksum(id_number)
+
+    MAGIC_LETTERS = "TRWAGMYFPDXBNJZSQVHLCKE"
+
+    @staticmethod
+    def checksum(id_number: str) -> bool:
+        idx = int(id_number[:-1]) % 23
+        return NationalID.MAGIC_LETTERS[idx] == id_number[-1]


Test patch:
diff --git a/idnumbers/nationalid/test_ESP.py b/idnumbers/nationalid/test_ESP.py
new file mode 100644
index 00000000..3426f695
--- /dev/null
+++ b/idnumbers/nationalid/test_ESP.py
@@ -0,0 +1,16 @@
+from unittest import TestCase, main
+from idnumbers.nationalid import ESP
+
+
+class TestESPNationalIDValidation(TestCase):
+    def test_normal_case(self):
+        self.assertTrue(ESP.NationalID.validate('12345678Z'))
+        self.assertTrue(ESP.NationalID.validate('10469226V'))
+
+    def test_error_case(self):
+        self.assertFalse(ESP.NationalID.validate('1234567A'))
+        self.assertFalse(ESP.NationalID.validate('12345678A'))
+
+
+if __name__ == '__main__':
+    main()