Skip to content

Commit 5599c56

Browse files
committed
Update build tool for new metadata information
1 parent 43b7027 commit 5599c56

1 file changed

Lines changed: 99 additions & 8 deletions

File tree

tools/python/buildmetadatafromxml.py

Lines changed: 99 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
import sys
4242
import os
43+
import copy
4344
import re
4445
import getopt
4546
import datetime
@@ -154,6 +155,30 @@ def _dews_re(re_str):
154155
return re.sub(r'\s', '', re_str)
155156

156157

158+
_NUM_RE = re.compile('\d+')
159+
_RANGE_RE = re.compile(r'\[(?P<min>\d+)-(?P<max>\d+)\]')
160+
161+
162+
def _extract_lengths(ll):
163+
"""Extract list of possible lengths from string"""
164+
results = set()
165+
if ll is None:
166+
return []
167+
for val in ll.split(','):
168+
m = _NUM_RE.match(val)
169+
if m:
170+
results.add(int(val))
171+
else:
172+
m = _RANGE_RE.match(val)
173+
if m is None:
174+
raise Exception("Unrecognized length specification %s" % ll)
175+
min = int(m.group('min'))
176+
max = int(m.group('max'))
177+
for ii in range(min, max + 1):
178+
results.add(ii)
179+
return sorted(list(results))
180+
181+
157182
def _expand_formatting_rule(rule, national_prefix):
158183
"""Formatting rules can include terms "$NP" and "$FG",
159184
These get replaced with:
@@ -216,7 +241,7 @@ def __init__(self, owning_xterr, xtag, national_prefix,
216241
if self.o.national_prefix_formatting_rule is not None:
217242
# expand abbreviations
218243
self.o.national_prefix_formatting_rule = _expand_formatting_rule(self.o.national_prefix_formatting_rule,
219-
national_prefix)
244+
national_prefix)
220245
else:
221246
# set to territory-wide formatting rule
222247
self.o.national_prefix_formatting_rule = national_prefix_formatting_rule
@@ -231,7 +256,7 @@ def __init__(self, owning_xterr, xtag, national_prefix,
231256
if self.o.domestic_carrier_code_formatting_rule is not None:
232257
# expand abbreviations
233258
self.o.domestic_carrier_code_formatting_rule = _expand_formatting_rule(self.o.domestic_carrier_code_formatting_rule,
234-
national_prefix)
259+
national_prefix)
235260
else:
236261
# set to territory-wide formatting rule
237262
self.o.domestic_carrier_code_formatting_rule = carrier_code_formatting_rule
@@ -278,11 +303,16 @@ def __unicode__(self):
278303

279304
class XPhoneNumberDesc(UnicodeMixin):
280305
"""Parse PhoneNumberDesc object from XML element"""
281-
def __init__(self, xtag, template=None, fill_na=True):
306+
def __init__(self, xtag, template=None, fill_na=True, lengths_expected=True):
307+
self.xtag = xtag
282308
self.o = PhoneNumberDesc()
283309
self.o._mutable = True
284310
self.o.national_number_pattern = None
285311
self.o.possible_number_pattern = None
312+
# Set possible length info to None for now, to mark that it wasn't specified
313+
# for this numberDesc.
314+
self.o.possible_length = None
315+
self.o.possible_length_local_only = None
286316
self.o.example_number = None
287317
if xtag is None:
288318
if fill_na:
@@ -305,6 +335,21 @@ def __init__(self, xtag, template=None, fill_na=True):
305335
example_number = _get_unique_child_value(xtag, 'exampleNumber')
306336
if example_number is not None:
307337
self.o.example_number = example_number
338+
possible_lengths = _get_unique_child(xtag, 'possibleLengths')
339+
if possible_lengths is not None:
340+
if not lengths_expected:
341+
raise Exception("Found unexpected possibleLengths element in %s" % xtag.tag)
342+
national_lengths = possible_lengths.attrib['national'] # REQUIRED attribute
343+
if national_lengths == "-1":
344+
# A value of -1 for possibleLengths.national is a special marker to indicate
345+
# that this sub-type of number doesn't actually exist.
346+
if fill_na:
347+
raise Exception("Found possibleLengths -1 for unexpected number type")
348+
self.o.possible_length = [-1]
349+
return
350+
self.o.possible_length = _extract_lengths(national_lengths)
351+
local_lengths = possible_lengths.get('localOnly', None) # IMPLIED attribute
352+
self.o.possible_length_local_only = _extract_lengths(local_lengths)
308353

309354
def __unicode__(self):
310355
return u(self.o)
@@ -374,10 +419,19 @@ def __init__(self, xterritory, short_data):
374419
# first and most important; it will be used to fill out missing fields in
375420
# many of the other PhoneNumberDesc elements.
376421
self.o.general_desc = XPhoneNumberDesc(_get_unique_child(xterritory, 'generalDesc'),
377-
fill_na=False)
422+
fill_na=False, lengths_expected=False)
423+
# As a special case, the possible lengths for the general_desc should be empty
424+
# (they will be deduced below).
425+
if self.o.general_desc.o.possible_length is not None or self.o.general_desc.o.possible_length_local_only is not None:
426+
raise Exception("Found generalDesc for %s with unexpected possibleLength element" % self.o.general_desc.id)
427+
378428
# areaCodeOptional is in the XML but not used in the code.
379429
self.o.area_code_optional = XPhoneNumberDesc(_get_unique_child(xterritory, 'areaCodeOptional'),
380430
template=self.o.general_desc.o)
431+
self.o.toll_free = XPhoneNumberDesc(_get_unique_child(xterritory, 'tollFree'),
432+
template=self.o.general_desc.o)
433+
self.o.premium_rate = XPhoneNumberDesc(_get_unique_child(xterritory, 'premiumRate'),
434+
template=self.o.general_desc.o)
381435
if not short_data:
382436
self.o.fixed_line = XPhoneNumberDesc(_get_unique_child(xterritory, 'fixedLine'),
383437
template=self.o.general_desc.o, fill_na=False)
@@ -397,6 +451,14 @@ def __init__(self, xterritory, short_data):
397451
template=self.o.general_desc.o)
398452
self.o.no_international_dialling = XPhoneNumberDesc(_get_unique_child(xterritory, 'noInternationalDialling'),
399453
template=self.o.general_desc.o)
454+
# Skip noInternationalDialling when combining possible length information
455+
sub_descs = (self.o.area_code_optional, self.o.toll_free, self.o.premium_rate,
456+
self.o.fixed_line, self.o.mobile, self.o.pager, self.o.shared_cost,
457+
self.o.personal_number, self.o.voip, self.o.uan, self.o.voicemail)
458+
all_descs = (self.o.area_code_optional, self.o.toll_free, self.o.premium_rate,
459+
self.o.fixed_line, self.o.mobile, self.o.pager, self.o.shared_cost,
460+
self.o.personal_number, self.o.voip, self.o.uan, self.o.voicemail,
461+
self.o.no_international_dialling)
400462
else:
401463
self.o.standard_rate = XPhoneNumberDesc(_get_unique_child(xterritory, 'standardRate'),
402464
template=self.o.general_desc.o)
@@ -406,10 +468,39 @@ def __init__(self, xterritory, short_data):
406468
template=self.o.general_desc.o)
407469
self.o.emergency = XPhoneNumberDesc(_get_unique_child(xterritory, 'emergency'),
408470
template=self.o.general_desc.o)
409-
self.o.toll_free = XPhoneNumberDesc(_get_unique_child(xterritory, 'tollFree'),
410-
template=self.o.general_desc.o)
411-
self.o.premium_rate = XPhoneNumberDesc(_get_unique_child(xterritory, 'premiumRate'),
412-
template=self.o.general_desc.o)
471+
# For short number metadata, copy the lengths from the "short code" section only.
472+
sub_descs = (self.o.short_code,)
473+
all_descs = (self.o.area_code_optional, self.o.toll_free, self.o.premium_rate,
474+
self.o.standard_rate, self.o.short_code, self.o.carrier_specific,
475+
self.o.emergency)
476+
477+
# Build the possible length information for general_desc based on all the different types of number.
478+
possible_lengths = set()
479+
local_lengths = set()
480+
for desc in sub_descs:
481+
if desc.o is None:
482+
continue
483+
if desc.o.possible_length is not None:
484+
possible_lengths.update(desc.o.possible_length)
485+
if desc.o.possible_length_local_only is not None:
486+
local_lengths.update(desc.o.possible_length_local_only)
487+
self.o.general_desc.o.possible_length = list(possible_lengths)
488+
self.o.general_desc.o.possible_length_local_only = list(local_lengths)
489+
490+
# Now that the union of length information is available, trickle it back down to those types
491+
# of number that didn't specify any length information (indicated by having those fields set
492+
# to None). But only if they're non
493+
for desc in all_descs:
494+
if desc.o is not None:
495+
if desc.o.national_number_pattern == DATA_NA:
496+
desc.o.possible_length = []
497+
desc.o.possible_length_local_only = []
498+
continue
499+
if desc.o.possible_length is None:
500+
desc.o.possible_length = copy.copy(self.o.general_desc.o.possible_length)
501+
if desc.o.possible_length_local_only is None:
502+
desc.o.possible_length_local_only = copy.copy(self.o.general_desc.o.possible_length_local_only)
503+
413504
# Look for available formats
414505
self.has_explicit_intl_format = False
415506
formats = _get_unique_child(xterritory, "availableFormats")

0 commit comments

Comments
 (0)