Skip to content

Commit

Permalink
Extend Person Provider to support nonbinary suffixes and prefixes (#1206
Browse files Browse the repository at this point in the history
)

* Implement nonbinary Person Provider

* Address flake8 and isort findings

* Fix import ordering in tests

* Add tests for en Provider to test preexisting suffix scenario

* Refine tests for en Provider
  • Loading branch information
crd authored Jun 21, 2020
1 parent 7ecd296 commit 03a1a66
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 0 deletions.
36 changes: 36 additions & 0 deletions faker/providers/person/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ def name_male(self):
pattern = self.random_element(formats)
return self.generator.parse(pattern)

def name_nonbinary(self):
if hasattr(self, 'formats_nonbinary'):
formats = self.formats_nonbinary
else:
formats = self.formats
pattern = self.random_element(formats)
return self.generator.parse(pattern)

def name_female(self):
if hasattr(self, 'formats_female'):
formats = self.formats_female
Expand All @@ -80,6 +88,11 @@ def first_name_male(self):
return self.random_element(self.first_names_male)
return self.first_name()

def first_name_nonbinary(self):
if hasattr(self, 'first_names_nonbinary'):
return self.random_element(self.first_names_nonbinary)
return self.first_name()

def first_name_female(self):
if hasattr(self, 'first_names_female'):
return self.random_element(self.first_names_female)
Expand All @@ -90,6 +103,11 @@ def last_name_male(self):
return self.random_element(self.last_names_male)
return self.last_name()

def last_name_nonbinary(self):
if hasattr(self, 'last_names_nonbinary'):
return self.random_element(self.last_names_nonbinary)
return self.last_name()

def last_name_female(self):
if hasattr(self, 'last_names_female'):
return self.random_element(self.last_names_female)
Expand All @@ -98,6 +116,10 @@ def last_name_female(self):
def prefix(self):
if hasattr(self, 'prefixes'):
return self.random_element(self.prefixes)
if hasattr(self, 'prefixes_male') and hasattr(self, 'prefixes_female') and hasattr(self, 'prefixes_nonbinary'):
prefixes = self.random_element(
(self.prefixes_male, self.prefixes_female, self.prefixes_nonbinary))
return self.random_element(prefixes)
if hasattr(self, 'prefixes_male') and hasattr(self, 'prefixes_female'):
prefixes = self.random_element(
(self.prefixes_male, self.prefixes_female))
Expand All @@ -109,6 +131,11 @@ def prefix_male(self):
return self.random_element(self.prefixes_male)
return self.prefix()

def prefix_nonbinary(self):
if hasattr(self, 'prefixes_nonbinary'):
return self.random_element(self.prefixes_nonbinary)
return self.prefix()

def prefix_female(self):
if hasattr(self, 'prefixes_female'):
return self.random_element(self.prefixes_female)
Expand All @@ -117,6 +144,10 @@ def prefix_female(self):
def suffix(self):
if hasattr(self, 'suffixes'):
return self.random_element(self.suffixes)
if hasattr(self, 'suffixes_male') and hasattr(self, 'suffixes_female') and hasattr(self, 'suffixes_nonbinary'):
suffixes = self.random_element(
(self.suffixes_male, self.suffixes_female, self.suffixes_nonbinary))
return self.random_element(suffixes)
if hasattr(self, 'suffixes_male') and hasattr(self, 'suffixes_female'):
suffixes = self.random_element(
(self.suffixes_male, self.suffixes_female))
Expand All @@ -128,6 +159,11 @@ def suffix_male(self):
return self.random_element(self.suffixes_male)
return self.suffix()

def suffix_nonbinary(self):
if hasattr(self, 'suffixes_nonbinary'):
return self.random_element(self.suffixes_nonbinary)
return self.suffix()

def suffix_female(self):
if hasattr(self, 'suffixes_female'):
return self.random_element(self.suffixes_female)
Expand Down
20 changes: 20 additions & 0 deletions faker/providers/person/en_US/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ class Provider(PersonProvider):
('{{prefix_female}} {{first_name_female}} {{last_name}} {{suffix_female}}', 0.005),
))

formats_nonbinary = OrderedDict((
('{{first_name_nonbinary}} {{last_name}}', 0.97),
('{{prefix_nonbinary}} {{first_name_nonbinary}} {{last_name}}', 0.015),
('{{first_name_nonbinary}} {{last_name}} {{suffix_nonbinary}}', 0.02),
('{{prefix_nonbinary}} {{first_name_nonbinary}} {{last_name}} {{suffix_nonbinary}}', 0.005),
))

