from __future__ import annotations import phonenumbers from phonenumbers import carrier, geocoder, PhoneNumberType class PhoneVerificationResult: def __init__( self, valid: bool, international_format: str | None = None, national_format: str | None = None, country_code: int | None = None, location: str | None = None, carrier_name: str | None = None, line_type: str | None = None, error: str | None = None, ) -> None: self.valid = valid self.international_format = international_format self.national_format = national_format self.country_code = country_code self.location = location self.carrier = carrier_name self.line_type = line_type self.error = error def dict(self) -> dict: return { "valid": self.valid, "international_format": self.international_format, "national_format": self.national_format, "country_code": self.country_code, "location": self.location, "carrier": self.carrier, "line_type": self.line_type, "error": self.error, } _TYPE_NAMES = { PhoneNumberType.FIXED_LINE: "fixed_line", PhoneNumberType.MOBILE: "mobile", PhoneNumberType.FIXED_LINE_OR_MOBILE: "fixed_line_or_mobile", PhoneNumberType.TOLL_FREE: "toll_free", PhoneNumberType.PREMIUM_RATE: "premium_rate", PhoneNumberType.SHARED_COST: "shared_cost", PhoneNumberType.VOIP: "voip", PhoneNumberType.PERSONAL_NUMBER: "personal_number", PhoneNumberType.PAGER: "pager", PhoneNumberType.UAN: "uan", PhoneNumberType.VOICEMAIL: "voicemail", PhoneNumberType.UNKNOWN: "unknown", } class VerifyService: def verify_phone(self, number: str, country_code: str | None = None) -> PhoneVerificationResult: try: parsed = phonenumbers.parse(number, country_code) except phonenumbers.NumberParseException as exc: return PhoneVerificationResult(valid=False, error=f"Parsing error: {exc}") if not phonenumbers.is_valid_number(parsed): return PhoneVerificationResult(valid=False, error="Invalid phone number") number_type = phonenumbers.number_type(parsed) line_type = _TYPE_NAMES.get(number_type, "unknown") location = geocoder.description_for_number(parsed, "en") or None carrier_name = carrier.name_for_number(parsed, "en") or None return PhoneVerificationResult( valid=True, international_format=phonenumbers.format_number(parsed, phonenumbers.PhoneNumberFormat.INTERNATIONAL), national_format=phonenumbers.format_number(parsed, phonenumbers.PhoneNumberFormat.NATIONAL), country_code=parsed.country_code, location=location, carrier_name=carrier_name, line_type=line_type, )