Skip to content

Commit 8800c97

Browse files
committed
Merge code changes from upstream r622
1 parent f91ffb6 commit 8800c97

13 files changed

Lines changed: 496 additions & 182 deletions

python/phonenumbers/__init__.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
>>> from phonenumbers.util import prnt # equivalent to Py3k print()
77
>>> x = phonenumbers.parse("+442083661177", None)
88
>>> prnt(x)
9-
Country Code: 44 National Number: 2083661177 Leading Zero: False
9+
Country Code: 44 National Number: 2083661177 Leading Zero(s): False
1010
>>> type(x)
1111
<class 'phonenumbers.phonenumber.PhoneNumber'>
1212
>>> str(phonenumbers.format_number(x, phonenumbers.PhoneNumberFormat.NATIONAL))
@@ -17,7 +17,7 @@
1717
'+442083661177'
1818
>>> y = phonenumbers.parse("020 8366 1177", "GB")
1919
>>> prnt(y)
20-
Country Code: 44 National Number: 2083661177 Leading Zero: False
20+
Country Code: 44 National Number: 2083661177 Leading Zero(s): False
2121
>>> x == y
2222
True
2323
>>>
@@ -117,10 +117,11 @@
117117
truncate_too_long_number,
118118
is_mobile_number_portable_region,)
119119
from .shortnumberinfo import (ShortNumberCost,
120+
is_possible_short_number_for_region,
120121
is_possible_short_number,
121-
is_possible_short_number_object,
122+
is_valid_short_number_for_region,
122123
is_valid_short_number,
123-
is_valid_short_number_object,
124+
expected_cost_for_region,
124125
expected_cost,
125126
connects_to_emergency_number,
126127
is_emergency_number,
@@ -179,10 +180,11 @@
179180
# end of items from phonenumberutil.py
180181
# items from shortnumberinfo.py
181182
'ShortNumberCost',
183+
'is_possible_short_number_for_region',
182184
'is_possible_short_number',
183-
'is_possible_short_number_object',
185+
'is_valid_short_number_for_region',
184186
'is_valid_short_number',
185-
'is_valid_short_number_object',
187+
'expected_cost_for_region',
186188
'expected_cost',
187189
'connects_to_emergency_number',
188190
'is_emergency_number',

python/phonenumbers/geocoder.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
from .util import prnt, unicod, u, U_EMPTY_STRING, U_ZERO
4848
from .phonenumberutil import region_code_for_number, PhoneNumberType, PhoneNumber
4949
from .phonenumberutil import country_mobile_token, national_significant_number, number_type
50+
from .phonenumberutil import region_code_for_country_code, parse, NumberParseException
5051
from .prefix import prefix_description_for_number
5152
try:
5253
from .geodata import GEOCODE_DATA, GEOCODE_LONGEST_PREFIX
@@ -147,9 +148,13 @@ def description_for_valid_number(numobj, lang, script=None, region=None):
147148
# before the national destination code, this should be removed before
148149
# geocoding.
149150
national_number = national_number[len(mobile_token):]
150-
copied_numobj = PhoneNumber(country_code=numobj.country_code,
151-
national_number=national_number,
152-
italian_leading_zero=national_number.startswith(U_ZERO))
151+
152+
region = region_code_for_country_code(numobj.country_code)
153+
try:
154+
copied_numobj = parse(national_number, region)
155+
except NumberParseException:
156+
# If this happens, just re-use what we had.
157+
copied_numobj = numobj
153158
area_description = prefix_description_for_number(GEOCODE_DATA, GEOCODE_LONGEST_PREFIX,
154159
copied_numobj, lang, script, region)
155160
else:

python/phonenumbers/pb2/phonenumber_pb2.py

Lines changed: 14 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python/phonenumbers/phonenumber.py

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,24 @@ class CountryCodeSource(object):
2424
"""The source from which a country code is derived."""
2525

2626
# The country_code is derived based on a phone number with a leading "+",
27-
# e.g. the French number "+33 (0)1 42 68 53 00".
27+
# e.g. the French number "+33 1 42 68 53 00".
2828
FROM_NUMBER_WITH_PLUS_SIGN = 1
2929

3030
# The country_code is derived based on a phone number with a leading IDD,
31-
# e.g. the French number "011 33 (0)1 42 68 53 00", as it is dialled
31+
# e.g. the French number "011 33 1 42 68 53 00", as it is dialled
3232
# from US.
3333
FROM_NUMBER_WITH_IDD = 5
3434

3535
# The country_code is derived based on a phone number without a leading
36-
# "+", e.g. the French number "33 (0)1 42 68 53 00" when default_country is
36+
# "+", e.g. the French number "33 1 42 68 53 00" when default_country is
3737
# supplied as France.
3838
FROM_NUMBER_WITHOUT_PLUS_SIGN = 10
3939

4040
# The country_code is derived NOT based on the phone number itself, but
4141
# from the default_country parameter provided in the parsing function by
4242
# the clients. This happens mostly for numbers written in the national
4343
# format (without country code). For example, this would be set when
44-
# parsing the French number "(0)1 42 68 53 00", when default_country is
44+
# parsing the French number "01 42 68 53 00", when default_country is
4545
# supplied as France.
4646
FROM_DEFAULT_COUNTRY = 20
4747

@@ -58,6 +58,7 @@ def __init__(self,
5858
national_number=None,
5959
extension=None,
6060
italian_leading_zero=False,
61+
number_of_leading_zeros=None,
6162
raw_input=None,
6263
country_code_source=None,
6364
preferred_domestic_carrier_code=None):
@@ -71,18 +72,21 @@ def __init__(self,
7172
else:
7273
self.country_code = int(country_code)
7374

75+
# Number does not contain National(trunk) prefix.
7476
# National (significant) Number is defined in International
75-
# Telecommunication Union Recommendation E.164. It is a
77+
# Telecommunication Union (ITU) Recommendation E.164. It is a
7678
# language/country-neutral representation of a phone number at a
77-
# country level. For countries which have the concept of Area Code, the
78-
# National (significant) Number contains the area code. It contains a
79-
# maximum number of digits which equal to 15 - n, where n is the number
80-
# of digits of the country code. Take note that National (significant)
81-
# Number does not contain National(trunk) prefix.
79+
# country level. For countries which have the concept of Area Code,
80+
# the National (significant) Number contains the area code. It
81+
# contains a maximum number of digits which equal to 15 - n, where n
82+
# is the number of digits of the country code. Take note that National
83+
# (significant) Number does not contain National(trunk)
84+
# prefix.
8285
#
8386
# None if not set, of type long otherwise (and so it will never
8487
# contain any formatting (hypens, spaces, parentheses), nor any
8588
# alphanumeric spellings).
89+
8690
if national_number is None:
8791
self.national_number = None
8892
else:
@@ -98,23 +102,25 @@ def __init__(self,
98102
# However, only ASCII digits should be stored here.
99103
self.extension = force_unicode(extension) # None or Unicode '[0-9]+'
100104

101-
# In some countries, the national (significant) number starts with
102-
# a "0" without this being a national prefix or trunk code of some
103-
# kind. For example, the leading zero in the national (significant)
104-
# number of an Italian phone number indicates the number is a
105-
# fixed-line number. There have been plans to migrate fixed-line
105+
# In some countries, the national (significant) number starts with one
106+
# or more "0"s without this being a national prefix or trunk code of
107+
# some kind. For example, the leading zero in the national
108+
# (significant) number of an Italian phone number indicates the number
109+
# is a fixed-line number. There have been plans to migrate fixed-line
106110
# numbers to start with the digit two since December 2000, but it has
107111
# not happened yet. See http://en.wikipedia.org/wiki/%2B39 for more
108112
# details.
109113
#
110-
# This field can be safely ignored (there is no need to set it) for
111-
# most countries. Some limited amount of countries behave like Italy;
112-
# for these cases, if the leading zero of a number would be
113-
# retained even when dialling internationally, set this flag to true.
114+
# These fields can be safely ignored (there is no need to set them)
115+
# for most countries. Some limited number of countries behave like
116+
# Italy - for these cases, if the leading zero(s) of a number would be
117+
# retained even when dialling internationally, set this flag to true,
118+
# and also set the number of leading zeros.
114119
#
115-
# Clients who use the parsing functionality of the phonenumbers
116-
# library will have this field set if necessary automatically.
120+
# Clients who use the parsing functionality of the i18n phone number
121+
# libraries will have these fields set if necessary automatically.
117122
self.italian_leading_zero = bool(italian_leading_zero)
123+
self.number_of_leading_zeros = number_of_leading_zeros # None or int
118124

119125
# The next few fields are non-essential fields for a phone number.
120126
# They retain extra information about the form the phone number was
@@ -151,6 +157,7 @@ def clear(self):
151157
self.national_number = None
152158
self.extension = None
153159
self.italian_leading_zero = False
160+
self.number_of_leading_zeros = None
154161
self.raw_input = None
155162
self.country_code_source = None
156163
self.preferred_domestic_carrier_code = None
@@ -165,6 +172,8 @@ def merge_from(self, other):
165172
self.extension = other.extension
166173
if other.italian_leading_zero is not None:
167174
self.italian_leading_zero = other.italian_leading_zero
175+
if other.number_of_leading_zeros is not None:
176+
self.number_of_leading_zeros = other.number_of_leading_zeros
168177
if other.raw_input is not None:
169178
self.raw_input = other.raw_input
170179
if other.country_code_source is not None:
@@ -179,6 +188,7 @@ def __eq__(self, other):
179188
self.national_number == other.national_number and
180189
self.extension == other.extension and
181190
self.italian_leading_zero == other.italian_leading_zero and
191+
self.number_of_leading_zeros == other.number_of_leading_zeros and
182192
self.raw_input == other.raw_input and
183193
self.country_code_source == other.country_code_source and
184194
self.preferred_domestic_carrier_code == other.preferred_domestic_carrier_code)
@@ -188,19 +198,23 @@ def __ne__(self, other):
188198

189199
def __repr__(self):
190200
return (unicod("PhoneNumber(country_code=%s, national_number=%s, extension=%s, " +
191-
"italian_leading_zero=%s, country_code_source=%s, preferred_domestic_carrier_code=%s)") %
201+
"italian_leading_zero=%s, number_of_leading_zeros=%s, " +
202+
"country_code_source=%s, preferred_domestic_carrier_code=%s)") %
192203
(self.country_code,
193204
self.national_number,
194205
rpr(self.extension),
195206
self.italian_leading_zero,
207+
self.number_of_leading_zeros,
196208
self.country_code_source,
197209
rpr(self.preferred_domestic_carrier_code)))
198210

199211
def __unicode__(self):
200212
result = (unicod("Country Code: %s National Number: %s") %
201213
(self.country_code, self.national_number))
202214
if self.italian_leading_zero is not None:
203-
result += unicod(" Leading Zero: %s") % self.italian_leading_zero
215+
result += unicod(" Leading Zero(s): %s") % self.italian_leading_zero
216+
if self.number_of_leading_zeros is not None:
217+
result += unicod(" Number of leading zeros: %d") % self.number_of_leading_zeros
204218
if self.extension is not None:
205219
result += unicod(" Extension: %s") % self.extension
206220
if self.country_code_source is not None:
@@ -218,6 +232,7 @@ def __hash__(self):
218232
self.national_number,
219233
self.extension,
220234
self.italian_leading_zero,
235+
self.number_of_leading_zeros,
221236
self.raw_input,
222237
self.country_code_source,
223238
self.preferred_domestic_carrier_code))

python/phonenumbers/phonenumbermatcher.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
# Extra regexp function; see README
2222
from .re_util import fullmatch
2323
from .util import UnicodeMixin, u, unicod, prnt
24-
from .util import U_EMPTY_STRING, U_DASH, U_SEMICOLON, U_SLASH, U_X_LOWER, U_X_UPPER, U_PERCENT
24+
from .util import U_EMPTY_STRING, U_DASH, U_SEMICOLON, U_SLASH, U_X_LOWER, U_X_UPPER, U_PERCENT, U_STAR
2525
from .unicode_util import Category, Block, is_letter
2626
from .phonenumberutil import _MAX_LENGTH_FOR_NSN, _MAX_LENGTH_COUNTRY_CODE
2727
from .phonenumberutil import _VALID_PUNCTUATION, _PLUS_CHARS, NON_DIGITS_PATTERN
@@ -225,6 +225,10 @@ def _all_number_groups_remain_grouped(numobj, normalized_candidate, formatted_nu
225225
Returns True if expectations matched.
226226
"""
227227
from_index = 0
228+
if numobj.country_code_source != CountryCodeSource.FROM_DEFAULT_COUNTRY:
229+
# First skip the country code if the normalized candidate contained it.
230+
country_code = str(numobj.country_code)
231+
from_index = normalized_candidate.find(country_code) + len(country_code)
228232
# Check each group of consecutive digits are not broken into separate
229233
# groupings in the candidate string.
230234
for ii, formatted_number_group in enumerate(formatted_number_groups):
@@ -662,6 +666,28 @@ def _parse_and_verify(self, candidate, offset):
662666
return None
663667

664668
numobj = parse(candidate, self.preferred_region, keep_raw_input=True)
669+
# Check Israel * numbers: these are a special case in that they
670+
# are four-digit numbers that our library supports, but they can
671+
# only be dialled with a leading *. Since we don't actually store
672+
# or detect the * in our phone number library, this means in
673+
# practice we detect most four digit numbers as being valid for
674+
# Israel. We are considering moving these numbers to
675+
# ShortNumberInfo instead, in which case this problem would go
676+
# away, but in the meantime we want to restrict the false matches
677+
# so we only allow these numbers if they are preceded by a
678+
# star. We enforce this for all leniency levels even though these
679+
# numbers are technically accepted by isPossibleNumber and
680+
# isValidNumber since we consider it to be a deficiency in those
681+
# methods that they accept these numbers without the *.
682+
# TODO: Remove this or make it significantly less hacky once we've
683+
# decided how to handle these short codes going forward in
684+
# ShortNumberInfo. We could use the formatting rules for instance,
685+
# but that would be slower.
686+
if (region_code_for_country_code(numobj.country_code) == "IL" and
687+
len(national_significant_number(numobj)) == 4 and
688+
(offset == 0 or (offset > 0 and self.text[offset - 1] != U_STAR))):
689+
# No match.
690+
return None
665691
if _verify(self.leniency, numobj, candidate):
666692
# We used parse(keep_raw_input=True) to create this number,
667693
# but for now we don't return the extra values parsed.

0 commit comments

Comments
 (0)