-
-
Notifications
You must be signed in to change notification settings - Fork 149
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
Inversion of control for a streaming upload provider #48
Comments
I see the point. I will look into it over the next days (don't hesitate to ping me if I don't ;-) |
BTW: |
The problem is that HTTP libraries (e.g. requests) require an object that implements |
I've got an idea for solving this and some related requirements we have. For each HTTP method dealt with in class RequestServer(object):
# ...
def doPUT(self, environ, start_response):
# ...
res = provider.getResourceInst(path, environ)
try:
return res.overridePUT(environ, start_response)
except NotImplemented:
pass
# continue as usual This allows completely short circuiting the default functionality when required. We'd add This would allow:
|
I was thinking about a similar approach def doPUT(self, environ, start_response):
res = provider.getResourceInst(path, environ)
return res.handlePUT(environ, start_response) with the default implementation in Having this for all other HTTP commands as well is a good idea, I didn't think of those use cases. For Samuel's use case however (which might be quite common) I would like to try to find a more elegant solution, than implementing a slightly modified copy to the 150 lines of code of I wonder if it would be possible to implement have a buffer, and pass a BufferedWriter() to the PUT handler with |
Looking at the code for the chunked transfer as well as the non-chunked upload, it seems we could pull these out into a generator that accepts the environ and yields either one chunk at a time, or one The default handlePUT could then loop over this and call If the request is not chunked, we'd still prefer to pass |
Thanks @samuelfekete, #51 looks good to me, I think we can merge soon. |
@mar10, I have made another change to use generators, and I have isolated the code that writes to the file object in the small method |
I merged #51 , thank you all. I also added a branch that explores another approach: def beginWrite(self, contentType=None):
queue = FileLikeQueue(maxsize=1)
requests.post(..., data=queue)
return queue It also includes some tests and adds Would this work in your use case as well? |
Thank you. Having quickly glanced at your branch I can tell you that callers (at least Boto3) assume the end of file was reached if The way I'm using it now, class StreamingFile(object):
"""A file object wrapped around an iterator / data stream."""
def __init__(self, data_stream):
"""Intialise the object with the data stream."""
self.data_stream = data_stream
self.buffer = ''
def read(self, size=None):
"""Read bytes from an iterator."""
while size is None or len(self.buffer) < size:
try:
self.buffer += self.data_stream.next()
except StopIteration:
break
sized_chunk = self.buffer[:size]
if size is None:
self.buffer = ''
else:
self.buffer = self.buffer[size:]
return sized_chunk |
@mar10, I think a queued file object would work as well for our use case. Though, what would be the advantage of that over simply reading from the iterators? |
Your I played with |
* Add FileLikeQueue class and tests * Move FileLikeQueue to filielike_queue module * Rename filelike_queue to stream_tools Update #48
Thanks @mar10. I'm fine with adding them to |
@samuelfekete could add some lines to the docstring of |
I need a way to proxy streaming uploads, that is to forward bytes from the client as soon as they are received, without temp files. To do that, I need to have a file-like object given to the provider for reading - as opposed to the provider giving the request server a file-like object for writing.
I am thinking something along the lines of checking for a flag in
doPUT
, and if the provider prefers, just give it the reference toenviron["wsgi.input"]
for reading.Any thoughts?
@mar10 @tomviner
The text was updated successfully, but these errors were encountered: