0
# Number Validation
1
2
Comprehensive validation functions to check if phone numbers are valid, possible, or match specific criteria. These functions provide detailed validation information and support various validation levels.
3
4
## Capabilities
5
6
### Basic Validity Checking
7
8
Determine if phone numbers are valid according to official numbering plan rules and formatting requirements.
9
10
```python { .api }
11
def is_valid_number(numobj: PhoneNumber) -> bool:
12
"""
13
Check if a phone number is valid.
14
15
A valid number is one that is both possible (correct length) and
16
follows the numbering rules for its region and type.
17
18
Parameters:
19
- numobj: PhoneNumber object to validate
20
21
Returns:
22
True if the number is valid, False otherwise
23
"""
24
25
def is_valid_number_for_region(numobj: PhoneNumber, region_code: str) -> bool:
26
"""
27
Check if a phone number is valid for a specific region.
28
29
Parameters:
30
- numobj: PhoneNumber object to validate
31
- region_code: Two-letter region code to validate against
32
33
Returns:
34
True if valid for the specified region, False otherwise
35
"""
36
```
37
38
**Usage Examples:**
39
40
```python
41
import phonenumbers
42
43
# Parse and validate various numbers
44
numbers = [
45
"+442083661177", # Valid UK number
46
"+1234567890", # Invalid country code
47
"+44208366", # Too short
48
"+442083661177123", # Too long
49
]
50
51
for number_str in numbers:
52
try:
53
number = phonenumbers.parse(number_str)
54
is_valid = phonenumbers.is_valid_number(number)
55
print(f"{number_str}: {'Valid' if is_valid else 'Invalid'}")
56
except phonenumbers.NumberParseException:
57
print(f"{number_str}: Parse failed")
58
59
# Region-specific validation
60
number = phonenumbers.parse("+442083661177")
61
print(f"Valid for GB: {phonenumbers.is_valid_number_for_region(number, 'GB')}")
62
print(f"Valid for US: {phonenumbers.is_valid_number_for_region(number, 'US')}")
63
```
64
65
### Possibility Checking
66
67
Check if numbers have valid lengths and basic formatting, which is less strict than full validation.
68
69
```python { .api }
70
def is_possible_number(numobj: PhoneNumber) -> bool:
71
"""
72
Check if a phone number is possible (has valid length).
73
74
This is a quicker check than full validation - it only verifies
75
that the number length is appropriate for the region.
76
77
Parameters:
78
- numobj: PhoneNumber object to check
79
80
Returns:
81
True if the number could possibly be valid, False otherwise
82
"""
83
84
def is_possible_number_string(number: str, region_code: str) -> bool:
85
"""
86
Check if a number string is possible without full parsing.
87
88
Parameters:
89
- number: Phone number string to check
90
- region_code: Region code for parsing context
91
92
Returns:
93
True if the string could represent a valid number, False otherwise
94
"""
95
```
96
97
### Detailed Possibility Analysis
98
99
Get detailed information about why a number might not be possible, with specific reasons for failure.
100
101
```python { .api }
102
def is_possible_number_with_reason(numobj: PhoneNumber) -> ValidationResult:
103
"""
104
Check number possibility with detailed reason for the result.
105
106
Parameters:
107
- numobj: PhoneNumber object to analyze
108
109
Returns:
110
ValidationResult indicating specific possibility status:
111
- IS_POSSIBLE: Number has valid length
112
- IS_POSSIBLE_LOCAL_ONLY: Valid for local dialing only
113
- INVALID_COUNTRY_CODE: Country code is not recognized
114
- TOO_SHORT: Number is shorter than valid lengths
115
- TOO_LONG: Number is longer than valid lengths
116
- INVALID_LENGTH: Length doesn't match any valid pattern
117
"""
118
119
def is_possible_number_for_type(numobj: PhoneNumber,
120
phone_type: PhoneNumberType) -> bool:
121
"""
122
Check if number is possible for a specific phone number type.
123
124
Parameters:
125
- numobj: PhoneNumber object to check
126
- phone_type: Specific type to validate against (MOBILE, FIXED_LINE, etc.)
127
128
Returns:
129
True if possible for the specified type, False otherwise
130
"""
131
132
def is_possible_number_for_type_with_reason(numobj: PhoneNumber,
133
phone_type: PhoneNumberType) -> ValidationResult:
134
"""
135
Check type-specific possibility with detailed reason.
136
137
Parameters:
138
- numobj: PhoneNumber object to analyze
139
- phone_type: Phone number type to check against
140
141
Returns:
142
ValidationResult with specific reason for the validation outcome
143
"""
144
```
145
146
**Usage Examples:**
147
148
```python
149
import phonenumbers
150
from phonenumbers import PhoneNumberType, ValidationResult
151
152
number = phonenumbers.parse("+44208366", "GB") # Too short
153
154
# Basic possibility check
155
print(f"Is possible: {phonenumbers.is_possible_number(number)}")
156
157
# Detailed analysis
158
result = phonenumbers.is_possible_number_with_reason(number)
159
if result == ValidationResult.TOO_SHORT:
160
print("Number is too short")
161
elif result == ValidationResult.TOO_LONG:
162
print("Number is too long")
163
elif result == ValidationResult.IS_POSSIBLE:
164
print("Number is possible")
165
166
# Type-specific checking
167
mobile_number = phonenumbers.parse("+447700900123", "GB")
168
is_mobile_possible = phonenumbers.is_possible_number_for_type(
169
mobile_number, PhoneNumberType.MOBILE
170
)
171
print(f"Possible as mobile: {is_mobile_possible}")
172
```
173
174
### Number Type Classification
175
176
Determine what type of phone number (mobile, fixed-line, toll-free, etc.) a given number represents.
177
178
```python { .api }
179
def number_type(numobj: PhoneNumber) -> PhoneNumberType:
180
"""
181
Determine the type of a phone number.
182
183
Parameters:
184
- numobj: PhoneNumber object to classify
185
186
Returns:
187
PhoneNumberType indicating the number's classification:
188
- FIXED_LINE: Traditional landline number
189
- MOBILE: Mobile/cellular number
190
- FIXED_LINE_OR_MOBILE: Cannot distinguish (e.g., US numbers)
191
- TOLL_FREE: Free-to-caller service number
192
- PREMIUM_RATE: Premium-rate service number
193
- SHARED_COST: Shared cost between caller and receiver
194
- VOIP: Voice over IP number
195
- PERSONAL_NUMBER: Personal numbering service
196
- PAGER: Pager number
197
- UAN: Universal Access Number (company number)
198
- VOICEMAIL: Voicemail access number
199
- UNKNOWN: Cannot determine type
200
"""
201
```
202
203
### Geographic Number Analysis
204
205
Analyze whether numbers are tied to specific geographic locations.
206
207
```python { .api }
208
def is_number_geographical(numobj: PhoneNumber) -> bool:
209
"""
210
Check if a phone number is geographical (tied to a location).
211
212
Parameters:
213
- numobj: PhoneNumber object to analyze
214
215
Returns:
216
True if the number is associated with a geographic area, False otherwise
217
"""
218
219
def is_number_type_geographical(phone_type: PhoneNumberType) -> bool:
220
"""
221
Check if a phone number type is generally geographical.
222
223
Parameters:
224
- phone_type: PhoneNumberType to check
225
226
Returns:
227
True if numbers of this type are typically geographical
228
"""
229
```
230
231
### International Dialing Capability
232
233
Check if numbers can be dialed internationally from other countries.
234
235
```python { .api }
236
def can_be_internationally_dialled(numobj: PhoneNumber) -> bool:
237
"""
238
Check if a number can be dialed internationally.
239
240
Some numbers (like emergency services) cannot be reached from abroad.
241
242
Parameters:
243
- numobj: PhoneNumber object to check
244
245
Returns:
246
True if the number can be dialed from other countries, False otherwise
247
"""
248
```
249
250
### Length Truncation
251
252
Attempt to truncate overly long numbers to valid lengths.
253
254
```python { .api }
255
def truncate_too_long_number(numobj: PhoneNumber) -> PhoneNumber:
256
"""
257
Truncate a number that is too long to a valid length.
258
259
Parameters:
260
- numobj: PhoneNumber that may be too long
261
262
Returns:
263
PhoneNumber truncated to valid length, or original if already valid
264
"""
265
```
266
267
## Usage Patterns
268
269
### Comprehensive Number Validation
270
271
```python
272
import phonenumbers
273
from phonenumbers import PhoneNumberType, ValidationResult
274
275
def validate_phone_number(number_string, region=None):
276
"""Comprehensive phone number validation with detailed feedback."""
277
try:
278
# Parse the number
279
number = phonenumbers.parse(number_string, region)
280
281
# Basic validation
282
is_valid = phonenumbers.is_valid_number(number)
283
is_possible = phonenumbers.is_possible_number(number)
284
285
# Detailed possibility analysis
286
possibility_reason = phonenumbers.is_possible_number_with_reason(number)
287
288
# Number type classification
289
num_type = phonenumbers.number_type(number)
290
291
# Geographic analysis
292
is_geographic = phonenumbers.is_number_geographical(number)
293
294
# International dialing capability
295
can_dial_intl = phonenumbers.can_be_internationally_dialled(number)
296
297
return {
298
'number': number,
299
'is_valid': is_valid,
300
'is_possible': is_possible,
301
'possibility_reason': possibility_reason,
302
'type': num_type,
303
'is_geographic': is_geographic,
304
'can_dial_internationally': can_dial_intl,
305
'formatted': {
306
'e164': phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.E164),
307
'international': phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.INTERNATIONAL),
308
'national': phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.NATIONAL)
309
}
310
}
311
312
except phonenumbers.NumberParseException as e:
313
return {
314
'error': str(e),
315
'error_type': e.error_type
316
}
317
318
# Example usage
319
result = validate_phone_number("+442083661177")
320
if 'error' not in result:
321
print(f"Valid: {result['is_valid']}")
322
print(f"Type: {result['type']}")
323
print(f"Geographic: {result['is_geographic']}")
324
print(f"E164: {result['formatted']['e164']}")
325
```
326
327
### Batch Validation
328
329
```python
330
import phonenumbers
331
332
def validate_number_list(numbers, default_region="US"):
333
"""Validate a list of phone numbers with summary statistics."""
334
results = {
335
'valid': [],
336
'invalid': [],
337
'unparseable': [],
338
'types': {}
339
}
340
341
for number_str in numbers:
342
try:
343
number = phonenumbers.parse(number_str, default_region)
344
345
if phonenumbers.is_valid_number(number):
346
results['valid'].append(number_str)
347
num_type = phonenumbers.number_type(number)
348
results['types'][num_type] = results['types'].get(num_type, 0) + 1
349
else:
350
results['invalid'].append(number_str)
351
352
except phonenumbers.NumberParseException:
353
results['unparseable'].append(number_str)
354
355
return results
356
357
# Example usage
358
test_numbers = [
359
"+1-800-555-1234", # Valid US toll-free
360
"+44 20 8366 1177", # Valid UK fixed-line
361
"+1-555-123", # Invalid (too short)
362
"not-a-number" # Unparseable
363
]
364
365
results = validate_number_list(test_numbers)
366
print(f"Valid: {len(results['valid'])}")
367
print(f"Invalid: {len(results['invalid'])}")
368
print(f"Unparseable: {len(results['unparseable'])}")
369
print(f"Types found: {results['types']}")
370
```