Package pyxb :: Package binding :: Module generate
[hide private]
[frames] | no frames]

Source Code for Module pyxb.binding.generate

   1  # -*- coding: utf-8 -*- 
   2  # Copyright 2009-2013, Peter A. Bigot 
   3  # 
   4  # Licensed under the Apache License, Version 2.0 (the "License"); you may 
   5  # not use this file except in compliance with the License. You may obtain a 
   6  # copy of the License at: 
   7  # 
   8  #            http://www.apache.org/licenses/LICENSE-2.0 
   9  # 
  10  # Unless required by applicable law or agreed to in writing, software 
  11  # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
  12  # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
  13  # License for the specific language governing permissions and limitations 
  14  # under the License. 
  15   
  16  """The really ugly code that generates the Python bindings.  This 
  17  whole thing is going to be refactored once customized generation makes 
  18  it to the top of the task queue.""" 
  19   
  20  import sys 
  21  import os.path 
  22  import logging 
  23  import logging.config 
  24  import io 
  25  import datetime 
  26  import errno 
  27   
  28  import pyxb 
  29  import pyxb.xmlschema as xs 
  30  from pyxb.utils import utility, templates, six 
  31  from pyxb.utils.utility import repr2to3 
  32  from pyxb.binding import basis, datatypes, facets 
  33   
  34  _log = logging.getLogger(__name__) 
