python: публиковать данные в stringIO через плакат?

params = {'file': open("test.txt", "rb"), 'name': 'upload test'}
datagen, headers = poster.encode.multipart_encode(params)
request = urllib2.Request(upload_url, datagen, headers)
result = urllib2.urlopen(request)

Я использую библиотеку плакатов для POST для HTTP. Это работает хорошо. Я доволен этим.

Но я хочу попробовать кое-что. Как вы видите выше, чтобы отправить данные файла, мне нужно ОТКРЫТЬ файл. Но есть ли способ не сделать для этого настоящий файл? Мы можем использовать STREAM, например StringIO, для работы с данными, как с файлами, верно? Но, я не знаю о poster глубоко. Итак, я хочу знать, как использовать STREAM с poster.

ДОБАВЛЕН

На самом деле, я пытался отправить данные изображения POST. Я написал это ниже

from PyQt4 import QtCore, QtGui
from poster.encode import multipart_encode
from poster.streaminghttp import register_openers
import urllib2, os

register_openers()
app = QtGui.QApplication(sys.argv)
pixmap = QtGui.QPixmap("c:/test_img.png")
byte_array = QtCore.QByteArray()
buffer = QtCore.QBuffer(byte_array)
buffer.open(QtCore.QIODevice.WriteOnly)
pixmap.save(buffer, "PNG")
from cStringIO import StringIO
datagen, headers = multipart_encode({"image": StringIO(str(byte_array.toBase64()))})
request = urllib2.Request(upload_url, datagen, headers)
_rnt = urllib2.urlopen(request)

Но я получаю эту ошибку:

Traceback (most recent call last):
  File "<pyshell#25>", line 1, in <module>
    _rnt = urllib2.urlopen(request)
  File "C:\Python26\lib\urllib2.py", line 126, in urlopen
    return _opener.open(url, data, timeout)
  File "C:\Python26\lib\urllib2.py", line 397, in open
    response = meth(req, response)
  File "C:\Python26\lib\urllib2.py", line 510, in http_response
    'http', request, response, code, msg, hdrs)
  File "C:\Python26\lib\urllib2.py", line 435, in error
    return self._call_chain(*args)
  File "C:\Python26\lib\urllib2.py", line 369, in _call_chain
    result = func(*args)
  File "C:\Python26\lib\urllib2.py", line 518, in http_error_default
    raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
HTTPError: HTTP Error 500: Internal Server Error

person Hyun-geun Kim    schedule 13.11.2012    source источник
comment
Это не относится к вашей проблеме, но вы понимаете, что ваш код никогда не закрывает text.txt, верно? В CPython он вероятно закроется автоматически, как только params и datagen исчезнут, но никаких гарантий; в других реализациях еще хуже.   -  person abarnert    schedule 13.11.2012
comment
Опять же, возможно, это не связано с вашей новой проблемой, но: я не думаю, что вам нужно использовать base64 для данных, поскольку они уже будут правильно закодированы в теле MIME - вам нужно будет выполнить дополнительное декодирование base64 на Обратная сторона. Кроме того, почему вы создаете растровое изображение из файла PNG, а затем сохраняете его в буфер как PNG, а не просто читаете файл PNG (или просто передаете его в poster)?   -  person abarnert    schedule 13.11.2012
comment
Вы получаете сообщение об ошибке HTTP 500: Internal Server Error. Это означает ошибку в веб-сервере или, что более вероятно, во внутреннем скрипте, который он запускает для вашего URL. Если этот URL-адрес обычно надежен, это может означать, что вы отправили мусор настолько далеко за пределы того, что кто-либо ожидал, что вы обнаружили ошибку, которую никто никогда не тестировал. Попробуйте сохранить буфер, чтобы убедиться, что это действительно PNG, сохраните вывод datagen и headers, чтобы убедиться, что они разумны, и выполните более простой тест без всего Qt, где вы просто отправляете StringIO с данными, которые хотите закончить с.   -  person abarnert    schedule 13.11.2012
comment
Является ли upload_url общедоступной службой? Или, если нет, у вас есть исходный код и вы можете его где-нибудь опубликовать (вместе с инструкциями по установке)? Это позволит другим людям помочь вам проверить, что происходит не так.   -  person abarnert    schedule 13.11.2012
comment
@abarnert Конечно, я могу сохранить в файл PNG и отправить его на постер. Но, я надеюсь сократить время обработки, поэтому пробовал так. :) А, upload_url проверю, но это не моя обязанность, так что как-нибудь возьмется.   -  person Hyun-geun Kim    schedule 14.11.2012
comment
Что ж, если один из ваших коллег отвечает за веб-службу, в которую вы пытаетесь выполнить загрузку, отправьте сообщение об ошибке в его работе — сервису всегда неправильно возвращать 500 только потому, что он получил неверные данные. Что касается сокращения времени обработки — очевидно, что чтение PNG, преобразование его в QPixmap, рендеринг этого QPixmap в буфер, затем кодирование и отправка этого буфера занимает больше времени, чем простое кодирование и отправка файла PNG напрямую.   -  person abarnert    schedule 14.11.2012


Ответы (1)


Параметр file — это место, где вы передаете файловый объект. Итак, что произойдет, если вместо этого вы передадите файлоподобный объект?

>>> params = {'file': cStringIO.StringIO('upload test data'), 'name': 'upload test'}
>>> datagen, headers = poster.encode.multipart_encode(params)
>>> headers
{'Content-Length': '317', 'Content-Type': 'multipart/form-data; boundary=0c56082b1e134424a918b2b083391467'}

Похоже, это сработало.

Что говорится в документации?

Значения представляют собой либо строковые значения параметров, либо файловые объекты, используемые в качестве значения параметра. Файлоподобные объекты должны поддерживать .read() и либо .fileno(), либо и .seek(), и .tell().

Итак, вы можете использовать объекты StringIO, потому что они поддерживают seek() и tell().

Но вам не нужно. Вы должны иметь возможность просто использовать необработанную строку. Давайте попробуем и посмотрим:

>>> params = {'file': 'upload test data', 'name': 'upload test'}
>>> datagen, headers = poster.encode.multipart_encode(params)
>>> headers
{'Content-Length': '317', 'Content-Type': 'multipart/form-data; boundary=0c56082b1e134424a918b2b083391467'}

Посмотрите на это, документация верна.

person abarnert    schedule 13.11.2012
comment
@pydsigner: Ну, библиотека описана как неполная и одна версия не имеет стабильного API, а в документации есть предупреждение о том, что она может не соответствовать текущей версии… - person abarnert; 13.11.2012