Exemple #1
0
    def __init__ (self, archive_path=None, generation_uid=None, loadable=True, stage=None):
        """Create a new namespace archive.

        If C{namespaces} is given, this is an output archive.

        If C{namespaces} is absent, this is an input archive.

        @raise IOError: error attempting to read the archive file
        @raise pickle.UnpicklingError: something is wrong with the format of the library
        """
        self.__namespaces = set()
        if generation_uid is not None:
            if archive_path:
                raise pyxb.LogicError('NamespaceArchive: cannot define both namespaces and archive_path')
            self.__generationUID = generation_uid
            self.__locateModuleRecords()
        elif archive_path is not None:
            if generation_uid is not None:
                raise pyxb.LogicError('NamespaceArchive: cannot provide generation_uid with archive_path')
            self.__archivePath = archive_path
            self.__stage = self._STAGE_UNOPENED
            self.__isLoadable = loadable
            if self.__isLoadable:
                if stage is None:
                    stage = self._STAGE_moduleRecords
                self._readToStage(stage)
        else:
            pass
Exemple #2
0
    def createChildElement(self, expanded_name, parent=None):
        """Create a new element node in the tree.

        @param expanded_name: The name of the element.  A plain string
        indicates a name in no namespace.
        @type expanded_name: L{pyxb.namespace.ExpandedName} or C{str} or C{unicode}

        @keyword parent: The node in the tree that will serve as the child's
        parent.  If C{None}, the document element is used.  (If there is no
        document element, then this call creates it as a side-effect.)

        @return: A newly created DOM element
        @rtype: C{xml.dom.Element}
        """

        if parent is None:
            parent = self.document().documentElement
        if parent is None:
            parent = self.__document
        if isinstance(expanded_name, (str, unicode)):
            expanded_name = pyxb.namespace.ExpandedName(None, expanded_name)
        if not isinstance(expanded_name, pyxb.namespace.ExpandedName):
            raise pyxb.LogicError('Invalid type %s for expanded name' %
                                  (type(expanded_name), ))
        ns = expanded_name.namespace()
        name = expanded_name.localName()
        ns_uri = xml.dom.EMPTY_NAMESPACE
        pfx = self.namespacePrefix(ns)
        if pfx is not None:
            ns_uri = ns.uri()
            name = '%s:%s' % (pfx, name)
        element = self.__document.createElementNS(ns_uri, name)
        return parent.appendChild(element)
Exemple #3
0
    def bindingRequires(self, reset=False, include_lax=False):
        """Return a set of components upon whose bindings this component's
        bindings depend.

        For example, bindings that are extensions or restrictions depend on
        their base types.  Complex type definition bindings require that the
        types of their attribute declarations be available at the class
        definition, and the types of their element declarations in the
        postscript.

        @keyword include_lax: if C{False} (default), only the requirements of
        the class itself are returned.  If C{True}, all requirements are
        returned.
        @rtype: C{set(L{pyxb.xmlschema.structures._SchemaComponent_mixin})}
        """
        if reset or (self.__bindingRequires is None):
            if isinstance(
                    self,
                    resolution._Resolvable_mixin) and not (self.isResolved()):
                raise pyxb.LogicError(
                    'Unresolved %s in %s: %s' %
                    (self.__class__.__name__,
                     self._namespaceContext().targetNamespace(), self.name()))
            self.__bindingRequires = self._bindingRequires_vx(include_lax)
        return self.__bindingRequires
Exemple #4
0
    def __new__ (cls, *args, **kw):
        """Pickling and singleton support.

        This ensures that no more than one Namespace instance exists
        for any given URI.  We could do this up in __init__, but that
        doesn't normally get called when unpickling instances; this
        does.  See also __getnewargs__()."""
        (uri,) = args
        if isinstance(uri, tuple):
            # Special handling to reconstruct absent namespaces.
            (variant, uid) = uri
            if cls.__SerializedVariantAbsent == variant:
                ns = cls.__AbsentNamespaceRegistry.get(uid)
                if ns is None:
                    raise pyxb.UsageError('Unable to reconstruct instance of absent namespace')
                return ns
            raise pyxb.LogicError('Unrecognized serialized namespace variant %s uid %s' % (variant, uid))
        elif not (uri in cls.__Registry):
            instance = object.__new__(cls)
            # Do this one step of __init__ so we can do checks during unpickling
            instance.__uri = uri
            instance._reset()
            # Absent namespaces are not stored in the registry.
            if uri is None:
                cls.__AbsentNamespaces.add(instance)
                return instance
            cls.__Registry[uri] = instance
        return cls.__Registry[uri]
Exemple #5
0
 def _readToStage(self, stage):
     if self.__stage is None:
         raise pyxb.NamespaceArchiveError(
             'Attempt to read from invalid archive %s' % (self, ))
     try:
         while self.__stage < stage:
             if self.__stage < self._STAGE_uid:
                 self.__unpickler = self.__createUnpickler()
                 self.__stage = self._STAGE_uid
                 continue
             if self.__stage < self._STAGE_readModules:
                 assert self.__unpickler is not None
                 self.__readModules(self.__unpickler)
                 self.__stage = self._STAGE_readModules
                 continue
             if self.__stage < self._STAGE_validateModules:
                 self.__validateModules()
                 self.__stage = self._STAGE_validateModules
                 continue
             if self.__stage < self._STAGE_readComponents:
                 assert self.__unpickler is not None
                 self.__stage = self._STAGE_readComponents
                 self.__readComponentSet(self.__unpickler)
                 self.__unpickler = None
                 continue
             raise pyxb.LogicError('Too many stages (at %s, want %s)' %
                                   (self.__stage, stage))
     except:
         self.__stage = None
         self.__unpickler = None
         raise
