Skip to content

Commit 5fc9bd4

Browse files
committed
Merge branch 'dev' into python3
Conflicts: python/phonenumbers/asyoutypeformatter.py python/phonenumbers/data/region_800.py python/phonenumbers/data/region_808.py python/phonenumbers/data/region_888.py python/phonenumbers/data/region_979.py python/phonenumbers/data/region_BG.py python/phonenumbers/data/region_EG.py python/phonenumbers/data/region_GA.py python/phonenumbers/data/region_IT.py python/phonenumbers/data/region_JP.py python/phonenumbers/data/region_LB.py python/phonenumbers/data/region_LI.py python/phonenumbers/geocoder.py python/phonenumbers/geodata/__init__.py python/tests/asyoutypetest.py python/tests/testdata/region_US.py tools/python/README
2 parents 9ac9d7a + f34b26a commit 5fc9bd4

35 files changed

Lines changed: 1521 additions & 274 deletions

python/HISTORY

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11

2+
=====================
3+
What's new in 5.1b1
4+
=====================
5+
6+
Merge up to upstream Subversion revision 516.
7+
8+
29
=====================
310
What's new in 5.0b2
411
=====================

python/phonenumbers/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@
121121

122122
# Version number is taken from the upstream libphonenumber version
123123
# together with an indication of the version of the Python-specific code.
124-
__version__ = "5.0b2"
124+
__version__ = "5.1b1"
125125

