mrkeyoor.com_
Sat 07 Nov 08:57 UTC
PyPIUtilsupdated 07 Nov 2026

phonenumbers review

phonenumbers 9.0.37 is the Python port of Google's international phone-number library and generated numbering data. `parse()` turns national input plus a region, or an international `+` number, into a `PhoneNumber`. Separate calls check possible length, current assigned patterns, number type, and region, then format national, international, RFC3966, or E.164 output. Stateful formatting and text matching cover interactive fields and extraction. Optional modules map a number to a plan-based place description, original carrier, or possible time zones. Version 9.0.37 syncs upstream metadata changes for 17 regions plus alternate-format, short-number, geocoding, carrier, and time-zone data.

Verdict

phonenumbers 9.0.37 installed in 0.6 seconds as 1 pure-Python package using 23 MB, imported in 0.10 seconds, and produced 0 audit findings in our sandbox. Install it for international parsing and plan checks; keep ownership verification and live carrier claims outside this dependency.

We installed it

Lab card: what happened when we installed phonenumbersScreenshot of phonenumbers documentation
Install✓ · 0.6s1 package on disk · 23 MB
Import✓import phonenumbers in 0.10s · pure Python · py.typed · requires Python >=2.5
Known vulns0(pip-audit)

Answers from our run

Does phonenumbers install cleanly?

Yes. In a fresh container with an empty cache, pip install phonenumbers finished in 0.6s, leaving 1 package and 23 MB on disk. pip-audit reported no known vulnerabilities.

What does phonenumbers need to run?

Python >=2.5, and nothing compiled: it is pure Python. In our run import phonenumbers succeeded in 0.10s, and the package ships py.typed for type checkers.

phonenumbers or phonenumberslite: which should you use?

phonenumberslite: Choose it for the same parsing and validation API without geocoder, carrier, or time-zone data. phonenumbers 9.0.37 installed in 0.6 seconds as 1 pure-Python package using 23 MB, imported in 0.10 seconds, and produced 0 audit findings in our sandbox.

When should you not use phonenumbers?

You need proof that a person controls the line. A valid result matches numbering metadata; only a verification call or message tests possession.

API stability5/5The documented surface still uses `parse`, `format_number`, `is_possible_number`, `is_valid_number`, `PhoneNumberMatcher`, `AsYouTypeFormatter`, and `PhoneNumber` objects familiar across the long-running port. The version history says 9.0.0 changed only Python metadata despite the upstream major bump. Stable signatures do not guarantee fixed answers because metadata updates can revise validity, number type, region, carrier, or formatting.
Docs4/5The README demonstrates regional and international parsing, exception behavior, possible versus valid checks, four output formats, incremental formatting, text matching, geocoding, carrier lookup, time zones, lazy metadata, lightweight installation, and static typing. Generated API pages cover symbols in detail. The docs could state the trust limits more directly: allocation is not ownership, carrier names can predate portability, and a location is a numbering-plan hint.
Maintenance5/5PyPI published 9.0.37 on August 14, 2026, and the GitHub repository was pushed the same day. GitHub reported an unarchived project with 3,767 stars and 11 open issues and pull requests. The port tracks Google's frequent metadata releases; 9.0.37 incorporates changes to 17 region plans plus supporting data. That cadence matters because new allocations arrive even when the Python functions stay unchanged.
Ecosystem5/5PyPI Stats counted 9,230,696 downloads in the latest week. Django integrations and validation packages use the same PhoneNumber representation, while `phonenumberslite` supplies an API-compatible option without extended lookup data. Our install found 0 direct dependencies and a `py.typed` marker, so Python applications get editor and type-checker information without adding another runtime graph. The tradeoff is the measured 23 MB installed footprint.

Use it if

  • A backend accepts national phone input from multiple countries and stores a normalized E.164 value.
  • Validation must distinguish an impossible length from digits that do not match the current numbering plan.
  • Documents need phone matches with exact source offsets for linking, redaction, or review.
  • The product needs as-you-type display, short-number checks, or plan-based region and time-zone hints.
Skip it if

Setup reality

We installed phonenumbers 9.0.37 in a fresh Python 3.12 Bookworm sandbox in 0.6 seconds. It left 1 package and 23 MB on disk, and pip-audit found 0 known vulnerabilities. The distribution has 0 direct dependencies, is pure Python, declares Python 2.5 or newer, and ships py.typed. import phonenumbers worked in 0.10 seconds. PyPI did not return a license value, while the GitHub repository identifies Apache-2.0.

International input beginning with + needs no region. National text does: the same digits can mean something different under GB and US. Parsing only constructs a candidate and may succeed for an impossible or unassigned number. Run is_possible_number() for the length and prefix shape, then is_valid_number() when current allocation rules are part of the decision. Catch NumberParseException for missing regions and malformed input.

Core region metadata loads when a region is first used. Geocoder, carrier, and time-zone data live behind separate imports, so a worker's first lookup can pay an extra loading cost. PhoneMetadata.load_all() moves core loading into startup. Import the extended modules there as well when predictable request latency matters. Install phonenumberslite if none of those extended lookups are needed.