Exemple #6
0
 def LateDatatypeBindsSuperclass(cls):
     """Return true if false if the proposed datatype should be
     used, or True if the base type definition of the proposed
     datatype should be used."""
     if cls._LateDatatypeBindsSuperclass is None:
         raise pyxb.LogicError(
             'Class %s did not set _LateDatatypeBindsSuperclass variable.')
     return cls._LateDatatypeBindsSuperclass
Exemple #7
0
 def _setObjectOrigin(self, object_origin, override=False):
     if (self.__objectOrigin is not None) and (not override):
         if self.__objectOrigin != object_origin:
             raise pyxb.LogicError(
                 'Inconsistent origins for object %s: %s %s' %
                 (self, self.__objectOrigin, object_origin))
     else:
         self.__objectOrigin = object_origin
Exemple #8
0
 def builtinModulePath (self):
     from pyxb.namespace import builtin
     if not self.__builtinModulePath:
         raise pyxb.LogicError('Namespace has no built-in module: %s' % (self,))
     mr = self.lookupModuleRecordByUID(builtin.BuiltInObjectUID)
     assert mr is not None
     assert mr.modulePath() == self.__builtinModulePath
     return self.__builtinModulePath
Exemple #9
0
 def __init__ (self, **kw):
     namespace_set = set(kw.get('namespace_set', []))
     namespace = kw.get('namespace')
     if namespace is not None:
         namespace_set.add(namespace)
     if 0 == len(namespace_set):
         raise pyxb.LogicError('NamespaceDependencies requires at least one root namespace')
     self.__rootNamespaces = namespace_set
Exemple #10
0
    def __getnewargs__(self):
        """Pickling support.

        To ensure that unpickled Namespace instances are unique per
        URI, we ensure that the routine that creates unpickled
        instances knows what it's supposed to return."""
        if self.uri() is None:
            raise pyxb.LogicError('Illegal to serialize absent namespaces')
        return (self.uri(), )
Exemple #11
0
    def _bindingRequires_vx (self, include_lax):
        """Placeholder for subclass method that identifies the necessary components.

        @note: Override in subclasses.

        @return: The component instances on which this component depends
        @rtype: C{frozenset}
        @raise LogicError: A subclass failed to implement this method
        """
        raise pyxb.LogicError('%s does not implement _bindingRequires_vx' % (type(self),))
Exemple #12
0
def NamespaceInstance (namespace):
    """Get a namespace instance for the given namespace.

    This is used when it is unclear whether the namespace is specified by URI
    or by instance or by any other mechanism we might dream up in the
    future."""
    if isinstance(namespace, pyxb.namespace.Namespace):
        return namespace
    if isinstance(namespace, basestring):
        return NamespaceForURI(namespace, True)
    raise pyxb.LogicError('Cannot identify namespace from value of type %s' % (type(namespace),))
Exemple #13
0
 def ClassForFacet(cls, name):
     """Given the name of a facet, return the Facet subclass that represents it."""
     assert cls != Facet
     if 0 <= name.find(':'):
         name = name.split(':', 1)[1]
     facet_class = globals().get('%s_%s' % (cls._FacetPrefix, name), None)
     if facet_class is None:
         raise pyxb.LogicError(
             'Unrecognized facet name %s: expect %s' %
             (name, ','.join([_f._Name for _f in cls.Facets])))
     assert facet_class is not None
     return facet_class
Exemple #14
0
def NamespaceForURI(uri, create_if_missing=False):
    """Given a URI, provide the L{Namespace} instance corresponding to it.

    This can only be used to lookup or create real namespaces.  To create
    absent namespaces, use L{CreateAbsentNamespace}.

    @param uri: The URI that identifies the namespace
    @type uri: A non-empty C{str} or C{unicode} string
    @keyword create_if_missing: If C{True}, a namespace for the given URI is
    created if one has not already been registered.  Default is C{False}.
    @type create_if_missing: C{bool}
    @return: The Namespace corresponding to C{uri}, if available
    @rtype: L{Namespace} or C{None}
    @raise pyxb.LogicError: The uri is not a non-empty string
    """
    if not isinstance(uri, (str, unicode)):
        raise pyxb.LogicError('Cannot lookup absent namespaces')
    if 0 == len(uri):
        raise pyxb.LogicError('Namespace URIs must not be empty strings')
    rv = pyxb.namespace.Namespace._NamespaceForURI(uri)
    if (rv is None) and create_if_missing:
        rv = pyxb.namespace.Namespace(uri)
    return rv
Exemple #15
0
    def __identifyNamespace (self, nsval):
        """Identify the specified namespace, which should be a built-in.

        Normally we can just use a reference to the Namespace module instance,
        but when creating those instances we sometimes need to refer to ones
        for which the instance has not yet been created.  In that case, we use
        the name of the instance, and resolve the namespace when we need to
        create the initial context."""
        if nsval is None:
            return self
        if isinstance(nsval, six.string_types):
            nsval = globals().get(nsval)
        if isinstance(nsval, Namespace):
            return nsval
        raise pyxb.LogicError('Cannot identify namespace from %s' % (nsval,))
Exemple #16
0
    def __init__(self,
                 uri,
                 description=None,
                 builtin_namespace=None,
                 builtin_module_path=None,
                 is_undeclared_namespace=False,
                 is_loaded_namespace=False,
                 bound_prefix=None,
                 default_namespace=None,
                 in_scope_namespaces=None):
        """Create a new Namespace.

        The URI must be non-None, and must not already be assigned to
        a Namespace instance.  See _NamespaceForURI().

        User-created Namespace instances may also provide a description.

        Users should never provide a builtin_namespace parameter.
        """

        # New-style superclass invocation
        super(Namespace, self).__init__()

        self.__contextDefaultNamespace = default_namespace
        self.__contextInScopeNamespaces = in_scope_namespaces

        # Make sure that we're not trying to do something restricted to
        # built-in namespaces
        is_builtin_namespace = not (builtin_namespace is None)
        if not is_builtin_namespace:
            if bound_prefix is not None:
                raise pyxb.LogicError(
                    'Only permanent Namespaces may have bound prefixes')

        # We actually set the uri when this instance was allocated;
        # see __new__().
        assert self.__uri == uri
        self.__boundPrefix = bound_prefix
        self.__description = description
        self.__isBuiltinNamespace = is_builtin_namespace
        self.__builtinNamespaceVariable = builtin_namespace
        self.__builtinModulePath = builtin_module_path
        self.__isUndeclaredNamespace = is_undeclared_namespace
        self.__isLoadedNamespace = is_loaded_namespace

        self._reset()

        assert (self.__uri is None) or (self.__Registry[self.__uri] == self)
Exemple #17
0
    def __init__(self,
                 default_namespace=None,
                 namespace_prefix_map=None,
                 inherit_from=None):
        """Create a new namespace declaration configuration.

        @keyword default_namespace: Optional L{pyxb.namespace.Namespace}
        instance that serves as the default namespace (applies to unqualified
        names).

        @keyword namespace_prefix_map: Optional map from
        L{pyxb.namespace.Namespace} instances to C{str} values that are to be
        used as the corresponding namespace prefix when constructing
        U{qualified names<http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-qname>}.

        @keyword inherit_from: Optional instance of this class from which
        defaults are inherited.  Inheritance is overridden by values of other
        keywords in the initializer.
        """
        self.__prefixes = set()
        self.__namespacePrefixCounter = 0
        self.__namespaces = {}
        self.__defaultNamespace = None
        self.__resetNamespacePrefixMap()
        if inherit_from is not None:
            if default_namespace is None:
                default_namespace = inherit_from.defaultNamespace()
            self.__namespacePrefixMap.update(inherit_from.__namespacePrefixMap)
            self.__namespacePrefixCount = inherit_from.__namespacePrefixCounter
            self.__namespaces.update(inherit_from.__namespaces)
            self.__prefixes.update(inherit_from.__prefixes)
        if default_namespace is not None:
            self.setDefaultNamespace(default_namespace)
        prefixes = set(self.__namespacePrefixMap.itervalues())
        prefixes.update(self.__prefixes)
        if namespace_prefix_map is not None:
            prefixes = set()
            for (ns, pfx) in namespace_prefix_map.iteritems():
                ns = pyxb.namespace.NamespaceInstance(ns)
                if pfx in prefixes:
                    raise pyxb.LogicError(
                        'Cannot assign same prefix to multiple namespacess: %s'
                        % (pfx, ))
                prefixes.add(pfx)
                self.__namespacePrefixMap[ns] = pfx
Exemple #18
0
    def declareNamespace(self, namespace, prefix=None, add_to_map=False):
        """Record the given namespace as one to be used in this document.

        @param namespace: The namespace to be associated with the document.
        @type namespace: L{pyxb.namespace.Namespace}

        @keyword prefix: Optional prefix to be used with this namespace.  If
        not provided, a unique prefix is generated or a standard prefix is
        used, depending on the namespace.

        @return: a prefix that may be used with the namespace.  If C{prefix}
        was C{None} the return value may be a previously-assigned prefix.

        @todo: ensure multiple namespaces do not share the same prefix
        @todo: provide default prefix in L{pyxb.namespace.Namespace}
        """
        if not isinstance(namespace, pyxb.namespace.Namespace):
            raise pyxb.UsageError(
                'declareNamespace: must be given a namespace instance')
        if namespace.isAbsentNamespace():
            raise pyxb.UsageError(
                'declareNamespace: namespace must not be an absent namespace')
        if prefix is None:
            prefix = namespace.prefix()
        if prefix is None:
            pfxs = self.__inScopePrefixes.get(namespace)
            if pfxs:
                prefix = next(iter(pfxs))
        while prefix is None:
            self.__namespacePrefixCounter += 1
            candidate_prefix = 'ns%d' % (self.__namespacePrefixCounter, )
            if not (candidate_prefix in self.__inScopeNamespaces):
                prefix = candidate_prefix
        ns = self.__inScopePrefixes.get(prefix)
        if ns:
            if ns != namespace:
                raise pyxb.LogicError('Prefix %s is already in use for %s' %
                                      (prefix, ns))
            return prefix
        if not self.__mutableInScopeNamespaces:
            self.__clonePrefixMap()
            self.__mutableInScopeNamespaces = True
        self.__addPrefixMap(prefix, namespace)
        return prefix
Exemple #19
0
    def declareNamespace(self, namespace, prefix=None, add_to_map=False):
        """Add the given namespace as one to be used in this document.

        @param namespace: The namespace to be associated with the document.
        @type namespace: L{pyxb.namespace.Namespace}

        @keyword prefix: Optional prefix to be used with this namespace.  If
        not provided, a unique prefix is generated or a standard prefix is
        used, depending on the namespace.

        @keyword add_to_map: If C{False} (default), the prefix is not added to
        the namespace prefix map.  If C{True} it is added.  (Often, things
        added to the prefix map are preserved across resets, which is often
        not desired for specific prefix/namespace pairs).

        @todo: ensure multiple namespaces do not share the same prefix
        @todo: provide default prefix in L{pyxb.namespace.Namespace}
        @todo: support multiple prefixes for each namespace
        """
        if not isinstance(namespace, pyxb.namespace.Namespace):
            raise pyxb.UsageError(
                'declareNamespace: must be given a namespace instance')
        if namespace.isAbsentNamespace():
            raise pyxb.UsageError(
                'declareNamespace: namespace must not be an absent namespace')
        if prefix is None:
            prefix = self.__namespaces.get(namespace)
        if prefix is None:
            prefix = self.__namespacePrefixMap.get(namespace)
        if prefix is None:
            prefix = namespace.prefix()
        if prefix is None:
            self.__namespacePrefixCounter += 1
            prefix = 'ns%d' % (self.__namespacePrefixCounter, )
        if prefix == self.__namespaces.get(namespace):
            return prefix
        if prefix in self.__prefixes:
            raise pyxb.LogicError('Prefix %s is already in use' % (prefix, ))
        self.__namespaces[namespace] = prefix
        self.__prefixes.add(prefix)
        if add_to_map:
            self.__namespacePrefixMap[namespace] = prefix
        return prefix
Exemple #20
0
    def _makeURINodeNamePair(self, node):
        """Convert namespace information from a DOM node to text for new DOM node.

        The namespaceURI and nodeName are extracted and parsed.  The namespace
        (if any) is registered within the document, along with any prefix from
        the node name.  A pair is returned where the first element is the
        namespace URI or C{None}, and the second is a QName to be used for the
        expanded name within this document.

        @param node: An xml.dom.Node instance, presumably from a wildcard match.
        @rtype: C{( str, str )}"""
        ns = None
        if node.namespaceURI is not None:
            ns = pyxb.namespace.NamespaceForURI(node.namespaceURI,
                                                create_if_missing=True)
        if node.ELEMENT_NODE == node.nodeType:
            name = node.tagName
        elif node.ATTRIBUTE_NODE == node.nodeType:
            name = node.name
            # saxdom uses the uriTuple as the name field while minidom uses
            # the QName.  @todo saxdom should be fixed.
            if isinstance(name, tuple):
                name = name[1]
        else:
            raise pyxb.UsageError('Unable to determine name from DOM node %s' %
                                  (node, ))
        pfx = None
        local_name = name
        if 0 < name.find(':'):
            (pfx, local_name) = name.split(':', 1)
            if ns is None:
                raise pyxb.LogicError(
                    'QName with prefix but no available namespace')
        ns_uri = None
        node_name = local_name
        if ns is not None:
            ns_uri = ns.uri()
            self.declareNamespace(ns, pfx)
            if pfx is None:
                pfx = self.namespacePrefix(ns)
            if pfx is not None:
                node_name = '%s:%s' % (pfx, local_name)
        return (ns_uri, node_name)
Exemple #21
0
def ResolveSiblingNamespaces(sibling_namespaces, origin_uid):
    for ns in sibling_namespaces:
        ns.configureCategories([archive.NamespaceArchive._AnonymousCategory()])
        ns.validateComponentModel()

    need_resolved = set(sibling_namespaces)
    while need_resolved:
        new_nr = set()
        for ns in need_resolved:
            if not ns.needsResolution():
                continue
            #print 'Attempting resolution %s' % (ns.uri(),)
            if not ns.resolveDefinitions(allow_unresolved=True):
                print 'Holding incomplete resolution %s' % (ns.uri(), )
                new_nr.add(ns)
        if need_resolved == new_nr:
            raise pyxb.LogicError(
                'Unexpected external dependency in sibling namespaces: %s' %
                ("\n  ".join([str(_ns) for _ns in need_resolved]), ))
        need_resolved = new_nr
