phonenumbers

Python port of Google's libphonenumber for parsing, validating, and formatting phone numbers from over 200 countries and regions.

Library
PyPI
v9.0.38
3,769stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
78/100Good
Development Activity84
Maintenance44
Community84
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
83/100Excellent
Architecture80
Code Quality85
Innovation82
Learning Curve85

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 structured PhoneNumber object
  • is_possible_number() and is_valid_number() for two-tier validation — structurally plausible versus actually assigned
  • format_number() supporting E.164, INTERNATIONAL, NATIONAL, and RFC3966 output formats
  • AsYouTypeFormatter for live-formatting a number as a user types it into a form field
  • PhoneNumberMatcher for finding and extracting phone numbers embedded in arbitrary free text
  • Optional geocoder, carrier, and timezone submodules for region, carrier-name, and timezone lookups tied to a parsed number
  • Full PEP 561 type stubs (.pyi files plus a py.typed marker) 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.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search