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
126
136
144
152
192
194
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
199 if isinstance(value, six.list_type):
200 return [ pythonLiteral(_v, **kw) for _v in value ]
201
202
203 if isinstance(value, pyxb.namespace.ExpandedName):
204 return pythonLiteral(ReferenceExpandedName(expanded_name=value, **kw))
205
206
207 if isinstance(value, (six.tuple_type, set)):
208 return type(value)(pythonLiteral(list(value), **kw))
209
210
211
212 if isinstance(value, facets._Enumeration_mixin):
213 return pythonLiteral(ReferenceEnumerationMember(enum_value=value, **kw))
214
215
216
217
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
234 if isinstance(value, facets._PatternElement):
235 return pythonLiteral(value.pattern)
236
237
238 if isinstance(value, facets._EnumerationElement):
239 return pythonLiteral(value.value())
240
241
242 if isinstance(value, xs.structures.Wildcard):
243 return pythonLiteral(ReferenceWildcard(value, **kw))
244
245
246 if isinstance(value, xs.structures._SchemaComponent_mixin):
247 return pythonLiteral(ReferenceSchemaComponent(value, **kw))
248
249
250 if isinstance(value, ReferenceLiteral):
251 return value.asLiteral()
252
253
254 if isinstance(value, pyxb.namespace.Namespace):
255 return repr2to3(value.uri())
256
257
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
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
288
289
290 st = xit.consumingState()
291
292
293
294
295
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
361
381
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
389
390 if (fi is None) and (fc in td.baseTypeDefinition().facets()):
391
392 continue
393 if (fi is not None) and (fi.ownerTypeDefinition() != td):
394
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
429
430
431 fi = td.facets().get(facets.CF_enumeration)
432 if fi is None:
433
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
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
468
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
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}
520 class %{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}
527 class %{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}
535 class %{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}
546 class %{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
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
601 import pyxb.utils.fac
602 import operator
603 import functools
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
654
655
656
657
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
669
670
671
672
673
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
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
740 pm.update(cm)
741
742
743
744 pm.update(c1.intersection(p1))
745
746
747
748 p1.difference_update(pm)
749 c1.difference_update(pm)
750
751
752
753 p1.symmetric_difference_update(c1)
754
755 def _ttPrePluralityWalk (node, pos, arg):
756
757
758 if isinstance(node, pyxb.utils.fac.MultiTermNode):
759 arg.append([])
760
761 def _ttPostPluralityWalk (node, pos, arg):
762
763 singles = set()
764 multiples = set()
765 combined = (singles, multiples)
766 if isinstance(node, pyxb.utils.fac.MultiTermNode):
767
768 term_list = arg.pop()
769 if isinstance(node, pyxb.utils.fac.Choice):
770
771
772 for (t1, tm) in term_list:
773 multiples.update(tm)
774 singles.update(t1)
775 else:
776
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
784 singles.add(term.baseDeclaration())
785 elif isinstance(term, xs.structures.Wildcard):
786 pass
787 else:
788 assert isinstance(term, list)
789
790 for tt in term:
791 _ttMergeSets(combined, BuildPluralityData(tt))
792 else:
793 assert isinstance(node, pyxb.utils.fac.NumericalConstraint)
794
795
796 combined = arg[-1].pop()
797 (singles, multiples) = combined
798 if 0 == node.max:
799
800
801 multiples.clear()
802 singles.clear()
803 elif 1 == node.max:
804
805 pass
806 else:
807
808
809 multiples.update(singles)
810 singles.clear()
811 arg[-1].append(combined)
812
813
814
815 arg = [[]]
816 term_tree.walkTermTree(_ttPrePluralityWalk, _ttPostPluralityWalk, arg)
817
818
819 assert 1 == len(arg)
820 arg = arg[0]
821 assert 1 == len(arg)
822 return arg[0]
823
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
845
846 @classmethod
849
850 @classmethod
851 - def Get (cls, ctd):
853
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}
898 class %{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
908
909
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
927 class_keywords = frozenset(basis.complexTypeDefinition._ReservedSymbols)
928 class_unique = set()
929
930
931
932
933
934
935
936 element_uses = []
937
938 definitions = []
939
940 definitions.append('# Base type is %{base_type}')
941
942
943
944
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
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
999 attribute_uses = []
1000
1001
1002
1003
1004
1005
1006
1007
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
1089
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
1118
1126
1128 use_map = component._templateMap()
1129 class_unique = nsm.uniqueInClass(container)
1130 assert isinstance(component, xs.structures._ScopedDeclaration_mixin)
1131 unique_name = utility.PrepareIdentifier(component.expandedName().localName(), class_unique)
1132 use_map['id'] = unique_name
1133 use_map['inspector'] = unique_name
1134 use_map['mutator'] = utility.PrepareIdentifier('set' + unique_name[0].upper() + unique_name[1:], class_unique)
1135 use_map['use'] = utility.MakeUnique('__' + unique_name.strip('_'), class_unique)
1136 assert component._scope() == container
1137 assert component.nameInBinding() is None, 'Use %s but binding name %s for %s' % (use_map['use'], component.nameInBinding(), component.expandedName())
1138 component.setNameInBinding(use_map['use'])
1139 key_name = six.u('%s_%s_%s') % (six.text_type(nsm.namespace()), container.nameInBinding(), component.expandedName())
1140 use_map['key'] = utility.PrepareIdentifier(key_name, class_unique, private=True)
1141 use_map['qname'] = six.text_type(component.expandedName())
1142 if isinstance(component, xs.structures.ElementDeclaration) and is_plural:
1143 use_map['appender'] = utility.PrepareIdentifier('add' + unique_name[0].upper() + unique_name[1:], class_unique)
1144 return use_map
1145
1147 __prolog = None
1148 __postscript = None
1149 __templateMap = None
1150 __stringIO = None
1151 __bindingFilePath = None
1152 __bindingFile = None
1153
1154 - def __init__ (self, binding_module, **kw):
1155 super(BindingIO, self).__init__()
1156 self.__bindingModule = binding_module
1157 self.__bindingFilePath = kw['binding_file_path']
1158 self.__bindingFile = kw['binding_file']
1159 self.__prolog = []
1160 self.__postscript = []
1161 self.__templateMap = kw.copy()
1162 encoding = kw.get('encoding', pyxb._OutputEncoding)
1163 self.__templateMap.update({ 'date' : str(datetime.datetime.now()),
1164 'filePath' : self.__bindingFilePath,
1165 'coding' : encoding,
1166 'binding_module' : binding_module,
1167 'binding_tag' : binding_module.bindingTag(),
1168 'pyxbVersion' : pyxb.__version__,
1169 'pyxb_version' : repr2to3(pyxb.__version__),
1170 'pythonVersion' : '.'.join(map(str, sys.version_info))})
1171 self.__stringIO = io.StringIO()
1172 if self.__bindingFile:
1173 prefacet = self.expand('''# %{filePath}
1174 # -*- coding: %{coding} -*-
1175 # PyXB bindings for %{binding_tag}
1176 # Generated %{date} by PyXB version %{pyxbVersion} using Python %{pythonVersion}
1177 %{binding_preface}''', binding_preface=binding_module.bindingPreface())
1178 self.__bindingFile.write(prefacet.encode(encoding))
1179 self.__bindingFile.flush()
1180
1183
1184 - def expand (self, template, **kw):
1188
1190 self.prolog().append(self.expand('''# Unique identifier for bindings created at the same time
1191 _GenerationUID = %{generation_uid_expr}
1192
1193 # Version of PyXB used to generate the bindings
1194 _PyXBVersion = %{pyxb_version}
1195 # Generated bindings are not compatible across PyXB versions
1196 if pyxb.__version__ != _PyXBVersion:
1197 raise pyxb.PyXBVersionError(_PyXBVersion)
1198
1199 # A holder for module-level binding classes so we can access them from
1200 # inside class definitions where property names may conflict.
1201 _module_typeBindings = pyxb.utils.utility.Object()
1202
1203 # Import bindings for namespaces imported into schema
1204 %{aux_imports}
1205
1206 # NOTE: All namespace declarations are reserved within the binding
1207 %{namespace_decls}
1208 ''', **tm))
1209
1210 - def write (self, template, **kw):
1213
1216 __bindingModule = None
1217
1220 - def postscript (self):
1221 return self.__postscript
1222
1226
1227 - def contents (self):
1228 rv = self.__prolog
1229 rv.append(self.__stringIO.getvalue())
1230 rv.extend(self.__postscript)
1231 return ''.join(rv)
1232
1234 __anonSTDIndex = None
1235 __anonCTDIndex = None
1236 __uniqueInModule = None
1237 __uniqueInClass = None
1238 __referencedFromClass = None
1239
1240 _UniqueInModule = set([ 'pyxb', 'sys', '_module_typeBindings' ])
1241 """Identifiers that are reserved within a module.
1242
1243 Subclasses extend this with the identifiers they add to the
1244 module. Module-level schema-derived identifiers (such as type
1245 definition and element names) are deconflicted from this set and
1246 from each other."""
1247
1248 _ReferencedFromClass = set([ 'pyxb', 'sys', '_module_typeBindings' ])
1249 """Identifiers defined in module that are accessed unqualified from class.
1250
1251 These include standard import module names and globals such as
1252 references to namespaces."""
1253
1254 __ComponentBindingModuleMap = {}
1255
1258 __generator = None
1259
1260 - def __init__ (self, generator, *args, **kw):
1275
1277 assert not isinstance(module, pyxb.namespace.Namespace)
1278 assert isinstance(module, (_ModuleNaming_mixin, pyxb.namespace.archive.ModuleRecord)), 'Unexpected type %s' % (type(module),)
1279 if isinstance(module, NamespaceModule):
1280 if pyxb.namespace.XMLSchema == module.namespace():
1281 return
1282 module = module.moduleRecord()
1283 assert isinstance(module, (pyxb.namespace.archive.ModuleRecord, NamespaceGroupModule))
1284 if not (module in self.__importModulePathMap):
1285 module_path = module.modulePath()
1286 if 'pyxb' == module_path.split('.', 2)[0]:
1287 assert 'pyxb' in self.uniqueInModule()
1288 assert 'pyxb' in self.__referencedFromClass
1289 module_path = None
1290 else:
1291 module_path = utility.PrepareIdentifier('ImportedBinding_' + module_path.replace('.', '_'),
1292 self.uniqueInModule(), protected=True)
1293 self.__referencedFromClass.add(module_path)
1294 self.__importModulePathMap[module] = module_path
1295
1316
1317 __referencedNamespaces = None
1318
1320 return self.__bindingIO
1321
1322 __moduleUID = None
1327
1329 return str(id(self))
1330
1332 """Return a distinct string recorded in the first 4096 bytes of the binding file.
1333
1334 This is used to ensure uniqueness and avoid overwriting data
1335 belonging to a different binding. The return value comprises
1336 the class-specialized L{_bindingTagPrefix_vx} with the
1337 L{moduleUID}.
1338 """
1339 return '%s:%s' % (self._bindingTagPrefix_vx(), self.moduleUID())
1340
1342 raise pyxb.LogicError('Subclass %s does not define _bindingTagPrefix_vx' % (type(self),))
1343
1345 """Return a block of binding text (comment or code) serving as a preface.
1346
1347 Normally this should describe the module contents."""
1348 return self._bindingPreface_vx()
1351
1352 - def moduleContents (self):
1353 template_map = {}
1354 aux_imports = []
1355 for (mr, as_path) in six.iteritems(self.__importModulePathMap):
1356 assert self != mr
1357 if as_path is not None:
1358 aux_imports.append('import %s as %s' % (mr.modulePath(), as_path))
1359 else:
1360 aux_imports.append('import %s' % (mr.modulePath(),))
1361 template_map['aux_imports'] = "\n".join(aux_imports)
1362 template_map['namespace_decls'] = "\n".join(self.__namespaceDeclarations)
1363 template_map['module_uid'] = self.moduleUID()
1364 template_map['generation_uid_expr'] = repr2to3(self.generator().generationUID())
1365 self._finalizeModuleContents_vx(template_map)
1366 return self.__bindingIO.contents()
1367
1380 __modulePath = None
1381
1383 """Python code reference to an object in an imported module"""
1384 if isinstance(module, NamespaceModule):
1385 module = module.moduleRecord()
1386 as_path = self.__importModulePathMap[module]
1387 if as_path is None:
1388 as_path = module.modulePath()
1389 return '%s.%s' % (as_path, name)
1390
1393 __bindingFile = None
1394 __bindingFilePath = None
1395
1398
1401
1402 @classmethod
1406
1407 @classmethod
1410
1411 @classmethod
1415 @classmethod
1418 __RecordModuleMap = { }
1419
1437 return self.__componentNameMap.get(component)
1438
1459
1461
1463 rv = self.__referencedNamespaces.get(namespace)
1464 assert rv is None, 'Module %s already has reference to %s' % (self, namespace)
1465
1466
1467
1468
1469 assert name.startswith('Namespace'), 'unexpected %s naming %s' % (name, namespace)
1470 name = utility.PrepareIdentifier(name, self.__uniqueInModule, **kw)
1471 self.__referencedFromClass.add(name)
1472 if definition is None:
1473 if namespace.isAbsentNamespace():
1474 definition = 'pyxb.namespace.CreateAbsentNamespace()'
1475 else:
1476 definition = 'pyxb.namespace.NamespaceForURI(%s, create_if_missing=True)' % (repr2to3(namespace.uri()),)
1477 self.__namespaceDeclarations.append('%s = %s' % (name, definition))
1478 self.__namespaceDeclarations.append("%s.configureCategories(['typeBinding', 'elementBinding'])" % (name,))
1479 self.__referencedNamespaces[namespace] = name
1480 return name
1481
1483 rv = self.__referencedNamespaces.get(namespace)
1484 if rv is None:
1485 assert not (isinstance(self, NamespaceModule) and (self.namespace() == namespace))
1486 assert namespace.isBuiltinNamespace() or not namespace.isUndeclaredNamespace()
1487 if namespace.isBuiltinNamespace():
1488 rv = namespace.builtinNamespaceRepresentation()
1489 if rv is None:
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499 if namespace.prefix():
1500 nsn = 'Namespace_%s' % (namespace.prefix(),)
1501 else:
1502 nsn = 'Namespace'
1503 nsdef = None
1504 for im in six.iterkeys(self.__importModulePathMap):
1505 if isinstance(im, pyxb.namespace.archive.ModuleRecord):
1506 if im.namespace() == namespace:
1507 nsdef = self.pathFromImport(im, 'Namespace')
1508 break
1509 elif isinstance(im, NamespaceGroupModule):
1510 pass
1511 else:
1512 assert False, 'unexpected import from type %s %s' % (type(im), im,)
1513
1514
1515
1516 if (nsdef is None) and not (isinstance(self, NamespaceGroupModule) and self.moduleForNamespace(namespace) is not None):
1517
1518
1519
1520 pass
1521
1522 rv = self.defineNamespace(namespace, nsn, nsdef, protected=True)
1523 assert 0 < len(self.__namespaceDeclarations)
1524 self.__referencedNamespaces[namespace] = rv
1525 return rv
1526
1556
1558 return self.__bindingIO.literal(*args, **kw)
1559
1561 _log.info('Importing to %s from %s', self, module)
1562 self._importModule(module)
1563 for c in self.__components:
1564 local_name = self.nameInModule(c)
1565 assert local_name is not None
1566 rem_name = module.nameInModule(c)
1567 if rem_name is None:
1568 continue
1569 aux = ''
1570 if local_name != rem_name:
1571 aux = ' as %s' % (local_name,)
1572 self.__bindingIO.write("from %s import %s%s # %s\n" % (module.modulePath(), rem_name, aux, c.expandedName()))
1573
1581
1583 """This class represents a Python module that holds all the
1584 declarations belonging to a specific namespace."""
1585
1588 __namespace = None
1589
1592 __moduleRecord = None
1593
1598 __namespaceGroupModule = None
1599
1600 _UniqueInModule = _ModuleNaming_mixin._UniqueInModule.copy()
1601 _UniqueInModule.update([ 'CreateFromDOM', 'CreateFromDocument' ])
1602
1605 __namespaceGroupHead = None
1606 __namespaceGroup = None
1607
1610 __components = None
1611
1612 @classmethod
1615 __ComponentModuleMap = { }
1616
1619
1621 ns = self.namespace()
1622 rvl = ['# Namespace %s' % (ns,)]
1623 if ns.prefix() is not None:
1624 rvl.append(' [xmlns:%s]' % (ns.prefix(),))
1625 rvl.append('\n')
1626 return ''.join(rvl)
1627
1632
1635
1636 - def __init__ (self, generator, module_record, mr_scc, components=None, **kw):
1650
1658
1659 - def _finalizeModuleContents_vx (self, template_map):
1660 template_map['_TextType'] = '_six.text_type'
1661 self.bindingIO().prolog().append('''
1662 from __future__ import unicode_literals
1663 import pyxb
1664 import pyxb.binding
1665 import pyxb.binding.saxer
1666 import io
1667 import pyxb.utils.utility
1668 import pyxb.utils.domutils
1669 import sys
1670 import pyxb.utils.six as _six
1671 ''')
1672 self.bindingIO().appendPrologBoilerplate(template_map)
1673 self.bindingIO().prolog().append(self.bindingIO().expand('''
1674 def CreateFromDocument (xml_text, default_namespace=None, location_base=None):
1675 """Parse the given XML and use the document element to create a
1676 Python instance.
1677
1678 @param xml_text An XML document. This should be data (Python 2
1679 str or Python 3 bytes), or a text (Python 2 unicode or Python 3
1680 str) in the L{pyxb._InputEncoding} encoding.
1681
1682 @keyword default_namespace The L{pyxb.Namespace} instance to use as the
1683 default namespace where there is no default namespace in scope.
1684 If unspecified or C{None}, the namespace of the module containing
1685 this function will be used.
1686
1687 @keyword location_base: An object to be recorded as the base of all
1688 L{pyxb.utils.utility.Location} instances associated with events and
1689 objects handled by the parser. You might pass the URI from which
1690 the document was obtained.
1691 """
1692
1693 if pyxb.XMLStyle_saxer != pyxb._XMLStyle:
1694 dom = pyxb.utils.domutils.StringToDOM(xml_text)
1695 return CreateFromDOM(dom.documentElement, default_namespace=default_namespace)
1696 if default_namespace is None:
1697 default_namespace = Namespace.fallbackNamespace()
1698 saxer = pyxb.binding.saxer.make_parser(fallback_namespace=default_namespace, location_base=location_base)
1699 handler = saxer.getContentHandler()
1700 xmld = xml_text
1701 if isinstance(xmld, %{_TextType}):
1702 xmld = xmld.encode(pyxb._InputEncoding)
1703 saxer.parse(io.BytesIO(xmld))
1704 instance = handler.rootObject()
1705 return instance
1706
1707 def CreateFromDOM (node, default_namespace=None):
1708 """Create a Python instance from the given DOM node.
1709 The node tag must correspond to an element declaration in this module.
1710
1711 @deprecated: Forcing use of DOM interface is unnecessary; use L{CreateFromDocument}."""
1712 if default_namespace is None:
1713 default_namespace = Namespace.fallbackNamespace()
1714 return pyxb.binding.basis.element.AnyCreateFromDOM(node, default_namespace)
1715
1716 ''', **template_map))
1717
1718 __components = None
1719 __componentBindingName = None
1720
1729
1732
1801
1802
1803 -def GeneratePython (schema_location=None,
1804 schema_text=None,
1805 namespace=None,
1806 module_prefix_elts=[],
1807 **kw):
1818
1819 import optparse
1820 import re
1823 """Configuration and data for a single binding-generation action."""
1824
1825 _DEFAULT_bindingRoot = '.'
1827 """The directory path into which generated bindings will be written.
1828 @rtype: C{str}"""
1829 return self.__bindingRoot
1833 __bindingRoot = None
1834
1836 if isinstance(module_elts, six.string_types):
1837 module_elts = module_elts.split('.')
1838 else:
1839 module_elts = module_elts[:]
1840 assert 0 < len(module_elts)
1841 if not inhibit_extension:
1842 assert not module_elts[-1].endswith('.py')
1843 module_elts[-1] = '%s.py' % (module_elts[-1],)
1844 return os.path.join(self.bindingRoot(), *module_elts)
1845
1848 __generateToFiles = None
1849
1851
1852
1853
1854
1855 module_path = None
1856 if isinstance(module, NamespaceModule):
1857 mr = module.moduleRecord()
1858 if mr is None:
1859 return ('/dev/null', None, None)
1860 if self.generationUID() != mr.generationUID():
1861 return ('/dev/null', None, None)
1862 if not self.generateToFiles():
1863 return ('/dev/null', None, None)
1864 if mr.namespace().isBuiltinNamespace() and (not self.allowBuiltinGeneration()):
1865 return ('/dev/null', None, None)
1866 module_path = mr.modulePath()
1867 assert module_path is not None, 'No path specified for module %s' % (mr,)
1868
1869
1870
1871 module_elts = module_path.split('.')
1872 if self.writeForCustomization():
1873 import_file_path = self.__moduleFilePath(module_elts)
1874 module_elts.insert(-1, 'raw')
1875 if not os.path.exists(import_file_path):
1876 raw_module_path = '.'.join(module_elts)
1877 fd = pyxb.utils.utility.OpenOrCreate(import_file_path)
1878 impt = '''# -*- coding: utf-8 -*-
1879 from %s import *
1880 ''' % (raw_module_path,)
1881 impd = impt.encode('utf-8')
1882 fd.write(impd)
1883 fd.close()
1884 binding_file_path = self.__moduleFilePath(module_elts)
1885 try:
1886 binding_file = pyxb.utils.utility.OpenOrCreate(binding_file_path, tag=module.moduleUID())
1887 except OSError as e:
1888 if errno.EEXIST == e.errno:
1889 raise pyxb.BindingGenerationError('Target file %s for module %s bindings exists with other content' % (binding_file_path, mr))
1890 raise
1891 elif isinstance(module, NamespaceGroupModule):
1892 if not self.generateToFiles():
1893 raise pyxb.BindingGenerationError('Generation of namespace groups requires generate-to-files')
1894 module_elts = []
1895 if self.modulePrefix():
1896 module_elts.extend(map(utility.MakeModuleElement, self.modulePrefix().split('.')))
1897 if self.writeForCustomization():
1898 module_elts.append('raw')
1899 in_use = set()
1900 while True:
1901 module_elts.append(pyxb.utils.utility.PrepareIdentifier('nsgroup', in_use, protected=True))
1902 try:
1903 binding_file_path = self.__moduleFilePath(module_elts)
1904 _log.info('Attempting group %s uid %s at %s', module, module.moduleUID(), binding_file_path)
1905 binding_file = pyxb.utils.utility.OpenOrCreate(binding_file_path, tag=module.moduleUID())
1906 break
1907 except OSError as e:
1908 if errno.EEXIST != e.errno:
1909 raise
1910 module_elts.pop()
1911 module_path = '.'.join(module_elts)
1912 else:
1913 assert False
1914 if self.generateToFiles():
1915 for n in range(len(module_elts)-1):
1916 sub_path = self.__moduleFilePath(module_elts[:1+n], inhibit_extension=True)
1917 init_path = os.path.join(sub_path, '__init__.py')
1918 if not os.path.exists(init_path):
1919 open(init_path, 'w')
1920 return (binding_file_path, binding_file, module_path)
1921
1923 """The directory from which entrypoint schemas specified as
1924 relative file paths will be read."""
1925 return self.__schemaRoot
1927 if not schema_root.endswith(os.sep):
1928 schema_root = schema_root + os.sep
1929 self.__schemaRoot = schema_root
1930 return self
1931 __schemaRoot = None
1932
1934 """Optional string that is stripped from the beginning of
1935 schemaLocation values before loading from them.
1936
1937 This applies only to the values of schemaLocation attributes
1938 in C{import} and C{include} elements. Its purpose is to
1939 convert absolute schema locations into relative ones to allow
1940 offline processing when all schema are available in a local
1941 directory. See C{schemaRoot}.
1942 """
1943 return self.__schemaStrippedPrefix
1947 __schemaStrippedPrefix = None
1948
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
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
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 try:
1982 (prefix, substituent) = prefix_rewrite.split('=', 1)
1983 except:
1984 raise
1985 self.addLocationPrefixRewrite(prefix, substituent)
1986 __locationPrefixMap = {}
1987
1989 """A list of locations from which entrypoint schemas are to be
1990 read.
1991
1992 The values in the list are either URIs, or tuples consisting
1993 of a value and a callable which, when passed the generator
1994 object and the value, will return a
1995 L{pyxb.xmlschema.structures.Schema} instance. See
1996 L{addSchemaLocation}.
1997
1998 See also L{addSchemaLocation} and L{schemas}.
1999 """
2000 return self.__schemaLocationList
2006 """Add the location of an entrypoint schema.
2007
2008 @param schema_location: The location of the schema. This
2009 should be a URL; if the schema location does not have a URL
2010 scheme (e.g., C{http:}), it is assumed to be a file, and if it
2011 is not an absolute path is located relative to the
2012 C{schemaRoot}.
2013
2014 @keyword converter: Optional callable that will be invoked
2015 with the generator instance and the schema location, and is
2016 expected to return a L{pyxb.xmlschema.structures.Schema}
2017 instance. If absent, the contents of the location are
2018 converted directly.
2019
2020 @note: The C{converter} argument derives from WSDL support: we
2021 need to add to the sequence of schema locations a URI of
2022 something that will not parse as a schema, but does have inner
2023 material that can if treated properly. "Treated properly" may
2024 include having the archive path and other namespace
2025 manipulations configured before anything is done to it.
2026 """
2027 self.__schemaLocationList.append( (schema_location, converter) )
2028 return self
2030 """Add the location of an entrypoint schema. The provided
2031 value should be a URL; if it does not have a URL scheme (e.g.,
2032 C{http:}), it is assumed to be a file, and if it is not an
2033 absolute path is located relative to the C{schemaRoot}."""
2034 self.addSchemaLocation(schema_location)
2035 __schemaLocationList = None
2036
2038 """Schema for which bindings should be generated.
2039
2040 These may be L{Schema<pyxb.xmlschema.structures.Schema>}
2041 instances, or strings; the latter is preferred, and is parsed
2042 into a Schema instance when required.
2043
2044 This is the list of entrypoint schemas for binding generation.
2045 Values in L{schemaLocationList} are read and converted into
2046 schema, then appended to this list. Values from L{moduleList}
2047 are applied starting with the first schema in this list.
2048 """
2049 return self.__schemas[:]
2057 __schemas = None
2058
2060 """The set of L{namespaces<pyxb.namespace.Namespace>} for
2061 which bindings will be generated.
2062
2063 This is the set of namespaces read from entrypoint schema,
2064 closed under reference to namespaces defined by schema import.
2065
2066 @rtype: C{set}
2067 """
2068 return self.__namespaces.copy()
2076 __namespaces = None
2077
2079 """A list of module names to be applied in order to the namespaces of entrypoint schemas"""
2080 return self.__moduleList[:]
2085
2087 """Add a module name corresponding to an entrypoint schema.
2088
2089 The namespace defined by the corresponding schema will be
2090 written to a binding using the given module name, adjusted by
2091 L{modulePrefix}."""
2092 self.__moduleList.append(module_name)
2093 return self
2094 __moduleList = None
2095
2097 """The prefix for binding modules.
2098
2099 The base name for the module holding a binding is taken from
2100 the moduleList, moduleMap, or an XMLNS prefix associated with
2101 the namespace in a containing schema. This value, if present,
2102 is used as a prefix to allow a deeper module hierarchy."""
2103 return self.__modulePrefix
2107 __modulePrefix = None
2108
2110 """A map from namespace URIs to the module to be used for the
2111 corresponding generated binding.
2112
2113 Module values are adjusted by L{modulePrefix} if that has been
2114 specified.
2115
2116 An entry in this map for a namespace supersedes the module
2117 specified in moduleList if the namespace is defined by an
2118 entrypoint schema.
2119
2120 @return: A reference to the namespace module map.
2121 """
2122 return self.__namespaceModuleMap
2123 __namespaceModuleMap = None
2124
2126 """A colon-separated list of paths from which namespace
2127 archives can be read.
2128
2129 The default path is the contents of the C{PYXB_ARCHIVE_PATH}
2130 environment variable, or the standard path configured at
2131 installation time. Any file with the extension C{.wxs} found
2132 in one of these directories is examined to see whether it is a
2133 namespace archive.
2134 """
2135 return self.__archivePath
2139 __archivePath = None
2140
2142 """A frozenset of namespaces that must not be loaded from an archive."""
2143 return frozenset(self.__noLoadNamespaces)
2145 """Record the set of namespaces that should not be loaded from an archive.
2146
2147 The expectation is that any required entities in the namespace
2148 will be defined by loading schema."""
2149 self.__noLoadNamespaces.clear()
2150 self.__noLoadNamespaces.update([ pyxb.namespace.NamespaceInstance(_ns) for _ns in namespace_set ])
2152 """Mark that the specified namespace should not be loaded from an archive.
2153
2154 Use this when you are generating bindings for an application
2155 that has a restricted profile of a namespace that would
2156 otherwise be read from an archive. Be aware that this removes
2157 any knowledge of any archive in which this namespace is
2158 present as a non-private member."""
2159 self.__noLoadNamespaces.add(pyxb.namespace.NamespaceInstance(namespace))
2160 __noloadNamespaces = None
2161
2170 """Mark that the specified namespace may be imported by new bindings.
2171
2172 Normally namespaces that are available from archives are
2173 considered to be complete, and schema locations in import
2174 directives are ignored. Use this to indicate that the
2175 bindings being generated import new bindings.
2176
2177 Note that attempts to import schema that contributed to the
2178 archive will only be detected if the archive was generated
2179 from the same schemaLocation URI; if the archive was generated
2180 from a different source component definitions might
2181 conflict."""
2182 self.__importAugmentableNamespaces.add(pyxb.namespace.NamespaceInstance(namespace))
2183 __importAugmentableNamespaces = None
2184
2186 """Optional file into which the archive of namespaces will be written.
2187
2188 Subsequent generation actions can read pre-parsed namespaces
2189 from this file, and therefore reference the bindings that were
2190 built earlier rather than re-generating them.
2191
2192 The file name should normally end with C{.wxs}."""
2193 return self.__archiveToFile
2197 __archiveToFile = None
2198
2212 """Indicates, for specific namespaces, whether their
2213 visibility in the archive should be public or private."""
2214 return self.__namespaceVisibilityMap.copy()
2215 __namespaceVisibilityMap = None
2216
2218 """Indicates whether unmentioned namespaces will be public or private (default) in the archive.
2219
2220 A namespace is I{mentioned} if it is the target namespace of
2221 an entrypoint schema, or appears in a namespace visibility
2222 specification. I.e., this default applies only to namespaces
2223 that are modified as a result of including some schema, which
2224 is generally a local customization of something.
2225 """
2226 return self.__defaultNamespacePublic
2229 __defaultNamespacePublic = None
2230
2232 """Indicates whether the bindings should validate mutations
2233 against the content model."""
2234 return self.__validateChanges
2238 __validateChanges = None
2239
2241 """Indicates whether the binding Python code should be written into a sub-module for customization.
2242
2243 If enabled, a module C{path.to.namespace} will be written to
2244 the file C{path/to/raw/namespace.py}, so that the file
2245 C{path/to/namespace.py} can import it and override behavior."""
2246 return self.__writeForCustomization
2250 __writeForCustomization = None
2251
2253 """Indicates whether the code generator is permitted to
2254 process namespace for which no module path can be determined.
2255
2256 Use this only when generating bindings that will not be
2257 referenced by other bindings."""
2258 return self.__allowAbsentModule
2262 __allowAbsentModule = None
2263
2265 """Indicates whether bindings will be written for namespaces that are built-in to PyXB.
2266
2267 This must be enabled when building bindings for the XML,
2268 XMLSchema instance, and other built-in namespaces. Normally
2269 generation of these namespaces is inhibited lest it produce
2270 inconsistencies."""
2271 return self.__allowBuiltinGeneration
2275 __allowBuiltinGeneration = None
2276
2278 """The directory path into which any content retrieved by URI will be written.
2279
2280 This serves as a local cache, and to give you an opportunity
2281 to inspect material retrieved from some other system.
2282 @rtype: C{str}"""
2283 return self.__uriContentArchiveDirectory
2286 __uriContentArchiveDirectory = None
2287
2289 """A file provided to L{logging.config.fileConfig} to control log messages.
2290
2291 In the absence of other configuration the Python standard logging infrastructure is used in its
2292 default configuration.
2293
2294 @rtype: C{str}"""
2295 return self.__loggingConfigFile
2298 __loggingConfigFile = None
2299
2301 """Create a configuration to be used for generating bindings.
2302
2303 Arguments are treated as additions to the schema location list
2304 after all keywords have been processed.
2305
2306 @keyword binding_root: Invokes L{setBindingRoot}
2307 @keyword schema_root: Invokes L{setSchemaRoot}
2308 @keyword schema_stripped_prefix: Invokes L{setSchemaStrippedPrefix}
2309 @keyword location_prefix_rewrite_map: Invokes L{setLocationPrefixRewriteMap}
2310 @keyword schema_location_list: Invokes L{setSchemaLocationList}
2311 @keyword module_list: Invokes L{_setModuleList}
2312 @keyword module_prefix: Invokes L{setModulePrefix}
2313 @keyword archive_path: Invokes L{setArchivePath}
2314 @keyword no_load_namespaces: Invokes L{_setNoLoadNamespaces}
2315 @keyword import_augmentable_namespaces: Invokes L{_setImportAugmentableNamespaces}
2316 @keyword archive_to_file: Invokes L{setArchiveToFile}
2317 @keyword public_namespace: Invokes L{setNamespaceVisibility}
2318 @keyword private_namespace: Invokes L{setNamespaceVisibility}
2319 @keyword default_namespace_public: Invokes L{setDefaultNamespacePublic}
2320 @keyword validate_changes: Invokes L{setValidateChanges}
2321 @keyword namespace_module_map: Initializes L{namespaceModuleMap}
2322 @keyword schemas: Invokes L{setSchemas}
2323 @keyword namespaces: Invokes L{setNamespaces}
2324 @keyword write_for_customization: Invokes L{setWriteForCustomization}
2325 @keyword allow_builtin_generation: Invokes L{setAllowBuiltinGeneration}
2326 @keyword allow_absent_module: Invokes L{setAllowAbsentModule}
2327 @keyword generate_to_files: Sets L{generateToFiles}
2328 @keyword uri_content_archive_directory: Invokes L{setUriContentArchiveDirectory}
2329 @keyword logging_config_file: Invokes L{setLoggingConfigFile}
2330 """
2331 argv = kw.get('argv')
2332 if argv is not None:
2333 kw = {}
2334 self.__bindingRoot = kw.get('binding_root', self._DEFAULT_bindingRoot)
2335 self.__schemaRoot = kw.get('schema_root', os.getcwd() + os.path.sep)
2336 self.__schemaStrippedPrefix = kw.get('schema_stripped_prefix')
2337 self.__locationPrefixRewriteMap = kw.get('location_prefix_rewrite_map', {})
2338 self.__schemas = []
2339 self.__schemaLocationList = kw.get('schema_location_list', [])[:]
2340 self.__moduleList = kw.get('module_list', [])[:]
2341 self.__modulePrefix = kw.get('module_prefix')
2342 self.__archivePath = kw.get('archive_path', pyxb.namespace.archive.GetArchivePath())
2343 self.__noLoadNamespaces = kw.get('no_load_namespaces', set()).copy()
2344 self.__importAugmentableNamespaces = kw.get('import_augmentable_namespaces', set()).copy()
2345 self.__archiveToFile = kw.get('archive_to_file')
2346 self.__namespaceVisibilityMap = {}
2347 self._setNamespaceVisibilities(kw.get('public_namespaces', set()), kw.get('private_namespaces', set()))
2348 self.__defaultNamespacePublic = kw.get('default_namespace_public', False)
2349 self.__validateChanges = kw.get('validate_changes', True)
2350 self.__namespaceModuleMap = kw.get('namespace_module_map', {}).copy()
2351 self.__schemas = kw.get('schemas', [])[:]
2352 self.__namespaces = set(kw.get('namespaces', []))
2353 self.__writeForCustomization = kw.get('write_for_customization', False)
2354 self.__allowBuiltinGeneration = kw.get('allow_builtin_generation', False)
2355 self.__allowAbsentModule = kw.get('allow_absent_module', False)
2356 self.__generateToFiles = kw.get('generate_to_files', True)
2357 self.__uriContentArchiveDirectory = kw.get('uri_content_archive_directory')
2358 self.__loggingConfigFile = kw.get('logging_config_file')
2359 self.__unnamedModulePaths = set()
2360
2361 if argv is not None:
2362 self.applyOptionValues(*self.optionParser().parse_args(argv))
2363 [ self.addSchemaLocation(_a) for _a in args ]
2364
2365 self.__generationUID = pyxb.utils.utility.UniqueIdentifier()
2366
2367 pyxb.namespace.XML.validateComponentModel()
2368
2369 __stripSpaces_re = re.compile('\s\s\s+')
2372
2373 __OptionSetters = (
2374 ('binding_root', setBindingRoot),
2375 ('schema_root', setSchemaRoot),
2376 ('schema_stripped_prefix', setSchemaStrippedPrefix),
2377 ('location_prefix_rewrite', argAddLocationPrefixRewrite),
2378 ('schema_location', setSchemaLocationList),
2379 ('module', _setModuleList),
2380 ('module_prefix', setModulePrefix),
2381 ('archive_path', setArchivePath),
2382 ('no_load_namespace', _setNoLoadNamespaces),
2383 ('import_augmentable_namespace', _setImportAugmentableNamespaces),
2384 ('archive_to_file', setArchiveToFile),
2385 ('default_namespace_public', setDefaultNamespacePublic),
2386 ('validate_changes', setValidateChanges),
2387 ('write_for_customization', setWriteForCustomization),
2388 ('allow_builtin_generation', setAllowBuiltinGeneration),
2389 ('allow_absent_module', setAllowAbsentModule),
2390 ('uri_content_archive_directory', setUriContentArchiveDirectory),
2391 ('logging_config_file', setLoggingConfigFile)
2392 )
2406
2408 if argv is None:
2409 argv = sys.argv[1:]
2410 (options, args) = self.optionParser().parse_args(argv)
2411 self.applyOptionValues(options, args)
2412 return self
2413
2415 """A unique identifier associated with this Generator instance.
2416
2417 This is an instance of L{pyxb.utils.utility.UniqueIdentifier}.
2418 Its associated objects are
2419 L{pyxb.namespace.archive._SchemaOrigin} instances, which
2420 identify schema that contribute to the definition of a
2421 namespace."""
2422 return self.__generationUID
2423 __generationUID = None
2424
2426 """Return an C{optparse.OptionParser} instance tied to this configuration.
2427
2428 @param reset: If C{False} (default), a parser created in a
2429 previous invocation will be returned. If C{True}, any
2430 previous option parser is discarded and a new one created.
2431 @type reset: C{bool}
2432 """
2433 if reset or (self.__optionParser is None):
2434 parser = optparse.OptionParser(usage="%prog [options] [more schema locations...]",
2435 version='%%prog from PyXB %s' % (pyxb.__version__,),
2436 description='Generate bindings from a set of XML schemas')
2437
2438 group = optparse.OptionGroup(parser, 'Identifying Schema', 'Specify and locate schema for which bindings should be generated.')
2439 group.add_option('--schema-location', '-u', metavar="FILE_or_URL",
2440 action='append',
2441 help=self.__stripSpaces(self.argAddSchemaLocation.__doc__))
2442 group.add_option('--schema-root', metavar="DIRECTORY",
2443 help=self.__stripSpaces(self.schemaRoot.__doc__))
2444 group.add_option('--schema-stripped-prefix', metavar="TEXT", type='string',
2445 help=self.__stripSpaces(self.schemaStrippedPrefix.__doc__))
2446 group.add_option('--location-prefix-rewrite', metavar="TEXT", type='string',
2447 help=self.__stripSpaces(self.argAddLocationPrefixRewrite.__doc__))
2448 group.add_option('--uri-content-archive-directory', metavar="DIRECTORY",
2449 help=self.__stripSpaces(self.uriContentArchiveDirectory.__doc__))
2450 parser.add_option_group(group)
2451
2452 group = optparse.OptionGroup(parser, 'Configuring Bindings', 'Specify where generated bindings should be written, and how they will be accessed from Python.')
2453 group.add_option('--module', '-m', metavar="MODULE",
2454 action='append',
2455 help=self.__stripSpaces(self.addModuleName.__doc__))
2456 group.add_option('--module-prefix', metavar="MODULE",
2457 help=self.__stripSpaces(self.modulePrefix.__doc__))
2458 group.add_option('--binding-root', metavar="DIRECTORY",
2459 help=self.__stripSpaces(self.bindingRoot.__doc__))
2460 group.add_option('-r', '--write-for-customization',
2461 action='store_true', dest='write_for_customization',
2462 help=self.__stripSpaces(self.writeForCustomization.__doc__ + ' This option turns on the feature.'))
2463 group.add_option('--no-write-for-customization',
2464 action='store_false', dest='write_for_customization',
2465 help=self.__stripSpaces(self.writeForCustomization.__doc__ + ' This option turns off the feature (I{default}).'))
2466 parser.add_option_group(group)
2467
2468 group = optparse.OptionGroup(parser, 'Reading Namespace Archives', 'Locating and loading (or inhibiting load of) namespace archives.')
2469 group.add_option('--archive-path', metavar="PATH",
2470 help=self.__stripSpaces(self.archivePath.__doc__))
2471 group.add_option('--import-augmentable-namespace', metavar="URI",
2472 action='append',
2473 help=self.__stripSpaces(self.addImportAugmentableNamespace.__doc__))
2474 group.add_option('--no-load-namespace', metavar="URI",
2475 action='append',
2476 help=self.__stripSpaces(self.addNoLoadNamespace.__doc__))
2477 parser.add_option_group(group)
2478
2479 group = optparse.OptionGroup(parser, 'Writing Namespace Archives', 'Control the location and content of a namespace archive corresponding to a binding generation.')
2480 group.add_option('--archive-to-file', metavar="FILE",
2481 help=self.__stripSpaces(self.archiveToFile.__doc__))
2482 group.add_option('--public-namespace', metavar="URI",
2483 action='append',
2484 help=self.__stripSpaces(self.namespaceVisibilityMap.__doc__ + ' This option adds the namespace as a public archive member.'))
2485 group.add_option('--private-namespace', metavar="URI",
2486 action='append',
2487 help=self.__stripSpaces(self.namespaceVisibilityMap.__doc__ + ' This option adds the namespace as a private archive member.'))
2488 group.add_option('--default-namespace-public',
2489 action="store_true", dest='default_namespace_public',
2490 help=self.__stripSpaces(self.defaultNamespacePublic.__doc__ + ' This option makes the default C{public} (I{default}).'))
2491 group.add_option('--default-namespace-private',
2492 action="store_false", dest='default_namespace_public',
2493 help=self.__stripSpaces(self.defaultNamespacePublic.__doc__ + ' This option makes the default C{private}.'))
2494 parser.add_option_group(group)
2495
2496 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.")
2497 group.add_option('--validate-changes',
2498 action='store_true', dest='validate_changes',
2499 help=self.__stripSpaces(self.validateChanges.__doc__ + ' This option turns on validation (default).'))
2500 group.add_option('--no-validate-changes',
2501 action='store_false', dest='validate_changes',
2502 help=self.__stripSpaces(self.validateChanges.__doc__ + ' This option turns off validation.'))
2503 parser.add_option_group(group)
2504
2505 group = optparse.OptionGroup(parser, 'Miscellaneous Options', "Anything else.")
2506 group.add_option('--logging-config-file', metavar="FILE",
2507 help=self.__stripSpaces(self.loggingConfigFile.__doc__))
2508 parser.add_option_group(group)
2509
2510 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.")
2511
2512 group.add_option('--allow-absent-module',
2513 action='store_true', dest='allow_absent_module',
2514 help=self.__stripSpaces(self.allowAbsentModule.__doc__ + ' This option turns on the feature.'))
2515 group.add_option('--no-allow-absent-module',
2516 action='store_false', dest='allow_absent_module',
2517 help=self.__stripSpaces(self.allowAbsentModule.__doc__ + ' This option turns off the feature (default).'))
2518 group.add_option('--allow-builtin-generation',
2519 action='store_true', dest='allow_builtin_generation',
2520 help=self.__stripSpaces(self.allowBuiltinGeneration.__doc__ + ' This option turns on the feature.'))
2521 group.add_option('--no-allow-builtin-generation',
2522 action='store_false', dest='allow_builtin_generation',
2523 help=self.__stripSpaces(self.allowBuiltinGeneration.__doc__ + ' This option turns off the feature (default).'))
2524 parser.add_option_group(group)
2525
2526 self.__optionParser = parser
2527 return self.__optionParser
2528 __optionParser = None
2529
2531 """Return a command line option sequence that could be used to
2532 construct an equivalent configuration.
2533
2534 @note: If you extend the option parser, as is done by
2535 C{pyxbgen}, this may not be able to reconstruct the correct
2536 command line."""
2537 opts = []
2538 module_list = self.moduleList()
2539 schema_list = self.schemaLocationList()
2540 while module_list and schema_list:
2541 ml = module_list.pop(0)
2542 sl = schema_list.pop(0)
2543 if isinstance(sl, tuple):
2544 sl = sl[0]
2545 opts.extend(['--schema-location=' + sl, '--module=' + ml])
2546 for sl in schema_list:
2547 opts.append('--schema-location=' + sl)
2548 if self.schemaRoot() is not None:
2549 opts.append('--schema-root=' + self.schemaRoot())
2550 if self.schemaStrippedPrefix() is not None:
2551 opts.append('--schema-stripped-prefix=%s' + self.schemaStrippedPrefix())
2552 for (pfx, sub) in self.locationPrefixRewriteMap():
2553 opts.append('--location-prefix-rewrite=%s=%s' % (pfx, sub))
2554 if self.modulePrefix() is not None:
2555 opts.append('--module-prefix=' + self.modulePrefix())
2556 opts.append('--binding-root=' + self.bindingRoot())
2557 if self.archivePath() is not None:
2558 opts.append('--archive-path=' + self.archivePath())
2559 for ns in self.noLoadNamespaces():
2560 opts.append('--no-load-namespace=' + ns.uri())
2561 for ns in self.importAugmentableNamespaces():
2562 opts.append('--import-augmentable-namespace=' + ns.uri())
2563 if self.archiveToFile() is not None:
2564 opts.append('--archive-to-file=' + self.archiveToFile())
2565 for (ns, visibility) in self.namespaceVisibilityMap():
2566 if visibility:
2567 opts.append('--public-namespace=' + ns.uri())
2568 else:
2569 opts.append('--private-namespace=' + ns.uri())
2570 if self.defaultNamespacePublic():
2571 opts.append('--default-namespace-public')
2572 else:
2573 opts.append('--default-namespace-private')
2574 for (val, opt) in ( (self.validateChanges(), 'validate-changes'),
2575 (self.writeForCustomization(), 'write-for-customization'),
2576 (self.allowAbsentModule(), 'allow-absent-module'),
2577 (self.allowBuiltinGeneration(), 'allow-builtin-generation') ):
2578 if val:
2579 opts.append('--' + opt)
2580 else:
2581 opts.append('--no-' + opt)
2582 if self.uriContentArchiveDirectory() is not None:
2583 opts.append('--uri-content-archive-directory=%s' + self.uriContentArchiveDirectory())
2584 return opts
2585
2591
2593 """Provide a Python module path for the module record.
2594
2595 This is the path by which the module bindings associated with
2596 C{module_record} will be imported.
2597
2598 If a path had already been assigned to the module, it is left
2599 in place.
2600
2601 @param module_record: Information about a collection of related bindings
2602 @type module_record: L{pyxb.namespace.archive.ModuleRecord}
2603
2604 @param module_path: Default path to use
2605 @type module_path: C{str}
2606
2607 @return: C{module_record}
2608 """
2609 if module_record.modulePath() is not None:
2610 return module_record
2611 namespace = module_record.namespace()
2612 if not namespace.isAbsentNamespace():
2613
2614 if (module_path is None) and not (namespace.prefix() is None):
2615 module_path = namespace.prefix()
2616
2617 module_path = self.namespaceModuleMap().get(namespace.uri(), module_path)
2618 if (module_path is None) and self.generateToFiles():
2619 module_path = pyxb.utils.utility.MakeUnique('binding', self.__unnamedModulePaths)
2620 if (module_path is not None) and self.modulePrefix():
2621
2622 module_path = '.'.join([self.modulePrefix(), module_path])
2623 module_record.setModulePath(module_path)
2624 return module_record
2625
2626 __didResolveExternalSchema = False
2628 if self.__didResolveExternalSchema:
2629 return
2630
2631
2632
2633 pyxb.namespace.archive.NamespaceArchive.PreLoadArchives(self.archivePath())
2634
2635
2636
2637
2638 for ns in self.noLoadNamespaces():
2639 assert isinstance(ns, pyxb.namespace.Namespace)
2640 _log.info("Namespace %s marked not loadable" % (ns,))
2641 ns.markNotLoadable()
2642
2643
2644
2645 for ns in self.importAugmentableNamespaces():
2646 assert isinstance(ns, pyxb.namespace.Namespace)
2647 _log.info("Namespace %s marked import-augmentable" % (ns,))
2648 ns.setImportAugmentable(True)
2649
2650
2651 while self.__schemaLocationList:
2652 sl = self.__schemaLocationList.pop(0)
2653 if isinstance(sl, tuple):
2654 (sl, converter) = sl
2655 else:
2656 converter = None
2657 try:
2658 if converter is None:
2659 schema = xs.schema.CreateFromLocation(absolute_schema_location=self.normalizeSchemaLocation(sl),
2660 generation_uid=self.generationUID(),
2661 uri_content_archive_directory=self.uriContentArchiveDirectory())
2662 else:
2663 schema = converter(self, sl)
2664 self.addSchema(schema)
2665 except pyxb.SchemaUniquenessError as e:
2666 _log.info('Skipped redundant translation of %s defining %s', e.schemaLocation(), e.namespace())
2667 self.addSchema(e.existingSchema())
2668
2669
2670
2671 for schema in self.__schemas:
2672 if isinstance(schema, six.string_types):
2673 schema = xs.schema.CreateFromDocument(schema, generation_uid=self.generationUID())
2674 origin = schema.originRecord()
2675 assert origin is not None
2676 module_path = None
2677 if self.__moduleList:
2678 module_path = self.__moduleList.pop(0)
2679 self.assignModulePath(origin.moduleRecord(), module_path)
2680 assert schema.targetNamespace() == origin.moduleRecord().namespace()
2681 self.addNamespace(schema.targetNamespace())
2682 self.__didResolveExternalSchema = True
2683
2684
2685 self.__componentGraph = None
2686 self.__componentOrder = None
2687
2711
2757
2758 __moduleRecords = None
2759 __componentGraph = None
2760 __componentOrder = None
2761
2763 """The set of L{pyxb.namespace.archive.ModuleRecord} instances
2764 associated with schema processed in this generation
2765 instance.
2766
2767 These should be in one-to-one correspondence with the
2768 namespaces for which bindings are being generated. Multiple
2769 input schemas may contribute to a single module record; all
2770 material in that record is placed in a single binding file.
2771 """
2772 if self.__moduleRecords is None:
2773 self.__resolveComponentDependencies()
2774 return self.__moduleRecords
2775
2780
2785
2787
2788
2789
2790
2791
2792 module_graph = pyxb.utils.utility.Graph()
2793 [ module_graph.addRoot(_mr) for _mr in self.moduleRecords() ]
2794 for (s, t) in self.componentGraph().edges():
2795 module_graph.addEdge(s._objectOrigin().moduleRecord(), t._objectOrigin().moduleRecord())
2796 module_scc_order = module_graph.sccOrder()
2797
2798 record_binding_map = {}
2799 modules = []
2800 nsvm = self.namespaceVisibilityMap()
2801 for mr_scc in module_scc_order:
2802 scc_modules = [ ]
2803 for mr in mr_scc:
2804 mr._setIsPublic(nsvm.get(mr.namespace(), self.defaultNamespacePublic()))
2805 self.assignModulePath(mr)
2806 if (mr.modulePath() is None) and self.generateToFiles():
2807 raise pyxb.BindingGenerationError('No prefix or module name available for %s' % (mr,))
2808 if (not mr.isPublic()) and (mr.modulePath() is not None):
2809 elts = mr.modulePath().split('.')
2810 elts[-1] = '_%s' % (elts[-1],)
2811 mr.setModulePath('.'.join(elts))
2812 nsm = NamespaceModule(self, mr, mr_scc)
2813 record_binding_map[mr] = nsm
2814 scc_modules.append(nsm)
2815
2816 scc_modules.sort(key=lambda _nm: _nm.namespace().uri())
2817 modules.extend(scc_modules)
2818 if 1 < len(mr_scc):
2819 ngm = NamespaceGroupModule(self, scc_modules)
2820 modules.append(ngm)
2821 for nsm in scc_modules:
2822 nsm.setNamespaceGroupModule(ngm)
2823
2824 element_declarations = []
2825 type_definitions = []
2826 for c in self.componentOrder():
2827 if isinstance(c, xs.structures.ElementDeclaration) and c._scopeIsGlobal():
2828
2829 nsm = record_binding_map[c._objectOrigin().moduleRecord()]
2830 nsm.bindComponent(c)
2831 element_declarations.append(c)
2832 elif c.isTypeDefinition():
2833 type_definitions.append(c)
2834 else:
2835
2836 pass
2837
2838 simple_type_definitions = []
2839 complex_type_definitions = []
2840 for td in type_definitions:
2841 nsm = record_binding_map[td._objectOrigin().moduleRecord()]
2842 assert nsm is not None, 'No namespace module for %s type %s scope %s namespace %s' % (td.expandedName(), type(td), td._scope(), td.bindingNamespace)
2843 module_context = nsm.bindComponent(td)
2844 assert isinstance(module_context, _ModuleNaming_mixin), 'Unexpected type %s' % (type(module_context),)
2845 if isinstance(td, xs.structures.SimpleTypeDefinition):
2846 _PrepareSimpleTypeDefinition(td, self, nsm, module_context)
2847 simple_type_definitions.append(td)
2848 elif isinstance(td, xs.structures.ComplexTypeDefinition):
2849 _PrepareComplexTypeDefinition(td, self, nsm, module_context)
2850 complex_type_definitions.append(td)
2851 else:
2852 assert False, 'Unexpected component type %s' % (type(td),)
2853
2854 for ngm in modules:
2855 if isinstance(ngm, NamespaceGroupModule):
2856 for m in ngm.namespaceModules():
2857 m.addImportsFrom(ngm)
2858
2859 for std in simple_type_definitions:
2860 GenerateSTD(std, self)
2861 for ctd in complex_type_definitions:
2862 GenerateCTD(ctd, self)
2863 for ed in element_declarations:
2864 GenerateED(ed, self)
2865
2866 self.__bindingModules = modules
2867
2868 __bindingModules = None
2875
2891
2894