Repository: joke2k/faker
Pull request #1922 (2023-10-09 11:46:13)

Gender support for Latvian (lv_LV) names
### What does this change

Separated male and female person first names and last names.


Patch:
diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index e36b5a73..9d2714eb 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 19.6.2
+current_version = 19.7.0
 files = VERSION faker/__init__.py docs/conf.py
 commit = True
 tag = True
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 429fdaa1..1a0267f9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 ## Changelog
 
+### [v19.7.0 - 2023-10-09](https://github.com/joke2k/faker/compare/v19.6.2...v19.7.0)
+
+* Add MAC Address Multicast. Thanks @d3vyce.
+
 ### [v19.6.2 - 2023-09-20](https://github.com/joke2k/faker/compare/v19.6.1...v19.6.2)
 
 * fix type error in `pyfloat`  when `max_value` is `None`. Thanks @HugoJP1.
diff --git a/VERSION b/VERSION
index d518155b..e669eb0b 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-19.6.2
+19.7.0
diff --git a/docs/conf.py b/docs/conf.py
index 1643558b..dbd6ad4d 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 = "19.6.2"
+version = "19.7.0"
 # The full version, including alpha/beta/rc tags.
-release = "19.6.2"
+release = "19.7.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 33ce6599..70f15612 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 = "19.6.2"
+VERSION = "19.7.0"
 
 __all__ = ("Factory", "Generator", "Faker")
diff --git a/faker/providers/internet/__init__.py b/faker/providers/internet/__init__.py
index 9dc35254..9898c96e 100644
--- a/faker/providers/internet/__init__.py
+++ b/faker/providers/internet/__init__.py
@@ -582,8 +582,18 @@ class Provider(BaseProvider):
             address = str(IPv6Network(address, strict=False))
         return address
 
-    def mac_address(self) -> str:
-        mac = [self.generator.random.randint(0x00, 0xFF) for _ in range(0, 6)]
+    def mac_address(self, multicast: bool = False) -> str:
+        """
+        Returns a random MAC address.
+
+        :param multicast: Multicast address
+        :returns: MAC Address
+        """
+        mac = [self.generator.random.randint(0x00, 0xFF) for _ in range(0, 5)]
+        if multicast is True:
+            mac.insert(0, self.generator.random.randrange(0x01, 0xFF, 2))
+        else:
+            mac.insert(0, self.generator.random.randrange(0x00, 0xFE, 2))
         return ":".join("%02x" % x for x in mac)
 
     def port_number(self, is_system: bool = False, is_user: bool = False, is_dynamic: bool = False) -> int:
diff --git a/faker/providers/passport/__init__.py b/faker/providers/passport/__init__.py
index b624be1e..0641ed71 100644
--- a/faker/providers/passport/__init__.py
+++ b/faker/providers/passport/__init__.py
@@ -15,7 +15,7 @@ class Provider(BaseProvider):
     passport_number_formats: ElementsType = ()
 
     def passport_dob(self) -> datetime.date:
-        """Generate a datetime date of bisrth."""
+        """Generate a datetime date of birth."""
         birthday = self.generator.date_of_birth()
         return birthday
 
diff --git a/faker/providers/person/lv_LV/__init__.py b/faker/providers/person/lv_LV/__init__.py
index 798eb130..05a24c23 100644
--- a/faker/providers/person/lv_LV/__init__.py
+++ b/faker/providers/person/lv_LV/__init__.py
@@ -8,7 +8,7 @@ class Provider(PersonProvider):
         "{{last_name}}, {{first_name}}",
     )
 