Store E.164 separately from the user's display value, and model an extension as its own field when downstream systems require it. AsYouTypeFormatter keeps state; deletion or a country change means clearing it and replaying the remaining digits. A FIXED_LINE_OR_MOBILE result is expected for plans that do not encode service type in the number. Location, carrier, and time-zone results describe numbering metadata, not the subscriber's verified situation.

Patterns

Parse national input in context parse-regional-number

import phonenumbers

phone = phonenumbers.parse('020 8366 1177', 'GB')
print(phone.country_code, phone.national_number)

A national string needs a valid default region; the same 020 prefix has no global meaning by itself.

Validate and store E.164 normalize-to-e164

import phonenumbers
from phonenumbers import PhoneNumberFormat

phone = phonenumbers.parse(raw_value, region)
if not phonenumbers.is_valid_number(phone):
    raise ValueError('number does not match the current plan')
e164 = phonenumbers.format_number(phone, PhoneNumberFormat.E164)

A valid plan match does not prove the line exists or that the user owns it; verify possession separately.

Separate shape from allocation distinguish-possible-valid

possible = phonenumbers.is_possible_number(phone)
valid = phonenumbers.is_valid_number(phone)
if not possible:
    reason = phonenumbers.is_possible_number_with_reason(phone)

Possibility checks length and structural rules. Validity also uses the assigned digit patterns embedded in version 9.0.37.

Catch unusable input handle-parse-exception

from phonenumbers import NumberParseException, parse

try:
    phone = parse(raw_value, default_region)
except NumberParseException as exc:
    return {'error_type': exc.error_type, 'message': str(exc)}

parse raises for malformed text and for a national number supplied without a valid region; `error_type` lets a form classify the cause.

Produce local and international labels format-for-display

from phonenumbers import PhoneNumberFormat, format_number

national = format_number(phone, PhoneNumberFormat.NATIONAL)
international = format_number(phone, PhoneNumberFormat.INTERNATIONAL)
rfc3966 = format_number(phone, PhoneNumberFormat.RFC3966)

Formatting uses the parsed plan metadata. Store E.164 as the normalized identity and derive display strings when needed.

Handle ambiguous service types classify-line-type

from phonenumbers import PhoneNumberType, number_type

kind = number_type(phone)
sms_candidate = kind in (
    PhoneNumberType.MOBILE,
    PhoneNumberType.FIXED_LINE_OR_MOBILE,
)

Some numbering plans cannot distinguish mobile from fixed service by digits, so `FIXED_LINE_OR_MOBILE` needs an explicit product rule.

Apply as-you-type formatting format-typed-digits

from phonenumbers import AsYouTypeFormatter

formatter = AsYouTypeFormatter('US')
rendered = ''
for digit in '6502532222':
    rendered = formatter.input_digit(digit)
print(rendered)

AsYouTypeFormatter is stateful. Call `clear()` and replay the remaining digits after deletion or a region switch.

Find phone spans in prose match-phone-text

from phonenumbers import PhoneNumberMatcher, PhoneNumberFormat, format_number

for match in PhoneNumberMatcher(text, 'US'):
    e164 = format_number(match.number, PhoneNumberFormat.E164)
    print(match.start, match.end, match.raw_string, e164)

Each match includes source offsets. Matching can still confuse number-shaped identifiers, so review the surrounding text for high-risk automation.

Map a parsed number to a region lookup-region-code

from phonenumbers import region_code_for_number

region = region_code_for_number(phone)
if region != allowed_region:
    raise ValueError('number belongs to another numbering plan')

Region is derived from numbering metadata and may be absent for non-geographic services or ambiguous shared calling codes.

Test an emergency short number check-emergency-number

from phonenumbers import shortnumberinfo

is_emergency = shortnumberinfo.is_emergency_number('911', 'US')

Short-number rules require a region and can differ from ordinary PhoneNumber validation; never use this check to route an actual emergency call.

Read allocation-based hints read-carrier-location

from phonenumbers import carrier, geocoder, timezone

original_carrier = carrier.name_for_number(phone, 'en')
place = geocoder.description_for_number(phone, 'en')
zones = timezone.time_zones_for_number(phone)

Carrier data can be stale after portability, and the place or time-zone result does not prove where the subscriber is now.

Pay metadata cost during startup preload-metadata

from phonenumbers import PhoneMetadata
import phonenumbers.carrier
import phonenumbers.geocoder
import phonenumbers.timezone

PhoneMetadata.load_all()

Core metadata otherwise loads by region on first use; importing extended modules also loads their separate data sets.

Alternatives

PackageRegistryPick it when
phonenumberslitePyPIChoose it for the same parsing and validation API without geocoder, carrier, or time-zone data.
django-phonenumber-fieldPyPIChoose it when Django model fields, forms, and serializers should wrap phonenumbers behavior.
python-stdnumPyPIChoose it when phone-related checks sit inside a wider job covering tax, bank, and business identifiers.

More utils guides

lru-cache · type-fest · ajv · zod · p-limit · find-up · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.