35 36 -def PrefixModule (value, text=None):
37 if text is None: 38 text = value.__name__ 39 if value.__module__ == datatypes.__name__: 40 return 'pyxb.binding.datatypes.%s' % (text,) 41 if value.__module__ == facets.__name__: 42 return 'pyxb.binding.facets.%s' % (text,) 43 raise ValueError('No standard name for module of value', value)
44
45 -class ReferenceLiteral (object):
46 """Base class for something that requires fairly complex activity 47 in order to generate its literal value.""" 48 49 # Either a STD or a subclass of _Enumeration_mixin, this is the 50 # class in which the referenced object is a member. 51 __ownerClass = None 52 53 # The value to be used as a literal for this object 54 __literal = None 55
56 - def __init__ (self, **kw):
57 # NB: Pre-extend __init__ 58 self.__ownerClass = kw.get('type_definition')
59
60 - def setLiteral (self, literal):
61 self.__literal = literal 62 return literal
63
64 - def asLiteral (self):
65 return self.__literal
66
67 - def _addTypePrefix (self, text, **kw):
68 if self.__ownerClass is not None: 69 text = '%s.%s' % (pythonLiteral(self.__ownerClass, **kw), text) 70 return text
71
72 -class ReferenceFacetMember (ReferenceLiteral):
73 __facetClass = None 74
75 - def __init__ (self, **kw):
76 variable = kw.get('variable') 77 assert (variable is None) or isinstance(variable, facets.Facet) 78 79 if variable is not None: 80 kw.setdefault('type_definition', variable.ownerTypeDefinition()) 81 self.__facetClass = type(variable) 82 self.__facetClass = kw.get('facet_class', self.__facetClass) 83 84 super(ReferenceFacetMember, self).__init__(**kw) 85 86 self.setLiteral(self._addTypePrefix('_CF_%s' % (self.__facetClass.Name(),), **kw))
87
88 -class ReferenceWildcard (ReferenceLiteral):
89 __wildcard = None 90
91 - def __init__ (self, wildcard, **kw):
92 self.__wildcard = wildcard 93 super(ReferenceWildcard, self).__init__(**kw) 94 95 template_map = { } 96 template_map['Wildcard'] = 'pyxb.binding.content.Wildcard' 97 if (xs.structures.Wildcard.NC_any == wildcard.namespaceConstraint()): 98 template_map['nc'] = templates.replaceInText('%{Wildcard}.NC_any', **template_map) 99 elif isinstance(wildcard.namespaceConstraint(), (set, frozenset)): 100 namespaces = [] 101 for ns in wildcard.namespaceConstraint(): 102 if ns is None: 103 namespaces.append(None) 104 else: 105 namespaces.append(ns.uri()) 106 template_map['nc'] = 'set([%s])' % (",".join( [ repr2to3(_ns) for _ns in namespaces ])) 107 else: 108 assert isinstance(wildcard.namespaceConstraint(), tuple) 109 ns = wildcard.namespaceConstraint()[1] 110 if ns is not None: 111 ns = ns.uri() 112 template_map['nc'] = templates.replaceInText('(%{Wildcard}.NC_not, %{namespace})', namespace=repr2to3(ns), **template_map) 113 template_map['pc'] = wildcard.processContents() 114 self.setLiteral(templates.replaceInText('%{Wildcard}(process_contents=%{Wildcard}.PC_%{pc}, namespace_constraint=%{nc})', **template_map))
115
116 -class ReferenceSchemaComponent (ReferenceLiteral):
117 __component = None 118
119 - def __init__ (self, component, **kw):
120 self.__component = component 121 binding_module = kw['binding_module'] 122 super(ReferenceSchemaComponent, self).__init__(**kw) 123 rv = binding_module.referenceSchemaComponent(component) 124 self.setLiteral(rv)
125
126 -class ReferenceNamespace (ReferenceLiteral):
127 __namespace = None 128
129 - def __init__ (self, **kw):
130 self.__namespace = kw['namespace'] 131 binding_module = kw['binding_module'] 132 super(ReferenceNamespace, self).__init__(**kw) 133 rv = binding_module.referenceNamespace(self.__namespace) 134 self.setLiteral(rv)
135
136 -class ReferenceExpandedName (ReferenceLiteral):
137 __expandedName = None 138
139 - def __init__ (self, **kw):
140 self.__expandedName = kw['expanded_name'] 141 super(ReferenceExpandedName, self).__init__(**kw) 142 self.setLiteral('pyxb.namespace.ExpandedName(%s, %s)' % (pythonLiteral(self.__expandedName.namespace(), **kw), pythonLiteral(self.__expandedName.localName(), **kw)))
143
144 -class ReferenceFacet (ReferenceLiteral):
145 __facet = None 146
147 - def __init__ (self, **kw):
148 self.__facet = kw['facet'] 149 super(ReferenceFacet, self).__init__(**kw) 150 self.setLiteral('%s._CF_%s' % (pythonLiteral(self.__facet.ownerTypeDefinition(), **kw), self.__facet.Name()))
151
152 -class ReferenceEnumerationMember (ReferenceLiteral):
153 enumerationElement = None 154
155 - def __init__ (self, **kw):
156 # NB: Pre-extended __init__ 157 158 # All we really need is the enumeration element, so we can get 159 # its tag, and a type definition or datatype, so we can create 160 # the proper prefix. 161 162 # See if we were given a value, from which we can extract the 163 # other information. 164 value = kw.get('enum_value') 165 assert (value is None) or isinstance(value, facets._Enumeration_mixin) 166 167 # Must provide facet_instance, or a value from which it can be 168 # obtained. 169 facet_instance = kw.get('facet_instance') 170 if facet_instance is None: 171 assert isinstance(value, facets._Enumeration_mixin) 172 facet_instance = value._CF_enumeration 173 assert isinstance(facet_instance, facets.CF_enumeration) 174 175 # Must provide the enumeration_element, or a facet_instance 176 # and value from which it can be identified. 177 self.enumerationElement = kw.get('enumeration_element') 178 if self.enumerationElement is None: 179 assert value is not None 180 self.enumerationElement = facet_instance.elementForValue(value) 181 assert isinstance(self.enumerationElement, facets._EnumerationElement) 182 assert self.enumerationElement.tag() is not None 183 184 # If no type definition was provided, use the value datatype 185 # for the facet. 186 kw.setdefault('type_definition', facet_instance.valueDatatype()) 187 188 super(ReferenceEnumerationMember, self).__init__(**kw) 189 190 self.setLiteral(self._addTypePrefix(self.enumerationElement.tag(), **kw))
191
192 -def pythonLiteral (value, **kw):
193 # For dictionaries, apply translation to all values (not keys) 194 if isinstance(value, six.dictionary_type): 195 return ', '.join([ '%s=%s' % (k, pythonLiteral(v, **kw)) for (k, v) in six.iteritems(value) ]) 196 197 # For lists, apply translation to all members 198 if isinstance(value, six.list_type): 199 return [ pythonLiteral(_v, **kw) for _v in value ] 200 201 # ExpandedName is a tuple, but not here 202 if isinstance(value, pyxb.namespace.ExpandedName): 203 return pythonLiteral(ReferenceExpandedName(expanded_name=value, **kw)) 204 205 # For other collection types, do what you do for list 206 if isinstance(value, (six.tuple_type, set)): 207 return type(value)(pythonLiteral(list(value), **kw)) 208 209 # Value is a binding value for which there should be an 210 # enumeration constant. Return that constant. 211 if isinstance(value, facets._Enumeration_mixin): 212 return pythonLiteral(ReferenceEnumerationMember(enum_value=value, **kw)) 213 214 # Value is an instance of a Python binding, e.g. one of the 215 # XMLSchema datatypes. Use its value, applying the proper prefix 216 # for the module. 217 if isinstance(value, basis.simpleTypeDefinition): 218 return PrefixModule(value, value.pythonLiteral()) 219 220 if isinstance(value, pyxb.namespace.Namespace): 221 return pythonLiteral(ReferenceNamespace(namespace=value, **kw)) 222 223 if isinstance(value, type): 224 if issubclass(value, basis.simpleTypeDefinition): 225 return PrefixModule(value) 226 if issubclass(value, facets.Facet): 227 return PrefixModule(value) 228 229 if isinstance(value, facets.Facet): 230 return pythonLiteral(ReferenceFacet(facet=value, **kw)) 231 232 # Treat pattern elements as their value 233 if isinstance(value, facets._PatternElement): 234 return pythonLiteral(value.pattern) 235 236 # Treat enumeration elements as their value 237 if isinstance(value, facets._EnumerationElement): 238 return pythonLiteral(value.value()) 239 240 # Wildcards expand to a pyxb.binding.content.Wildcard instance 241 if isinstance(value, xs.structures.Wildcard): 242 return pythonLiteral(ReferenceWildcard(value, **kw)) 243 244 # Schema components have a single name through their lifespan 245 if isinstance(value, xs.structures._SchemaComponent_mixin): 246 return pythonLiteral(ReferenceSchemaComponent(value, **kw)) 247 248 # Other special cases 249 if isinstance(value, ReferenceLiteral): 250 return value.asLiteral() 251 252 # Represent namespaces by their URI 253 if isinstance(value, pyxb.namespace.Namespace): 254 return repr2to3(value.uri()) 255 256 # Standard Python types, including string types 257 if isinstance(value, (six.none_type, six.boolean_type, six.float_type, six.integer_types, six.string_types)): 258 return pyxb.utils.utility.repr2to3(value) 259 260 raise Exception('Unexpected literal type %s' % (type(value),))
261
262 -def _GenerateAutomaton (automaton, template_map, containing_state, lines, **kw):
263 binding_module = kw['binding_module'] 264 name = utility.PrepareIdentifier('BuildAutomaton', binding_module.uniqueInModule(), protected=True) 265 au_src = [] 266 au_src.append(templates.replaceInText(''' 267 def %{name} (): 268 # Remove this helper function from the namespace after it is invoked 269 global %{name} 270 del %{name} 271 import pyxb.utils.fac as fac 272 ''', name=name)) 273 274 def stateSortKey (st): 275 if isinstance(st.symbol, xs.structures.ModelGroup): 276 return st.symbol.facStateSortKey() 277 return st.symbol[0].facStateSortKey()
278 279 def counterConditionSortKey (cc): 280 return cc.metadata.facStateSortKey() 281 282 def updateInstructionSortKey (ui): 283 return counterConditionSortKey(ui.counterCondition) 284 285 def transitionSortKey (xit): 286 # The destination of a transition is not unique; need to 287 # differentiate using the update instructions. Which 288 # themselves should be sorted. 289 st = xit.consumingState() 290 291 # Transitions into/out-of subautomata might not include a 292 # consuming state. Give those a sort value None. 293 ssk = None 294 if st is not None: 295 ssk = stateSortKey(st) 296 keys = [ ssk ] 297 keys.extend(map(updateInstructionSortKey, sorted(xit.updateInstructions, key=updateInstructionSortKey))) 298 return tuple(keys) 299 300 au_src.append(' counters = set()') 301 counter_map = {} 302 sorted_counter_conditions = sorted(automaton.counterConditions, key=counterConditionSortKey) 303 for cc in sorted_counter_conditions: 304 cc_id = 'cc_%u' % (len(counter_map),) 305 counter_map[cc] = cc_id 306 au_src.append(' %s = fac.CounterCondition(min=%s, max=%s, metadata=%r)' % (cc_id, repr2to3(cc.min), repr2to3(cc.max), cc.metadata._location())) 307 au_src.append(' counters.add(%s)' % (cc_id,)) 308 state_map = {} 309 au_src.append(' states = []') 310 sorted_states = sorted(automaton.states, key=stateSortKey) 311 for st in sorted_states: 312 st_id = 'st_%u' % (len(state_map),) 313 state_map[st] = st_id 314 if st.subAutomata is not None: 315 au_src.append(' sub_automata = []') 316 for sa in st.subAutomata: 317 au_src.append(' sub_automata.append(%s)' % (_GenerateAutomaton(sa, template_map, st_id, lines, **kw),)) 318 if st.finalUpdate is None: 319 au_src.append(' final_update = None') 320 else: 321 au_src.append(' final_update = set()') 322 for ui in sorted(st.finalUpdate, key=updateInstructionSortKey): 323 au_src.append(' final_update.add(fac.UpdateInstruction(%s, %r))' % (counter_map[ui.counterCondition], ui.doIncrement)) 324 if isinstance(st.symbol, xs.structures.ModelGroup): 325 au_src.append(' symbol = %r' % (st.symbol._location(),)) 326 else: 327 (particle, symbol) = st.symbol 328 if isinstance(symbol, xs.structures.Wildcard): 329 au_src.append(templates.replaceInText(' symbol = pyxb.binding.content.WildcardUse(%{wildcard}, %{location})', wildcard=binding_module.literal(symbol, **kw), location=repr2to3(particle._location()))) 330 elif isinstance(symbol, xs.structures.ElementDeclaration): 331 binding_module.importForDeclaration(symbol) 332 au_src.append(templates.replaceInText(' symbol = pyxb.binding.content.ElementUse(%{ctd}._UseForTag(%{field_tag}), %{location})', field_tag=binding_module.literal(symbol.expandedName(), **kw), location=repr2to3(particle._location()), **template_map)) 333 au_src.append(' %s = fac.State(symbol, is_initial=%r, final_update=final_update, is_unordered_catenation=%r)' % (st_id, st.isInitial, st.isUnorderedCatenation)) 334 if st.subAutomata is not None: 335 au_src.append(' %s._set_subAutomata(*sub_automata)' % (st_id,)) 336 au_src.append(' states.append(%s)' % (st_id,)) 337 for st in sorted_states: 338 au_src.append(' transitions = []') 339 for xit in sorted(st.transitionSet, key=transitionSortKey): 340 au_src.append(' transitions.append(fac.Transition(%s, [' % (state_map[xit.destination],)) 341 sorted_ui = sorted(xit.updateInstructions, key=updateInstructionSortKey) 342 au_src.append(' %s ]))' % (',\n '.join(map(lambda _ui: 'fac.UpdateInstruction(%s, %r)' % (counter_map[_ui.counterCondition], _ui.doIncrement), sorted_ui)))) 343 au_src.append(' %s._set_transitionSet(transitions)' % (state_map[st],)) 344 au_src.append(' return fac.Automaton(states, counters, %r, containing_state=%s)' % (automaton.nullable, containing_state)) 345 lines.extend(au_src) 346 return '%s()' % (name,) 347
348 -def GenerateAutomaton (ctd, **kw):
349 aux = _CTDAuxData.Get(ctd) 350 binding_module = kw['binding_module'] 351 template_map = { 'ctd' : binding_module.literal(ctd, **kw) } 352 automaton = aux.automaton 353 if automaton is None: 354 return None 355 lines = [] 356 name = _GenerateAutomaton(automaton, template_map, 'None', lines, **kw) 357 return (name, lines)
358
359 -def _useEnumerationTags (td):
360 if td is None: 361 return False 362 assert isinstance(td, xs.structures.SimpleTypeDefinition) 363 ptd = td.baseTypeDefinition() 364 python_support = None 365 # Atomic types that use strings as their representation 366 if (ptd.VARIETY_atomic == ptd.variety()): 367 python_support = ptd.primitiveTypeDefinition().pythonSupport() 368 return issubclass(python_support, six.string_types) 369 # Derivations from anySimpleType use strings too 370 if (ptd.VARIETY_absent == ptd.variety()): 371 return True 372 # Union types? Yeah, I suppose so. Though this only applies to 373 # members lifted up into the union. 374 if (ptd.VARIETY_union == ptd.variety()): 375 return True 376 # List types have spaces so no tags. 377 return False
378
379 -def GenerateFacets (td, generator, **kw):
380 binding_module = kw['binding_module'] 381 outf = binding_module.bindingIO() 382 facet_instances = [] 383 gen_enum_tag = _useEnumerationTags(td) 384 for (fc, fi) in six.iteritems(td.facets()): 385 #if (fi is None) or (fi.ownerTypeDefinition() != td): 386 # continue 387 if (fi is None) and (fc in td.baseTypeDefinition().facets()): 388 # Nothing new here 389 continue 390 if (fi is not None) and (fi.ownerTypeDefinition() != td): 391 # Did this one in an ancestor 392 continue 393 argset = { } 394 is_collection = issubclass(fc, facets._CollectionFacet_mixin) 395 if issubclass(fc, facets._LateDatatype_mixin): 396 vdt = td 397 if fc.LateDatatypeBindsSuperclass(): 398 vdt = vdt.baseTypeDefinition() 399 argset['value_datatype'] = vdt 400 if fi is not None: 401 if not is_collection: 402 argset['value'] = fi.value() 403 if isinstance(fi, facets.CF_enumeration): 404 argset['enum_prefix'] = fi.enumPrefix() 405 facet_var = ReferenceFacetMember(type_definition=td, facet_class=fc, **kw) 406 outf.write("%s = %s(%s)\n" % binding_module.literal( (facet_var, fc, argset ), **kw)) 407 facet_instances.append(binding_module.literal(facet_var, **kw)) 408 if (fi is not None) and is_collection: 409 for i in six.iteritems(fi): 410 if isinstance(i, facets._EnumerationElement): 411 if isinstance(i.value(), pyxb.namespace.ExpandedName): 412 enum_config = '%s.addEnumeration(value=%s, tag=%s)' % binding_module.literal( ( facet_var, i.value(), i.tag() ), **kw) 413 else: 414 enum_config = '%s.addEnumeration(unicode_value=%s, tag=%s)' % binding_module.literal( ( facet_var, i.unicodeValue(), i.tag() ), **kw) 415 if gen_enum_tag and (i.tag() is not None): 416 enum_member = ReferenceEnumerationMember(type_definition=td, facet_instance=fi, enumeration_element=i, **kw) 417 outf.write("%s = %s\n" % (binding_module.literal(enum_member, **kw), enum_config)) 418 if fi.enumPrefix() is not None: 419 outf.write("%s_%s = %s\n" % (fi.enumPrefix(), i.tag(), binding_module.literal(enum_member, **kw))) 420 else: 421 outf.write("%s\n" % (enum_config,)) 422 if isinstance(i, facets._PatternElement): 423 outf.write("%s.addPattern(pattern=%s)\n" % binding_module.literal( (facet_var, i.pattern ), **kw)) 424 if gen_enum_tag and (xs.structures.SimpleTypeDefinition.VARIETY_union == td.variety()): 425 # If the union has enumerations of its own, there's no need to 426 # inherit anything, because they supersede anything implicitly 427 # inherited. 428 fi = td.facets().get(facets.CF_enumeration) 429 if fi is None: 430 # Need to expose any enumerations in members up in this class 431 for mtd in td.memberTypeDefinitions(): 432 if not _useEnumerationTags(mtd): 433 continue 434 fi = mtd.facets().get(facets.CF_enumeration) 435 if fi is None: 436 continue 437 for i in six.iteritems(fi): 438 assert isinstance(i, facets._EnumerationElement) 439 etd = i.enumeration().ownerTypeDefinition() 440 enum_member = ReferenceEnumerationMember(type_definition=td, facet_instance=fi, enumeration_element=i, **kw) 441 outf.write("%-50s%s\n" % ('%s = %s' % binding_module.literal( (enum_member, i.unicodeValue()) ), 442 '# originally %s.%s' % (binding_module.literal(etd), i.tag()))) 443 if 2 <= len(facet_instances): 444 map_args = ",\n ".join(facet_instances) 445 else: 446 map_args = ','.join(facet_instances) 447 outf.write("%s._InitializeFacetMap(%s)\n" % (binding_module.literal(td, **kw), map_args))
448
449 -def _VCAppendAuxInit (vc_source, aux_init, binding_module, kw):
450 if vc_source.fixed() is not None: 451 aux_init.append('fixed=True') 452 aux_init.append('unicode_default=%s' % (binding_module.literal(vc_source.fixed(), **kw),)) 453 elif vc_source.default() is not None: 454 aux_init.append('unicode_default=%s' % (binding_module.literal(vc_source.default(), **kw),))
455
456 # If std is a simple type that requires an enumeration mixin, return the 457 # corresponding facet; otherwise return None. 458 -def simpleTypeOwnedEnumerationFacet (std):
459 if not isinstance(std, xs.structures.SimpleTypeDefinition): 460 return None 461 enum_facet = std.facets().get(facets.CF_enumeration) 462 if (enum_facet is not None) and (enum_facet.ownerTypeDefinition() == std): 463 return enum_facet 464 return None
465
466 -def GenerateSTD (std, generator):
467 468 binding_module = generator.moduleForComponent(std) 469 outf = binding_module.bindingIO() 470 471 class_keywords = frozenset(basis.simpleTypeDefinition._ReservedSymbols) 472 class_unique = set() 473 474 kw = { } 475 kw['binding_module'] = binding_module 476 kw['class_keywords'] = class_keywords 477 kw['class_unique'] = class_unique 478 479 parent_classes = [ binding_module.literal(std.baseTypeDefinition(), **kw) ] 480 if simpleTypeOwnedEnumerationFacet(std) is not None: 481 parent_classes.append('pyxb.binding.basis.enumeration_mixin') 482 483 template_map = { } 484 binding_name = template_map['std'] = binding_module.literal(std, **kw) 485 if (std.expandedName() is not None) and (std.expandedName().localName() != binding_name): 486 _log.warning('Simple type %s renamed to %s', std.expandedName(), binding_name) 487 488 template_map['superclasses'] = '' 489 if 0 < len(parent_classes): 490 template_map['superclasses'] = ', '.join(parent_classes) 491 template_map['expanded_name'] = binding_module.literal(std.expandedName(), **kw) 492 if std.expandedName() is not None: 493 template_map['qname'] = six.text_type(std.expandedName()) 494 else: 495 template_map['qname'] = '[anonymous]' 496 template_map['namespaceReference'] = binding_module.literal(std.bindingNamespace(), **kw) 497 template_map['xsd_location'] = repr2to3(std._location()) 498 if std.annotation() is not None: 499 template_map['documentation'] = std.annotation().asDocString() 500 template_map['documentation_expr'] = binding_module.literal(std.annotation().text()) 501 else: 502 template_map['documentation'] = '' 503 template_map['documentation_expr'] = binding_module.literal(None) 504 505 # @todo: Extensions of LIST will be wrong in below 506 507 common_template = ''' 508 """%{documentation}""" 509 510 _ExpandedName = %{expanded_name} 511 _XSDLocation = %{xsd_location} 512 _Documentation = %{documentation_expr} 513 ''' 514 if xs.structures.SimpleTypeDefinition.VARIETY_absent == std.variety(): 515 template = ''' 516 # The ur simple type: %{qname} 517 class %{std} (%{superclasses}): 518 ''' + common_template 519 if not template_map['documentation']: 520 template_map['documentation'] = 'The ur simple type.' 521 elif xs.structures.SimpleTypeDefinition.VARIETY_atomic == std.variety(): 522 template = ''' 523 # Atomic simple type: %{qname} 524 class %{std} (%{superclasses}): 525 ''' + common_template 526 if not template_map['documentation']: 527 template_map['documentation'] = 'An atomic simple type.' 528 elif xs.structures.SimpleTypeDefinition.VARIETY_list == std.variety(): 529 template = ''' 530 # List simple type: %{qname} 531 # superclasses %{superclasses} 532 class %{std} (pyxb.binding.basis.STD_list): 533 ''' + common_template + ''' 534 _ItemType = %{itemtype} 535 ''' 536 template_map['itemtype'] = binding_module.literal(std.itemTypeDefinition(), **kw) 537 if not template_map['documentation']: 538 template_map['documentation'] = templates.replaceInText('Simple type that is a list of %{itemtype}.', **template_map) 539 elif xs.structures.SimpleTypeDefinition.VARIETY_union == std.variety(): 540 template = ''' 541 # Union simple type: %{qname} 542 # superclasses %{superclasses} 543 class %{std} (pyxb.binding.basis.STD_union): 544 ''' + common_template + ''' 545 _MemberTypes = ( %{membertypes}, ) 546 ''' 547 template_map['membertypes'] = ", ".join( [ binding_module.literal(_mt, **kw) for _mt in std.memberTypeDefinitions() ]) 548 if not template_map['documentation']: 549 template_map['documentation'] = templates.replaceInText('Simple type that is a union of %{membertypes}.', **template_map) 550 else: 551 raise pyxb.LogicError("Unhandled STD variety") 552 553 outf.write(templates.replaceInText(template, **template_map)) 554 555 GenerateFacets(std, generator, **kw) 556 557 if std.name() is not None: 558 outf.write(templates.replaceInText("%{namespaceReference}.addCategoryObject('typeBinding', %{localName}, %{std})\n", 559 localName=binding_module.literal(std.name(), **kw), **template_map))
560
561 -def elementDeclarationMap (ed, binding_module, **kw):
562 template_map = { } 563 template_map['qname'] = six.text_type(ed.expandedName()) 564 template_map['decl_location'] = repr2to3(ed._location()) 565 template_map['namespaceReference'] = binding_module.literal(ed.bindingNamespace(), **kw) 566 if (ed.SCOPE_global == ed.scope()): 567 binding_name = template_map['class'] = binding_module.literal(ed, **kw) 568 if ed.expandedName().localName() != binding_name: 569 _log.warning('Element %s renamed to %s', ed.expandedName(), binding_name) 570 template_map['localName'] = binding_module.literal(ed.name(), **kw) 571 template_map['map_update'] = templates.replaceInText("%{namespaceReference}.addCategoryObject('elementBinding', %{localName}, %{class})", **template_map) 572 else: 573 template_map['scope'] = binding_module.literal(ed.scope(), **kw) 574 if ed.annotation() is not None: 575 template_map['documentation'] = binding_module.literal(six.text_type(ed.annotation())) 576 if ed.abstract(): 577 template_map['abstract'] = binding_module.literal(ed.abstract(), **kw) 578 if ed.nillable(): 579 template_map['nillable'] = binding_module.literal(ed.nillable(), **kw) 580 if ed.default(): 581 template_map['defaultValue'] = binding_module.literal(ed.default(), **kw) 582 template_map['typeDefinition'] = binding_module.literal(ed.typeDefinition(), **kw) 583 if ed.substitutionGroupAffiliation(): 584 template_map['substitution_group'] = binding_module.literal(ed.substitutionGroupAffiliation(), **kw) 585 aux_init = [] 586 for k in ( 'nillable', 'abstract', 'scope', 'documentation' ): 587 if k in template_map: 588 aux_init.append('%s=%s' % (k, template_map[k])) 589 aux_init.append('location=%s' % (template_map['decl_location'],)) 590 _VCAppendAuxInit(ed, aux_init, binding_module, kw) 591 template_map['element_aux_init'] = '' 592 if 0 < len(aux_init): 593 template_map['element_aux_init'] = ', ' + ', '.join(aux_init) 594 595 return template_map
596 597 import pyxb.utils.fac 598 import operator 599 import functools
600 601 # A Symbol in the term tree is a pair consisting of the containing 602 # particle (for location information) and one of an 603 # ElementDeclaration, Wildcard, or tuple of sub-term-trees for All 604 # model groups. 605 606 -def BuildTermTree (node):
607 """Construct a L{FAC term tree<pyxb.utils.fac.Node>} for a L{particle<xs.structures.Particle>}. 608 609 This translates the XML schema content model of particles, model 610 groups, element declarations, and wildcards into a tree expressing 611 the corresponding content as a regular expression with numerical 612 constraints. 613 614 @param node: An instance of L{xs.structures.Particle} 615 616 @return: An instance of L{pyxb.utils.fac.Node} 617 """ 618 619 def _generateTermTree_visitor (node, entered, arg): 620 """Helper for constructing a L{FAC term tree<pyxb.utils.fac.Node>}. 621 622 This is passed to L{xs.structures.Particle.walkParticleTree}. 623 624 @param node: An instance of L{xs.structures._ParticleTree_mixin} 625 626 @param entered: C{True} entering an interior tree node, C{False} 627 leaving an interior tree node, C{None} at a leaf node. 628 629 @param arg: A list of pairs C{(particle, terms)} where C{particle} 630 is the L{xs.structures.Particle} instance containing a list of 631 L{term trees<pyxb.utils.fac.Node>}. 632 """ 633 634 if entered is None: 635 (parent_particle, terms) = arg.peekNodeTermPair() 636 assert isinstance(parent_particle, xs.structures.Particle) 637 assert isinstance(node, (xs.structures.ElementDeclaration, xs.structures.Wildcard)) 638 node._setFacStateSortKey(arg.nextSequenceNumber()) 639 terms.append(pyxb.utils.fac.Symbol((parent_particle, node))) 640 elif entered: 641 node._setFacStateSortKey(arg.nextSequenceNumber()) 642 arg.addNode(node) 643 else: 644 (xnode, terms) = arg.popNodeTermPair() 645 assert xnode == node 646 (parent_particle, siblings) = arg.peekNodeTermPair() 647 if 1 == len(terms): 648 term = terms[0] 649 # Either node is a Particle, or it's a single-member model 650 # group. If it's a non-trivial particle we need a 651 # numerical constraint; if it's a single-member model 652 # group or a trivial particle we can use the term 653 # directly. 654 if isinstance(node, xs.structures.Particle) and ((1 != node.minOccurs()) or (1 != node.maxOccurs())): 655 term = pyxb.utils.fac.NumericalConstraint(term, node.minOccurs(), node.maxOccurs(), metadata=node) 656 else: 657 assert isinstance(parent_particle, xs.structures.Particle), 'unexpected %s' % (parent_particle,) 658 assert isinstance(node, xs.structures.ModelGroup) 659 if node.C_CHOICE == node.compositor(): 660 term = pyxb.utils.fac.Choice(*terms, metadata=node) 661 elif node.C_SEQUENCE == node.compositor(): 662 term = pyxb.utils.fac.Sequence(*terms, metadata=node) 663 else: 664 # The quadratic state explosion and need to clone 665 # terms that results from a naive transformation of 666 # unordered catenation to choices among sequences of 667 # nodes and recursively-defined catenation expressions 668 # is not worth the pain. Create a "symbol" for the 669 # state and hold the alternatives in it. 670 assert node.C_ALL == node.compositor() 671 assert functools.reduce(operator.and_, map(lambda _s: isinstance(_s, pyxb.utils.fac.Node), terms), True) 672 term = pyxb.utils.fac.All(*terms, metadata=node) 673 siblings.append(term)
674 675 class TermTreeArg (object): 676 __sequenceNumber = None 677 __termTreeList = None 678 __nodeTermPairs = None 679 def __init__ (self, node): 680 self.__sequenceNumber = 0 681 self.__termTreeList = [] 682 self.__nodeTermPairs = [ (node, self.__termTreeList) ] 683 684 def termTree (self): 685 assert 1 == len(self.__nodeTermPairs) 686 assert 1 == len(self.__termTreeList) 687 return self.__termTreeList[0] 688 689 def peekNodeTermPair (self): 690 return self.__nodeTermPairs[-1] 691 692 def popNodeTermPair (self): 693 return self.__nodeTermPairs.pop() 694 695 def addNode (self, node): 696 self.__nodeTermPairs.append((node, [])) 697 698 def nextSequenceNumber (self): 699 rv = self.__sequenceNumber 700 self.__sequenceNumber += 1 701 return rv 702 703 assert isinstance(node, xs.structures.Particle) 704 ttarg = TermTreeArg(node) 705 node.walkParticleTree(_generateTermTree_visitor, ttarg) 706 term_tree = ttarg.termTree() 707 return term_tree 708
709 -def BuildPluralityData (term_tree):
710 """Walk a term tree to determine which element declarations may 711 appear multiple times. 712 713 The bindings need to use a list for any Python attribute 714 corresponding to an element declaration that can occur multiple 715 times in the content model. The number of occurrences is 716 determined by the occurrence constraints on parent particles and 717 the compositors of containing model groups. All this information 718 is available in the term tree used for the content model 719 automaton. 720 721 @param term_tree: A L{FAC term tree<pyxb.utils.fac.Node>} 722 representing the content model for a complex data type. 723 724 @return: Plurality data, as a pair C{(singles, multiples)} where 725 C{singles} is a set of base L{element 726 declarations<xs.structures.ElementDeclaration>} that are known to 727 occur at least once and at most once in a region of the content, 728 and C{multiples} is a similar set of declarations that are known 729 to potentially occur more than once.""" 730 731 def _ttMergeSets (parent, child): 732 (p1, pm) = parent 733 (c1, cm) = child 734 735 # Anything multiple in the child becomes multiple in the parent. 736 pm.update(cm) 737 738 # Anything independently occuring once in both parent and child 739 # becomes multiple in the parent. 740 pm.update(c1.intersection(p1)) 741 742 # Anything that was single in the parent (child) but is now 743 # multiple is no longer single. 744 p1.difference_update(pm) 745 c1.difference_update(pm) 746 747 # Anything that was single in the parent and also single in the 748 # child is no longer single in the parent. 749 p1.symmetric_difference_update(c1)
750 751 def _ttPrePluralityWalk (node, pos, arg): 752 # If there are multiple children, create a new list on which they 753 # will be placed. 754 if isinstance(node, pyxb.utils.fac.MultiTermNode): 755 arg.append([]) 756 757 def _ttPostPluralityWalk (node, pos, arg): 758 # Initialize a fresh result for this node 759 singles = set() 760 multiples = set() 761 combined = (singles, multiples) 762 if isinstance(node, pyxb.utils.fac.MultiTermNode): 763 # Get the list of children, and examine 764 term_list = arg.pop() 765 if isinstance(node, pyxb.utils.fac.Choice): 766 # For choice we aggregate the singles and multiples 767 # separately. 768 for (t1, tm) in term_list: 769 multiples.update(tm) 770 singles.update(t1) 771 else: 772 # For sequence (ordered or not) we merge the children 773 assert isinstance(node, (pyxb.utils.fac.Sequence, pyxb.utils.fac.All)) 774 for tt in term_list: 775 _ttMergeSets(combined, tt) 776 elif isinstance(node, pyxb.utils.fac.Symbol): 777 (particle, term) = node.metadata 778 if isinstance(term, xs.structures.ElementDeclaration): 779 # One instance of the base declaration for the element 780 singles.add(term.baseDeclaration()) 781 elif isinstance(term, xs.structures.Wildcard): 782 pass 783 else: 784 assert isinstance(term, list) 785 # Unordered catenation is the same as ordered catenation. 786 for tt in term: 787 _ttMergeSets(combined, BuildPluralityData(tt)) 788 else: 789 assert isinstance(node, pyxb.utils.fac.NumericalConstraint) 790 # Grab the data for the topmost tree and adjust it based on 791 # occurrence data. 792 combined = arg[-1].pop() 793 (singles, multiples) = combined 794 if 0 == node.max: 795 # If the node can't match at all, there are no occurrences 796 # at all 797 multiples.clear() 798 singles.clear() 799 elif 1 == node.max: 800 # If the node can only match once, what we've got is right 801 pass 802 else: 803 # If the node can match multiple times, there are no 804 # singles. 805 multiples.update(singles) 806 singles.clear() 807 arg[-1].append(combined) 808 809 # Initialize state with an implied parent that currently has no 810 # children 811 arg = [[]] 812 term_tree.walkTermTree(_ttPrePluralityWalk, _ttPostPluralityWalk, arg) 813 814 # The result term tree is the single child of that implied parent 815 assert 1 == len(arg) 816 arg = arg[0] 817 assert 1 == len(arg) 818 return arg[0] 819
820 -class _CTDAuxData (object):
821 """Helper class holding information need in both preparation and generation.""" 822 823 contentBasis = None 824 termTree = None 825 edSingles = None 826 edMultiples = None 827 automaton = None 828 ctd = None 829
830 - def __init__ (self, ctd):
831 self.ctd = ctd 832 ctd.__auxData = self 833 self.contentBasis = ctd.contentType()[1] 834 if isinstance(self.contentBasis, xs.structures.Particle): 835 self.termTree = BuildTermTree(self.contentBasis) 836 self.automaton = self.termTree.buildAutomaton() 837 (self.edSingles, self.edMultiples) = BuildPluralityData(self.termTree) 838 else: 839 self.edSingles = set() 840 self.edMultiples = set()
841 842 @classmethod
843 - def Create (cls, ctd):
844 return cls(ctd)
845 846 @classmethod
847 - def Get (cls, ctd):
848 return ctd.__auxData
849
850 -def GenerateCTD (ctd, generator, **kw):
851 binding_module = generator.moduleForComponent(ctd) 852 outf = binding_module.bindingIO() 853 854 prolog_template = None 855 template_map = { } 856 binding_name = template_map['ctd'] = binding_module.literal(ctd, **kw) 857 if (ctd.expandedName() is not None) and (ctd.expandedName().localName() != binding_name): 858 _log.warning('Complex type %s renamed to %s', ctd.expandedName(), binding_name) 859 860 base_type = ctd.baseTypeDefinition() 861 content_type_tag = ctd._contentTypeTag() 862 863 template_map['base_type'] = binding_module.literal(base_type, **kw) 864 template_map['namespaceReference'] = binding_module.literal(ctd.bindingNamespace(), **kw) 865 template_map['expanded_name'] = binding_module.literal(ctd.expandedName(), **kw) 866 if ctd.expandedName() is not None: 867 template_map['qname'] = six.text_type(ctd.expandedName()) 868 else: 869 template_map['qname'] = '[anonymous]' 870 template_map['xsd_location'] = repr2to3(ctd._location()) 871 template_map['simple_base_type'] = binding_module.literal(None, **kw) 872 template_map['contentTypeTag'] = content_type_tag 873 template_map['is_abstract'] = repr2to3(not not ctd.abstract()) 874 875 content_basis = None 876 if (ctd.CT_SIMPLE == content_type_tag): 877 content_basis = ctd.contentType()[1] 878 template_map['simple_base_type'] = binding_module.literal(content_basis, **kw) 879 elif (ctd.CT_MIXED == content_type_tag): 880 content_basis = ctd.contentType()[1] 881 elif (ctd.CT_ELEMENT_ONLY == content_type_tag): 882 content_basis = ctd.contentType()[1] 883 884 if ctd.annotation() is not None: 885 template_map['documentation'] = ctd.annotation().asDocString() 886 elif isinstance(ctd.owner(), xs.structures.ElementDeclaration) \ 887 and ctd.owner().annotation() is not None: 888 template_map['documentation'] = ctd.owner().annotation().asDocString() 889 else: 890 template_map['documentation'] = templates.replaceInText("Complex type %{qname} with content type %{contentTypeTag}", **template_map) 891 892 prolog_template = ''' 893 # Complex type %{qname} with content type %{contentTypeTag} 894 class %{ctd} (%{superclass}): 895 """%{documentation}""" 896 _TypeDefinition = %{simple_base_type} 897 _ContentTypeTag = pyxb.binding.basis.complexTypeDefinition._CT_%{contentTypeTag} 898 _Abstract = %{is_abstract} 899 _ExpandedName = %{expanded_name} 900 _XSDLocation = %{xsd_location} 901 ''' 902 903 # Complex types that inherit from non-ur-type complex types should 904 # have their base type as their Python superclass, so pre-existing 905 # elements and attributes can be re-used. 906 inherits_from_base = True 907 template_map['superclass'] = binding_module.literal(base_type, **kw) 908 if ctd._isHierarchyRoot(): 909 inherits_from_base = False 910 template_map['superclass'] = 'pyxb.binding.basis.complexTypeDefinition' 911 assert base_type.nameInBinding() is not None 912 913 if inherits_from_base: 914 prolog_template += ''' _ElementMap = %{superclass}._ElementMap.copy() 915 _AttributeMap = %{superclass}._AttributeMap.copy() 916 ''' 917 else: 918 prolog_template += ''' _ElementMap = {} 919 _AttributeMap = {} 920 ''' 921 922 # Support for deconflicting attributes, elements, and reserved symbols 923 class_keywords = frozenset(basis.complexTypeDefinition._ReservedSymbols) 924 class_unique = set() 925 926 # Deconflict elements first, attributes are lower priority. 927 # Expectation is that all elements that have the same tag in the 928 # XML are combined into the same instance member, even if they 929 # have different types. Determine what name that should be, and 930 # whether there might be multiple instances of elements of that 931 # name. 932 element_uses = [] 933 934 definitions = [] 935 936 definitions.append('# Base type is %{base_type}') 937 938 # Retain in the ctd the information about the element 939 # infrastructure, so it can be inherited where appropriate in 940 # subclasses. 941 942 if isinstance(content_basis, xs.structures.Particle): 943 aux = _CTDAuxData.Get(ctd) 944 elements = aux.edSingles.union(aux.edMultiples) 945 946 outf.postscript().append("\n\n") 947 for ed in sorted(elements, key=lambda _c: _c.schemaOrderSortKey()): 948 is_plural = ed in aux.edMultiples 949 # @todo Detect and account for plurality change between this and base 950 ef_map = ed._templateMap() 951 if ed.scope() == ctd: 952 ef_map.update(elementDeclarationMap(ed, binding_module, **kw)) 953 aux_init = [] 954 ef_map['is_plural'] = repr2to3(is_plural) 955 element_uses.append(templates.replaceInText('%{use}.name() : %{use}', **ef_map)) 956 if 0 == len(aux_init): 957 ef_map['aux_init'] = '' 958 else: 959 ef_map['aux_init'] = ', ' + ', '.join(aux_init) 960 ef_map['element_binding'] = utility.PrepareIdentifier('%s_elt' % (ef_map['id'],), class_unique, class_keywords, private=True) 961 if ed.annotation() is not None: 962 ef_map['documentation'] = binding_module.literal(six.text_type(ed.annotation())) 963 else: 964 ef_map['documentation'] = binding_module.literal(None) 965 if ed.scope() != ctd: 966 definitions.append(templates.replaceInText(''' 967 # Element %{id} (%{qname}) inherited from %{decl_type_en}''', decl_type_en=six.text_type(ed.scope().expandedName()), **ef_map)) 968 continue 969 970 binding_module.importForDeclaration(ed) 971 if ed.expandedName().localName() != ef_map['id']: 972 _log.warning('Element use %s.%s renamed to %s', ctd.expandedName(), ed.expandedName(), ef_map['id']) 973 definitions.append(templates.replaceInText(''' 974 # Element %{qname} uses Python identifier %{id} 975 %{use} = pyxb.binding.content.ElementDeclaration(%{name_expr}, '%{id}', '%{key}', %{is_plural}, %{decl_location}, %{aux_init}) 976 ''', name_expr=binding_module.literal(ed.expandedName(), **kw), **ef_map)) 977 978 definitions.append(templates.replaceInText(''' 979 %{inspector} = property(%{use}.value, %{use}.set, None, %{documentation}) 980 ''', **ef_map)) 981 outf.postscript().append(templates.replaceInText(''' 982 %{ctd}._AddElement(pyxb.binding.basis.element(%{name_expr}, %{typeDefinition}%{element_aux_init})) 983 ''', name_expr=binding_module.literal(ed.expandedName(), **kw), ctd=template_map['ctd'], **ef_map)) 984 985 auto_defn = GenerateAutomaton(ctd, binding_module=binding_module, **kw) 986 if auto_defn is not None: 987 (automaton_ctor, lines) = auto_defn 988 if lines: 989 outf.postscript().append("\n".join(lines)) 990 outf.postscript().append("\n") 991 outf.postscript().append(templates.replaceInText('%{ctd}._Automaton = %{automaton_ctor}\n', ctd=template_map['ctd'], automaton_ctor=automaton_ctor)) 992 outf.postscript().append("\n") 993 994 # Create definitions for all attributes. 995 attribute_uses = [] 996 997 # name - String value of expanded name of the attribute (attr_tag, attr_ns) 998 # name_expr - Python expression for an expanded name identifying the attribute (attr_tag) 999 # use - Binding variable name holding AttributeUse instance (attr_name) 1000 # id - Python identifier for attribute (python_attr_name) 1001 # key - String used as dictionary key holding instance value of attribute (value_attr_name) 1002 # inspector - Name of the method used for inspection (attr_inspector) 1003 # mutator - Name of the method use for mutation (attr_mutator) 1004 for au in sorted(ctd.attributeUses(), key=lambda _au: _au.attributeDeclaration().schemaOrderSortKey()): 1005 ad = au.attributeDeclaration() 1006 assert isinstance(ad.scope(), xs.structures.ComplexTypeDefinition), 'unexpected scope %s' % (ad.scope(),) 1007 au_map = ad._templateMap() 1008 if ad.scope() != ctd: 1009 definitions.append(templates.replaceInText(''' 1010 # Attribute %{id} inherited from %{decl_type_en}''', decl_type_en=six.text_type(ad.scope().expandedName()), **au_map)) 1011 continue 1012 assert isinstance(au_map, dict) 1013 aur = au 1014 while aur.restrictionOf() is not None: 1015 aur = aur.restrictionOf() 1016 if au != aur: 1017 au_map = aur.attributeDeclaration()._templateMap().copy() 1018 definitions.append(templates.replaceInText(''' 1019 # Attribute %{id} is restricted from parent''', **au_map)) 1020 1021 assert ad.typeDefinition() is not None 1022 au_map['attr_type'] = binding_module.literal(ad.typeDefinition(), **kw) 1023 au_map['decl_location'] = repr2to3(ad._location()) 1024 au_map['use_location'] = repr2to3(au._location()) 1025 1026 vc_source = ad 1027 if au.valueConstraint() is not None: 1028 vc_source = au 1029 aux_init = [] 1030 _VCAppendAuxInit(vc_source, aux_init, binding_module, kw) 1031 if au.required(): 1032 aux_init.append('required=True') 1033 if au.prohibited(): 1034 aux_init.append('prohibited=True') 1035 if 0 == len(aux_init): 1036 au_map['aux_init'] = '' 1037 else: 1038 aux_init.insert(0, '') 1039 au_map['aux_init'] = ', '.join(aux_init) 1040 if ad.annotation() is not None: 1041 au_map['documentation'] = binding_module.literal(six.text_type(ad.annotation())) 1042 else: 1043 au_map['documentation'] = binding_module.literal(None) 1044 1045 binding_module.importForDeclaration(ad) 1046 attribute_uses.append(templates.replaceInText('%{use}.name() : %{use}', **au_map)) 1047 if ad.expandedName().localName() != au_map['id']: 1048 _log.warning('Attribute %s.%s renamed to %s', ctd.expandedName(), ad.expandedName(), au_map['id']) 1049 definitions.append(templates.replaceInText(''' 1050 # Attribute %{qname} uses Python identifier %{id} 1051 %{use} = pyxb.binding.content.AttributeUse(%{name_expr}, '%{id}', '%{key}', %{attr_type}%{aux_init}) 1052 %{use}._DeclarationLocation = %{decl_location} 1053 %{use}._UseLocation = %{use_location}''', name_expr=binding_module.literal(ad.expandedName(), **kw), **au_map)) 1054 definitions.append(templates.replaceInText(''' 1055 %{inspector} = property(%{use}.value, %{use}.set, None, %{documentation}) 1056 ''', ctd=template_map['ctd'], **au_map)) 1057 1058 if ctd.attributeWildcard() is not None: 1059 definitions.append('_AttributeWildcard = %s' % (binding_module.literal(ctd.attributeWildcard(), **kw),)) 1060 if ctd.hasWildcardElement(): 1061 definitions.append('_HasWildcardElement = True') 1062 template_map['attribute_uses'] = ",\n ".join(attribute_uses) 1063 template_map['element_uses'] = ",\n ".join(element_uses) 1064 1065 template_map['registration'] = '' 1066 if ctd.name() is not None: 1067 template_map['registration'] = templates.replaceInText("%{namespaceReference}.addCategoryObject('typeBinding', %{localName}, %{ctd})", 1068 localName=binding_module.literal(ctd.name(), **kw), **template_map) 1069 1070 template = ''.join([prolog_template, 1071 " ", "\n ".join(definitions), "\n", 1072 ''' _ElementMap.update({ 1073 %{element_uses} 1074 }) 1075 _AttributeMap.update({ 1076 %{attribute_uses} 1077 }) 1078 %{registration} 1079 1080 ''']) 1081 1082 outf.write(template, **template_map)
1083
1084 -def GenerateED (ed, generator, **kw):
1085 # Unscoped declarations should never be referenced in the binding. 1086 assert ed._scopeIsGlobal() 1087 1088 binding_module = generator.moduleForComponent(ed) 1089 outf = binding_module.bindingIO() 1090 1091 template_map = elementDeclarationMap(ed, binding_module, **kw) 1092 template_map.setdefault('scope', binding_module.literal(None, **kw)) 1093 template_map.setdefault('map_update', '') 1094 1095 binding_module.importForDeclaration(ed) 1096 outf.write(templates.replaceInText(''' 1097 %{class} = pyxb.binding.basis.element(%{name_expr}, %{typeDefinition}%{element_aux_init}) 1098 %{namespaceReference}.addCategoryObject('elementBinding', %{class}.name().localName(), %{class}) 1099 ''', name_expr=binding_module.literal(ed.expandedName(), **kw), **template_map)) 1100 1101 if ed.substitutionGroupAffiliation() is not None: 1102 outf.postscript().append(templates.replaceInText(''' 1103 %{class}._setSubstitutionGroup(%{substitution_group}) 1104 ''', **template_map))
1105
1106 -def _PrepareSimpleTypeDefinition (std, generator, nsm, module_context):
1107 std._templateMap()['_unique'] = nsm.uniqueInClass(std) 1108 if _useEnumerationTags(std): 1109 enum_facet = simpleTypeOwnedEnumerationFacet(std) 1110 if enum_facet is not None: 1111 for ei in six.iteritems(enum_facet): 1112 assert ei.tag() is None, '%s already has a tag' % (ei,) 1113 ei._setTag(utility.PrepareIdentifier(ei.unicodeValue(), nsm.uniqueInClass(std)))
1114
1115 -def _PrepareComplexTypeDefinition (ctd, generator, nsm, module_context):
1116 kw = { 'binding_module' : module_context } 1117 ctd._templateMap()['_unique'] = nsm.uniqueInClass(ctd) 1118 aux = _CTDAuxData.Create(ctd) 1119 multiples = aux.edMultiples 1120 for cd in ctd.localScopedDeclarations(): 1121 _SetNameWithAccessors(cd, ctd, cd in multiples, module_context, nsm, kw)
1122
1123 -def _SetNameWithAccessors (component, container, is_plural, binding_module, nsm, kw):
1124 use_map = component._templateMap() 1125 class_unique = nsm.uniqueInClass(container) 1126 assert isinstance(component, xs.structures._ScopedDeclaration_mixin) 1127 unique_name = utility.PrepareIdentifier(component.expandedName().localName(), class_unique) 1128 use_map['id'] = unique_name 1129 use_map['inspector'] = unique_name 1130 use_map['mutator'] = utility.PrepareIdentifier('set' + unique_name[0].upper() + unique_name[1:], class_unique) 1131 use_map['use'] = utility.MakeUnique('__' + unique_name.strip('_'), class_unique) 1132 assert component._scope() == container 1133 assert component.nameInBinding() is None, 'Use %s but binding name %s for %s' % (use_map['use'], component.nameInBinding(), component.expandedName()) 1134 component.setNameInBinding(use_map['use']) 1135 key_name = six.u('%s_%s_%s') % (six.text_type(nsm.namespace()), container.nameInBinding(), component.expandedName()) 1136 use_map['key'] = utility.PrepareIdentifier(key_name, class_unique, private=True) 1137 use_map['qname'] = six.text_type(component.expandedName()) 1138 if isinstance(component, xs.structures.ElementDeclaration) and is_plural: 1139 use_map['appender'] = utility.PrepareIdentifier('add' + unique_name[0].upper() + unique_name[1:], class_unique) 1140 return use_map
1141
1142 -class BindingIO (object):
1143 __prolog = None 1144 __postscript = None 1145 __templateMap = None 1146 __stringIO = None 1147 __bindingFilePath = None 1148 __bindingFile = None 1149
1150 - def __init__ (self, binding_module, **kw):
1151 super(BindingIO, self).__init__() 1152 self.__bindingModule = binding_module 1153 self.__bindingFilePath = kw['binding_file_path'] 1154 self.__bindingFile = kw['binding_file'] 1155 self.__prolog = [] 1156 self.__postscript = [] 1157 self.__templateMap = kw.copy() 1158 encoding = kw.get('encoding', pyxb._OutputEncoding) 1159 self.__templateMap.update({ 'date' : str(datetime.datetime.now()), 1160 'filePath' : self.__bindingFilePath, 1161 'coding' : encoding, 1162 'binding_module' : binding_module, 1163 'binding_tag' : binding_module.bindingTag(), 1164 'pyxbVersion' : pyxb.__version__, 1165 'pythonVersion' : '.'.join(map(str, sys.version_info))}) 1166 self.__stringIO = io.StringIO() 1167 if self.__bindingFile: 1168 prefacet = self.expand('''# %{filePath} 1169 # -*- coding: %{coding} -*- 1170 # PyXB bindings for %{binding_tag} 1171 # Generated %{date} by PyXB version %{pyxbVersion} using Python %{pythonVersion} 1172 %{binding_preface}''', binding_preface=binding_module.bindingPreface()) 1173 self.__bindingFile.write(prefacet.encode(encoding)) 1174 self.__bindingFile.flush()
1175
1176 - def bindingFile (self):
1177 return self.__bindingFile
1178
1179 - def expand (self, template, **kw):
1180 tm = self.__templateMap.copy() 1181 tm.update(kw) 1182 return templates.replaceInText(template, **tm)
1183
1184 - def write (self, template, **kw):
1185 txt = self.expand(template, **kw) 1186 self.__stringIO.write(txt)
1187
1188 - def bindingModule (self):
1189 return self.__bindingModule
1190 __bindingModule = None 1191
1192 - def prolog (self):
1193 return self.__prolog
1194 - def postscript (self):
1195 return self.__postscript
1196
1197 - def literal (self, *args, **kw):
1198 kw.update(self.__templateMap) 1199 return pythonLiteral(*args, **kw)
1200
1201 - def contents (self):
1202 rv = self.__prolog 1203 rv.append(self.__stringIO.getvalue()) 1204 rv.extend(self.__postscript) 1205 return ''.join(rv)
1206
1207 -class _ModuleNaming_mixin (object):
1208 __anonSTDIndex = None 1209 __anonCTDIndex = None 1210 __uniqueInModule = None 1211 __uniqueInClass = None 1212 __referencedFromClass = None 1213 1214 _UniqueInModule = set([ 'pyxb', 'sys' ]) 1215 """Identifiers that are reserved within a module. 1216 1217 Subclasses extend this with the identifiers they add to the 1218 module. Module-level schema-derived identifiers (such as type 1219 definition and element names) are deconflicted from this set and 1220 from each other.""" 1221 1222 _ReferencedFromClass = set([ 'pyxb', 'sys' ]) 1223 """Identifiers defined in module that are accessed unqualified from class. 1224 1225 These include standard import module names and globals such as 1226 references to namespaces.""" 1227 1228 __ComponentBindingModuleMap = {} 1229
1230 - def generator (self):
1231 return self.__generator
1232 __generator = None 1233
1234 - def __init__ (self, generator, *args, **kw):
1235 super(_ModuleNaming_mixin, self).__init__(*args, **kw) 1236 self.__generator = generator 1237 assert isinstance(self.__generator, Generator) 1238 self.__anonSTDIndex = 1 1239 self.__anonCTDIndex = 1 1240 self.__components = [] 1241 self.__componentNameMap = {} 1242 self.__uniqueInModule = set() 1243 self.__referencedFromClass = self._ReferencedFromClass.copy() 1244 self.__bindingIO = None 1245 self.__importModulePathMap = {} 1246 self.__namespaceDeclarations = [] 1247 self.__referencedNamespaces = {} 1248 self.__uniqueInClass = {}
1249
1250 - def _importModule (self, module):
1251 assert not isinstance(module, pyxb.namespace.Namespace) 1252 assert isinstance(module, (_ModuleNaming_mixin, pyxb.namespace.archive.ModuleRecord)), 'Unexpected type %s' % (type(module),) 1253 if isinstance(module, NamespaceModule): 1254 if pyxb.namespace.XMLSchema == module.namespace(): 1255 return 1256 module = module.moduleRecord() 1257 assert isinstance(module, (pyxb.namespace.archive.ModuleRecord, NamespaceGroupModule)) 1258 if not (module in self.__importModulePathMap): 1259 module_path = module.modulePath() 1260 if 'pyxb' == module_path.split('.', 2)[0]: 1261 assert 'pyxb' in self.uniqueInModule() 1262 assert 'pyxb' in self.__referencedFromClass 1263 module_path = None 1264 else: 1265 module_path = utility.PrepareIdentifier('ImportedBinding_' + module_path.replace('.', '_'), 1266 self.uniqueInModule(), protected=True) 1267 self.__referencedFromClass.add(module_path) 1268 self.__importModulePathMap[module] = module_path
1269
1270 - def uniqueInClass (self, component):
1271 rv = self.__uniqueInClass.get(component) 1272 if rv is None: 1273 rv = set() 1274 rv.update(self.__referencedFromClass) 1275 if isinstance(component, xs.structures.SimpleTypeDefinition): 1276 rv.update(basis.simpleTypeDefinition._ReservedSymbols) 1277 if simpleTypeOwnedEnumerationFacet(component) is not None: 1278 rv.update(basis.enumeration_mixin._ReservedSymbols) 1279 else: 1280 assert isinstance(component, xs.structures.ComplexTypeDefinition) 1281 if component._isHierarchyRoot(): 1282 rv.update(basis.complexTypeDefinition._ReservedSymbols) 1283 else: 1284 base_td = component.baseTypeDefinition() 1285 base_unique = base_td._templateMap().get('_unique') 1286 assert base_unique is not None, 'Base %s of %s has no unique' % (base_td.expandedName(), component.expandedName()) 1287 rv.update(base_unique) 1288 self.__uniqueInClass[component] = rv 1289 return rv
1290 1291 __referencedNamespaces = None 1292
1293 - def bindingIO (self):
1294 return self.__bindingIO
1295 1296 __moduleUID = None
1297 - def moduleUID (self):
1298 if self.__moduleUID is None: 1299 self.__moduleUID = pyxb.utils.utility.HashForText(self._moduleUID_vx()) 1300 return self.__moduleUID
1301
1302 - def _moduleUID_vx (self):
1303 return str(id(self))
1304
1305 - def bindingTag (self):
1306 """Return a distinct string recorded in the first 4096 bytes of the binding file. 1307 1308 This is used to ensure uniqueness and avoid overwriting data 1309 belonging to a different binding. The return value comprises 1310 the class-specialized L{_bindingTagPrefix_vx} with the 1311 L{moduleUID}. 1312 """ 1313 return '%s:%s' % (self._bindingTagPrefix_vx(), self.moduleUID())
1314
1315 - def _bindingTagPrefix_vx (self):
1316 raise pyxb.LogicError('Subclass %s does not define _bindingTagPrefix_vx' % (type(self),))
1317
1318 - def bindingPreface (self):
1319 """Return a block of binding text (comment or code) serving as a preface. 1320 1321 Normally this should describe the module contents.""" 1322 return self._bindingPreface_vx()
1323 - def _bindingPreface_vx (self):
1324 return ''
1325
1326 - def moduleContents (self):
1327 template_map = {} 1328 aux_imports = [] 1329 for (mr, as_path) in six.iteritems(self.__importModulePathMap): 1330 assert self != mr 1331 if as_path is not None: 1332 aux_imports.append('import %s as %s' % (mr.modulePath(), as_path)) 1333 else: 1334 aux_imports.append('import %s' % (mr.modulePath(),)) 1335 template_map['aux_imports'] = "\n".join(aux_imports) 1336 template_map['namespace_decls'] = "\n".join(self.__namespaceDeclarations) 1337 template_map['module_uid'] = self.moduleUID() 1338 template_map['generation_uid_expr'] = repr2to3(self.generator().generationUID()) 1339 self._finalizeModuleContents_vx(template_map) 1340 return self.__bindingIO.contents()
1341
1342 - def modulePath (self):
1343 return self.__modulePath
1344 - def _setModulePath (self, path_data):
1345 (binding_file_path, binding_file, module_path) = path_data 1346 self.__bindingFilePath = binding_file_path 1347 self.__bindingFile = binding_file 1348 if module_path is None: 1349 module_path = self.moduleRecord().modulePath() 1350 if module_path is not None: 1351 self.__modulePath = module_path 1352 kw = self._initialBindingTemplateMap() 1353 self.__bindingIO = BindingIO(self, binding_file=binding_file, binding_file_path=binding_file_path, **kw)
1354 __modulePath = None 1355
1356 - def pathFromImport (self, module, name):
1357 """Python code reference to an object in an imported module""" 1358 if isinstance(module, NamespaceModule): 1359 module = module.moduleRecord() 1360 as_path = self.__importModulePathMap[module] 1361 if as_path is None: 1362 as_path = module.modulePath() 1363 return '%s.%s' % (as_path, name)
1364
1365 - def bindingFile (self):
1366 return self.__bindingFile
1367 __bindingFile = None 1368 __bindingFilePath = None 1369
1370 - def _initializeUniqueInModule (self, unique_in_module):
1371 self.__uniqueInModule = set(unique_in_module)
1372
1373 - def uniqueInModule (self):
1374 return self.__uniqueInModule
1375 1376 @classmethod
1377 - def BindComponentInModule (cls, component, module):
1378 cls.__ComponentBindingModuleMap[component] = module 1379 return module
1380 1381 @classmethod
1382 - def ComponentBindingModule (cls, component):
1383 return cls.__ComponentBindingModuleMap.get(component)
1384 1385 @classmethod
1386 - def _RecordModule (cls, module):
1387 cls.__RecordModuleMap[module.moduleRecord()] = module 1388 return module
1389 @classmethod
1390 - def _ForRecord (cls, module_record):
1391 return cls.__RecordModuleMap.get(module_record)
1392 __RecordModuleMap = { } 1393
1394 - def _bindComponent (self, component):
1395 kw = {} 1396 rv = component.bestNCName() 1397 if rv is None: 1398 if isinstance(component, xs.structures.ComplexTypeDefinition): 1399 rv = utility.PrepareIdentifier('CTD_ANON', self.uniqueInClass(component), protected=True) 1400 elif isinstance(component, xs.structures.SimpleTypeDefinition): 1401 rv = utility.PrepareIdentifier('STD_ANON', self.uniqueInClass(component), protected=True) 1402 else: 1403 assert False 1404 kw['protected'] = True 1405 rv = utility.PrepareIdentifier(rv, self.__uniqueInModule, kw) 1406 assert not component in self.__componentNameMap 1407 self.__components.append(component) 1408 self.__componentNameMap[component] = rv 1409 return rv
1410 - def nameInModule (self, component):
1411 return self.__componentNameMap.get(component)
1412
1413 - def referenceSchemaComponent (self, component):
1414 origin = component._objectOrigin() 1415 assert origin is not None 1416 module_record = origin.moduleRecord() 1417 assert module_record is not None 1418 if self.generator().generationUID() != module_record.generationUID(): 1419 self._importModule(module_record) 1420 return self.pathFromImport(module_record, component.nameInBinding()) 1421 component_module = _ModuleNaming_mixin.ComponentBindingModule(component) 1422 assert component_module is not None, 'No binding module for %s from %s in %s as %s' % (component, module_record, self.moduleRecord(), component.nameInBinding()) 1423 name = component_module.__componentNameMap.get(component) 1424 if name is None: 1425 assert isinstance(self, NamespaceModule) and (self.namespace() == component.bindingNamespace()) 1426 name = component.nameInBinding() 1427 if self != component_module: 1428 self._importModule(component_module) 1429 name = self.pathFromImport(component_module, name) 1430 return name
1431
1432 - def _referencedNamespaces (self): return self.__referencedNamespaces
1433
1434 - def defineNamespace (self, namespace, name, definition=None, **kw):
1435 rv = self.__referencedNamespaces.get(namespace) 1436 assert rv is None, 'Module %s already has reference to %s' % (self, namespace) 1437 # All module-level namespace declarations are reserved. 1438 # Some may have a protected name. The unprotected name 1439 # shall always begin with 'Namespace'. These names may 1440 # be referenced from class implementations as well. 1441 assert name.startswith('Namespace'), 'unexpected %s naming %s' % (name, namespace) 1442 name = utility.PrepareIdentifier(name, self.__uniqueInModule, **kw) 1443 self.__referencedFromClass.add(name) 1444 if definition is None: 1445 if namespace.isAbsentNamespace(): 1446 definition = 'pyxb.namespace.CreateAbsentNamespace()' 1447 else: 1448 definition = 'pyxb.namespace.NamespaceForURI(%s, create_if_missing=True)' % (repr2to3(namespace.uri()),) 1449 self.__namespaceDeclarations.append('%s = %s' % (name, definition)) 1450 self.__namespaceDeclarations.append("%s.configureCategories(['typeBinding', 'elementBinding'])" % (name,)) 1451 self.__referencedNamespaces[namespace] = name 1452 return name
1453
1454 - def referenceNamespace (self, namespace):
1455 rv = self.__referencedNamespaces.get(namespace) 1456 if rv is None: 1457 assert not (isinstance(self, NamespaceModule) and (self.namespace() == namespace)) 1458 assert namespace.isBuiltinNamespace() or not namespace.isUndeclaredNamespace() 1459 if namespace.isBuiltinNamespace(): 1460 rv = namespace.builtinNamespaceRepresentation() 1461 if rv is None: 1462 # Not the local namespace or a built-in. Give it a 1463 # local name, potentially derived from its prefix. 1464 # Then try to find an existing import that defines the 1465 # namespace. Then define the local name within the 1466 # binding, either as a reference to a namespace 1467 # reachable from an import or by doing a runtime 1468 # lookup from the namespace URI if somehow no provider 1469 # has been imported. (This last case should apply 1470 # only to namespace group modules.) 1471 if namespace.prefix(): 1472 nsn = 'Namespace_%s' % (namespace.prefix(),) 1473 else: 1474 nsn = 'Namespace' 1475 nsdef = None 1476 for im in six.iterkeys(self.__importModulePathMap): 1477 if isinstance(im, pyxb.namespace.archive.ModuleRecord): 1478 if im.namespace() == namespace: 1479 nsdef = self.pathFromImport(im, 'Namespace') 1480 break 1481 elif isinstance(im, NamespaceGroupModule): 1482 pass 1483 else: 1484 assert False, 'unexpected import from type %s %s' % (type(im), im,) 1485 # If we failed to identify the namespace in an existing import, 1486 # and this module is not a namespace group which includes the 1487 # namespace as part of its content, something went wrong. 1488 if (nsdef is None) and not (isinstance(self, NamespaceGroupModule) and self.moduleForNamespace(namespace) is not None): 1489 # This can happen if we've got a QName for some namespace for which 1490 # we don't have any information. That's actually OK, so just go 1491 # ahead and define a namespace we can reference. 1492 pass 1493 1494 rv = self.defineNamespace(namespace, nsn, nsdef, protected=True) 1495 assert 0 < len(self.__namespaceDeclarations) 1496 self.__referencedNamespaces[namespace] = rv 1497 return rv
1498
1499 - def importForDeclaration (self, decl):
1500 """Import the binding from which the declaration came. 1501 1502 Figure out where the declaration came from. If it's not part 1503 of this binding, make sure we import the binding associated 1504 with the schema from which it came. We need that, if not for 1505 something in the declaration itself, at least to be able to 1506 get the Namespace for the declaration's name. None of this is 1507 relevant if the declaration has no namespace.""" 1508 sdecl = decl 1509 while sdecl._cloneSource() is not None: 1510 sdecl = sdecl._cloneSource() 1511 assert decl.expandedName() == sdecl.expandedName() 1512 ns = decl.expandedName().namespace() 1513 if ns is None: 1514 return 1515 mr = sdecl._objectOrigin().moduleRecord() 1516 if isinstance(self, NamespaceModule): 1517 need_import = self.moduleRecord().modulePath() != mr.modulePath() 1518 elif isinstance(self, NamespaceGroupModule): 1519 need_import = True 1520 for nm in self.namespaceModules(): 1521 if nm.moduleRecord().modulePath() == mr.modulePath(): 1522 need_import = False 1523 break 1524 else: 1525 raise pyxb.LogicError('Unhandled module naming', self) 1526 if need_import: 1527 self._importModule(mr)
1528
1529 - def literal (self, *args, **kw):
1530 return self.__bindingIO.literal(*args, **kw)
1531
1532 - def addImportsFrom (self, module):
1533 _log.info('Importing to %s from %s', self, module) 1534 self._importModule(module) 1535 for c in self.__components: 1536 local_name = self.nameInModule(c) 1537 assert local_name is not None 1538 rem_name = module.nameInModule(c) 1539 if rem_name is None: 1540 continue 1541 aux = '' 1542 if local_name != rem_name: 1543 aux = ' as %s' % (local_name,) 1544 self.__bindingIO.write("from %s import %s%s # %s\n" % (module.modulePath(), rem_name, aux, c.expandedName()))
1545
1546 - def writeToModuleFile (self):
1547 if self.bindingFile(): 1548 self.bindingFile().write(self.moduleContents().encode(pyxb._OutputEncoding)) 1549 self.bindingFile().close() 1550 _log.info('Saved binding source to %s', self.__bindingFilePath) 1551 else: 1552 _log.info('No binding file for %s', self)
1553
1554 -class NamespaceModule (_ModuleNaming_mixin):
1555 """This class represents a Python module that holds all the 1556 declarations belonging to a specific namespace.""" 1557
1558 - def namespace (self):
1559 return self.__namespace
1560 __namespace = None 1561
1562 - def moduleRecord (self):
1563 return self.__moduleRecord
1564 __moduleRecord = None 1565
1566 - def namespaceGroupModule (self):
1567 return self.__namespaceGroupModule
1568 - def setNamespaceGroupModule (self, namespace_group_module):
1569 self.__namespaceGroupModule = namespace_group_module
1570 __namespaceGroupModule = None 1571 1572 _UniqueInModule = _ModuleNaming_mixin._UniqueInModule.copy() 1573 _UniqueInModule.update([ 'CreateFromDOM', 'CreateFromDocument' ]) 1574
1575 - def namespaceGroupHead (self):
1576 return self.__namespaceGroupHead
1577 __namespaceGroupHead = None 1578 __namespaceGroup = None 1579
1580 - def componentsInNamespace (self):
1581 return self.__components
1582 __components = None 1583 1584 @classmethod
1585 - def ForComponent (cls, component):
1586 return cls.__ComponentModuleMap.get(component)
1587 __ComponentModuleMap = { } 1588
1589 - def _bindingTagPrefix_vx (self):
1590 return 'NM'
1591
1592 - def _bindingPreface_vx (self):
1593 ns = self.namespace() 1594 rvl = ['# Namespace %s' % (ns,)] 1595 if ns.prefix() is not None: 1596 rvl.append(' [xmlns:%s]' % (ns.prefix(),)) 1597 rvl.append('\n') 1598 return ''.join(rvl)
1599
1600 - def _moduleUID_vx (self):
1601 if self.namespace().isAbsentNamespace(): 1602 return 'Absent' 1603 return six.text_type(self.namespace())
1604
1605 - def namespaceGroupMulti (self):
1606 return 1 < len(self.__namespaceGroup)
1607
1608 - def __init__ (self, generator, module_record, mr_scc, components=None, **kw):
1609 super(NamespaceModule, self).__init__(generator, **kw) 1610 self._initializeUniqueInModule(self._UniqueInModule) 1611 self.__moduleRecord = module_record 1612 self.__namespace = self.__moduleRecord.namespace() 1613 self.defineNamespace(self.__namespace, 'Namespace') 1614 self._RecordModule(self) 1615 self.__components = components 1616 # wow! fromkeys actually IS useful! 1617 if self.__components is not None: 1618 self.__ComponentModuleMap.update(dict.fromkeys(self.__components, self)) 1619 self.__namespaceBindingNames = {} 1620 self.__componentBindingName = {} 1621 self._setModulePath(generator.modulePathData(self))
1622
1623 - def _initialBindingTemplateMap (self):
1624 kw = { 'moduleType' : 'namespace' 1625 , 'targetNamespace' : repr2to3(self.__namespace.uri()) 1626 , 'namespaceURI' : self.__namespace.uri() 1627 , 'namespaceReference' : self.referenceNamespace(self.__namespace) 1628 , 'pyxb_version' : repr2to3(pyxb.__version__) 1629 } 1630 return kw
1631
1632 - def _finalizeModuleContents_vx (self, template_map):
1633 template_map['_TextType'] = '_six.text_type' 1634 self.bindingIO().prolog().append(self.bindingIO().expand(''' 1635 from __future__ import unicode_literals 1636 import pyxb 1637 import pyxb.binding 1638 import pyxb.binding.saxer 1639 import io 1640 import pyxb.utils.utility 1641 import pyxb.utils.domutils 1642 import sys 1643 import pyxb.utils.six as _six 1644 1645 # Unique identifier for bindings created at the same time 1646 _GenerationUID = %{generation_uid_expr} 1647 1648 # Version of PyXB used to generate the bindings 1649 _PyXBVersion = %{pyxb_version} 1650 # Generated bindings are not compatible across PyXB versions 1651 if pyxb.__version__ != _PyXBVersion: 1652 raise pyxb.PyXBVersionError(_PyXBVersion) 1653 1654 # Import bindings for namespaces imported into schema 1655 %{aux_imports} 1656 1657 # NOTE: All namespace declarations are reserved within the binding 1658 %{namespace_decls} 1659 1660 def CreateFromDocument (xml_text, default_namespace=None, location_base=None): 1661 """Parse the given XML and use the document element to create a 1662 Python instance. 1663 1664 @param xml_text An XML document. This should be data (Python 2 1665 str or Python 3 bytes), or a text (Python 2 unicode or Python 3 1666 str) in the L{pyxb._InputEncoding} encoding. 1667 1668 @keyword default_namespace The L{pyxb.Namespace} instance to use as the 1669 default namespace where there is no default namespace in scope. 1670 If unspecified or C{None}, the namespace of the module containing 1671 this function will be used. 1672 1673 @keyword location_base: An object to be recorded as the base of all 1674 L{pyxb.utils.utility.Location} instances associated with events and 1675 objects handled by the parser. You might pass the URI from which 1676 the document was obtained. 1677 """ 1678 1679 if pyxb.XMLStyle_saxer != pyxb._XMLStyle: 1680 dom = pyxb.utils.domutils.StringToDOM(xml_text) 1681 return CreateFromDOM(dom.documentElement, default_namespace=default_namespace) 1682 if default_namespace is None: 1683 default_namespace = Namespace.fallbackNamespace() 1684 saxer = pyxb.binding.saxer.make_parser(fallback_namespace=default_namespace, location_base=location_base) 1685 handler = saxer.getContentHandler() 1686 xmld = xml_text 1687 if isinstance(xmld, %{_TextType}): 1688 xmld = xmld.encode(pyxb._InputEncoding) 1689 saxer.parse(io.BytesIO(xmld)) 1690 instance = handler.rootObject() 1691 return instance 1692 1693 def CreateFromDOM (node, default_namespace=None): 1694 """Create a Python instance from the given DOM node. 1695 The node tag must correspond to an element declaration in this module. 1696 1697 @deprecated: Forcing use of DOM interface is unnecessary; use L{CreateFromDocument}.""" 1698 if default_namespace is None: 1699 default_namespace = Namespace.fallbackNamespace() 1700 return pyxb.binding.basis.element.AnyCreateFromDOM(node, default_namespace) 1701 1702 ''', **template_map))
1703 1704 __components = None 1705 __componentBindingName = None 1706
1707 - def bindComponent (self, component):
1708 ns_name = self._bindComponent(component) 1709 component.setNameInBinding(ns_name) 1710 binding_module = self 1711 if self.__namespaceGroupModule: 1712 self.__namespaceGroupModule._bindComponent(component) 1713 binding_module = self.__namespaceGroupModule 1714 return _ModuleNaming_mixin.BindComponentInModule(component, binding_module)
1715
1716 - def __str__ (self):
1717 return 'NM:%s@%s' % (self.namespace(), self.modulePath())
1718
1719 -class NamespaceGroupModule (_ModuleNaming_mixin):
1720 """This class represents a Python module that holds all the 1721 declarations belonging to a set of namespaces which have 1722 interdependencies.""" 1723
1724 - def namespaceModules (self):
1725 return self.__namespaceModules
1726 __namespaceModules = None 1727
1728 - def moduleForNamespace (self, namespace):
1729 for nm in self.__namespaceModules: 1730 if nm.namespace() == namespace: 1731 return nm 1732 return None
1733 1734 __components = None 1735 __componentBindingName = None 1736 __uniqueInModule = None 1737 1738 __UniqueInGroups = set() 1739 1740 _GroupPrefix = '_group' 1741
1742 - def __init__ (self, generator, namespace_modules, **kw):
1743 super(NamespaceGroupModule, self).__init__(generator, **kw) 1744 assert 1 < len(namespace_modules) 1745 self.__namespaceModules = namespace_modules 1746 self.__namespaceGroupHead = namespace_modules[0].namespaceGroupHead() 1747 self._initializeUniqueInModule(self._UniqueInModule) 1748 self._setModulePath(generator.modulePathData(self))
1749
1750 - def _initialBindingTemplateMap (self):
1751 kw = { 'moduleType' : 'namespaceGroup' } 1752 return kw
1753
1754 - def _bindingTagPrefix_vx (self):
1755 return 'NGM'
1756
1757 - def _bindingPreface_vx (self):
1758 rvl = ['# Group contents:\n' ] 1759 for nsm in self.namespaceModules(): 1760 rvl.append(nsm.bindingPreface()) 1761 rvl.append('\n') 1762 return ''.join(rvl)
1763
1764 - def _finalizeModuleContents_vx (self, template_map):
1765 self.bindingIO().prolog().append(self.bindingIO().expand(''' 1766 from __future__ import unicode_literals 1767 import pyxb 1768 import pyxb.binding 1769 import pyxb.utils.utility 1770 import pyxb.utils.six as _six 1771 1772 # Unique identifier for bindings created at the same time 1773 _GenerationUID = %{generation_uid_expr} 1774 1775 # Import bindings for schemas in group 1776 %{aux_imports} 1777 1778 # NOTE: All namespace declarations are reserved within the binding 1779 %{namespace_decls} 1780 ''', **template_map))
1781
1782 - def _moduleUID_vx (self):
1783 nss = [] 1784 for nsm in self.namespaceModules(): 1785 ns = nsm.namespace() 1786 if ns.isAbsentNamespace(): 1787 nss.append('Absent') 1788 else: 1789 nss.append(six.text_type(ns)) 1790 nss.sort() 1791 return six.u(';').join(nss)
1792
1793 - def __str__ (self):
1794 return 'NGM:%s' % (self.modulePath(),)
1795
1796 1797 -def GeneratePython (schema_location=None, 1798 schema_text=None, 1799 namespace=None, 1800 module_prefix_elts=[], 1801 **kw):
1802 1803 generator = Generator(allow_absent_module=True, generate_to_files=False, **kw) 1804 if schema_location is not None: 1805 generator.addSchemaLocation(schema_location) 1806 elif schema_text is not None: 1807 generator.addSchema(schema_text) 1808 modules = generator.bindingModules() 1809 1810 assert 1 == len(modules), '%s produced %d modules: %s' % (namespace, len(modules), six.u(' ').join([ six.text_type(_m) for _m in modules])) 1811 return modules.pop().moduleContents()
1812 1813 import optparse 1814 import re
1815 1816 -class Generator (object):
1817 """Configuration and data for a single binding-generation action.""" 1818 1819 _DEFAULT_bindingRoot = '.'
1820 - def bindingRoot (self):
1821 """The directory path into which generated bindings will be written. 1822 @rtype: C{str}""" 1823 return self.__bindingRoot
1824 - def setBindingRoot (self, binding_root):
1825 self.__bindingRoot = binding_root 1826 return self
1827 __bindingRoot = None 1828
1829 - def __moduleFilePath (self, module_elts, inhibit_extension=False):
1830 if isinstance(module_elts, six.string_types): 1831 module_elts = module_elts.split('.') 1832 else: 1833 module_elts = module_elts[:] 1834 assert 0 < len(module_elts) 1835 if not inhibit_extension: 1836 assert not module_elts[-1].endswith('.py') 1837 module_elts[-1] = '%s.py' % (module_elts[-1],) 1838 return os.path.join(self.bindingRoot(), *module_elts)
1839
1840 - def generateToFiles (self):
1841 return self.__generateToFiles
1842 __generateToFiles = None 1843
1844 - def modulePathData (self, module):
1845 # file system path to where the bindings are written 1846 # module path from which the bindings are normally imported 1847 # file object into which bindings are written 1848 1849 module_path = None 1850 if isinstance(module, NamespaceModule): 1851 mr = module.moduleRecord() 1852 if mr is None: 1853 return ('/dev/null', None, None) 1854 if self.generationUID() != mr.generationUID(): 1855 return ('/dev/null', None, None) 1856 if not self.generateToFiles(): 1857 return ('/dev/null', None, None) 1858 if mr.namespace().isBuiltinNamespace() and (not self.allowBuiltinGeneration()): 1859 return ('/dev/null', None, None) 1860 module_path = mr.modulePath() 1861 assert module_path is not None, 'No path specified for module %s' % (mr,) 1862 #if pyxb.namespace.XMLSchema != ns: 1863 # return ('/dev/null', None, None) 1864 #module_path="bogus.xsd" 1865 module_elts = module_path.split('.') 1866 if self.writeForCustomization(): 1867 import_file_path = self.__moduleFilePath(module_elts) 1868 module_elts.insert(-1, 'raw') 1869 if not os.path.exists(import_file_path): 1870 raw_module_path = '.'.join(module_elts) 1871 fd = pyxb.utils.utility.OpenOrCreate(import_file_path) 1872 impt = '''# -*- coding: utf-8 -*- 1873 from %s import * 1874 ''' % (raw_module_path,) 1875 impd = impt.encode('utf-8') 1876 fd.write(impd) 1877 fd.close() 1878 binding_file_path = self.__moduleFilePath(module_elts) 1879 try: 1880 binding_file = pyxb.utils.utility.OpenOrCreate(binding_file_path, tag=module.moduleUID()) 1881 except OSError as e: 1882 if errno.EEXIST == e.errno: 1883 raise pyxb.BindingGenerationError('Target file %s for module %s bindings exists with other content' % (binding_file_path, mr)) 1884 raise 1885 elif isinstance(module, NamespaceGroupModule): 1886 if not self.generateToFiles(): 1887 raise pyxb.BindingGenerationError('Generation of namespace groups requires generate-to-files') 1888 module_elts = [] 1889 if self.modulePrefix(): 1890 module_elts.extend(self.modulePrefix().split('.')) 1891 if self.writeForCustomization(): 1892 module_elts.append('raw') 1893 in_use = set() 1894 while True: 1895 module_elts.append(pyxb.utils.utility.PrepareIdentifier('nsgroup', in_use, protected=True)) 1896 try: 1897 binding_file_path = self.__moduleFilePath(module_elts) 1898 _log.info('Attempting group %s uid %s at %s', module, module.moduleUID(), binding_file_path) 1899 binding_file = pyxb.utils.utility.OpenOrCreate(binding_file_path, tag=module.moduleUID()) 1900 break 1901 except OSError as e: 1902 if errno.EEXIST != e.errno: 1903 raise 1904 module_elts.pop() 1905 module_path = '.'.join(module_elts) 1906 else: 1907 assert False 1908 if self.generateToFiles(): 1909 for n in range(len(module_elts)-1): 1910 sub_path = self.__moduleFilePath(module_elts[:1+n], inhibit_extension=True) 1911 init_path = os.path.join(sub_path, '__init__.py') 1912 if not os.path.exists(init_path): 1913 open(init_path, 'w') 1914 return (binding_file_path, binding_file, module_path)
1915
1916 - def schemaRoot (self):
1917 """The directory from which entrypoint schemas specified as 1918 relative file paths will be read.""" 1919 return self.__schemaRoot
1920 - def setSchemaRoot (self, schema_root):
1921 if not schema_root.endswith(os.sep): 1922 schema_root = schema_root + os.sep 1923 self.__schemaRoot = schema_root 1924 return self
1925 __schemaRoot = None 1926
1927 - def schemaStrippedPrefix (self):
1928 """Optional string that is stripped from the beginning of 1929 schemaLocation values before loading from them. 1930 1931 This applies only to the values of schemaLocation attributes 1932 in C{import} and C{include} elements. Its purpose is to 1933 convert absolute schema locations into relative ones to allow 1934 offline processing when all schema are available in a local 1935 directory. See C{schemaRoot}. 1936 """ 1937 return self.__schemaStrippedPrefix
1938 - def setSchemaStrippedPrefix (self, schema_stripped_prefix):
1939 self.__schemaStrippedPrefix = schema_stripped_prefix 1940 return self
1941 __schemaStrippedPrefix = None 1942
1943 - def locationPrefixRewriteMap (self):
1944 """Optional map to rewrite schema locations. 1945 1946 This applies only to the values of schemaLocation attributes 1947 in C{import} and C{include} elements. Its purpose is to 1948 convert remote or absolute schema locations into local or 1949 relative ones to allow offline processing when all schema are 1950 available in a local directory. See C{schemaRoot}. 1951 """ 1952 return self.__locationPrefixRewriteMap
1953 - def setLocationPrefixRewriteMap (self, location_prefix_rewrite_map):
1954 self.__locationPrefixMap.clear() 1955 self.__locationPrefixMap.update(location_prefix_rewrite_map) 1956 return self
1957 - def addLocationPrefixRewrite (self, prefix, substituent):
1958 """Add a rewrite entry for schema locations. 1959 1960 @param prefix : A text prefix that should be removed from 1961 schema location URIs. 1962 1963 @param substituent : The text prefix that should replace 1964 C{prefix} as a prefix in a schema location URI. 1965 """ 1966 1967 self.__locationPrefixRewriteMap[prefix] = substituent 1968 return self
1969 - def argAddLocationPrefixRewrite (self, prefix_rewrite):
1970 """Add a rewrite entry for schema locations. 1971 1972 Parameter values are strings of the form C{pfx=sub}. The 1973 effect is that a schema location that begins with C{pfx} is 1974 rewritten so that it instead begins with C{sub}.""" 1975 try: 1976 (prefix, substituent) = prefix_rewrite.split('=', 1) 1977 except: 1978 raise 1979 self.addLocationPrefixRewrite(prefix, substituent)
1980 __locationPrefixMap = {} 1981
1982 - def schemaLocationList (self):
1983 """A list of locations from which entrypoint schemas are to be 1984 read. 1985 1986 The values in the list are either URIs, or tuples consisting 1987 of a value and a callable which, when passed the generator 1988 object and the value, will return a 1989 L{pyxb.xmlschema.structures.Schema} instance. See 1990 L{addSchemaLocation}. 1991 1992 See also L{addSchemaLocation} and L{schemas}. 1993 """ 1994 return self.__schemaLocationList
1995 - def setSchemaLocationList (self, schema_location_list):
1996 self.__schemaLocationList[:] = [] 1997 self.__schemaLocationList.extend(schema_location_list) 1998 return self
1999 - def addSchemaLocation (self, schema_location, converter=None):
2000 """Add the location of an entrypoint schema. 2001 2002 @param schema_location: The location of the schema. This 2003 should be a URL; if the schema location does not have a URL 2004 scheme (e.g., C{http:}), it is assumed to be a file, and if it 2005 is not an absolute path is located relative to the 2006 C{schemaRoot}. 2007 2008 @keyword converter: Optional callable that will be invoked 2009 with the generator instance and the schema location, and is 2010 expected to return a L{pyxb.xmlschema.structures.Schema} 2011 instance. If absent, the contents of the location are 2012 converted directly. 2013 2014 @note: The C{converter} argument derives from WSDL support: we 2015 need to add to the sequence of schema locations a URI of 2016 something that will not parse as a schema, but does have inner 2017 material that can if treated properly. "Treated properly" may 2018 include having the archive path and other namespace 2019 manipulations configured before anything is done to it. 2020 """ 2021 self.__schemaLocationList.append( (schema_location, converter) ) 2022 return self
2023 - def argAddSchemaLocation (self, schema_location):
2024 """Add the location of an entrypoint schema. The provided 2025 value should be a URL; if it does not have a URL scheme (e.g., 2026 C{http:}), it is assumed to be a file, and if it is not an 2027 absolute path is located relative to the C{schemaRoot}.""" 2028 self.addSchemaLocation(schema_location)
2029 __schemaLocationList = None 2030
2031 - def schemas (self):
2032 """Schema for which bindings should be generated. 2033 2034 These may be L{Schema<pyxb.xmlschema.structures.Schema>} 2035 instances, or strings; the latter is preferred, and is parsed 2036 into a Schema instance when required. 2037 2038 This is the list of entrypoint schemas for binding generation. 2039 Values in L{schemaLocationList} are read and converted into 2040 schema, then appended to this list. Values from L{moduleList} 2041 are applied starting with the first schema in this list. 2042 """ 2043 return self.__schemas[:]
2044 - def setSchemas (self, schemas):
2045 self.__schemas[:] = [] 2046 self.__schemas.extend(schemas) 2047 return self
2048 - def addSchema (self, schema):
2049 self.__schemas.append(schema) 2050 return self
2051 __schemas = None 2052
2053 - def namespaces (self):
2054 """The set of L{namespaces<pyxb.namespace.Namespace>} for 2055 which bindings will be generated. 2056 2057 This is the set of namespaces read from entrypoint schema, 2058 closed under reference to namespaces defined by schema import. 2059 2060 @rtype: C{set} 2061 """ 2062 return self.__namespaces.copy()
2063 - def setNamespaces (self, namespace_set):
2064 self.__namespaces.clear() 2065 self.__namespaces.update(namespace_set) 2066 return self
2067 - def addNamespace (self, namespace):
2068 self.__namespaces.add(namespace) 2069 return self
2070 __namespaces = None 2071
2072 - def moduleList (self):
2073 """A list of module names to be applied in order to the namespaces of entrypoint schemas""" 2074 return self.__moduleList[:]
2075 - def _setModuleList (self, module_list):
2076 self.__moduleList[:] = [] 2077 self.__moduleList.extend(module_list) 2078 return self
2079
2080 - def addModuleName (self, module_name):
2081 """Add a module name corresponding to an entrypoint schema. 2082 2083 The namespace defined by the corresponding schema will be 2084 written to a binding using the given module name, adjusted by 2085 L{modulePrefix}.""" 2086 self.__moduleList.append(module_name) 2087 return self
2088 __moduleList = None 2089
2090 - def modulePrefix (self):
2091 """The prefix for binding modules. 2092 2093 The base name for the module holding a binding is taken from 2094 the moduleList, moduleMap, or an XMLNS prefix associated with 2095 the namespace in a containing schema. This value, if present, 2096 is used as a prefix to allow a deeper module hierarchy.""" 2097 return self.__modulePrefix
2098 - def setModulePrefix (self, module_prefix):
2099 self.__modulePrefix = module_prefix 2100 return self
2101 __modulePrefix = None 2102
2103 - def namespaceModuleMap (self):
2104 """A map from namespace URIs to the module to be used for the 2105 corresponding generated binding. 2106 2107 Module values are adjusted by L{modulePrefix} if that has been 2108 specified. 2109 2110 An entry in this map for a namespace supersedes the module 2111 specified in moduleList if the namespace is defined by an 2112 entrypoint schema. 2113 2114 @return: A reference to the namespace module map. 2115 """ 2116 return self.__namespaceModuleMap
2117 __namespaceModuleMap = None 2118
2119 - def archivePath (self):
2120 """A colon-separated list of paths from which namespace 2121 archives can be read. 2122 2123 The default path is the contents of the C{PYXB_ARCHIVE_PATH} 2124 environment variable, or the standard path configured at 2125 installation time. Any file with the extension C{.wxs} found 2126 in one of these directories is examined to see whether it is a 2127 namespace archive. 2128 """ 2129 return self.__archivePath
2130 - def setArchivePath (self, archive_path):
2131 self.__archivePath = archive_path 2132 return self
2133 __archivePath = None 2134
2135 - def noLoadNamespaces (self):
2136 """A frozenset of namespaces that must not be loaded from an archive.""" 2137 return frozenset(self.__noLoadNamespaces)
2138 - def _setNoLoadNamespaces (self, namespace_set):
2139 """Record the set of namespaces that should not be loaded from an archive. 2140 2141 The expectation is that any required entities in the namespace 2142 will be defined by loading schema.""" 2143 self.__noLoadNamespaces.clear() 2144 self.__noLoadNamespaces.update([ pyxb.namespace.NamespaceInstance(_ns) for _ns in namespace_set ])
2145 - def addNoLoadNamespace (self, namespace):
2146 """Mark that the specified namespace should not be loaded from an archive. 2147 2148 Use this when you are generating bindings for an application 2149 that has a restricted profile of a namespace that would 2150 otherwise be read from an archive. Be aware that this removes 2151 any knowledge of any archive in which this namespace is 2152 present as a non-private member.""" 2153 self.__noLoadNamespaces.add(pyxb.namespace.NamespaceInstance(namespace))
2154 __noloadNamespaces = None 2155
2156 - def importAugmentableNamespaces (self):
2157 """A list of namespaces for which new bindings are allowd.""" 2158 return frozenset(self.__importAugmentableNamespaces)
2159 - def _setImportAugmentableNamespaces (self, namespace_set):
2160 """Return the set of namespaces that may be augmented by import directives.""" 2161 self.__importAugmentableNamespaces.clear() 2162 self.__importAugmentableNamespaces.update([ pyxb.namespace.NamespaceInstance(_ns) for _ns in namespace_set ])
2163 - def addImportAugmentableNamespace (self, namespace):
2164 """Mark that the specified namespace may be imported by new bindings. 2165 2166 Normally namespaces that are available from archives are 2167 considered to be complete, and schema locations in import 2168 directives are ignored. Use this to indicate that the 2169 bindings being generated import new bindings. 2170 2171 Note that attempts to import schema that contributed to the 2172 archive will only be detected if the archive was generated 2173 from the same schemaLocation URI; if the archive was generated 2174 from a different source component definitions might 2175 conflict.""" 2176 self.__importAugmentableNamespaces.add(pyxb.namespace.NamespaceInstance(namespace))
2177 __importAugmentableNamespaces = None 2178
2179 - def archiveToFile (self):
2180 """Optional file into which the archive of namespaces will be written. 2181 2182 Subsequent generation actions can read pre-parsed namespaces 2183 from this file, and therefore reference the bindings that were 2184 built earlier rather than re-generating them. 2185 2186 The file name should normally end with C{.wxs}.""" 2187 return self.__archiveToFile
2188 - def setArchiveToFile (self, archive_to_file):
2189 self.__archiveToFile = archive_to_file 2190 return self
2191 __archiveToFile = None 2192
2193 - def setNamespaceVisibility (self, namespace, visibility):
2197 - def _setNamespaceVisibilities (self, public, private):
2198 if public is None: 2199 public = set() 2200 if private is None: 2201 private = set() 2202 self.__namespaceVisibilityMap.clear() 2203 self.__namespaceVisibilityMap.update(dict.fromkeys(public, True)) 2204 self.__namespaceVisibilityMap.update(dict.fromkeys(private, False))
2205 - def namespaceVisibilityMap (self):
2206 """Indicates, for specific namespaces, whether their 2207 visibility in the archive should be public or private.""" 2208 return self.__namespaceVisibilityMap.copy()
2209 __namespaceVisibilityMap = None 2210
2211 - def defaultNamespacePublic (self):
2212 """Indicates whether unmentioned namespaces will be public or private (default) in the archive. 2213 2214 A namespace is I{mentioned} if it is the target namespace of 2215 an entrypoint schema, or appears in a namespace visibility 2216 specification. I.e., this default applies only to namespaces 2217 that are modified as a result of including some schema, which 2218 is generally a local customization of something. 2219 """ 2220 return self.__defaultNamespacePublic
2221 - def setDefaultNamespacePublic (self, default_namespace_public):
2222 self.__defaultNamespacePublic = default_namespace_public
2223 __defaultNamespacePublic = None 2224
2225 - def validateChanges (self):
2226 """Indicates whether the bindings should validate mutations 2227 against the content model.""" 2228 return self.__validateChanges
2229 - def setValidateChanges (self, validate_changes):
2230 self.__validateChanges = validate_changes 2231 return self
2232 __validateChanges = None 2233
2234 - def writeForCustomization (self):
2235 """Indicates whether the binding Python code should be written into a sub-module for customization. 2236 2237 If enabled, a module C{path.to.namespace} will be written to 2238 the file C{path/to/raw/namespace.py}, so that the file 2239 C{path/to/namespace.py} can import it and override behavior.""" 2240 return self.__writeForCustomization
2241 - def setWriteForCustomization (self, write_for_customization):
2242 self.__writeForCustomization = write_for_customization 2243 return self
2244 __writeForCustomization = None 2245
2246 - def allowAbsentModule (self):
2247 """Indicates whether the code generator is permitted to 2248 process namespace for which no module path can be determined. 2249 2250 Use this only when generating bindings that will not be 2251 referenced by other bindings.""" 2252 return self.__allowAbsentModule
2253 - def setAllowAbsentModule (self, allow_absent_module):
2254 self.__allowAbsentModule = allow_absent_module 2255 return self
2256 __allowAbsentModule = None 2257
2258 - def allowBuiltinGeneration (self):
2259 """Indicates whether bindings will be written for namespaces that are built-in to PyXB. 2260 2261 This must be enabled when building bindings for the XML, 2262 XMLSchema instance, and other built-in namespaces. Normally 2263 generation of these namespaces is inhibited lest it produce 2264 inconsistencies.""" 2265 return self.__allowBuiltinGeneration
2266 - def setAllowBuiltinGeneration (self, allow_builtin_generation):
2267 self.__allowBuiltinGeneration = allow_builtin_generation 2268 return self
2269 __allowBuiltinGeneration = None 2270
2271 - def uriContentArchiveDirectory (self):
2272 """The directory path into which any content retrieved by URI will be written. 2273 2274 This serves as a local cache, and to give you an opportunity 2275 to inspect material retrieved from some other system. 2276 @rtype: C{str}""" 2277 return self.__uriContentArchiveDirectory
2278 - def setUriContentArchiveDirectory (self, ucad):
2280 __uriContentArchiveDirectory = None 2281
2282 - def loggingConfigFile (self):
2283 """A file provided to L{logging.config.fileConfig} to control log messages. 2284 2285 In the absence of other configuration the Python standard logging infrastructure is used in its 2286 default configuration. 2287 2288 @rtype: C{str}""" 2289 return self.__loggingConfigFile
2290 - def setLoggingConfigFile (self, logging_config_file):
2291 self.__loggingConfigFile = logging_config_file
2292 __loggingConfigFile = None 2293
2294 - def __init__ (self, *args, **kw):
2295 """Create a configuration to be used for generating bindings. 2296 2297 Arguments are treated as additions to the schema location list 2298 after all keywords have been processed. 2299 2300 @keyword binding_root: Invokes L{setBindingRoot} 2301 @keyword schema_root: Invokes L{setSchemaRoot} 2302 @keyword schema_stripped_prefix: Invokes L{setSchemaStrippedPrefix} 2303 @keyword location_prefix_rewrite_map: Invokes L{setLocationPrefixRewriteMap} 2304 @keyword schema_location_list: Invokes L{setSchemaLocationList} 2305 @keyword module_list: Invokes L{_setModuleList} 2306 @keyword module_prefix: Invokes L{setModulePrefix} 2307 @keyword archive_path: Invokes L{setArchivePath} 2308 @keyword no_load_namespaces: Invokes L{_setNoLoadNamespaces} 2309 @keyword import_augmentable_namespaces: Invokes L{_setImportAugmentableNamespaces} 2310 @keyword archive_to_file: Invokes L{setArchiveToFile} 2311 @keyword public_namespace: Invokes L{setNamespaceVisibility} 2312 @keyword private_namespace: Invokes L{setNamespaceVisibility} 2313 @keyword default_namespace_public: Invokes L{setDefaultNamespacePublic} 2314 @keyword validate_changes: Invokes L{setValidateChanges} 2315 @keyword namespace_module_map: Initializes L{namespaceModuleMap} 2316 @keyword schemas: Invokes L{setSchemas} 2317 @keyword namespaces: Invokes L{setNamespaces} 2318 @keyword write_for_customization: Invokes L{setWriteForCustomization} 2319 @keyword allow_builtin_generation: Invokes L{setAllowBuiltinGeneration} 2320 @keyword allow_absent_module: Invokes L{setAllowAbsentModule} 2321 @keyword generate_to_files: Sets L{generateToFiles} 2322 @keyword uri_content_archive_directory: Invokes L{setUriContentArchiveDirectory} 2323 @keyword logging_config_file: Invokes L{setLoggingConfigFile} 2324 """ 2325 argv = kw.get('argv') 2326 if argv is not None: 2327 kw = {} 2328 self.__bindingRoot = kw.get('binding_root', self._DEFAULT_bindingRoot) 2329 self.__schemaRoot = kw.get('schema_root', '.') 2330 self.__schemaStrippedPrefix = kw.get('schema_stripped_prefix') 2331 self.__locationPrefixRewriteMap = kw.get('location_prefix_rewrite_map', {}) 2332 self.__schemas = [] 2333 self.__schemaLocationList = kw.get('schema_location_list', [])[:] 2334 self.__moduleList = kw.get('module_list', [])[:] 2335 self.__modulePrefix = kw.get('module_prefix') 2336 self.__archivePath = kw.get('archive_path', pyxb.namespace.archive.GetArchivePath()) 2337 self.__noLoadNamespaces = kw.get('no_load_namespaces', set()).copy() 2338 self.__importAugmentableNamespaces = kw.get('import_augmentable_namespaces', set()).copy() 2339 self.__archiveToFile = kw.get('archive_to_file') 2340 self.__namespaceVisibilityMap = {} 2341 self._setNamespaceVisibilities(kw.get('public_namespaces', set()), kw.get('private_namespaces', set())) 2342 self.__defaultNamespacePublic = kw.get('default_namespace_public', False) 2343 self.__validateChanges = kw.get('validate_changes', True) 2344 self.__namespaceModuleMap = kw.get('namespace_module_map', {}).copy() 2345 self.__schemas = kw.get('schemas', [])[:] 2346 self.__namespaces = set(kw.get('namespaces', [])) 2347 self.__writeForCustomization = kw.get('write_for_customization', False) 2348 self.__allowBuiltinGeneration = kw.get('allow_builtin_generation', False) 2349 self.__allowAbsentModule = kw.get('allow_absent_module', False) 2350 self.__generateToFiles = kw.get('generate_to_files', True) 2351 self.__uriContentArchiveDirectory = kw.get('uri_content_archive_directory') 2352 self.__loggingConfigFile = kw.get('logging_config_file') 2353 self.__unnamedModulePaths = set() 2354 2355 if argv is not None: 2356 self.applyOptionValues(*self.optionParser().parse_args(argv)) 2357 [ self.addSchemaLocation(_a) for _a in args ] 2358 2359 self.__generationUID = pyxb.utils.utility.UniqueIdentifier() 2360 2361 pyxb.namespace.XML.validateComponentModel()
2362 2363 __stripSpaces_re = re.compile('\s\s\s+')
2364 - def __stripSpaces (self, string):
2365 return self.__stripSpaces_re.sub(' ', string)
2366 2367 __OptionSetters = ( 2368 ('binding_root', setBindingRoot), 2369 ('schema_root', setSchemaRoot), 2370 ('schema_stripped_prefix', setSchemaStrippedPrefix), 2371 ('location_prefix_rewrite', argAddLocationPrefixRewrite), 2372 ('schema_location', setSchemaLocationList), 2373 ('module', _setModuleList), 2374 ('module_prefix', setModulePrefix), 2375 ('archive_path', setArchivePath), 2376 ('no_load_namespace', _setNoLoadNamespaces), 2377 ('import_augmentable_namespace', _setImportAugmentableNamespaces), 2378 ('archive_to_file', setArchiveToFile), 2379 ('default_namespace_public', setDefaultNamespacePublic), 2380 ('validate_changes', setValidateChanges), 2381 ('write_for_customization', setWriteForCustomization), 2382 ('allow_builtin_generation', setAllowBuiltinGeneration), 2383 ('allow_absent_module', setAllowAbsentModule), 2384 ('uri_content_archive_directory', setUriContentArchiveDirectory), 2385 ('logging_config_file', setLoggingConfigFile) 2386 )
2387 - def applyOptionValues (self, options, args=None):
2388 for (tag, method) in self.__OptionSetters: 2389 v = getattr(options, tag) 2390 if v is not None: 2391 method(self, v) 2392 public_namespaces = getattr(options, 'public_namespace') 2393 private_namespaces = getattr(options, 'private_namespace') 2394 self._setNamespaceVisibilities(public_namespaces, private_namespaces) 2395 if args is not None: 2396 self.__schemaLocationList.extend(args) 2397 pyxb.utils.utility.SetLocationPrefixRewriteMap(self.locationPrefixRewriteMap()) 2398 if self.__loggingConfigFile is not None: 2399 logging.config.fileConfig(self.__loggingConfigFile)
2400
2401 - def setFromCommandLine (self, argv=None):
2402 if argv is None: 2403 argv = sys.argv[1:] 2404 (options, args) = self.optionParser().parse_args(argv) 2405 self.applyOptionValues(options, args) 2406 return self
2407
2408 - def generationUID (self):
2409 """A unique identifier associated with this Generator instance. 2410 2411 This is an instance of L{pyxb.utils.utility.UniqueIdentifier}. 2412 Its associated objects are 2413 L{pyxb.namespace.archive._SchemaOrigin} instances, which 2414 identify schema that contribute to the definition of a 2415 namespace.""" 2416 return self.__generationUID
2417 __generationUID = None 2418
2419 - def optionParser (self, reset=False):
2420 """Return an C{optparse.OptionParser} instance tied to this configuration. 2421 2422 @param reset: If C{False} (default), a parser created in a 2423 previous invocation will be returned. If C{True}, any 2424 previous option parser is discarded and a new one created. 2425 @type reset: C{bool} 2426 """ 2427 if reset or (self.__optionParser is None): 2428 parser = optparse.OptionParser(usage="%prog [options] [more schema locations...]", 2429 version='%%prog from PyXB %s' % (pyxb.__version__,), 2430 description='Generate bindings from a set of XML schemas') 2431 2432 group = optparse.OptionGroup(parser, 'Identifying Schema', 'Specify and locate schema for which bindings should be generated.') 2433 group.add_option('--schema-location', '-u', metavar="FILE_or_URL", 2434 action='append', 2435 help=self.__stripSpaces(self.argAddSchemaLocation.__doc__)) 2436 group.add_option('--schema-root', metavar="DIRECTORY", 2437 help=self.__stripSpaces(self.schemaRoot.__doc__)) 2438 group.add_option('--schema-stripped-prefix', metavar="TEXT", type='string', 2439 help=self.__stripSpaces(self.schemaStrippedPrefix.__doc__)) 2440 group.add_option('--location-prefix-rewrite', metavar="TEXT", type='string', 2441 help=self.__stripSpaces(self.argAddLocationPrefixRewrite.__doc__)) 2442 group.add_option('--uri-content-archive-directory', metavar="DIRECTORY", 2443 help=self.__stripSpaces(self.uriContentArchiveDirectory.__doc__)) 2444 parser.add_option_group(group) 2445 2446 group = optparse.OptionGroup(parser, 'Configuring Bindings', 'Specify where generated bindings should be written, and how they will be accessed from Python.') 2447 group.add_option('--module', '-m', metavar="MODULE", 2448 action='append', 2449 help=self.__stripSpaces(self.addModuleName.__doc__)) 2450 group.add_option('--module-prefix', metavar="MODULE", 2451 help=self.__stripSpaces(self.modulePrefix.__doc__)) 2452 group.add_option('--binding-root', metavar="DIRECTORY", 2453 help=self.__stripSpaces(self.bindingRoot.__doc__)) 2454 group.add_option('-r', '--write-for-customization', 2455 action='store_true', dest='write_for_customization', 2456 help=self.__stripSpaces(self.writeForCustomization.__doc__ + ' This option turns on the feature.')) 2457 group.add_option('--no-write-for-customization', 2458 action='store_false', dest='write_for_customization', 2459 help=self.__stripSpaces(self.writeForCustomization.__doc__ + ' This option turns off the feature (I{default}).')) 2460 parser.add_option_group(group) 2461 2462 group = optparse.OptionGroup(parser, 'Reading Namespace Archives', 'Locating and loading (or inhibiting load of) namespace archives.') 2463 group.add_option('--archive-path', metavar="PATH", 2464 help=self.__stripSpaces(self.archivePath.__doc__)) 2465 group.add_option('--import-augmentable-namespace', metavar="URI", 2466 action='append', 2467 help=self.__stripSpaces(self.addImportAugmentableNamespace.__doc__)) 2468 group.add_option('--no-load-namespace', metavar="URI", 2469 action='append', 2470 help=self.__stripSpaces(self.addNoLoadNamespace.__doc__)) 2471 parser.add_option_group(group) 2472 2473 group = optparse.OptionGroup(parser, 'Writing Namespace Archives', 'Control the location and content of a namespace archive corresponding to a binding generation.') 2474 group.add_option('--archive-to-file', metavar="FILE", 2475 help=self.__stripSpaces(self.archiveToFile.__doc__)) 2476 group.add_option('--public-namespace', metavar="URI", 2477 action='append', 2478 help=self.__stripSpaces(self.namespaceVisibilityMap.__doc__ + ' This option adds the namespace as a public archive member.')) 2479 group.add_option('--private-namespace', metavar="URI", 2480 action='append', 2481 help=self.__stripSpaces(self.namespaceVisibilityMap.__doc__ + ' This option adds the namespace as a private archive member.')) 2482 group.add_option('--default-namespace-public', 2483 action="store_true", dest='default_namespace_public', 2484 help=self.__stripSpaces(self.defaultNamespacePublic.__doc__ + ' This option makes the default C{public} (I{default}).')) 2485 group.add_option('--default-namespace-private', 2486 action="store_false", dest='default_namespace_public', 2487 help=self.__stripSpaces(self.defaultNamespacePublic.__doc__ + ' This option makes the default C{private}.')) 2488 parser.add_option_group(group) 2489 2490 group = optparse.OptionGroup(parser, 'Configuring Binding Code Generation', "Control the style and content of the generated bindings. This is not well-supported, and you are advised to pretend these options don't exist.") 2491 group.add_option('--validate-changes', 2492 action='store_true', dest='validate_changes', 2493 help=self.__stripSpaces(self.validateChanges.__doc__ + ' This option turns on validation (default).')) 2494 group.add_option('--no-validate-changes', 2495 action='store_false', dest='validate_changes', 2496 help=self.__stripSpaces(self.validateChanges.__doc__ + ' This option turns off validation.')) 2497 parser.add_option_group(group) 2498 2499 group = optparse.OptionGroup(parser, 'Miscellaneous Options', "Anything else.") 2500 group.add_option('--logging-config-file', metavar="FILE", 2501 help=self.__stripSpaces(self.loggingConfigFile.__doc__)) 2502 parser.add_option_group(group) 2503 2504 group = optparse.OptionGroup(parser, 'Maintainer Options', "Don't use these. They don't exist. If they did, they'd do different things at different times, and if you used them you'd probably be sorry.") 2505 2506 group.add_option('--allow-absent-module', 2507 action='store_true', dest='allow_absent_module', 2508 help=self.__stripSpaces(self.allowAbsentModule.__doc__ + ' This option turns on the feature.')) 2509 group.add_option('--no-allow-absent-module', 2510 action='store_false', dest='allow_absent_module', 2511 help=self.__stripSpaces(self.allowAbsentModule.__doc__ + ' This option turns off the feature (default).')) 2512 group.add_option('--allow-builtin-generation', 2513 action='store_true', dest='allow_builtin_generation', 2514 help=self.__stripSpaces(self.allowBuiltinGeneration.__doc__ + ' This option turns on the feature.')) 2515 group.add_option('--no-allow-builtin-generation', 2516 action='store_false', dest='allow_builtin_generation', 2517 help=self.__stripSpaces(self.allowBuiltinGeneration.__doc__ + ' This option turns off the feature (default).')) 2518 parser.add_option_group(group) 2519 2520 self.__optionParser = parser 2521 return self.__optionParser
2522 __optionParser = None 2523
2524 - def getCommandLineArgs (self):
2525 """Return a command line option sequence that could be used to 2526 construct an equivalent configuration. 2527 2528 @note: If you extend the option parser, as is done by 2529 C{pyxbgen}, this may not be able to reconstruct the correct 2530 command line.""" 2531 opts = [] 2532 module_list = self.moduleList() 2533 schema_list = self.schemaLocationList() 2534 while module_list and schema_list: 2535 ml = module_list.pop(0) 2536 sl = schema_list.pop(0) 2537 if isinstance(sl, tuple): 2538 sl = sl[0] 2539 opts.extend(['--schema-location=' + sl, '--module=' + ml]) 2540 for sl in schema_list: 2541 opts.append('--schema-location=' + sl) 2542 if self.schemaRoot() is not None: 2543 opts.append('--schema-root=' + self.schemaRoot()) 2544 if self.schemaStrippedPrefix() is not None: 2545 opts.append('--schema-stripped-prefix=%s' + self.schemaStrippedPrefix()) 2546 for (pfx, sub) in self.locationPrefixRewriteMap(): 2547 opts.append('--location-prefix-rewrite=%s=%s' % (pfx, sub)) 2548 if self.modulePrefix() is not None: 2549 opts.append('--module-prefix=' + self.modulePrefix()) 2550 opts.append('--binding-root=' + self.bindingRoot()) 2551 if self.archivePath() is not None: 2552 opts.append('--archive-path=' + self.archivePath()) 2553 for ns in self.noLoadNamespaces(): 2554 opts.append('--no-load-namespace=' + ns.uri()) 2555 for ns in self.importAugmentableNamespaces(): 2556 opts.append('--import-augmentable-namespace=' + ns.uri()) 2557 if self.archiveToFile() is not None: 2558 opts.append('--archive-to-file=' + self.archiveToFile()) 2559 for (ns, visibility) in self.namespaceVisibilityMap(): 2560 if visibility: 2561 opts.append('--public-namespace=' + ns.uri()) 2562 else: 2563 opts.append('--private-namespace=' + ns.uri()) 2564 if self.defaultNamespacePublic(): 2565 opts.append('--default-namespace-public') 2566 else: 2567 opts.append('--default-namespace-private') 2568 for (val, opt) in ( (self.validateChanges(), 'validate-changes'), 2569 (self.writeForCustomization(), 'write-for-customization'), 2570 (self.allowAbsentModule(), 'allow-absent-module'), 2571 (self.allowBuiltinGeneration(), 'allow-builtin-generation') ): 2572 if val: 2573 opts.append('--' + opt) 2574 else: 2575 opts.append('--no-' + opt) 2576 if self.uriContentArchiveDirectory() is not None: 2577 opts.append('--uri-content-archive-directory=%s' + self.uriContentArchiveDirectory()) 2578 return opts
2579
2580 - def normalizeSchemaLocation (self, sl):
2581 ssp = self.schemaStrippedPrefix() 2582 if ssp and sl.startswith(ssp): 2583 sl = sl[len(ssp):] 2584 return pyxb.utils.utility.NormalizeLocation(sl, self.schemaRoot())
2585
2586 - def assignModulePath (self, module_record, module_path=None):
2587 """Provide a Python module path for the module record. 2588 2589 This is the path by which the module bindings associated with 2590 C{module_record} will be imported. 2591 2592 If a path had already been assigned to the module, it is left 2593 in place. 2594 2595 @param module_record: Information about a collection of related bindings 2596 @type module_record: L{pyxb.namespace.archive.ModuleRecord} 2597 2598 @param module_path: Default path to use 2599 @type module_path: C{str} 2600 2601 @return: C{module_record} 2602 """ 2603 if module_record.modulePath() is not None: 2604 return module_record 2605 namespace = module_record.namespace() 2606 if not namespace.isAbsentNamespace(): 2607 # Use the namespace prefix from a referencing schema if no other clue was given 2608 if (module_path is None) and not (namespace.prefix() is None): 2609 module_path = namespace.prefix() 2610 # Prefer an existing assignment over a new one 2611 module_path = self.namespaceModuleMap().get(namespace.uri(), module_path) 2612 if (module_path is None) and self.generateToFiles(): 2613 module_path = pyxb.utils.utility.MakeUnique('binding', self.__unnamedModulePaths) 2614 if (module_path is not None) and self.modulePrefix(): # non-empty value 2615 # Prepend a configured module prefix 2616 module_path = '.'.join([self.modulePrefix(), module_path]) 2617 module_record.setModulePath(module_path) 2618 return module_record
2619 2620 __didResolveExternalSchema = False
2621 - def resolveExternalSchema (self):
2622 if self.__didResolveExternalSchema: 2623 return 2624 2625 # Locate all relevant archives and the namespaces they 2626 # provide. 2627 pyxb.namespace.archive.NamespaceArchive.PreLoadArchives(self.archivePath()) 2628 2629 # Mark the namespaces we were told not to load. These may be 2630 # namespaces for which we already have bindings in the search 2631 # path, but we want to generate completely new ones. 2632 for ns in self.noLoadNamespaces(): 2633 assert isinstance(ns, pyxb.namespace.Namespace) 2634 _log.info("Namespace %s marked not loadable" % (ns,)) 2635 ns.markNotLoadable() 2636 2637 # Mark the namespaces that we permit to be extended by import 2638 # statements. 2639 for ns in self.importAugmentableNamespaces(): 2640 assert isinstance(ns, pyxb.namespace.Namespace) 2641 _log.info("Namespace %s marked import-augmentable" % (ns,)) 2642 ns.setImportAugmentable(True) 2643 2644 # Read all the schema we were told about. 2645 while self.__schemaLocationList: 2646 sl = self.__schemaLocationList.pop(0) 2647 if isinstance(sl, tuple): 2648 (sl, converter) = sl 2649 else: 2650 converter = None 2651 try: 2652 if converter is None: 2653 schema = xs.schema.CreateFromLocation(absolute_schema_location=self.normalizeSchemaLocation(sl), 2654 generation_uid=self.generationUID(), 2655 uri_content_archive_directory=self.uriContentArchiveDirectory()) 2656 else: 2657 schema = converter(self, sl) 2658 self.addSchema(schema) 2659 except pyxb.SchemaUniquenessError as e: 2660 _log.info('Skipped redundant translation of %s defining %s', e.schemaLocation(), e.namespace()) 2661 self.addSchema(e.existingSchema()) 2662 2663 # Assign Python modules to hold bindings for the schema we're 2664 # processing. 2665 for schema in self.__schemas: 2666 if isinstance(schema, six.string_types): 2667 schema = xs.schema.CreateFromDocument(schema, generation_uid=self.generationUID()) 2668 origin = schema.originRecord() 2669 assert origin is not None 2670 module_path = None 2671 if self.__moduleList: 2672 module_path = self.__moduleList.pop(0) 2673 self.assignModulePath(origin.moduleRecord(), module_path) 2674 assert schema.targetNamespace() == origin.moduleRecord().namespace() 2675 self.addNamespace(schema.targetNamespace()) 2676 self.__didResolveExternalSchema = True 2677 2678 # Discard any existing component information 2679 self.__componentGraph = None 2680 self.__componentOrder = None
2681
2682 - def __graphFromComponents (self, components, include_lax):
2683 components = components.copy() 2684 component_graph = pyxb.utils.utility.Graph() 2685 need_visit = components.copy() 2686 bindable_fn = lambda _c: isinstance(_c, xs.structures.ElementDeclaration) or _c.isTypeDefinition() 2687 while 0 < len(need_visit): 2688 c = need_visit.pop() 2689 assert c is not None 2690 assert bindable_fn(c) or include_lax 2691 assert c._objectOrigin() is not None, '%s %s has no origin' % (type(c), c) 2692 component_graph.addNode(c) 2693 br = c.bindingRequires(reset=True, include_lax=include_lax) 2694 for cd in br: 2695 assert bindable_fn(cd) or include_lax, '%s produced %s in requires' % (type(c), type(cd)) 2696 if cd._objectOrigin() is None: 2697 assert isinstance(cd, (pyxb.xmlschema.structures.Annotation, pyxb.xmlschema.structures.Wildcard)) 2698 continue 2699 if (cd._objectOrigin().moduleRecord() in self.__moduleRecords) and not (cd in components): 2700 components.add(cd) 2701 need_visit.add(cd) 2702 if cd in components: 2703 component_graph.addEdge(c, cd) 2704 return component_graph
2705
2707 self.resolveExternalSchema() 2708 2709 bindable_fn = lambda _c: isinstance(_c, xs.structures.ElementDeclaration) or _c.isTypeDefinition() 2710 2711 self.__moduleRecords = set() 2712 all_components = set() 2713 for origin in self.generationUID().associatedObjects(): 2714 mr = origin.moduleRecord() 2715 if not (mr in self.__moduleRecords): 2716 self.__moduleRecords.add(mr) 2717 mr.completeGenerationAssociations() 2718 all_components.update(origin.originatedObjects()) 2719 2720 namespaces = set() 2721 for mr in self.__moduleRecords: 2722 if mr.namespace().isBuiltinNamespace() and not self.allowBuiltinGeneration(): 2723 continue 2724 namespaces.add(mr.namespace()) 2725 pyxb.namespace.resolution.ResolveSiblingNamespaces(namespaces) 2726 2727 # Mark module visibility. Entry-point namespaces default to 2728 # public. 2729 for ns in self.namespaces(): 2730 self.__namespaceVisibilityMap.setdefault(ns, True) 2731 2732 # Generate the graph from all components and descend into lax 2733 # requirements; otherwise we might miss anonymous types hidden 2734 # inside attribute declarations and the like. 2735 component_graph = self.__graphFromComponents(all_components, True) 2736 2737 binding_components = set(filter(bindable_fn, component_graph.nodes())) 2738 for c in binding_components: 2739 assert bindable_fn(c), 'Unexpected %s in binding components' % (type(c),) 2740 c._setBindingNamespace(c._objectOrigin().moduleRecord().namespace()) 2741 2742 component_order = [] 2743 root_sets = self.__graphFromComponents(binding_components, False).rootSetOrder() 2744 if root_sets is None: 2745 raise pyxb.BindingGenerationError('Unable to partial-order named components') 2746 for rs in root_sets: 2747 component_order.extend(sorted(rs, key=lambda _c: _c.schemaOrderSortKey())) 2748 2749 self.__componentGraph = component_graph 2750 self.__componentOrder = component_order
2751 2752 __moduleRecords = None 2753 __componentGraph = None 2754 __componentOrder = None 2755
2756 - def moduleRecords (self):
2757 """The set of L{pyxb.namespace.archive.ModuleRecord} instances 2758 associated with schema processed in this generation 2759 instance. 2760 2761 These should be in one-to-one correspondence with the 2762 namespaces for which bindings are being generated. Multiple 2763 input schemas may contribute to a single module record; all 2764 material in that record is placed in a single binding file. 2765 """ 2766 if self.__moduleRecords is None: 2767 self.__resolveComponentDependencies() 2768 return self.__moduleRecords
2769
2770 - def componentGraph (self):
2771 if self.__componentGraph is None: 2772 self.__resolveComponentDependencies() 2773 return self.__componentGraph
2774
2775 - def componentOrder (self):
2776 if self.__componentOrder is None: 2777 self.__resolveComponentDependencies() 2778 return self.__componentOrder
2779
2780 - def __generateBindings (self):
2781 2782 # Note that module graph may have fewer nodes than 2783 # self.moduleRecords(), if a module has no components that 2784 # require binding generation. 2785 2786 module_graph = pyxb.utils.utility.Graph() 2787 [ module_graph.addRoot(_mr) for _mr in self.moduleRecords() ] 2788 for (s, t) in self.componentGraph().edges(): 2789 module_graph.addEdge(s._objectOrigin().moduleRecord(), t._objectOrigin().moduleRecord()) 2790 module_scc_order = module_graph.sccOrder() 2791 2792 record_binding_map = {} 2793 modules = [] 2794 nsvm = self.namespaceVisibilityMap() 2795 for mr_scc in module_scc_order: 2796 scc_modules = [ ] 2797 for mr in mr_scc: 2798 mr._setIsPublic(nsvm.get(mr.namespace(), self.defaultNamespacePublic())) 2799 self.assignModulePath(mr) 2800 if (mr.modulePath() is None) and self.generateToFiles(): 2801 raise pyxb.BindingGenerationError('No prefix or module name available for %s' % (mr,)) 2802 if (not mr.isPublic()) and (mr.modulePath() is not None): 2803 elts = mr.modulePath().split('.') 2804 elts[-1] = '_%s' % (elts[-1],) 2805 mr.setModulePath('.'.join(elts)) 2806 nsm = NamespaceModule(self, mr, mr_scc) 2807 record_binding_map[mr] = nsm 2808 scc_modules.append(nsm) 2809 2810 scc_modules.sort(key=lambda _nm: _nm.namespace().uri()) 2811 modules.extend(scc_modules) 2812 if 1 < len(mr_scc): 2813 ngm = NamespaceGroupModule(self, scc_modules) 2814 modules.append(ngm) 2815 for nsm in scc_modules: 2816 nsm.setNamespaceGroupModule(ngm) 2817 2818 element_declarations = [] 2819 type_definitions = [] 2820 for c in self.componentOrder(): 2821 if isinstance(c, xs.structures.ElementDeclaration) and c._scopeIsGlobal(): 2822 # Only bind elements this pass, so their names get priority in deconfliction 2823 nsm = record_binding_map[c._objectOrigin().moduleRecord()] 2824 nsm.bindComponent(c) 2825 element_declarations.append(c) 2826 elif c.isTypeDefinition(): 2827 type_definitions.append(c) 2828 else: 2829 # No binding generation required 2830 pass 2831 2832 simple_type_definitions = [] 2833 complex_type_definitions = [] 2834 for td in type_definitions: 2835 nsm = record_binding_map[td._objectOrigin().moduleRecord()] 2836 assert nsm is not None, 'No namespace module for %s type %s scope %s namespace %s' % (td.expandedName(), type(td), td._scope(), td.bindingNamespace) 2837 module_context = nsm.bindComponent(td) 2838 assert isinstance(module_context, _ModuleNaming_mixin), 'Unexpected type %s' % (type(module_context),) 2839 if isinstance(td, xs.structures.SimpleTypeDefinition): 2840 _PrepareSimpleTypeDefinition(td, self, nsm, module_context) 2841 simple_type_definitions.append(td) 2842 elif isinstance(td, xs.structures.ComplexTypeDefinition): 2843 _PrepareComplexTypeDefinition(td, self, nsm, module_context) 2844 complex_type_definitions.append(td) 2845 else: 2846 assert False, 'Unexpected component type %s' % (type(td),) 2847 2848 for ngm in modules: 2849 if isinstance(ngm, NamespaceGroupModule): 2850 for m in ngm.namespaceModules(): 2851 m.addImportsFrom(ngm) 2852 2853 for std in simple_type_definitions: 2854 GenerateSTD(std, self) 2855 for ctd in complex_type_definitions: 2856 GenerateCTD(ctd, self) 2857 for ed in element_declarations: 2858 GenerateED(ed, self) 2859 2860 self.__bindingModules = modules
2861 2862 __bindingModules = None
2863 - def bindingModules (self):
2864 if self.__componentGraph is None: 2865 self.__resolveComponentDependencies() 2866 if self.__bindingModules is None: 2867 self.__generateBindings() 2868 return self.__bindingModules
2869
2870 - def writeNamespaceArchive (self):
2871 archive_file = self.archiveToFile() 2872 if archive_file is not None: 2873 ns_archive = pyxb.namespace.archive.NamespaceArchive(generation_uid=self.generationUID()) 2874 try: 2875 ns_archive.writeNamespaces(pyxb.utils.utility.OpenOrCreate(archive_file)) 2876 _log.info('Saved parsed schema to %s URI', archive_file) 2877 except Exception as e: 2878 _log.exception('Failure saving preprocessed schema to %s', archive_file) 2879 #try: 2880 # os.unlink(component_model_file) 2881 #except (OSError, IOError), e: 2882 # pass 2883 if isinstance(e, (AssertionError, AttributeError, TypeError)): 2884 raise
2885
2886 - def moduleForComponent (self, component):
2888