1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """The really ugly code that generates the Python bindings. This
17 whole thing is going to be refactored once customized generation makes
18 it to the top of the task queue."""
19
20 import sys
21 import os.path
22 import logging
23 import logging.config
24 import io
25 import datetime
26 import errno
27
28 import pyxb
29 import pyxb.xmlschema as xs
30 from pyxb.utils import utility, templates, six
31 from pyxb.utils.utility import repr2to3
32 from pyxb.binding import basis, datatypes, facets
33
34 _log = logging.getLogger(__name__)
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
46 """Base class for something that requires fairly complex activity
47 in order to generate its literal value."""
48
49
50
51 __ownerClass = None
52
53
54 __literal = None
55
59
63
66
71
87
89 __wildcard = None
90
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
125
135
143
151
191
193
194 if isinstance(value, six.dictionary_type):
195 return ', '.join([ '%s=%s' % (k, pythonLiteral(v, **kw)) for (k, v) in six.iteritems(value) ])
196
197
198 if isinstance(value, six.list_type):
199 return [ pythonLiteral(_v, **kw) for _v in value ]
200
201
202 if isinstance(value, pyxb.namespace.ExpandedName):
203 return pythonLiteral(ReferenceExpandedName(expanded_name=value, **kw))
204
205
206 if isinstance(value, (six.tuple_type, set)):
207 return type(value)(pythonLiteral(list(value), **kw))
208
209
210
211 if isinstance(value, facets._Enumeration_mixin):
212 return pythonLiteral(ReferenceEnumerationMember(enum_value=value, **kw))
213
214
215
216
217 if isinstance(value, basis.simpleTypeDefinition):
218 return PrefixModule(value, value.pythonLiteral())
219
220 if isinstance(value, pyxb.namespace.Namespace):
221 return pythonLiteral(ReferenceNamespace(namespace=value, **kw))
222
223 if isinstance(value, type):
224 if issubclass(value, basis.simpleTypeDefinition):
225 return PrefixModule(value)
226 if issubclass(value, facets.Facet):
227 return PrefixModule(value)
228
229 if isinstance(value, facets.Facet):
230 return pythonLiteral(ReferenceFacet(facet=value, **kw))
231
232
233 if isinstance(value, facets._PatternElement):
234 return pythonLiteral(value.pattern)
235
236
237 if isinstance(value, facets._EnumerationElement):
238 return pythonLiteral(value.value())
239
240
241 if isinstance(value, xs.structures.Wildcard):
242 return pythonLiteral(ReferenceWildcard(value, **kw))
243
244
245 if isinstance(value, xs.structures._SchemaComponent_mixin):
246 return pythonLiteral(ReferenceSchemaComponent(value, **kw))
247
248
249 if isinstance(value, ReferenceLiteral):
250 return value.asLiteral()
251
252
253 if isinstance(value, pyxb.namespace.Namespace):
254 return repr2to3(value.uri())
255
256
257 if isinstance(value, (six.none_type, six.boolean_type, six.float_type, six.integer_types, six.string_types)):
258 return pyxb.utils.utility.repr2to3(value)
259
260 raise Exception('Unexpected literal type %s' % (type(value),))
261
278
279 def counterConditionSortKey (cc):
280 return cc.metadata.facStateSortKey()
281
282 def updateInstructionSortKey (ui):
283 return counterConditionSortKey(ui.counterCondition)
284
285 def transitionSortKey (xit):
286
287
288
289 st = xit.consumingState()
290
291
292
293 ssk = None
294 if st is not None:
295 ssk = stateSortKey(st)
296 keys = [ ssk ]
297 keys.extend(map(updateInstructionSortKey, sorted(xit.updateInstructions, key=updateInstructionSortKey)))
298 return tuple(keys)
299
300 au_src.append(' counters = set()')
301 counter_map = {}
302 sorted_counter_conditions = sorted(automaton.counterConditions, key=counterConditionSortKey)
303 for cc in sorted_counter_conditions:
304 cc_id = 'cc_%u' % (len(counter_map),)
305 counter_map[cc] = cc_id
306 au_src.append(' %s = fac.CounterCondition(min=%s, max=%s, metadata=%r)' % (cc_id, repr2to3(cc.min), repr2to3(cc.max), cc.metadata._location()))
307 au_src.append(' counters.add(%s)' % (cc_id,))
308 state_map = {}
309 au_src.append(' states = []')
310 sorted_states = sorted(automaton.states, key=stateSortKey)
311 for st in sorted_states:
312 st_id = 'st_%u' % (len(state_map),)
313 state_map[st] = st_id
314 if st.subAutomata is not None:
315 au_src.append(' sub_automata = []')
316 for sa in st.subAutomata:
317 au_src.append(' sub_automata.append(%s)' % (_GenerateAutomaton(sa, template_map, st_id, lines, **kw),))
318 if st.finalUpdate is None:
319 au_src.append(' final_update = None')
320 else:
321 au_src.append(' final_update = set()')
322 for ui in sorted(st.finalUpdate, key=updateInstructionSortKey):
323 au_src.append(' final_update.add(fac.UpdateInstruction(%s, %r))' % (counter_map[ui.counterCondition], ui.doIncrement))
324 if isinstance(st.symbol, xs.structures.ModelGroup):
325 au_src.append(' symbol = %r' % (st.symbol._location(),))
326 else:
327 (particle, symbol) = st.symbol
328 if isinstance(symbol, xs.structures.Wildcard):
329 au_src.append(templates.replaceInText(' symbol = pyxb.binding.content.WildcardUse(%{wildcard}, %{location})', wildcard=binding_module.literal(symbol, **kw), location=repr2to3(particle._location())))
330 elif isinstance(symbol, xs.structures.ElementDeclaration):
331 binding_module.importForDeclaration(symbol)
332 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))
333 au_src.append(' %s = fac.State(symbol, is_initial=%r, final_update=final_update, is_unordered_catenation=%r)' % (st_id, st.isInitial, st.isUnorderedCatenation))
334 if st.subAutomata is not None:
335 au_src.append(' %s._set_subAutomata(*sub_automata)' % (st_id,))
336 au_src.append(' states.append(%s)' % (st_id,))
337 for st in sorted_states:
338 au_src.append(' transitions = []')
339 for xit in sorted(st.transitionSet, key=transitionSortKey):
340 au_src.append(' transitions.append(fac.Transition(%s, [' % (state_map[xit.destination],))
341 sorted_ui = sorted(xit.updateInstructions, key=updateInstructionSortKey)
342 au_src.append(' %s ]))' % (',\n '.join(map(lambda _ui: 'fac.UpdateInstruction(%s, %r)' % (counter_map[_ui.counterCondition], _ui.doIncrement), sorted_ui))))
343 au_src.append(' %s._set_transitionSet(transitions)' % (state_map[st],))
344 au_src.append(' return fac.Automaton(states, counters, %r, containing_state=%s)' % (automaton.nullable, containing_state))
345 lines.extend(au_src)
346 return '%s()' % (name,)
347
358
378
380 binding_module = kw['binding_module']
381 outf = binding_module.bindingIO()
382 facet_instances = []
383 gen_enum_tag = _useEnumerationTags(td)
384 for (fc, fi) in six.iteritems(td.facets()):
385
386
387 if (fi is None) and (fc in td.baseTypeDefinition().facets()):
388
389 continue
390 if (fi is not None) and (fi.ownerTypeDefinition() != td):
391
392 continue
393 argset = { }
394 is_collection = issubclass(fc, facets._CollectionFacet_mixin)
395 if issubclass(fc, facets._LateDatatype_mixin):
396 vdt = td
397 if fc.LateDatatypeBindsSuperclass():
398 vdt = vdt.baseTypeDefinition()
399 argset['value_datatype'] = vdt
400 if fi is not None:
401 if not is_collection:
402 argset['value'] = fi.value()
403 if isinstance(fi, facets.CF_enumeration):
404 argset['enum_prefix'] = fi.enumPrefix()
405 facet_var = ReferenceFacetMember(type_definition=td, facet_class=fc, **kw)
406 outf.write("%s = %s(%s)\n" % binding_module.literal( (facet_var, fc, argset ), **kw))
407 facet_instances.append(binding_module.literal(facet_var, **kw))
408 if (fi is not None) and is_collection:
409 for i in six.iteritems(fi):
410 if isinstance(i, facets._EnumerationElement):
411 if isinstance(i.value(), pyxb.namespace.ExpandedName):
412 enum_config = '%s.addEnumeration(value=%s, tag=%s)' % binding_module.literal( ( facet_var, i.value(), i.tag() ), **kw)
413 else:
414 enum_config = '%s.addEnumeration(unicode_value=%s, tag=%s)' % binding_module.literal( ( facet_var, i.unicodeValue(), i.tag() ), **kw)
415 if gen_enum_tag and (i.tag() is not None):
416 enum_member = ReferenceEnumerationMember(type_definition=td, facet_instance=fi, enumeration_element=i, **kw)
417 outf.write("%s = %s\n" % (binding_module.literal(enum_member, **kw), enum_config))
418 if fi.enumPrefix() is not None:
419 outf.write("%s_%s = %s\n" % (fi.enumPrefix(), i.tag(), binding_module.literal(enum_member, **kw)))
420 else:
421 outf.write("%s\n" % (enum_config,))
422 if isinstance(i, facets._PatternElement):
423 outf.write("%s.addPattern(pattern=%s)\n" % binding_module.literal( (facet_var, i.pattern ), **kw))
424 if gen_enum_tag and (xs.structures.SimpleTypeDefinition.VARIETY_union == td.variety()):
425
426
427
428 fi = td.facets().get(facets.CF_enumeration)
429 if fi is None:
430
431 for mtd in td.memberTypeDefinitions():
432 if not _useEnumerationTags(mtd):
433 continue
434 fi = mtd.facets().get(facets.CF_enumeration)
435 if fi is None:
436 continue
437 for i in six.iteritems(fi):
438 assert isinstance(i, facets._EnumerationElement)
439 etd = i.enumeration().ownerTypeDefinition()
440 enum_member = ReferenceEnumerationMember(type_definition=td, facet_instance=fi, enumeration_element=i, **kw)
441 outf.write("%-50s%s\n" % ('%s = %s' % binding_module.literal( (enum_member, i.unicodeValue()) ),
442 '# originally %s.%s' % (binding_module.literal(etd), i.tag())))
443 if 2 <= len(facet_instances):
444 map_args = ",\n ".join(facet_instances)
445 else:
446 map_args = ','.join(facet_instances)
447 outf.write("%s._InitializeFacetMap(%s)\n" % (binding_module.literal(td, **kw), map_args))
448
450 if vc_source.fixed() is not None:
451 aux_init.append('fixed=True')
452 aux_init.append('unicode_default=%s' % (binding_module.literal(vc_source.fixed(), **kw),))
453 elif vc_source.default() is not None:
454 aux_init.append('unicode_default=%s' % (binding_module.literal(vc_source.default(), **kw),))
455
465
467
468 binding_module = generator.moduleForComponent(std)
469 outf = binding_module.bindingIO()
470
471 class_keywords = frozenset(basis.simpleTypeDefinition._ReservedSymbols)
472 class_unique = set()
473
474 kw = { }
475 kw['binding_module'] = binding_module
476 kw['class_keywords'] = class_keywords
477 kw['class_unique'] = class_unique
478
479 parent_classes = [ binding_module.literal(std.baseTypeDefinition(), **kw) ]
480 if simpleTypeOwnedEnumerationFacet(std) is not None:
481 parent_classes.append('pyxb.binding.basis.enumeration_mixin')
482
483 template_map = { }
484 binding_name = template_map['std'] = binding_module.literal(std, **kw)
485 if (std.expandedName() is not None) and (std.expandedName().localName() != binding_name):
486 _log.warning('Simple type %s renamed to %s', std.expandedName(), binding_name)
487
488 template_map['superclasses'] = ''
489 if 0 < len(parent_classes):
490 template_map['superclasses'] = ', '.join(parent_classes)
491 template_map['expanded_name'] = binding_module.literal(std.expandedName(), **kw)
492 if std.expandedName() is not None:
493 template_map['qname'] = six.text_type(std.expandedName())
494 else:
495 template_map['qname'] = '[anonymous]'
496 template_map['namespaceReference'] = binding_module.literal(std.bindingNamespace(), **kw)
497 template_map['xsd_location'] = repr2to3(std._location())
498 if std.annotation() is not None:
499 template_map['documentation'] = std.annotation().asDocString()
500 template_map['documentation_expr'] = binding_module.literal(std.annotation().text())
501 else:
502 template_map['documentation'] = ''
503 template_map['documentation_expr'] = binding_module.literal(None)
504
505
506
507 common_template = '''
508 """%{documentation}"""
509
510 _ExpandedName = %{expanded_name}
511 _XSDLocation = %{xsd_location}
512 _Documentation = %{documentation_expr}
513 '''
514 if xs.structures.SimpleTypeDefinition.VARIETY_absent == std.variety():
515 template = '''
516 # The ur simple type: %{qname}
517 class %{std} (%{superclasses}):
518 ''' + common_template
519 if not template_map['documentation']:
520 template_map['documentation'] = 'The ur simple type.'
521 elif xs.structures.SimpleTypeDefinition.VARIETY_atomic == std.variety():
522 template = '''
523 # Atomic simple type: %{qname}
524 class %{std} (%{superclasses}):
525 ''' + common_template
526 if not template_map['documentation']:
527 template_map['documentation'] = 'An atomic simple type.'
528 elif xs.structures.SimpleTypeDefinition.VARIETY_list == std.variety():
529 template = '''
530 # List simple type: %{qname}
531 # superclasses %{superclasses}
532 class %{std} (pyxb.binding.basis.STD_list):
533 ''' + common_template + '''
534 _ItemType = %{itemtype}
535 '''
536 template_map['itemtype'] = binding_module.literal(std.itemTypeDefinition(), **kw)
537 if not template_map['documentation']:
538 template_map['documentation'] = templates.replaceInText('Simple type that is a list of %{itemtype}.', **template_map)
539 elif xs.structures.SimpleTypeDefinition.VARIETY_union == std.variety():
540 template = '''
541 # Union simple type: %{qname}
542 # superclasses %{superclasses}
543 class %{std} (pyxb.binding.basis.STD_union):
544 ''' + common_template + '''
545 _MemberTypes = ( %{membertypes}, )
546 '''
547 template_map['membertypes'] = ", ".join( [ binding_module.literal(_mt, **kw) for _mt in std.memberTypeDefinitions() ])
548 if not template_map['documentation']:
549 template_map['documentation'] = templates.replaceInText('Simple type that is a union of %{membertypes}.', **template_map)
550 else:
551 raise pyxb.LogicError("Unhandled STD variety")
552
553 outf.write(templates.replaceInText(template, **template_map))
554
555 GenerateFacets(std, generator, **kw)
556
557 if std.name() is not None:
558 outf.write(templates.replaceInText("%{namespaceReference}.addCategoryObject('typeBinding', %{localName}, %{std})\n",
559 localName=binding_module.literal(std.name(), **kw), **template_map))
560
562 template_map = { }
563 template_map['qname'] = six.text_type(ed.expandedName())
564 template_map['decl_location'] = repr2to3(ed._location())
565 template_map['namespaceReference'] = binding_module.literal(ed.bindingNamespace(), **kw)
566 if (ed.SCOPE_global == ed.scope()):
567 binding_name = template_map['class'] = binding_module.literal(ed, **kw)
568 if ed.expandedName().localName() != binding_name:
569 _log.warning('Element %s renamed to %s', ed.expandedName(), binding_name)
570 template_map['localName'] = binding_module.literal(ed.name(), **kw)
571 template_map['map_update'] = templates.replaceInText("%{namespaceReference}.addCategoryObject('elementBinding', %{localName}, %{class})", **template_map)
572 else:
573 template_map['scope'] = binding_module.literal(ed.scope(), **kw)
574 if ed.annotation() is not None:
575 template_map['documentation'] = binding_module.literal(six.text_type(ed.annotation()))
576 if ed.abstract():
577 template_map['abstract'] = binding_module.literal(ed.abstract(), **kw)
578 if ed.nillable():
579 template_map['nillable'] = binding_module.literal(ed.nillable(), **kw)
580 if ed.default():
581 template_map['defaultValue'] = binding_module.literal(ed.default(), **kw)
582 template_map['typeDefinition'] = binding_module.literal(ed.typeDefinition(), **kw)
583 if ed.substitutionGroupAffiliation():
584 template_map['substitution_group'] = binding_module.literal(ed.substitutionGroupAffiliation(), **kw)
585 aux_init = []
586 for k in ( 'nillable', 'abstract', 'scope', 'documentation' ):
587 if k in template_map:
588 aux_init.append('%s=%s' % (k, template_map[k]))
589 aux_init.append('location=%s' % (template_map['decl_location'],))
590 _VCAppendAuxInit(ed, aux_init, binding_module, kw)
591 template_map['element_aux_init'] = ''
592 if 0 < len(aux_init):
593 template_map['element_aux_init'] = ', ' + ', '.join(aux_init)
594
595 return template_map
596
597 import pyxb.utils.fac
598 import operator
599 import functools
607 """Construct a L{FAC term tree<pyxb.utils.fac.Node>} for a L{particle<xs.structures.Particle>}.
608
609 This translates the XML schema content model of particles, model
610 groups, element declarations, and wildcards into a tree expressing
611 the corresponding content as a regular expression with numerical
612 constraints.
613
614 @param node: An instance of L{xs.structures.Particle}
615
616 @return: An instance of L{pyxb.utils.fac.Node}
617 """
618
619 def _generateTermTree_visitor (node, entered, arg):
620 """Helper for constructing a L{FAC term tree<pyxb.utils.fac.Node>}.
621
622 This is passed to L{xs.structures.Particle.walkParticleTree}.
623
624 @param node: An instance of L{xs.structures._ParticleTree_mixin}
625
626 @param entered: C{True} entering an interior tree node, C{False}
627 leaving an interior tree node, C{None} at a leaf node.
628
629 @param arg: A list of pairs C{(particle, terms)} where C{particle}
630 is the L{xs.structures.Particle} instance containing a list of
631 L{term trees<pyxb.utils.fac.Node>}.
632 """
633
634 if entered is None:
635 (parent_particle, terms) = arg.peekNodeTermPair()
636 assert isinstance(parent_particle, xs.structures.Particle)
637 assert isinstance(node, (xs.structures.ElementDeclaration, xs.structures.Wildcard))
638 node._setFacStateSortKey(arg.nextSequenceNumber())
639 terms.append(pyxb.utils.fac.Symbol((parent_particle, node)))
640 elif entered:
641 node._setFacStateSortKey(arg.nextSequenceNumber())
642 arg.addNode(node)
643 else:
644 (xnode, terms) = arg.popNodeTermPair()
645 assert xnode == node
646 (parent_particle, siblings) = arg.peekNodeTermPair()
647 if 1 == len(terms):
648 term = terms[0]
649
650
651
652
653
654 if isinstance(node, xs.structures.Particle) and ((1 != node.minOccurs()) or (1 != node.maxOccurs())):
655 term = pyxb.utils.fac.NumericalConstraint(term, node.minOccurs(), node.maxOccurs(), metadata=node)
656 else:
657 assert isinstance(parent_particle, xs.structures.Particle), 'unexpected %s' % (parent_particle,)
658 assert isinstance(node, xs.structures.ModelGroup)
659 if node.C_CHOICE == node.compositor():
660 term = pyxb.utils.fac.Choice(*terms, metadata=node)
661 elif node.C_SEQUENCE == node.compositor():
662 term = pyxb.utils.fac.Sequence(*terms, metadata=node)
663 else:
664
665
666
667
668
669
670 assert node.C_ALL == node.compositor()
671 assert functools.reduce(operator.and_, map(lambda _s: isinstance(_s, pyxb.utils.fac.Node), terms), True)
672 term = pyxb.utils.fac.All(*terms, metadata=node)
673 siblings.append(term)
674
675 class TermTreeArg (object):
676 __sequenceNumber = None
677 __termTreeList = None
678 __nodeTermPairs = None
679 def __init__ (self, node):
680 self.__sequenceNumber = 0
681 self.__termTreeList = []
682 self.__nodeTermPairs = [ (node, self.__termTreeList) ]
683
684 def termTree (self):
685 assert 1 == len(self.__nodeTermPairs)
686 assert 1 == len(self.__termTreeList)
687 return self.__termTreeList[0]
688
689 def peekNodeTermPair (self):
690 return self.__nodeTermPairs[-1]
691
692 def popNodeTermPair (self):
693 return self.__nodeTermPairs.pop()
694
695 def addNode (self, node):
696 self.__nodeTermPairs.append((node, []))
697
698 def nextSequenceNumber (self):
699 rv = self.__sequenceNumber
700 self.__sequenceNumber += 1
701 return rv
702
703 assert isinstance(node, xs.structures.Particle)
704 ttarg = TermTreeArg(node)
705 node.walkParticleTree(_generateTermTree_visitor, ttarg)
706 term_tree = ttarg.termTree()
707 return term_tree
708
710 """Walk a term tree to determine which element declarations may
711 appear multiple times.
712
713 The bindings need to use a list for any Python attribute
714 corresponding to an element declaration that can occur multiple
715 times in the content model. The number of occurrences is
716 determined by the occurrence constraints on parent particles and
717 the compositors of containing model groups. All this information
718 is available in the term tree used for the content model
719 automaton.
720
721 @param term_tree: A L{FAC term tree<pyxb.utils.fac.Node>}
722 representing the content model for a complex data type.
723
724 @return: Plurality data, as a pair C{(singles, multiples)} where
725 C{singles} is a set of base L{element
726 declarations<xs.structures.ElementDeclaration>} that are known to
727 occur at least once and at most once in a region of the content,
728 and C{multiples} is a similar set of declarations that are known
729 to potentially occur more than once."""
730
731 def _ttMergeSets (parent, child):
732 (p1, pm) = parent
733 (c1, cm) = child
734
735
736 pm.update(cm)
737
738
739
740 pm.update(c1.intersection(p1))
741
742
743
744 p1.difference_update(pm)
745 c1.difference_update(pm)
746
747
748
749 p1.symmetric_difference_update(c1)
750
751 def _ttPrePluralityWalk (node, pos, arg):
752
753
754 if isinstance(node, pyxb.utils.fac.MultiTermNode):
755 arg.append([])
756
757 def _ttPostPluralityWalk (node, pos, arg):
758
759 singles = set()
760 multiples = set()
761 combined = (singles, multiples)
762 if isinstance(node, pyxb.utils.fac.MultiTermNode):
763
764 term_list = arg.pop()
765 if isinstance(node, pyxb.utils.fac.Choice):
766
767
768 for (t1, tm) in term_list:
769 multiples.update(tm)
770 singles.update(t1)
771 else:
772
773 assert isinstance(node, (pyxb.utils.fac.Sequence, pyxb.utils.fac.All))
774 for tt in term_list:
775 _ttMergeSets(combined, tt)
776 elif isinstance(node, pyxb.utils.fac.Symbol):
777 (particle, term) = node.metadata
778 if isinstance(term, xs.structures.ElementDeclaration):
779
780 singles.add(term.baseDeclaration())
781 elif isinstance(term, xs.structures.Wildcard):
782 pass
783 else:
784 assert isinstance(term, list)
785
786 for tt in term:
787 _ttMergeSets(combined, BuildPluralityData(tt))
788 else:
789 assert isinstance(node, pyxb.utils.fac.NumericalConstraint)
790
791
792 combined = arg[-1].pop()
793 (singles, multiples) = combined
794 if 0 == node.max:
795
796
797 multiples.clear()
798 singles.clear()
799 elif 1 == node.max:
800
801 pass
802 else:
803
804
805 multiples.update(singles)
806 singles.clear()
807 arg[-1].append(combined)
808
809
810
811 arg = [[]]
812 term_tree.walkTermTree(_ttPrePluralityWalk, _ttPostPluralityWalk, arg)
813
814
815 assert 1 == len(arg)
816 arg = arg[0]
817 assert 1 == len(arg)
818 return arg[0]
819
821 """Helper class holding information need in both preparation and generation."""
822
823 contentBasis = None
824 termTree = None
825 edSingles = None
826 edMultiples = None
827 automaton = None
828 ctd = None
829
841
842 @classmethod
845
846 @classmethod
847 - def Get (cls, ctd):
849
851 binding_module = generator.moduleForComponent(ctd)
852 outf = binding_module.bindingIO()
853
854 prolog_template = None
855 template_map = { }
856 binding_name = template_map['ctd'] = binding_module.literal(ctd, **kw)
857 if (ctd.expandedName() is not None) and (ctd.expandedName().localName() != binding_name):
858 _log.warning('Complex type %s renamed to %s', ctd.expandedName(), binding_name)
859
860 base_type = ctd.baseTypeDefinition()
861 content_type_tag = ctd._contentTypeTag()
862
863 template_map['base_type'] = binding_module.literal(base_type, **kw)
864 template_map['namespaceReference'] = binding_module.literal(ctd.bindingNamespace(), **kw)
865 template_map['expanded_name'] = binding_module.literal(ctd.expandedName(), **kw)
866 if ctd.expandedName() is not None:
867 template_map['qname'] = six.text_type(ctd.expandedName())
868 else:
869 template_map['qname'] = '[anonymous]'
870 template_map['xsd_location'] = repr2to3(ctd._location())
871 template_map['simple_base_type'] = binding_module.literal(None, **kw)
872 template_map['contentTypeTag'] = content_type_tag
873 template_map['is_abstract'] = repr2to3(not not ctd.abstract())
874
875 content_basis = None
876 if (ctd.CT_SIMPLE == content_type_tag):
877 content_basis = ctd.contentType()[1]
878 template_map['simple_base_type'] = binding_module.literal(content_basis, **kw)
879 elif (ctd.CT_MIXED == content_type_tag):
880 content_basis = ctd.contentType()[1]
881 elif (ctd.CT_ELEMENT_ONLY == content_type_tag):
882 content_basis = ctd.contentType()[1]
883
884 if ctd.annotation() is not None:
885 template_map['documentation'] = ctd.annotation().asDocString()
886 elif isinstance(ctd.owner(), xs.structures.ElementDeclaration) \
887 and ctd.owner().annotation() is not None:
888 template_map['documentation'] = ctd.owner().annotation().asDocString()
889 else:
890 template_map['documentation'] = templates.replaceInText("Complex type %{qname} with content type %{contentTypeTag}", **template_map)
891
892 prolog_template = '''
893 # Complex type %{qname} with content type %{contentTypeTag}
894 class %{ctd} (%{superclass}):
895 """%{documentation}"""
896 _TypeDefinition = %{simple_base_type}
897 _ContentTypeTag = pyxb.binding.basis.complexTypeDefinition._CT_%{contentTypeTag}
898 _Abstract = %{is_abstract}
899 _ExpandedName = %{expanded_name}
900 _XSDLocation = %{xsd_location}
901 '''
902
903
904
905
906 inherits_from_base = True
907 template_map['superclass'] = binding_module.literal(base_type, **kw)
908 if ctd._isHierarchyRoot():
909 inherits_from_base = False
910 template_map['superclass'] = 'pyxb.binding.basis.complexTypeDefinition'
911 assert base_type.nameInBinding() is not None
912
913 if inherits_from_base:
914 prolog_template += ''' _ElementMap = %{superclass}._ElementMap.copy()
915 _AttributeMap = %{superclass}._AttributeMap.copy()
916 '''
917 else:
918 prolog_template += ''' _ElementMap = {}
919 _AttributeMap = {}
920 '''
921
922
923 class_keywords = frozenset(basis.complexTypeDefinition._ReservedSymbols)
924 class_unique = set()
925
926
927
928
929
930
931
932 element_uses = []
933
934 definitions = []
935
936 definitions.append('# Base type is %{base_type}')
937
938
939
940
941
942 if isinstance(content_basis, xs.structures.Particle):
943 aux = _CTDAuxData.Get(ctd)
944 elements = aux.edSingles.union(aux.edMultiples)
945
946 outf.postscript().append("\n\n")
947 for ed in sorted(elements, key=lambda _c: _c.schemaOrderSortKey()):
948 is_plural = ed in aux.edMultiples
949
950 ef_map = ed._templateMap()
951 if ed.scope() == ctd:
952 ef_map.update(elementDeclarationMap(ed, binding_module, **kw))
953 aux_init = []
954 ef_map['is_plural'] = repr2to3(is_plural)
955 element_uses.append(templates.replaceInText('%{use}.name() : %{use}', **ef_map))
956 if 0 == len(aux_init):
957 ef_map['aux_init'] = ''
958 else:
959 ef_map['aux_init'] = ', ' + ', '.join(aux_init)
960 ef_map['element_binding'] = utility.PrepareIdentifier('%s_elt' % (ef_map['id'],), class_unique, class_keywords, private=True)
961 if ed.annotation() is not None:
962 ef_map['documentation'] = binding_module.literal(six.text_type(ed.annotation()))
963 else:
964 ef_map['documentation'] = binding_module.literal(None)
965 if ed.scope() != ctd:
966 definitions.append(templates.replaceInText('''
967 # Element %{id} (%{qname}) inherited from %{decl_type_en}''', decl_type_en=six.text_type(ed.scope().expandedName()), **ef_map))
968 continue
969
970 binding_module.importForDeclaration(ed)
971 if ed.expandedName().localName() != ef_map['id']:
972 _log.warning('Element use %s.%s renamed to %s', ctd.expandedName(), ed.expandedName(), ef_map['id'])
973 definitions.append(templates.replaceInText('''
974 # Element %{qname} uses Python identifier %{id}
975 %{use} = pyxb.binding.content.ElementDeclaration(%{name_expr}, '%{id}', '%{key}', %{is_plural}, %{decl_location}, %{aux_init})
976 ''', name_expr=binding_module.literal(ed.expandedName(), **kw), **ef_map))
977
978 definitions.append(templates.replaceInText('''
979 %{inspector} = property(%{use}.value, %{use}.set, None, %{documentation})
980 ''', **ef_map))
981 outf.postscript().append(templates.replaceInText('''
982 %{ctd}._AddElement(pyxb.binding.basis.element(%{name_expr}, %{typeDefinition}%{element_aux_init}))
983 ''', name_expr=binding_module.literal(ed.expandedName(), **kw), ctd=template_map['ctd'], **ef_map))
984
985 auto_defn = GenerateAutomaton(ctd, binding_module=binding_module, **kw)
986 if auto_defn is not None:
987 (automaton_ctor, lines) = auto_defn
988 if lines:
989 outf.postscript().append("\n".join(lines))
990 outf.postscript().append("\n")
991 outf.postscript().append(templates.replaceInText('%{ctd}._Automaton = %{automaton_ctor}\n', ctd=template_map['ctd'], automaton_ctor=automaton_ctor))
992 outf.postscript().append("\n")
993
994
995 attribute_uses = []
996
997
998
999
1000
1001
1002
1003
1004 for au in sorted(ctd.attributeUses(), key=lambda _au: _au.attributeDeclaration().schemaOrderSortKey()):
1005 ad = au.attributeDeclaration()
1006 assert isinstance(ad.scope(), xs.structures.ComplexTypeDefinition), 'unexpected scope %s' % (ad.scope(),)
1007 au_map = ad._templateMap()
1008 if ad.scope() != ctd:
1009 definitions.append(templates.replaceInText('''
1010 # Attribute %{id} inherited from %{decl_type_en}''', decl_type_en=six.text_type(ad.scope().expandedName()), **au_map))
1011 continue
1012 assert isinstance(au_map, dict)
1013 aur = au
1014 while aur.restrictionOf() is not None:
1015 aur = aur.restrictionOf()
1016 if au != aur:
1017 au_map = aur.attributeDeclaration()._templateMap().copy()
1018 definitions.append(templates.replaceInText('''
1019 # Attribute %{id} is restricted from parent''', **au_map))
1020
1021 assert ad.typeDefinition() is not None
1022 au_map['attr_type'] = binding_module.literal(ad.typeDefinition(), **kw)
1023 au_map['decl_location'] = repr2to3(ad._location())
1024 au_map['use_location'] = repr2to3(au._location())
1025
1026 vc_source = ad
1027 if au.valueConstraint() is not None:
1028 vc_source = au
1029 aux_init = []
1030 _VCAppendAuxInit(vc_source, aux_init, binding_module, kw)
1031 if au.required():
1032 aux_init.append('required=True')
1033 if au.prohibited():
1034 aux_init.append('prohibited=True')
1035 if 0 == len(aux_init):
1036 au_map['aux_init'] = ''
1037 else:
1038 aux_init.insert(0, '')
1039 au_map['aux_init'] = ', '.join(aux_init)
1040 if ad.annotation() is not None:
1041 au_map['documentation'] = binding_module.literal(six.text_type(ad.annotation()))
1042 else:
1043 au_map['documentation'] = binding_module.literal(None)
1044
1045 binding_module.importForDeclaration(ad)
1046 attribute_uses.append(templates.replaceInText('%{use}.name() : %{use}', **au_map))
1047 if ad.expandedName().localName() != au_map['id']:
1048 _log.warning('Attribute %s.%s renamed to %s', ctd.expandedName(), ad.expandedName(), au_map['id'])
1049 definitions.append(templates.replaceInText('''
1050 # Attribute %{qname} uses Python identifier %{id}
1051 %{use} = pyxb.binding.content.AttributeUse(%{name_expr}, '%{id}', '%{key}', %{attr_type}%{aux_init})
1052 %{use}._DeclarationLocation = %{decl_location}
1053 %{use}._UseLocation = %{use_location}''', name_expr=binding_module.literal(ad.expandedName(), **kw), **au_map))
1054 definitions.append(templates.replaceInText('''
1055 %{inspector} = property(%{use}.value, %{use}.set, None, %{documentation})
1056 ''', ctd=template_map['ctd'], **au_map))
1057
1058 if ctd.attributeWildcard() is not None:
1059 definitions.append('_AttributeWildcard = %s' % (binding_module.literal(ctd.attributeWildcard(), **kw),))
1060 if ctd.hasWildcardElement():
1061 definitions.append('_HasWildcardElement = True')
1062 template_map['attribute_uses'] = ",\n ".join(attribute_uses)
1063 template_map['element_uses'] = ",\n ".join(element_uses)
1064
1065 template_map['registration'] = ''
1066 if ctd.name() is not None:
1067 template_map['registration'] = templates.replaceInText("%{namespaceReference}.addCategoryObject('typeBinding', %{localName}, %{ctd})",
1068 localName=binding_module.literal(ctd.name(), **kw), **template_map)
1069
1070 template = ''.join([prolog_template,
1071 " ", "\n ".join(definitions), "\n",
1072 ''' _ElementMap.update({
1073 %{element_uses}
1074 })
1075 _AttributeMap.update({
1076 %{attribute_uses}
1077 })
1078 %{registration}
1079
1080 '''])
1081
1082 outf.write(template, **template_map)
1083
1085
1086 assert ed._scopeIsGlobal()
1087
1088 binding_module = generator.moduleForComponent(ed)
1089 outf = binding_module.bindingIO()
1090
1091 template_map = elementDeclarationMap(ed, binding_module, **kw)
1092 template_map.setdefault('scope', binding_module.literal(None, **kw))
1093 template_map.setdefault('map_update', '')
1094
1095 binding_module.importForDeclaration(ed)
1096 outf.write(templates.replaceInText('''
1097 %{class} = pyxb.binding.basis.element(%{name_expr}, %{typeDefinition}%{element_aux_init})
1098 %{namespaceReference}.addCategoryObject('elementBinding', %{class}.name().localName(), %{class})
1099 ''', name_expr=binding_module.literal(ed.expandedName(), **kw), **template_map))
1100
1101 if ed.substitutionGroupAffiliation() is not None:
1102 outf.postscript().append(templates.replaceInText('''
1103 %{class}._setSubstitutionGroup(%{substitution_group})
1104 ''', **template_map))
1105
1114
1122
1124 use_map = component._templateMap()
1125 class_unique = nsm.uniqueInClass(container)
1126 assert isinstance(component, xs.structures._ScopedDeclaration_mixin)
1127 unique_name = utility.PrepareIdentifier(component.expandedName().localName(), class_unique)
1128 use_map['id'] = unique_name
1129 use_map['inspector'] = unique_name
1130 use_map['mutator'] = utility.PrepareIdentifier('set' + unique_name[0].upper() + unique_name[1:], class_unique)
1131 use_map['use'] = utility.MakeUnique('__' + unique_name.strip('_'), class_unique)
1132 assert component._scope() == container
1133 assert component.nameInBinding() is None, 'Use %s but binding name %s for %s' % (use_map['use'], component.nameInBinding(), component.expandedName())
1134 component.setNameInBinding(use_map['use'])
1135 key_name = six.u('%s_%s_%s') % (six.text_type(nsm.namespace()), container.nameInBinding(), component.expandedName())
1136 use_map['key'] = utility.PrepareIdentifier(key_name, class_unique, private=True)
1137 use_map['qname'] = six.text_type(component.expandedName())
1138 if isinstance(component, xs.structures.ElementDeclaration) and is_plural:
1139 use_map['appender'] = utility.PrepareIdentifier('add' + unique_name[0].upper() + unique_name[1:], class_unique)
1140 return use_map
1141
1143 __prolog = None
1144 __postscript = None
1145 __templateMap = None
1146 __stringIO = None
1147 __bindingFilePath = None
1148 __bindingFile = None
1149
1150 - def __init__ (self, binding_module, **kw):
1151 super(BindingIO, self).__init__()
1152 self.__bindingModule = binding_module
1153 self.__bindingFilePath = kw['binding_file_path']
1154 self.__bindingFile = kw['binding_file']
1155 self.__prolog = []
1156 self.__postscript = []
1157 self.__templateMap = kw.copy()
1158 encoding = kw.get('encoding', pyxb._OutputEncoding)
1159 self.__templateMap.update({ 'date' : str(datetime.datetime.now()),
1160 'filePath' : self.__bindingFilePath,
1161 'coding' : encoding,
1162 'binding_module' : binding_module,
1163 'binding_tag' : binding_module.bindingTag(),
1164 'pyxbVersion' : pyxb.__version__,
1165 'pythonVersion' : '.'.join(map(str, sys.version_info))})
1166 self.__stringIO = io.StringIO()
1167 if self.__bindingFile:
1168 prefacet = self.expand('''# %{filePath}
1169 # -*- coding: %{coding} -*-
1170 # PyXB bindings for %{binding_tag}
1171 # Generated %{date} by PyXB version %{pyxbVersion} using Python %{pythonVersion}
1172 %{binding_preface}''', binding_preface=binding_module.bindingPreface())
1173 self.__bindingFile.write(prefacet.encode(encoding))
1174 self.__bindingFile.flush()
1175
1178
1179 - def expand (self, template, **kw):
1183
1184 - def write (self, template, **kw):
1187
1190 __bindingModule = None
1191
1194 - def postscript (self):
1195 return self.__postscript
1196
1200
1201 - def contents (self):
1202 rv = self.__prolog
1203 rv.append(self.__stringIO.getvalue())
1204 rv.extend(self.__postscript)
1205 return ''.join(rv)
1206
1208 __anonSTDIndex = None
1209 __anonCTDIndex = None
1210 __uniqueInModule = None
1211 __uniqueInClass = None
1212 __referencedFromClass = None
1213
1214 _UniqueInModule = set([ 'pyxb', 'sys' ])
1215 """Identifiers that are reserved within a module.
1216
1217 Subclasses extend this with the identifiers they add to the
1218 module. Module-level schema-derived identifiers (such as type
1219 definition and element names) are deconflicted from this set and
1220 from each other."""
1221
1222 _ReferencedFromClass = set([ 'pyxb', 'sys' ])
1223 """Identifiers defined in module that are accessed unqualified from class.
1224
1225 These include standard import module names and globals such as
1226 references to namespaces."""
1227
1228 __ComponentBindingModuleMap = {}
1229
1232 __generator = None
1233
1234 - def __init__ (self, generator, *args, **kw):
1249
1251 assert not isinstance(module, pyxb.namespace.Namespace)
1252 assert isinstance(module, (_ModuleNaming_mixin, pyxb.namespace.archive.ModuleRecord)), 'Unexpected type %s' % (type(module),)
1253 if isinstance(module, NamespaceModule):
1254 if pyxb.namespace.XMLSchema == module.namespace():
1255 return
1256 module = module.moduleRecord()
1257 assert isinstance(module, (pyxb.namespace.archive.ModuleRecord, NamespaceGroupModule))
1258 if not (module in self.__importModulePathMap):
1259 module_path = module.modulePath()
1260 if 'pyxb' == module_path.split('.', 2)[0]:
1261 assert 'pyxb' in self.uniqueInModule()
1262 assert 'pyxb' in self.__referencedFromClass
1263 module_path = None
1264 else:
1265 module_path = utility.PrepareIdentifier('ImportedBinding_' + module_path.replace('.', '_'),
1266 self.uniqueInModule(), protected=True)
1267 self.__referencedFromClass.add(module_path)
1268 self.__importModulePathMap[module] = module_path
1269
1290
1291 __referencedNamespaces = None
1292
1294 return self.__bindingIO
1295
1296 __moduleUID = None
1301
1303 return str(id(self))
1304
1306 """Return a distinct string recorded in the first 4096 bytes of the binding file.
1307
1308 This is used to ensure uniqueness and avoid overwriting data
1309 belonging to a different binding. The return value comprises
1310 the class-specialized L{_bindingTagPrefix_vx} with the
1311 L{moduleUID}.
1312 """
1313 return '%s:%s' % (self._bindingTagPrefix_vx(), self.moduleUID())
1314
1316 raise pyxb.LogicError('Subclass %s does not define _bindingTagPrefix_vx' % (type(self),))
1317
1319 """Return a block of binding text (comment or code) serving as a preface.
1320
1321 Normally this should describe the module contents."""
1322 return self._bindingPreface_vx()
1325
1326 - def moduleContents (self):
1327 template_map = {}
1328 aux_imports = []
1329 for (mr, as_path) in six.iteritems(self.__importModulePathMap):
1330 assert self != mr
1331 if as_path is not None:
1332 aux_imports.append('import %s as %s' % (mr.modulePath(), as_path))
1333 else:
1334 aux_imports.append('import %s' % (mr.modulePath(),))
1335 template_map['aux_imports'] = "\n".join(aux_imports)
1336 template_map['namespace_decls'] = "\n".join(self.__namespaceDeclarations)
1337 template_map['module_uid'] = self.moduleUID()
1338 template_map['generation_uid_expr'] = repr2to3(self.generator().generationUID())
1339 self._finalizeModuleContents_vx(template_map)
1340 return self.__bindingIO.contents()
1341
1354 __modulePath = None
1355
1357 """Python code reference to an object in an imported module"""
1358 if isinstance(module, NamespaceModule):
1359 module = module.moduleRecord()
1360 as_path = self.__importModulePathMap[module]
1361 if as_path is None:
1362 as_path = module.modulePath()
1363 return '%s.%s' % (as_path, name)
1364
1367 __bindingFile = None
1368 __bindingFilePath = None
1369
1372
1375
1376 @classmethod
1380
1381 @classmethod
1384
1385 @classmethod
1389 @classmethod
1392 __RecordModuleMap = { }
1393
1411 return self.__componentNameMap.get(component)
1412
1431
1433
1435 rv = self.__referencedNamespaces.get(namespace)
1436 assert rv is None, 'Module %s already has reference to %s' % (self, namespace)
1437
1438
1439
1440
1441 assert name.startswith('Namespace'), 'unexpected %s naming %s' % (name, namespace)
1442 name = utility.PrepareIdentifier(name, self.__uniqueInModule, **kw)
1443 self.__referencedFromClass.add(name)
1444 if definition is None:
1445 if namespace.isAbsentNamespace():
1446 definition = 'pyxb.namespace.CreateAbsentNamespace()'
1447 else:
1448 definition = 'pyxb.namespace.NamespaceForURI(%s, create_if_missing=True)' % (repr2to3(namespace.uri()),)
1449 self.__namespaceDeclarations.append('%s = %s' % (name, definition))
1450 self.__namespaceDeclarations.append("%s.configureCategories(['typeBinding', 'elementBinding'])" % (name,))
1451 self.__referencedNamespaces[namespace] = name
1452 return name
1453
1455 rv = self.__referencedNamespaces.get(namespace)
1456 if rv is None:
1457 assert not (isinstance(self, NamespaceModule) and (self.namespace() == namespace))
1458 assert namespace.isBuiltinNamespace() or not namespace.isUndeclaredNamespace()
1459 if namespace.isBuiltinNamespace():
1460 rv = namespace.builtinNamespaceRepresentation()
1461 if rv is None:
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471 if namespace.prefix():
1472 nsn = 'Namespace_%s' % (namespace.prefix(),)
1473 else:
1474 nsn = 'Namespace'
1475 nsdef = None
1476 for im in six.iterkeys(self.__importModulePathMap):
1477 if isinstance(im, pyxb.namespace.archive.ModuleRecord):
1478 if im.namespace() == namespace:
1479 nsdef = self.pathFromImport(im, 'Namespace')
1480 break
1481 elif isinstance(im, NamespaceGroupModule):
1482 pass
1483 else:
1484 assert False, 'unexpected import from type %s %s' % (type(im), im,)
1485
1486
1487
1488 if (nsdef is None) and not (isinstance(self, NamespaceGroupModule) and self.moduleForNamespace(namespace) is not None):
1489
1490
1491
1492 pass
1493
1494 rv = self.defineNamespace(namespace, nsn, nsdef, protected=True)
1495 assert 0 < len(self.__namespaceDeclarations)
1496 self.__referencedNamespaces[namespace] = rv
1497 return rv
1498
1528
1530 return self.__bindingIO.literal(*args, **kw)
1531
1533 _log.info('Importing to %s from %s', self, module)
1534 self._importModule(module)
1535 for c in self.__components:
1536 local_name = self.nameInModule(c)
1537 assert local_name is not None
1538 rem_name = module.nameInModule(c)
1539 if rem_name is None:
1540 continue
1541 aux = ''
1542 if local_name != rem_name:
1543 aux = ' as %s' % (local_name,)
1544 self.__bindingIO.write("from %s import %s%s # %s\n" % (module.modulePath(), rem_name, aux, c.expandedName()))
1545
1553
1555 """This class represents a Python module that holds all the
1556 declarations belonging to a specific namespace."""
1557
1560 __namespace = None
1561
1564 __moduleRecord = None
1565
1570 __namespaceGroupModule = None
1571
1572 _UniqueInModule = _ModuleNaming_mixin._UniqueInModule.copy()
1573 _UniqueInModule.update([ 'CreateFromDOM', 'CreateFromDocument' ])
1574
1577 __namespaceGroupHead = None
1578 __namespaceGroup = None
1579
1582 __components = None
1583
1584 @classmethod
1587 __ComponentModuleMap = { }
1588
1591
1593 ns = self.namespace()
1594 rvl = ['# Namespace %s' % (ns,)]
1595 if ns.prefix() is not None:
1596 rvl.append(' [xmlns:%s]' % (ns.prefix(),))
1597 rvl.append('\n')
1598 return ''.join(rvl)
1599
1604
1607
1608 - def __init__ (self, generator, module_record, mr_scc, components=None, **kw):
1622
1631
1632 - def _finalizeModuleContents_vx (self, template_map):
1633 template_map['_TextType'] = '_six.text_type'
1634 self.bindingIO().prolog().append(self.bindingIO().expand('''
1635 from __future__ import unicode_literals
1636 import pyxb
1637 import pyxb.binding
1638 import pyxb.binding.saxer
1639 import io
1640 import pyxb.utils.utility
1641 import pyxb.utils.domutils
1642 import sys
1643 import pyxb.utils.six as _six
1644
1645 # Unique identifier for bindings created at the same time
1646 _GenerationUID = %{generation_uid_expr}
1647
1648 # Version of PyXB used to generate the bindings
1649 _PyXBVersion = %{pyxb_version}
1650 # Generated bindings are not compatible across PyXB versions
1651 if pyxb.__version__ != _PyXBVersion:
1652 raise pyxb.PyXBVersionError(_PyXBVersion)
1653
1654 # Import bindings for namespaces imported into schema
1655 %{aux_imports}
1656
1657 # NOTE: All namespace declarations are reserved within the binding
1658 %{namespace_decls}
1659
1660 def CreateFromDocument (xml_text, default_namespace=None, location_base=None):
1661 """Parse the given XML and use the document element to create a
1662 Python instance.
1663
1664 @param xml_text An XML document. This should be data (Python 2
1665 str or Python 3 bytes), or a text (Python 2 unicode or Python 3
1666 str) in the L{pyxb._InputEncoding} encoding.
1667
1668 @keyword default_namespace The L{pyxb.Namespace} instance to use as the
1669 default namespace where there is no default namespace in scope.
1670 If unspecified or C{None}, the namespace of the module containing
1671 this function will be used.
1672
1673 @keyword location_base: An object to be recorded as the base of all
1674 L{pyxb.utils.utility.Location} instances associated with events and
1675 objects handled by the parser. You might pass the URI from which
1676 the document was obtained.
1677 """
1678
1679 if pyxb.XMLStyle_saxer != pyxb._XMLStyle:
1680 dom = pyxb.utils.domutils.StringToDOM(xml_text)
1681 return CreateFromDOM(dom.documentElement, default_namespace=default_namespace)
1682 if default_namespace is None:
1683 default_namespace = Namespace.fallbackNamespace()
1684 saxer = pyxb.binding.saxer.make_parser(fallback_namespace=default_namespace, location_base=location_base)
1685 handler = saxer.getContentHandler()
1686 xmld = xml_text
1687 if isinstance(xmld, %{_TextType}):
1688 xmld = xmld.encode(pyxb._InputEncoding)
1689 saxer.parse(io.BytesIO(xmld))
1690 instance = handler.rootObject()
1691 return instance
1692
1693 def CreateFromDOM (node, default_namespace=None):
1694 """Create a Python instance from the given DOM node.
1695 The node tag must correspond to an element declaration in this module.
1696
1697 @deprecated: Forcing use of DOM interface is unnecessary; use L{CreateFromDocument}."""
1698 if default_namespace is None:
1699 default_namespace = Namespace.fallbackNamespace()
1700 return pyxb.binding.basis.element.AnyCreateFromDOM(node, default_namespace)
1701
1702 ''', **template_map))
1703
1704 __components = None
1705 __componentBindingName = None
1706
1715
1718
1720 """This class represents a Python module that holds all the
1721 declarations belonging to a set of namespaces which have
1722 interdependencies."""
1723
1726 __namespaceModules = None
1727
1733
1734 __components = None
1735 __componentBindingName = None
1736 __uniqueInModule = None
1737
1738 __UniqueInGroups = set()
1739
1740 _GroupPrefix = '_group'
1741
1742 - def __init__ (self, generator, namespace_modules, **kw):
1749
1751 kw = { 'moduleType' : 'namespaceGroup' }
1752 return kw
1753
1756
1763
1764 - def _finalizeModuleContents_vx (self, template_map):
1765 self.bindingIO().prolog().append(self.bindingIO().expand('''
1766 from __future__ import unicode_literals
1767 import pyxb
1768 import pyxb.binding
1769 import pyxb.utils.utility
1770 import pyxb.utils.six as _six
1771
1772 # Unique identifier for bindings created at the same time
1773 _GenerationUID = %{generation_uid_expr}
1774
1775 # Import bindings for schemas in group
1776 %{aux_imports}
1777
1778 # NOTE: All namespace declarations are reserved within the binding
1779 %{namespace_decls}
1780 ''', **template_map))
1781
1792
1795
1796
1797 -def GeneratePython (schema_location=None,
1798 schema_text=None,
1799 namespace=None,
1800 module_prefix_elts=[],
1801 **kw):
1812
1813 import optparse
1814 import re
1817 """Configuration and data for a single binding-generation action."""
1818
1819 _DEFAULT_bindingRoot = '.'
1821 """The directory path into which generated bindings will be written.
1822 @rtype: C{str}"""
1823 return self.__bindingRoot
1827 __bindingRoot = None
1828
1830 if isinstance(module_elts, six.string_types):
1831 module_elts = module_elts.split('.')
1832 else:
1833 module_elts = module_elts[:]
1834 assert 0 < len(module_elts)
1835 if not inhibit_extension:
1836 assert not module_elts[-1].endswith('.py')
1837 module_elts[-1] = '%s.py' % (module_elts[-1],)
1838 return os.path.join(self.bindingRoot(), *module_elts)
1839
1842 __generateToFiles = None
1843
1845
1846
1847
1848
1849 module_path = None
1850 if isinstance(module, NamespaceModule):
1851 mr = module.moduleRecord()
1852 if mr is None:
1853 return ('/dev/null', None, None)
1854 if self.generationUID() != mr.generationUID():
1855 return ('/dev/null', None, None)
1856 if not self.generateToFiles():
1857 return ('/dev/null', None, None)
1858 if mr.namespace().isBuiltinNamespace() and (not self.allowBuiltinGeneration()):
1859 return ('/dev/null', None, None)
1860 module_path = mr.modulePath()
1861 assert module_path is not None, 'No path specified for module %s' % (mr,)
1862
1863
1864
1865 module_elts = module_path.split('.')
1866 if self.writeForCustomization():
1867 import_file_path = self.__moduleFilePath(module_elts)
1868 module_elts.insert(-1, 'raw')
1869 if not os.path.exists(import_file_path):
1870 raw_module_path = '.'.join(module_elts)
1871 fd = pyxb.utils.utility.OpenOrCreate(import_file_path)
1872 impt = '''# -*- coding: utf-8 -*-
1873 from %s import *
1874 ''' % (raw_module_path,)
1875 impd = impt.encode('utf-8')
1876 fd.write(impd)
1877 fd.close()
1878 binding_file_path = self.__moduleFilePath(module_elts)
1879 try:
1880 binding_file = pyxb.utils.utility.OpenOrCreate(binding_file_path, tag=module.moduleUID())
1881 except OSError as e:
1882 if errno.EEXIST == e.errno:
1883 raise pyxb.BindingGenerationError('Target file %s for module %s bindings exists with other content' % (binding_file_path, mr))
1884 raise
1885 elif isinstance(module, NamespaceGroupModule):
1886 if not self.generateToFiles():
1887 raise pyxb.BindingGenerationError('Generation of namespace groups requires generate-to-files')
1888 module_elts = []
1889 if self.modulePrefix():
1890 module_elts.extend(self.modulePrefix().split('.'))
1891 if self.writeForCustomization():
1892 module_elts.append('raw')
1893 in_use = set()
1894 while True:
1895 module_elts.append(pyxb.utils.utility.PrepareIdentifier('nsgroup', in_use, protected=True))
1896 try:
1897 binding_file_path = self.__moduleFilePath(module_elts)
1898 _log.info('Attempting group %s uid %s at %s', module, module.moduleUID(), binding_file_path)
1899 binding_file = pyxb.utils.utility.OpenOrCreate(binding_file_path, tag=module.moduleUID())
1900 break
1901 except OSError as e:
1902 if errno.EEXIST != e.errno:
1903 raise
1904 module_elts.pop()
1905 module_path = '.'.join(module_elts)
1906 else:
1907 assert False
1908 if self.generateToFiles():
1909 for n in range(len(module_elts)-1):
1910 sub_path = self.__moduleFilePath(module_elts[:1+n], inhibit_extension=True)
1911 init_path = os.path.join(sub_path, '__init__.py')
1912 if not os.path.exists(init_path):
1913 open(init_path, 'w')
1914 return (binding_file_path, binding_file, module_path)
1915
1917 """The directory from which entrypoint schemas specified as
1918 relative file paths will be read."""
1919 return self.__schemaRoot
1921 if not schema_root.endswith(os.sep):
1922 schema_root = schema_root + os.sep
1923 self.__schemaRoot = schema_root
1924 return self
1925 __schemaRoot = None
1926
1928 """Optional string that is stripped from the beginning of
1929 schemaLocation values before loading from them.
1930
1931 This applies only to the values of schemaLocation attributes
1932 in C{import} and C{include} elements. Its purpose is to
1933 convert absolute schema locations into relative ones to allow
1934 offline processing when all schema are available in a local
1935 directory. See C{schemaRoot}.
1936 """
1937 return self.__schemaStrippedPrefix
1941 __schemaStrippedPrefix = None
1942
1944 """Optional map to rewrite schema locations.
1945
1946 This applies only to the values of schemaLocation attributes
1947 in C{import} and C{include} elements. Its purpose is to
1948 convert remote or absolute schema locations into local or
1949 relative ones to allow offline processing when all schema are
1950 available in a local directory. See C{schemaRoot}.
1951 """
1952 return self.__locationPrefixRewriteMap
1958 """Add a rewrite entry for schema locations.
1959
1960 @param prefix : A text prefix that should be removed from
1961 schema location URIs.
1962
1963 @param substituent : The text prefix that should replace
1964 C{prefix} as a prefix in a schema location URI.
1965 """
1966
1967 self.__locationPrefixRewriteMap[prefix] = substituent
1968 return self
1970 """Add a rewrite entry for schema locations.
1971
1972 Parameter values are strings of the form C{pfx=sub}. The
1973 effect is that a schema location that begins with C{pfx} is
1974 rewritten so that it instead begins with C{sub}."""
1975 try:
1976 (prefix, substituent) = prefix_rewrite.split('=', 1)
1977 except:
1978 raise
1979 self.addLocationPrefixRewrite(prefix, substituent)
1980 __locationPrefixMap = {}
1981
1983 """A list of locations from which entrypoint schemas are to be
1984 read.
1985
1986 The values in the list are either URIs, or tuples consisting
1987 of a value and a callable which, when passed the generator
1988 object and the value, will return a
1989 L{pyxb.xmlschema.structures.Schema} instance. See
1990 L{addSchemaLocation}.
1991
1992 See also L{addSchemaLocation} and L{schemas}.
1993 """
1994 return self.__schemaLocationList
2000 """Add the location of an entrypoint schema.
2001
2002 @param schema_location: The location of the schema. This
2003 should be a URL; if the schema location does not have a URL
2004 scheme (e.g., C{http:}), it is assumed to be a file, and if it
2005 is not an absolute path is located relative to the
2006 C{schemaRoot}.
2007
2008 @keyword converter: Optional callable that will be invoked
2009 with the generator instance and the schema location, and is
2010 expected to return a L{pyxb.xmlschema.structures.Schema}
2011 instance. If absent, the contents of the location are
2012 converted directly.
2013
2014 @note: The C{converter} argument derives from WSDL support: we
2015 need to add to the sequence of schema locations a URI of
2016 something that will not parse as a schema, but does have inner
2017 material that can if treated properly. "Treated properly" may
2018 include having the archive path and other namespace
2019 manipulations configured before anything is done to it.
2020 """
2021 self.__schemaLocationList.append( (schema_location, converter) )
2022 return self
2024 """Add the location of an entrypoint schema. The provided
2025 value should be a URL; if it does not have a URL scheme (e.g.,
2026 C{http:}), it is assumed to be a file, and if it is not an
2027 absolute path is located relative to the C{schemaRoot}."""
2028 self.addSchemaLocation(schema_location)
2029 __schemaLocationList = None
2030
2032 """Schema for which bindings should be generated.
2033
2034 These may be L{Schema<pyxb.xmlschema.structures.Schema>}
2035 instances, or strings; the latter is preferred, and is parsed
2036 into a Schema instance when required.
2037
2038 This is the list of entrypoint schemas for binding generation.
2039 Values in L{schemaLocationList} are read and converted into
2040 schema, then appended to this list. Values from L{moduleList}
2041 are applied starting with the first schema in this list.
2042 """
2043 return self.__schemas[:]
2051 __schemas = None
2052
2054 """The set of L{namespaces<pyxb.namespace.Namespace>} for
2055 which bindings will be generated.
2056
2057 This is the set of namespaces read from entrypoint schema,
2058 closed under reference to namespaces defined by schema import.
2059
2060 @rtype: C{set}
2061 """
2062 return self.__namespaces.copy()
2070 __namespaces = None
2071
2073 """A list of module names to be applied in order to the namespaces of entrypoint schemas"""
2074 return self.__moduleList[:]
2079
2081 """Add a module name corresponding to an entrypoint schema.
2082
2083 The namespace defined by the corresponding schema will be
2084 written to a binding using the given module name, adjusted by
2085 L{modulePrefix}."""
2086 self.__moduleList.append(module_name)
2087 return self
2088 __moduleList = None
2089
2091 """The prefix for binding modules.
2092
2093 The base name for the module holding a binding is taken from
2094 the moduleList, moduleMap, or an XMLNS prefix associated with
2095 the namespace in a containing schema. This value, if present,
2096 is used as a prefix to allow a deeper module hierarchy."""
2097 return self.__modulePrefix
2101 __modulePrefix = None
2102
2104 """A map from namespace URIs to the module to be used for the
2105 corresponding generated binding.
2106
2107 Module values are adjusted by L{modulePrefix} if that has been
2108 specified.
2109
2110 An entry in this map for a namespace supersedes the module
2111 specified in moduleList if the namespace is defined by an
2112 entrypoint schema.
2113
2114 @return: A reference to the namespace module map.
2115 """
2116 return self.__namespaceModuleMap
2117 __namespaceModuleMap = None
2118
2120 """A colon-separated list of paths from which namespace
2121 archives can be read.
2122
2123 The default path is the contents of the C{PYXB_ARCHIVE_PATH}
2124 environment variable, or the standard path configured at
2125 installation time. Any file with the extension C{.wxs} found
2126 in one of these directories is examined to see whether it is a
2127 namespace archive.
2128 """
2129 return self.__archivePath
2133 __archivePath = None
2134
2136 """A frozenset of namespaces that must not be loaded from an archive."""
2137 return frozenset(self.__noLoadNamespaces)
2139 """Record the set of namespaces that should not be loaded from an archive.
2140
2141 The expectation is that any required entities in the namespace
2142 will be defined by loading schema."""
2143 self.__noLoadNamespaces.clear()
2144 self.__noLoadNamespaces.update([ pyxb.namespace.NamespaceInstance(_ns) for _ns in namespace_set ])
2146 """Mark that the specified namespace should not be loaded from an archive.
2147
2148 Use this when you are generating bindings for an application
2149 that has a restricted profile of a namespace that would
2150 otherwise be read from an archive. Be aware that this removes
2151 any knowledge of any archive in which this namespace is
2152 present as a non-private member."""
2153 self.__noLoadNamespaces.add(pyxb.namespace.NamespaceInstance(namespace))
2154 __noloadNamespaces = None
2155
2164 """Mark that the specified namespace may be imported by new bindings.
2165
2166 Normally namespaces that are available from archives are
2167 considered to be complete, and schema locations in import
2168 directives are ignored. Use this to indicate that the
2169 bindings being generated import new bindings.
2170
2171 Note that attempts to import schema that contributed to the
2172 archive will only be detected if the archive was generated
2173 from the same schemaLocation URI; if the archive was generated
2174 from a different source component definitions might
2175 conflict."""
2176 self.__importAugmentableNamespaces.add(pyxb.namespace.NamespaceInstance(namespace))
2177 __importAugmentableNamespaces = None
2178
2180 """Optional file into which the archive of namespaces will be written.
2181
2182 Subsequent generation actions can read pre-parsed namespaces
2183 from this file, and therefore reference the bindings that were
2184 built earlier rather than re-generating them.
2185
2186 The file name should normally end with C{.wxs}."""
2187 return self.__archiveToFile
2191 __archiveToFile = None
2192
2206 """Indicates, for specific namespaces, whether their
2207 visibility in the archive should be public or private."""
2208 return self.__namespaceVisibilityMap.copy()
2209 __namespaceVisibilityMap = None
2210
2212 """Indicates whether unmentioned namespaces will be public or private (default) in the archive.
2213
2214 A namespace is I{mentioned} if it is the target namespace of
2215 an entrypoint schema, or appears in a namespace visibility
2216 specification. I.e., this default applies only to namespaces
2217 that are modified as a result of including some schema, which
2218 is generally a local customization of something.
2219 """
2220 return self.__defaultNamespacePublic
2223 __defaultNamespacePublic = None
2224
2226 """Indicates whether the bindings should validate mutations
2227 against the content model."""
2228 return self.__validateChanges
2232 __validateChanges = None
2233
2235 """Indicates whether the binding Python code should be written into a sub-module for customization.
2236
2237 If enabled, a module C{path.to.namespace} will be written to
2238 the file C{path/to/raw/namespace.py}, so that the file
2239 C{path/to/namespace.py} can import it and override behavior."""
2240 return self.__writeForCustomization
2244 __writeForCustomization = None
2245
2247 """Indicates whether the code generator is permitted to
2248 process namespace for which no module path can be determined.
2249
2250 Use this only when generating bindings that will not be
2251 referenced by other bindings."""
2252 return self.__allowAbsentModule
2256 __allowAbsentModule = None
2257
2259 """Indicates whether bindings will be written for namespaces that are built-in to PyXB.
2260
2261 This must be enabled when building bindings for the XML,
2262 XMLSchema instance, and other built-in namespaces. Normally
2263 generation of these namespaces is inhibited lest it produce
2264 inconsistencies."""
2265 return self.__allowBuiltinGeneration
2269 __allowBuiltinGeneration = None
2270
2272 """The directory path into which any content retrieved by URI will be written.
2273
2274 This serves as a local cache, and to give you an opportunity
2275 to inspect material retrieved from some other system.
2276 @rtype: C{str}"""
2277 return self.__uriContentArchiveDirectory
2280 __uriContentArchiveDirectory = None
2281
2283 """A file provided to L{logging.config.fileConfig} to control log messages.
2284
2285 In the absence of other configuration the Python standard logging infrastructure is used in its
2286 default configuration.
2287
2288 @rtype: C{str}"""
2289 return self.__loggingConfigFile
2292 __loggingConfigFile = None
2293
2295 """Create a configuration to be used for generating bindings.
2296
2297 Arguments are treated as additions to the schema location list
2298 after all keywords have been processed.
2299
2300 @keyword binding_root: Invokes L{setBindingRoot}
2301 @keyword schema_root: Invokes L{setSchemaRoot}
2302 @keyword schema_stripped_prefix: Invokes L{setSchemaStrippedPrefix}
2303 @keyword location_prefix_rewrite_map: Invokes L{setLocationPrefixRewriteMap}
2304 @keyword schema_location_list: Invokes L{setSchemaLocationList}
2305 @keyword module_list: Invokes L{_setModuleList}
2306 @keyword module_prefix: Invokes L{setModulePrefix}
2307 @keyword archive_path: Invokes L{setArchivePath}
2308 @keyword no_load_namespaces: Invokes L{_setNoLoadNamespaces}
2309 @keyword import_augmentable_namespaces: Invokes L{_setImportAugmentableNamespaces}
2310 @keyword archive_to_file: Invokes L{setArchiveToFile}
2311 @keyword public_namespace: Invokes L{setNamespaceVisibility}
2312 @keyword private_namespace: Invokes L{setNamespaceVisibility}
2313 @keyword default_namespace_public: Invokes L{setDefaultNamespacePublic}
2314 @keyword validate_changes: Invokes L{setValidateChanges}
2315 @keyword namespace_module_map: Initializes L{namespaceModuleMap}
2316 @keyword schemas: Invokes L{setSchemas}
2317 @keyword namespaces: Invokes L{setNamespaces}
2318 @keyword write_for_customization: Invokes L{setWriteForCustomization}
2319 @keyword allow_builtin_generation: Invokes L{setAllowBuiltinGeneration}
2320 @keyword allow_absent_module: Invokes L{setAllowAbsentModule}
2321 @keyword generate_to_files: Sets L{generateToFiles}
2322 @keyword uri_content_archive_directory: Invokes L{setUriContentArchiveDirectory}
2323 @keyword logging_config_file: Invokes L{setLoggingConfigFile}
2324 """
2325 argv = kw.get('argv')
2326 if argv is not None:
2327 kw = {}
2328 self.__bindingRoot = kw.get('binding_root', self._DEFAULT_bindingRoot)
2329 self.__schemaRoot = kw.get('schema_root', '.')
2330 self.__schemaStrippedPrefix = kw.get('schema_stripped_prefix')
2331 self.__locationPrefixRewriteMap = kw.get('location_prefix_rewrite_map', {})
2332 self.__schemas = []
2333 self.__schemaLocationList = kw.get('schema_location_list', [])[:]
2334 self.__moduleList = kw.get('module_list', [])[:]
2335 self.__modulePrefix = kw.get('module_prefix')
2336 self.__archivePath = kw.get('archive_path', pyxb.namespace.archive.GetArchivePath())
2337 self.__noLoadNamespaces = kw.get('no_load_namespaces', set()).copy()
2338 self.__importAugmentableNamespaces = kw.get('import_augmentable_namespaces', set()).copy()
2339 self.__archiveToFile = kw.get('archive_to_file')
2340 self.__namespaceVisibilityMap = {}
2341 self._setNamespaceVisibilities(kw.get('public_namespaces', set()), kw.get('private_namespaces', set()))
2342 self.__defaultNamespacePublic = kw.get('default_namespace_public', False)
2343 self.__validateChanges = kw.get('validate_changes', True)
2344 self.__namespaceModuleMap = kw.get('namespace_module_map', {}).copy()
2345 self.__schemas = kw.get('schemas', [])[:]
2346 self.__namespaces = set(kw.get('namespaces', []))
2347 self.__writeForCustomization = kw.get('write_for_customization', False)
2348 self.__allowBuiltinGeneration = kw.get('allow_builtin_generation', False)
2349 self.__allowAbsentModule = kw.get('allow_absent_module', False)
2350 self.__generateToFiles = kw.get('generate_to_files', True)
2351 self.__uriContentArchiveDirectory = kw.get('uri_content_archive_directory')
2352 self.__loggingConfigFile = kw.get('logging_config_file')
2353 self.__unnamedModulePaths = set()
2354
2355 if argv is not None:
2356 self.applyOptionValues(*self.optionParser().parse_args(argv))
2357 [ self.addSchemaLocation(_a) for _a in args ]
2358
2359 self.__generationUID = pyxb.utils.utility.UniqueIdentifier()
2360
2361 pyxb.namespace.XML.validateComponentModel()
2362
2363 __stripSpaces_re = re.compile('\s\s\s+')
2366
2367 __OptionSetters = (
2368 ('binding_root', setBindingRoot),
2369 ('schema_root', setSchemaRoot),
2370 ('schema_stripped_prefix', setSchemaStrippedPrefix),
2371 ('location_prefix_rewrite', argAddLocationPrefixRewrite),
2372 ('schema_location', setSchemaLocationList),
2373 ('module', _setModuleList),
2374 ('module_prefix', setModulePrefix),
2375 ('archive_path', setArchivePath),
2376 ('no_load_namespace', _setNoLoadNamespaces),
2377 ('import_augmentable_namespace', _setImportAugmentableNamespaces),
2378 ('archive_to_file', setArchiveToFile),
2379 ('default_namespace_public', setDefaultNamespacePublic),
2380 ('validate_changes', setValidateChanges),
2381 ('write_for_customization', setWriteForCustomization),
2382 ('allow_builtin_generation', setAllowBuiltinGeneration),
2383 ('allow_absent_module', setAllowAbsentModule),
2384 ('uri_content_archive_directory', setUriContentArchiveDirectory),
2385 ('logging_config_file', setLoggingConfigFile)
2386 )
2400
2402 if argv is None:
2403 argv = sys.argv[1:]
2404 (options, args) = self.optionParser().parse_args(argv)
2405 self.applyOptionValues(options, args)
2406 return self
2407
2409 """A unique identifier associated with this Generator instance.
2410
2411 This is an instance of L{pyxb.utils.utility.UniqueIdentifier}.
2412 Its associated objects are
2413 L{pyxb.namespace.archive._SchemaOrigin} instances, which
2414 identify schema that contribute to the definition of a
2415 namespace."""
2416 return self.__generationUID
2417 __generationUID = None
2418
2420 """Return an C{optparse.OptionParser} instance tied to this configuration.
2421
2422 @param reset: If C{False} (default), a parser created in a
2423 previous invocation will be returned. If C{True}, any
2424 previous option parser is discarded and a new one created.
2425 @type reset: C{bool}
2426 """
2427 if reset or (self.__optionParser is None):
2428 parser = optparse.OptionParser(usage="%prog [options] [more schema locations...]",
2429 version='%%prog from PyXB %s' % (pyxb.__version__,),
2430 description='Generate bindings from a set of XML schemas')
2431
2432 group = optparse.OptionGroup(parser, 'Identifying Schema', 'Specify and locate schema for which bindings should be generated.')
2433 group.add_option('--schema-location', '-u', metavar="FILE_or_URL",
2434 action='append',
2435 help=self.__stripSpaces(self.argAddSchemaLocation.__doc__))
2436 group.add_option('--schema-root', metavar="DIRECTORY",
2437 help=self.__stripSpaces(self.schemaRoot.__doc__))
2438 group.add_option('--schema-stripped-prefix', metavar="TEXT", type='string',
2439 help=self.__stripSpaces(self.schemaStrippedPrefix.__doc__))
2440 group.add_option('--location-prefix-rewrite', metavar="TEXT", type='string',
2441 help=self.__stripSpaces(self.argAddLocationPrefixRewrite.__doc__))
2442 group.add_option('--uri-content-archive-directory', metavar="DIRECTORY",
2443 help=self.__stripSpaces(self.uriContentArchiveDirectory.__doc__))
2444 parser.add_option_group(group)
2445
2446 group = optparse.OptionGroup(parser, 'Configuring Bindings', 'Specify where generated bindings should be written, and how they will be accessed from Python.')
2447 group.add_option('--module', '-m', metavar="MODULE",
2448 action='append',
2449 help=self.__stripSpaces(self.addModuleName.__doc__))
2450 group.add_option('--module-prefix', metavar="MODULE",
2451 help=self.__stripSpaces(self.modulePrefix.__doc__))
2452 group.add_option('--binding-root', metavar="DIRECTORY",
2453 help=self.__stripSpaces(self.bindingRoot.__doc__))
2454 group.add_option('-r', '--write-for-customization',
2455 action='store_true', dest='write_for_customization',
2456 help=self.__stripSpaces(self.writeForCustomization.__doc__ + ' This option turns on the feature.'))
2457 group.add_option('--no-write-for-customization',
2458 action='store_false', dest='write_for_customization',
2459 help=self.__stripSpaces(self.writeForCustomization.__doc__ + ' This option turns off the feature (I{default}).'))
2460 parser.add_option_group(group)
2461
2462 group = optparse.OptionGroup(parser, 'Reading Namespace Archives', 'Locating and loading (or inhibiting load of) namespace archives.')
2463 group.add_option('--archive-path', metavar="PATH",
2464 help=self.__stripSpaces(self.archivePath.__doc__))
2465 group.add_option('--import-augmentable-namespace', metavar="URI",
2466 action='append',
2467 help=self.__stripSpaces(self.addImportAugmentableNamespace.__doc__))
2468 group.add_option('--no-load-namespace', metavar="URI",
2469 action='append',
2470 help=self.__stripSpaces(self.addNoLoadNamespace.__doc__))
2471 parser.add_option_group(group)
2472
2473 group = optparse.OptionGroup(parser, 'Writing Namespace Archives', 'Control the location and content of a namespace archive corresponding to a binding generation.')
2474 group.add_option('--archive-to-file', metavar="FILE",
2475 help=self.__stripSpaces(self.archiveToFile.__doc__))
2476 group.add_option('--public-namespace', metavar="URI",
2477 action='append',
2478 help=self.__stripSpaces(self.namespaceVisibilityMap.__doc__ + ' This option adds the namespace as a public archive member.'))
2479 group.add_option('--private-namespace', metavar="URI",
2480 action='append',
2481 help=self.__stripSpaces(self.namespaceVisibilityMap.__doc__ + ' This option adds the namespace as a private archive member.'))
2482 group.add_option('--default-namespace-public',
2483 action="store_true", dest='default_namespace_public',
2484 help=self.__stripSpaces(self.defaultNamespacePublic.__doc__ + ' This option makes the default C{public} (I{default}).'))
2485 group.add_option('--default-namespace-private',
2486 action="store_false", dest='default_namespace_public',
2487 help=self.__stripSpaces(self.defaultNamespacePublic.__doc__ + ' This option makes the default C{private}.'))
2488 parser.add_option_group(group)
2489
2490 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.")
2491 group.add_option('--validate-changes',
2492 action='store_true', dest='validate_changes',
2493 help=self.__stripSpaces(self.validateChanges.__doc__ + ' This option turns on validation (default).'))
2494 group.add_option('--no-validate-changes',
2495 action='store_false', dest='validate_changes',
2496 help=self.__stripSpaces(self.validateChanges.__doc__ + ' This option turns off validation.'))
2497 parser.add_option_group(group)
2498
2499 group = optparse.OptionGroup(parser, 'Miscellaneous Options', "Anything else.")
2500 group.add_option('--logging-config-file', metavar="FILE",
2501 help=self.__stripSpaces(self.loggingConfigFile.__doc__))
2502 parser.add_option_group(group)
2503
2504 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.")
2505
2506 group.add_option('--allow-absent-module',
2507 action='store_true', dest='allow_absent_module',
2508 help=self.__stripSpaces(self.allowAbsentModule.__doc__ + ' This option turns on the feature.'))
2509 group.add_option('--no-allow-absent-module',
2510 action='store_false', dest='allow_absent_module',
2511 help=self.__stripSpaces(self.allowAbsentModule.__doc__ + ' This option turns off the feature (default).'))
2512 group.add_option('--allow-builtin-generation',
2513 action='store_true', dest='allow_builtin_generation',
2514 help=self.__stripSpaces(self.allowBuiltinGeneration.__doc__ + ' This option turns on the feature.'))
2515 group.add_option('--no-allow-builtin-generation',
2516 action='store_false', dest='allow_builtin_generation',
2517 help=self.__stripSpaces(self.allowBuiltinGeneration.__doc__ + ' This option turns off the feature (default).'))
2518 parser.add_option_group(group)
2519
2520 self.__optionParser = parser
2521 return self.__optionParser
2522 __optionParser = None
2523
2525 """Return a command line option sequence that could be used to
2526 construct an equivalent configuration.
2527
2528 @note: If you extend the option parser, as is done by
2529 C{pyxbgen}, this may not be able to reconstruct the correct
2530 command line."""
2531 opts = []
2532 module_list = self.moduleList()
2533 schema_list = self.schemaLocationList()
2534 while module_list and schema_list:
2535 ml = module_list.pop(0)
2536 sl = schema_list.pop(0)
2537 if isinstance(sl, tuple):
2538 sl = sl[0]
2539 opts.extend(['--schema-location=' + sl, '--module=' + ml])
2540 for sl in schema_list:
2541 opts.append('--schema-location=' + sl)
2542 if self.schemaRoot() is not None:
2543 opts.append('--schema-root=' + self.schemaRoot())
2544 if self.schemaStrippedPrefix() is not None:
2545 opts.append('--schema-stripped-prefix=%s' + self.schemaStrippedPrefix())
2546 for (pfx, sub) in self.locationPrefixRewriteMap():
2547 opts.append('--location-prefix-rewrite=%s=%s' % (pfx, sub))
2548 if self.modulePrefix() is not None:
2549 opts.append('--module-prefix=' + self.modulePrefix())
2550 opts.append('--binding-root=' + self.bindingRoot())
2551 if self.archivePath() is not None:
2552 opts.append('--archive-path=' + self.archivePath())
2553 for ns in self.noLoadNamespaces():
2554 opts.append('--no-load-namespace=' + ns.uri())
2555 for ns in self.importAugmentableNamespaces():
2556 opts.append('--import-augmentable-namespace=' + ns.uri())
2557 if self.archiveToFile() is not None:
2558 opts.append('--archive-to-file=' + self.archiveToFile())
2559 for (ns, visibility) in self.namespaceVisibilityMap():
2560 if visibility:
2561 opts.append('--public-namespace=' + ns.uri())
2562 else:
2563 opts.append('--private-namespace=' + ns.uri())
2564 if self.defaultNamespacePublic():
2565 opts.append('--default-namespace-public')
2566 else:
2567 opts.append('--default-namespace-private')
2568 for (val, opt) in ( (self.validateChanges(), 'validate-changes'),
2569 (self.writeForCustomization(), 'write-for-customization'),
2570 (self.allowAbsentModule(), 'allow-absent-module'),
2571 (self.allowBuiltinGeneration(), 'allow-builtin-generation') ):
2572 if val:
2573 opts.append('--' + opt)
2574 else:
2575 opts.append('--no-' + opt)
2576 if self.uriContentArchiveDirectory() is not None:
2577 opts.append('--uri-content-archive-directory=%s' + self.uriContentArchiveDirectory())
2578 return opts
2579
2585
2587 """Provide a Python module path for the module record.
2588
2589 This is the path by which the module bindings associated with
2590 C{module_record} will be imported.
2591
2592 If a path had already been assigned to the module, it is left
2593 in place.
2594
2595 @param module_record: Information about a collection of related bindings
2596 @type module_record: L{pyxb.namespace.archive.ModuleRecord}
2597
2598 @param module_path: Default path to use
2599 @type module_path: C{str}
2600
2601 @return: C{module_record}
2602 """
2603 if module_record.modulePath() is not None:
2604 return module_record
2605 namespace = module_record.namespace()
2606 if not namespace.isAbsentNamespace():
2607
2608 if (module_path is None) and not (namespace.prefix() is None):
2609 module_path = namespace.prefix()
2610
2611 module_path = self.namespaceModuleMap().get(namespace.uri(), module_path)
2612 if (module_path is None) and self.generateToFiles():
2613 module_path = pyxb.utils.utility.MakeUnique('binding', self.__unnamedModulePaths)
2614 if (module_path is not None) and self.modulePrefix():
2615
2616 module_path = '.'.join([self.modulePrefix(), module_path])
2617 module_record.setModulePath(module_path)
2618 return module_record
2619
2620 __didResolveExternalSchema = False
2622 if self.__didResolveExternalSchema:
2623 return
2624
2625
2626
2627 pyxb.namespace.archive.NamespaceArchive.PreLoadArchives(self.archivePath())
2628
2629
2630
2631
2632 for ns in self.noLoadNamespaces():
2633 assert isinstance(ns, pyxb.namespace.Namespace)
2634 _log.info("Namespace %s marked not loadable" % (ns,))
2635 ns.markNotLoadable()
2636
2637
2638
2639 for ns in self.importAugmentableNamespaces():
2640 assert isinstance(ns, pyxb.namespace.Namespace)
2641 _log.info("Namespace %s marked import-augmentable" % (ns,))
2642 ns.setImportAugmentable(True)
2643
2644
2645 while self.__schemaLocationList:
2646 sl = self.__schemaLocationList.pop(0)
2647 if isinstance(sl, tuple):
2648 (sl, converter) = sl
2649 else:
2650 converter = None
2651 try:
2652 if converter is None:
2653 schema = xs.schema.CreateFromLocation(absolute_schema_location=self.normalizeSchemaLocation(sl),
2654 generation_uid=self.generationUID(),
2655 uri_content_archive_directory=self.uriContentArchiveDirectory())
2656 else:
2657 schema = converter(self, sl)
2658 self.addSchema(schema)
2659 except pyxb.SchemaUniquenessError as e:
2660 _log.info('Skipped redundant translation of %s defining %s', e.schemaLocation(), e.namespace())
2661 self.addSchema(e.existingSchema())
2662
2663
2664
2665 for schema in self.__schemas:
2666 if isinstance(schema, six.string_types):
2667 schema = xs.schema.CreateFromDocument(schema, generation_uid=self.generationUID())
2668 origin = schema.originRecord()
2669 assert origin is not None
2670 module_path = None
2671 if self.__moduleList:
2672 module_path = self.__moduleList.pop(0)
2673 self.assignModulePath(origin.moduleRecord(), module_path)
2674 assert schema.targetNamespace() == origin.moduleRecord().namespace()
2675 self.addNamespace(schema.targetNamespace())
2676 self.__didResolveExternalSchema = True
2677
2678
2679 self.__componentGraph = None
2680 self.__componentOrder = None
2681
2705
2751
2752 __moduleRecords = None
2753 __componentGraph = None
2754 __componentOrder = None
2755
2757 """The set of L{pyxb.namespace.archive.ModuleRecord} instances
2758 associated with schema processed in this generation
2759 instance.
2760
2761 These should be in one-to-one correspondence with the
2762 namespaces for which bindings are being generated. Multiple
2763 input schemas may contribute to a single module record; all
2764 material in that record is placed in a single binding file.
2765 """
2766 if self.__moduleRecords is None:
2767 self.__resolveComponentDependencies()
2768 return self.__moduleRecords
2769
2774
2779
2781
2782
2783
2784
2785
2786 module_graph = pyxb.utils.utility.Graph()
2787 [ module_graph.addRoot(_mr) for _mr in self.moduleRecords() ]
2788 for (s, t) in self.componentGraph().edges():
2789 module_graph.addEdge(s._objectOrigin().moduleRecord(), t._objectOrigin().moduleRecord())
2790 module_scc_order = module_graph.sccOrder()
2791
2792 record_binding_map = {}
2793 modules = []
2794 nsvm = self.namespaceVisibilityMap()
2795 for mr_scc in module_scc_order:
2796 scc_modules = [ ]
2797 for mr in mr_scc:
2798 mr._setIsPublic(nsvm.get(mr.namespace(), self.defaultNamespacePublic()))
2799 self.assignModulePath(mr)
2800 if (mr.modulePath() is None) and self.generateToFiles():
2801 raise pyxb.BindingGenerationError('No prefix or module name available for %s' % (mr,))
2802 if (not mr.isPublic()) and (mr.modulePath() is not None):
2803 elts = mr.modulePath().split('.')
2804 elts[-1] = '_%s' % (elts[-1],)
2805 mr.setModulePath('.'.join(elts))
2806 nsm = NamespaceModule(self, mr, mr_scc)
2807 record_binding_map[mr] = nsm
2808 scc_modules.append(nsm)
2809
2810 scc_modules.sort(key=lambda _nm: _nm.namespace().uri())
2811 modules.extend(scc_modules)
2812 if 1 < len(mr_scc):
2813 ngm = NamespaceGroupModule(self, scc_modules)
2814 modules.append(ngm)
2815 for nsm in scc_modules:
2816 nsm.setNamespaceGroupModule(ngm)
2817
2818 element_declarations = []
2819 type_definitions = []
2820 for c in self.componentOrder():
2821 if isinstance(c, xs.structures.ElementDeclaration) and c._scopeIsGlobal():
2822
2823 nsm = record_binding_map[c._objectOrigin().moduleRecord()]
2824 nsm.bindComponent(c)
2825 element_declarations.append(c)
2826 elif c.isTypeDefinition():
2827 type_definitions.append(c)
2828 else:
2829
2830 pass
2831
2832 simple_type_definitions = []
2833 complex_type_definitions = []
2834 for td in type_definitions:
2835 nsm = record_binding_map[td._objectOrigin().moduleRecord()]
2836 assert nsm is not None, 'No namespace module for %s type %s scope %s namespace %s' % (td.expandedName(), type(td), td._scope(), td.bindingNamespace)
2837 module_context = nsm.bindComponent(td)
2838 assert isinstance(module_context, _ModuleNaming_mixin), 'Unexpected type %s' % (type(module_context),)
2839 if isinstance(td, xs.structures.SimpleTypeDefinition):
2840 _PrepareSimpleTypeDefinition(td, self, nsm, module_context)
2841 simple_type_definitions.append(td)
2842 elif isinstance(td, xs.structures.ComplexTypeDefinition):
2843 _PrepareComplexTypeDefinition(td, self, nsm, module_context)
2844 complex_type_definitions.append(td)
2845 else:
2846 assert False, 'Unexpected component type %s' % (type(td),)
2847
2848 for ngm in modules:
2849 if isinstance(ngm, NamespaceGroupModule):
2850 for m in ngm.namespaceModules():
2851 m.addImportsFrom(ngm)
2852
2853 for std in simple_type_definitions:
2854 GenerateSTD(std, self)
2855 for ctd in complex_type_definitions:
2856 GenerateCTD(ctd, self)
2857 for ed in element_declarations:
2858 GenerateED(ed, self)
2859
2860 self.__bindingModules = modules
2861
2862 __bindingModules = None
2869
2885
2888