CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-phonenumberslite

Python library for parsing, formatting, storing and validating international phone numbers with reduced memory footprint

Pending
Overview
Eval results
Files

number-validation.mddocs/

Number Validation

Comprehensive validation functions to check if phone numbers are valid, possible, or match specific criteria. These functions provide detailed validation information and support various validation levels.

Capabilities

Basic Validity Checking

Determine if phone numbers are valid according to official numbering plan rules and formatting requirements.

def is_valid_number(numobj: PhoneNumber) -> bool:
    """
    Check if a phone number is valid.
    
    A valid number is one that is both possible (correct length) and 
    follows the numbering rules for its region and type.
    
    Parameters:
    - numobj: PhoneNumber object to validate
    
    Returns:
    True if the number is valid, False otherwise
    """

def is_valid_number_for_region(numobj: PhoneNumber, region_code: str) -> bool:
    """
    Check if a phone number is valid for a specific region.
    
    Parameters:
    - numobj: PhoneNumber object to validate
    - region_code: Two-letter region code to validate against
    
    Returns:
    True if valid for the specified region, False otherwise
    """

Usage Examples:

import phonenumbers

# Parse and validate various numbers
numbers = [
    "+442083661177",    # Valid UK number
    "+1234567890",      # Invalid country code
    "+44208366",        # Too short
    "+442083661177123", # Too long
]

for number_str in numbers:
    try:
        number = phonenumbers.parse(number_str)
        is_valid = phonenumbers.is_valid_number(number)
        print(f"{number_str}: {'Valid' if is_valid else 'Invalid'}")
    except phonenumbers.NumberParseException:
        print(f"{number_str}: Parse failed")

# Region-specific validation
number = phonenumbers.parse("+442083661177")
print(f"Valid for GB: {phonenumbers.is_valid_number_for_region(number, 'GB')}")
print(f"Valid for US: {phonenumbers.is_valid_number_for_region(number, 'US')}")

Possibility Checking

Check if numbers have valid lengths and basic formatting, which is less strict than full validation.

def is_possible_number(numobj: PhoneNumber) -> bool:
    """
    Check if a phone number is possible (has valid length).
    
    This is a quicker check than full validation - it only verifies
    that the number length is appropriate for the region.
    
    Parameters:
    - numobj: PhoneNumber object to check
    
    Returns:
    True if the number could possibly be valid, False otherwise
    """

def is_possible_number_string(number: str, region_code: str) -> bool:
    """
    Check if a number string is possible without full parsing.
    
    Parameters:
    - number: Phone number string to check
    - region_code: Region code for parsing context
    
    Returns:
    True if the string could represent a valid number, False otherwise
    """

Detailed Possibility Analysis

Get detailed information about why a number might not be possible, with specific reasons for failure.

def is_possible_number_with_reason(numobj: PhoneNumber) -> ValidationResult:
    """
    Check number possibility with detailed reason for the result.
    
    Parameters:
    - numobj: PhoneNumber object to analyze
    
    Returns:
    ValidationResult indicating specific possibility status:
    - IS_POSSIBLE: Number has valid length
    - IS_POSSIBLE_LOCAL_ONLY: Valid for local dialing only
    - INVALID_COUNTRY_CODE: Country code is not recognized
    - TOO_SHORT: Number is shorter than valid lengths
    - TOO_LONG: Number is longer than valid lengths
    - INVALID_LENGTH: Length doesn't match any valid pattern
    """

def is_possible_number_for_type(numobj: PhoneNumber, 
                               phone_type: PhoneNumberType) -> bool:
    """
    Check if number is possible for a specific phone number type.
    
    Parameters:
    - numobj: PhoneNumber object to check
    - phone_type: Specific type to validate against (MOBILE, FIXED_LINE, etc.)
    
    Returns:
    True if possible for the specified type, False otherwise
    """

def is_possible_number_for_type_with_reason(numobj: PhoneNumber, 
                                          phone_type: PhoneNumberType) -> ValidationResult:
    """
    Check type-specific possibility with detailed reason.
    
    Parameters:
    - numobj: PhoneNumber object to analyze
    - phone_type: Phone number type to check against
    
    Returns:
    ValidationResult with specific reason for the validation outcome
    """

Usage Examples:

import phonenumbers
from phonenumbers import PhoneNumberType, ValidationResult

number = phonenumbers.parse("+44208366", "GB")  # Too short

# Basic possibility check
print(f"Is possible: {phonenumbers.is_possible_number(number)}")

# Detailed analysis
result = phonenumbers.is_possible_number_with_reason(number)
if result == ValidationResult.TOO_SHORT:
    print("Number is too short")
elif result == ValidationResult.TOO_LONG:
    print("Number is too long")
elif result == ValidationResult.IS_POSSIBLE:
    print("Number is possible")

# Type-specific checking
mobile_number = phonenumbers.parse("+447700900123", "GB")
is_mobile_possible = phonenumbers.is_possible_number_for_type(
    mobile_number, PhoneNumberType.MOBILE
)
print(f"Possible as mobile: {is_mobile_possible}")

Number Type Classification

Determine what type of phone number (mobile, fixed-line, toll-free, etc.) a given number represents.

