Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incompatible with static_file in bottlepy #37

Open
yangzhe1990 opened this issue Aug 20, 2012 · 8 comments
Open

Incompatible with static_file in bottlepy #37

yangzhe1990 opened this issue Aug 20, 2012 · 8 comments

Comments

@yangzhe1990
Copy link

fapws3 will print the below line when I'm using static_file() in bottlepy

wsgi output of is neither a list, neither a fileobject, neither an iterable object!!!!!

Demo code can be found here: http://bottlepy.org/docs/dev/tutorial.html#routing-static-files

btw, return a static_file("index.html", root = ".").output which is a file object also fails. Even return an open("index.html") fails. Only return open("index.html").readlines() works.

p.s. Thank you for putting my name on the contributor list

@william-os4y
Copy link
Owner

So it sounds that your file object does not match the PyFile_check :-(.
https://github.com/william-os4y/fapws3/blob/master/fapws/mainloop.c#L552

Which release of Fapws are you using ?

@yangzhe1990
Copy link
Author

I'm using the newest fapws3. It's compiled with python2.7-dev and the python version I'm using is also 2.7

@william-os4y
Copy link
Owner

I'm not a bottle's expert, neither user, but what I see in the bottle code is that:

  • static_file return HTTPResponse objects,
  • HTTPResponse is neither a list, a tuple an iter nor a file object.

Thus Fapws's complaints is logic.

Concerning your initial comment ... return a file object must work.
For example return open("index.html", "rb") is working on my several Fapws's projects.

@yangzhe1990
Copy link
Author

Thank you. I'll find some time to test why returning a file object didn't work. Maybe bottle's @ did something.

An additional question to ask: Does HTTPResponse object conform to WSGI?

@defnull
Copy link

defnull commented Nov 9, 2013

Bottle unpacks HTTPResponse objects in Bottle._cast(). The result should be one of the following four options:

  1. A file object created by open(..., 'rb').
  2. A generator returned by _file_iter_range() on range requests.
  3. A string on errors.
  4. An instance of environ['wsgi.file_wrapper'] if defined.

All four should be WSGI conform.

@defnull
Copy link

defnull commented Nov 9, 2013

Actually, because fapws3 does not implement environ['wsgi.file_wrapper'], an instance of WSGIFileWrapper may be returned. That object looks like a file-object, but it is not a real one. It is still iterable and conforms to WSGI.

Perhaps that helps.

@william-os4y
Copy link
Owner

I've the feeling that both Fapws and bottle use the name "static file", but
implement it differently :-(.

If I read the Bootle code, I see that static_file return an HTTPResponse
object, where fapws expect a file object. At least recognized by PyFile_Check.

In fact, Fapws treats objects responding "true" to the following: PyList_Check,
PyTuple_Check, PyFile_Check, PyIter_Check.

Could we not get an intermediary object building the bridge between both
systems ?
Does this is your idea, when you talk about file_wrapper ?
Are you talking about a code like this ?
if 'wsgi.file_wrapper' in environ: return
environ['wsgi.file_wrapper'](filelike, block_size) else: return
iter(lambda: filelike.read(block_size), '')

(copy/past from http://www.python.org/dev/peps/pep-0333/)

On Sat, Nov 9, 2013 at 10:50 PM, Marcel Hellkamp
[email protected]:

Actually, because fapws3 does not implement environ['wsgi.file_wrapper'],
an instance of WSGIFileWrapper may be returned. That object looks like a
file-object, but it is not a real one. It is still iterable and conforms to
WSGI.


Reply to this email directly or view it on GitHubhttps://github.com//issues/37#issuecomment-28137833
.

@eivindt
Copy link

eivindt commented Oct 26, 2016

As mentioned by @defnull, bottle will cast the HTTPResponse's body in _cast(). Since fapws3 doesn't define a wsgi.file_wrapper, the cast ends up as a WSGIFileWrapper object. This is not a file object, according to PyFile_Check (which is to be expected), but it does not pass the iterator check either, which is more surprising (since that seems to be the point of the WSGIFileWrapper class).

As far as I can see, bottle's WSGIFileWrapper implements container iteration (iter() returns an iterator), whereas PyIter_Check checks for an actual iterator object.

I found 2 workarounds:

  1. Make FapwsServer set wsgi.file_wrapper to this class:
class MyWSGIFileWrapper(WSGIFileWrapper):
        def __iter__(self):
                return self

        def next(self):
                part = self.read(self.buffer_size)
                if not part:
                        raise StopIteration
                return part

(i.e. implement the necessary methods to be recognized as an iterator object)

or 2:

def WSGIFileWrapperWrapper(fp):
        return iter(WSGIFileWrapper(fp))

(i.e. use the iterator object returned by iter).

I'm not sure if any of these are that nice. Making fapws recognize and use a generator as well as an iterator would be nice, but I couldn't find out how.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants