country_name_for_number in phonenumbers returns nothing

1.2k Views Asked by At

I want to access the country name using a phone number with Python. But for some input data it does not return anything, how can I fix this? In the Phonenumbers documentation, I spotted the following suspicious comment:

If the number has already been found valid for one region, then we don't know which region it belongs to so we return nothing.

import phonenumbers
from phonenumbers import geocoder

phone = '+39391359045341'
p = phonenumbers.parse(phone)
geocoder.country_name_for_number(p, 'en')
3

There are 3 best solutions below

0
xjcl On

The reason your code fails is that +39 is used by multiple countries (Italy and the Vatican), and as the comment you quoted explains, in that case the function just returns nothing because the region is ambiguous. (A few functions inside of the library seem to just use the major region though).

So here is my fixed function if you want the major region (returns "Italy"):

import phonenumbers.geocoder

def country_name_for_number(p: phonenumbers.PhoneNumber, lang="en") -> str:
    rc = phonenumbers.geocoder.region_code_for_country_code(p.country_code)
    return phonenumbers.geocoder._region_display_name(rc, lang)

Or if you want all regions (returns ["Italy", "Vatican"])

def country_names_for_number(p: phonenumbers.PhoneNumber, lang="en") -> list[str]:
    rcs = phonenumbers.geocoder.region_codes_for_country_code(p.country_code)
    return [phonenumbers.geocoder._region_display_name(rc, lang) for rc in rcs]

Original comment:

I was able to reproduce the issue of country_name_for_number not returning anything. I checked the source code and it internally calls region_code_for_country_code to look up the 2 letter code (+39... -> IT) and then uses a LOCALE_DATA dictionary inside of _region_display_name to look up the code (IT -> Italy). Interactively:

import phonenumbers.geocoder

c = phonenumbers.parse("+39391359045341")
print(phonenumbers.geocoder.country_name_for_number(c, "en"))  # returns 'None'?!
print(phonenumbers.geocoder.region_code_for_country_code(c.country_code))  # 'IT'
print(phonenumbers.geocoder._region_display_name("IT", "en"))  # Italy
1
David On

@xjcl answer makes perfect sense, I hadn't inspected the library and I used an incorrect method. Using the function provided by @xjcl

#check whether a phone number is valid or not
import phonenumbers
from phonenumbers import geocoder

people = ['John', 'Mary', 'Peter']
texts = ['+39391359045341', '+919876543210', '+559876543210']
# Parsing String to Phone number
numbers = [phonenumbers.parse(txt) for txt in texts]
valids = [phonenumbers.is_valid_number(number) for number in numbers]
countries = [country_names_for_number(number) for number in numbers]

result = []
for i in range(len(valids)):
    if valids[i]:
        result.append((people[i], texts[i], countries[i]))
print(result)

Original comment:

Apparently there are some bugs in the phonenumbers library, see, when running on some numbers it finds a country state (Maranhão) instead of the country itself (Brazil). Report to the library builder.

    #check whether a phone number is valid or not
    import phonenumbers
    people = ['John', 'Mary', 'Peter']
    texts = ['+39391359045341', '+919876543210', '+559876543210']
    # Parsing String to Phone number
    numbers = [phonenumbers.parse(txt) for txt in texts]
    valids = [phonenumbers.is_valid_number(number) for number in numbers]
    possibles = [phonenumbers.is_possible_number(number) for number in numbers]
    print(valids)
    print(possibles)

    #find carrier and region of a phone number
    from phonenumbers import geocoder, carrier
    carriers = [carrier.name_for_number(number, 'en') for number in numbers]
    regions = [geocoder.description_for_number(number, 'en') for number in numbers]

    result = []
    for i in range(len(valids)):
        if valids[i]:
            result.append((people[i], texts[i], carriers[i], regions[i]))
    print(result)
1
SB Piyal On
import phonenumbers.geocoder

c = phonenumbers.parse("+393891916627")
print(phonenumbers.geocoder.country_name_for_number(c, "en")) # THIS WILL RETURN NOTHING
print(phonenumbers.geocoder.region_code_for_country_code(c.country_code))  # 'IT'
print(phonenumbers.geocoder._region_display_name("IT", "en"))  #CHANGING IT TO ITS FULL NAME