Repository: joke2k/faker
Pull request #2059 (2024-06-10 13:34:40)

Change `pydecimal` type hint for `min_value`, `max_value` to `numbers.Number`
### What does this change
in`faker\providers\python\__init__.py` method `pydecimal` I changed the type hints for `min_value`, `max_value` to `numbers.Number`

### What was wrong
#2041 issue in `mypy` for `type hints`

### How this fixes it
This PR will use `numbers.Number` instead of `float` for type hint


Patch:
diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index 3377e576..32165d08 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 25.8.0
+current_version = 25.9.0
 files = VERSION faker/__init__.py docs/conf.py
 commit = True
 tag = True
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cab81022..a2884691 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
 ## Changelog
 
+### [v25.9.0 - 2024-06-20](https://github.com/joke2k/faker/compare/v25.8.0..v25.9.0)
+
+* Add support for Nigerian Yoruba names and surnames (`yo_NG`). Thanks @5uru.
 
 ### [v25.8.0 - 2024-05-07](https://github.com/joke2k/faker/compare/v25.7.0..v25.8.0)
 
diff --git a/VERSION b/VERSION
index 11d4ad6c..e362e4c4 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-25.8.0
+25.9.0
diff --git a/docs/conf.py b/docs/conf.py
index 8d5933df..4ab0bbf8 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -51,9 +51,9 @@ copyright = f"2014-{datetime.now().year}, Daniele Faraglia"
 # built documents.
 #
 # The short X.Y version.
-version = "25.8.0"
+version = "25.9.0"
 # The full version, including alpha/beta/rc tags.
-release = "25.8.0"
+release = "25.9.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 c379fd59..f482dcc2 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 = "25.8.0"
+VERSION = "25.9.0"
 
 __all__ = ("Factory", "Generator", "Faker")