formats_male = OrderedDict((
('{{first_name_male}} {{last_name}}', 0.97),
('{{prefix_male}} {{first_name_male}} {{last_name}}', 0.015),
Expand Down Expand Up @@ -741,6 +748,9 @@ class Provider(PersonProvider):
first_names = first_names_male.copy()
first_names.update(first_names_female)

first_names_nonbinary = first_names_male.copy()
first_names_nonbinary.update(first_names_female)

# Top 1000 US surnames from US Census data
# Weighted by number of occurrences
# By way of http://names.mongabay.com/data/1000.html on 2/10/2016
Expand Down Expand Up @@ -1758,6 +1768,14 @@ class Provider(PersonProvider):
('Dr.', 0.3),
))

# https://en.wikipedia.org/wiki/Gender-neutral_title
prefixes_nonbinary = OrderedDict((
('Mx.', 0.5),
('Ind.', 0.1),
('Misc.', 0.1),
('Dr.', 0.3),
))

suffixes_female = OrderedDict((
('MD', 0.5),
('DDS', 0.3),
Expand All @@ -1777,3 +1795,5 @@ class Provider(PersonProvider):
('PhD', 0.1),
('DVM', 0.1),
))

suffixes_nonbinary = suffixes_male.copy()
85 changes: 85 additions & 0 deletions tests/providers/test_person.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from faker import Faker
from faker.providers.person.ar_AA import Provider as ArProvider
from faker.providers.person.cs_CZ import Provider as CsCZProvider
from faker.providers.person.en import Provider as EnProvider
from faker.providers.person.en_US import Provider as EnUSProvider
from faker.providers.person.es_ES import Provider as EsESProvider
from faker.providers.person.fi_FI import Provider as FiProvider
from faker.providers.person.hy_AM import Provider as HyAmProvider
Expand Down Expand Up @@ -611,3 +613,86 @@ def setUp(self):
def test_language_name(self):
language_name = self.fake.language_name()
assert language_name in EsESProvider.language_names


class TestUs(unittest.TestCase):
""" Tests person in the en_US locale """

def setUp(self):
self.fake = Faker('en_US')
Faker.seed(0)

def test_first_names(self):
# General first name
name = self.fake.first_name()
self.assertIsInstance(name, str)
assert name in EnUSProvider.first_names

# Female first name
name = self.fake.first_name_female()
self.assertIsInstance(name, str)
assert name in EnUSProvider.first_names
assert name in EnUSProvider.first_names_female

# Male first name
name = self.fake.first_name_male()
self.assertIsInstance(name, str)
assert name in EnUSProvider.first_names
assert name in EnUSProvider.first_names_male

# Nonbinary first name
name = self.fake.first_name_nonbinary()
self.assertIsInstance(name, str)
assert name in EnUSProvider.first_names
assert name in EnUSProvider.first_names_nonbinary

def test_last_names(self):

# General last name
name = self.fake.last_name()
self.assertIsInstance(name, str)
assert name in EnUSProvider.last_names

# Female last name
name = self.fake.last_name_female()
self.assertIsInstance(name, str)
assert name in EnUSProvider.last_names

# Male last name
name = self.fake.last_name_male()
self.assertIsInstance(name, str)
assert name in EnUSProvider.last_names

# Nonbinary last name
name = self.fake.last_name_nonbinary()
self.assertIsInstance(name, str)
assert name in EnUSProvider.last_names

def test_prefix(self):

# Nonbinary prefix
prefix = self.fake.prefix_nonbinary()
self.assertIsInstance(prefix, str)
assert prefix in EnUSProvider.prefixes_nonbinary

def test_suffix(self):

# Nonbinary suffix
suffix = self.fake.suffix_nonbinary()
self.assertIsInstance(suffix, str)
assert suffix in EnUSProvider.suffixes_nonbinary


class TestEn(unittest.TestCase):
""" Tests person in the en locale """

def setUp(self):
self.fake = Faker('en')
Faker.seed(0)

def test_suffix(self):

# Traditional suffix -- provider does not offer a nonbinary suffix at this time
suffix = self.fake.suffix()
self.assertIsInstance(suffix, str)
assert suffix in EnProvider.suffixes_male or suffix in EnProvider.suffixes_female

0 comments on commit 03a1a66

Please sign in to comment.