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