diff --git a/faker/providers/person/yo_NG/__init__.py b/faker/providers/person/yo_NG/__init__.py
new file mode 100644
index 00000000..db857302
--- /dev/null
+++ b/faker/providers/person/yo_NG/__init__.py
@@ -0,0 +1,340 @@
+from .. import Provider as PersonProvider
+
+
+class Provider(PersonProvider):
+    """
+    A Faker provider for generating fake Zulu names in South Africa.
+    """
+
+    formats = (
+        "{{first_name_male}} {{last_name_male}}",
+        "{{first_name_male}} {{last_name_male}}",
+        "{{first_name_male}} {{last_name_male}}",
+        "{{first_name_male}} {{last_name_male}}",
+        "{{first_name_male}} {{last_name_male}} {{last_name_male}}",
+        "{{first_name_female}} {{last_name_female}}",
+        "{{first_name_female}} {{last_name_female}}",
+        "{{first_name_female}} {{last_name_female}}",
+        "{{first_name_female}} {{last_name_female}}",
+        "{{first_name_female}} {{last_name_female}} {{last_name_female}}",
+        "{{prefix_male}} {{first_name_male}} {{last_name_male}}",
+        "{{prefix_female}} {{first_name_female}} {{last_name_female}}",
+        "{{prefix_male}} {{first_name_male}} {{last_name_male}}",
+        "{{prefix_female}} {{first_name_female}} {{last_name_female}}",
+    )
+
+    # first names sourced from:
+    # 1. https://github.com/faker-js/faker/blob/next/src/locales/yo_NG/person/last_name.ts
+    # 2. https://github.com/faker-js/faker/blob/next/src/locales/yo_NG/person/male_first_name.ts
+
+    first_names_male = (
+        "Abayomi",
+        "Abiodun",
+        "Abiona",
+        "Adebiyi",
+        "Adebowale",
+        "Adedayo",
+        "Adedeji",
+        "Adekitan",
+        "Adekola",
+        "Adekunle",
+        "Adeleke",
+        "Adeniyi",
+        "Adeolu",
+        "Adeoti",
+        "Aderopo",
+        "Adeshina",
+        "Adesoji",
+        "Adetayo",
+        "Adeyi",
+        "Adigun",
+        "Afolarin",
+        "Ajala",
+        "Ajani",
+        "Akanmu",
+        "Akinkunmi",
+        "Akinlabi",
+        "Akinwale",
+        "Alade",
+        "Alamu",
+        "Anjolaoluwa",
+        "Ayinde",
+        "Ayodeji",
+        "Ayodele",
+        "Babasola",
+        "Babatunji",
+        "Babawale",
+        "Damife",
+        "Demilade",
+        "Durodola",
+        "Ekundayo",
+        "Esupofo",
+        "Folu",
+        "Gbadebo",
+        "Gbolahan",
+        "Gbowoade",
+        "Ibidapo",
+        "Ige",
+        "Ikeoluwa",
+        "Inioluwa",
+        "Iseoluwa",
+        "Ishola",
+        "Juwon",
+        "Keji",
+        "Kolawole",
+        "Korede",
+        "Leke",
+        "Lere",
+        "Niyilolawa",
+        "Oba",
+        "ObaniJesu",
+        "Ogooluwa",
+        "Oke",
+        "Oladare",
+        "Oladimeji",
+        "Olakunle",
+        "Olanrewaju",
+        "Olansile",
+        "Olumorotimi",
+        "Oluwafemi",
+        "Oluwagbemiga",
+        "Oluwamumibori",
+        "Oluwamuyiwa",
+        "Oluwasanmi",
+        "Oluwasegun",
+        "Oluwole",
+        "Omobobola",
+        "Omotayo",
+        "Osunleke",
+        "Seye",
+        "Shekoni",
+        "Sijuade",
+        "Tade",
+        "Temidayo",
+        "Toki",
+        "Tokunbo",
+        "Tomori",
+    )
+    first_names_female = (
+        "Aanuoluwapo",
+        "Abebi",
+        "Abeni",
+        "Abosede",
+        "Adebukola",
+        "Adenike",
+        "Adepeju",
+        "Adesewa",
+        "Adesua",
+        "Adetoke",
+        "Adetoun",
+        "Adunni",
+        "Ajoke",
+        "Amoke",
+        "Amope",
+        "Arike",
+        "Arinola",
+        "Asake",
+        "Atinuke",
+        "Awero",
+        "Ayinke",
+        "Ayoka",
+        "Bolatito",
+        "Boluwatife",
+        "Bunmi",
+        "Doyinsola",
+        "Eniola",
+        "Ewatomi",
+        "Fadekemi",
+        "Faderera",
+        "Fehintola",
+        "Fibikemi",
+        "Fikayomi",
+        "Folashade",
+        "Ibironke",
+        "Iretioluwa",
+        "Iyabode",
+        "Iyadunni",
+        "Kikelomo",
+        "Modupe",
+        "Mofifoluwa",
+        "Mojisola",
+        "Mojisoluwa",
+        "Moradeke",
+        "Morayo",
+        "Morenike",
+        "Morolake",
+        "Mosinmileoluwa",
+        "Mosunmola",
+        "Motunrayo",
+        "Moyosore",
+        "Ninioluwa",
+        "Olajumoke",
+        "Olasunmbo",
+        "Ololade",
+        "Olufunke",
+        "Olufunmilayo",
+        "Oluwakemi",
+        "Omobolanle",
+        "Omodunni",
+        "Omolabake",
+        "Omolara",
+        "Omosalewa",
+        "Omotara",
+        "Omotola",
+        "Omotoun",
+        "Omowumi",
+        "Oreofe",
+        "Oyenike",
+        "Oyindasola",
+        "Radeke",
+        "Ronke",
+        "Segilola",
+        "Similoluwa",
+        "Simisola",
+        "Sowande",
+        "Subomi",
+        "Titilayo",
+        "Tolulope",
+        "Toluwanimi",
+        "Wuraola",
+        "Yejide",
+        "Yetunde",
+        "Yewande",
+    )
+
+    first_names = first_names_male + first_names_female
+
+    # last names sourced from :
+    # 1. https://github.com/faker-js/faker/blob/next/src/locales/yo_NG/person/last_name.ts
+    last_names_male = (
+        "Adebisi",
+        "Adegbite",
+        "Adegoke",
+        "Adekunle",
+        "Adelakun",
+        "Adeleke",
+        "Adelusi",
+        "Ademiluyi",
+        "Aderibigbe",
+        "Aderogba",
+        "Adesiyan",
+        "Adeyemo",
+        "Adisa",
+        "Afolabi",
+        "Afolayan",
+        "Afonja",
+        "Ajao",
+        "Ajayi",
+        "Ajewole",
+        "Akinrinola",
+        "Alabi",
+        "Aloba",
+        "Awodiran",
+        "Awolowo",
+        "Ayandokun",
+        "Ayoola",
+        "Babtunde",
+        "Bakare",
+        "Balogun",
+        "Bamidele",
+        "Bamiloye",
+        "Edun",
+        "Fadipe",
+        "Fagunwa",
+        "Fajimi",
+        "Falabi",
+        "Faleti",
+        "Faloye",
+        "Fasasi",
+        "Ibikunle",
+        "Ilori",
+        "Ilupeju",
+        "Iyanda",
+        "Jaiyeola",
+        "Kolade",
+        "Kosoko",
+        "Koya",
+        "Makinde",
+        "Makinwa",
+        "Morawo",
+        "Ninalowo",
+        "Odetola",
+        "Odunsi",
+        "Ogindan",
+        "Oginni",
+        "Ogulana",
+        "Ogunbamigbe",
+        "Ogunbiyi",
+        "Ogunbo",
+        "Ogunde",
+        "Ogunwobi",
+        "Ogunyeye",
+        "Ojo",
+        "Ojua",
+        "Olabode",
+        "Oladipupo",
+        "Olaiya",
+        "Olasupo",
+        "Olowokeere",
+        "Oloyede",
+        "Olubode",
+        "Olugbayila",
+        "Olujimi",
+        "Olukotun",
+        "Olukunga",
+        "Olusanya",
+        "Oluwagbemi",
+        "Omidina",
+        "Omojola",
+        "Omotoso",
+        "Oparinde",
+        "Oshin",
+        "Osuntokun",
+        "Owokoniran",
+        "Owolabi",
+        "Owoyemi",
+        "Oyadiran",
+        "Oyaifo",
+        "Oyeniyi",
+        "Oyetoro",
+        "Oyeyemi",
+        "Oyinlola",
+        "Paimo",
+        "Salako",
+        "Salami",
+        "Shekoni",
+        "Sobowale",
+        "Soyinka",
+    )
+
+    # last names are not sex dependant
+    last_names_female = last_names_male
+    last_names = last_names_male + last_names_female
+
+    prefixes_female = (
+        "Mrs.",
+        "Ms.",
+        "Dr.",
+        "Alhaja",
+        "Mama",
+        "Iya",
+        "Madam",
+        "Chief",
+        "Lady",
+        "Erelu",
+        "Olori",
+        "Princess",
+    )
+
+    prefixes_male = (
+        "Mr.",
+        "Dr.",
+        "Alhaji",
+        "Baba",
+        "Ogbeni",
+        "Oloye",
+        "Chief",
+        "Prince",
+        "Oba",
+        "Kabiyesi",
+    )
diff --git a/faker/providers/python/__init__.py b/faker/providers/python/__init__.py
index b4ebef28..136f4f56 100644
--- a/faker/providers/python/__init__.py
+++ b/faker/providers/python/__init__.py
@@ -5,6 +5,7 @@ import warnings
 
 from decimal import Decimal
 from enum import Enum
