Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/phonenumbers/phonenumber.py: 38%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

94 statements  

1"""PhoneNumber object definition""" 

2 

3# Based on original Java code and protocol buffer: 

4# resources/phonenumber.proto 

5# java/src/com/google/i18n/phonenumbers/Phonenumber.java 

6# Copyright (C) 2010-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. 

19from .util import UnicodeMixin, ImmutableMixin, mutating_method 

20from .util import to_long, unicod, rpr, force_unicode, u 

21 

22 

23class CountryCodeSource(object): 

24 """The source from which a country code is derived.""" 

25 # Default value returned if this is not set, because the phone number was 

26 # created using parse(keep_raw_input=False). 

27 UNSPECIFIED = 0 

28 

29 # The country_code is derived based on a phone number with a leading "+", 

30 # e.g. the French number "+33 1 42 68 53 00". 

31 FROM_NUMBER_WITH_PLUS_SIGN = 1 

32 

33 # The country_code is derived based on a phone number with a leading IDD, 

34 # e.g. the French number "011 33 1 42 68 53 00", as it is dialled 

35 # from US. 

36 FROM_NUMBER_WITH_IDD = 5 

37 

38 # The country_code is derived based on a phone number without a leading 

39 # "+", e.g. the French number "33 1 42 68 53 00" when default_country is 

40 # supplied as France. 

41 FROM_NUMBER_WITHOUT_PLUS_SIGN = 10 

42 

43 # The country_code is derived NOT based on the phone number itself, but 

44 # from the default_country parameter provided in the parsing function by 

45 # the clients. This happens mostly for numbers written in the national 

46 # format (without country code). For example, this would be set when 

47 # parsing the French number "01 42 68 53 00", when default_country is 

48 # supplied as France. 

49 FROM_DEFAULT_COUNTRY = 20 

50 

51 @classmethod 

52 def to_string(cls, val): 

53 """Return a string representation of a CountryCodeSource value""" 

54 if val == CountryCodeSource.UNSPECIFIED: 

55 return u("UNSPECIFIED") 

56 elif val == CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN: 

57 return u("FROM_NUMBER_WITH_PLUS_SIGN") 

58 elif val == CountryCodeSource.FROM_NUMBER_WITH_IDD: 

59 return u("FROM_NUMBER_WITH_IDD") 

60 elif val == CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN: 

61 return u("FROM_NUMBER_WITHOUT_PLUS_SIGN") 

62 elif val == CountryCodeSource.FROM_DEFAULT_COUNTRY: 

63 return u("FROM_DEFAULT_COUNTRY") 

64 else: 

65 return u("INVALID (%d)" % val) 

66 

67 

68class PhoneNumber(UnicodeMixin): 

69 """Class representing international telephone numbers. 

70 

71 This class is hand-created based on phonenumber.proto. Please refer 

72 to that file for detailed descriptions of the meaning of each field. 

73 """ 

74 

75 def __init__(self, 

76 country_code=None, 

77 national_number=None, 

78 extension=None, 

79 italian_leading_zero=None, 

80 number_of_leading_zeros=None, 

81 raw_input=None, 

82 country_code_source=CountryCodeSource.UNSPECIFIED, 

83 preferred_domestic_carrier_code=None): 

84 # The country calling code for this number, as defined by the 

85 # International Telecommunication Union (ITU). For example, this would 

86 # be 1 for NANPA countries, and 33 for France. 

87 # 

88 # None if not set, of type int otherwise. 

89 if country_code is None: 

90 self.country_code = None 

91 else: 

92 self.country_code = int(country_code) 

93 

94 # Number does not contain National(trunk) prefix. 

95 # National (significant) Number is defined in International 

96 # Telecommunication Union (ITU) Recommendation E.164. It is a 

97 # language/country-neutral representation of a phone number at a 

98 # country level. For countries which have the concept of an "area 

99 # code" or "national destination code", this is included in the 

100 # National (significant) Number. Although the ITU says the maximum 

101 # length should be 15, we have found longer numbers in some countries 

