Repository: identique/idnumbers (language: python)

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


Discussion / hints:

Fix patch:
diff --git a/idnumbers/nationalid/BHR.py b/idnumbers/nationalid/BHR.py
new file mode 100644
index 00000000..a6d9c169
--- /dev/null
+++ b/idnumbers/nationalid/BHR.py
@@ -0,0 +1,63 @@
+import re
+from types import SimpleNamespace
+from typing import Optional, TypedDict
+from .util import CHECK_DIGIT
+
+
+class ParseResult(TypedDict):
+    yymm: str
+    """birthday of this ID"""
+    sn: str
+    """serial number"""
+    checksum: CHECK_DIGIT
+    """checksum"""
+
+
+class PersonalNumber:
+    """
+    Bahrain Personal Number, Identification Card Number, Arabic:  الرقم الشخصي
+    https://en.wikipedia.org/wiki/National_identification_number#Bahrain
+    * According to the doc, we can know it has checksum algorithm. But we cannot find it.
+    """
+    METADATA = SimpleNamespace(**{
+        'iso3166_alpha2': 'BH',
+        'min_length': 9,
+        'max_length': 9,
+        'parsable': True,
+        'checksum': False,
+        'regexp': re.compile(r'^(?P<yymm>\d{2}(?:0[1-9]|1[012]))'
+                             r'(?P<sn>\d{4})'
+                             r'(?P<checksum>\d)$')
+    })
+
+    @staticmethod
+    def validate(id_number: str) -> bool:
+        """
+        Validate the civil number
+        """
+        if not id_number:
+            return False
+
+        if not isinstance(id_number, str):
+            id_number = repr(id_number)
+        return PersonalNumber.parse(id_number) is not None
+
+    @staticmethod
+    def parse(id_number: str) -> Optional[ParseResult]:
+        """
+        parse the id number
+        """
+        match_obj = PersonalNumber.METADATA.regexp.match(id_number)
+        if not match_obj:
+            return None
+
+        # TODO: find and implement checksum
+        return {
+            'yymm': match_obj.group('yymm'),
+            'sn': match_obj.group('sn'),
+            'checksum': int(match_obj.group('checksum'))
+        }
+
+
+NationalID = PersonalNumber
+"""alias of PersonalNumber"""


Test patch:
diff --git a/tests/nationalid/test_BHR.py b/tests/nationalid/test_BHR.py
new file mode 100644
index 00000000..59a09c48
--- /dev/null
+++ b/tests/nationalid/test_BHR.py
@@ -0,0 +1,17 @@
+from unittest import TestCase
+
+from idnumbers.nationalid import BHR
+
+
+class TestBHRValidation(TestCase):
+    def test_normal_case(self):
+        self.assertTrue(BHR.NationalID.validate('051108109'))
+
+    def test_error_case(self):
+        self.assertFalse(BHR.NationalID.validate('053108109'))
+
+    def test_parse(self):
+        result = BHR.NationalID.parse('051108109')
+        self.assertEqual('0511', result['yymm'])
+        self.assertEqual('0810', result['sn'])
+        self.assertEqual(9, result['checksum'])