Skip to content

Commit 5216517

Browse files
committed
Merge upstream code changes for 8.4.0
1 parent 877da71 commit 5216517

4 files changed

Lines changed: 452 additions & 30 deletions

File tree

python/phonenumbers/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@
105105
is_number_geographical,
106106
is_number_type_geographical,
107107
is_possible_number,
108+
is_possible_number_for_type,
109+
is_possible_number_for_type_with_reason,
108110
is_possible_number_string,
109111
is_possible_number_with_reason,
110112
is_valid_number,
@@ -121,6 +123,8 @@
121123
region_code_for_country_code,
122124
region_codes_for_country_code,
123125
region_code_for_number,
126+
supported_types_for_region,
127+
supported_types_for_non_geo_entity,
124128
truncate_too_long_number,
125129
is_mobile_number_portable_region,)
126130
from .shortnumberinfo import (ShortNumberCost,
@@ -172,6 +176,8 @@
172176
'is_number_type_geographical',
173177
'is_number_match',
174178
'is_possible_number',
179+
'is_possible_number_for_type',
180+
'is_possible_number_for_type_with_reason',
175181
'is_possible_number_string',
176182
'is_possible_number_with_reason',
177183
'is_valid_number',
@@ -187,6 +193,8 @@
187193
'region_code_for_country_code',
188194
'region_codes_for_country_code',
189195
'region_code_for_number',
196+
'supported_types_for_region',
197+
'supported_types_for_non_geo_entity',
190198
'truncate_too_long_number',
191199
'is_mobile_number_portable_region',
192200
# end of items from phonenumberutil.py

python/phonenumbers/geocoder.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ def description_for_valid_number(numobj, lang, script=None, region=None):
152152
underscore (e.g. "Hant")
153153
region -- The region code for a given user. This region will be omitted
154154
from the description if the phone number comes from this
155-
region. It should be a two-letter uppercase ISO country
156-
code as defined by ISO 3166-1.
155+
region. It should be a two-letter upper-case CLDR region
156+
code.
157157
158158
Returns a text description in the given language code, for the given phone
159159
number, or an empty string if the number could come from multiple countries,
@@ -205,7 +205,10 @@ def description_for_number(numobj, lang, script=None, region=None):
205205
script -- A 4-letter titlecase (first letter uppercase, rest lowercase)
206206
ISO script code as defined in ISO 15924, separated by an
207207
underscore (e.g. "Hant")
208-
region -- A 2-letter uppercase ISO 3166-1 country code (e.g. "GB")
208+
region -- The region code for a given user. This region will be omitted
209+
from the description if the phone number comes from this
210+
region. It should be a two-letter upper-case CLDR region
211+
code.
209212
210213
Returns a text description in the given language code, for the given phone
211214
number, or an empty string if no description is available."""

python/phonenumbers/phonenumberutil.py

Lines changed: 165 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
# -*- coding: utf-8 -*-
12
"""Python phone number parsing and formatting library
23
34
If you use this library, and want to be notified about important changes,
45
please sign up to the libphonenumber mailing list at
56
http://groups.google.com/group/libphonenumber-discuss/about.
67
78
NOTE: A lot of methods in this module require Region Code strings. These must
8-
be provided using ISO 3166-1 two-letter country-code format. These should be
9-
in upper-case. The list of the codes can be found here:
9+
be provided using CLDR two-letter region-code format. These should be in
10+
upper-case. The list of the codes can be found here:
1011
http://www.iso.org/iso/country_codes/iso_3166_code_lists/country_names_and_code_elements.htm
1112
1213
author: Shaopeng Jia (original Java version)
@@ -462,6 +463,9 @@ class ValidationResult(object):
462463
# The number is longer than the shortest valid numbers for this region,
463464
# shorter than the longest valid numbers for this region, and does not
464465
# itself have a number length that matches valid numbers for this region.
466+
# This can also be returned in the case where
467+
# is_possible_number_for_type_with_reason was called, and there are no
468+
# numbers of this type at all for this region.
465469
INVALID_LENGTH = 5
466470
# The number is longer than all valid numbers for this region.
467471
TOO_LONG = 3
@@ -801,6 +805,76 @@ def _normalize_helper(number, replacements, remove_non_matches):
801805
return U_EMPTY_STRING.join(normalized_number)
802806

803807

808+
def _desc_has_possible_number_data(desc):
809+
"""Returns true if there is any possible number data set for a particular PhoneNumberDesc."""
810+
# If this is empty, it means numbers of this type inherit from the "general desc" -> the value
811+
# "-1" means that no numbers exist for this type.
812+
if desc is None:
813+
return False
814+
return len(desc.possible_length) != 1 or desc.possible_length[0] != -1
815+
816+
817+
# Note: desc_has_data must account for any of MetadataFilter's excludableChildFields potentially
818+
# being absent from the metadata. It must check them all. For any changes in descHasData, ensure
819+
# that all the excludableChildFields are still being checked. If your change is safe simply
820+
# mention why during a review without needing to change MetadataFilter.
821+
def _desc_has_data(desc):
822+
"""Returns true if there is any data set for a particular PhoneNumberDesc."""
823+
if desc is None:
824+
return False
825+
# Checking most properties since we don't know what's present, since a custom build may have
826+
# stripped just one of them (e.g. liteBuild strips exampleNumber). We don't bother checking the
827+
# possibleLengthsLocalOnly, since if this is the only thing that's present we don't really
828+
# support the type at all: no type-specific methods will work with only this data.
829+
return ((desc.example_number is not None) or
830+
_desc_has_possible_number_data(desc) or
831+
((desc.national_number_pattern is not None) and (desc.national_number_pattern != "NA")))
832+
833+
834+
def _supported_types_for_metadata(metadata):
835+
"""Returns the types we have metadata for based on the PhoneMetadata object passed in, which must be non-None."""
836+
numtypes = set()
837+
for numtype in PhoneNumberType.values():
838+
if numtype in (PhoneNumberType.FIXED_LINE_OR_MOBILE, PhoneNumberType.UNKNOWN):
839+
# Never return FIXED_LINE_OR_MOBILE (it is a convenience type, and represents that a
840+
# particular number type can't be determined) or UNKNOWN (the non-type).
841+
continue
842+
if _desc_has_data(_number_desc_by_type(metadata, numtype)):
843+
numtypes.add(numtype)
844+
return numtypes
845+
846+
847+
def supported_types_for_region(region_code):
848+
"""Returns the types for a given region which the library has metadata for.
849+
850+
Will not include FIXED_LINE_OR_MOBILE (if numbers in this region could
851+
be classified as FIXED_LINE_OR_MOBILE, both FIXED_LINE and MOBILE would
852+
be present) and UNKNOWN.
853+
854+
No types will be returned for invalid or unknown region codes.
855+
"""
856+
if not _is_valid_region_code(region_code):
857+
return set()
858+
metadata = PhoneMetadata.metadata_for_region(region_code.upper())
859+
return _supported_types_for_metadata(metadata)
860+
861+
862+
def supported_types_for_non_geo_entity(country_code):
863+
"""Returns the types for a country-code belonging to a non-geographical entity
864+
which the library has metadata for. Will not include FIXED_LINE_OR_MOBILE
865+
(if numbers for this non-geographical entity could be classified as
866+
FIXED_LINE_OR_MOBILE, both FIXED_LINE and MOBILE would be present) and
867+
UNKNOWN.
868+
869+
No types will be returned for country calling codes that do not map to a
870+
known non-geographical entity.
871+
"""
872+
metadata = PhoneMetadata.metadata_for_nongeo_region(country_code, None)
873+
if metadata is None:
874+
return set()
875+
return _supported_types_for_metadata(metadata)
876+
877+
804878
def _formatting_rule_has_first_group_only(national_prefix_formatting_rule):
805879
"""Helper function to check if the national prefix formatting rule has the
806880
first group only, i.e., does not start with the national prefix.
@@ -1115,7 +1189,7 @@ def format_number_for_mobile_dialing(numobj, region_calling_from, with_formattin
11151189
metadata = PhoneMetadata.metadata_for_region(region_calling_from)
11161190
if (_can_be_internationally_dialled(numobj_no_ext) and
11171191
_test_number_length(national_significant_number(numobj_no_ext),
1118-
metadata.general_desc) != ValidationResult.TOO_SHORT):
1192+
metadata) != ValidationResult.TOO_SHORT):
11191193
formatted_number = format_number(numobj_no_ext, PhoneNumberFormat.INTERNATIONAL)
11201194
else:
11211195
formatted_number = format_number(numobj_no_ext, PhoneNumberFormat.NATIONAL)
@@ -2132,21 +2206,79 @@ def is_possible_number(numobj):
21322206
return is_possible_number_with_reason(numobj) == ValidationResult.IS_POSSIBLE
21332207

21342208

2135-
def _test_number_length(national_number, number_desc):
2209+
def is_possible_number_for_type(numobj, numtype):
2210+
"""Convenience wrapper around is_possible_number_for_type_with_reason.
2211+
2212+
Instead of returning the reason for failure, this method returns a boolean value.
2213+
2214+
Arguments:
2215+
numobj -- the number object that needs to be checked
2216+
numtype -- the type we are interested in
2217+
2218+
Returns True if the number is possible
2219+
"""
2220+
return is_possible_number_for_type_with_reason(numobj, numtype) == ValidationResult.IS_POSSIBLE
2221+
2222+
2223+
def _test_number_length(national_number, metadata, numtype=PhoneNumberType.UNKNOWN):
21362224
"""Helper method to check a number against possible lengths for this number,
21372225
and determine whether it matches, or is too short or too long. Currently,
21382226
if a number pattern suggests that numbers of length 7 and 10 are possible,
21392227
and a number in between these possible lengths is entered, such as of
21402228
length 8, this will return TOO_LONG.
21412229
"""
2142-
possible_lengths = number_desc.possible_length
2143-
local_lengths = number_desc.possible_length_local_only
2230+
desc_for_type = _number_desc_by_type(metadata, numtype)
2231+
if desc_for_type is None:
2232+
possible_lengths = metadata.general_desc.possible_length
2233+
local_lengths = ()
2234+
else:
2235+
# There should always be "possibleLengths" set for every element. This is declared in the XML
2236+
# schema which is verified by PhoneNumberMetadataSchemaTest.
2237+
# For size efficiency, where a sub-description (e.g. fixed-line) has the same possibleLengths
2238+
# as the parent, this is missing, so we fall back to the general desc (where no numbers of the
2239+
# type exist at all, there is one possible length (-1) which is guaranteed not to match the
2240+
# length of any real phone number).
2241+
possible_lengths = desc_for_type.possible_length
2242+
if len(possible_lengths) == 0:
2243+
possible_lengths = metadata.general_desc.possible_length
2244+
local_lengths = desc_for_type.possible_length_local_only
2245+
2246+
if numtype == PhoneNumberType.FIXED_LINE_OR_MOBILE:
2247+
if not _desc_has_possible_number_data(_number_desc_by_type(metadata, PhoneNumberType.FIXED_LINE)):
2248+
# The rare case has been encountered where no fixedLine data is available (true for some
2249+
# non-geographical entities), so we just check mobile.
2250+
return _test_number_length(national_number, metadata, PhoneNumberType.MOBILE)
2251+
else:
2252+
mobile_desc = _number_desc_by_type(metadata, PhoneNumberType.MOBILE)
2253+
if _desc_has_possible_number_data(mobile_desc):
2254+
# Merge the mobile data in if there was any. We have to make a copy to do this.
2255+
possible_lengths = list(possible_lengths)
2256+
# Note that when adding the possible lengths from mobile, we have to again check they
2257+
# aren't empty since if they are this indicates they are the same as the general desc and
2258+
# should be obtained from there.
2259+
if len(mobile_desc.possible_length) == 0:
2260+
possible_lengths += metadata.general_desc.possible_length
2261+
else:
2262+
possible_lengths += mobile_desc.possible_length
2263+
# The current list is sorted; we need to merge in the new list and re-sort (duplicates
2264+
# are okay). Sorting isn't so expensive because the lists are very small.
2265+
list.sort(possible_lengths)
2266+
2267+
if len(local_lengths) == 0:
2268+
local_lengths = mobile_desc.possible_length_local_only
2269+
else:
2270+
local_lengths = list(local_lengths)
2271+
local_lengths += mobile_desc.possible_length_local_only
2272+
list.sort(local_lengths)
2273+
2274+
# If the type is not supported at all (indicated by a missing PhoneNumberDesc) we return invalid length.
2275+
if desc_for_type is None:
2276+
return ValidationResult.INVALID_LENGTH
2277+
21442278
actual_length = len(national_number)
21452279
if actual_length in local_lengths:
21462280
return ValidationResult.IS_POSSIBLE
2147-
# There should always be "possible_lengths" set for every element. This
2148-
# will be a build-time check once ShortNumberMetadata.xml is migrated to
2149-
# contain this information as well.
2281+
21502282
minimum_length = possible_lengths[0]
21512283
if minimum_length == actual_length:
21522284
return ValidationResult.IS_POSSIBLE
@@ -2167,18 +2299,23 @@ def _test_number_length(national_number, number_desc):
21672299

21682300

21692301
def is_possible_number_with_reason(numobj):
2170-
"""Check whether a phone number is a possible number.
2302+
return is_possible_number_for_type_with_reason(numobj, PhoneNumberType.UNKNOWN)
2303+
2304+
2305+
def is_possible_number_for_type_with_reason(numobj, numtype):
2306+
"""Check whether a phone number is a possible number of a particular type.
21712307
2172-
It provides a more lenient check than is_valid_number() in the following
2173-
sense:
2308+
For types that don't exist in a particular region, this will return a result
2309+
that isn't so useful; it is recommended that you use
2310+
supported_types_for_region or supported_types_for_non_geo_entity
2311+
respectively before calling this method to determine whether you should call
2312+
it for this number at all.
2313+
2314+
This provides a more lenient check than is_valid_number in the following sense:
21742315
21752316
- It only checks the length of phone numbers. In particular, it doesn't
21762317
check starting digits of the number.
21772318
2178-
- It doesn't attempt to figure out the type of the number, but uses
2179-
general rules which applies to all types of phone numbers in a
2180-
region. Therefore, it is much faster than is_valid_number.
2181-
21822319
- For fixed line numbers, many regions have the concept of area code,
21832320
which together with subscriber number constitute the national
21842321
significant number. It is sometimes okay to dial the subscriber number
@@ -2191,23 +2328,27 @@ def is_possible_number_with_reason(numobj):
21912328
21922329
Arguments:
21932330
numobj -- The number object that needs to be checked
2331+
numtype -- The type we are interested in
21942332
21952333
Returns a value from ValidationResult which indicates whether the number
21962334
is possible
21972335
"""
21982336
national_number = national_significant_number(numobj)
21992337
country_code = numobj.country_code
2200-
# Note: For Russian Fed and NANPA numbers, we just use the rules from the
2201-
# default region (US or Russia) since the region_code_for_number() will
2202-
# not work if the number is possible but not valid. This would need to be
2203-
# revisited if the possible number pattern ever differed between various
2204-
# regions within those plans.
2338+
# Note: For regions that share a country calling code, like NANPA numbers,
2339+
# we just use the rules from the default region (US in this case) since the
2340+
# region_code_for_number will not work if the number is possible but not
2341+
# valid. There is in fact one country calling code (290) where the possible
2342+
# number pattern differs between various regions (Saint Helena and Tristan
2343+
# da Cuñha), but this is handled by putting all possible lengths for any
2344+
# country with this country calling code in the metadata for the default
2345+
# region in this case.
22052346
if not _has_valid_country_calling_code(country_code):
22062347
return ValidationResult.INVALID_COUNTRY_CODE
22072348
region_code = region_code_for_country_code(country_code)
22082349
# Metadata cannot be None because the country calling code is valid.
22092350
metadata = PhoneMetadata.metadata_for_region_or_calling_code(country_code, region_code)
2210-
return _test_number_length(national_number, metadata.general_desc)
2351+
return _test_number_length(national_number, metadata, numtype)
22112352

22122353

22132354
def is_possible_number_string(number, region_dialing_from):
@@ -2384,7 +2525,7 @@ def _maybe_extract_country_code(number, metadata, keep_raw_input, numobj):
23842525
# instead.
23852526
if ((fullmatch(valid_pattern, full_number) is None and
23862527
fullmatch(valid_pattern, potential_national_number)) or
2387-
(_test_number_length(full_number, general_desc) == ValidationResult.TOO_LONG)):
2528+
(_test_number_length(full_number, metadata) == ValidationResult.TOO_LONG)):
23882529
if keep_raw_input:
23892530
numobj.country_code_source = CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN
23902531
numobj.country_code = default_country_code
@@ -2714,7 +2855,7 @@ def parse(number, region=None, keep_raw_input=False,
27142855
# prefix and carrier code be long enough to be a possible length for
27152856
# the region. Otherwise, we don't do the stripping, since the original
27162857
# number could be a valid short number.
2717-
if _test_number_length(potential_national_number, metadata.general_desc) != ValidationResult.TOO_SHORT:
2858+
if _test_number_length(potential_national_number, metadata) != ValidationResult.TOO_SHORT:
27182859
normalized_national_number = potential_national_number
27192860
if keep_raw_input and carrier_code is not None and len(carrier_code) > 0:
27202861
numobj.preferred_domestic_carrier_code = carrier_code

0 commit comments

Comments
 (0)