Exemple #22
0
 def processXMLNS(self, prefix, uri):
     from pyxb.namespace import builtin
     if not self.__mutableInScopeNamespaces:
         self.__clonePrefixMap()
         self.__mutableInScopeNamespaces = True
     if builtin.XML.boundPrefix() == prefix:
         # Bound prefix xml is permitted if it's bound to the right URI, or
         # if the scope is being left.  In neither case is the mapping
         # adjusted.
         if (uri is None) or builtin.XML.uri() == uri:
             return
         raise pyxb.LogicError('Cannot manipulate bound prefix xml')
     if uri:
         if prefix is None:
             ns = self.__defaultNamespace = utility.NamespaceForURI(
                 uri, create_if_missing=True)
             self.__inScopeNamespaces[None] = self.__defaultNamespace
         else:
             ns = utility.NamespaceForURI(uri, create_if_missing=True)
             self.__removePrefixMap(prefix)
             self.__addPrefixMap(prefix, ns)
         if self.__targetNamespace:
             self.__targetNamespace._referenceNamespace(ns)
         else:
             self.__pendingReferencedNamespaces.add(ns)
     else:
         # NB: XMLNS 6.2 says that you can undefine a default
         # namespace, but does not say anything explicitly about
         # undefining a prefixed namespace.  XML-Infoset 2.2
         # paragraph 6 implies you can do this, but expat blows up
         # if you try it.  I don't think it's legal.
         if prefix is not None:
             raise pyxb.NamespaceError(
                 self, 'Attempt to undefine non-default namespace %s' %
                 (prefix, ))
         self.__removePrefixMap(prefix)
         self.__defaultNamespace = None
Exemple #23
0
    def _resolve(self):
        """Perform whatever steps are required to resolve this component.

        Resolution is performed in the context of the namespace to which the
        component belongs.  Invoking this method may fail to complete the
        resolution process if the component itself depends on unresolved
        components.  The sole caller of this should be
        L{_NamespaceResolution_mixin.resolveDefinitions}.
        
        This method is permitted (nay, encouraged) to raise an exception if
        resolution requires interpreting a QName and the named component
        cannot be found.

        Override this in the child class.  In the prefix, if L{isResolved} is
        true, return right away.  If something prevents you from completing
        resolution, invoke L{self._queueForResolution()} (so it is retried
        later) and immediately return self.  Prior to leaving after successful
        resolution discard any cached dom node by setting C{self.__domNode=None}.

        @return: C{self}, whether or not resolution succeeds.
        @raise pyxb.SchemaValidationError: if resolution requlres a reference to an unknown component
        """
        raise pyxb.LogicError('Resolution not implemented in %s' %
                              (self.__class__, ))
Exemple #24
0
 def _validateConstraint_vx(self, value):
     raise pyxb.LogicError("Facet %s does not implement constraints" %
                           (self.Name(), ))
Exemple #25
0
    def PreLoadArchives(cls, archive_path=None, reset=False):
        """Scan for available archives, associating them with namespaces.

        This only validates potential archive contents; it does not load
        namespace data from the archives.

        @keyword archive_path: A list of files or directories in which
        namespace archives can be found.  The entries are separated by
        os.pathsep, which is a colon on POSIX platforms and a semi-colon on
        Windows.  See L{PathEnvironmentVariable}.  Defaults to
        L{GetArchivePath()}.  If not defaulted, C{reset} will be forced to
        C{True}.  For any directory in the path, all files ending with
        C{.wxs} are examined.

        @keyword reset: If C{False} (default), the most recently read set of
        archives is returned; if C{True}, the archive path is re-scanned and the
        namespace associations validated.
        """

        from pyxb.namespace import builtin

        reset = reset or (archive_path
                          is not None) or (cls.__NamespaceArchives is None)
        if reset:
            # Get a list of pre-existing archives, initializing the map if
            # this is the first time through.
            if cls.__NamespaceArchives is None:
                cls.__NamespaceArchives = {}
            existing_archives = set(six.itervalues(cls.__NamespaceArchives))
            archive_set = set()

            # Ensure we have an archive path.  If not, don't do anything.
            if archive_path is None:
                archive_path = GetArchivePath()
            if archive_path is not None:

                # Get archive instances for everything in the archive path
                candidate_files = pyxb.utils.utility.GetMatchingFiles(
                    archive_path,
                    cls.__ArchivePattern_re,
                    default_path_wildcard='+',
                    default_path=GetArchivePath(),
                    prefix_pattern='&',
                    prefix_substituend=DefaultArchivePrefix)
                for afn in candidate_files:
                    try:
                        nsa = cls.__GetArchiveInstance(
                            afn, stage=cls._STAGE_readModules)
                        archive_set.add(nsa)
                    except pickle.UnpicklingError:
                        _log.exception('Cannot unpickle archive %s', afn)
                    except pyxb.NamespaceArchiveError:
                        _log.exception('Cannot process archive %s', afn)

                # Do this for two reasons: first, to get an iterable that won't
                # cause problems when we remove unresolvable archives from
                # archive_set; and second to aid with forced dependency inversion
                # testing
                ordered_archives = sorted(list(archive_set),
                                          key=lambda _a: _a.archivePath())
                ordered_archives.reverse()

                # Create a graph that identifies dependencies between the archives
                archive_map = {}
                for a in archive_set:
                    archive_map[a.generationUID()] = a
                archive_graph = pyxb.utils.utility.Graph()
                for a in ordered_archives:
                    prereqs = a._unsatisfiedModulePrerequisites()
                    if 0 < len(prereqs):
                        for p in prereqs:
                            if builtin.BuiltInObjectUID == p:
                                continue
                            da = archive_map.get(p)
                            if da is None:
                                _log.warning(
                                    '%s depends on unavailable archive %s', a,
                                    p)
                                archive_set.remove(a)
                            else:
                                archive_graph.addEdge(a, da)
                    else:
                        archive_graph.addRoot(a)

                # Verify that there are no dependency loops.
                archive_scc = archive_graph.sccOrder()
                for scc in archive_scc:
                    if 1 < len(scc):
                        raise pyxb.LogicError(
                            "Cycle in archive dependencies.  How'd you do that?\n  "
                            + "\n  ".join([_a.archivePath() for _a in scc]))
                    archive = scc[0]
                    if not (archive in archive_set):
                        archive.discard()
                        existing_archives.remove(archive)
                        continue
                    #archive._readToStage(cls._STAGE_COMPLETE)

            # Discard any archives that we used to know about but now aren't
            # supposed to.  @todo make this friendlier in the case of archives
            # we've already incorporated.
            for archive in existing_archives.difference(archive_set):
                _log.info('Discarding excluded archive %s', archive)
                archive.discard()
