changeset 737:ca72e3dc443d trunk

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.
author cmlenz
date Thu, 05 Jun 2008 17:00:15 +0000
parents a1e8b24bc1bb
children 3b8a38fcc1ab
files genshi/_speedups.c genshi/builder.py genshi/core.py genshi/tests/builder.py
diffstat 4 files changed, 38 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- 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__},
--- 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.
         
--- 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('<', '&lt;') \
                             .replace('>', '&gt;')
--- 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 <a href="http://genshi.edgwall.org">'
+                                   'genshi</a>'))
 
 def suite():
     suite = unittest.TestSuite()
Copyright (C) 2012-2017 Edgewall Software