crowdcomms / faker-e164

Faker provider to generate E164 Phone Numbers
Apache License 2.0
22 stars 10 forks source link

Safe numbers provoke unique constraints failure #14

Open an0o0nym opened 4 months ago

an0o0nym commented 4 months ago

Hi, Thanks a lot for your work on providing this custom provider! Been struggling to make it work with phonenumbers parser in my test suite until I found faker-e164.

Now when I run tests I get the unique constraints failure for telephone number. I figured out that it creates multiple user using the same phone number. Is there only a limited number of phone numbers that may be provoking this? Any way to fix this?

This is how I use it:

    telephone = factory.Faker("safe_e164", region_code="AU")
an0o0nym commented 4 months ago

OK, I just inspected the source code of this package, and it seems to randomly select a phone number from a set of predefined phone numbers... hmm

an0o0nym commented 4 months ago

Anyway, if anyone stumbles upon this, here is my solution for AU numbers, thats been tested and proved to work:

import factory
import phonenumbers
import random
from faker_e164.providers import E164Provider

def generate_australian_mobile():
    # https://en.wikipedia.org/wiki/Telephone_numbers_in_Australia#List_of_non-geographic_numbers
    ranges = [
        (420000000, 420019999),
        (420020000, 420029999),
        (420030000, 420039999),
        (420090000, 420099999),
        (420100000, 420109999),
        (420110000, 420119999),
        (444500000, 444599999),
        (488800000, 488899999),
        (489000000, 489099999),
        (489840000, 489849999),
        (489900000, 489999999),
        (491500000, 491519999),
        (491570000, 491579999),
    ]
    selected_range = random.choice(ranges)
    number = random.randint(selected_range[0], selected_range[1])
    return f"+61{number:09d}"

class E164ProviderAU(E164Provider):
    def safe_e164(self, region_code: str = None) -> str:
        if region_code == "AU":
            phone_number = phonenumbers.parse(generate_australian_mobile())
            return phonenumbers.format_number(
                phone_number, phonenumbers.PhoneNumberFormat.E164
            )
        return super().safe_e164(region_code)

factory.Faker.add_provider(E164ProviderAU)

class UserFactory(factory.DjangoModelFactory):
    telephone = factory.Faker("safe_e164", region_code="AU")
    ....