+from numbers import Number
 from typing import Any, Dict, Iterable, Iterator, List, Optional, Set, Tuple, Type, TypeVar, Union, cast, no_type_check
 
 from ...exceptions import BaseFakerException
@@ -284,8 +285,8 @@ class Provider(BaseProvider):
         left_digits: Optional[int] = None,
         right_digits: Optional[int] = None,
         positive: bool = False,
-        min_value: Optional[float] = None,
-        max_value: Optional[float] = None,
+        min_value: Optional[Number] = None,
+        max_value: Optional[Number] = None,
     ) -> Decimal:
         if left_digits is not None and left_digits < 0:
             raise ValueError("A decimal number cannot have less than 0 digits in its " "integer part")


Test patch:
diff --git a/tests/providers/test_person.py b/tests/providers/test_person.py
index 19ca4a6f..ee5ac157 100644
--- a/tests/providers/test_person.py
+++ b/tests/providers/test_person.py
@@ -36,6 +36,7 @@ from faker.providers.person.ta_IN import Provider as TaINProvider
 from faker.providers.person.th_TH import Provider as ThThProvider
 from faker.providers.person.uk_UA import Provider as UkUAProvider
 from faker.providers.person.uk_UA import translit as UkUATranslit
+from faker.providers.person.yo_NG import Provider as YoNGProvider
 from faker.providers.person.zh_CN import Provider as ZhCNProvider
 from faker.providers.person.zh_TW import Provider as ZhTWProvider
 from faker.providers.person.zu_ZA import Provider as ZuZAProvider
