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