changeset 688:d8571da25bc5 trunk

The `Stream.render` now accepts an optional `out` parameter that can be used to pass in a writable file-like object to use for assembling the output, instead of building a big string and returning it.
author cmlenz
date Wed, 12 Mar 2008 20:46:34 +0000
parents 8ce1a80c8843
children 3881a602048a
files ChangeLog genshi/core.py genshi/output.py genshi/tests/core.py
diffstat 4 files changed, 45 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -46,6 +46,9 @@
    of the serializer (ticket #146).
  * Assigning to a variable named `data` in a Python code block no longer
    breaks context lookup.
+ * The `Stream.render` now accepts an optional `out` parameter that can be
+   used to pass in a writable file-like object to use for assembling the
+   output, instead of building a big string and returning it.
 
 
 Version 0.4.4
--- a/genshi/core.py
+++ b/genshi/core.py
@@ -149,7 +149,7 @@
         """
         return reduce(operator.or_, (self,) + filters)
 
-    def render(self, method=None, encoding='utf-8', **kwargs):
+    def render(self, method=None, encoding='utf-8', out=None, **kwargs):
         """Return a string representation of the stream.
         
         Any additional keyword arguments are passed to the serializer, and thus
@@ -161,15 +161,22 @@
                        the stream is used
         :param encoding: how the output string should be encoded; if set to
                          `None`, this method returns a `unicode` object
-        :return: a `str` or `unicode` object
+        :param out: a file-like object that the output should be written to
+                    instead of being returned as one big string; note that if
+                    this is a file or socket (or similar), the `encoding` must
+                    not be `None` (that is, the output must be encoded)
+        :return: a `str` or `unicode` object (depending on the `encoding`
+                 parameter), or `None` if the `out` parameter is provided
         :rtype: `basestring`
+        
         :see: XMLSerializer, XHTMLSerializer, HTMLSerializer, TextSerializer
+        :note: Changed in 0.5: added the `out` parameter
         """
         from genshi.output import encode
         if method is None:
             method = self.serializer or 'xml'
         generator = self.serialize(method=method, **kwargs)
-        return encode(generator, method=method, encoding=encoding)
+        return encode(generator, method=method, encoding=encoding, out=out)
 
     def select(self, path, namespaces=None, variables=None):
         """Return a new stream that contains the events matching the given
--- a/genshi/output.py
+++ b/genshi/output.py
@@ -30,7 +30,7 @@
            'XHTMLSerializer', 'HTMLSerializer', 'TextSerializer']
 __docformat__ = 'restructuredtext en'
 
-def encode(iterator, method='xml', encoding='utf-8'):
+def encode(iterator, method='xml', encoding='utf-8', out=None):
     """Encode serializer output into a string.
     
     :param iterator: the iterator returned from serializing a stream (basically
@@ -39,16 +39,27 @@
                    representable in the specified encoding are treated
     :param encoding: how the output string should be encoded; if set to `None`,
                      this method returns a `unicode` object
-    :return: a string or unicode object (depending on the `encoding` parameter)
+    :param out: a file-like object that the output should be written to
+                instead of being returned as one big string; note that if
+                this is a file or socket (or similar), the `encoding` must
+                not be `None` (that is, the output must be encoded)
+    :return: a `str` or `unicode` object (depending on the `encoding`
+             parameter), or `None` if the `out` parameter is provided
+    
     :since: version 0.4.1
+    :note: Changed in 0.5: added the `out` parameter
     """
-    output = u''.join(list(iterator))
     if encoding is not None:
         errors = 'replace'
         if method != 'text' and not isinstance(method, TextSerializer):
             errors = 'xmlcharrefreplace'
-        return output.encode(encoding, errors)
-    return output
+        _encode = lambda string: string.encode(encoding, errors)
+    else:
+        _encode = lambda string: string
+    if out is None:
+        return _encode(u''.join(list(iterator)))
+    for chunk in iterator:
+        out.write(_encode(chunk))
 
 def get_serializer(method='xml', **kwargs):
     """Return a serializer object for the given method.
--- a/genshi/tests/core.py
+++ b/genshi/tests/core.py
@@ -14,6 +14,10 @@
 import doctest
 import pickle
 from StringIO import StringIO
+try:
+    from cStringIO import StringIO as cStringIO
+except ImportError:
+    cStringIO = StringIO
 import unittest
 
 from genshi import core
@@ -35,6 +39,18 @@
         xml = XML('<li>Über uns</li>')
         self.assertEqual('<li>&#220;ber uns</li>', xml.render(encoding='ascii'))
 
+    def test_render_output_stream_utf8(self):
+        xml = XML('<li>Über uns</li>')
+        strio = cStringIO()
+        self.assertEqual(None, xml.render(out=strio))
+        self.assertEqual('<li>Über uns</li>', strio.getvalue())
+
+    def test_render_output_stream_unicode(self):
+        xml = XML('<li>Über uns</li>')
+        strio = StringIO()
+        self.assertEqual(None, xml.render(encoding=None, out=strio))
+        self.assertEqual(u'<li>Über uns</li>', strio.getvalue())
+
     def test_pickle(self):
         xml = XML('<li>Foo</li>')
         buf = StringIO()
Copyright (C) 2012-2017 Edgewall Software