# Copyright (c) The PyAMF Project. # See LICENSE.txt for details. """ Provides XML support. @since: 0.6 """ #: list of supported third party packages that support the C{etree} #: interface. At least enough for our needs anyway. ETREE_MODULES = [ 'lxml.etree', 'xml.etree.cElementTree', 'cElementTree', 'xml.etree.ElementTree', 'elementtree.ElementTree' ] #: A tuple of class/type objects that are used to represent XML objects. types = None #: A mapping of type -> module for all known xml types. modules = {} #: The module that will be used to create C{ElementTree} instances. ET = None __all__ = ['set_default_interface'] def set_default_interface(etree): """ Sets the default interface that PyAMF will use to deal with XML entities (both objects and blobs). """ global types, ET, modules t = _get_etree_type(etree) _types = set(types or []) _types.update([t]) types = tuple(_types) modules[t] = etree old, ET = ET, etree return old def find_libs(): """ Run through L{ETREE_MODULES} and find C{ElementTree} implementations so that any type can be encoded. We work through the C implementations first, then the pure Python versions. The downside to this is that B{all} libraries will be imported but I{only} one is ever used. The libs are small (relatively) and the flexibility that this gives seems to outweigh the cost. Time will tell. """ from pyamf.util import get_module types = [] mapping = {} for mod in ETREE_MODULES: try: etree = get_module(mod) except ImportError: continue t = _get_etree_type(etree) types.append(t) mapping[t] = etree return tuple(types), mapping def is_xml(obj): """ Determines C{obj} is a valid XML type. If L{types} is not populated then L{find_libs} be called. """ global types try: _bootstrap() except ImportError: return False return isinstance(obj, types) def _get_type(e): """ Returns the type associated with handling XML objects from this etree interface. """ try: return e.__class__ except AttributeError: return type(e) def _get_etree_type(etree): """ Returns the type associated with handling XML objects from this etree interface. """ e = etree.fromstring('') return _get_type(e) def _no_et(): raise ImportError('Unable to find at least one compatible ElementTree ' 'library, use pyamf.set_default_etree to enable XML support') def _bootstrap(): global types, modules, ET if types is None: types, modules = find_libs() if ET is None: try: etree = modules[types[0]] except IndexError: _no_et() set_default_interface(etree) def tostring(element, *args, **kwargs): """ Helper func to provide easy access to the (possibly) moving target that is C{ET}. """ global modules _bootstrap() t = _get_type(element) etree = modules.get(t, None) if not etree: raise RuntimeError('Unable to find the etree implementation related ' 'to %r (type %r)' % (element, t)) return etree.tostring(element, *args, **kwargs) def fromstring(*args, **kwargs): """ Helper func to provide easy access to the (possibly) moving target that is C{ET}. """ global ET _bootstrap() return ET.fromstring(*args, **kwargs)