Repository: joke2k/faker
Pull request #1491 (2021-07-31 12:46:19)

add missing diacritics in French last names
### What does this changes

Add some missing diacritics, e.g., Herve -> Hervé, Francois -> François, Etienne -> Étienne

### What was wrong

All diacritics are missing from the French last names. First names seem ok, though.

### How this fixes it

Gracefully.



Patch:
diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index 5f80e929..a87d36ea 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 8.10.3
+current_version = 8.12.0
 files = VERSION faker/__init__.py docs/conf.py
 commit = True
 tag = True
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 024ea21e..2afc0c12 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
 ## Changelog
 
+### [v8.12.0 - 2021-08-20](https://github.com/joke2k/faker/compare/v8.11.0...v8.12.0)
+
+* Added non-geo numbers and services phones format for ``pt_BR``. Thanks @leogregianin.
+* Add datetime formats in ``pt_BR``. Thanks @leogregianin.
+* Add currency formats in ``pt_BR``. Thanks @leogregianin.
+
+### [v8.11.0 - 2021-08-03](https://github.com/joke2k/faker/compare/v8.10.3...v8.11.0)
+
+*  Add ``nic_handle``. Thanks @pishchalnikov.
+
 ### [v8.10.3 - 2021-07-26](https://github.com/joke2k/faker/compare/v8.10.2...v8.10.3)
 
 * Remove potentially offensive surname in ``it_IT``. Thanks @lordgordon.
diff --git a/CITATION.cff b/CITATION.cff
new file mode 100644
index 00000000..a0ee0b10
--- /dev/null
+++ b/CITATION.cff
@@ -0,0 +1,9 @@
+authors: 
+  - family-names: Faraglia
+    given-names: Daniele
+  - name: "Other Contributors"
+cff-version: 1.2.0
+license: MIT
+message: If you use this software, please cite it using these metadata.
+repository-code: "https://github.com/joke2k/faker"
+title: "Faker"
diff --git a/MANIFEST.in b/MANIFEST.in
index ceb0e3b6..72e4bd43 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,6 +4,7 @@ include CONTRIBUTING.rst
 include CHANGELOG.md
 include RELEASE_PROCESS.rst
 include VERSION
+include CITATION.cff
 recursive-include tests *.json
 recursive-include tests *.py
 recursive-exclude faker/sphinx *.py
diff --git a/VERSION b/VERSION
index 213bb682..e51b3430 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-8.10.3
+8.12.0
diff --git a/docs/conf.py b/docs/conf.py
index 87dc1741..58fc9550 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -51,9 +51,9 @@ copyright = '2014, Daniele Faraglia'
 # built documents.
 #
 # The short X.Y version.
-version = '8.10.3'
+version = '8.12.0'
 # The full version, including alpha/beta/rc tags.
-release = '8.10.3'
+release = '8.12.0'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/faker/__init__.py b/faker/__init__.py
index 3c306691..1b96fc49 100644
--- a/faker/__init__.py
+++ b/faker/__init__.py
@@ -2,6 +2,6 @@ from faker.factory import Factory
 from faker.generator import Generator
 from faker.proxy import Faker
 
-VERSION = '8.10.3'
+VERSION = '8.12.0'
 
 __all__ = ('Factory', 'Generator', 'Faker')