102 # e.g. Germany. Note that the National (significant) Number does not 

103 # contain the National(trunk) prefix. 

104 # 

105 # None if not set, of type long otherwise (and so it will never 

106 # contain any formatting (hypens, spaces, parentheses), nor any 

107 # alphanumeric spellings). 

108 

109 if national_number is None: 

110 self.national_number = None 

111 else: 

112 self.national_number = to_long(national_number) 

113 

114 # Extension is not standardized in ITU recommendations, except for 

115 # being defined as a series of numbers with a maximum length of 40 

116 # digits. 

117 # 

118 # When present, it is a Unicode string to accommodate for the 

119 # possible use of a leading zero in the extension (organizations 

120 # have complete freedom to do so, as there is no standard defined). 

121 # However, only ASCII digits should be stored here. 

122 self.extension = force_unicode(extension) # None or Unicode '[0-9]+' 

123 

124 # In some countries, the national (significant) number starts with one 

125 # or more "0"s without this being a national prefix or trunk code of 

126 # some kind. For example, the leading zero in the national 

127 # (significant) number of an Italian phone number indicates the number 

128 # is a fixed-line number. There have been plans to migrate fixed-line 

129 # numbers to start with the digit two since December 2000, but it has 

130 # not happened yet. See http://en.wikipedia.org/wiki/%2B39 for more 

131 # details. 

132 # 

133 # These fields can be safely ignored (there is no need to set them) 

134 # for most countries. Some limited number of countries behave like 

135 # Italy - for these cases, if the leading zero(s) of a number would be 

136 # retained even when dialling internationally, set this flag to true, 

137 # and also set the number of leading zeros. 

138 # 

139 # Clients who use the parsing functionality of the i18n phone number 

140 # libraries will have these fields set if necessary automatically. 

141 # 

142 # None if not set, of type bool otherwise: 

143 if italian_leading_zero is None: 

144 self.italian_leading_zero = None 

145 else: 

146 self.italian_leading_zero = bool(italian_leading_zero) 

147 

148 # None if not set, of type int otherwise. 

149 if number_of_leading_zeros is None: 

150 self.number_of_leading_zeros = None 

151 else: 

152 self.number_of_leading_zeros = int(number_of_leading_zeros) 

153 

154 # The next few fields are non-essential fields for a phone number. 

155 # They retain extra information about the form the phone number was 

156 # in when it was provided to us to parse. They can be safely 

157 # ignored by most clients. 

158 

159 # This field is used to store the raw input string containing phone 

160 # numbers before it was canonicalized by the library. For example, it 

161 # could be used to store alphanumerical numbers such as 

162 # "1-800-GOOG-411". 

163 self.raw_input = force_unicode(raw_input) # None or Unicode string 

164 

165 # The source from which the country_code is derived. This is not set 

166 # in the general parsing method, but in the method that parses and 

167 # keeps raw_input. New fields could be added upon request. 

168 self.country_code_source = country_code_source # CountryCodeSource.VALUE 

169 if self.country_code_source is None: # pragma no cover 

170 self.country_code_source = CountryCodeSource.UNSPECIFIED 

171 

172 # The carrier selection code that is preferred when calling this 

173 # phone number domestically. This also includes codes that need to 

174 # be dialed in some countries when calling from landlines to mobiles 

175 # or vice versa. For example, in Columbia, a "3" needs to be dialed 

176 # before the phone number itself when calling from a mobile phone to 

177 # a domestic landline phone and vice versa. 

178 # 

179 # Note this is the "preferred" code, which means other codes may work 

180 # as well. 

181 self.preferred_domestic_carrier_code = force_unicode(preferred_domestic_carrier_code) 

182 # None or Unicode string 

183 

184 def clear(self): 

185 """Erase the contents of the object""" 

186 self.country_code = None 

187 self.national_number = None 

188 self.extension = None 

189 self.italian_leading_zero = None 

190 self.number_of_leading_zeros = None 

191 self.raw_input = None 