Exemple #26
0
    def __init__(self,
                 dom_node=None,
                 parent_context=None,
                 including_context=None,
                 recurse=True,
                 default_namespace=None,
                 target_namespace=None,
                 in_scope_namespaces=None,
                 expanded_name=None,
                 finalize_target_namespace=True
                 ):  # MUST BE True for WSDL to work with minidom
        """Determine the namespace context that should be associated with the
        given node and, optionally, its element children.

        @param dom_node: The DOM node
        @type dom_node: C{xml.dom.Element}
        @keyword parent_context: Optional value that specifies the context
        associated with C{dom_node}'s parent node.  If not provided, only the
        C{xml} namespace is in scope.
        @type parent_context: L{NamespaceContext}
        @keyword recurse: If True (default), create namespace contexts for all
        element children of C{dom_node}
        @type recurse: C{bool}
        @keyword default_namespace: Optional value to set as the default
        namespace.  Values from C{parent_context} would override this, as
        would an C{xmlns} attribute in the C{dom_node}.
        @type default_namespace: L{NamespaceContext}
        @keyword target_namespace: Optional value to set as the target
        namespace.  Values from C{parent_context} would override this, as
        would a C{targetNamespace} attribute in the C{dom_node}
        @type target_namespace: L{NamespaceContext}
        @keyword in_scope_namespaces: Optional value to set as the initial set
        of in-scope namespaces.  The always-present namespaces are added to
        this if necessary.
        @type in_scope_namespaces: C{dict} mapping C{string} to L{Namespace}.
        """
        from pyxb.namespace import builtin

        if dom_node is not None:
            try:
                assert dom_node.__namespaceContext is None
            except AttributeError:
                pass
            dom_node.__namespaceContext = self

        self.__defaultNamespace = default_namespace
        self.__targetNamespace = target_namespace
        self.__inScopeNamespaces = builtin._UndeclaredNamespaceMap
        self.__mutableInScopeNamespaces = False

        if in_scope_namespaces is not None:
            if parent_context is not None:
                raise pyxb.LogicError(
                    'Cannot provide both parent_context and in_scope_namespaces'
                )
            self.__inScopeNamespaces = builtin._UndeclaredNamespaceMap.copy()
            self.__inScopeNamespaces.update(in_scope_namespaces)
            self.__mutableInScopeNamespaces = True

        if parent_context is not None:
            self.__inScopeNamespaces = parent_context.inScopeNamespaces()
            self.__mutableInScopeNamespaces = False
            self.__defaultNamespace = parent_context.defaultNamespace()
            self.__targetNamespace = parent_context.targetNamespace()
            self.__fallbackToTargetNamespace = parent_context.__fallbackToTargetNamespace

        if self.__targetNamespace is None:
            self.__pendingReferencedNamespaces = set()
        attribute_map = {}
        if dom_node is not None:
            if expanded_name is None:
                expanded_name = pyxb.namespace.ExpandedName(dom_node)
            for ai in range(dom_node.attributes.length):
                attr = dom_node.attributes.item(ai)
                if builtin.XMLNamespaces.uri() == attr.namespaceURI:
                    prefix = attr.localName
                    if 'xmlns' == prefix:
                        prefix = None
                    self.processXMLNS(prefix, attr.value)
                else:
                    if attr.namespaceURI is not None:
                        uri = utility.NamespaceForURI(attr.namespaceURI,
                                                      create_if_missing=True)
                        key = pyxb.namespace.ExpandedName(uri, attr.localName)
                    else:
                        key = pyxb.namespace.ExpandedName(None, attr.localName)
                    attribute_map[key] = attr.value

        if finalize_target_namespace:
            tns_uri = None
            tns_attr = self._TargetNamespaceAttribute(expanded_name)
            if tns_attr is not None:
                tns_uri = attribute_map.get(tns_attr)
                self.finalizeTargetNamespace(
                    tns_uri, including_context=including_context)

        # Store in each node the in-scope namespaces at that node;
        # we'll need them for QName interpretation of attribute
        # values.
        if (dom_node is not None) and recurse:
            from xml.dom import Node
            assert Node.ELEMENT_NODE == dom_node.nodeType
            for cn in dom_node.childNodes:
                if Node.ELEMENT_NODE == cn.nodeType:
                    NamespaceContext(cn, self, True)