def number_type(numobj: PhoneNumber) -> PhoneNumberType:
    """
    Determine the type of a phone number.
    
    Parameters:
    - numobj: PhoneNumber object to classify
    
    Returns:
    PhoneNumberType indicating the number's classification:
    - FIXED_LINE: Traditional landline number
    - MOBILE: Mobile/cellular number
    - FIXED_LINE_OR_MOBILE: Cannot distinguish (e.g., US numbers)
    - TOLL_FREE: Free-to-caller service number
    - PREMIUM_RATE: Premium-rate service number
    - SHARED_COST: Shared cost between caller and receiver
    - VOIP: Voice over IP number
    - PERSONAL_NUMBER: Personal numbering service
    - PAGER: Pager number
    - UAN: Universal Access Number (company number)
    - VOICEMAIL: Voicemail access number
    - UNKNOWN: Cannot determine type
    """

Geographic Number Analysis

Analyze whether numbers are tied to specific geographic locations.

def is_number_geographical(numobj: PhoneNumber) -> bool:
    """
    Check if a phone number is geographical (tied to a location).
    
    Parameters:
    - numobj: PhoneNumber object to analyze
    
    Returns:
    True if the number is associated with a geographic area, False otherwise
    """

def is_number_type_geographical(phone_type: PhoneNumberType) -> bool:
    """
    Check if a phone number type is generally geographical.
    
    Parameters:
    - phone_type: PhoneNumberType to check
    
    Returns:
    True if numbers of this type are typically geographical
    """

International Dialing Capability

Check if numbers can be dialed internationally from other countries.

def can_be_internationally_dialled(numobj: PhoneNumber) -> bool:
    """
    Check if a number can be dialed internationally.
    
    Some numbers (like emergency services) cannot be reached from abroad.
    
    Parameters:
    - numobj: PhoneNumber object to check
    
    Returns:
    True if the number can be dialed from other countries, False otherwise
    """

Length Truncation

Attempt to truncate overly long numbers to valid lengths.

def truncate_too_long_number(numobj: PhoneNumber) -> PhoneNumber:
    """
    Truncate a number that is too long to a valid length.
    
    Parameters:
    - numobj: PhoneNumber that may be too long
    
    Returns:
    PhoneNumber truncated to valid length, or original if already valid
    """

Usage Patterns

Comprehensive Number Validation

import phonenumbers
from phonenumbers import PhoneNumberType, ValidationResult

def validate_phone_number(number_string, region=None):
    """Comprehensive phone number validation with detailed feedback."""
    try:
        # Parse the number
        number = phonenumbers.parse(number_string, region)
        
        # Basic validation
        is_valid = phonenumbers.is_valid_number(number)
        is_possible = phonenumbers.is_possible_number(number)
        
        # Detailed possibility analysis
        possibility_reason = phonenumbers.is_possible_number_with_reason(number)
        
        # Number type classification
        num_type = phonenumbers.number_type(number)
        
        # Geographic analysis
        is_geographic = phonenumbers.is_number_geographical(number)
        
        # International dialing capability
        can_dial_intl = phonenumbers.can_be_internationally_dialled(number)
        
        return {
            'number': number,
            'is_valid': is_valid,
            'is_possible': is_possible,
            'possibility_reason': possibility_reason,
            'type': num_type,
            'is_geographic': is_geographic,
            'can_dial_internationally': can_dial_intl,
            'formatted': {
                'e164': phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.E164),
                'international': phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.INTERNATIONAL),
                'national': phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.NATIONAL)
            }
        }
        
    except phonenumbers.NumberParseException as e:
        return {
            'error': str(e),
            'error_type': e.error_type
        }

# Example usage
result = validate_phone_number("+442083661177")
if 'error' not in result:
    print(f"Valid: {result['is_valid']}")
    print(f"Type: {result['type']}")
    print(f"Geographic: {result['is_geographic']}")
    print(f"E164: {result['formatted']['e164']}")

Batch Validation

import phonenumbers

def validate_number_list(numbers, default_region="US"):
    """Validate a list of phone numbers with summary statistics."""
    results = {
        'valid': [],
        'invalid': [],
        'unparseable': [],
        'types': {}
    }
    
    for number_str in numbers:
        try:
            number = phonenumbers.parse(number_str, default_region)
            
            if phonenumbers.is_valid_number(number):
                results['valid'].append(number_str)
                num_type = phonenumbers.number_type(number)
                results['types'][num_type] = results['types'].get(num_type, 0) + 1
            else:
                results['invalid'].append(number_str)
                
        except phonenumbers.NumberParseException:
            results['unparseable'].append(number_str)
    
    return results

# Example usage
test_numbers = [
    "+1-800-555-1234",  # Valid US toll-free
    "+44 20 8366 1177", # Valid UK fixed-line
    "+1-555-123",       # Invalid (too short)
    "not-a-number"      # Unparseable
]

results = validate_number_list(test_numbers)
print(f"Valid: {len(results['valid'])}")
print(f"Invalid: {len(results['invalid'])}")
print(f"Unparseable: {len(results['unparseable'])}")
print(f"Types found: {results['types']}")

Install with Tessl CLI

npx tessl i tessl/pypi-phonenumberslite

docs

as-you-type-formatting.md

core-parsing-formatting.md

index.md

number-validation.md

phone-number-matching.md

region-metadata.md

short-numbers.md

utility-functions.md

tile.json