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