Commits

Allan Crooks  committed bb85cb9

Use is_iterator function to determine if the response content is iterable, rather than just testing if it is a generator.

This is in preparation for a fix for #1288. Note - we could test against
collections.Iterator, but this seems like a cleaner way of doing it for now.

  • Participants
  • Parent commits 4537fd4
  • Branches cp4

Comments (0)

Files changed (3)

File cherrypy/lib/__init__.py

 # Deprecated in CherryPy 3.2 -- remove in CherryPy 3.3
 from cherrypy.lib.reprconf import unrepr, modules, attributes
 
+def is_iterator(obj):
+    '''Returns a boolean indicating if the object provided implements
+     the iterator protocol (i.e. like a generator). This will return
+     false for objects which iterable, but not iterators themselves.'''
+    from types import GeneratorType
+    if isinstance(obj, GeneratorType):
+        return True
+    elif not hasattr(obj, '__iter__'):
+        return False
+    else:
+        # Types which implement the protocol must return themselves when
+        # invoking 'iter' upon them.
+        return iter(obj) is obj
 
 class file_generator(object):
     """Yield the given input (a file object) in chunks (default 64k). (Core)"""

File cherrypy/lib/tools/flatten.py

 import cherrypy
+from cherrypy.lib import is_iterator
 
 
 def flatten(debug=False):
     This allows cherrypy.response.body to consist of 'nested generators';
     that is, a set of generators that yield generators.
     """
-    import types
-
     def flattener(input):
         numchunks = 0
         for x in input:
-            if not isinstance(x, types.GeneratorType):
+            if not is_iterator(x):
                 numchunks += 1
                 yield x
             else:

File cherrypy/lib/tools/sessions/base.py

 import datetime
 import os
 import time
-import types
 
 from magicbus.plugins.tasks import Monitor
 
 import cherrypy
 from cherrypy.lib.tools import Tool
-from cherrypy.lib import httputil
+from cherrypy.lib import httputil, is_iterator
 
 missing = object()
 
     else:
         # If the body is not being streamed, we save the data now
         # (so we can release the lock).
-        if isinstance(response.body, types.GeneratorType):
+        if is_iterator(response.body):
             response.collapse_body()
         cherrypy.session.save()
 save.failsafe = True