Repository: joke2k/faker

Issue:
State Abbreviations for en_US have too many
The output of the state provider in address only outputs the 50 states, but the state_abbr has 59 potential outputs

### Steps to reproduce

Generate a value using the state_abbr provider

### Expected behavior

The value should be one of the 50 US states abbreviations

### Actual behavior

The value is one of the 50 US states, Washington DC (DC), American Samoa (AS), Micronesia (FM), Guam (GU), Marshall Islands (MH), Northern Marianas (MP), Palau (PW), Puerto Rico (PR), and Virgin Isles (VI). It appears the list was pulled from sources such as https://www.factmonster.com/us/postal-information/state-abbreviations-and-state-postal-codes that list every possible postal state abbreviation. 


Discussion:
Hi @stephenross 

I agree that including US _territories_ in the `state_abbr` is confusing.

The reason they're there is that the purpose of the address provider is to generate valid(ish) postal address, and the USPS uses the territories abbreviation as a postal state abbreviation.

I think we should add an argument to `state_abbr`. Something like `states_only=False`.

The reason I would default it to `False` is because `Faker` is often used for fuzzy testing, and this is a good example of an edge-case people don't usually think of.
Ya, definitely agreed. The reason I bring it up is exactly that, we are using it to do fuzzy testing and the non-state abbreviation caused some of our code to fail.

Resolving patch:
diff --git a/faker/providers/address/en_US/__init__.py b/faker/providers/address/en_US/__init__.py
--- a/faker/providers/address/en_US/__init__.py
+++ b/faker/providers/address/en_US/__init__.py
@@ -272,13 +272,19 @@ class Provider(AddressProvider):
         'West Virginia', 'Wisconsin', 'Wyoming',
     )
     states_abbr = (
-        'AL', 'AK', 'AS', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FM', 'FL',
-        'GA', 'GU', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MH',
-        'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ', 'NM',
-        'NY', 'NC', 'ND', 'MP', 'OH', 'OK', 'OR', 'PW', 'PA', 'PR', 'RI', 'SC',
-        'SD', 'TN', 'TX', 'UT', 'VT', 'VI', 'VA', 'WA', 'WV', 'WI', 'WY',
+        'AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FL', 'GA', 'HI',
+        'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD', 'MA', 'MI', 'MN',
+        'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'OH',
+        'OK', 'OR', 'PA', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VA', 'WA',
+        'WV', 'WI', 'WY',
     )
 
+    territories_abbr = (
+        'AS', 'FM', 'GU', 'MH', 'MP', 'PW', 'PR', 'VI',
+    )
+
+    states_and_territories_abbr = states_abbr + territories_abbr
+
     military_state_abbr = ('AE', 'AA', 'AP')
 
     military_ship_prefix = ('USS', 'USNS', 'USNV', 'USCGC')
@@ -329,7 +335,15 @@ def secondary_address(self):
     def state(self):
         return self.random_element(self.states)
 
-    def state_abbr(self):
+    def state_abbr(self, include_territories=True):
+        """
+        :returns: A random state or territory abbreviation.
+
+        :param include_territories: If True, territories will be included.
+            If False, only states will be returned.
+        """
+        if include_territories:
+            self.random_element(self.states_and_territories_abbr)
         return self.random_element(self.states_abbr)
 
     def postcode(self):


Test patch:
diff --git a/tests/providers/test_address.py b/tests/providers/test_address.py
--- a/tests/providers/test_address.py
+++ b/tests/providers/test_address.py
@@ -313,6 +313,12 @@ def test_state(self):
     def test_state_abbr(self):
         state_abbr = self.factory.state_abbr()
         assert isinstance(state_abbr, string_types)
+        states_and_territories = EnUsProvider.states_and_territories_abbr
+        assert state_abbr in states_and_territories
+
+    def test_state_abbr_no_territories(self):
+        state_abbr = self.factory.state_abbr(include_territories=False)
+        assert isinstance(state_abbr, string_types)
         assert state_abbr in EnUsProvider.states_abbr
 
     def test_postcode(self):