phonenumbers
Python port of Google's libphonenumber for parsing, validating, and formatting phone numbers from over 200 countries and regions.
Repository Health
Technical Analysis
phonenumbers is a direct Python port of Google’s libphonenumber, the library that powers phone-number handling in Android and Google’s own products. It parses phone numbers written in almost any human format — with or without a country code, with local punctuation, spaces, or extensions — into a structured PhoneNumber object, then lets you validate whether that number is possible or actually assigned, and reformat it into national, international, E.164, or RFC3966 styles.
Beyond parsing and formatting, the library ships companion modules for geocoding a number to its region, looking up carrier and timezone information, live “as you type” formatting for input fields, and scanning free-text strings to find embedded phone numbers. All of this metadata is generated from the same upstream data as the Java/C++ libphonenumber project and kept in sync via an automated upstream-tracking workflow, so regional numbering-plan changes propagate without requiring API changes downstream.
What You Get
- A
parse()function that turns loosely formatted input (with or without a default region) into a structuredPhoneNumberobject is_possible_number()andis_valid_number()for two-tier validation — structurally plausible versus actually assignedformat_number()supporting E.164, INTERNATIONAL, NATIONAL, and RFC3966 output formatsAsYouTypeFormatterfor live-formatting a number as a user types it into a form fieldPhoneNumberMatcherfor finding and extracting phone numbers embedded in arbitrary free text- Optional
geocoder,carrier, andtimezonesubmodules for region, carrier-name, and timezone lookups tied to a parsed number - Full PEP 561 type stubs (
.pyifiles plus apy.typedmarker) for static type checking with mypy
Common Use Cases
- Validating and normalizing phone numbers submitted through signup or checkout forms before storing them
- Formatting stored E.164 numbers back into the locally expected display format for a user’s region
- Live-formatting a phone input field as the user types, mirroring how libphonenumber powers Android’s dialer
- Extracting phone numbers from unstructured text such as support tickets, emails, or scraped web content
- Deriving a caller’s likely country, carrier, or timezone from a phone number alone
Under The Hood
Architecture
The library centers on phonenumberutil.py, which defines the core PhoneNumber value object and the parse/format/validate pipeline, with specialized concerns split into separate importable submodules — phonenumbermatcher.py for finding numbers in free text, asyoutypeformatter.py for incremental live formatting, and geocoder.py/carrier.py/timezone.py for auxiliary lookups. All of these depend on compiled per-region metadata generated from upstream libphonenumber’s XML resources and packaged as Python data modules (data/, geodata/, carrierdata/, tzdata/, shortdata/) rather than loaded at runtime, so the library performs no network calls or file I/O — the only real blast radius from a core change is parse()/format_number(), since every auxiliary module builds on those primitives.
Tech Stack
Pure Python with zero runtime dependencies — the pyproject.toml build backend is plain setuptools, with version derived dynamically from phonenumbers.__version__. The codebase targets an unusually wide compatibility range (Python 2.5 through 3.13, including PyPy) in a single unforked codebase. Type coverage is provided via hand-maintained .pyi stub files and a py.typed marker for PEP 561 compliance. Metadata is regenerated from upstream Java libphonenumber’s XML data via internal build tooling under tools/python, keeping regional numbering-plan data current without hand-editing.
Code Quality
The tests/ directory mirrors the library 1:1 (phonenumberutiltest.py, phonenumbermatchertest.py, asyoutypetest.py, etc.) with dedicated test-only data fixtures (testdata/, testgeodata/, testcarrierdata/, testtzdata/) so tests don’t depend on production metadata. CI runs the suite across eight Python/PyPy version combinations plus dedicated coverage, typing (mypy via run_stubtest.py), and upstream-parity workflows, and fails the build if regenerating metadata from XML produces any drift from the checked-in files. Errors are explicit and typed — NumberParseException carries a specific error-code enum rather than a bare string message.
API Design
The common path is deliberately small: parse() plus one of is_valid_number()/format_number() covers most integrations in two or three lines, operating on a single PhoneNumber object rather than scattering state across return values. Less common needs — geocoding, carrier lookup, timezone lookup, as-you-type formatting, free-text extraction — live in clearly separated submodules instead of bloating the core API, and the package installs with all metadata bundled, so there’s no separate data file or download step to configure. The main friction newcomers hit is that parse() still requires an explicit default region for any input that isn’t already in E.164 form, a constraint inherited from the underlying libphonenumber design rather than a Python-specific choice.
Used by 4 apps in this directory
Flowsint
Automation · Developer Tools
A privacy-first, graph-based OSINT investigation platform with 30+ automated enrichers for mapping relationships between domains, IPs, people, and organizations.
Khoj
AI Assistants · Knowledge Management · Productivity
A self-hostable AI second brain that chats with your documents, searches the web, builds custom agents, and runs entirely on your own LLM.
QRev
CRM · AI Agents
Open source AI-first sales platform that replaces Salesforce with autonomous agents handling prospecting, outreach, and lead management at scale.
SWIRL
Search · Databases · Data Engineering
Federated AI search and RAG across 100+ enterprise sources—no data extraction, no vector database required.