# string conversion stuff def entitize(s): """ entitize a string so it can be used in XML content and attrs """ return s.replace('&', '&').replace('"', '"').replace( '<', '<').replace('>', '>') def strconvert(s, charset): from templess import nodebase if isinstance(s, nodebase): return s elif isinstance(s, xmlstring): return unicode(s) elif isinstance(s, str): s = unicode(s, charset) elif not isinstance(s, unicode): s = str(s) return entitize(s) # helper functions def is_iterable_not_string(v): """ determine if something is iterable but not a string """ from templess import elnode for t in (str, unicode, xmlstring, objectcontext, elnode): if isinstance(v, t): return False try: iter(v) except TypeError: return False else: return True # some helper classes for templess users class xmlstring(unicode): """ wrapper around unicode to mark a string as XML when Templess encounters this object, it will not escape entities """ def iterwrapper(iterable): for i in iterable: yield objectcontext(i) class objectcontext(object): """ wrapper around objects to allow Templess to traverse attributes this is similar to the nastyness Zope exposes to its users in TAL, when Templess retrieves a key from the context, if the context is an objectcontext wrapping an object, instead of just doing a __getitem__ the following will be done: - first a __getitem__ is tried, then a __getattr_, if the value is still not found a KeyError is raised - before the value is returned, a check is done whether it's callable, and if so it's called (without arguments) """ # XXX do we want to allow arguments in something like "@key,key" form or # something scary like that? this is nasty already anyway ;) def __init__(self, o): self.object = o __marker__ = [] def __getitem__(self, name): try: ret = self.object[name] except (TypeError, KeyError): try: ret = self.object.__dict__[name] except KeyError: try: ret = self.object.__class__.__dict__[name] except KeyError: raise KeyError, name if callable(ret): ret = ret() return self.wrap(ret) def __str__(self): return getattr(self.object, '__str__', self.object.__repr__)() def __repr__(self): return '' % (self.object.__class__.__name__,) def wrap(self, obj): if is_iterable_not_string(obj): return iterwrapper(obj) return objectcontext(obj) def __hasattr__(self, name): return hasattr(self.object, name)