Exemple #27
0
    def __init__ (self, *args, **kw):
        """Create an expanded name.

        Expected argument patterns are:

         - ( C{str} ) : the local name in an absent namespace
         - ( L{ExpandedName} ) : a copy of the given expanded name
         - ( C{xml.dom.Node} ) : The name extracted from node.namespaceURI and node.localName
         - ( C{str}, C{str} ) : the namespace URI and the local name
         - ( L{Namespace}, C{str} ) : the namespace and the local name
         - ( L{ExpandedName}, C{str}) : the namespace from the expanded name, and the local name

        Wherever C{str} occurs C{unicode} is also permitted.

        @keyword fallback_namespace: Optional Namespace instance to use if the
        namespace would otherwise be None.  This is only used if it is an
        absent namespace.

        """
        fallback_namespace = kw.get('fallback_namespace')
        if 0 == len(args):
            raise pyxb.LogicError('Too few arguments to ExpandedName constructor')
        if 2 < len(args):
            raise pyxb.LogicError('Too many arguments to ExpandedName constructor')
        if 2 == len(args):
            # Namespace(str, unicode, Namespace) and local name basestring
            ( ns, ln ) = args
        else:
            # Local name basestring or ExpandedName or Node
            assert 1 == len(args)
            ln = args[0]
            ns = None
            if isinstance(ln, six.string_types):
                pass
            elif isinstance(ln, tuple) and (2 == len(ln)):
                (ns, ln) = ln
            elif isinstance(ln, ExpandedName):
                ns = ln.namespace()
                ln = ln.localName()
            elif isinstance(ln, xml.dom.Node):
                if not(ln.nodeType in (xml.dom.Node.ELEMENT_NODE, xml.dom.Node.ATTRIBUTE_NODE)):
                    raise pyxb.LogicError('Cannot create expanded name from non-element DOM node %s' % (ln.nodeType,))
                ns = ln.namespaceURI
                ln = ln.localName
            else:
                raise pyxb.LogicError('Unrecognized argument type %s' % (type(ln),))
        if (ns is None) and (fallback_namespace is not None):
            if fallback_namespace.isAbsentNamespace():
                ns = fallback_namespace
        if isinstance(ns, six.string_types):
            ns = NamespaceForURI(ns, create_if_missing=True)
        if isinstance(ns, ExpandedName):
            ns = ns.namespace()
        if (ns is not None) and not isinstance(ns, Namespace):
            raise pyxb.LogicError('ExpandedName must include a valid (perhaps absent) namespace, or None.')
        self.__namespace = ns
        if self.__namespace is not None:
            self.__namespaceURI = self.__namespace.uri()
        self.__localName = ln
        assert self.__localName is not None
        self.__expandedName = ( self.__namespace, self.__localName )
        self.__uriTuple = ( self.__namespaceURI, self.__localName )
        super(ExpandedName, self).__init__(*args, **kw)
Exemple #28
0
    def isResolved(self):
        """Determine whether this named component is resolved.

        Override this in the child class."""
        raise pyxb.LogicError('Resolved check not implemented in %s' %
                              (self.__class__, ))
Exemple #29
0
    def PreLoadArchives(cls,
                        archive_path=None,
                        required_archive_files=None,
                        reset=False):
        """Scan for available archives, associating them with namespaces.

        This only validates potential archive contents; it does not load
        namespace data from the archives.  If invoked with no arguments, 

        @keyword archive_path: A colon-separated list of files or directories in
        which namespace archives can be found; see L{PathEnvironmentVariable}.
        Defaults to L{GetArchivePath()}.  If not defaulted, C{reset} will be
        forced to C{True}.  For any directory in the path, all files ending with
        C{.wxs} are examined.

        @keyword required_archive_files: A list of paths to files that must
        resolve to valid namespace archives.

        @keyword reset: If C{False} (default), the most recently read set of
        archives is returned; if C{True}, the archive path is re-scanned and the
        namespace associations validated.

        @return: A list of L{NamespaceArchive} instances corresponding to the
        members of C{required_archive_files}, in order.  If
        C{required_archive_files} was not provided, returns an empty list.

        @raise pickle.UnpicklingError: a C{required_archive_files} member does not
        contain a valid namespace archive.
        """

        import builtin

        reset = reset or (archive_path is not None) or (
            required_archive_files
            is not None) or (cls.__NamespaceArchives is None)
        required_archives = []
        if reset:
            # Get a list of pre-existing archives, initializing the map if
            # this is the first time through.
            if cls.__NamespaceArchives is None:
                cls.__NamespaceArchives = {}
            existing_archives = set(cls.__NamespaceArchives.values())
            archive_set = set(required_archives)

            # Get archives for all required files
            if required_archive_files is not None:
                for afn in required_archive_files:
                    required_archives.append(
                        cls.__GetArchiveInstance(afn,
                                                 stage=cls._STAGE_readModules))

            # Ensure we have an archive path.  If not, don't do anything.
            if archive_path is None:
                archive_path = GetArchivePath()
            if archive_path is not None:

                # Get archive instances for everything in the archive path
                candidate_files = pyxb.utils.utility.GetMatchingFiles(
                    archive_path,
                    cls.__ArchivePattern_re,
                    prefix_pattern='&',
                    prefix_substituend=DefaultArchivePrefix)
                for afn in candidate_files:
                    #print 'Considering %s' % (afn,)
                    try:
                        nsa = cls.__GetArchiveInstance(
                            afn, stage=cls._STAGE_readModules)
                        archive_set.add(nsa)
                    except pickle.UnpicklingError, e:
                        print 'Cannot use archive %s: %s' % (afn, e)
                    except pyxb.NamespaceArchiveError, e:
                        print 'Cannot use archive %s: %s' % (afn, e)

                # Do this for two reasons: first, to get an iterable that won't
                # cause problems when we remove unresolvable archives from
                # archive_set; and second to aid with forced dependency inversion
                # testing
                ordered_archives = sorted(
                    list(archive_set),
                    lambda _a, _b: cmp(_a.archivePath(), _b.archivePath()))
                ordered_archives.reverse()

                # Create a graph that identifies dependencies between the archives
                archive_map = {}
                for a in archive_set:
                    archive_map[a.generationUID()] = a
                archive_graph = pyxb.utils.utility.Graph()
                for a in ordered_archives:
                    prereqs = a._unsatisfiedModulePrerequisites()
                    if 0 < len(prereqs):
                        for p in prereqs:
                            if builtin.BuiltInObjectUID == p:
                                continue
                            da = archive_map.get(p)
                            if da is None:
                                print 'WARNING: %s depends on unavailable archive %s' % (
                                    a, p)
                                archive_set.remove(a)
                            else:
                                #print '%s depends on %s' % (a, da)
                                archive_graph.addEdge(a, da)
                    else:
                        #print '%s has no dependencies' % (a,)
                        archive_graph.addRoot(a)

                # Verify that there are no dependency loops.
                archive_scc = archive_graph.sccOrder()
                for scc in archive_scc:
                    if 1 < len(scc):
                        raise pyxb.LogicError(
                            "Cycle in archive dependencies.  How'd you do that?\n  "
                            + "\n  ".join([_a.archivePath() for _a in scc]))
                    archive = scc[0]
                    if not (archive in archive_set):
                        #print 'Discarding unresolvable %s' % (archive,)
                        archive.discard()
                        existing_archives.remove(archive)
                        continue