126126
__all__ = ['PhoneNumber', 'CountryCodeSource', 'FrozenPhoneNumber',
127127
'REGION_CODE_FOR_NON_GEO_ENTITY', 'NumberFormat', 'PhoneNumberDesc', 'PhoneMetadata',

python/phonenumbers/asyoutypeformatter.py

Lines changed: 81 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@
3434
from .phonenumberutil import _PLUS_SIGN, _PLUS_CHARS_PATTERN
3535
from .phonenumberutil import _extract_country_code, region_code_for_country_code
3636
from .phonenumberutil import country_code_for_region
37+
from .phonenumberutil import _formatting_rule_has_first_group_only
3738

39+
# Character used when appropriate to separate a prefix, such as a long NDD or
40+
# a country calling code, from the national number.
41+
_SEPARATOR_BEFORE_NATIONAL_NUMBER = U_SPACE
3842
_EMPTY_METADATA = PhoneMetadata(id=unicod(""),
3943
international_prefix=unicod("NA"),
4044
register=False)
@@ -49,6 +53,10 @@
4953
# two-digit number, since the phone number can be as long as 15 digits.
5054
_STANDALONE_DIGIT_PATTERN = re.compile(unicod("\\d(?=[^,}][^,}])"))
5155

56+
# A set of characters that, if found in a national prefix formatting rules, are an indicator to
57+
# us that we should separate the national prefix from the number when formatting.
58+
_NATIONAL_PREFIX_SEPARATORS_PATTERN = re.compile("[- ]")
59+
5260
# A pattern that is used to determine if a number_format under
5361
# available_formats is eligible to be used by the AYTF. It is eligible when
5462
# the format element under number_format contains groups of the dollar sign
@@ -110,6 +118,10 @@ def _maybe_create_new_template(self):
110118
return False
111119
if self._create_formatting_template(number_format):
112120
self._current_formatting_pattern = pattern
121+
if number_format.national_prefix_formatting_rule is None:
122+
self._should_add_space_after_national_prefix = False
123+
else:
124+
self._should_add_space_after_national_prefix = bool(_NATIONAL_PREFIX_SEPARATORS_PATTERN.search(number_format.national_prefix_formatting_rule))
113125
# With a new formatting template, the matched position using
114126
# the old template needs to be reset.
115127
self._last_match_position = 0
@@ -123,14 +135,18 @@ def _maybe_create_new_template(self):
123135
return False
124136

125137
def _get_available_formats(self, leading_three_digits):
126-
if (self._is_international_formatting and
138+
if (self._is_complete_number and
127139
len(self._current_metadata.intl_number_format) > 0):
128140
format_list = self._current_metadata.intl_number_format
129141
else:
130142
format_list = self._current_metadata.number_format
143+
national_prefix_is_used_by_country = (self._current_metadata.national_prefix is not None)
131144
for this_format in format_list:
132-
if self._is_format_eligible(this_format.format):
133-
self._possible_formats.append(this_format)
145+
if (not national_prefix_is_used_by_country or self._is_complete_number or
146+
this_format.national_prefix_optional_when_formatting or
147+
_formatting_rule_has_first_group_only(this_format.national_prefix_formatting_rule)):
148+
if self._is_format_eligible(this_format.format):
149+
self._possible_formats.append(this_format)
134150
self._narrow_down_possible_formats(leading_three_digits)
135151

136152
def _is_format_eligible(self, format):
@@ -210,6 +226,7 @@ def _clear(self):
210226
# inserted). For example, this can contain IDD, country code, and/or
211227
# NDD, etc.
212228
self._prefix_before_national_number = U_EMPTY_STRING
229+
self._should_add_space_after_national_prefix = False
213230
# This contains the national prefix that has been extracted. It
214231
# contains only digits without formatting.
215232
self._national_prefix_extracted = U_EMPTY_STRING
@@ -228,7 +245,11 @@ def _clear(self):
228245
# most recently invoked, as found in the original sequence of
229246
# characters the user entered.
230247
self._original_position = 0
231-
self._is_international_formatting = False
248+
# This is set to true when we know the user is entering a full
249+
# national significant number, since we have either detected a
250+
# national prefix or an international dialing prefix. When this is
251+
# true, we will no longer use local number formatting patterns.
252+
self._is_complete_number = False
232253
self._is_expecting_country_calling_code = False
233254
self._possible_formats = []
234255

@@ -284,8 +305,11 @@ def input_digit(self, next_char, remember_position=False):
284305
return self._current_output
285306
elif self._able_to_extract_longer_ndd():
286307
# Add an additional space to separate long NDD and national
287-
# significant number for readability.
288-
self._prefix_before_national_number += U_SPACE
308+
# significant number for readability. We don't set
309+
# should_add_space_after_national_prefix to True, since we don't
310+
# want this to change later when we choose formatting
311+
# templates.
312+
self._prefix_before_national_number += _SEPARATOR_BEFORE_NATIONAL_NUMBER
289313
self._current_output = self._attempt_to_choose_pattern_with_prefix_extracted()
290314
return self._current_output
291315

@@ -313,8 +337,7 @@ def input_digit(self, next_char, remember_position=False):
313337
self._current_output = self._prefix_before_national_number + self._national_number
314338
return self._current_output
315339

316-
if len(self._possible_formats) > 0:
317-
# The formatting pattern is already chosen.
340+
if len(self._possible_formats) > 0: # The formatting pattern is already chosen.
318341
temp_national_number = self._input_digit_helper(next_char)
319342
# See if the accrued digits can be formatted properly already. If
320343
# not, use the results from input_digit_helper, which does
@@ -328,7 +351,7 @@ def input_digit(self, next_char, remember_position=False):
328351
self._current_output = self._input_accrued_national_number()
329352
return self._current_output
330353
if self._able_to_format:
331-
self._current_output = self._prefix_before_national_number + temp_national_number
354+
self._current_output = self._append_national_number(temp_national_number)
332355
return self._current_output
333356
else:
334357
self._current_output = self._accrued_input
@@ -365,11 +388,18 @@ def _is_digit_or_leading_plus_sign(self, next_char):
365388
fullmatch(_PLUS_CHARS_PATTERN, next_char)))
366389

