blob: 2aab38e27ca335a75bd68eb466565d273af6568c [file] [log] [blame]
# 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('<foo/>')
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)