@@ -1397,6 +1398,85 @@ class TestGaIE(TestEnIE):
         Faker.seed(0)
 
 
+class TestYoNG(unittest.TestCase):
+    def setUp(self):
+        self.fake = Faker("yo_NG")
+        Faker.seed(0)
+
+    def test_last_name(self):
+        """
+        Test the generation of Zulu last names.
+        """
+        # There's no gender-specific last name in Zulu.
+        self.assertTrue(hasattr(YoNGProvider, "last_names_male"))
+        self.assertTrue(hasattr(YoNGProvider, "last_names_female"))
+
+        # All last names apply to all genders.
+        self.assertTrue(hasattr(YoNGProvider, "last_names"))
+
+        # General last name.
+        name = self.fake.last_name()
+        self.assertIsInstance(name, str)
+        self.assertIn(name, YoNGProvider.last_names)
+
+        # Females last name.
+        name = self.fake.last_name_female()
+        self.assertIsInstance(name, str)
+        self.assertIn(name, YoNGProvider.last_names)
+
+        # Male last name.
+        name = self.fake.last_name_male()
+        self.assertIsInstance(name, str)
+        self.assertIn(name, YoNGProvider.last_names)
+
+    def test_first_name(self):
+        """
+        Test the generation of Zulu first names.
+        """
+        # General first name.
+        name = self.fake.first_name()
+        self.assertIsInstance(name, str)
+        self.assertIn(name, YoNGProvider.first_names)
+
+        # Female first name.
+        name = self.fake.first_name_female()
+        self.assertIsInstance(name, str)
+        self.assertIn(name, YoNGProvider.first_names)
+        self.assertIn(name, YoNGProvider.first_names_female)
+
+        # Male first name.
+        name = self.fake.first_name_male()
+        self.assertIsInstance(name, str)
+        self.assertIn(name, YoNGProvider.first_names)
+        self.assertIn(name, YoNGProvider.first_names_male)
+
+    def test_full_name(self):
+        """
+        Test the generation of full Zulu names.
+        """
+        # Full name.
+        name = self.fake.name()
+        self.assertIsInstance(name, str)
+
+        full_name_parts = name.split()
+
+        if len(full_name_parts) == 2:
+            first_name = full_name_parts[0]
+            last_name = full_name_parts[1]
+            self.assertIn(first_name, YoNGProvider.first_names)
+            self.assertIn(last_name, YoNGProvider.last_names)
+        elif len(full_name_parts) == 3:
+            prefix = full_name_parts[0]
+            first_name = full_name_parts[1]
+            last_name = full_name_parts[2]
+
+            self.assertIn(prefix, YoNGProvider.prefixes_female + YoNGProvider.prefixes_male)
+            self.assertIn(first_name, YoNGProvider.first_names)
+            self.assertIn(last_name, YoNGProvider.last_names)
+        else:
+            raise AssertionError("Invalid number of name parts. Expected 2 or 3.")
+
+
 class TestZuZa(unittest.TestCase):
     def setUp(self):
         self.fake = Faker("zu_ZA")