Repository: joke2k/faker
Pull request #561 (2017-07-23 09:01:29)

Adding an implementation of `identity_card_number` for pl_PL person provider


Patch:
diff --git a/faker/providers/person/pl_PL/__init__.py b/faker/providers/person/pl_PL/__init__.py
index aef9f9d1..94d49150 100644
--- a/faker/providers/person/pl_PL/__init__.py
+++ b/faker/providers/person/pl_PL/__init__.py
@@ -3,6 +3,24 @@ from __future__ import unicode_literals
 from .. import Provider as PersonProvider
 
 
+def checksum_identity_card_number(characters):
+    """
+    Calculates and returns a control digit for given list of characters basing on Identity Card Number standards.
+    """
+    weights_for_check_digit = [7, 3, 1, 0, 7, 3, 1, 7, 3]
+    check_digit = 0
+
+    for i in range(3):
+        check_digit += weights_for_check_digit[i] * (ord(characters[i]) - 55)
+
+    for i in range(4, 9):
+        check_digit += weights_for_check_digit[i] * characters[i]
+
+    check_digit %= 10
+
+    return check_digit
+
+
 class Provider(PersonProvider):
     formats = (
         '{{first_name}} {{last_name}}',
@@ -527,3 +545,29 @@ class Provider(PersonProvider):
     @classmethod
     def last_name(cls):
         return cls.random_element(cls.unisex_last_names)
+
+    @classmethod
+    def identity_card_number(cls):
+        """
+        Returns 9 character Polish Identity Card Number,
+        Polish: Numer Dowodu Osobistego.
+
+        The card number consists of 3 letters followed by 6 digits (for example, ABA300000),
+        of which the first digit (at position 3) is the check digit.
+
+        https://en.wikipedia.org/wiki/Polish_identity_card
+        """
+        identity = []
+
+        for _ in range(3):
+            identity.append(cls.random_letter().upper())
+
+        # it will be overwritten by a checksum
+        identity.append(0)
+
+        for _ in range(5):
+            identity.append(cls.random_digit())
+
+        identity[3] = checksum_identity_card_number(identity)
+
+        return ''.join(str(character) for character in identity)


Test patch:
diff --git a/tests/providers/person.py b/tests/providers/person.py
index 49732ae8..925fd3e7 100644
--- a/tests/providers/person.py
+++ b/tests/providers/person.py
@@ -2,11 +2,14 @@
 
 from __future__ import unicode_literals
 
+import re
 import unittest
 
 from faker import Factory
 from faker.providers.person.ne_NP import Provider as NeProvider
 from faker.providers.person.sv_SE import Provider as SvSEProvider
+from faker.providers.person.pl_PL import (Provider as PlProvider,
+                                          checksum_identity_card_number as pl_checksum_identity_card_number)
 from .. import string_types
 
 
@@ -100,3 +103,20 @@ class TestSvSE(unittest.TestCase):
         self.assertIn(name, SvSEProvider.first_names_male)
         name = self.factory.first_name()
         self.assertIn(name, SvSEProvider.first_names)
+
+
+class TestPlPL(unittest.TestCase):
+
+    def setUp(self):
+        self.factory = Factory.create('pl_PL')
+
+    def test_identity_card_number_checksum(self):
+        self.assertEqual(pl_checksum_identity_card_number(['A', 'I', 'S', 8, 5, 0, 2, 1, 4]), 8)
+        self.assertEqual(pl_checksum_identity_card_number(['A', 'U', 'L', 9, 2, 7, 2, 8, 5]), 9)
+        self.assertEqual(pl_checksum_identity_card_number(['A', 'E', 'I', 2, 5, 1, 8, 2, 4]), 2)
+        self.assertEqual(pl_checksum_identity_card_number(['A', 'H', 'F', 2, 2, 0, 6, 8, 0]), 2)
+        self.assertEqual(pl_checksum_identity_card_number(['A', 'X', 'E', 8, 2, 0, 3, 4, 0]), 8)
+
+    def test_identity_card_number(self):
+        for _ in range(100):
+            self.assertTrue(re.search(r'^[A-Z]{3}\d{6}$', PlProvider.identity_card_number()))