Skip to content

Commit bb1769a

Browse files
committed
Create shortnumberutil code from upstream r374
1 parent b15ed9d commit bb1769a

4 files changed

Lines changed: 132 additions & 0 deletions

File tree

python/phonenumbers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
# Functionality
8383
from asyoutypeformatter import AsYouTypeFormatter
8484
from phonenumberutil import *
85+
from shortnumberutil import connects_to_emergency_number
8586
from phonenumbermatcher import PhoneNumberMatch, PhoneNumberMatcher, Leniency
8687
from geocoder import (area_description_for_number, country_name_for_number,
8788
description_for_number, description_for_valid_number)
@@ -123,6 +124,7 @@
123124
'region_code_for_country_code',
124125
'region_code_for_number',
125126
'truncate_too_long_number',
127+
'connects_to_emergency_number',
126128
'PhoneNumberMatch', 'PhoneNumberMatcher', 'Leniency',
127129
'area_description_for_number',
128130
'country_name_for_number',
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""Utility for international short phone numbers, such as short codes and emergency numbers.
2+
3+
Note most commercial short numbers are not handled here, but by phonenumberutil.py
4+
"""
5+
# Based on original Java code:
6+
# java/src/com/google/i18n/phonenumbers/ShortNumberUtil.java
7+
# Copyright (C) 2011 The Libphonenumber Authors
8+
#
9+
# Licensed under the Apache License, Version 2.0 (the "License");
10+
# you may not use this file except in compliance with the License.
11+
# You may obtain a copy of the License at
12+
#
13+
# http://www.apache.org/licenses/LICENSE-2.0
14+
#
15+
# Unless required by applicable law or agreed to in writing, software
16+
# distributed under the License is distributed on an "AS IS" BASIS,
17+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
# See the License for the specific language governing permissions and
19+
# limitations under the License.
20+
import re
21+
22+
from re_util import fullmatch
23+
from phonemetadata import PhoneMetadata
24+
from phonenumberutil import _extract_possible_number, _PLUS_CHARS_PATTERN
25+
from phonenumberutil import normalize_digits_only
26+
27+
28+
def connects_to_emergency_number(number, region_code):
29+
"""Returns whether the number might be used to connect to an emergency
30+
service in the given region.
31+
32+
This function takes into account cases where the number might contain
33+
formatting, or might have additional digits appended (when it is okay to
34+
do that in the region specified).
35+
36+
Arguments:
37+
number -- The phone number to test.
38+
region_code -- The region where the phone number is being dialed.
39+
40+
Returns whether the number might be used to connect to an emergency
41+
service in the given region.
42+
"""
43+
number = _extract_possible_number(number)
44+
if _PLUS_CHARS_PATTERN.match(number):
45+
# Returns False if the number starts with a plus sign. We don't
46+
# believe dialing the country code before emergency numbers
47+
# (e.g. +1911) works, but later, if that proves to work, we can add
48+
# additional logic here to handle it.
49+
return False
50+
normalized_number = normalize_digits_only(number)
51+
metadata = PhoneMetadata.region_metadata.get(region_code.upper(), None)
52+
emergency_number_desc = metadata.emergency
53+
emergency_number_pattern = re.compile(emergency_number_desc.national_number_pattern)
54+
if region_code == "BR":
55+
# This is to prevent Brazilian local numbers which start with 911
56+
# being incorrectly classified as emergency numbers. In Brazil, it is
57+
# impossible to append additional digits to an emergency number to
58+
# dial the number.
59+
if not fullmatch(emergency_number_pattern, normalized_number):
60+
return False
61+
# Check the prefix against possible emergency numbers for this region.
62+
return emergency_number_pattern.match(normalized_number) is not None

python/tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from phonenumbertest import PhoneNumberTest
55
from phonenumberutiltest import PhoneNumberUtilTest
6+
from shortnumberutiltest import ShortNumberUtilTest
67
from asyoutypetest import AsYouTypeFormatterTest
78
from examplenumberstest import ExampleNumbersTest
89
from phonenumbermatchertest import PhoneNumberMatchTest, PhoneNumberMatcherTest
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/env python
2+
"""Unit tests for shortnumberutil.py"""
3+
4+
# Based on original Java code:
5+
# java/test/com/google/i18n/phonenumbers/ShortNumberUtilTest.java
6+
# Copyright (C) 2011 The Libphonenumber Authors
7+
#
8+
# Licensed under the Apache License, Version 2.0 (the "License");
9+
# you may not use this file except in compliance with the License.
10+
# You may obtain a copy of the License at
11+
#
12+
# http://www.apache.org/licenses/LICENSE-2.0
13+
#
14+
# Unless required by applicable law or agreed to in writing, software
15+
# distributed under the License is distributed on an "AS IS" BASIS,
16+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
# See the License for the specific language governing permissions and
18+
# limitations under the License.
19+
20+
import unittest
21+
22+
import pathfix
23+
pathfix.fix()
24+
25+
from phonenumbers import connects_to_emergency_number
26+
from phonenumberutiltest import insert_test_metadata, reinstate_real_metadata
27+
28+
29+
class ShortNumberUtilTest(unittest.TestCase):
30+
def setUp(self):
31+
insert_test_metadata()
32+
33+
def tearDown(self):
34+
reinstate_real_metadata()
35+
36+
def testConnectsToEmergencyNumber_US(self):
37+
self.assertTrue(connects_to_emergency_number("911", "US"))
38+
self.assertTrue(connects_to_emergency_number("119", "US"))
39+
self.assertFalse(connects_to_emergency_number("999", "US"))
40+
41+
def testConnectsToEmergencyNumberLongNumber_US(self):
42+
self.assertTrue(connects_to_emergency_number("9116666666", "US"))
43+
self.assertTrue(connects_to_emergency_number("1196666666", "US"))
44+
self.assertFalse(connects_to_emergency_number("9996666666", "US"))
45+
46+
def testConnectsToEmergencyNumberWithFormatting_US(self):
47+
self.assertTrue(connects_to_emergency_number("9-1-1", "US"))
48+
self.assertTrue(connects_to_emergency_number("1-1-9", "US"))
49+
self.assertFalse(connects_to_emergency_number("9-9-9", "US"))
50+
51+
def testConnectsToEmergencyNumberWithPlusSign_US(self):
52+
self.assertFalse(connects_to_emergency_number("+911", "US"))
53+
self.assertFalse(connects_to_emergency_number(u"\uFF0B911", "US"))
54+
self.assertFalse(connects_to_emergency_number(" +911", "US"))
55+
self.assertFalse(connects_to_emergency_number("+119", "US"))
56+
self.assertFalse(connects_to_emergency_number("+999", "US"))
57+
58+
def testConnectsToEmergencyNumber_BR(self):
59+
self.assertTrue(connects_to_emergency_number("911", "BR"))
60+
self.assertTrue(connects_to_emergency_number("190", "BR"))
61+
self.assertFalse(connects_to_emergency_number("999", "BR"))
62+
63+
def testConnectsToEmergencyNumberLongNumber_BR(self):
64+
# Brazilian emergency numbers don't work when additional digits are appended.
65+
self.assertFalse(connects_to_emergency_number("9111", "BR"))
66+
self.assertFalse(connects_to_emergency_number("1900", "BR"))
67+
self.assertFalse(connects_to_emergency_number("9996", "BR"))

0 commit comments

Comments
 (0)