diff --git a/faker/providers/currency/pt_BR/__init__.py b/faker/providers/currency/pt_BR/__init__.py
new file mode 100644
index 00000000..17ee8e3f
--- /dev/null
+++ b/faker/providers/currency/pt_BR/__init__.py
@@ -0,0 +1,9 @@
+from .. import Provider as CurrencyProvider
+
+
+class Provider(CurrencyProvider):
+
+    price_formats = ["#,##", "%#,##", "%##,##", "%.###,##", "%#.###,##"]
+
+    def pricetag(self):
+        return ("R$" + self.numerify(self.random_element(self.price_formats)))
diff --git a/faker/providers/date_time/pt_BR/__init__.py b/faker/providers/date_time/pt_BR/__init__.py
new file mode 100644
index 00000000..e853211f
--- /dev/null
+++ b/faker/providers/date_time/pt_BR/__init__.py
@@ -0,0 +1,37 @@
+from .. import Provider as DateTimeProvider
+
+
+class Provider(DateTimeProvider):
+
+    DAY_NAMES = {
+        "0": "domingo",
+        "1": "segunda-feira",
+        "2": "terça-feira",
+        "3": "quarta-feira",
+        "4": "quinta-feira",
+        "5": "sexta-feira",
+        "6": "sábado",
+    }
+
+    MONTH_NAMES = {
+        "01": "janeiro",
+        "02": "fevereiro",
+        "03": "março",
+        "04": "abril",
+        "05": "maio",
+        "06": "junho",
+        "07": "julho",
+        "08": "agosto",
+        "09": "setembro",
+        "10": "outubro",
+        "11": "novembro",
+        "12": "dezembro",
+    }
+
+    def day_of_week(self):
+        day = self.date("%w")
+        return self.DAY_NAMES[day]
+
+    def month_name(self):
+        month = self.month()
+        return self.MONTH_NAMES[month]
diff --git a/faker/providers/person/fr_FR/__init__.py b/faker/providers/person/fr_FR/__init__.py
index 42df5875..53a4c41c 100644
--- a/faker/providers/person/fr_FR/__init__.py
+++ b/faker/providers/person/fr_FR/__init__.py
@@ -208,7 +208,6 @@ class Provider(PersonProvider):
         'Margot',
         'Margaret',
         'Maggie',
-        'daisy',
         'Marianne',
         'Marie',
         'Marine',
