# HG changeset patch # User cmlenz # Date 1212685215 0 # Node ID ca72e3dc443de591f481369cdcdb9cf71f9ea131 # Parent a1e8b24bc1bbba5c6e78f2c5978918d62a290e29 Implement the `__html__` protocol as suggested in #202. This would allow Genshi to be used in combination with other markup generating tools, as long as they support the same protocol. diff --git a/genshi/_speedups.c b/genshi/_speedups.c --- a/genshi/_speedups.c +++ b/genshi/_speedups.c @@ -61,6 +61,18 @@ Py_INCREF(text); return text; } + if (PyObject_HasAttrString(text, "__html__")) { + ret = PyObject_CallMethod(text, "__html__", NULL); + args = PyTuple_New(1); + if (args == NULL) { + Py_DECREF(ret); + return NULL; + } + PyTuple_SET_ITEM(args, 0, ret); + ret = MarkupType.tp_new(&MarkupType, args, NULL); + Py_DECREF(args); + return ret; + } in = (PyUnicodeObject *) PyObject_Unicode(text); if (in == NULL) { return NULL; @@ -191,6 +203,13 @@ return escape(text, quotes); } +static PyObject * +Markup_html(PyObject *self) +{ + Py_INCREF(self); + return self; +} + PyDoc_STRVAR(join__doc__, "Return a `Markup` object which is the concatenation of the strings\n\ in the given sequence, where this `Markup` object is the separator\n\ @@ -516,6 +535,7 @@ } MarkupObject; static PyMethodDef Markup_methods[] = { + {"__html__", (PyCFunction) Markup_html, METH_NOARGS, NULL}, {"escape", (PyCFunction) Markup_escape, METH_VARARGS|METH_CLASS|METH_KEYWORDS, escape__doc__}, {"join", (PyCFunction)Markup_join, METH_VARARGS|METH_KEYWORDS, join__doc__}, diff --git a/genshi/builder.py b/genshi/builder.py --- a/genshi/builder.py +++ b/genshi/builder.py @@ -73,7 +73,8 @@ except NameError: from sets import Set as set -from genshi.core import Attrs, Namespace, QName, Stream, START, END, TEXT +from genshi.core import Attrs, Markup, Namespace, QName, Stream, \ + START, END, TEXT __all__ = ['Fragment', 'Element', 'ElementFactory', 'tag'] __docformat__ = 'restructuredtext en' @@ -112,6 +113,9 @@ def __unicode__(self): return unicode(self.generate()) + def __html__(self): + return Markup(self.generate()) + def append(self, node): """Append an element or string as child node. diff --git a/genshi/core.py b/genshi/core.py --- a/genshi/core.py +++ b/genshi/core.py @@ -245,6 +245,9 @@ def __unicode__(self): return self.render(encoding=None) + def __html__(self): + return self + START = Stream.START END = Stream.END @@ -485,6 +488,9 @@ return cls() if type(text) is cls: return text + if hasattr(text, '__html__'): + return Markup(text.__html__()) + text = unicode(text).replace('&', '&') \ .replace('<', '<') \ .replace('>', '>') diff --git a/genshi/tests/builder.py b/genshi/tests/builder.py --- a/genshi/tests/builder.py +++ b/genshi/tests/builder.py @@ -16,7 +16,7 @@ import unittest from genshi.builder import Element, tag -from genshi.core import Attrs, Stream +from genshi.core import Attrs, Markup, Stream from genshi.input import XML @@ -60,6 +60,12 @@ self.assertEqual((Stream.END, 'b'), xml[3][:2]) self.assertEqual((Stream.END, 'span'), xml[4][:2]) + def test_markup_escape(self): + from genshi.core import Markup + m = Markup('See %s') % tag.a('genshi', + href='http://genshi.edgwall.org') + self.assertEqual(m, Markup('See ' + 'genshi')) def suite(): suite = unittest.TestSuite()