toastdriven / restless

A lightweight REST miniframework for Python.
http://restless.readthedocs.org/en/latest/
BSD 3-Clause "New" or "Revised" License
832 stars 107 forks source link

str vs bytes #14

Closed SevereOverfl0w closed 10 years ago

SevereOverfl0w commented 10 years ago

Just been playing with this using Pyramid, and mildly following the tutorial.

I am hitting an issue with an error:

the JSON object must be str, not 'bytes'

I believe this is a python 2 vs 3.4 issue. But I am not sure if it's an error I am making, or something within the framework!

This occurs when trying to post with CURL to create a new minion. It occurs before it even hits my function ( I believe! )

curl -X POST -H "Content-Type: application/json" -d '{"title": "New library released!", "author": "daniel", "body": "I just released a new thing!"}' http://127.0.0.1:6543/minions/

Traceback:

{"traceback": "Traceback (most recent call last):
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/waitress/task.py", line 74, in handler_thread
    task.service()
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/waitress/channel.py", line 337, in service
    task.service()
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/waitress/task.py", line 173, in service
    self.execute()
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/waitress/task.py", line 392, in execute
    app_iter = self.channel.server.application(env, start_response)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/pyramid/router.py", line 242, in __call__
    response = self.invoke_subrequest(request, use_tweens=True)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/pyramid/router.py", line 217, in invoke_subrequest
    response = handle_request(request)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/pyramid_debugtoolbar/toolbar.py", line 177, in toolbar_tween
    response = _handler(request)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/pyramid_debugtoolbar/panels/performance.py", line 57, in resource_timer_handler
    result = handler(request)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/pyramid/tweens.py", line 21, in excview_tween
    response = handler(request)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/pyramid_tm/__init__.py", line 63, in tm_tween
    response = handler(request)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/pyramid/router.py", line 163, in handle_request
    response = view_callable(context, request)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/pyramid/config/views.py", line 329, in attr_view
    return view(context, request)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/pyramid/config/views.py", line 305, in predicate_wrapper
    return view(context, request)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/pyramid/config/views.py", line 385, in viewresult_to_response
    result = view(context, request)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/pyramid/config/views.py", line 501, in _requestonly_view
    response = view(request)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/restless/resources.py", line 139, in _wrapper
    return inst.handle(view_type, *args, **kwargs)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/restless/resources.py", line 294, in handle
    return self.handle_error(err)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/restless/resources.py", line 313, in handle_error
    return self.build_error(err)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/restless/resources.py", line 289, in handle
    self.data = self.deserialize(method, endpoint, self.request_body())
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/restless/resources.py", line 335, in deserialize
    return self.deserialize_list(body)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/restless/resources.py", line 349, in deserialize_list
    return self.serializer.deserialize(body)
  File "/home/overfl0w/c0d3/experiments/minion-database/env/lib/python3.4/site-packages/restless/serializers.py", line 62, in deserialize
    return json.loads(body)
  File "/usr/lib64/python3.4/json/__init__.py", line 312, in loads
    s.__class__.__name__))
TypeError: the JSON object must be str, not 'bytes'", "error": "the JSON object must be str, not 'bytes'"}
toxinu commented 10 years ago

Same error on a PUT request.

toxinu commented 10 years ago

In order to reproduce bug with existing test you have to patch FakeHTTPResponse object.

import six
class FakeHttpResponse(object):
    def __init__(self, body, content_type='text/html'):
        self.body = body
        if six.PY3:
            self.body = body.encode('utf-8')
        self.content_type = content_type
        self.status_code = 200

I think most web framework consider string representation as utf-8, so bytes in Python 3 (like Django, and Pyramid @SevereOverfl0w ). Can we update tests and quickly think about a solution ?

For me, this bug is very important cause it make restless unusable with Django in Python3 and I think it's the same thing for Pyramid below.

By the way, thank you for your great work @toastdriven , I just leave django-restframework to restless give a a very nice breath of air :smile:

I can make a pull request if you want but I'm not totally of how to fix it. But the nice coverage will be a good point.

sigmavirus24 commented 10 years ago

For what it's worth, @toastdriven other people are now encountering this. I've made a cursory pass at @socketubs' pull request (#17) and it looks acceptable. It's simple and @socketubs may still be willing to revisit it if you would offer feedback.

toastdriven commented 10 years ago

Fixed in SHA: 5376ac2