@@ -259,41 +258,41 @@ class Provider(PersonProvider):
     last_names = (
         'Martin', 'Bernard', 'Thomas', 'Robert', 'Petit', 'Dubois', 'Richard', 'Garcia', 'Durand', 'Moreau', 'Lefebvre',
         'Simon', 'Laurent', 'Michel', 'Leroy', 'Martinez', 'David', 'Fontaine', 'Da Silva', 'Morel', 'Fournier',
-        'Dupont', 'Bertrand', 'Lambert', 'Rousseau', 'Girard', 'Roux', 'Vincent', 'Lefevre', 'Boyer', 'Lopez', 'Bonnet',
-        'Andre', 'Francois', 'Mercier', 'Muller', 'Guerin', 'Legrand', 'Sanchez', 'Garnier', 'Chevalier', 'Faure',
-        'Perez', 'Clement', 'Fernandez', 'Blanc', 'Robin', 'Morin', 'Gauthier', 'Pereira', 'Perrin', 'Roussel', 'Henry',
-        'Duval', 'Gautier', 'Nicolas', 'Masson', 'Marie', 'Noel', 'Ferreira', 'Lemaire', 'Mathieu', 'Riviere', 'Denis',
+        'Dupont', 'Bertrand', 'Lambert', 'Rousseau', 'Girard', 'Roux', 'Vincent', 'Lefèvre', 'Boyer', 'Lopez', 'Bonnet',
+        'Andre', 'François', 'Mercier', 'Muller', 'Guérin', 'Legrand', 'Sanchez', 'Garnier', 'Chevalier', 'Faure',
+        'Perez', 'Clément', 'Fernandez', 'Blanc', 'Robin', 'Morin', 'Gauthier', 'Pereira', 'Perrin', 'Roussel', 'Henry',
+        'Duval', 'Gautier', 'Nicolas', 'Masson', 'Marie', 'Noël', 'Ferreira', 'Lemaire', 'Mathieu', 'Rivière', 'Denis',
         'Marchand', 'Rodriguez', 'Dumont', 'Payet', 'Lucas', 'Dufour', 'Dos Santos', 'Joly', 'Blanchard', 'Meunier',
-        'Rodrigues', 'Caron', 'Gerard', 'Fernandes', 'Brunet', 'Meyer', 'Barbier', 'Leroux', 'Renard', 'Goncalves',
+        'Rodrigues', 'Caron', 'Gérard', 'Fernandes', 'Brunet', 'Meyer', 'Barbier', 'Leroux', 'Renard', 'Goncalves',
         'Gaillard', 'Brun', 'Roy', 'Picard', 'Giraud', 'Roger', 'Schmitt', 'Colin', 'Arnaud', 'Vidal', 'Gonzalez',
         'Lemoine', 'Roche', 'Aubert', 'Olivier', 'Leclercq', 'Pierre', 'Philippe', 'Bourgeois', 'Renaud', 'Martins',
         'Leclerc', 'Guillaume', 'Lacroix', 'Lecomte', 'Benoit', 'Fabre', 'Carpentier', 'Vasseur', 'Louis', 'Hubert',
         'Jean', 'Dumas', 'Rolland', 'Grondin', 'Rey', 'Huet', 'Gomez', 'Dupuis', 'Guillot', 'Berger', 'Moulin',
         'Hoarau', 'Menard', 'Deschamps', 'Fleury', 'Adam', 'Boucher', 'Poirier', 'Bertin', 'Charles', 'Aubry',
         'Da Costa', 'Royer', 'Dupuy', 'Maillard', 'Paris', 'Baron', 'Lopes', 'Guyot', 'Carre', 'Jacquet', 'Renault',
-        'Herve', 'Charpentier', 'Klein', 'Cousin', 'Collet', 'Leger', 'Ribeiro', 'Hernandez', 'Bailly', 'Schneider',
-        'Le Gall', 'Ruiz', 'Langlois', 'Bouvier', 'Gomes', 'Prevost', 'Julien', 'Lebrun', 'Breton', 'Germain', 'Millet',
-        'Boulanger', 'Remy', 'Le Roux', 'Daniel', 'Marques', 'Maillot', 'Leblanc', 'Le Goff', 'Barre', 'Perrot',
-        'Leveque', 'Marty', 'Benard', 'Monnier', 'Hamon', 'Pelletier', 'Alves', 'Etienne', 'Marchal', 'Poulain',
-        'Tessier', 'Lemaitre', 'Guichard', 'Besson', 'Mallet', 'Hoareau', 'Gillet', 'Weber', 'Jacob', 'Collin',
-        'Chevallier', 'Perrier', 'Michaud', 'Carlier', 'Delaunay', 'Chauvin', 'Alexandre', 'Marechal', 'Antoine',
+        'Hervé', 'Charpentier', 'Klein', 'Cousin', 'Collet', 'Léger', 'Ribeiro', 'Hernandez', 'Bailly', 'Schneider',
+        'Le Gall', 'Ruiz', 'Langlois', 'Bouvier', 'Gomes', 'Prévost', 'Julien', 'Lebrun', 'Breton', 'Germain', 'Millet',
+        'Boulanger', 'Rémy', 'Le Roux', 'Daniel', 'Marques', 'Maillot', 'Leblanc', 'Le Goff', 'Barre', 'Perrot',
+        'Lévêque', 'Marty', 'Benard', 'Monnier', 'Hamon', 'Pelletier', 'Alves', 'Étienne', 'Marchal', 'Poulain',
+        'Tessier', 'Lemaître', 'Guichard', 'Besson', 'Mallet', 'Hoareau', 'Gillet', 'Weber', 'Jacob', 'Collin',
+        'Chevallier', 'Perrier', 'Michaud', 'Carlier', 'Delaunay', 'Chauvin', 'Alexandre', 'Maréchal', 'Antoine',
         'Lebon', 'Cordier', 'Lejeune', 'Bouchet', 'Pasquier', 'Legros', 'Delattre', 'Humbert', 'De Oliveira', 'Briand',
         'Lamy', 'Launay', 'Gilbert', 'Perret', 'Lesage', 'Gay', 'Nguyen', 'Navarro', 'Besnard', 'Pichon', 'Hebert',
         'Cohen', 'Pons', 'Lebreton', 'Sauvage', 'De Sousa', 'Pineau', 'Albert', 'Jacques', 'Pinto', 'Barthelemy',
-        'Turpin', 'Bigot', 'Lelievre', 'Georges', 'Reynaud', 'Ollivier', 'Martel', 'Voisin', 'Leduc', 'Guillet',
-        'Vallee', 'Coulon', 'Camus', 'Marin', 'Teixeira', 'Costa', 'Mahe', 'Didier', 'Charrier', 'Gaudin', 'Bodin',
-        'Guillou', 'Gregoire', 'Gros', 'Blanchet', 'Buisson', 'Blondel', 'Paul', 'Dijoux', 'Barbe', 'Hardy', 'Laine',
-        'Evrard', 'Laporte', 'Rossi', 'Joubert', 'Regnier', 'Tanguy', 'Gimenez', 'Allard', 'Devaux', 'Morvan', 'Levy',
+        'Turpin', 'Bigot', 'Lelièvre', 'Georges', 'Reynaud', 'Ollivier', 'Martel', 'Voisin', 'Leduc', 'Guillet',
+        'Vallée', 'Coulon', 'Camus', 'Marin', 'Teixeira', 'Costa', 'Mahe', 'Didier', 'Charrier', 'Gaudin', 'Bodin',
+        'Guillou', 'Grégoire', 'Gros', 'Blanchet', 'Buisson', 'Blondel', 'Paul', 'Dijoux', 'Barbe', 'Hardy', 'Laine',
+        'Evrard', 'Laporte', 'Rossi', 'Joubert', 'Regnier', 'Tanguy', 'Gimenez', 'Allard', 'Devaux', 'Morvan', 'Lévy',
         'Dias', 'Courtois', 'Lenoir', 'Berthelot', 'Pascal', 'Vaillant', 'Guilbert', 'Thibault', 'Moreno', 'Duhamel',
         'Colas', 'Masse', 'Baudry', 'Bruneau', 'Verdier', 'Delorme', 'Blin', 'Guillon', 'Mary', 'Coste', 'Pruvost',
         'Maury', 'Allain', 'Valentin', 'Godard', 'Joseph', 'Brunel', 'Marion', 'Texier', 'Seguin', 'Raynaud', 'Bourdon',
         'Raymond', 'Bonneau', 'Chauvet', 'Maurice', 'Legendre', 'Loiseau', 'Ferrand', 'Toussaint', 'Techer', 'Lombard',
         'Lefort', 'Couturier', 'Bousquet', 'Diaz', 'Riou', 'Clerc', 'Weiss', 'Imbert', 'Jourdan', 'Delahaye', 'Gilles',
-        'Guibert', 'Begue', 'Descamps', 'Delmas', 'Peltier', 'Dupre', 'Chartier', 'Martineau', 'Laroche', 'Leconte',
-        'Maillet', 'Parent', 'Labbe', 'Potier', 'Bazin', 'Normand', 'Pottier', 'Torres', 'Lagarde', 'Blot', 'Jacquot',
-        'Lemonnier', 'Grenier', 'Rocher', 'Bonnin', 'Boutin', 'Fischer', 'Munoz', 'Neveu', 'Lacombe', 'Mendes',
+        'Guibert', 'Bègue', 'Descamps', 'Delmas', 'Peltier', 'Dupré', 'Chartier', 'Martineau', 'Laroche', 'Leconte',
+        'Maillet', 'Parent', 'Labbé', 'Potier', 'Bazin', 'Normand', 'Pottier', 'Torres', 'Lagarde', 'Blot', 'Jacquot',
+        'Lemonnier', 'Grenier', 'Rocher', 'Bonnin', 'Boutin', 'Fischer', 'Munoz', 'Neveu', 'Lacombe', 'Mendès',
         'Delannoy', 'Auger', 'Wagner', 'Fouquet', 'Mace', 'Ramos', 'Pages', 'Petitjean', 'Chauveau', 'Foucher', 'Peron',
-        'Guyon', 'Gallet', 'Rousset', 'Traore', 'Bernier', 'Vallet', 'Letellier', 'Bouvet', 'Hamel', 'Chretien',
+        'Guyon', 'Gallet', 'Rousset', 'Traore', 'Bernier', 'Vallet', 'Letellier', 'Bouvet', 'Hamel', 'Chrétien',
         'Faivre', 'Boulay', 'Thierry', 'Samson', 'Ledoux', 'Salmon', 'Gosselin', 'Lecoq', 'Pires', 'Leleu', 'Becker',
         'Diallo', 'Merle', 'Valette',
     )
