Repository: joke2k/faker
Pull request #954 (2019-05-10 17:57:22)

Pldevelop
### What does this changes

PESEL and automotive plates for Poland with tests.


adwojak: Can You help me fix issues in my pull request? AppVeroy build fails but I think that's not from my fault. Also coverage has decreased. Do I need to write more tests for my functionality to increase tests coverage? Honestly, it is my first contribution to someone's repo and I don't know how to handle that problems :)
fcurella: Thank you @adwojak !

I've created #955 to fix the build. Once that's merged in, feel free to rebase your branch against master and force-push your branch.

I wouldn't worry about a 0.04 decrease in 
adwojak: Thanks for help, all checks are successfull :) So for now, I don't have to do nothing more? :)
fcurella: @adwojak That's all! Thank you very much :) ✨ 

Patch:
diff --git a/faker/providers/automotive/pl_PL/__init__.py b/faker/providers/automotive/pl_PL/__init__.py
new file mode 100644
index 00000000..965a996b
--- /dev/null
+++ b/faker/providers/automotive/pl_PL/__init__.py
@@ -0,0 +1,28 @@
+# coding=utf-8
+
+from __future__ import unicode_literals
+from .. import Provider as AutomotiveProvider
+
+
+class Provider(AutomotiveProvider):
+    # from
+    # https://en.wikipedia.org/wiki/Vehicle_registration_plates_of_Poland
+    license_formats = (
+        '?? #####',
+        '?? ####?',
+        '?? ###??',
+        '?? #?###',
+        '?? #??##',
+        '??? ?###',
+        '??? ##??',
+        '??? #?##',
+        '??? ##?#',
+        '??? #??#',
+        '??? ??##',
+        '??? #####',
+        '??? ####?',
+        '??? ###??',
+    )
+
+    def license_plate_regex_formats(self):
+        return [plate.replace('?', '[A-Z]').replace('#', '[0-9]') for plate in self.license_formats]
diff --git a/faker/providers/person/pl_PL/__init__.py b/faker/providers/person/pl_PL/__init__.py
index 11c17670..49c622df 100644
--- a/faker/providers/person/pl_PL/__init__.py
+++ b/faker/providers/person/pl_PL/__init__.py
@@ -21,6 +21,28 @@ def checksum_identity_card_number(characters):
     return check_digit
 
 
+def generate_pesel_checksum_value(pesel_digits):
+    """
+    Calculates and returns a control digit for given PESEL.
+    """
+    checksum_values = [9, 7, 3, 1, 9, 7, 3, 1, 9, 7]
+
+    checksum = sum((int(a) * b for a, b in zip(list(pesel_digits), checksum_values)))
+
+    return checksum % 10
+
+
+def checksum_pesel_number(pesel_digits):
+    """
+    Calculates and returns True if PESEL is valid.
+    """
+    checksum_values = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3, 1]
+
+    checksum = sum((int(a) * b for a, b in zip(list(pesel_digits), checksum_values)))
+
+    return checksum % 10 == 0
+
+
 class Provider(PersonProvider):
     formats = (
         '{{first_name}} {{last_name}}',
@@ -702,3 +724,31 @@ class Provider(PersonProvider):
         identity[3] = checksum_identity_card_number(identity)
 
         return ''.join(str(character) for character in identity)
+
+    def pesel(self):
+        """
+        Returns 11 characters of Universal Electronic System for Registration of the Population.
+        Polish: Powszechny Elektroniczny System Ewidencji Ludności.
+
+        PESEL has 11 digits which identifies just one person.
+        Month: if person was born in 1900-2000, december is 12. If person was born > 2000, we have to add 20 to month,
+        so december is 32.
+        Person id: last digit identifies person's sex. Even for females, odd for males.
+
+        https://en.wikipedia.org/wiki/PESEL
+        """
+
+        birth = self.generator.date_of_birth()
+
+        year_pesel = str(birth.year)[-2:]
+        month_pesel = birth.month if birth.year < 2000 else birth.month + 20
+        day_pesel = birth.day
+        person_id = self.random_int(1000, 9999)
+
+        current_pesel = '{year}{month:02d}{day:02d}{person_id:04d}'.format(year=year_pesel, month=month_pesel,
+                                                                           day=day_pesel,
+                                                                           person_id=person_id)
+
+        checksum_value = generate_pesel_checksum_value(current_pesel)
+        return '{pesel_without_checksum}{checksum_value}'.format(pesel_without_checksum=current_pesel,
+                                                                 checksum_value=checksum_value)


Test patch:
diff --git a/tests/providers/test_automotive.py b/tests/providers/test_automotive.py
index 88c57c5c..20f3c39e 100644
--- a/tests/providers/test_automotive.py
+++ b/tests/providers/test_automotive.py
@@ -49,3 +49,15 @@ class TestSvSE(unittest.TestCase):
     def test_sv_SE_plate_format(self):
         plate = self.factory.license_plate()
         assert re.match(r"[A-Z]{3} \d{2}[\dA-Z]{1}", plate), "%s is not in the correct format." % plate
+
+
+class TestPlPL(unittest.TestCase):
+
+    def setUp(self):
+        self.factory = Faker('pl_PL')
+
+    def test_pl_PL_plate_format(self):
+        plate = self.factory.license_plate()
+        patterns = self.factory.license_plate_regex_formats()
+        assert re.match(r'{patterns}'.format(patterns='|'.join(patterns)),
+                        plate), '{plate} is not the correct format.'.format(plate=plate)
diff --git a/tests/providers/test_person.py b/tests/providers/test_person.py
index 517a9a38..3767ef4d 100644
--- a/tests/providers/test_person.py
+++ b/tests/providers/test_person.py
@@ -16,6 +16,7 @@ from faker.providers.person.sv_SE import Provider as SvSEProvider
 from faker.providers.person.cs_CZ import Provider as CsCZProvider
 from faker.providers.person.pl_PL import (
     checksum_identity_card_number as pl_checksum_identity_card_number,
+    checksum_pesel_number as pl_checksum_pesel_number,
 )
 from faker.providers.person.zh_CN import Provider as ZhCNProvider
 from faker.providers.person.zh_TW import Provider as ZhTWProvider
@@ -206,6 +207,14 @@ class TestPlPL(unittest.TestCase):
         for _ in range(100):
             assert re.search(r'^[A-Z]{3}\d{6}$', self.factory.identity_card_number())
 
+    def test_pesel_number_checksum(self):
+        assert pl_checksum_pesel_number('31090655159') is True
+        assert pl_checksum_pesel_number('95030853577') is True
+        assert pl_checksum_pesel_number('05260953442') is True
+        assert pl_checksum_pesel_number('31090655158') is False
+        assert pl_checksum_pesel_number('95030853576') is False
+        assert pl_checksum_pesel_number('05260953441') is False
+
 
 class TestCsCZ(unittest.TestCase):