192 self.country_code_source = CountryCodeSource.UNSPECIFIED 

193 self.preferred_domestic_carrier_code = None 

194 

195 def merge_from(self, other): 

196 """Merge information from another PhoneNumber object into this one.""" 

197 if other.country_code is not None: 

198 self.country_code = other.country_code 

199 if other.national_number is not None: 

200 self.national_number = other.national_number 

201 if other.extension is not None: 

202 self.extension = other.extension 

203 if other.italian_leading_zero is not None: 

204 self.italian_leading_zero = other.italian_leading_zero 

205 if other.number_of_leading_zeros is not None: 

206 self.number_of_leading_zeros = other.number_of_leading_zeros 

207 if other.raw_input is not None: 

208 self.raw_input = other.raw_input 

209 if other.country_code_source is not CountryCodeSource.UNSPECIFIED: 

210 self.country_code_source = other.country_code_source 

211 if other.preferred_domestic_carrier_code is not None: 

212 self.preferred_domestic_carrier_code = other.preferred_domestic_carrier_code 

213 

214 def __eq__(self, other): 

215 if not isinstance(other, PhoneNumber): 

216 return False 

217 return (self.country_code == other.country_code and 

218 self.national_number == other.national_number and 

219 self.extension == other.extension and 

220 bool(self.italian_leading_zero) == bool(other.italian_leading_zero) and 

221 self.number_of_leading_zeros == other.number_of_leading_zeros and 

222 self.raw_input == other.raw_input and 

223 self.country_code_source == other.country_code_source and 

224 self.preferred_domestic_carrier_code == other.preferred_domestic_carrier_code) 

225 

226 def __ne__(self, other): 

227 return not self.__eq__(other) 

228 

229 def __repr__(self): 

230 return (unicod("%s(country_code=%s, national_number=%s, extension=%s, " + 

231 "italian_leading_zero=%s, number_of_leading_zeros=%s, " + 

232 "country_code_source=%s, preferred_domestic_carrier_code=%s)") % 

233 (type(self).__name__, 

234 self.country_code, 

235 self.national_number, 

236 rpr(self.extension), 

237 self.italian_leading_zero, 

238 self.number_of_leading_zeros, 

239 self.country_code_source, 

240 rpr(self.preferred_domestic_carrier_code))) 

241 

242 def __unicode__(self): 

243 result = (unicod("Country Code: %s National Number: %s") % 

244 (self.country_code, self.national_number)) 

245 if self.italian_leading_zero is not None: 

246 result += unicod(" Leading Zero(s): %s") % self.italian_leading_zero 

247 if self.number_of_leading_zeros is not None: 

248 result += unicod(" Number of leading zeros: %d") % self.number_of_leading_zeros 

249 if self.extension is not None: 

250 result += unicod(" Extension: %s") % self.extension 

251 if self.country_code_source is not CountryCodeSource.UNSPECIFIED: 

252 result += unicod(" Country Code Source: %s") % self.country_code_source 

253 if self.preferred_domestic_carrier_code is not None: 

254 result += (unicod(" Preferred Domestic Carrier Code: %s") % 

255 self.preferred_domestic_carrier_code) 

256 return result 

257 

258 

259class FrozenPhoneNumber(PhoneNumber, ImmutableMixin): 

260 """Immutable version of PhoneNumber""" 

261 def __hash__(self): 

262 return hash((self.country_code, 

263 self.national_number, 

264 self.extension, 

265 bool(self.italian_leading_zero), 

266 self.number_of_leading_zeros, 

267 self.raw_input, 

268 self.country_code_source, 

269 self.preferred_domestic_carrier_code)) 

270 

271 @mutating_method 

272 def __init__(self, *args, **kwargs): 

273 if len(kwargs) == 0 and len(args) == 1 and isinstance(args[0], PhoneNumber): 

274 # Copy constructor 

275 super(FrozenPhoneNumber, self).__init__(**args[0].__dict__) 

276 else: 

277 super(FrozenPhoneNumber, self).__init__(*args, **kwargs)