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