diff --git a/faker/providers/phone_number/pt_BR/__init__.py b/faker/providers/phone_number/pt_BR/__init__.py
index 46b1fb0b..2097f2ff 100644
--- a/faker/providers/phone_number/pt_BR/__init__.py
+++ b/faker/providers/phone_number/pt_BR/__init__.py
@@ -75,6 +75,14 @@ class Provider(PhoneNumberProvider):
         '71 ####-####',
         '81 ####-####',
         '84 ####-####',
+        '0300 ### ####',
+        '0500 ### ####',
+        '0800 ### ####',
+        '0900 ### ####',
+        '0300-###-####',
+        '0500-###-####',
+        '0800-###-####',
+        '0900-###-####',
     )
 
     msisdn_formats = (
@@ -102,6 +110,31 @@ class Provider(PhoneNumberProvider):
         '+55 (##) 9 ####-####',
     )
 
+    services_phones_formats = (
+        '100',
+        '128',
+        '151',
+        '152',
+        '153',
+        '156',
+        '180',
+        '181',
+        '185',
+        '188',
+        '190',
+        '191',
+        '192',
+        '193',
+        '194',
+        '197',
+        '198',
+        '199',
+    )
+
     def cellphone_number(self):
         pattern = self.random_element(self.cellphone_formats)
         return self.numerify(self.generator.parse(pattern))