-    first_names = (
+    first_names_male = (
         "Ādams",
         "Ādolfs",
         "Agris",
@@ -133,6 +133,9 @@ class Provider(PersonProvider):
         "Voldemārs",
         "Ziedonis",
         "Žanis",
+    )
+
+    first_names_female = (
         "Agnese",
         "Aiga",
         "Aija",
@@ -151,7 +154,6 @@ class Provider(PersonProvider):
         "Ārija",
         "Ausma",
         "Austra",
-        "Baba",
         "Baiba",
         "Berta",
         "Biruta",
@@ -283,8 +285,24 @@ class Provider(PersonProvider):
         "Zigrīda",
     )
 
-    last_names = (
+    first_names = first_names_male + first_names_female
+
+    last_names_unisex = (
         "Ābele",
+        "Bite",
+        "Caune",
+        "Krūze",
+        "Lapsa",
+        "Liepa",
+        "Paegle",
+        "Priede",
+        "Roze",
+        "Skuja",
+        "Vīksna",
+        "Zvaigzne",
+    )
+
+    last_names_male = (
         "Āboliņš",
         "Ābols",
         "Alksnis",
@@ -297,9 +315,7 @@ class Provider(PersonProvider):
         "Baltiņš",
         "Bērziņš",
         "Birznieks",
-        "Bite",
         "Briedis",
-        "Caune",
         "Celmiņš",
         "Celms",
         "Cīrulis",
@@ -318,38 +334,30 @@ class Provider(PersonProvider):
         "Krieviņš",
         "Krievs",
         "Krūmiņš",
-        "Krūze",
         "Kundziņš",
         "Lācis",
         "Lagzdiņš",
-        "Lapsa",
         "Līcis",
-        "Liepa",
         "Liepiņš",
         "Lukstiņš",
         "Lūsis",
-        "Paegle",
         "Pērkons",
         "Podnieks",
         "Polis",
-        "Priede",
         "Priedītis",
         "Puriņš",
         "Purmals",
         "Riekstiņš",
-        "Roze",
         "Rozītis",
         "Rubenis",
         "Rudzītis",
         "Saulītis",
         "Siliņš",
-        "Skuja",
         "Skujiņš",
         "Sproģis",
         "Strazdiņš",
         "Turiņš",
         "Vanags",
-        "Vīksna",
         "Vilciņš",
         "Vilks",
         "Vītoliņš",
@@ -360,6 +368,74 @@ class Provider(PersonProvider):
         "Zeltiņš",
         "Ziemelis",
         "Zirnis",
-        "Zvaigzne",
         "Zvirbulis",
     )
+
+    last_names_female = (
+        "Āboliņa",
+        "Ābola",
+        "Alksne",
+        "Apine",
+        "Apsīte",
+        "Auniņa",
+        "Auziņa",
+        "Avotiņa",
+        "Balode",
+        "Bērziņa",
+        "Birzniece",
+        "Briede",
+        "Celmiņa",
+        "Celma",
+        "Cīrule",
+        "Dzene",
+        "Dūmiņa",
+        "Eglīte",
+        "Jaunzema",
+        "Kalēja",
+        "Kalniņa",
+        "Kaņepa",
+        "Kārkliņa",
+        "Kauliņa",
+        "Kļaviņa",
+        "Krastiņa",
+        "Krēsliņa",
+        "Krieviņa",
+        "Krieva",
+        "Krūmiņa",
+        "Kundziņa",
+        "Lāce",
+        "Lagzdiņa",
+        "Līce",
+        "Liepiņa",
+        "Lukstiņa",
+        "Lūse",
+        "Pērkona",
+        "Podniece",
+        "Pole",
+        "Priedīte",
+        "Puriņa",
+        "Purmale",
+        "Riekstiņa",
+        "Rozīte",
+        "Rubene",
+        "Rudzīte",
+        "Saulīte",
+        "Siliņa",
+        "Skujiņa",
+        "Sproģe",
+        "Strazdiņa",
+        "Turiņa",
+        "Vanaga",
+        "Vilciņa",
+        "Vītoliņa",
+        "Vītola",
+        "Zaķe",
+        "Zālīte",
+        "Zariņa",
+        "Zeltiņa",
+        "Ziemele",
+        "Zirne",
+        "Zvirbule",
+    )
+
+    last_names = last_names_male + last_names_female + last_names_unisex


Test patch:
diff --git a/tests/providers/test_internet.py b/tests/providers/test_internet.py
index 9df8ba01..7a877ce5 100644
--- a/tests/providers/test_internet.py
+++ b/tests/providers/test_internet.py
@@ -304,6 +304,15 @@ class TestInternetProvider:
             assert len(address) <= 39 + 4
             assert re.compile(r"^([0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}/\d{1,3}$").search(address)
 
+    def test_mac_address(self, faker):
+        provider = InternetProvider(faker)
+
+        unicast_address = provider.mac_address()
+        assert int(unicast_address[0:2], base=16) % 2 == 0
+
+        multicast_address = provider.mac_address(multicast=True)
+        assert int(multicast_address[0:2], base=16) % 2 == 1
+
     def test_port_number(self, faker, num_samples):
         for _ in range(num_samples):
             assert 0 <= faker.port_number() <= 65535
diff --git a/tests/providers/test_person.py b/tests/providers/test_person.py
index 5002f5a9..6b24d69f 100644
--- a/tests/providers/test_person.py
+++ b/tests/providers/test_person.py
@@ -20,6 +20,7 @@ from faker.providers.person.fr_BE import Provider as FrBEProvider
 from faker.providers.person.ga_IE import Provider as GaIEProvider
 from faker.providers.person.he_IL import Provider as HeILProvider
 from faker.providers.person.hy_AM import Provider as HyAmProvider
+from faker.providers.person.lv_LV import Provider as LvProvider
 from faker.providers.person.ne_NP import Provider as NeProvider
 from faker.providers.person.nl_BE import Provider as NlBEProvider
 from faker.providers.person.or_IN import Provider as OrINProvider
@@ -288,6 +289,64 @@ class TestJaJP(unittest.TestCase):
         assert all(isinstance(s, str) for s in last_name_pair)
 
 
+class TestLvLV(unittest.TestCase):
+    def setUp(self):
+        self.fake = Faker("lv_LV")
+        Faker.seed(0)
+
+    def test_first_name(self):
+        # General first name
+        name = self.fake.first_name()
+        assert name
+        self.assertIsInstance(name, str)
+        assert name in LvProvider.provider.first_names
+
+        # Females first name
+        name = self.fake.first_name_female()
+        assert name
+        self.assertIsInstance(name, str)
+        assert name in LvProvider.provider.first_names
+        assert name in LvProvider.provider.first_names_female
+
+        # Male first name
+        name = self.fake.first_name_male()
+        assert name
+        self.assertIsInstance(name, str)
+        assert name in LvProvider.provider.first_names
+        assert name in LvProvider.provider.first_names_male
+
+    def test_last_name(self):
+        # General last name.
+        name = self.fake.last_name()
+        assert name
+        self.assertIsInstance(name, str)
+        assert name in LvProvider.last_names
+
+        # Females last name.
+        name = self.fake.last_name_female()
+        assert name
+        self.assertIsInstance(name, str)
+        assert name in LvProvider.last_names_female + LvProvider.last_names_unisex
+
+        # Females only last name.
+        name = self.fake.last_name_unique_to_female()
+        assert name
+        self.assertIsInstance(name, str)
+        assert name in LvProvider.last_names_female
+
+        # Male last name.
+        name = self.fake.last_name_male()
+        assert name
+        self.assertIsInstance(name, str)
+        assert name in LvProvider.last_names_male + LvProvider.last_names_unisex
+
+        # Male only last name.
+        name = self.fake.last_name_unique_to_male()
+        assert name
+        self.assertIsInstance(name, str)
+        assert name in LvProvider.last_names_male
+
+
 class TestNeNP(unittest.TestCase):
     def setUp(self):
         self.fake = Faker("ne_NP")