diff --git a/faker/providers/address/en_IN/__init__.py b/faker/providers/address/en_IN/__init__.py index 75e6d2960c..4355239994 100644 --- a/faker/providers/address/en_IN/__init__.py +++ b/faker/providers/address/en_IN/__init__.py @@ -1,4 +1,6 @@ -from .. import Provider as AddressProvider +import random +from typing import Optional +from faker.providers.address import Provider as AddressProvider class Provider(AddressProvider): @@ -391,6 +393,112 @@ class Provider(AddressProvider): "West Bengal", ) + states_abbr = ( + "AP", + "AR", + "AS", + "BR", + "CG", + "GA", + "GJ", + "HR", + "HP", + "JH", + "KA", + "KL", + "MP", + "MH", + "MN", + "ML", + "MZ", + "NL", + "OD", + "PB", + "RJ", + "SK", + "TN", + "TG", + "TR", + "UK", + "UP", + "WB", + ) + + union_territories = ( + ("Andaman and Nicobar Islands",), + ("Chandigarh",), + ("Dadra and Nagar Haveli, Dadra & Nagar Haveli",), + ("Daman and Diu",), + ("Delhi, National Capital Territory of Delhi",), + ("Jammu and Kashmir",), + ("Ladakh",), + ("Lakshadweep",), + ("Pondicherry",), + ("Puducherry",), + ) + + union_territories_abbr = ( + "AN", + "CH", + "DN", + "DD", + "DL", + "JK", + "LA", + "LD", + "PY", + ) + + # https://en.wikipedia.org/wiki/Postal_Index_Number + + # FIXME: Some states such as `BR/JH` / `UK/UP` have similar PIN code ranges + # FIXME: as mentioned in above link. + + state_pincode = { + "AP": [(510_000, 539_999)], + "AR": [(790_000, 792_999)], + "AS": [(780_000, 789_999)], + "BR": [(800_000, 859_999)], + "CG": [(490_000, 499_999)], + "GA": [(403_000, 403_999)], + "GJ": [(360_000, 399_999)], + "HR": [(120_000, 139_999)], + "HP": [(170_000, 179_999)], + "JH": [(800_000, 859_999)], + "KA": [(560_000, 599_999)], + "KL": [(670_000, 681_999), (683_000, 699_999)], + "MP": [(450_000, 489_999)], + "MH": [(400_000, 402_999), (404_000, 449_999)], + "MN": [(795_000, 795_999)], + "ML": [(793_000, 794_999)], + "MZ": [(796_000, 796_999)], + "NL": [(797_000, 798_999)], + "OD": [(750_000, 779_999)], + "PB": [(140_000, 159_999)], + "RJ": [(300_000, 349_999)], + "SK": [(737_000, 737_999)], + "TN": [(600_000, 669_999)], + "TG": [(500_000, 509_999)], + "TR": [(799_000, 799_999)], + "UK": [(200_000, 289_999)], + "UP": [(200_000, 289_999)], + "WB": [(700_000, 736_999), (738_000, 743_999), (745_000, 749_999)], + } + + union_territories_pincode = { + "AN": [(744_000, 744_999)], + "CH": [(160_000, 169_999)], + "DN": [(396_000, 396_999)], + "DD": [(396_000, 396_999)], + "DL": [(110_000, 119_999)], + "JK": [(180_000, 199_999)], + "LA": [(180_000, 199_999)], + "LD": [(682_000, 682_999)], + "PY": [(605_000, 605_999)], + } + + army_pincode = {"APS": (900_000, 999_999)} + def city_name(self) -> str: return self.random_element(self.cities) @@ -398,3 +506,71 @@ def administrative_unit(self) -> str: return self.random_element(self.states) state = administrative_unit + + def union_territory(self) -> str: + """Returns random union territory name""" + + return self.random_element(self.union_territories)[0] + + def pincode_in_state( + self, state_abbr: Optional[str] = None, include_union_territories=False + ) -> int: + """Random PIN Code within provided state abbreviation + + :param state_abbr: State Abbr, defaults to None + :param include_union_territories: Include Union Territories ?, defaults to False + :raises ValueError: If incorrect state abbr + :return: PIN Code + """ + + known_abbrs = self.states_abbr + if include_union_territories: + known_abbrs += self.union_territories_abbr + + if state_abbr is None: + state_abbr = self.random_element(known_abbrs) + + if state_abbr in known_abbrs: + codes = self.state_pincode + if include_union_territories: + codes = codes | self.union_territories_pincode + + pincode_range = self.random_element(codes[state_abbr]) + + return self.generator.random.randint(*pincode_range) + + raise ValueError("State Abbreviation not found in list") + + def pincode_in_military(self) -> int: + """Random PIN Code within Army Postal Service range""" + + key = self.random_element(self.army_pincode.keys()) + + return self.generator.random.randint(*self.army_pincode[key]) + + # Aliases + + def zipcode_in_state( + self, state_abbr: Optional[str] = None, include_union_territories=False + ) -> int: + return self.pincode_in_state(state_abbr, include_union_territories) + + def postcode_in_state( + self, state_abbr: Optional[str] = None, include_union_territories=False + ) -> int: + return self.pincode_in_state(state_abbr, include_union_territories) + + def pincode_in_army(self) -> int: + return self.pincode_in_military() + + def zipcode_in_military(self) -> int: + return self.pincode_in_military() + + def zipcode_in_army(self) -> int: + return self.pincode_in_military() + + def postcode_in_military(self) -> int: + return self.pincode_in_military() + + def postcode_in_army(self) -> int: + return self.pincode_in_military() diff --git a/tests/providers/test_address.py b/tests/providers/test_address.py index 6f5b3e410b..1c229cdc26 100644 --- a/tests/providers/test_address.py +++ b/tests/providers/test_address.py @@ -1865,17 +1865,58 @@ class TestEnIn: """Test en_IN address provider methods""" def test_city_name(self, faker, num_samples): + """Tests `city names` are fetched correctly""" + for _ in range(num_samples): city_name = faker.city_name() assert isinstance(city_name, str) assert city_name in EnInAddressProvider.cities def test_state(self, faker, num_samples): + """Tests `states` are fetched correctly""" + for _ in range(num_samples): state = faker.state() assert isinstance(state, str) assert state in EnInAddressProvider.states + def test_union_territories(self, faker, num_samples): + """Tests `union_territories` are fetched correctly""" + + for _ in range(num_samples): + union_territory = faker.union_territory() + assert isinstance(union_territory, str) + assert (union_territory,) in EnInAddressProvider.union_territories + + @pytest.mark.parametrize("pincodes", ["pincode_in_state", "zipcode_in_state", "postcode_in_state"]) + def test_pincodes_in_state(self, faker, num_samples, pincodes): + """Test `pincodes` for state and union territories""" + + for _ in range(num_samples): + include_ut = faker.random_element([True, False]) + pincode = getattr(faker, pincodes)(include_union_territories=include_ut) + assert isinstance(pincode, int) + assert len(str(pincode)) == 6 + + @pytest.mark.parametrize( + "pincodes", + [ + ("pincode_in_army"), + ("zipcode_in_army"), + ("postcode_in_army"), + ("postcode_in_military"), + ("zipcode_in_military"), + ("pincode_in_military"), + ], + ) + def test_pincodes_in_military(self, faker, num_samples, pincodes): + """Test `pincodes` for Army""" + + for _ in range(num_samples): + pincode = getattr(faker, pincodes)() + assert isinstance(pincode, int) + assert len(str(pincode)) == 6 + class TestSkSk: """Test sk_SK address provider methods"""