Hello community,
here is the log from the commit of package python-Faker for openSUSE:Factory checked in at 2019-08-05 11:18:08
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-Faker (Old)
and /work/SRC/openSUSE:Factory/.python-Faker.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-Faker"
Mon Aug 5 11:18:08 2019 rev:12 rq:718191 version:2.0.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-Faker/python-Faker.changes 2019-05-27 08:36:01.619126137 +0200
+++ /work/SRC/openSUSE:Factory/.python-Faker.new.4126/python-Faker.changes 2019-08-05 11:18:10.502516115 +0200
@@ -1,0 +2,18 @@
+Wed Jul 24 09:39:48 UTC 2019 - Marketa Calabkova
+
+- update to version 2.0.0
+ * Breaking change: Only allow providers to use OrderedDict s, to
+ avoid any more PYTHONHASHSEED problems.
+ * Remove some validations from Faker and delegate it to an
+ external library, validators.
+ * Add an "Invalid SSN" generator to the en_US SSN Provider.
+ * Loosen version restrictions on freezegun and random2.
+ * Add date_of_birth and sex argument to pesel Provider (pl_PL).
+ * Fix datetime parsing on environments with negative offsets.
+
+-------------------------------------------------------------------
+Fri Jul 19 20:16:51 UTC 2019 - Sean Marlow
+
+- Update ipaddress requirements.
+
+-------------------------------------------------------------------
Old:
----
Faker-1.0.7.tar.gz
New:
----
Faker-2.0.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-Faker.spec ++++++
--- /var/tmp/diff_new_pack.2sZXjC/_old 2019-08-05 11:18:11.346515769 +0200
+++ /var/tmp/diff_new_pack.2sZXjC/_new 2019-08-05 11:18:11.346515769 +0200
@@ -19,7 +19,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define oldpython python
Name: python-Faker
-Version: 1.0.7
+Version: 2.0.0
Release: 0
Summary: Python package that generates fake data
License: MIT
@@ -27,19 +27,19 @@
URL: https://github.com/joke2k/faker
Source: https://files.pythonhosted.org/packages/source/F/Faker/Faker-%{version}.tar.gz
BuildRequires: %{python_module UkPostcodeParser >= 1.1.1}
-BuildRequires: %{python_module email_validator >= 1.0.2}
-BuildRequires: %{python_module freezegun >= 0.3.11}
+BuildRequires: %{python_module freezegun}
BuildRequires: %{python_module mock}
-BuildRequires: %{python_module more-itertools}
BuildRequires: %{python_module pytest >= 3.8.0}
+BuildRequires: %{python_module pytest-runner}
BuildRequires: %{python_module python-dateutil >= 2.4}
-BuildRequires: %{python_module random2 >= 1.0.1}
+BuildRequires: %{python_module random2}
BuildRequires: %{python_module setuptools}
BuildRequires: %{python_module six >= 1.10}
BuildRequires: %{python_module text-unidecode >= 1.2}
+BuildRequires: %{python_module validators >= 0.13.0}
BuildRequires: fdupes
-BuildRequires: python-ipaddress
BuildRequires: python-rpm-macros
+BuildRequires: python2-ipaddress
Requires: python-python-dateutil >= 2.4
Requires: python-setuptools
Requires: python-six >= 1.10
@@ -47,9 +47,8 @@
Requires(post): update-alternatives
Requires(postun): update-alternatives
BuildArch: noarch
-BuildRequires: %{python_module pytest-runner}
%ifpython2
-Requires: python-ipaddress
+Requires: python2-ipaddress
Obsoletes: %{oldpython}-fake-factory < %{version}
Provides: %{oldpython}-fake-factory = %{version}
%endif
++++++ Faker-1.0.7.tar.gz -> Faker-2.0.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/CHANGELOG.rst new/Faker-2.0.0/CHANGELOG.rst
--- old/Faker-1.0.7/CHANGELOG.rst 2019-05-14 17:55:14.000000000 +0200
+++ new/Faker-2.0.0/CHANGELOG.rst 2019-07-15 16:41:26.000000000 +0200
@@ -1,6 +1,23 @@
Changelog
=========
+`2.0.0 - 15-July-2019 https://github.com/joke2k/faker/compare/v2.0.0...v1.0.8`__
+----------------------------------------------------------------------------------
+* Breaking change: Only allow providers to use ``OrderedDict`` s, to avoid any more ``PYTHONHASHSEED`` problems. Thanks @adamchainz.
+
+`1.0.8 - 15-July-2019 https://github.com/joke2k/faker/compare/v1.0.7...v1.0.8`__
+----------------------------------------------------------------------------------
+
+* Rename ``pyint`` ``min`` and ``max`` to ``min_value`` and ``max_value``. Thanks @francoisfreitag.
+* Remove some validations from Faker and delegate it to an external library, ``validators``. Thanks @kingbuzzman.
+* Add an "Invalid SSN" generator to the ``en_US`` SSN Provider. Thanks @darrylwhiting.
+* Include "Praia" as street_prefix in ``pr_BR`` address Provider. Thanks @G5Olivieri.
+* Loosen version restrictions on ``freezegun`` and ``random2``. Thanks @timokau.
+* Add SSN provider for ``es_MX``. Thanks @mrfunnyshoes.
+* Add ``pwz`` generator for ``pl_PL``. Thanks @torm89.
+* Add ``date_of_birth`` and ``sex`` argument to ``pesel`` Provider (`pl_PL`). Thanks @torm89.
+* Fix datetime parsing on environments with negative offsets. Thanks @bluesheeptoken.
+
`1.0.7 - 14-May-2019 https://github.com/joke2k/faker/compare/v1.0.6...v1.0.7`__
---------------------------------------------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/Faker.egg-info/PKG-INFO new/Faker-2.0.0/Faker.egg-info/PKG-INFO
--- old/Faker-1.0.7/Faker.egg-info/PKG-INFO 2019-05-14 18:11:36.000000000 +0200
+++ new/Faker-2.0.0/Faker.egg-info/PKG-INFO 2019-07-15 16:58:24.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.2
Name: Faker
-Version: 1.0.7
+Version: 2.0.0
Summary: Faker is a Python package that generates fake data for you.
Home-page: https://github.com/joke2k/faker
Author: joke2k
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/Faker.egg-info/SOURCES.txt new/Faker-2.0.0/Faker.egg-info/SOURCES.txt
--- old/Faker-1.0.7/Faker.egg-info/SOURCES.txt 2019-05-14 18:11:36.000000000 +0200
+++ new/Faker-2.0.0/Faker.egg-info/SOURCES.txt 2019-07-15 16:58:24.000000000 +0200
@@ -3,6 +3,7 @@
LICENSE.txt
MANIFEST.in
README.rst
+RELEASE_PROCESS.rst
VERSION
setup.cfg
setup.py
@@ -342,6 +343,7 @@
faker/providers/ssn/en_US/__init__.py
faker/providers/ssn/es_CA/__init__.py
faker/providers/ssn/es_ES/__init__.py
+faker/providers/ssn/es_MX/__init__.py
faker/providers/ssn/et_EE/__init__.py
faker/providers/ssn/fi_FI/__init__.py
faker/providers/ssn/fr_CH/__init__.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/MANIFEST.in new/Faker-2.0.0/MANIFEST.in
--- old/Faker-1.0.7/MANIFEST.in 2019-04-15 17:09:53.000000000 +0200
+++ new/Faker-2.0.0/MANIFEST.in 2019-07-15 16:44:46.000000000 +0200
@@ -2,6 +2,7 @@
include LICENSE.txt
include CONTRIBUTING.rst
include CHANGELOG.rst
+include RELEASE_PROCESS.rst
include VERSION
recursive-include tests *.json
recursive-include tests *.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/PKG-INFO new/Faker-2.0.0/PKG-INFO
--- old/Faker-1.0.7/PKG-INFO 2019-05-14 18:11:37.000000000 +0200
+++ new/Faker-2.0.0/PKG-INFO 2019-07-15 16:58:25.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.2
Name: Faker
-Version: 1.0.7
+Version: 2.0.0
Summary: Faker is a Python package that generates fake data for you.
Home-page: https://github.com/joke2k/faker
Author: joke2k
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/RELEASE_PROCESS.rst new/Faker-2.0.0/RELEASE_PROCESS.rst
--- old/Faker-1.0.7/RELEASE_PROCESS.rst 1970-01-01 01:00:00.000000000 +0100
+++ new/Faker-2.0.0/RELEASE_PROCESS.rst 2019-07-15 16:35:50.000000000 +0200
@@ -0,0 +1,11 @@
+Release Process
+---------------
+
+1. Compile entries in ``CHANGELOG.rst``. Each entry should:
+
+ * Be in the past tense (eg "Fix datetime on Windows")
+ * End with acknowledging the PR author(s): "Thanks @<github username>."
+
+2. Run ``bumpversion ``.
+3. Check the commit generated by ``bumpversion``, then ``git push``.
+4. Run ``make release``.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/VERSION new/Faker-2.0.0/VERSION
--- old/Faker-1.0.7/VERSION 2019-05-14 18:10:06.000000000 +0200
+++ new/Faker-2.0.0/VERSION 2019-07-15 16:57:52.000000000 +0200
@@ -1 +1 @@
-1.0.7
+2.0.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/faker/__init__.py new/Faker-2.0.0/faker/__init__.py
--- old/Faker-1.0.7/faker/__init__.py 2019-05-14 18:10:06.000000000 +0200
+++ new/Faker-2.0.0/faker/__init__.py 2019-07-15 16:57:52.000000000 +0200
@@ -1,6 +1,6 @@
from faker.generator import Generator # noqa F401
from faker.factory import Factory # noqa F401
-VERSION = '1.0.7'
+VERSION = '2.0.0'
Faker = Factory.create
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/faker/providers/__init__.py new/Faker-2.0.0/faker/providers/__init__.py
--- old/Faker-1.0.7/faker/providers/__init__.py 2019-04-15 17:09:53.000000000 +0200
+++ new/Faker-2.0.0/faker/providers/__init__.py 2019-07-15 16:39:47.000000000 +0200
@@ -3,6 +3,8 @@
import re
import string
+from collections import OrderedDict
+
from faker.utils.distribution import choices_distribution, choices_distribution_unique
@@ -178,6 +180,9 @@
return self.generator.random.choice(string.ascii_uppercase)
def random_elements(self, elements=('a', 'b', 'c'), length=None, unique=False):
+ if isinstance(elements, dict) and not isinstance(elements, OrderedDict):
+ raise ValueError("Use OrderedDict only to avoid dependency on PYTHONHASHSEED (See #363).")
+
fn = choices_distribution_unique if unique else choices_distribution
if length is None:
@@ -208,10 +213,15 @@
"""
Returns a list of random, non-unique elements from a passed object.
- If `elements` is a dictionary, the value will be used as
- a weighting element. For example::
+ If `elements` is an OrderedDict, the value will be used as a weighting
+ element. For example::
- random_element({"{{variable_1}}": 0.5, "{{variable_2}}": 0.2, "{{variable_3}}": 0.2, "{{variable_4}}": 0.1})
+ random_element(OrderedDict([
+ ("{{variable_1}}", 0.5),
+ ("{{variable_2}}", 0.2),
+ ("{{variable_3}}", 0.2),
+ ("{{variable_4}}": 0.1)
+ ])
will have the following distribution:
* `variable_1`: 50% probability
@@ -226,10 +236,15 @@
"""
Returns a random element from a passed object.
- If `elements` is a dictionary, the value will be used as
- a weighting element. For example::
+ If `elements` is an OrderedDict, the value will be used as a weighting
+ element. For example::
- random_element({"{{variable_1}}": 0.5, "{{variable_2}}": 0.2, "{{variable_3}}": 0.2, "{{variable_4}}": 0.1})
+ random_element(OrderedDict([
+ ("{{variable_1}}", 0.5),
+ ("{{variable_2}}", 0.2),
+ ("{{variable_3}}", 0.2),
+ ("{{variable_4}}": 0.1)
+ ])
will have the following distribution:
* `variable_1`: 50% probability
@@ -238,6 +253,7 @@
* `variable_4`: 10% probability
"""
+
return self.random_elements(elements, length=1)[0]
def random_sample(self, elements=('a', 'b', 'c'), length=None):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/faker/providers/address/no_NO/__init__.py new/Faker-2.0.0/faker/providers/address/no_NO/__init__.py
--- old/Faker-1.0.7/faker/providers/address/no_NO/__init__.py 2019-03-05 18:07:52.000000000 +0100
+++ new/Faker-2.0.0/faker/providers/address/no_NO/__init__.py 2019-07-15 16:39:47.000000000 +0200
@@ -1,6 +1,8 @@
# coding=utf-8
from __future__ import unicode_literals
+from collections import OrderedDict
+
from .. import Provider as AddressProvider
@@ -26,9 +28,16 @@
street_address_formats = ('{{street_name}} {{building_number}}',)
address_formats = ('{{street_address}}, {{postcode}} {{city}}',)
building_number_formats = ('%', '%', '%', '%?', '##', '##', '##?', '###')
- building_number_suffixes = {
- 'A': 0.2, 'B': 0.2, 'C': 0.2, 'D': 0.1, 'E': 0.1, 'F': 0.1, 'G': 0.05,
- 'H': 0.05}
+ building_number_suffixes = OrderedDict([
+ ('A', 0.2),
+ ('B', 0.2),
+ ('C', 0.2),
+ ('D', 0.1),
+ ('E', 0.1),
+ ('F', 0.1),
+ ('G', 0.05),
+ ('H', 0.05),
+ ])
postcode_formats = ('####',)
def building_number(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/faker/providers/address/pt_BR/__init__.py new/Faker-2.0.0/faker/providers/address/pt_BR/__init__.py
--- old/Faker-1.0.7/faker/providers/address/pt_BR/__init__.py 2019-03-05 18:07:52.000000000 +0100
+++ new/Faker-2.0.0/faker/providers/address/pt_BR/__init__.py 2019-07-12 17:17:07.000000000 +0200
@@ -53,6 +53,7 @@
'Passarela',
'Pátio',
'Praça',
+ 'Praia',
'Quadra',
'Recanto',
'Residencial',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/faker/providers/date_time/__init__.py new/Faker-2.0.0/faker/providers/date_time/__init__.py
--- old/Faker-1.0.7/faker/providers/date_time/__init__.py 2019-04-12 17:10:07.000000000 +0200
+++ new/Faker-2.0.0/faker/providers/date_time/__init__.py 2019-07-15 16:35:50.000000000 +0200
@@ -6,7 +6,6 @@
from calendar import timegm
from datetime import timedelta, MAXYEAR
-from time import time
from dateutil import relativedelta
from dateutil.tz import tzlocal, tzutc
@@ -1474,7 +1473,7 @@
@classmethod
def _parse_end_datetime(cls, value):
if value is None:
- return int(time())
+ return datetime_to_timestamp(datetime.now())
return cls._parse_date_time(value)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/faker/providers/person/et_EE/__init__.py new/Faker-2.0.0/faker/providers/person/et_EE/__init__.py
--- old/Faker-1.0.7/faker/providers/person/et_EE/__init__.py 2017-12-05 16:57:34.000000000 +0100
+++ new/Faker-2.0.0/faker/providers/person/et_EE/__init__.py 2019-07-15 16:39:47.000000000 +0200
@@ -1,5 +1,8 @@
# coding=utf-8
from __future__ import unicode_literals
+
+from collections import OrderedDict
+
from .. import Provider as PersonProvider
@@ -9,13 +12,20 @@
# About 70% of the population are Estonians and about 25% are Russians
est_rat = 0.7
rus_rat = 1.0 - est_rat
- formats = {'{{first_name_est}} {{last_name_est}}': est_rat,
- '{{first_name_rus}} {{last_name_rus}}': rus_rat}
+ formats = OrderedDict([
+ ('{{first_name_est}} {{last_name_est}}', est_rat),
+ ('{{first_name_rus}} {{last_name_rus}}', rus_rat),
+ ])
+
+ formats_male = OrderedDict([
+ ('{{first_name_male_est}} {{last_name_est}}', est_rat),
+ ('{{first_name_male_rus}} {{last_name_rus}}', rus_rat),
+ ])
- formats_male = {'{{first_name_male_est}} {{last_name_est}}': est_rat,
- '{{first_name_male_rus}} {{last_name_rus}}': rus_rat}
- formats_female = {'{{first_name_female_est}} {{last_name_est}}': est_rat,
- '{{first_name_female_rus}} {{last_name_rus}}': rus_rat}
+ formats_female = OrderedDict([
+ ('{{first_name_female_est}} {{last_name_est}}', est_rat),
+ ('{{first_name_female_rus}} {{last_name_rus}}', rus_rat),
+ ])
prefixes_neutral = ('doktor', 'dr', 'prof')
prefixes_male = ('härra', 'hr') + prefixes_neutral
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/faker/providers/person/pl_PL/__init__.py new/Faker-2.0.0/faker/providers/person/pl_PL/__init__.py
--- old/Faker-1.0.7/faker/providers/person/pl_PL/__init__.py 2019-05-14 17:28:28.000000000 +0200
+++ new/Faker-2.0.0/faker/providers/person/pl_PL/__init__.py 2019-07-15 16:35:50.000000000 +0200
@@ -21,28 +21,6 @@
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}}',
@@ -725,30 +703,74 @@
return ''.join(str(character) for character in identity)
- def pesel(self):
+ @staticmethod
+ def pesel_compute_check_digit(pesel):
+ checksum_values = [9, 7, 3, 1, 9, 7, 3, 1, 9, 7]
+ return sum(int(a) * b for a, b in zip(pesel, checksum_values)) % 10
+
+ def pesel(self, date_of_birth=None, sex=None):
"""
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.
+ pesel_date: 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.
+ pesel_sex: last digit identifies person's sex. Even for females, odd for males.
https://en.wikipedia.org/wiki/PESEL
"""
+ if date_of_birth is None:
+ date_of_birth = self.generator.date_of_birth()
+
+ pesel_date = '{year}{month:02d}{day:02d}'.format(
+ year=date_of_birth.year, day=date_of_birth.day,
+ month=date_of_birth.month if date_of_birth.year < 2000 else date_of_birth.month + 20)
+ pesel_date = pesel_date[2:]
+
+ pesel_core = ''.join(map(str, (self.random_digit() for _ in range(3))))
+ pesel_sex = self.random_digit()
+
+ if (sex == 'M' and pesel_sex % 2 == 0) or (sex == 'F' and pesel_sex % 2 == 1):
+ pesel_sex = (pesel_sex + 1) % 10
+
+ pesel = '{date}{core}{sex}'.format(date=pesel_date, core=pesel_core, sex=pesel_sex)
+ pesel += str(self.pesel_compute_check_digit(pesel))
+
+ return pesel
+
+ @staticmethod
+ def pwz_doctor_compute_check_digit(x):
+ return sum((i+1)*d for i, d in enumerate(x)) % 11
+
+ def pwz_doctor(self):
+ """
+ Function generates an identification number for medical doctors
+ Polish: Prawo Wykonywania Zawodu (PWZ)
+
+ https://www.nil.org.pl/rejestry/centralny-rejestr-lekarzy/zasady-weryfikowan...
+ """
+ core = [self.random_digit() for _ in range(6)]
+ check_digit = self.pwz_doctor_compute_check_digit(core)
+
+ if check_digit == 0:
+ core[-1] = (core[-1] + 1) % 10
+ check_digit = self.pwz_doctor_compute_check_digit(core)
+
+ return '{}{}'.format(check_digit, ''.join(map(str, core)))
+
+ def pwz_nurse(self, kind='nurse'):
+ """
+ Function generates an identification number for nurses and midwives
+ Polish: Prawo Wykonywania Zawodu (PWZ)
- birth = self.generator.date_of_birth()
+ http://arch.nipip.pl/index.php/prawo/uchwaly/naczelnych-rad/w-roku-2015/posi...
+ nr-381-vi-2015-w-sprawie-trybu-postepowania-dotyczacego-stwierdzania-i-przyznawania-prawa-wykonywania-zawodu-pi
+ elegniarki-i-zawodu-poloznej-oraz-sposobu-prowadzenia-rejestru-pielegniarek-i-rejestru-poloznych-przez-okregowe
+ -rady-pielegniarek-i-polo
+ """
+ region = self.random_int(1, 45)
+ core = [self.random_digit() for _ in range(5)]
+ kind_char = 'A' if kind == 'midwife' else 'P'
- 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)
+ return '{:02d}{}{}'.format(region, ''.join(map(str, core)), kind_char)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/faker/providers/python/__init__.py new/Faker-2.0.0/faker/providers/python/__init__.py
--- old/Faker-1.0.7/faker/providers/python/__init__.py 2019-05-14 17:28:28.000000000 +0200
+++ new/Faker-2.0.0/faker/providers/python/__init__.py 2019-07-12 17:17:07.000000000 +0200
@@ -71,8 +71,8 @@
self.random_number(right_digits),
))
- def pyint(self, min=0, max=9999, step=1):
- return self.generator.random_int(min, max, step=step)
+ def pyint(self, min_value=0, max_value=9999, step=1):
+ return self.generator.random_int(min_value, max_value, step=step)
def pydecimal(self, left_digits=None, right_digits=None, positive=False,
min_value=None, max_value=None):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/faker/providers/ssn/en_US/__init__.py new/Faker-2.0.0/faker/providers/ssn/en_US/__init__.py
--- old/Faker-1.0.7/faker/providers/ssn/en_US/__init__.py 2019-03-05 18:07:52.000000000 +0100
+++ new/Faker-2.0.0/faker/providers/ssn/en_US/__init__.py 2019-07-12 17:17:07.000000000 +0200
@@ -6,6 +6,7 @@
class Provider(BaseProvider):
+ INVALID_SSN_TYPE = 'INVALID_SSN'
SSN_TYPE = 'SSN'
ITIN_TYPE = 'ITIN'
EIN_TYPE = 'EIN'
@@ -139,6 +140,68 @@
ein = "{0:s}-{1:07d}".format(ein_prefix, sequence)
return ein
+ def invalid_ssn(self):
+ """ Generate a random invalid United States Social Security Identification Number (SSN).
+
+ Invalid SSNs have the following characteristics:
+ Cannot begin with the number 9
+ Cannot begin with 666 in positions 1 - 3
+ Cannot begin with 000 in positions 1 - 3
+ Cannot contain 00 in positions 4 - 5
+ Cannot contain 0000 in positions 6 - 9
+
+ https://www.ssa.gov/kc/SSAFactSheet--IssuingSSNs.pdf
+
+ Additionally, return an invalid SSN that is NOT a valid ITIN by excluding certain ITIN related "group" values
+ """
+ itin_group_numbers = [
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 88,
+ 90,
+ 91,
+ 92,
+ 94,
+ 95,
+ 96,
+ 97,
+ 98,
+ 99]
+ area = self.random_int(min=0, max=999)
+ if area < 900 and area not in {666, 0}:
+ random_group_or_serial = self.random_int(min=1, max=1000)
+ if random_group_or_serial <= 500:
+ group = 0
+ serial = self.random_int(0, 9999)
+ else:
+ group = self.random_int(0, 99)
+ serial = 0
+ elif area in {666, 0}:
+ group = self.random_int(0, 99)
+ serial = self.random_int(0, 9999)
+ else:
+ group = random.choice([x for x in range(0, 100) if x not in itin_group_numbers])
+ serial = self.random_int(0, 9999)
+
+ invalid_ssn = "{0:03d}-{1:02d}-{2:04d}".format(area, group, serial)
+ return invalid_ssn
+
def ssn(self, taxpayer_identification_number_type=SSN_TYPE):
""" Generate a random United States Taxpayer Identification Number of the specified type.
@@ -149,6 +212,8 @@
return self.itin()
elif taxpayer_identification_number_type == self.EIN_TYPE:
return self.ein()
+ elif taxpayer_identification_number_type == self.INVALID_SSN_TYPE:
+ return self.invalid_ssn()
elif taxpayer_identification_number_type == self.SSN_TYPE:
# Certain numbers are invalid for United States Social Security
@@ -166,4 +231,5 @@
return ssn
else:
- raise ValueError("taxpayer_identification_number_type must be one of 'SSN', 'EIN', or 'ITIN'.")
+ raise ValueError("taxpayer_identification_number_type must be one of 'SSN', 'EIN', 'ITIN',"
+ " or 'INVALID_SSN'.")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/faker/providers/ssn/es_MX/__init__.py new/Faker-2.0.0/faker/providers/ssn/es_MX/__init__.py
--- old/Faker-1.0.7/faker/providers/ssn/es_MX/__init__.py 1970-01-01 01:00:00.000000000 +0100
+++ new/Faker-2.0.0/faker/providers/ssn/es_MX/__init__.py 2019-07-12 17:17:07.000000000 +0200
@@ -0,0 +1,254 @@
+# coding=utf-8
+"""
+SSN provider for es_MX.
+
+This module adds a provider for mexican SSN, along with Unique Population
+Registry Code (CURP) and Federal Taxpayer Registry ID (RFC).
+"""
+
+
+from __future__ import unicode_literals
+
+import random
+import string
+
+from .. import Provider as BaseProvider
+
+
+ALPHABET = string.ascii_uppercase
+ALPHANUMERIC = string.digits + ALPHABET
+VOWELS = "AEIOU"
+CONSONANTS = [
+ letter
+ for letter in ALPHABET
+ if letter not in VOWELS
+]
+
+# https://es.wikipedia.org/wiki/Plantilla:Abreviaciones_de_los_estados_de_M%C3...
+STATES_RENAPO = [
+ "AS",
+ "BC",
+ "BS",
+ "CC",
+ "CS",
+ "CH",
+ "DF",
+ "CL",
+ "CM",
+ "DG",
+ "GT",
+ "GR",
+ "HG",
+ "JC",
+ "MC",
+ "MN",
+ "MS",
+ "NT",
+ "NL",
+ "OC",
+ "PL",
+ "QO",
+ "QR",
+ "SP",
+ "SL",
+ "SR",
+ "TC",
+ "TS",
+ "TL",
+ "VZ",
+ "YN",
+ "ZS",
+ "NE", # Foreign Born
+]
+
+FORBIDDEN_WORDS = {
+ "BUEI": "BUEX",
+ "BUEY": "BUEX",
+ "CACA": "CACX",
+ "CACO": "CACX",
+ "CAGA": "CAGX",
+ "CAGO": "CAGX",
+ "CAKA": "CAKX",
+ "CAKO": "CAKX",
+ "COGE": "COGX",
+ "COJA": "COJX",
+ "COJE": "COJX",
+ "COJI": "COJX",
+ "COJO": "COJX",
+ "CULO": "CULX",
+ "FETO": "FETX",
+ "GUEY": "GUEX",
+ "JOTO": "JOTX",
+ "KACA": "KACX",
+ "KACO": "KACX",
+ "KAGA": "KAGX",
+ "KAGO": "KAGX",
+ "KOGE": "KOGX",
+ "KOJO": "KOJX",
+ "KAKA": "KAKX",
+ "KULO": "KULX",
+ "MAME": "MAMX",
+ "MAMO": "MAMX",
+ "MEAR": "MEAX",
+ "MEAS": "MEAX",
+ "MEON": "MEOX",
+ "MION": "MIOX",
+ "MOCO": "MOCX",
+ "MULA": "MULX",
+ "PEDA": "PEDX",
+ "PEDO": "PEDX",
+ "PENE": "PENX",
+ "PUTA": "PUTX",
+ "PUTO": "PUTX",
+ "QULO": "QULX",
+ "RATA": "RATX",
+ "RUIN": "RUIN",
+}
+
+CURP_CHARACTERS = "0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"
+
+
+def _reduce_digits(number):
+ """
+ Sum of digits of a number until sum becomes single digit.
+
+ Example:
+ 658 => 6 + 5 + 8 = 19 => 1 + 9 = 10 => 1
+ """
+ if number == 0:
+ return 0
+ if number % 9 == 0:
+ return 9
+
+ return number % 9
+
+
+def ssn_checksum(digits):
+ """
+ Calculate the checksum for the mexican SSN (IMSS).
+ """
+ return -sum(
+ _reduce_digits(n * (i % 2 + 1))
+ for i, n in enumerate(digits)
+ ) % 10
+
+
+def curp_checksum(characters):
+ """
+ Calculate the checksum for the mexican CURP.
+ """
+ start = 18
+ return -sum(
+ (start - i) * CURP_CHARACTERS.index(n)
+ for i, n in enumerate(characters)
+ ) % 10
+
+
+class Provider(BaseProvider):
+ """
+ A Faker provider for the Mexican SSN, RFC and CURP
+ """
+ ssn_formats = ("###########",)
+
+ def ssn(self):
+ """
+ Mexican Social Security Number, as given by IMSS.
+
+ :return: a random Mexican SSN
+ """
+ office = self.random_int(min=1, max=99)
+ birth_year = self.random_int(min=0, max=99)
+ start_year = self.random_int(min=0, max=99)
+ serial = self.random_int(min=1, max=9999)
+
+ num = "{0:02d}{1:02d}{2:02d}{3:04d}".format(
+ office,
+ start_year,
+ birth_year,
+ serial,
+ )
+
+ check = ssn_checksum(map(int, num))
+ num += str(check)
+
+ return num
+
+ def curp(self):
+ """
+ See https://es.wikipedia.org/wiki/Clave_%C3%9Anica_de_Registro_de_Poblaci%C3%B3n.
+
+ :return: a random Mexican CURP (Unique Population Registry Code)
+ """
+ birthday = self.generator.date_of_birth()
+
+ first_surname = random.choice(ALPHABET) + random.choice(VOWELS)
+ second_surname = random.choice(ALPHABET)
+ given_name = random.choice(ALPHABET)
+ name_initials = first_surname + second_surname + given_name
+
+ birth_date = birthday.strftime("%y%m%d")
+ gender = random.choice("HM")
+ state = random.choice(STATES_RENAPO)
+ first_surname_inside = random.choice(CONSONANTS)
+ second_surname_inside = random.choice(CONSONANTS)
+ given_name_inside = random.choice(ALPHABET)
+
+ # This character is assigned to avoid duplicity
+ # It's normally '0' for those born < 2000
+ # and 'A' for those born >= 2000
+ assigned_character = "0" if birthday.year < 2000 else "A"
+
+ name_initials = FORBIDDEN_WORDS.get(name_initials, name_initials)
+
+ random_curp = (
+ name_initials +
+ birth_date +
+ gender +
+ state +
+ first_surname_inside +
+ second_surname_inside +
+ given_name_inside +
+ assigned_character
+ )
+
+ random_curp += str(curp_checksum(random_curp))
+
+ return random_curp
+
+ def rfc(self, natural=True):
+ """
+ See https://es.wikipedia.org/wiki/Registro_Federal_de_Contribuyentes
+
+ :param natural: Whether to return the RFC of a natural person.
+ Otherwise return the RFC of a legal person.
+ :type natural: bool
+ :return: a random Mexican RFC
+ """
+ birthday = self.generator.date_of_birth()
+
+ if natural:
+ first_surname = random.choice(ALPHABET) + random.choice(VOWELS)
+ second_surname = random.choice(ALPHABET)
+ given_name = random.choice(ALPHABET)
+ name_initials = first_surname + second_surname + given_name
+ else:
+ name_initials = (
+ self.random_uppercase_letter() +
+ self.random_uppercase_letter() +
+ self.random_uppercase_letter()
+ )
+
+ birth_date = birthday.strftime("%y%m%d")
+ disambiguation_code = (
+ random.choice(ALPHANUMERIC) +
+ random.choice(ALPHANUMERIC) +
+ random.choice(ALPHANUMERIC)
+ )
+
+ random_rfc = (
+ name_initials +
+ birth_date +
+ disambiguation_code
+ )
+
+ return random_rfc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/setup.py new/Faker-2.0.0/setup.py
--- old/Faker-1.0.7/setup.py 2019-05-14 17:28:28.000000000 +0200
+++ new/Faker-2.0.0/setup.py 2019-07-12 18:06:49.000000000 +0200
@@ -69,13 +69,15 @@
"text-unidecode==1.2",
],
tests_require=[
- "email_validator>=1.0.1,<1.1.0",
+ "validators>=0.13.0",
"ukpostcodeparser>=1.1.1",
"mock ; python_version < '3.3'",
"pytest>=3.8.0,<3.9",
"more-itertools<6.0.0 ; python_version < '3.0'",
- "random2==1.0.1",
- "freezegun==0.3.11",
+ # restricted because they may drop python2 support in future versions
+ # https://github.com/joke2k/faker/issues/970
+ "random2<1.1",
+ "freezegun<0.4",
],
extras_require={
':python_version<"3.3"': [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/tests/providers/test_date_time.py new/Faker-2.0.0/tests/providers/test_date_time.py
--- old/Faker-1.0.7/tests/providers/test_date_time.py 2019-04-12 17:10:07.000000000 +0200
+++ new/Faker-2.0.0/tests/providers/test_date_time.py 2019-07-15 16:35:50.000000000 +0200
@@ -3,10 +3,13 @@
from datetime import date, datetime, timedelta, tzinfo
from datetime import time as datetime_time
-import time
-import unittest
+import os
+import platform
+import pytest
import random
import sys
+import time
+import unittest
import six
@@ -17,8 +20,6 @@
from faker.providers.date_time.ar_EG import Provider as EgProvider
from faker.providers.date_time.hy_AM import Provider as HyAmProvider
-import pytest
-
def is64bit():
return sys.maxsize > 2**32
@@ -448,7 +449,7 @@
from faker.providers.date_time import datetime_to_timestamp
for _ in range(100):
- now = datetime.now(utc).replace(microsecond=0)
+ now = datetime.now().replace(microsecond=0)
epoch_start = datetime(1970, 1, 1, tzinfo=utc)
# Ensure doubly-constrained unix_times are generated correctly
@@ -490,6 +491,14 @@
self.assertIsInstance(constrained_unix_time, int)
self.assertBetween(constrained_unix_time, 0, datetime_to_timestamp(now))
+ # Ensure it does not throw error with startdate='now' for machines with negative offset
+ if platform.system() != 'Windows':
+ os.environ['TZ'] = 'Europe/Paris'
+ time.tzset()
+ self.factory.unix_time(start_datetime='now')
+ if platform.system() != 'Windows':
+ del os.environ['TZ']
+
class TestPlPL(unittest.TestCase):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/tests/providers/test_internet.py new/Faker-2.0.0/tests/providers/test_internet.py
--- old/Faker-1.0.7/tests/providers/test_internet.py 2019-05-14 17:28:28.000000000 +0200
+++ new/Faker-2.0.0/tests/providers/test_internet.py 2019-07-12 17:17:07.000000000 +0200
@@ -12,7 +12,7 @@
import pytest
import six
-from email_validator import validate_email
+from validators import email as validate_email
from faker import Faker
from faker.providers.person.ja_JP import Provider as JaProvider
@@ -120,7 +120,7 @@
def test_email(self):
email = self.factory.email()
- validate_email(email, check_deliverability=False)
+ validate_email(email)
def test_domain_word(self):
domain_word = self.factory.domain_word()
@@ -155,7 +155,7 @@
def test_email(self):
email = self.factory.email()
- validate_email(email, check_deliverability=False)
+ validate_email(email)
class TestHuHU(unittest.TestCase):
@@ -200,7 +200,7 @@
)
def test_ascii_safe_email(self):
email = self.factory.ascii_safe_email()
- validate_email(email, check_deliverability=False)
+ validate_email(email)
assert email.split('@')[0] == 'fabienne'
@mock.patch(
@@ -209,7 +209,7 @@
)
def test_ascii_free_email(self):
email = self.factory.ascii_free_email()
- validate_email(email, check_deliverability=False)
+ validate_email(email)
assert email.split('@')[0] == 'fabienne'
@mock.patch(
@@ -218,7 +218,7 @@
)
def test_ascii_company_email(self):
email = self.factory.ascii_company_email()
- validate_email(email, check_deliverability=False)
+ validate_email(email)
assert email.split('@')[0] == 'fabienne'
@@ -234,7 +234,7 @@
)
def test_ascii_safe_email(self):
email = self.factory.ascii_safe_email()
- validate_email(email, check_deliverability=False)
+ validate_email(email)
assert email.split('@')[0] == 'asyl'
@mock.patch(
@@ -243,7 +243,7 @@
)
def test_ascii_free_email(self):
email = self.factory.ascii_free_email()
- validate_email(email, check_deliverability=False)
+ validate_email(email)
assert email.split('@')[0] == 'asyl'
@mock.patch(
@@ -252,7 +252,7 @@
)
def test_ascii_company_email(self):
email = self.factory.ascii_company_email()
- validate_email(email, check_deliverability=False)
+ validate_email(email)
assert email.split('@')[0] == 'asyl'
@@ -268,7 +268,7 @@
)
def test_ascii_safe_email(self):
email = self.factory.ascii_safe_email()
- validate_email(email, check_deliverability=False)
+ validate_email(email)
assert email.split('@')[0] == 'vitoriamagalhaes'
@mock.patch(
@@ -277,7 +277,7 @@
)
def test_ascii_free_email(self):
email = self.factory.ascii_free_email()
- validate_email(email, check_deliverability=False)
+ validate_email(email)
assert email.split('@')[0] == 'joaosimoes'
@mock.patch(
@@ -286,5 +286,5 @@
)
def test_ascii_company_email(self):
email = self.factory.ascii_company_email()
- validate_email(email, check_deliverability=False)
+ validate_email(email)
assert email.split('@')[0] == 'andrecaua'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/tests/providers/test_person.py new/Faker-2.0.0/tests/providers/test_person.py
--- old/Faker-1.0.7/tests/providers/test_person.py 2019-05-14 17:28:28.000000000 +0200
+++ new/Faker-2.0.0/tests/providers/test_person.py 2019-07-15 16:35:50.000000000 +0200
@@ -4,9 +4,14 @@
import re
import unittest
-
+import datetime
import six
+try:
+ from unittest import mock
+except ImportError:
+ import mock
+
from faker import Faker
from faker.providers.person.ar_AA import Provider as ArProvider
from faker.providers.person.fi_FI import Provider as FiProvider
@@ -14,9 +19,9 @@
from faker.providers.person.ne_NP import Provider as NeProvider
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 Provider as PlPLProvider
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
@@ -207,13 +212,43 @@
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
+ @mock.patch.object(PlPLProvider, 'random_digit')
+ def test_pesel_birth_date(self, mock_random_digit):
+ mock_random_digit.side_effect = [3, 5, 8, 8, 7, 9, 9, 3]
+ assert self.factory.pesel(datetime.date(1999, 12, 31)) == '99123135885'
+ assert self.factory.pesel(datetime.date(2000, 1, 1)) == '00210179936'
+
+ @mock.patch.object(PlPLProvider, 'random_digit')
+ def test_pesel_sex_male(self, mock_random_digit):
+ mock_random_digit.side_effect = [1, 3, 4, 5, 6, 1, 7, 0]
+ assert self.factory.pesel(datetime.date(1909, 3, 3), 'M') == '09030313454'
+ assert self.factory.pesel(datetime.date(1913, 8, 16), 'M') == '13081661718'
+
+ @mock.patch.object(PlPLProvider, 'random_digit')
+ def test_pesel_sex_female(self, mock_random_digit):
+ mock_random_digit.side_effect = [4, 9, 1, 6, 6, 1, 7, 3]
+ assert self.factory.pesel(datetime.date(2007, 4, 13), 'F') == '07241349161'
+ assert self.factory.pesel(datetime.date(1933, 12, 16), 'F') == '33121661744'
+
+ @mock.patch.object(PlPLProvider, 'random_digit')
+ def test_pwz_doctor(self, mock_random_digit):
+ mock_random_digit.side_effect = [6, 9, 1, 9, 6, 5, 2, 7, 9, 9, 1, 5]
+ assert self.factory.pwz_doctor() == '2691965'
+ assert self.factory.pwz_doctor() == '4279915'
+
+ @mock.patch.object(PlPLProvider, 'random_digit')
+ def test_pwz_doctor_check_digit_zero(self, mock_random_digit):
+ mock_random_digit.side_effect = [0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 9, 9]
+ assert self.factory.pwz_doctor() == '6000012'
+ assert self.factory.pwz_doctor() == '1000090'
+
+ @mock.patch.object(PlPLProvider, 'random_int')
+ @mock.patch.object(PlPLProvider, 'random_digit')
+ def test_pwz_nurse(self, mock_random_digit, mock_random_int):
+ mock_random_digit.side_effect = [3, 4, 5, 6, 7, 1, 7, 5, 1, 2]
+ mock_random_int.side_effect = [45, 3]
+ assert self.factory.pwz_nurse(kind='nurse') == '4534567P'
+ assert self.factory.pwz_nurse(kind='midwife') == '0317512A'
class TestCsCZ(unittest.TestCase):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/tests/providers/test_python.py new/Faker-2.0.0/tests/providers/test_python.py
--- old/Faker-1.0.7/tests/providers/test_python.py 2019-04-15 17:10:34.000000000 +0200
+++ new/Faker-2.0.0/tests/providers/test_python.py 2019-07-12 17:17:07.000000000 +0200
@@ -20,16 +20,16 @@
self.assertEqual(0, random_int % 2)
def test_pyint_bound_0(self):
- self.assertEqual(0, self.factory.pyint(min=0, max=0))
+ self.assertEqual(0, self.factory.pyint(min_value=0, max_value=0))
def test_pyint_bound_positive(self):
- self.assertEqual(5, self.factory.pyint(min=5, max=5))
+ self.assertEqual(5, self.factory.pyint(min_value=5, max_value=5))
def test_pyint_bound_negative(self):
- self.assertEqual(-5, self.factory.pyint(min=-5, max=-5))
+ self.assertEqual(-5, self.factory.pyint(min_value=-5, max_value=-5))
def test_pyint_range(self):
- self.assertTrue(0 <= self.factory.pyint(min=0, max=2) <= 2)
+ self.assertTrue(0 <= self.factory.pyint(min_value=0, max_value=2) <= 2)
class TestPyfloat(unittest.TestCase):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/tests/providers/test_ssn.py new/Faker-2.0.0/tests/providers/test_ssn.py
--- old/Faker-1.0.7/tests/providers/test_ssn.py 2019-05-08 18:02:39.000000000 +0200
+++ new/Faker-2.0.0/tests/providers/test_ssn.py 2019-07-12 17:17:07.000000000 +0200
@@ -9,6 +9,7 @@
import freezegun
import pytest
import random2
+from validators.i18n.es import es_cif as is_cif, es_nif as is_nif, es_nie as is_nie
from faker import Faker
from faker.providers.ssn.en_CA import checksum as ca_checksum
@@ -18,6 +19,8 @@
from faker.providers.ssn.no_NO import checksum as no_checksum, Provider as no_Provider
from faker.providers.ssn.pl_PL import checksum as pl_checksum, calculate_month as pl_calculate_mouth
from faker.providers.ssn.pt_BR import checksum as pt_checksum
+from faker.providers.ssn.es_MX import (ssn_checksum as mx_ssn_checksum,
+ curp_checksum as mx_curp_checksum)
class TestBgBG(unittest.TestCase):
@@ -113,6 +116,98 @@
assert 1 <= int(serial) <= 9999
assert area != '666'
+ def test_invalid_ssn(self):
+ self.factory.random = random2.Random()
+ # Magic Numbers below generate '666-92-7944', '000-54-2963', '956-GG-9478', '436-00-1386',
+ # and 134-76-0000 respectively. The "group" (GG) returned for '956-GG-9478 will be a random
+ # number, and that random number is not in the "itin_group_numbers" List. The random GG occurs
+ # even when using the same seed_instance() due to using random.choice() for GG to avoid valid
+ # ITINs being returned as an invalid SSN:
+ #
+ # Ensure that generated SSNs are 11 characters long
+ # including dashes, consist of dashes and digits only, and the tested number
+ # violates the requirements below, ensuring an INVALID SSN is returned:
+ #
+ # A United States Social Security Number
+ # (SSN) is a tax processing number issued by the Internal
+ # Revenue Service with the format "AAA-GG-SSSS". The
+ # number is divided into three parts: the first three
+ # digits, known as the area number because they were
+ # formerly assigned by geographical region; the middle two
+ # digits, known as the group number; and the final four
+ # digits, known as the serial number. SSNs with the
+ # following characteristics are not allocated:
+ #
+ # 1) Numbers with all zeros in any digit group
+ # (000-##-####, ###-00-####, ###-##-0000).
+ #
+ # 2) Numbers with 666 or 900-999 in the first digit group.
+ #
+ # https://en.wikipedia.org/wiki/Social_Security_number
+ #
+ # ITIN explained:
+ # https://www.irs.gov/individuals/international-taxpayers/general-itin-informa...
+
+ itin_group_numbers = [
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 88,
+ 90,
+ 91,
+ 92,
+ 94,
+ 95,
+ 96,
+ 97,
+ 98,
+ 99]
+
+ self.factory.seed_instance(1143)
+ ssn = self.factory.ssn(taxpayer_identification_number_type='INVALID_SSN')
+
+ assert len(ssn) == 11
+ assert ssn.replace('-', '').isdigit()
+ assert ssn.startswith('666')
+
+ self.factory.seed_instance(1514)
+ ssn = self.factory.ssn(taxpayer_identification_number_type='INVALID_SSN')
+
+ assert ssn.startswith('000')
+
+ self.factory.seed_instance(2)
+ ssn = self.factory.ssn(taxpayer_identification_number_type='INVALID_SSN')
+ [area, group, serial] = ssn.split('-')
+
+ assert 900 <= int(area) <= 999 and int(group) not in itin_group_numbers
+
+ self.factory.seed_instance(9)
+ ssn = self.factory.ssn(taxpayer_identification_number_type='INVALID_SSN')
+ [area, group, serial] = ssn.split('-')
+
+ assert int(area) < 900 and int(group) == 0
+
+ self.factory.seed_instance(1)
+ ssn = self.factory.ssn(taxpayer_identification_number_type='INVALID_SSN')
+ [area, group, serial] = ssn.split('-')
+
+ assert int(area) < 900 and int(serial) == 0
+
def test_prohibited_ssn_value(self):
# 666 is a prohibited value. The magic number selected as a seed
# is one that would (if not specifically checked for) return an
@@ -268,92 +363,6 @@
self.factory.ssn(taxpayer_identification_number_type='ssn')
-def nif_nie_validation(doi, number_by_letter, special_cases):
- """
- Validate if the doi is a NIF or a NIE.
- :param doi: DOI to validate.
- :return: boolean if it's valid.
- """
- doi = doi.upper()
- if doi in special_cases:
- return False
-
- table = 'TRWAGMYFPDXBNJZSQVHLCKE'
-
- if len(doi) == 9:
- control = doi[8]
-
- # If it is not a DNI, convert the first letter to the corresponding digit
- numbers = number_by_letter.get(doi[0], doi[0]) + doi[1:8]
-
- return numbers.isdigit() and control == table[int(numbers) % 23]
-
- return False
-
-
-def is_cif(doi):
- """
- Validate if the doi is a CIF.
- :param doi: DOI to validate.
- :return: boolean if it's valid.
- """
- doi = doi.upper()
-
- if len(doi) != 9:
- return False
-
- table = 'JABCDEFGHI'
- first_chr = doi[0]
- doi_body = doi[1:8]
- control = doi[8]
-
- if not doi_body.isdigit():
- return False
-
- # Multiply each each odd position doi digit by 2 and sum it all together
- odd_result = sum(int(x) for x in ''.join(str(int(x) * 2) for x in doi_body[0::2]))
- # Sum all even doi digits
- even_result = sum(map(int, doi_body[1::2]))
-
- res = (10 - (even_result + odd_result) % 10) % 10
-
- if first_chr in 'ABEH': # Number type
- return str(res) == control
- elif first_chr in 'PSQW': # Letter type
- return table[res] == control
- elif first_chr not in 'CDFGJNRUV':
- return False
-
- return control == str(res) or control == table[res]
-
-
-def is_nif(doi):
- """
- Validate if the doi is a NIF.
- :param doi: DOI to validate.
- :return: boolean if it's valid.
- """
- number_by_letter = {'L': '0', 'M': '0', 'K': '0'}
- special_cases = ['X0000000T', '00000000T', '00000001R', '00000001R']
- return nif_nie_validation(doi, number_by_letter, special_cases)
-
-
-def is_nie(doi):
- """
- Validate if the doi is a NIE.
- :param doi: DOI to validate.
- :return: boolean if it's valid.
- """
- number_by_letter = {'X': '0', 'Y': '1', 'Z': '2'}
- special_cases = ['X0000000T']
-
- # NIE must must start with X Y or Z
- if not doi or doi[0] not in number_by_letter.keys():
- return False
-
- return nif_nie_validation(doi, number_by_letter, special_cases)
-
-
class TestEsES(unittest.TestCase):
def setUp(self):
self.factory = Faker('es_ES')
@@ -383,6 +392,41 @@
self.factory = Faker('es_CA')
+class TestEsMX(unittest.TestCase):
+ def setUp(self):
+ self.factory = Faker('es_MX')
+
+ def test_ssn(self):
+ for _ in range(100):
+ ssn = self.factory.ssn()
+
+ assert len(ssn) == 11
+ assert ssn.isnumeric()
+ assert mx_ssn_checksum(map(int, ssn[:-1])) == int(ssn[-1])
+
+ def test_curp(self):
+ for _ in range(100):
+ curp = self.factory.curp()
+
+ assert len(curp) == 18
+ assert re.search(r'^[A-Z]{4}\d{6}[A-Z]{6}[0A]\d$', curp)
+ assert mx_curp_checksum(curp[:-1]) == int(curp[-1])
+
+ def test_rfc_natural(self):
+ for _ in range(100):
+ rfc = self.factory.rfc()
+
+ assert len(rfc) == 13
+ assert re.search(r'^[A-Z]{4}\d{6}[0-9A-Z]{3}$', rfc)
+
+ def test_rfc_legal(self):
+ for _ in range(100):
+ rfc = self.factory.rfc(natural=False)
+
+ assert len(rfc) == 12
+ assert re.search(r'^[A-Z]{3}\d{6}[0-9A-Z]{3}$', rfc)
+
+
class TestEtEE(unittest.TestCase):
""" Tests SSN in the et_EE locale """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Faker-1.0.7/tests/test_factory.py new/Faker-2.0.0/tests/test_factory.py
--- old/Faker-1.0.7/tests/test_factory.py 2019-05-14 17:28:28.000000000 +0200
+++ new/Faker-2.0.0/tests/test_factory.py 2019-07-15 16:39:47.000000000 +0200
@@ -6,6 +6,8 @@
import unittest
import string
import sys
+
+from collections import OrderedDict
from ipaddress import ip_address, ip_network
import six
@@ -218,13 +220,17 @@
pick = provider.random_element(choices)
assert pick in choices
- choices = {'a': 5, 'b': 2, 'c': 2, 'd': 1}
+ # dicts not allowed because they introduce dependency on PYTHONHASHSEED
+ with self.assertRaises(ValueError):
+ provider.random_element({})
+
+ choices = OrderedDict([('a', 5), ('b', 2), ('c', 2), ('d', 1)])
pick = provider.random_element(choices)
- assert pick in choices
+ self.assertTrue(pick in choices)
- choices = {'a': 0.5, 'b': 0.2, 'c': 0.2, 'd': 0.1}
+ choices = OrderedDict([('a', 0.5), ('b', 0.2), ('c', 0.2), ('d', 0.1)])
pick = provider.random_element(choices)
- assert pick in choices
+ self.assertTrue(pick in choices)
def test_binary(self):
from faker.providers.misc import Provider