+
+    def service_phone_number(self):
+        pattern = self.random_element(self.services_phones_formats)
+        return self.numerify(self.generator.parse(pattern))


Test patch:
diff --git a/tests/providers/test_currency.py b/tests/providers/test_currency.py
index 60703517..d63a8a38 100644
--- a/tests/providers/test_currency.py
+++ b/tests/providers/test_currency.py
@@ -346,3 +346,19 @@ class TestRoRo:
         for _ in range(num_samples):
             pricetag = faker.pricetag()
             assert isinstance(pricetag, str)
+
+
+class TestPtBr:
+    """Test pt_BR currency provider"""
+
+    num_samples = 100
+
+    @classmethod
+    def setup_class(cls):
+        from faker.providers.currency.pt_BR import Provider as PtBrCurrencyProvider
+        cls.provider = PtBrCurrencyProvider
+
+    def test_pricetag(self, faker, num_samples):
+        for _ in range(num_samples):
+            pricetag = faker.pricetag()
+            assert isinstance(pricetag, str)
diff --git a/tests/providers/test_date_time.py b/tests/providers/test_date_time.py
index 38195d8e..33c4f16a 100644
--- a/tests/providers/test_date_time.py
+++ b/tests/providers/test_date_time.py
@@ -25,6 +25,7 @@ from faker.providers.date_time.es_ES import Provider as EsEsProvider
 from faker.providers.date_time.hy_AM import Provider as HyAmProvider
 from faker.providers.date_time.it_IT import Provider as ItItProvider
 from faker.providers.date_time.pl_PL import Provider as PlProvider
+from faker.providers.date_time.pt_BR import Provider as PtBrProvider
 from faker.providers.date_time.pt_PT import Provider as PtPtProvider
 from faker.providers.date_time.ro_RO import Provider as RoRoProvider
 from faker.providers.date_time.ru_RU import Provider as RuProvider
@@ -1103,6 +1104,21 @@ class TestTrTr(unittest.TestCase):
         assert month in TrTrProvider.MONTH_NAMES.values()
 
 
+class TestPtBr(unittest.TestCase):
+
+    def setUp(self):
+        self.fake = Faker('pt_BR')
+        Faker.seed(0)
+
+    def test_day(self):
+        day = self.fake.day_of_week()
+        assert day in PtBrProvider.DAY_NAMES.values()
+
+    def test_month(self):
+        month = self.fake.month_name()
+        assert month in PtBrProvider.MONTH_NAMES.values()
+
+
 class TestPtPt(unittest.TestCase):
 
     def setUp(self):
diff --git a/tests/providers/test_internet.py b/tests/providers/test_internet.py
index 356572c1..2f9c37d9 100644
--- a/tests/providers/test_internet.py
+++ b/tests/providers/test_internet.py
@@ -14,6 +14,7 @@ from faker.providers.internet.en_GB import Provider as EnGbInternetProvider
 from faker.providers.internet.es_ES import Provider as EsEsInternetProvider
 from faker.providers.internet.pl_PL import Provider as PlPlInternetProvider
 from faker.providers.internet.ro_RO import Provider as RoRoInternetProvider
+from faker.providers.internet.ru_RU import Provider as RuRuInternetProvider
 from faker.providers.internet.th_TH import Provider as ThThInternetProvider
 from faker.providers.internet.zh_CN import Provider as ZhCnInternetProvider
 from faker.providers.person.ja_JP import Provider as JaPersonProvider
@@ -691,6 +692,43 @@ class TestRoRo:
         assert tld in PlPlInternetProvider.tlds
 
 
+class TestRuRu:
+    """Test ru_RU internet provider methods"""
+
+    def test_free_email_domain(self, faker):
+        assert faker.free_email_domain() in RuRuInternetProvider.free_email_domains
+
+    def test_tld(self, faker):
+        assert faker.tld() in RuRuInternetProvider.tlds
+
+    @patch(
+        'faker.providers.internet.Provider.user_name',
+        lambda x: 'ИванИванов',
+    )
+    def test_ascii_safe_email(self, faker):
+        email = faker.ascii_safe_email()
+        validate_email(email)
+        assert email.split('@')[0] == 'ivanivanov'
+
+    @patch(
+        'faker.providers.internet.Provider.user_name',
+        lambda x: 'АлександрСмирнов',
+    )
+    def test_ascii_free_email(self, faker):
+        email = faker.ascii_free_email()
+        validate_email(email)
+        assert email.split('@')[0] == 'aleksandrsmirnov'
+
+    @patch(
+        'faker.providers.internet.Provider.user_name',
+        lambda x: 'СергейКузнецов',
+    )
+    def test_ascii_company_email(self, faker):
+        email = faker.ascii_company_email()
+        validate_email(email)
+        assert email.split('@')[0] == 'sergekuznetsov'
+
+
 class TestThTh:
     """Test th_TH internet provider methods"""
 
diff --git a/tests/providers/test_phone_number.py b/tests/providers/test_phone_number.py
index 04668374..287cfae5 100644
--- a/tests/providers/test_phone_number.py
+++ b/tests/providers/test_phone_number.py
@@ -37,7 +37,8 @@ class TestPtBr:
         pattern = re.compile(
             r'(?:\+55 )?'
             r'(?:[1-8]1|84|\((?:0[1-8]1|084)\))'
-            r' \d{4}[ -]\d{4}',
+            r' \d{4}[ -]\d{4}|'
+            r'\d{4}?[ -]\d{3}[ -]\d{4}',
         )
         for _ in range(num_samples):
             phone_number = faker.phone_number()
@@ -59,6 +60,12 @@ class TestPtBr:
             cellphone = faker.cellphone_number()
             assert pattern.fullmatch(cellphone)
 
+    def test_service_phone(self, faker, num_samples):
+        pattern = re.compile(r'1(?:0|2|5|8|9)?(?:[0-9])')
+        for _ in range(num_samples):
+            service = faker.service_phone_number()
+            assert pattern.fullmatch(service)
+
 
 class TestHuHu:
     """Test hu_HU phone number provider methods"""