Exemple #30
0
def ResolveSiblingNamespaces(sibling_namespaces):
    """Resolve all components in the sibling_namespaces.

    @param sibling_namespaces : A set of namespaces expected to be closed
    under dependency."""

    for ns in sibling_namespaces:
        ns.configureCategories([archive.NamespaceArchive._AnonymousCategory()])
        ns.validateComponentModel()

    def __keyForCompare(dependency_map):
        """Sort namespaces so dependencies get resolved first.

        Uses the trick underlying functools.cmp_to_key(), but optimized for
        this special case.  The dependency map is incorporated into the class
        definition by scope.
        """
        class K(object):
            def __init__(self, ns, *args):
                self.__ns = ns

            # self compares less than other if self.ns is in the dependency set
            # of other.ns but not vice-versa.
            def __lt__(self, other):
                return ((self.__ns in dependency_map.get(other.__ns, set())) \
                            and not (other.__ns in dependency_map.get(self.__ns, set())))

            # self compares equal to other if their namespaces are either
            # mutually dependent or independent.
            def __eq__(self, other):
                return (self.__ns in dependency_map.get(
                    other.__ns,
                    set())) == (other.__ns
                                in dependency_map.get(self.__ns, set()))

            # All other order metrics are derived.
            def __ne__(self, other):
                return not self.__eq__(other)

            def __le__(self, other):
                return self.__lt__(other) or self.__eq__(other)

            def __gt__(self, other):
                return other.__lt__(self.__ns)

            def __ge__(self, other):
                return other.__lt__(self.__ns) or self.__eq__(other)

        return K

    need_resolved_set = set(sibling_namespaces)
    dependency_map = {}
    last_state = None
    while need_resolved_set:
        need_resolved_list = list(need_resolved_set)
        if dependency_map:
            need_resolved_list.sort(key=__keyForCompare(dependency_map))
        need_resolved_set = set()
        dependency_map = {}
        for ns in need_resolved_list:
            if not ns.needsResolution():
                continue
            if not ns.resolveDefinitions(allow_unresolved=True):
                deps = dependency_map.setdefault(ns, set())
                for (c, dcs) in six.iteritems(ns._unresolvedDependents()):
                    for dc in dcs:
                        dns = dc.expandedName().namespace()
                        if dns != ns:
                            deps.add(dns)
                _log.info(
                    'Holding incomplete resolution %s depending on: ',
                    ns.uri(),
                    six.u(' ; ').join([six.text_type(_dns) for _dns in deps]))
                need_resolved_set.add(ns)
        # Exception termination check: if we have the same set of incompletely
        # resolved namespaces, and each has the same number of unresolved
        # components, assume there's an truly unresolvable dependency: either
        # due to circularity, or because there was an external namespace that
        # was missed from the sibling list.
        state = []
        for ns in need_resolved_set:
            state.append((ns, len(ns._unresolvedComponents())))
        state = tuple(state)
        if last_state == state:
            raise pyxb.LogicError(
                'Unexpected external dependency in sibling namespaces: %s' %
                (six.u('\n  ').join(
                    [six.text_type(_ns) for _ns in need_resolved_set]), ))
        last_state = state