0

I have the following flask app setup.

#!/usr/bin/env python3

import sys
import logging

from flask import Flask, jsonify
from flask_env import MetaFlaskEnv
from flask_restful import Resource, Api
from flask_restful import reqparse
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.wsgi import WSGIContainer

class Configuration(metaclass=MetaFlaskEnv):
    """
    export PORT=80
    """
    DEBUG = True
    PORT = 5000

root = logging.getLogger()
handler = logging.StreamHandler(sys.stdout)
root.addHandler(handler)

LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.DEBUG)

app = Flask(__name__)
app.config.from_object(Configuration)
api = Api(app)

peopleDict = {}

class People(Resource):
    def get(self):
        """curl http://localhost:5000/people/
        """
        return jsonify(peopleDict)

    def post(self):
        """curl http://localhost:5000/people -d "age=22&name=john" -X POST -v
        """
        parser = reqparse.RequestParser()
        parser.add_argument('name')
        parser.add_argument('age')

        args = parser.parse_args()
        peopleDict[args['name']] = {'age': args['age']}
        return jsonify({args['name']: peopleDict[args['name']]})


class Person(Resource):
    def get(self, name):
        """curl http://localhost:5000/person/john
        """
        return jsonify({name: peopleDict[name]})

    def put(self, name):
        """curl http://localhost:5000/person/john -d "age=30" -X PUT -v
        """
        parser = reqparse.RequestParser()
        parser.add_argument('age')

        args = parser.parse_args()
        peopleDict[name] = {'age': args['age']}
        return jsonify({name: peopleDict[name]})

    def delete(self, name):
        """curl http://localhost:5000/person/john -X DELETE -v
        """
        person = peopleDict[name]
        del peopleDict[name]
        return jsonify({name: person, 'deleted':'true'})


api.add_resource(People, '/people')
api.add_resource(Person, '/person/<string:name>')


@app.route('/')
def hello_world():
    return 'Hello, World!'

if __name__ == '__main__':
    LOGGER.debug("server starting on port :" + str(app.config["PORT"]))
    HTTP_SERVER = HTTPServer(WSGIContainer(app))
    HTTP_SERVER.listen(port=app.config["PORT"])
    IOLoop.instance().start()

I also have the test case written like this:

import json
import unittest
from ddt import ddt, data, unpack
from app import app

@ddt
class ApiTestCase(unittest.TestCase):

    def setUp(self):
        self.client = app.test_client()

    def testPostPeople(self):
        result = self.client.post('/people', data={'name':'john', 'age':22})
        print (result.data)
        values = json.loads(result.data)

and I'm getting the follwoing error when I run the test cases

b'{\n  "john": {\n    "age": "22"\n  }\n}\n'
E
======================================================================
ERROR: testPostPeople (tests.test_api.ApiTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ubuntu/transfer/tests/test_api.py", line 15, in testPostPeople
    values = json.loads(result.data)
  File "/usr/lib/python3.5/json/__init__.py", line 312, in loads
    s.__class__.__name__))
TypeError: the JSON object must be str, not 'bytes'

----------------------------------------------------------------------
Ran 1 test in 0.015s

I do NOT understand why I'm getting the json string in bytes, it should be in str. I can call decode() on result.data, but I really want to fix this probme in the app, not in the test cases.

user1187968
  • 7,154
  • 16
  • 81
  • 152
  • why do you think it "should" be in str? do you have any reference? if you look at Tornado docs, you must see that the response body is in bytes. – 3k- May 08 '17 at 19:18
  • Ok, I see, Tornado is returning in byte string, if there a way to convert it back to str? Or byte string is the HTTP standard? – user1187968 May 08 '17 at 19:42
  • yes, please see my answer – 3k- May 08 '17 at 19:48
  • 1
    The data transport between server and client is in byte stream. So the test client return `bytes` to you. The best practice is decode bytes to on input, process, encode text on output. The `requests` also provide `text` to provide `unicode(str)` and `content` to provide `str(bytes)`. – stamaimer May 09 '17 at 02:37

0 Answers0