summaryrefslogtreecommitdiff
path: root/python/phonenumbers/carrier.py
blob: a97aea8005f7ad0685fa841841120daf7ed7002b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
"""Phone number to carrier mapping functionality

>>> import phonenumbers
>>> from phonenumbers.carrier import name_for_number
>>> ro_number = phonenumbers.parse("+40721234567", "RO")
>>> str(name_for_number(ro_number, "en"))
'Vodafone'
>>> str(name_for_number(ro_number, "fr"))  # fall back to English
'Vodafone'

"""
# Based very loosely on original Java code:
#     java/carrier/src/com/google/i18n/phonenumbers/PhoneNumberToCarrierMapper.java
#   Copyright (C) 2013 The Libphonenumber Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from .util import prnt, u, U_EMPTY_STRING
from .phonenumberutil import PhoneNumberType, number_type
from .phonenumberutil import region_code_for_number
from .phonenumberutil import is_mobile_number_portable_region
from .prefix import _prefix_description_for_number
try:
    from .carrierdata import CARRIER_DATA, CARRIER_LONGEST_PREFIX
except ImportError:  # pragma no cover
    # Before the generated code exists, the carrierdata/ directory is empty.
    # The generation process imports this module, creating a circular
    # dependency.  The hack below works around this.
    import os
    import sys
    if (os.path.basename(sys.argv[0]) == "buildmetadatafromxml.py" or
        os.path.basename(sys.argv[0]) == "buildprefixdata.py"):
        prnt("Failed to import generated data (but OK as during autogeneration)", file=sys.stderr)
        CARRIER_DATA = {'1': {'en': u('United States')}}
        CARRIER_LONGEST_PREFIX = 1
    else:
        raise


__all__ = ['name_for_valid_number', 'name_for_number', 'safe_display_name']


def name_for_valid_number(numobj, lang, script=None, region=None):
    """Returns a carrier name for the given PhoneNumber object, in the
    language provided.

    The carrier name is the one the number was originally allocated to,
    however if the country supports mobile number portability the number might
    not belong to the returned carrier anymore. If no mapping is found an
    empty string is returned.

    This method assumes the validity of the number passed in has already been
    checked, and that the number is suitable for carrier lookup. We consider
    mobile and pager numbers possible candidates for carrier lookup.

    Arguments:
    numobj -- The PhoneNumber object for which we want to get a carrier name.
    lang -- A 2-letter lowercase ISO 639-1 language code for the language in
                  which the description should be returned (e.g. "en")
    script -- A 4-letter titlecase (first letter uppercase, rest lowercase)
                  ISO script code as defined in ISO 15924, separated by an
                  underscore (e.g. "Hant")
    region --  A 2-letter uppercase ISO 3166-1 country code (e.g. "GB")

    Returns a carrier name in the given language code, for the given phone
    number, or an empty string if no description is available.
    """
    return _prefix_description_for_number(CARRIER_DATA, CARRIER_LONGEST_PREFIX,
                                          numobj, lang, script, region)


def name_for_number(numobj, lang, script=None, region=None):
    """Returns a carrier name for the given PhoneNumber object, in the
    language provided.

    The carrier name is the one the number was originally allocated to,
    however if the country supports mobile number portability the number might
    not belong to the returned carrier anymore. If no mapping is found an
    empty string is returned.

    This function explicitly checks the validity of the number passed in

    Arguments:
    numobj -- The PhoneNumber object for which we want to get a carrier name.
    lang -- A 2-letter lowercase ISO 639-1 language code for the language in
                  which the description should be returned (e.g. "en")
    script -- A 4-letter titlecase (first letter uppercase, rest lowercase)
                  ISO script code as defined in ISO 15924, separated by an
                  underscore (e.g. "Hant")
    region --  A 2-letter uppercase ISO 3166-1 country code (e.g. "GB")

    Returns a carrier name in the given language code, for the given phone
    number, or an empty string if no description is available.
    """
    ntype = number_type(numobj)
    if _is_mobile(ntype):
        return name_for_valid_number(numobj, lang, script, region)
    return U_EMPTY_STRING


def safe_display_name(numobj, lang, script=None, region=None):
    """Gets the name of the carrier for the given PhoneNumber object only when
    it is 'safe' to display to users.  A carrier name is onsidered safe if the
    number is valid and for a region that doesn't support mobile number
    portability (http://en.wikipedia.org/wiki/Mobile_number_portability).


    This function explicitly checks the validity of the number passed in

    Arguments:
    numobj -- The PhoneNumber object for which we want to get a carrier name.
    lang -- A 2-letter lowercase ISO 639-1 language code for the language in
                  which the description should be returned (e.g. "en")
    script -- A 4-letter titlecase (first letter uppercase, rest lowercase)
                  ISO script code as defined in ISO 15924, separated by an
                  underscore (e.g. "Hant")
    region --  A 2-letter uppercase ISO 3166-1 country code (e.g. "GB")

    Returns a carrier name that is safe to display to users, or the empty string.
    """
    if is_mobile_number_portable_region(region_code_for_number(numobj)):
        return U_EMPTY_STRING
    return name_for_number(numobj, lang, script, region)


def _is_mobile(ntype):
    """Checks if the supplied number type supports carrier lookup"""
    return (ntype == PhoneNumberType.MOBILE or
            ntype == PhoneNumberType.FIXED_LINE_OR_MOBILE or
            ntype == PhoneNumberType.PAGER)

if __name__ == '__main__':  # pragma no cover
    import doctest
    doctest.testmod()