641 lines
33 KiB
Python
641 lines
33 KiB
Python
|
|
"""PhoneMetadata object definitions"""
|
||
|
|
|
||
|
|
# Based on original Java code and protocol buffer:
|
||
|
|
# resources/phonemetadata.proto
|
||
|
|
# java/src/com/google/i18n/phonenumbers/Phonemetadata.java
|
||
|
|
# Copyright (C) 2010-2011 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.
|
||
|
|
import threading
|
||
|
|
from .util import UnicodeMixin, ImmutableMixin, mutating_method
|
||
|
|
from .util import u, unicod, rpr, force_unicode
|
||
|
|
|
||
|
|
REGION_CODE_FOR_NON_GEO_ENTITY = u("001")
|
||
|
|
|
||
|
|
|
||
|
|
class NumberFormat(UnicodeMixin, ImmutableMixin):
|
||
|
|
"""Representation of way that a phone number can be formatted for output"""
|
||
|
|
@mutating_method
|
||
|
|
def __init__(self,
|
||
|
|
pattern=None,
|
||
|
|
format=None,
|
||
|
|
leading_digits_pattern=None,
|
||
|
|
national_prefix_formatting_rule=None,
|
||
|
|
national_prefix_optional_when_formatting=None,
|
||
|
|
domestic_carrier_code_formatting_rule=None):
|
||
|
|
# pattern is a regex that is used to match the national (significant)
|
||
|
|
# number. For example, the pattern "(20)(\d{4})(\d{4})" will match
|
||
|
|
# number "2070313000", which is the national (significant) number for
|
||
|
|
# Google London. Note the presence of the parentheses, which are
|
||
|
|
# capturing groups what specifies the grouping of numbers.
|
||
|
|
self.pattern = force_unicode(pattern) # Unicode string holding regexp
|
||
|
|
|
||
|
|
# format specifies how the national (significant) number matched by
|
||
|
|
# pattern should be formatted. Using the same example as above, format
|
||
|
|
# could contain "$1 $2 $3", meaning that the number should be
|
||
|
|
# formatted as "20 7031 3000". Each $x is replaced by the numbers
|
||
|
|
# captured by group x in the regex specified by pattern.
|
||
|
|
self.format = force_unicode(format) # None or Unicode string
|
||
|
|
|
||
|
|
# This field is a regex that is used to match a certain number of
|
||
|
|
# digits at the beginning of the national (significant) number. When
|
||
|
|
# the match is successful, the accompanying pattern and format should
|
||
|
|
# be used to format this number. For example, if
|
||
|
|
# leading_digits="[1-3]|44", then all the national numbers starting
|
||
|
|
# with 1, 2, 3 or 44 should be formatted using the accompanying
|
||
|
|
# pattern and format.
|
||
|
|
#
|
||
|
|
# The first leading_digits_pattern matches up to the first three digits
|
||
|
|
# of the national (significant) number; the next one matches the first
|
||
|
|
# four digits, then the first five and so on, until the
|
||
|
|
# leading_digits_pattern can uniquely identify one pattern and format
|
||
|
|
# to be used to format the number.
|
||
|
|
#
|
||
|
|
# In the case when only one formatting pattern exists, no
|
||
|
|
# leading_digits_pattern is needed.
|
||
|
|
self.leading_digits_pattern = [] # list of Unicode strings holding regexps
|
||
|
|
if leading_digits_pattern is not None:
|
||
|
|
self.leading_digits_pattern = [force_unicode(p) for p in leading_digits_pattern]
|
||
|
|
|
||
|
|
# This field specifies how the national prefix ($NP) together with the
|
||
|
|
# first group ($FG) in the national significant number should be
|
||
|
|
# formatted in the NATIONAL format when a national prefix exists for a
|
||
|
|
# certain country. For example, when this field contains "($NP$FG)", a
|
||
|
|
# number from Beijing, China (whose $NP = 0), which would by default
|
||
|
|
# be formatted without national prefix as 10 1234 5678 in NATIONAL
|
||
|
|
# format, will instead be formatted as (010) 1234 5678; to format it
|
||
|
|
# as (0)10 1234 5678, the field would contain "($NP)$FG". Note $FG
|
||
|
|
# should always be present in this field, but $NP can be omitted. For
|
||
|
|
# example, having "$FG" could indicate the number should be formatted
|
||
|
|
# in NATIONAL format without the national prefix. This is commonly
|
||
|
|
# used to override the rule specified for the territory in the XML
|
||
|
|
# file.
|
||
|
|
#
|
||
|
|
# When this field is missing, a number will be formatted without
|
||
|
|
# national prefix in NATIONAL format. This field does not affect how a
|
||
|
|
# number is formatted in other formats, such as INTERNATIONAL.
|
||
|
|
self.national_prefix_formatting_rule = force_unicode(national_prefix_formatting_rule) # None or Unicode string
|
||
|
|
|
||
|
|
# This field specifies whether the $NP can be omitted when formatting
|
||
|
|
# a number in national format, even though it usually wouldn't be. For
|
||
|
|
# example, a UK number would be formatted by our library as 020 XXXX
|
||
|
|
# XXXX. If we have commonly seen this number written by people without
|
||
|
|
# the leading 0, for example as (20) XXXX XXXX, this field would be
|
||
|
|
# set to true. This will be inherited from the value set for the
|
||
|
|
# territory in the XML file, unless a national_prefix_formatting_rule
|
||
|
|
# is defined specifically for this NumberFormat.
|
||
|
|
if national_prefix_optional_when_formatting is not None:
|
||
|
|
self.national_prefix_optional_when_formatting = bool(national_prefix_optional_when_formatting)
|
||
|
|
else:
|
||
|
|
self.national_prefix_optional_when_formatting = None
|
||
|
|
|
||
|
|
# This field specifies how any carrier code ($CC) together with the
|
||
|
|
# first group ($FG) in the national significant number should be
|
||
|
|
# formatted when format_with_carrier_code is called, if carrier codes
|
||
|
|
# are used for a certain country.
|
||
|
|
self.domestic_carrier_code_formatting_rule = force_unicode(domestic_carrier_code_formatting_rule) # None or Unicode string
|
||
|
|
|
||
|
|
def merge_from(self, other):
|
||
|
|
"""Merge information from another NumberFormat object into this one."""
|
||
|
|
if other.pattern is not None:
|
||
|
|
self.pattern = other.pattern
|
||
|
|
if other.format is not None:
|
||
|
|
self.format = other.format
|
||
|
|
self.leading_digits_pattern.extend(other.leading_digits_pattern)
|
||
|
|
if other.national_prefix_formatting_rule is not None:
|
||
|
|
self.national_prefix_formatting_rule = other.national_prefix_formatting_rule
|
||
|
|
if other.national_prefix_optional_when_formatting is not None:
|
||
|
|
self.national_prefix_optional_when_formatting = other.national_prefix_optional_when_formatting
|
||
|
|
if other.domestic_carrier_code_formatting_rule is not None:
|
||
|
|
self.domestic_carrier_code_formatting_rule = other.domestic_carrier_code_formatting_rule
|
||
|
|
|
||
|
|
def __eq__(self, other):
|
||
|
|
if not isinstance(other, NumberFormat):
|
||
|
|
return False
|
||
|
|
return (repr(self) == repr(other))
|
||
|
|
|
||
|
|
def __ne__(self, other):
|
||
|
|
return not self.__eq__(other)
|
||
|
|
|
||
|
|
def __repr__(self):
|
||
|
|
return str(self)
|
||
|
|
|
||
|
|
def __unicode__(self):
|
||
|
|
# Generate a string that is valid Python input for the constructor.
|
||
|
|
# Note that we use rpr (variant of repr), which generates its own quotes.
|
||
|
|
result = unicod("NumberFormat(pattern=%s, format=%s") % (rpr(self.pattern), rpr(self.format))
|
||
|
|
if self.leading_digits_pattern:
|
||
|
|
result += (unicod(", leading_digits_pattern=[%s]") %
|
||
|
|
unicod(", ").join([rpr(ld) for ld in self.leading_digits_pattern]))
|
||
|
|
if self.national_prefix_formatting_rule is not None:
|
||
|
|
result += unicod(", national_prefix_formatting_rule=%s") % rpr(self.national_prefix_formatting_rule)
|
||
|
|
if self.national_prefix_optional_when_formatting is not None:
|
||
|
|
result += unicod(", national_prefix_optional_when_formatting=%s") % str(self.national_prefix_optional_when_formatting)
|
||
|
|
if self.domestic_carrier_code_formatting_rule is not None:
|
||
|
|
result += unicod(", domestic_carrier_code_formatting_rule=%s") % rpr(self.domestic_carrier_code_formatting_rule)
|
||
|
|
result += unicod(")")
|
||
|
|
return result
|
||
|
|
|
||
|
|
|
||
|
|
class PhoneNumberDesc(UnicodeMixin, ImmutableMixin):
|
||
|
|
"""Class representing the description of a set of phone numbers."""
|
||
|
|
@mutating_method
|
||
|
|
def __init__(self,
|
||
|
|
national_number_pattern=None,
|
||
|
|
example_number=None,
|
||
|
|
possible_length=None,
|
||
|
|
possible_length_local_only=None):
|
||
|
|
# The national_number_pattern is the pattern that a valid national
|
||
|
|
# significant number would match. This specifies information such as
|
||
|
|
# its total length and leading digits.
|
||
|
|
self.national_number_pattern = force_unicode(national_number_pattern) # None or Unicode string holding regexp
|
||
|
|
|
||
|
|
# An example national significant number for the specific type. It
|
||
|
|
# should not contain any formatting information.
|
||
|
|
self.example_number = force_unicode(example_number) # None or Unicode string
|
||
|
|
|
||
|
|
# These represent the lengths a phone number from this region can be. They
|
||
|
|
# will be sorted from smallest to biggest. Note that these lengths are for
|
||
|
|
# the full number, without country calling code or national prefix. For
|
||
|
|
# example, for the Swiss number +41789270000, in local format 0789270000,
|
||
|
|
# this would be 9.
|
||
|
|
# This could be used to highlight tokens in a text that may be a phone
|
||
|
|
# number, or to quickly prune numbers that could not possibly be a phone
|
||
|
|
# number for this locale.
|
||
|
|
if possible_length is None:
|
||
|
|
possible_length = ()
|
||
|
|
self.possible_length = possible_length # sequence of int
|
||
|
|
|
||
|
|
# These represent the lengths that only local phone numbers (without an area
|
||
|
|
# code) from this region can be. They will be sorted from smallest to
|
||
|
|
# biggest. For example, since the American number 456-1234 may be locally
|
||
|
|
# diallable, although not diallable from outside the area, 7 could be a
|
||
|
|
# possible value.
|
||
|
|
# This could be used to highlight tokens in a text that may be a phone
|
||
|
|
# number.
|
||
|
|
# To our knowledge, area codes are usually only relevant for some fixed-line
|
||
|
|
# and mobile numbers, so this field should only be set for those types of
|
||
|
|
# numbers (and the general description) - however there are exceptions for
|
||
|
|
# NANPA countries.
|
||
|
|
if possible_length_local_only is None:
|
||
|
|
possible_length_local_only = ()
|
||
|
|
self.possible_length_local_only = possible_length_local_only # sequence of int
|
||
|
|
|
||
|
|
def merge_from(self, other):
|
||
|
|
"""Merge information from another PhoneNumberDesc object into this one."""
|
||
|
|
if other.national_number_pattern is not None:
|
||
|
|
self.national_number_pattern = other.national_number_pattern
|
||
|
|
if other.example_number is not None:
|
||
|
|
self.example_number = other.example_number
|
||
|
|
|
||
|
|
def __eq__(self, other):
|
||
|
|
if not isinstance(other, PhoneNumberDesc):
|
||
|
|
return False
|
||
|
|
return (repr(self) == repr(other))
|
||
|
|
|
||
|
|
def __ne__(self, other):
|
||
|
|
return not self.__eq__(other)
|
||
|
|
|
||
|
|
def __repr__(self):
|
||
|
|
return str(self)
|
||
|
|
|
||
|
|
def __unicode__(self):
|
||
|
|
# Generate a string that is valid Python input for constructor
|
||
|
|
result = unicod("PhoneNumberDesc(")
|
||
|
|
sep = unicod("")
|
||
|
|
if self.national_number_pattern is not None:
|
||
|
|
result += unicod("%snational_number_pattern=%s") % (sep, rpr(self.national_number_pattern))
|
||
|
|
sep = unicod(", ")
|
||
|
|
if self.example_number is not None:
|
||
|
|
result += unicod("%sexample_number=%s") % (sep, rpr(self.example_number))
|
||
|
|
sep = unicod(", ")
|
||
|
|
if self.possible_length:
|
||
|
|
result += unicod("%spossible_length=%s") % (sep, tuple(self.possible_length))
|
||
|
|
sep = unicod(", ")
|
||
|
|
if self.possible_length_local_only:
|
||
|
|
result += unicod("%spossible_length_local_only=%s") % (sep, tuple(self.possible_length_local_only))
|
||
|
|
sep = unicod(", ")
|
||
|
|
result += unicod(")")
|
||
|
|
return result
|
||
|
|
|
||
|
|
|
||
|
|
def _same_pattern(left, right):
|
||
|
|
if left is None and right is None:
|
||
|
|
return True
|
||
|
|
if left is None or right is None:
|
||
|
|
return False
|
||
|
|
return (left.national_number_pattern == right.national_number_pattern)
|
||
|
|
|
||
|
|
|
||
|
|
class PhoneMetadata(UnicodeMixin, ImmutableMixin):
|
||
|
|
"""Class representing metadata for international telephone numbers for a region.
|
||
|
|
|
||
|
|
This class is hand created based on phonemetadata.proto. Please refer to that file
|
||
|
|
for detailed descriptions of the meaning of each field.
|
||
|
|
|
||
|
|
WARNING: This API isn't stable. It is considered libphonenumber-internal
|
||
|
|
and can change at any time. We only declare it as public for easy
|
||
|
|
inclusion in our build tools not in this package. Clients should not
|
||
|
|
refer to this file, we do not commit to support backwards-compatibility or
|
||
|
|
to warn about breaking changes.
|
||
|
|
|
||
|
|
"""
|
||
|
|
# Lock that protects the *_available fields while they are being modified.
|
||
|
|
# The modification involves loading data from a file, so we cannot just
|
||
|
|
# rely on the GIL.
|
||
|
|
_metadata_lock = threading.Lock()
|
||
|
|
# If a region code is a key in this dict, metadata for that region is available.
|
||
|
|
# The corresponding value of the map is either:
|
||
|
|
# - a function which loads the region's metadata
|
||
|
|
# - None, to indicate that the metadata is already loaded
|
||
|
|
_region_available = {} # ISO 3166-1 alpha 2 => function or None
|
||
|
|
# Likewise for short number metadata.
|
||
|
|
_short_region_available = {} # ISO 3166-1 alpha 2 => function or None
|
||
|
|
# Likewise for non-geo country calling codes.
|
||
|
|
_country_code_available = {} # country calling code (as int) => function or None
|
||
|
|
|
||
|
|
_region_metadata = {} # ISO 3166-1 alpha 2 => PhoneMetadata
|
||
|
|
_short_region_metadata = {} # ISO 3166-1 alpha 2 => PhoneMetadata
|
||
|
|
# A mapping from a country calling code for a non-geographical entity to
|
||
|
|
# the PhoneMetadata for that country calling code. Examples of the country
|
||
|
|
# calling codes include 800 (International Toll Free Service) and 808
|
||
|
|
# (International Shared Cost Service).
|
||
|
|
_country_code_metadata = {} # country calling code (as int) => PhoneMetadata
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def metadata_for_region(kls, region_code, default=None):
|
||
|
|
loader = kls._region_available.get(region_code, None)
|
||
|
|
if loader is not None:
|
||
|
|
# Region metadata is available but has not yet been loaded. Do so now.
|
||
|
|
kls._metadata_lock.acquire()
|
||
|
|
loader(region_code)
|
||
|
|
kls._region_available[region_code] = None
|
||
|
|
kls._metadata_lock.release()
|
||
|
|
return kls._region_metadata.get(region_code, default)
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def short_metadata_for_region(kls, region_code, default=None):
|
||
|
|
loader = kls._short_region_available.get(region_code, None)
|
||
|
|
if loader is not None:
|
||
|
|
# Region short number metadata is available but has not yet been loaded. Do so now.
|
||
|
|
kls._metadata_lock.acquire()
|
||
|
|
loader(region_code)
|
||
|
|
kls._short_region_available[region_code] = None
|
||
|
|
kls._metadata_lock.release()
|
||
|
|
return kls._short_region_metadata.get(region_code, default)
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def metadata_for_nongeo_region(kls, country_code, default=None):
|
||
|
|
loader = kls._country_code_available.get(country_code, None)
|
||
|
|
if loader is not None:
|
||
|
|
# Region metadata is available but has not yet been loaded. Do so now.
|
||
|
|
kls._metadata_lock.acquire()
|
||
|
|
loader(country_code)
|
||
|
|
kls._country_code_available[country_code] = None
|
||
|
|
kls._metadata_lock.release()
|
||
|
|
return kls._country_code_metadata.get(country_code, default)
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def metadata_for_region_or_calling_code(kls, country_calling_code, region_code):
|
||
|
|
if region_code == REGION_CODE_FOR_NON_GEO_ENTITY:
|
||
|
|
return kls.metadata_for_nongeo_region(country_calling_code, None)
|
||
|
|
else:
|
||
|
|
return kls.metadata_for_region(region_code, None)
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def register_region_loader(kls, region_code, loader):
|
||
|
|
kls._region_available[region_code] = loader
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def register_short_region_loader(kls, region_code, loader):
|
||
|
|
kls._short_region_available[region_code] = loader
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def register_nongeo_region_loader(kls, country_code, loader):
|
||
|
|
kls._country_code_available[country_code] = loader
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def load_all(kls):
|
||
|
|
"""Force immediate load of all metadata"""
|
||
|
|
# Force expansion of contents to lists because we invalidate the iterator
|
||
|
|
for region_code, region_loader in list(kls._region_available.items()):
|
||
|
|
if region_loader is not None: # pragma no cover
|
||
|
|
region_loader(region_code)
|
||
|
|
kls._region_available[region_code] = None
|
||
|
|
for country_code, cc_loader in list(kls._country_code_available.items()):
|
||
|
|
if cc_loader is not None:
|
||
|
|
cc_loader(country_code)
|
||
|
|
kls._country_code_available[country_code] = None
|
||
|
|
|
||
|
|
@mutating_method
|
||
|
|
def __init__(self,
|
||
|
|
id,
|
||
|
|
general_desc=None,
|
||
|
|
fixed_line=None,
|
||
|
|
mobile=None,
|
||
|
|
toll_free=None,
|
||
|
|
premium_rate=None,
|
||
|
|
shared_cost=None,
|
||
|
|
personal_number=None,
|
||
|
|
voip=None,
|
||
|
|
pager=None,
|
||
|
|
uan=None,
|
||
|
|
emergency=None,
|
||
|
|
voicemail=None,
|
||
|
|
short_code=None,
|
||
|
|
standard_rate=None,
|
||
|
|
carrier_specific=None,
|
||
|
|
sms_services=None,
|
||
|
|
no_international_dialling=None,
|
||
|
|
country_code=None,
|
||
|
|
international_prefix=None,
|
||
|
|
preferred_international_prefix=None,
|
||
|
|
national_prefix=None,
|
||
|
|
preferred_extn_prefix=None,
|
||
|
|
national_prefix_for_parsing=None,
|
||
|
|
national_prefix_transform_rule=None,
|
||
|
|
number_format=None,
|
||
|
|
intl_number_format=None,
|
||
|
|
main_country_for_code=False,
|
||
|
|
leading_digits=None,
|
||
|
|
leading_zero_possible=False,
|
||
|
|
mobile_number_portable_region=False,
|
||
|
|
short_data=False,
|
||
|
|
register=True):
|
||
|
|
# The general_desc contains information which is a superset of
|
||
|
|
# descriptions for all types of phone numbers. If any element is
|
||
|
|
# missing in the description of a specific type of number, the element
|
||
|
|
# will inherit from its counterpart in the general_desc. For all types
|
||
|
|
# that are generally relevant to normal phone numbers, if the whole
|
||
|
|
# type is missing in the PhoneNumberMetadata XML file, it will not have
|
||
|
|
# national number data, and the possible lengths will be [-1].
|
||
|
|
self.general_desc = general_desc # None or PhoneNumberDesc
|
||
|
|
self.fixed_line = fixed_line # None or PhoneNumberDesc
|
||
|
|
self.mobile = mobile # None or PhoneNumberDesc
|
||
|
|
self.toll_free = toll_free # None or PhoneNumberDesc
|
||
|
|
self.premium_rate = premium_rate # None or PhoneNumberDesc
|
||
|
|
self.shared_cost = shared_cost # None or PhoneNumberDesc
|
||
|
|
self.personal_number = personal_number # None or PhoneNumberDesc
|
||
|
|
self.voip = voip # None or PhoneNumberDesc
|
||
|
|
self.pager = pager # None or PhoneNumberDesc
|
||
|
|
self.uan = uan # None or PhoneNumberDesc
|
||
|
|
self.emergency = emergency # None or PhoneNumberDesc
|
||
|
|
self.voicemail = voicemail # None or PhoneNumberDesc
|
||
|
|
self.short_code = short_code # None or PhoneNumberDesc
|
||
|
|
self.standard_rate = standard_rate # None or PhoneNumberDesc
|
||
|
|
self.carrier_specific = carrier_specific # None or PhoneNumberDesc
|
||
|
|
self.sms_services = sms_services # None or PhoneNumberDesc
|
||
|
|
|
||
|
|
# The rules here distinguish the numbers that are only able to be
|
||
|
|
# dialled nationally.
|
||
|
|
self.no_international_dialling = no_international_dialling # None or PhoneNumberDesc
|
||
|
|
|
||
|
|
# The ISO 3166-1 alpha-2 representation of a country/region, with the
|
||
|
|
# exception of "country calling codes" used for non-geographical
|
||
|
|
# entities, such as Universal International Toll Free Number
|
||
|
|
# (+800). These are all given the ID "001", since this is the numeric
|
||
|
|
# region code for the world according to UN M.49:
|
||
|
|
# http://en.wikipedia.org/wiki/UN_M.49
|
||
|
|
self.id = force_unicode(id) # None or Unicode string
|
||
|
|
|
||
|
|
# The country calling code that one would dial from overseas when
|
||
|
|
# trying to dial a phone number in this country. For example, this
|
||
|
|
# would be "64" for New Zealand.
|
||
|
|
self.country_code = country_code # None or int
|
||
|
|
|
||
|
|
# The international_prefix of country A is the number that needs to be
|
||
|
|
# dialled from country A to another country (country B). This is
|
||
|
|
# followed by the country code for country B. Note that some countries
|
||
|
|
# may have more than one international prefix, and for those cases, a
|
||
|
|
# regular expression matching the international prefixes will be
|
||
|
|
# stored in this field.
|
||
|
|
self.international_prefix = force_unicode(international_prefix) # None or Unicode string
|
||
|
|
|
||
|
|
# If more than one international prefix is present, a preferred prefix
|
||
|
|
# can be specified here for out-of-country formatting purposes. If
|
||
|
|
# this field is not present, and multiple international prefixes are
|
||
|
|
# present, then "+" will be used instead.
|
||
|
|
self.preferred_international_prefix = force_unicode(preferred_international_prefix) # None or Unicode string
|
||
|
|
|
||
|
|
# The national prefix of country A is the number that needs to be
|
||
|
|
# dialled before the national significant number when dialling
|
||
|
|
# internally. This would not be dialled when dialling
|
||
|
|
# internationally. For example, in New Zealand, the number that would
|
||
|
|
# be locally dialled as 09 345 3456 would be dialled from overseas as
|
||
|
|
# +64 9 345 3456. In this case, 0 is the national prefix.
|
||
|
|
self.national_prefix = force_unicode(national_prefix) # None or Unicode string
|
||
|
|
|
||
|
|
# The preferred prefix when specifying an extension in this
|
||
|
|
# country. This is used for formatting only, and if this is not
|
||
|
|
# specified, a suitable default should be used instead. For example,
|
||
|
|
# if you wanted extensions to be formatted in the following way: 1
|
||
|
|
# (365) 345 445 ext. 2345 " ext. " should be the preferred extension
|
||
|
|
# prefix.
|
||
|
|
self.preferred_extn_prefix = force_unicode(preferred_extn_prefix) # None or Unicode string
|
||
|
|
|
||
|
|
# This field is used for cases where the national prefix of a country
|
||
|
|
# contains a carrier selection code, and is written in the form of a
|
||
|
|
# regular expression. For example, to dial the number 2222-2222 in
|
||
|
|
# Fortaleza, Brazil (area code 85) using the long distance carrier Oi
|
||
|
|
# (selection code 31), one would dial 0 31 85 2222 2222. Assuming the
|
||
|
|
# only other possible carrier selection code is 32, the field will
|
||
|
|
# contain "03[12]".
|
||
|
|
#
|
||
|
|
# When it is missing, this field inherits the value of national_prefix,
|
||
|
|
# if that is present.
|
||
|
|
self.national_prefix_for_parsing = force_unicode(national_prefix_for_parsing) # None or Unicode string holding regexp
|
||
|
|
|
||
|
|
# This field is only populated and used under very rare situations.
|
||
|
|
# For example, mobile numbers in Argentina are written in two
|
||
|
|
# completely different ways when dialed in-country and out-of-country
|
||
|
|
# (e.g. 0343 15 555 1212 is exactly the same number as +54 9 343 555
|
||
|
|
# 1212). This field is used together with national_prefix_for_parsing
|
||
|
|
# to transform the number into a particular representation for storing
|
||
|
|
# in the PhoneNumber class in those rare cases.
|
||
|
|
self.national_prefix_transform_rule = force_unicode(national_prefix_transform_rule) # None or Unicode string
|
||
|
|
|
||
|
|
# Specifies whether the mobile and fixed-line patterns are the same or
|
||
|
|
# not. This is used to speed up determining phone number type in
|
||
|
|
# countries where these two types of phone numbers can never be
|
||
|
|
# distinguished.
|
||
|
|
self.same_mobile_and_fixed_line_pattern = _same_pattern(self.mobile, self.fixed_line)
|
||
|
|
|
||
|
|
# Note that the number format here is used for formatting only, not
|
||
|
|
# parsing. Hence all the varied ways a user *may* write a number need
|
||
|
|
# not be recorded - just the ideal way we would like to format it for
|
||
|
|
# them. When this element is absent, the national significant number
|
||
|
|
# will be formatted as a whole without any formatting applied.
|
||
|
|
self.number_format = [] # List of NumberFormat objects
|
||
|
|
if number_format is not None:
|
||
|
|
self.number_format = number_format
|
||
|
|
|
||
|
|
# This field is populated only when the national significant number is
|
||
|
|
# formatted differently when it forms part of the INTERNATIONAL format
|
||
|
|
# and NATIONAL format. A case in point is mobile numbers in Argentina:
|
||
|
|
# The number, which would be written in INTERNATIONAL format as
|
||
|
|
# +54 9 343 555 1212, will be written as 0343 15 555 1212 for NATIONAL
|
||
|
|
# format. In this case, the prefix 9 is inserted when dialling from
|
||
|
|
# overseas, but otherwise the prefix 0 and the carrier selection code
|
||
|
|
# 15 (inserted after the area code of 343) is used.
|
||
|
|
# Note: this field is populated by setting a value for <intlFormat>
|
||
|
|
# inside the <numberFormat> tag in the XML file. If <intlFormat> is
|
||
|
|
# not set then it defaults to the same value as the <format> tag.
|
||
|
|
#
|
||
|
|
# Examples:
|
||
|
|
# To set the <intlFormat> to a different value than the <format>:
|
||
|
|
# <numberFormat pattern=....>
|
||
|
|
# <format>$1 $2 $3</format>
|
||
|
|
# <intlFormat>$1-$2-$3</intlFormat>
|
||
|
|
# </numberFormat>
|
||
|
|
#
|
||
|
|
# To have a format only used for national formatting, set <intlFormat> to
|
||
|
|
# "NA":
|
||
|
|
# <numberFormat pattern=....>
|
||
|
|
# <format>$1 $2 $3</format>
|
||
|
|
# <intlFormat>NA</intlFormat>
|
||
|
|
# </numberFormat>
|
||
|
|
self.intl_number_format = [] # List of NumberFormat objects
|
||
|
|
if intl_number_format is not None:
|
||
|
|
self.intl_number_format = intl_number_format
|
||
|
|
|
||
|
|
# This field is set when this country is considered to be the main
|
||
|
|
# country for a calling code. It may not be set by more than one
|
||
|
|
# country with the same calling code, and it should not be set by
|
||
|
|
# countries with a unique calling code. This can be used to indicate
|
||
|
|
# that "GB" is the main country for the calling code "44" for example,
|
||
|
|
# rather than Jersey or the Isle of Man.
|
||
|
|
self.main_country_for_code = bool(main_country_for_code)
|
||
|
|
|
||
|
|
# This field is populated only for countries or regions that share a
|
||
|
|
# country calling code. If a number matches this pattern, it could
|
||
|
|
# belong to this region. This is not intended as a replacement for
|
||
|
|
# is_valid_for_region, and does not mean the number must come from this
|
||
|
|
# region (for example, 800 numbers are valid for all NANPA countries.)
|
||
|
|
# This field should be a regular expression of the expected prefix
|
||
|
|
# match.
|
||
|
|
self.leading_digits = force_unicode(leading_digits) # None or Unicode string holding regexp
|
||
|
|
|
||
|
|
# Deprecated: do not use. Will be deleted when there are no references
|
||
|
|
# to this later.
|
||
|
|
self.leading_zero_possible = bool(leading_zero_possible)
|
||
|
|
|
||
|
|
# This field is set when this country has implemented mobile number
|
||
|
|
# portability. This means that transferring mobile numbers between
|
||
|
|
# carriers is allowed. A consequence of this is that phone prefix to
|
||
|
|
# carrier mapping is less reliable.
|
||
|
|
self.mobile_number_portable_region = mobile_number_portable_region # bool
|
||
|
|
|
||
|
|
# Record whether this metadata is for short numbers or normal numbers.
|
||
|
|
self.short_data = short_data # bool
|
||
|
|
|
||
|
|
if register:
|
||
|
|
# Register this instance with the relevant class-wide map
|
||
|
|
if self.id == REGION_CODE_FOR_NON_GEO_ENTITY:
|
||
|
|
if self.country_code in PhoneMetadata._country_code_metadata:
|
||
|
|
other = PhoneMetadata._country_code_metadata[self.country_code]
|
||
|
|
if self != other:
|
||
|
|
raise Exception("Duplicate non-geo PhoneMetadata for %s (from %s:%s)" % (self.country_code, self.id, self.country_code))
|
||
|
|
else:
|
||
|
|
PhoneMetadata._country_code_metadata[self.country_code] = self
|
||
|
|
elif self.short_data:
|
||
|
|
if self.id in PhoneMetadata._short_region_metadata:
|
||
|
|
other = PhoneMetadata._short_region_metadata[self.id]
|
||
|
|
if self != other:
|
||
|
|
raise Exception("Duplicate short PhoneMetadata for %s (from %s:%s)" % (self.id, self.id, self.country_code))
|
||
|
|
else:
|
||
|
|
PhoneMetadata._short_region_metadata[self.id] = self
|
||
|
|
else:
|
||
|
|
if self.id in PhoneMetadata._region_metadata:
|
||
|
|
other = PhoneMetadata._region_metadata[self.id]
|
||
|
|
if self != other:
|
||
|
|
raise Exception("Duplicate PhoneMetadata for %s (from %s:%s)" % (self.id, self.id, self.country_code))
|
||
|
|
else:
|
||
|
|
PhoneMetadata._region_metadata[self.id] = self
|
||
|
|
|
||
|
|
def __eq__(self, other):
|
||
|
|
if not isinstance(other, PhoneMetadata):
|
||
|
|
return False
|
||
|
|
return (repr(self) == repr(other))
|
||
|
|
|
||
|
|
def __ne__(self, other):
|
||
|
|
return not self.__eq__(other)
|
||
|
|
|
||
|
|
def __repr__(self):
|
||
|
|
return str(self)
|
||
|
|
|
||
|
|
def __unicode__(self):
|
||
|
|
# Generate a string that is valid Python input for the constructor
|
||
|
|
result = (unicod("PhoneMetadata(id='%s', country_code=%r, international_prefix=%s") %
|
||
|
|
(self.id, self.country_code, rpr(self.international_prefix)))
|
||
|
|
result += unicod(",\n general_desc=%s") % self.general_desc
|
||
|
|
if self.fixed_line is not None:
|
||
|
|
result += unicod(",\n fixed_line=%s") % self.fixed_line
|
||
|
|
if self.mobile is not None:
|
||
|
|
result += unicod(",\n mobile=%s") % self.mobile
|
||
|
|
if self.toll_free is not None:
|
||
|
|
result += unicod(",\n toll_free=%s") % self.toll_free
|
||
|
|
if self.premium_rate is not None:
|
||
|
|
result += unicod(",\n premium_rate=%s") % self.premium_rate
|
||
|
|
if self.shared_cost is not None:
|
||
|
|
result += unicod(",\n shared_cost=%s") % self.shared_cost
|
||
|
|
if self.personal_number is not None:
|
||
|
|
result += unicod(",\n personal_number=%s") % self.personal_number
|
||
|
|
if self.voip is not None:
|
||
|
|
result += unicod(",\n voip=%s") % self.voip
|
||
|
|
if self.pager is not None:
|
||
|
|
result += unicod(",\n pager=%s") % self.pager
|
||
|
|
if self.uan is not None:
|
||
|
|
result += unicod(",\n uan=%s") % self.uan
|
||
|
|
if self.emergency is not None:
|
||
|
|
result += unicod(",\n emergency=%s") % self.emergency
|
||
|
|
if self.voicemail is not None:
|
||
|
|
result += unicod(",\n voicemail=%s") % self.voicemail
|
||
|
|
if self.short_code is not None:
|
||
|
|
result += unicod(",\n short_code=%s") % self.short_code
|
||
|
|
if self.standard_rate is not None:
|
||
|
|
result += unicod(",\n standard_rate=%s") % self.standard_rate
|
||
|
|
if self.carrier_specific is not None:
|
||
|
|
result += unicod(",\n carrier_specific=%s") % self.carrier_specific
|
||
|
|
if self.sms_services is not None:
|
||
|
|
result += unicod(",\n sms_services=%s") % self.sms_services
|
||
|
|
if self.no_international_dialling is not None:
|
||
|
|
result += unicod(",\n no_international_dialling=%s") % self.no_international_dialling
|
||
|
|
|
||
|
|
if self.preferred_international_prefix is not None:
|
||
|
|
result += unicod(",\n preferred_international_prefix=%s") % rpr(self.preferred_international_prefix)
|
||
|
|
if self.national_prefix is not None:
|
||
|
|
result += unicod(",\n national_prefix=%s") % rpr(self.national_prefix)
|
||
|
|
if self.preferred_extn_prefix is not None:
|
||
|
|
result += unicod(",\n preferred_extn_prefix=%s") % rpr(self.preferred_extn_prefix)
|
||
|
|
if self.national_prefix_for_parsing is not None:
|
||
|
|
result += unicod(",\n national_prefix_for_parsing=%s") % rpr(self.national_prefix_for_parsing)
|
||
|
|
if self.national_prefix_transform_rule is not None:
|
||
|
|
# Note that we use rpr() on self.national_prefix_transform_rule, which generates its own quotes
|
||
|
|
result += unicod(",\n national_prefix_transform_rule=%s") % rpr(self.national_prefix_transform_rule)
|
||
|
|
if self.number_format:
|
||
|
|
result += unicod(",\n number_format=[%s]") % unicod(',\n ').join(map(u, self.number_format))
|
||
|
|
if self.intl_number_format:
|
||
|
|
result += unicod(",\n intl_number_format=[%s]") % unicod(',\n ').join(map(u, self.intl_number_format))
|
||
|
|
if self.main_country_for_code:
|
||
|
|
result += unicod(",\n main_country_for_code=True")
|
||
|
|
if self.leading_digits is not None:
|
||
|
|
result += unicod(",\n leading_digits='%s'") % self.leading_digits
|
||
|
|
if self.leading_zero_possible:
|
||
|
|
result += unicod(",\n leading_zero_possible=True")
|
||
|
|
if self.mobile_number_portable_region:
|
||
|
|
result += unicod(",\n mobile_number_portable_region=True")
|
||
|
|
if self.short_data:
|
||
|
|
result += unicod(",\n short_data=True")
|
||
|
|
result += unicod(")")
|
||
|
|
return result
|