diff --git a/faker/providers/address/mr_IN/__init__.py b/faker/providers/address/mr_IN/__init__.py new file mode 100644 index 0000000000..3ce37ce1c8 --- /dev/null +++ b/faker/providers/address/mr_IN/__init__.py @@ -0,0 +1,126 @@ +from .. import Provider as AddressProvider + + +class Provider(AddressProvider): + city_formats = ("{{city_name}}",) + + street_name_formats = ( + "{{first_name}} {{last_name}}", + "{{last_name}}", + ) + + street_address_formats = ("{{building_number}} {{street_name}}",) + + address_formats = ( + "{{street_address}}\n{{city}} {{postcode}}", + "{{street_address}}\n{{city}}-{{postcode}}", + ) + + building_number_formats = ( + "####", + "###", + "##", + "#", + "#/#", + "##/##", + "##/###", + "##/####", + ) + + postcode_formats = ("######",) + + # Source references (accessed 2026-04-18): + # - https://en.wikipedia.org/wiki/List_of_cities_in_Maharashtra_by_population (cities) + # - https://www.india.gov.in/my-government/states-uts (states baseline) + # - https://github.com/unicode-org/cldr-json/blob/main/cldr-json/cldr-localenames-full/main/mr/territories.json + # (Marathi territory/country names) + # Data is manually filtered and normalized for Faker synthetic generation. + + cities = ( + "अहमदनगर", + "अकोला", + "अमरावती", + "औरंगाबाद", + "उस्मानाबाद", + "कोल्हापूर", + "गोंदिया", + "चंद्रपूर", + "जळगाव", + "ठाणे", + "धुळे", + "नवी मुंबई", + "नागपूर", + "नांदेड", + "नाशिक", + "पिंपरी-चिंचवड", + "पुणे", + "परभणी", + "बीड", + "मुंबई", + "मिरज", + "यवतमाळ", + "रत्नागिरी", + "लातूर", + "वसई", + "सांगली", + "सातारा", + "सोलापूर", + "हिंगोली", + ) + + states = ( + "आंध्र प्रदेश", + "अरुणाचल प्रदेश", + "आसाम", + "उत्तर प्रदेश", + "उत्तराखंड", + "ओडिशा", + "कर्नाटक", + "केरळ", + "गोवा", + "गुजरात", + "छत्तीसगड", + "झारखंड", + "तामिळनाडू", + "तेलंगणा", + "त्रिपुरा", + "नागालँड", + "पंजाब", + "पश्चिम बंगाल", + "बिहार", + "मणिपूर", + "मध्य प्रदेश", + "महाराष्ट्र", + "मेघालय", + "मिझोरम", + "राजस्थान", + "सिक्कीम", + "हरियाणा", + "हिमाचल प्रदेश", + ) + + countries = ( + "ऑस्ट्रेलिया", + "कॅनडा", + "जर्मनी", + "जपान", + "नेपाळ", + "पाकिस्तान", + "भारत", + "भूतान", + "बांग्लादेश", + "फ्रान्स", + "युनायटेड किंगडम", + "संयुक्त अरब अमिरात", + "संयुक्त राज्य अमेरिका", + "सिंगापूर", + "श्रीलंका", + ) + + def city_name(self) -> str: + return self.random_element(self.cities) + + def administrative_unit(self) -> str: + return self.random_element(self.states) + + state = administrative_unit diff --git a/faker/providers/date_time/mr_IN/__init__.py b/faker/providers/date_time/mr_IN/__init__.py new file mode 100644 index 0000000000..bf5a2fc2b1 --- /dev/null +++ b/faker/providers/date_time/mr_IN/__init__.py @@ -0,0 +1,40 @@ +from .. import Provider as DateTimeProvider + + +class Provider(DateTimeProvider): + # Source references (accessed 2026-04-18): + # - https://mr.wikipedia.org/wiki/वार: (Marathi weekday naming) + # - https://mr.wikipedia.org/wiki/महिने: (Marathi month naming) + # Data is normalized for synthetic locale generation. + DAY_NAMES = { + "0": "रविवार", + "1": "सोमवार", + "2": "मंगळवार", + "3": "बुधवार", + "4": "गुरुवार", + "5": "शुक्रवार", + "6": "शनिवार", + } + + MONTH_NAMES = { + "01": "जानेवारी", + "02": "फेब्रुवारी", + "03": "मार्च", + "04": "एप्रिल", + "05": "मे", + "06": "जून", + "07": "जुलै", + "08": "ऑगस्ट", + "09": "सप्टेंबर", + "10": "ऑक्टोबर", + "11": "नोव्हेंबर", + "12": "डिसेंबर", + } + + def day_of_week(self) -> str: + day = self.date("%w") + return self.DAY_NAMES[day] + + def month_name(self) -> str: + month = self.month() + return self.MONTH_NAMES[month] diff --git a/faker/providers/person/mr_IN/__init__.py b/faker/providers/person/mr_IN/__init__.py new file mode 100644 index 0000000000..a2d7948eeb --- /dev/null +++ b/faker/providers/person/mr_IN/__init__.py @@ -0,0 +1,160 @@ +from .. import Provider as PersonProvider + + +class Provider(PersonProvider): + + formats_male = ( + "{{first_name_male}} {{last_name}}", + "{{prefix_male}} {{first_name_male}} {{last_name}}", + "{{first_name_male}} {{last_name}}{{suffix}}", + ) + + formats_female = ( + "{{first_name_female}} {{last_name}}", + "{{prefix_female}} {{first_name_female}} {{last_name}}", + "{{first_name_female}} {{last_name}}{{suffix}}", + ) + + formats = ( + "{{first_name}} {{last_name}}", + "{{prefix}} {{first_name}} {{last_name}}", + "{{first_name}} {{last_name}}{{suffix}}", + ) + + # Source references (accessed 2026-04-18): + # - https://www.behindthename.com/names/usage/marathi (given names) + # - https://en.wikipedia.org/wiki/Category:Marathi-language_surnames (surnames) + # Data is manually filtered for synthetic test-data suitability. + + first_names_female = ( + "अंजली", + "अनिता", + "अनुष्का", + "अपर्णा", + "आकांक्षा", + "आशा", + "इशिता", + "उमा", + "कविता", + "कल्पना", + "कीर्ती", + "कोमल", + "गौरी", + "चेतना", + "ज्योती", + "तन्वी", + "दीपाली", + "नेहा", + "पल्लवी", + "पूजा", + "प्रज्ञा", + "प्रिया", + "माधुरी", + "मानसी", + "मीनल", + "मेघा", + "रेणुका", + "रीमा", + "रोहिणी", + "लता", + "वैशाली", + "शिल्पा", + "श्रुती", + "स्मिता", + "स्वाती", + "स्नेहा", + "हर्षदा", + ) + + first_names_male = ( + "अभिजीत", + "अभिषेक", + "अमित", + "अमोल", + "अनिल", + "अनिरुद्ध", + "अरुण", + "अशोक", + "आदित्य", + "आकाश", + "ईश्वर", + "उमेश", + "किरण", + "कैलास", + "गणेश", + "गौरव", + "चेतन", + "जितेंद्र", + "दत्तात्रेय", + "दीपक", + "धनंजय", + "निखिल", + "निलेश", + "पंकज", + "प्रकाश", + "प्रवीण", + "प्रशांत", + "भूषण", + "मकरंद", + "मंगेश", + "माधव", + "मिलिंद", + "मोहन", + "राहुल", + "रोहित", + "विकास", + "विनायक", + "विवेक", + "सचिन", + "संदीप", + "समीर", + "सुनील", + "सुरेश", + "हर्षद", + ) + + first_names = first_names_female + first_names_male + + last_names = ( + "आगरकर", + "अहेर", + "ओक", + "कदम", + "कांबळे", + "कुलकर्णी", + "कोल्हे", + "गवळी", + "गायकवाड", + "चव्हाण", + "चौगुले", + "जगताप", + "जाधव", + "जोशी", + "ठाकूर", + "देशमुख", + "देशपांडे", + "पाटील", + "पवार", + "फडके", + "भोसले", + "महाजन", + "माने", + "मोरे", + "राऊत", + "शिंदे", + "शिरसाट", + "साळुंखे", + "साने", + "सावंत", + ) + + prefixes_female = ( + "श्रीमती", + "कुमारी", + ) + + prefixes_male = ("श्री",) + + prefixes = prefixes_female + prefixes_male + + suffixes = ("जी",) diff --git a/faker/providers/phone_number/mr_IN/__init__.py b/faker/providers/phone_number/mr_IN/__init__.py new file mode 100644 index 0000000000..d4e533505d --- /dev/null +++ b/faker/providers/phone_number/mr_IN/__init__.py @@ -0,0 +1,15 @@ +from .. import Provider as PhoneNumberProvider + + +class Provider(PhoneNumberProvider): + # Source references (accessed 2026-04-18): + # - https://dot.gov.in/numbering-resources (India numbering resources) + # - Faker locale patterns in `phone_number/hi_IN` and `phone_number/ta_IN` + # Patterns are intended for structurally valid synthetic Indian numbers. + formats = ( + "+91 ##########", + "+91 ### #######", + "0##-########", + "0##########", + "0#### ######", + ) diff --git a/tests/providers/test_address.py b/tests/providers/test_address.py index 9b2b0b56ab..0591fc815e 100644 --- a/tests/providers/test_address.py +++ b/tests/providers/test_address.py @@ -43,6 +43,7 @@ from faker.providers.address.ja_JP import Provider as JaJpAddressProvider from faker.providers.address.ka_GE import Provider as KaGeAddressProvider from faker.providers.address.ko_KR import Provider as KoKrAddressProvider +from faker.providers.address.mr_IN import Provider as MrInAddressProvider from faker.providers.address.ne_NP import Provider as NeNpAddressProvider from faker.providers.address.no_NO import Provider as NoNoAddressProvider from faker.providers.address.pl_PL import Provider as PlPlAddressProvider @@ -1976,6 +1977,28 @@ def test_road_address(self, faker, num_samples): assert isinstance(road_address, str) +class TestMrIn: + """Test mr_IN address provider methods""" + + def test_city_name(self, faker, num_samples): + for _ in range(num_samples): + city_name = faker.city_name() + assert isinstance(city_name, str) + assert city_name in MrInAddressProvider.cities + + def test_state(self, faker, num_samples): + for _ in range(num_samples): + state = faker.state() + assert isinstance(state, str) + assert state in MrInAddressProvider.states + + def test_country(self, faker, num_samples): + for _ in range(num_samples): + country = faker.country() + assert isinstance(country, str) + assert country in MrInAddressProvider.countries + + class TestNeNp: """Test ne_NP address provider methods""" diff --git a/tests/providers/test_date_time.py b/tests/providers/test_date_time.py index fbf7d732f0..b28378186d 100644 --- a/tests/providers/test_date_time.py +++ b/tests/providers/test_date_time.py @@ -34,6 +34,7 @@ from faker.providers.date_time.it_IT import Provider as ItItProvider from faker.providers.date_time.ja_JP import Provider as JaJpProvider from faker.providers.date_time.ka_GE import Provider as KaGeProvider +from faker.providers.date_time.mr_IN import Provider as MrINProvider from faker.providers.date_time.nl_NL import Provider as NlProvider from faker.providers.date_time.no_NO import Provider as NoNoProvider from faker.providers.date_time.pl_PL import Provider as PlProvider @@ -838,6 +839,24 @@ def test_month_in_guj(self): assert month in GuINProvider.MONTH_NAMES_IN_GUJARATI.values() +class TestMrIN(unittest.TestCase): + """Tests date_time in the mr_IN locale""" + + def setUp(self): + self.fake = Faker("mr_IN") + Faker.seed(0) + + def test_day(self): + day = self.fake.day_of_week() + assert isinstance(day, str) + assert day in MrINProvider.DAY_NAMES.values() + + def test_month(self): + month = self.fake.month_name() + assert isinstance(month, str) + assert month in MrINProvider.MONTH_NAMES.values() + + class TestHyAm(unittest.TestCase): """Tests date_time in the hy_AM locale""" diff --git a/tests/providers/test_person.py b/tests/providers/test_person.py index 0296123df3..823337da90 100644 --- a/tests/providers/test_person.py +++ b/tests/providers/test_person.py @@ -35,6 +35,7 @@ from faker.providers.person.ig_NG import Provider as IgNgProvider from faker.providers.person.is_IS import Provider as IsISProvider from faker.providers.person.lv_LV import Provider as LvProvider +from faker.providers.person.mr_IN import Provider as MrINProvider 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 @@ -1504,6 +1505,55 @@ def test_last_name(self): assert name in LvProvider.last_names_male +class TestMrIN(unittest.TestCase): + """Tests person in the mr_IN locale""" + + def setUp(self): + self.fake = Faker("mr_IN") + Faker.seed(0) + + def test_first_name(self): + name = self.fake.first_name() + assert name in MrINProvider.first_names + + name = self.fake.first_name_male() + assert name in MrINProvider.first_names_male + + name = self.fake.first_name_female() + assert name in MrINProvider.first_names_female + + def test_last_name(self): + last_name = self.fake.last_name() + assert last_name in MrINProvider.last_names + + def test_prefix(self): + prefix = self.fake.prefix() + assert prefix in MrINProvider.prefixes + + prefix = self.fake.prefix_male() + assert prefix in MrINProvider.prefixes_male + + prefix = self.fake.prefix_female() + assert prefix in MrINProvider.prefixes_female + + def test_name(self): + name = self.fake.name().split() + assert all(isinstance(n, str) for n in name) + + prefixes = MrINProvider.prefixes + if len(name) == 3: + assert name[0] in prefixes + assert name[1] in MrINProvider.first_names + assert name[2] in MrINProvider.last_names + else: + assert name[0] in MrINProvider.first_names + if name[1].endswith(MrINProvider.suffixes): + assert name[1][:-1] in MrINProvider.last_names + assert name[1][-1] in MrINProvider.suffixes + else: + assert name[1] in MrINProvider.last_names + + class TestNeNP(unittest.TestCase): def setUp(self): self.fake = Faker("ne_NP") diff --git a/tests/providers/test_phone_number.py b/tests/providers/test_phone_number.py index 92c4e3e2e7..a3cf0c81d4 100644 --- a/tests/providers/test_phone_number.py +++ b/tests/providers/test_phone_number.py @@ -476,6 +476,18 @@ def test_phone_number(self, faker, num_samples): assert pattern.fullmatch(phone_number) +class TestMrIn: + """Test mr_IN phone number provider methods""" + + def test_phone_number(self, faker, num_samples): + pattern: Pattern = re.compile( + r"\+91 \d{10}|" r"\+91 \d{3} \d{7}|" r"0\d{2}-\d{8}|" r"0\d{10}|" r"0\d{4} \d{6}", + ) + for _ in range(num_samples): + phone_number = faker.phone_number() + assert pattern.fullmatch(phone_number) + + class TestTaIn: """Test ta_IN phone number provider methods"""