2012-12-05 3 views
2

Я пишу тесты для POST-глагола API RESTful, который отправляет на сервер многоформатные данные формы. Я хотел бы json-encode данных. Каким будет правильный способ сделать это? Ниже приведены 3 теста, из которых первый 2-й проход и третий (сценарий, который мне нужен) терпят неудачу. Любая помощь будет оценена по достоинству.запросы python

import requests 
import json 

print "test 1, files+data/nojson" 
requests.post('http://localhost:8080', files={'spot[photo]': open('test.jpg', 'rb')}, data={'spot': 'spot_description'}) 

print "test 2, only data/json" 
requests.post('http://localhost:8080',data=json.dumps({'spot': 'spot_description'})) 

print "test 3, only files+data/json" 
requests.post('http://localhost:8080', files={'spot[photo]': open('test.jpg', 
'rb')}, data=json.dumps({'spot': 'spot_description'})) 

Кодовые выходы:

$ /cygdrive/c/Python27/python.exe -B test.py 
test 1, files+data/nojson 
test 2, only data/json 
test 3, only files+data/json 
Traceback (most recent call last): 
    File "test.py", line 12, in <module> 
    'rb')}, data=json.dumps({'spot': 'spot_description'})) 
    File "C:\Python27\lib\site-packages\requests\api.py", line 98, in post 
    return request('post', url, data=data, **kwargs) 
    File "C:\Python27\lib\site-packages\requests\safe_mode.py", line 39, in wrapped 
    return function(method, url, **kwargs) 
    File "C:\Python27\lib\site-packages\requests\api.py", line 51, in request 
    return session.request(method=method, url=url, **kwargs) 
    File "C:\Python27\lib\site-packages\requests\sessions.py", line 241, in request 
    r.send(prefetch=prefetch) 
    File "C:\Python27\lib\site-packages\requests\models.py", line 532, in send 
    (body, content_type) = self._encode_files(self.files) 
    File "C:\Python27\lib\site-packages\requests\models.py", line 358, in _encode_files 
    fields = to_key_val_list(self.data) 
    File "C:\Python27\lib\site-packages\requests\utils.py", line 157, in to_key_val_list 
    raise ValueError('cannot encode objects that are not 2-tuples') 
ValueError: cannot encode objects that are not 2-tuples 
+0

Мое предварительное предположение (нет времени для тестирования) заключается в том, что вы просто передаете контейнер IO файла, когда вы передаете его 'open ('test.jpg', 'rb')'. Вы должны передать ему фактический поток, 'open ('test.jpg', 'rb'). Read()'. – jdotjdot

+0

Я проверю это завтра. Это не звучит корректно, так как передача файлов и простой словарь данных действительно работают –

ответ

2

Ошибка в том, что ваш параметр data является строкой.

models.py::send() в:

# Multi-part file uploads. 
    if self.files: 
     (body, content_type) = self._encode_files(self.files) 

в models.py::_encode_files():

fields = to_key_val_list(self.data) 
    files = to_key_val_list(files) 

В utils.py::to_key_val_list():

if isinstance(value, (str, bytes, bool, int)): 
    raise ValueError('cannot encode objects that are not 2-tuples') 

Это получить удар по вызову с self.data. Вы переходящий в строковом представлении словаря, но это ожидает словарь себя, например, так:

requests.post('http://localhost:8080', 
       files={'spot[photo]': open('test.jpg', 'rb')}, 
       data={'spot': 'spot_description'}) 

Так что, если что-либо назначен файлы пары, то пары данных не может быть типом ул, байты, bool или int. Вы можете следовать в исходном коде: https://github.com/kennethreitz/requests/blob/master/requests/models.py#L531

+0

Это звучит очень разумно, но оставляет пару вопросов: 1. Почему, если я оставляю «файлы», то работает 2, что мне делать? способный обработать тело запроса –

+0

Я отредактировал свой ответ, чтобы объяснить ответ на ваш первый вопрос. Что касается второго вопроса, я не уверен, возможно ли это в модуле Requests. –

+0

Большое спасибо за усилия. Проголосовал за ваш ответ, не принял его, хотя, так как я все еще надеюсь получить лучший ответ на главный вопрос, который у меня есть. –

1

POST ИНГ данных в формате JSON можно обойти путем включения его в поле формы закодированного следующим образом:

post(url, data={'data': json.dumps(actual_data)}, files={'myfile': open('foo.data')}) 

также, я думаю, вы можете просто положить все в files, как это:

post(url, files={'data': json.dumps(actual_data), 'myfile': open('foo.dat')}) 

... который должен быть эквивалентен первому сниппета.

Смежные вопросы