Repository: joke2k/faker
Pull request #1878 (2023-06-15 22:41:34)

add digit above two type to numerify function
Issue ticket: https://github.com/joke2k/faker/issues/1849

### What does this change

Adds a digit type for values 2-9 to comply with US telephone number standards.

### What was wrong

US telephone number generation was creating impossible numbers. 

### How this fixes it

Adds a 2-9 type to numerify, adds testing to validate, ports the US phone numbers over to the new format. 


dlwrnc: Coverage is the same, not sure why coveralls is upset -- I think it's fine as-is, but happy to make modifications if needed. 

Patch:
diff --git a/faker/providers/__init__.py b/faker/providers/__init__.py
index c329d512..e4932a4d 100644
--- a/faker/providers/__init__.py
+++ b/faker/providers/__init__.py
@@ -10,6 +10,7 @@ from ..utils.distribution import choices_distribution, choices_distribution_uniq
 
 _re_hash = re.compile(r"#")
 _re_perc = re.compile(r"%")
+_re_dol = re.compile(r"\$")
 _re_excl = re.compile(r"!")
 _re_at = re.compile(r"@")
 _re_qm = re.compile(r"\?")
@@ -325,6 +326,11 @@ class BaseProvider:
 
         return self.generator.random.randint(1, 9)
 
+    def random_digit_above_two(self) -> int:
+        """Generate a random digit above value two (2 to 9)."""
+
+        return self.generator.random.randint(2, 9)
+
     def random_digit_or_empty(self) -> Union[int, str]:
         """Generate a random digit (0 to 9) or an empty string.
 
@@ -603,6 +609,7 @@ class BaseProvider:
 
         - Number signs ('#') are replaced with a random digit (0 to 9).
         - Percent signs ('%') are replaced with a random non-zero digit (1 to 9).
+        - Dollar signs ('$') are replaced with a random digit above two (2 to 9).
         - Exclamation marks ('!') are replaced with a random digit or an empty string.
         - At symbols ('@') are replaced with a random non-zero digit or an empty string.
 
@@ -617,6 +624,7 @@ class BaseProvider:
         """
         text = _re_hash.sub(lambda x: str(self.random_digit()), text)
         text = _re_perc.sub(lambda x: str(self.random_digit_not_null()), text)
+        text = _re_dol.sub(lambda x: str(self.random_digit_above_two()), text)
         text = _re_excl.sub(lambda x: str(self.random_digit_or_empty()), text)
         text = _re_at.sub(lambda x: str(self.random_digit_not_null_or_empty()), text)
         return text
diff --git a/faker/providers/phone_number/en_US/__init__.py b/faker/providers/phone_number/en_US/__init__.py
index ac1367e8..dc7dc7ee 100644
--- a/faker/providers/phone_number/en_US/__init__.py
+++ b/faker/providers/phone_number/en_US/__init__.py
@@ -4,45 +4,45 @@ from .. import Provider as PhoneNumberProvider
 class Provider(PhoneNumberProvider):
     formats = (
         # Standard 10-digit phone number formats
-        "##########",
-        "##########",
-        "###-###-####",
-        "###-###-####",
+        "$##$######",
+        "$##$######",
+        "$##-$##-####",
+        "$##-$##-####",
         # Optional 10-digit local phone number format
-        "(###)###-####",
-        "(###)###-####",
+        "($##)$##-####",
+        "($##)$##-####",
         # Non-standard 10-digit phone number format
-        "###.###.####",
-        "###.###.####",
+        "$##.$##.####",
+        "$##.$##.####",
         # Standard 10-digit phone number format with extensions
-        "###-###-####x###",
-        "###-###-####x####",
-        "###-###-####x#####",
+        "$##-$##-####x###",
+        "$##-$##-####x####",
+        "$##-$##-####x#####",
         # Optional 10-digit local phone number format with extensions
-        "(###)###-####x###",
-        "(###)###-####x####",
-        "(###)###-####x#####",
+        "($##)$##-####x###",
+        "($##)$##-####x####",
+        "($##)$##-####x#####",
         # Non-standard 10-digit phone number format with extensions
-        "###.###.####x###",
-        "###.###.####x####",
-        "###.###.####x#####",
+        "$##.$##.####x###",
+        "$##.$##.####x####",
+        "$##.$##.####x#####",
         # Standard 11-digit phone number format
-        "+1-###-###-####",
-        "001-###-###-####",
+        "+1-$##-$##-####",
+        "001-$##-$##-####",
         # Standard 11-digit phone number format with extensions
-        "+1-###-###-####x###",
-        "+1-###-###-####x####",
-        "+1-###-###-####x#####",
-        "001-###-###-####x###",
-        "001-###-###-####x####",
-        "001-###-###-####x#####",
+        "+1-$##-$##-####x###",
+        "+1-$##-$##-####x####",
+        "+1-$##-$##-####x#####",
+        "001-$##-$##-####x###",
+        "001-$##-$##-####x####",
+        "001-$##-$##-####x#####",
     )
 
     basic_formats = (
         # basic 10-digit phone number format with no extensions
-        "##########",
-        "###-###-####",
-        "(###)###-####",
+        "$##$######",
+        "$##-$##-####",
+        "($##)$##-####",
     )
 
     def basic_phone_number(self) -> str:


Test patch:
diff --git a/tests/providers/__init__.py b/tests/providers/__init__.py
index 565a726c..efc9dec6 100644
--- a/tests/providers/__init__.py
+++ b/tests/providers/__init__.py
@@ -35,6 +35,10 @@ class TestBaseProvider:
         samples = [faker.random_digit_not_null() for _ in range(num_samples * 10)]
         assert set(samples) == set(range(1, 10))
 
+    def test_random_digit_above_two(self, faker, num_samples):
+        samples = [faker.random_digit_above_two() for _ in range(num_samples * 10)]
+        assert set(samples) == set(range(2, 10))
+
     def test_random_digit_or_empty(self, faker, num_samples):
         expected = set(range(10))
         expected.add("")