Django

Code

Ticket #11371 (closed: fixed)

Opened 9 months ago

Last modified 5 months ago

Unable to put non-MULTIPART_CONTENT data in method django.test.Client.put()

Reported by: vorushin Assigned to: phyfus
Milestone: Component: Testing framework
Version: SVN Keywords:
Cc: sanfordarmstrong@gmail.com, johann@phyfus.com Triage Stage: Ready for checkin
Has patch: 1 Needs documentation: 0
Needs tests: 0 Patch needs improvement: 0

Description

I started to write tests for my RESTful web service, written in Django. I use django.test.Client for making HTTP requests. GET and POST methods works all right, but I didn't find any options to send non-MULTIPART_CONTENT data in PUT request.

My code is:

from django.test import TestCase 
from django.utils.http import urlencode 
class UsersTest(TestCase): 
        def test_registration_and_management(self): 
                response = self.client.put('/users/1234567/', 
                    urlencode({'password': '', 'wrong_attempts': 100}, doseq=True), 
                    content_type='application/x-www-form-urlencoded') 
                self.failUnlessEqual(response.status_code, 200) 
                self.assertContains(response, 'raw_password') 

When I launch tests (via python manage.py test), I receive error:

  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/ 
python2.6/site-packages/django/test/client.py", line 370, in put 
    'QUERY_STRING':   urlencode(data, doseq=True) or parsed[4], 
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/ 
python2.6/site-packages/django/utils/http.py", line 42, in urlencode 
    for k, v in query], 
ValueError: need more than 1 value to unpack 

Problems seems to be in Client.put method, file django.test.client.py:

    def put(self, path, data={}, content_type=MULTIPART_CONTENT, 
            follow=False, **extra): 
        """ 
        Send a resource to the server using PUT. 
        """ 
        if content_type is MULTIPART_CONTENT: 
            post_data = encode_multipart(BOUNDARY, data) 
        else: 
            post_data = data 
        parsed = urlparse(path) 
        r = { 
            'CONTENT_LENGTH': len(post_data), 
            'CONTENT_TYPE':   content_type, 
            'PATH_INFO':      urllib.unquote(parsed[2]), 
            'QUERY_STRING':   urlencode(data, doseq=True) or parsed[4], 
            'REQUEST_METHOD': 'PUT', 
            'wsgi.input':     FakePayload(post_data), 
        } 
        r.update(extra) 
        response = self.request(**r) 
        if follow: 
            response = self._handle_redirects(response) 
        return response 

If I change line

'QUERY_STRING':   urlencode(data, doseq=True) or parsed[4], 

to

'QUERY_STRING':  parsed[4], 

everythings works all right in my case. Client.post() method uses the same technology (no urlencode, only parsed[4]).

Attachments

tests.diff (1.4 kB) - added by phyfus on 10/19/09 18:01:10.
Tests to prove their is a bug.
patch.diff (2.2 kB) - added by phyfus on 10/19/09 18:44:59.
A patch with both the tests and the fix.

Change History

07/23/09 07:14:18 changed by sanfordarmstrong@gmail.com

  • cc set to sanfordarmstrong@gmail.com.
  • needs_better_patch changed.
  • needs_tests changed.
  • needs_docs changed.

I have the same issue. In my case, I'm PUTing JSON like this:

client.put(abs_uri, data=json_str, content_type='application/json')

For now, I am "fixing" client.put at runtime like so:

self.client.put = curry(self.client.post, REQUEST_METHOD='PUT')

I'm using SVN r11290 (basically, 1.1 RC1).

08/04/09 08:31:58 changed by anonymous

The same issue here,

In [57]: d = dumps({'bug':'confirmed'})

In [58]: response = client.put(path = '/account/1.0/instance', data = d, content_type='application/json', follow=True)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)

/home/bluszcz/projects/branches/www.moovida.org/<ipython console> in <module>()

/usr/local/lib/python2.6/dist-packages/django/test/client.pyc in put(self, path, data, content_type, follow, **extra)
    368             'CONTENT_TYPE':   content_type,
    369             'PATH_INFO':      urllib.unquote(parsed[2]),
--> 370             'QUERY_STRING':   urlencode(data, doseq=True) or parsed[4],
    371             'REQUEST_METHOD': 'PUT',
    372             'wsgi.input':     FakePayload(post_data),

/usr/local/lib/python2.6/dist-packages/django/utils/http.pyc in urlencode(query, doseq)
     40         [(smart_str(k),
     41          isinstance(v, (list,tuple)) and [smart_str(i) for i in v] or smart_str(v))
---> 42             for k, v in query],
     43         doseq)
     44 

ValueError: need more than 1 value to unpack

In [59]: 

08/26/09 10:30:10 changed by kmtracey

#11786 was a dup.

08/26/09 10:33:53 changed by anonymous

Yep, my dupe ticket (#11786) is the same issue.

10/19/09 12:42:14 changed by phyfus

  • owner changed from nobody to phyfus.

10/19/09 18:01:10 changed by phyfus

  • attachment tests.diff added.

Tests to prove their is a bug.

10/19/09 18:19:20 changed by phyfus

  • has_patch set to 1.
  • stage changed from Unreviewed to Accepted.

I have added a patch which fixes the problem.

I ran it against the entire Djando test suite and all tests passed.

10/19/09 18:19:52 changed by phyfus

  • cc changed from sanfordarmstrong@gmail.com to sanfordarmstrong@gmail.com, johann@phyfus.com.

10/19/09 18:33:12 changed by phyfus

Updated the patch based on Alex Gaynor's suggestion.

Changed query_string = to query_string = None

10/19/09 18:44:59 changed by phyfus

  • attachment patch.diff added.

A patch with both the tests and the fix.

10/19/09 18:49:31 changed by Alex

  • stage changed from Accepted to Ready for checkin.

10/26/09 10:04:35 changed by jacob

  • status changed from new to closed.
  • resolution set to fixed.

(In [11657]) [1.1.X] Fixed #11371: Made django.test.Client.put() work for non-form-data PUT (i.e. JSON, etc.). Thanks, phyfus. Backport of [11656] from trunk.


Add/Change #11371 (Unable to put non-MULTIPART_CONTENT data in method django.test.Client.put())




Change Properties
Action