367390
def _attempt_to_format_accrued_digits(self):
368-
for num_format in self._possible_formats:
369-
num_re = re.compile(num_format.pattern)
391+
"""Check to see if there is an exact pattern match for these digits. If so, we should use this
392+
instead of any other formatting template whose leadingDigitsPattern also matches the input.
393+
"""
394+
for number_format in self._possible_formats:
395+
num_re = re.compile(number_format.pattern)
370396
if fullmatch(num_re, self._national_number):
371-
formatted_number = re.sub(num_re, num_format.format, self._national_number)
372-
return self._prefix_before_national_number + formatted_number
397+
if number_format.national_prefix_formatting_rule is None:
398+
self._should_add_space_after_national_prefix = False
399+
else:
400+
self._should_add_space_after_national_prefix = bool(_NATIONAL_PREFIX_SEPARATORS_PATTERN.search(number_format.national_prefix_formatting_rule))
401+
formatted_number = re.sub(num_re, number_format.format, self._national_number)
402+
return self._append_national_number(formatted_number)
373403
return U_EMPTY_STRING
374404

375405
def get_remembered_position(self):
@@ -388,6 +418,23 @@ def get_remembered_position(self):
388418
current_output_index += 1
389419
return current_output_index
390420

421+
def _append_national_number(self, national_number):
422+
"""Combines the national number with any prefix (IDD/+ and country
423+
code or national prefix) that was collected. A space will be inserted
424+
between them if the current formatting template indicates this to be
425+
suitable.
426+
"""
427+
prefix_before_nn_len = len(self._prefix_before_national_number)
428+
if (self._should_add_space_after_national_prefix and prefix_before_nn_len > 0 and
429+
self._prefix_before_national_number[-1] != _SEPARATOR_BEFORE_NATIONAL_NUMBER):
430+
# We want to add a space after the national prefix if the national
431+
# prefix formatting rule indicates that this would normally be
432+
# done, with the exception of the case where we already appended a
433+
# space because the NDD was surprisingly long.
434+
return self._prefix_before_national_number + _SEPARATOR_BEFORE_NATIONAL_NUMBER + national_number
435+
else:
436+
return self._prefix_before_national_number + national_number
437+
391438
def _attempt_to_choose_formatting_pattern(self):
392439
"""Attempts to set the formatting template and returns a string which
393440
contains the formatted version of the digits entered so far."""
@@ -400,7 +447,7 @@ def _attempt_to_choose_formatting_pattern(self):
400447
else:
401448
return self._accrued_input
402449
else:
403-
return self._prefix_before_national_number + self._national_number
450+
return self._append_national_number(self._national_number)
404451

405452
def _input_accrued_national_number(self):
406453
"""Invokes input_digit_helper on each digit of the national number
@@ -411,18 +458,30 @@ def _input_accrued_national_number(self):
411458
for ii in range(length_of_national_number):
412459
temp_national_number = self._input_digit_helper(self._national_number[ii])
413460
if self._able_to_format:
414-
return self._prefix_before_national_number + temp_national_number
461+
return self._append_national_number(temp_national_number)
415462
else:
416463
return self._accrued_input
417464
else:
418465
return self._prefix_before_national_number
419466

467+
def _is_nanpa_number_with_national_prefix(self):
468+
"""Returns true if the current country is a NANPA country and the
469+
national number begins with the national prefix.
470+
"""
471+
# For NANPA numbers beginning with 1[2-9], treat the 1 as the national
472+
# prefix. The reason is that national significant numbers in NANPA
473+
# always start with [2-9] after the national prefix. Numbers
474+
# beginning with 1[01] can only be short/emergency numbers, which
475+
# don't need the national prefix.
476+
return (self._current_metadata.country_code == 1 and self._national_number[0] == '1' and
477+
self._national_number[1] != '0' and self._national_number[1] != '1')
478+
420479
def _remove_national_prefix_from_national_number(self):
421480
start_of_national_number = 0
422-
if self._current_metadata.country_code == 1 and self._national_number[0] == unicod('1'):
481+
if self._is_nanpa_number_with_national_prefix():
423482
start_of_national_number = 1
424-
self._prefix_before_national_number += unicod("1 ")
425-
self._is_international_formatting = True
483+
self._prefix_before_national_number += unicod("1") + _SEPARATOR_BEFORE_NATIONAL_NUMBER
484+
self._is_complete_number = True
426485
elif self._current_metadata.national_prefix_for_parsing is not None:
427486
npp_re = re.compile(self._current_metadata.national_prefix_for_parsing)
428487
m = npp_re.match(self._national_number)
@@ -431,7 +490,7 @@ def _remove_national_prefix_from_national_number(self):
431490
# formatting rules instead of national ones, because national
432491
# formatting rules could contain local formatting rules for
433492
# numbers entered without area code.
434-
self._is_international_formatting = True
493+
self._is_complete_number = True
435494
start_of_national_number = m.end()
436495
self._prefix_before_national_number += self._national_number[:start_of_national_number]
437496
national_prefix = self._national_number[:start_of_national_number]
@@ -450,12 +509,12 @@ def _attempt_to_extract_idd(self):
450509
unicod("|") + self._current_metadata.international_prefix)
451510
idd_match = international_prefix.match(self._accrued_input_without_formatting)
452511
if idd_match:
453-
self._is_international_formatting = True
512+
self._is_complete_number = True
454513
start_of_country_calling_code = idd_match.end()
455514
self._national_number = self._accrued_input_without_formatting[start_of_country_calling_code:]
456515
self._prefix_before_national_number = self._accrued_input_without_formatting[:start_of_country_calling_code]
457516
if self._accrued_input_without_formatting[0] != _PLUS_SIGN:
458-
self._prefix_before_national_number += U_SPACE
517+
self._prefix_before_national_number += _SEPARATOR_BEFORE_NATIONAL_NUMBER
459518
return True
460519
return False
461520

@@ -482,7 +541,7 @@ def _attempt_to_extract_ccc(self):
482541
self._current_metadata = _get_metadata_for_region(new_region_code)
483542

484543
self._prefix_before_national_number += str(country_code)
485-
self._prefix_before_national_number += U_SPACE
544+
self._prefix_before_national_number += _SEPARATOR_BEFORE_NATIONAL_NUMBER
486545
return True
487546

488547
def _normalize_and_accrue_digits_and_plus_sign(self, next_char, remember_position):

python/phonenumbers/data/region_800.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@
1515
emergency=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
1616
voicemail=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
1717
no_international_dialling=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
18-
number_format=[NumberFormat(pattern='(\\d{4})(\\d{4})', format='\\1 \\2')])
18+
number_format=[NumberFormat(pattern='(\\d{4})(\\d{4})', format='\\1 \\2')],
19+
leading_zero_possible=True)

python/phonenumbers/data/region_808.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@
1515
emergency=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
1616
voicemail=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
1717
no_international_dialling=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
18-
number_format=[NumberFormat(pattern='(\\d{4})(\\d{4})', format='\\1 \\2')])
18+
number_format=[NumberFormat(pattern='(\\d{4})(\\d{4})', format='\\1 \\2')],
19+
leading_zero_possible=True)

python/phonenumbers/data/region_888.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@
1515
emergency=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
1616
voicemail=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
1717
no_international_dialling=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
18-
number_format=[NumberFormat(pattern='(\\d{3})(\\d{3})(\\d{5})', format='\\1 \\2 \\3')])
18+
number_format=[NumberFormat(pattern='(\\d{3})(\\d{3})(\\d{5})', format='\\1 \\2 \\3')],
19+
leading_zero_possible=True)

python/phonenumbers/data/region_979.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@
1515
emergency=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
1616
voicemail=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
1717
no_international_dialling=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
18-
number_format=[NumberFormat(pattern='(\\d)(\\d{4})(\\d{4})', format='\\1 \\2 \\3')])
18+
number_format=[NumberFormat(pattern='(\\d)(\\d{4})(\\d{4})', format='\\1 \\2 \\3')],
19+
leading_zero_possible=True)

python/phonenumbers/data/region_BF.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
PHONE_METADATA_BF = PhoneMetadata(id='BF', country_code=226, international_prefix='00',
55
general_desc=PhoneNumberDesc(national_number_pattern='[24-7]\\d{7}', possible_number_pattern='\\d{8}'),
66
fixed_line=PhoneNumberDesc(national_number_pattern='(?:20(?:49|5[23]|9[016-9])|40(?:4[56]|5[4-6]|7[0179])|50[34]\\d)\\d{4}', possible_number_pattern='\\d{8}', example_number='20491234'),
7-
mobile=PhoneNumberDesc(national_number_pattern='(?:6(?:0\\d|1[01]|6[0-4]|8[0-2])|7(?:[02-68]\\d|1[0-4689]|7[0-69]|9[0-689]))\\d{5}', possible_number_pattern='\\d{8}', example_number='70123456'),
7+
mobile=PhoneNumberDesc(national_number_pattern='(?:6(?:[05]\\d|1[01]|6[0-7]|8[0-2])|7(?:[02-68]\\d|1[0-4689]|7[0-69]|9[0-689]))\\d{5}', possible_number_pattern='\\d{8}', example_number='70123456'),
88
toll_free=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
99
premium_rate=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
1010
shared_cost=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),

python/phonenumbers/data/region_BG.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
no_international_dialling=PhoneNumberDesc(national_number_pattern='NA', possible_number_pattern='NA'),
1818
national_prefix='0',
1919
national_prefix_for_parsing='0',
20-
number_format=[NumberFormat(pattern='(2)(\\d{5})', format='\\1/\\2', leading_digits_pattern=['29'], national_prefix_formatting_rule='0\\1'),
21-
NumberFormat(pattern='(2)(\\d{3})(\\d{3,4})', format='\\1/\\2 \\3', leading_digits_pattern=['2'], national_prefix_formatting_rule='0\\1'),
22-
NumberFormat(pattern='(\\d{3})(\\d{4})', format='\\1/\\2', leading_digits_pattern=['43[124-7]|70[1-9]'], national_prefix_formatting_rule='0\\1'),
23-
NumberFormat(pattern='(\\d{3})(\\d{3})(\\d{2})', format='\\1/\\2 \\3', leading_digits_pattern=['43[124-7]|70[1-9]'], national_prefix_formatting_rule='0\\1'),
20+
number_format=[NumberFormat(pattern='(2)(\\d{5})', format='\\1 \\2', leading_digits_pattern=['29'], national_prefix_formatting_rule='0\\1'),
21+
NumberFormat(pattern='(2)(\\d{3})(\\d{3,4})', format='\\1 \\2 \\3', leading_digits_pattern=['2'], national_prefix_formatting_rule='0\\1'),
22+
NumberFormat(pattern='(\\d{3})(\\d{4})', format='\\1 \\2', leading_digits_pattern=['43[124-7]|70[1-9]'], national_prefix_formatting_rule='0\\1'),
23+
NumberFormat(pattern='(\\d{3})(\\d{3})(\\d{2})', format='\\1 \\2 \\3', leading_digits_pattern=['43[124-7]|70[1-9]'], national_prefix_formatting_rule='0\\1'),
2424
NumberFormat(pattern='(\\d{3})(\\d{2})(\\d{3})', format='\\1 \\2 \\3', leading_digits_pattern=['[78]00'], national_prefix_formatting_rule='0\\1'),
25-
NumberFormat(pattern='(\\d{2})(\\d{3})(\\d{2,3})', format='\\1/\\2 \\3', leading_digits_pattern=['[356]|7[1-9]|8[1-6]|9[1-7]'], national_prefix_formatting_rule='0\\1'),
25+
NumberFormat(pattern='(\\d{2})(\\d{3})(\\d{2,3})', format='\\1 \\2 \\3', leading_digits_pattern=['[356]|7[1-9]|8[1-6]|9[1-7]'], national_prefix_formatting_rule='0\\1'),
2626
NumberFormat(pattern='(\\d{2})(\\d{3})(\\d{3,4})', format='\\1 \\2 \\3', leading_digits_pattern=['48|8[7-9]|9[08]'], national_prefix_formatting_rule='0\\1')])

0 commit comments

Comments
 (0)