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