[Python] Fix Python UTF-8 Encoding Issue (#5679)

* Try decoding but don't bail on error

* Switch binary and ByteArray to bytes

* Read content type and parse appropriately

* Remove response parsing

* Remove response parsing and just return the data

* Update petshop examples w/ new generator code

* Fix copy/paste error with naming

* Update petstore examples

* Move response decoding to inside _preload_content block

* Update the clients again

* Use a raw string for the regex pattern

* Regenerate petstore clients

* Add bytes to python primitives as it's supported in 2.7 and 3

* Add bytes to the exports from model_utils

* Import bytes from model_utils

* Add conditional typing for regex pattern to match variable type

* Regenerate petstore clients

* Use read() instead of text() for asyncio

* Regenerate petstore clients

* Remove unused six import

* Regenerate petstore clients

* Add newline to kick Circle to re-run

* Remove whitespace from tox.ini

* Update more examples after ensure_updated

* Add sample updates that didn't run with the --batch flag

* Remove extra bracket in regex to remove warning

* Stop printing debug messages

* Add bytes examples to python doc generators

* Update generated FakeApi docs

* Regenerate api_client.py

* Remove print statements from generated clients

* Update bytes example in FakeApi.md. Again. I swear.

* Add yet another seemingly missing doc update

* Catch the error, decode the body, and re-throw

* Remove the updates now that the change is non-breaking

* Regenerate client

* Add bytes deserialization test

* Update exception parsing

* Add exception parsing for python-experimental

* Regenerate client with minor changes

* Revert test changes

* Regenerate model_utils.py

* Update confusing test name

* Remove bytes from mapping and examples

* Add back in the old binary/ByteArray to str mapping

* Update docs and api_client template

* Add experimental api_client changes

* Regenerate samples again

* Add Tornado handling to early return

* Try fixing Tornado python returns

* More documentation changes

* Re-generate the client code

* Remove bytes from test_format_test

* Remove more leftover bytes usages

* Switch bytes validation back to string

* Fix format_test template and regenerate

* Remove unused bytes var

* Remove bytes import from models and regenerate

* Remove bytes import from test_deserialization

* Reduce nested ifs

* Remove byte logic for now

* Regenerate client after latest changes

* Remove another bytes usage

* Regenerate after removing dangling byte string usage

* Reduce the scope of the try/catch in api_client

* Regenerate after try/catch cleanup

* Swap catch for except

* Regenerate Python client after api_client change

* Fix lint error on the generated api_client

* Add binary format test back in w/ string

* Add decoding to python-experimental and regenerate

* Import re into python-experimental api_client

* Ensure file upload json response is utf-8 encoded bytes
This commit is contained in:
Justin Niessner 2020-04-26 16:33:42 -04:00 committed by GitHub
parent cef5470ea8
commit db5941379f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 319 additions and 175 deletions

View File

@ -31,6 +31,7 @@ sidebar_label: python-experimental
<ul class="column-ul"> <ul class="column-ul">
<li>bool</li> <li>bool</li>
<li>bytes</li>
<li>date</li> <li>date</li>
<li>datetime</li> <li>datetime</li>
<li>dict</li> <li>dict</li>

View File

@ -31,6 +31,7 @@ sidebar_label: python
<ul class="column-ul"> <ul class="column-ul">
<li>bool</li> <li>bool</li>
<li>bytes</li>
<li>date</li> <li>date</li>
<li>datetime</li> <li>datetime</li>
<li>dict</li> <li>dict</li>

View File

@ -119,6 +119,7 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
languageSpecificPrimitives.add("object"); languageSpecificPrimitives.add("object");
// TODO file and binary is mapped as `file` // TODO file and binary is mapped as `file`
languageSpecificPrimitives.add("file"); languageSpecificPrimitives.add("file");
languageSpecificPrimitives.add("bytes");
typeMapping.clear(); typeMapping.clear();
typeMapping.put("integer", "int"); typeMapping.put("integer", "int");

View File

@ -22,7 +22,7 @@ import tornado.gen
from {{packageName}}.configuration import Configuration from {{packageName}}.configuration import Configuration
import {{modelPackage}} import {{modelPackage}}
from {{packageName}} import rest from {{packageName}} import rest
from {{packageName}}.exceptions import ApiValueError from {{packageName}}.exceptions import ApiValueError, ApiException
class ApiClient(object): class ApiClient(object):
@ -186,17 +186,38 @@ class ApiClient(object):
# use server/host defined in path or operation instead # use server/host defined in path or operation instead
url = _host + resource_path url = _host + resource_path
try:
# perform request and return response # perform request and return response
response_data = {{#asyncio}}await {{/asyncio}}{{#tornado}}yield {{/tornado}}self.request( response_data = {{#asyncio}}await {{/asyncio}}{{#tornado}}yield {{/tornado}}self.request(
method, url, query_params=query_params, headers=header_params, method, url, query_params=query_params, headers=header_params,
post_params=post_params, body=body, post_params=post_params, body=body,
_preload_content=_preload_content, _preload_content=_preload_content,
_request_timeout=_request_timeout) _request_timeout=_request_timeout)
except ApiException as e:
e.body = e.body.decode('utf-8') if six.PY3 else e.body
raise e
content_type = response_data.getheader('content-type')
self.last_response = response_data self.last_response = response_data
return_data = response_data return_data = response_data
if _preload_content:
if not _preload_content:
{{^tornado}}
return return_data
{{/tornado}}
{{#tornado}}
raise tornado.gen.Return(return_data)
{{/tornado}}
if six.PY3 and response_type not in ["file", "bytes"]:
match = None
if content_type is not None:
match = re.search(r"charset=([a-zA-Z\-\d]+)[\s\;]?", content_type)
encoding = match.group(1) if match else "utf-8"
response_data.data = response_data.data.decode(encoding)
# deserialize response data # deserialize response data
if response_type: if response_type:
return_data = self.deserialize(response_data, response_type) return_data = self.deserialize(response_data, response_type)

View File

@ -166,7 +166,7 @@ class RESTClientObject(object):
r = await self.pool_manager.request(**args) r = await self.pool_manager.request(**args)
if _preload_content: if _preload_content:
data = await r.text() data = await r.read()
r = RESTResponse(r, data) r = RESTResponse(r, data)
# log response body # log response body

View File

@ -7,6 +7,7 @@ import atexit
import mimetypes import mimetypes
from multiprocessing.pool import ThreadPool from multiprocessing.pool import ThreadPool
import os import os
import re
# python 2 and python 3 compatibility library # python 2 and python 3 compatibility library
import six import six
@ -17,7 +18,7 @@ import tornado.gen
from {{packageName}} import rest from {{packageName}} import rest
from {{packageName}}.configuration import Configuration from {{packageName}}.configuration import Configuration
from {{packageName}}.exceptions import ApiValueError from {{packageName}}.exceptions import ApiValueError, ApiException
from {{packageName}}.model_utils import ( from {{packageName}}.model_utils import (
ModelNormal, ModelNormal,
ModelSimple, ModelSimple,
@ -176,17 +177,39 @@ class ApiClient(object):
# use server/host defined in path or operation instead # use server/host defined in path or operation instead
url = _host + resource_path url = _host + resource_path
try:
# perform request and return response # perform request and return response
response_data = {{#asyncio}}await {{/asyncio}}{{#tornado}}yield {{/tornado}}self.request( response_data = {{#asyncio}}await {{/asyncio}}{{#tornado}}yield {{/tornado}}self.request(
method, url, query_params=query_params, headers=header_params, method, url, query_params=query_params, headers=header_params,
post_params=post_params, body=body, post_params=post_params, body=body,
_preload_content=_preload_content, _preload_content=_preload_content,
_request_timeout=_request_timeout) _request_timeout=_request_timeout)
except ApiException as e:
e.body = e.body.decode('utf-8') if six.PY3 else e.body
raise e
content_type = response_data.getheader('content-type')
self.last_response = response_data self.last_response = response_data
return_data = response_data return_data = response_data
if _preload_content:
if not _preload_content:
{{^tornado}}
return (return_data)
{{/tornado}}
{{#tornado}}
raise tornado.gen.Return(return_data)
{{/tornado}}
return return_data
if six.PY3 and response_type not in ["file", "bytes"]:
match = None
if content_type is not None:
match = re.search(r"charset=([a-zA-Z\-\d]+)[\s\;]?", content_type)
encoding = match.group(1) if match else "utf-8"
response_data.data = response_data.data.decode(encoding)
# deserialize response data # deserialize response data
if response_type: if response_type:
return_data = self.deserialize( return_data = self.deserialize(

View File

@ -209,11 +209,6 @@ class RESTClientObject(object):
if _preload_content: if _preload_content:
r = RESTResponse(r) r = RESTResponse(r)
# In the python 3, the response.data is bytes.
# we need to decode it to string.
if six.PY3:
r.data = r.data.decode('utf8')
# log response body # log response body
logger.debug("response body: %s", r.data) logger.debug("response body: %s", r.data)

View File

@ -8,7 +8,6 @@ import logging
import re import re
# python 2 and python 3 compatibility library # python 2 and python 3 compatibility library
import six
from six.moves.urllib.parse import urlencode from six.moves.urllib.parse import urlencode
import tornado import tornado
import tornado.gen import tornado.gen
@ -28,10 +27,6 @@ class RESTResponse(io.IOBase):
self.reason = resp.reason self.reason = resp.reason
if resp.body: if resp.body:
# In Python 3, the response body is utf-8 encoded bytes.
if six.PY3:
self.data = resp.body.decode('utf-8')
else:
self.data = resp.body self.data = resp.body
else: else:
self.data = None self.data = None

View File

@ -27,7 +27,7 @@ from six.moves.urllib.parse import quote
from petstore_api.configuration import Configuration from petstore_api.configuration import Configuration
import petstore_api.models import petstore_api.models
from petstore_api import rest from petstore_api import rest
from petstore_api.exceptions import ApiValueError from petstore_api.exceptions import ApiValueError, ApiException
class ApiClient(object): class ApiClient(object):
@ -177,17 +177,33 @@ class ApiClient(object):
# use server/host defined in path or operation instead # use server/host defined in path or operation instead
url = _host + resource_path url = _host + resource_path
try:
# perform request and return response # perform request and return response
response_data = await self.request( response_data = await self.request(
method, url, query_params=query_params, headers=header_params, method, url, query_params=query_params, headers=header_params,
post_params=post_params, body=body, post_params=post_params, body=body,
_preload_content=_preload_content, _preload_content=_preload_content,
_request_timeout=_request_timeout) _request_timeout=_request_timeout)
except ApiException as e:
e.body = e.body.decode('utf-8') if six.PY3 else e.body
raise e
content_type = response_data.getheader('content-type')
self.last_response = response_data self.last_response = response_data
return_data = response_data return_data = response_data
if _preload_content:
if not _preload_content:
return return_data
if six.PY3 and response_type not in ["file", "bytes"]:
match = None
if content_type is not None:
match = re.search(r"charset=([a-zA-Z\-\d]+)[\s\;]?", content_type)
encoding = match.group(1) if match else "utf-8"
response_data.data = response_data.data.decode(encoding)
# deserialize response data # deserialize response data
if response_type: if response_type:
return_data = self.deserialize(response_data, response_type) return_data = self.deserialize(response_data, response_type)

View File

@ -174,7 +174,7 @@ class RESTClientObject(object):
r = await self.pool_manager.request(**args) r = await self.pool_manager.request(**args)
if _preload_content: if _preload_content:
data = await r.text() data = await r.read()
r = RESTResponse(r, data) r = RESTResponse(r, data)
# log response body # log response body

View File

@ -15,6 +15,7 @@ import atexit
import mimetypes import mimetypes
from multiprocessing.pool import ThreadPool from multiprocessing.pool import ThreadPool
import os import os
import re
# python 2 and python 3 compatibility library # python 2 and python 3 compatibility library
import six import six
@ -22,7 +23,7 @@ from six.moves.urllib.parse import quote
from petstore_api import rest from petstore_api import rest
from petstore_api.configuration import Configuration from petstore_api.configuration import Configuration
from petstore_api.exceptions import ApiValueError from petstore_api.exceptions import ApiValueError, ApiException
from petstore_api.model_utils import ( from petstore_api.model_utils import (
ModelNormal, ModelNormal,
ModelSimple, ModelSimple,
@ -178,17 +179,34 @@ class ApiClient(object):
# use server/host defined in path or operation instead # use server/host defined in path or operation instead
url = _host + resource_path url = _host + resource_path
try:
# perform request and return response # perform request and return response
response_data = self.request( response_data = self.request(
method, url, query_params=query_params, headers=header_params, method, url, query_params=query_params, headers=header_params,
post_params=post_params, body=body, post_params=post_params, body=body,
_preload_content=_preload_content, _preload_content=_preload_content,
_request_timeout=_request_timeout) _request_timeout=_request_timeout)
except ApiException as e:
e.body = e.body.decode('utf-8') if six.PY3 else e.body
raise e
content_type = response_data.getheader('content-type')
self.last_response = response_data self.last_response = response_data
return_data = response_data return_data = response_data
if _preload_content:
if not _preload_content:
return (return_data)
return return_data
if six.PY3 and response_type not in ["file", "bytes"]:
match = None
if content_type is not None:
match = re.search(r"charset=([a-zA-Z\-\d]+)[\s\;]?", content_type)
encoding = match.group(1) if match else "utf-8"
response_data.data = response_data.data.decode(encoding)
# deserialize response data # deserialize response data
if response_type: if response_type:
return_data = self.deserialize( return_data = self.deserialize(

View File

@ -217,11 +217,6 @@ class RESTClientObject(object):
if _preload_content: if _preload_content:
r = RESTResponse(r) r = RESTResponse(r)
# In the python 3, the response.data is bytes.
# we need to decode it to string.
if six.PY3:
r.data = r.data.decode('utf8')
# log response body # log response body
logger.debug("response body: %s", r.data) logger.debug("response body: %s", r.data)

View File

@ -10,6 +10,7 @@ $ nosetests -v
""" """
import os import os
import six
import sys import sys
import unittest import unittest

View File

@ -377,6 +377,36 @@ class DeserializationTests(unittest.TestCase):
finally: finally:
os.unlink(file_path) os.unlink(file_path)
def test_deserialize_binary_to_str(self):
"""Ensures that bytes deserialization works"""
response_types_mixed = (str,)
# sample from http://www.jtricks.com/download-text
HTTPResponse = namedtuple(
'urllib3_response_HTTPResponse',
['status', 'reason', 'data', 'getheaders', 'getheader']
)
headers = {}
def get_headers():
return headers
def get_header(name, default=None):
return headers.get(name, default)
data = "str"
http_response = HTTPResponse(
status=200,
reason='OK',
data=json.dumps(data).encode("utf-8") if six.PY3 else json.dumps(data),
getheaders=get_headers,
getheader=get_header
)
mock_response = RESTResponse(http_response)
result = self.deserialize(mock_response, response_types_mixed, True)
self.assertEqual(isinstance(result, str), True)
self.assertEqual(result, data)
def test_deserialize_string_boolean_map(self): def test_deserialize_string_boolean_map(self):
""" """
Ensures that string boolean (additional properties) Ensures that string boolean (additional properties)

View File

@ -329,7 +329,7 @@ class PetApiTests(unittest.TestCase):
http_response = HTTPResponse( http_response = HTTPResponse(
status=200, status=200,
reason='OK', reason='OK',
data=json.dumps(api_respponse), data=json.dumps(api_respponse).encode('utf-8'),
getheaders=get_headers, getheaders=get_headers,
getheader=get_header getheader=get_header
) )

View File

@ -28,7 +28,7 @@ import tornado.gen
from petstore_api.configuration import Configuration from petstore_api.configuration import Configuration
import petstore_api.models import petstore_api.models
from petstore_api import rest from petstore_api import rest
from petstore_api.exceptions import ApiValueError from petstore_api.exceptions import ApiValueError, ApiException
class ApiClient(object): class ApiClient(object):
@ -178,17 +178,33 @@ class ApiClient(object):
# use server/host defined in path or operation instead # use server/host defined in path or operation instead
url = _host + resource_path url = _host + resource_path
try:
# perform request and return response # perform request and return response
response_data = yield self.request( response_data = yield self.request(
method, url, query_params=query_params, headers=header_params, method, url, query_params=query_params, headers=header_params,
post_params=post_params, body=body, post_params=post_params, body=body,
_preload_content=_preload_content, _preload_content=_preload_content,
_request_timeout=_request_timeout) _request_timeout=_request_timeout)
except ApiException as e:
e.body = e.body.decode('utf-8') if six.PY3 else e.body
raise e
content_type = response_data.getheader('content-type')
self.last_response = response_data self.last_response = response_data
return_data = response_data return_data = response_data
if _preload_content:
if not _preload_content:
raise tornado.gen.Return(return_data)
if six.PY3 and response_type not in ["file", "bytes"]:
match = None
if content_type is not None:
match = re.search(r"charset=([a-zA-Z\-\d]+)[\s\;]?", content_type)
encoding = match.group(1) if match else "utf-8"
response_data.data = response_data.data.decode(encoding)
# deserialize response data # deserialize response data
if response_type: if response_type:
return_data = self.deserialize(response_data, response_type) return_data = self.deserialize(response_data, response_type)

View File

@ -16,7 +16,6 @@ import logging
import re import re
# python 2 and python 3 compatibility library # python 2 and python 3 compatibility library
import six
from six.moves.urllib.parse import urlencode from six.moves.urllib.parse import urlencode
import tornado import tornado
import tornado.gen import tornado.gen
@ -36,10 +35,6 @@ class RESTResponse(io.IOBase):
self.reason = resp.reason self.reason = resp.reason
if resp.body: if resp.body:
# In Python 3, the response body is utf-8 encoded bytes.
if six.PY3:
self.data = resp.body.decode('utf-8')
else:
self.data = resp.body self.data = resp.body
else: else:
self.data = None self.data = None

View File

@ -27,7 +27,7 @@ from six.moves.urllib.parse import quote
from petstore_api.configuration import Configuration from petstore_api.configuration import Configuration
import petstore_api.models import petstore_api.models
from petstore_api import rest from petstore_api import rest
from petstore_api.exceptions import ApiValueError from petstore_api.exceptions import ApiValueError, ApiException
class ApiClient(object): class ApiClient(object):
@ -176,17 +176,33 @@ class ApiClient(object):
# use server/host defined in path or operation instead # use server/host defined in path or operation instead
url = _host + resource_path url = _host + resource_path
try:
# perform request and return response # perform request and return response
response_data = self.request( response_data = self.request(
method, url, query_params=query_params, headers=header_params, method, url, query_params=query_params, headers=header_params,
post_params=post_params, body=body, post_params=post_params, body=body,
_preload_content=_preload_content, _preload_content=_preload_content,
_request_timeout=_request_timeout) _request_timeout=_request_timeout)
except ApiException as e:
e.body = e.body.decode('utf-8') if six.PY3 else e.body
raise e
content_type = response_data.getheader('content-type')
self.last_response = response_data self.last_response = response_data
return_data = response_data return_data = response_data
if _preload_content:
if not _preload_content:
return return_data
if six.PY3 and response_type not in ["file", "bytes"]:
match = None
if content_type is not None:
match = re.search(r"charset=([a-zA-Z\-\d]+)[\s\;]?", content_type)
encoding = match.group(1) if match else "utf-8"
response_data.data = response_data.data.decode(encoding)
# deserialize response data # deserialize response data
if response_type: if response_type:
return_data = self.deserialize(response_data, response_type) return_data = self.deserialize(response_data, response_type)

View File

@ -217,11 +217,6 @@ class RESTClientObject(object):
if _preload_content: if _preload_content:
r = RESTResponse(r) r = RESTResponse(r)
# In the python 3, the response.data is bytes.
# we need to decode it to string.
if six.PY3:
r.data = r.data.decode('utf8')
# log response body # log response body
logger.debug("response body: %s", r.data) logger.debug("response body: %s", r.data)

View File

@ -44,7 +44,7 @@ class TestFormatTest(unittest.TestCase):
double = 67.8, double = 67.8,
string = 'a', string = 'a',
byte = 'YQ==', byte = 'YQ==',
binary = bytes(b'blah'), binary = 'bytes',
date = datetime.datetime.strptime('1975-12-30', '%Y-%m-%d').date(), date = datetime.datetime.strptime('1975-12-30', '%Y-%m-%d').date(),
date_time = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'), date_time = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'),
uuid = '72f98069-206d-4f12-9f12-3d1e525a8e84', uuid = '72f98069-206d-4f12-9f12-3d1e525a8e84',

View File

@ -10,6 +10,7 @@ $ nosetests -v
""" """
import os import os
import six
import sys import sys
import unittest import unittest

View File

@ -15,6 +15,7 @@ import atexit
import mimetypes import mimetypes
from multiprocessing.pool import ThreadPool from multiprocessing.pool import ThreadPool
import os import os
import re
# python 2 and python 3 compatibility library # python 2 and python 3 compatibility library
import six import six
@ -22,7 +23,7 @@ from six.moves.urllib.parse import quote
from petstore_api import rest from petstore_api import rest
from petstore_api.configuration import Configuration from petstore_api.configuration import Configuration
from petstore_api.exceptions import ApiValueError from petstore_api.exceptions import ApiValueError, ApiException
from petstore_api.model_utils import ( from petstore_api.model_utils import (
ModelNormal, ModelNormal,
ModelSimple, ModelSimple,
@ -178,17 +179,34 @@ class ApiClient(object):
# use server/host defined in path or operation instead # use server/host defined in path or operation instead
url = _host + resource_path url = _host + resource_path
try:
# perform request and return response # perform request and return response
response_data = self.request( response_data = self.request(
method, url, query_params=query_params, headers=header_params, method, url, query_params=query_params, headers=header_params,
post_params=post_params, body=body, post_params=post_params, body=body,
_preload_content=_preload_content, _preload_content=_preload_content,
_request_timeout=_request_timeout) _request_timeout=_request_timeout)
except ApiException as e:
e.body = e.body.decode('utf-8') if six.PY3 else e.body
raise e
content_type = response_data.getheader('content-type')
self.last_response = response_data self.last_response = response_data
return_data = response_data return_data = response_data
if _preload_content:
if not _preload_content:
return (return_data)
return return_data
if six.PY3 and response_type not in ["file", "bytes"]:
match = None
if content_type is not None:
match = re.search(r"charset=([a-zA-Z\-\d]+)[\s\;]?", content_type)
encoding = match.group(1) if match else "utf-8"
response_data.data = response_data.data.decode(encoding)
# deserialize response data # deserialize response data
if response_type: if response_type:
return_data = self.deserialize( return_data = self.deserialize(

View File

@ -217,11 +217,6 @@ class RESTClientObject(object):
if _preload_content: if _preload_content:
r = RESTResponse(r) r = RESTResponse(r)
# In the python 3, the response.data is bytes.
# we need to decode it to string.
if six.PY3:
r.data = r.data.decode('utf8')
# log response body # log response body
logger.debug("response body: %s", r.data) logger.debug("response body: %s", r.data)

View File

@ -27,7 +27,7 @@ from six.moves.urllib.parse import quote
from petstore_api.configuration import Configuration from petstore_api.configuration import Configuration
import petstore_api.models import petstore_api.models
from petstore_api import rest from petstore_api import rest
from petstore_api.exceptions import ApiValueError from petstore_api.exceptions import ApiValueError, ApiException
class ApiClient(object): class ApiClient(object):
@ -176,17 +176,33 @@ class ApiClient(object):
# use server/host defined in path or operation instead # use server/host defined in path or operation instead
url = _host + resource_path url = _host + resource_path
try:
# perform request and return response # perform request and return response
response_data = self.request( response_data = self.request(
method, url, query_params=query_params, headers=header_params, method, url, query_params=query_params, headers=header_params,
post_params=post_params, body=body, post_params=post_params, body=body,
_preload_content=_preload_content, _preload_content=_preload_content,
_request_timeout=_request_timeout) _request_timeout=_request_timeout)
except ApiException as e:
e.body = e.body.decode('utf-8') if six.PY3 else e.body
raise e
content_type = response_data.getheader('content-type')
self.last_response = response_data self.last_response = response_data
return_data = response_data return_data = response_data
if _preload_content:
if not _preload_content:
return return_data
if six.PY3 and response_type not in ["file", "bytes"]:
match = None
if content_type is not None:
match = re.search(r"charset=([a-zA-Z\-\d]+)[\s\;]?", content_type)
encoding = match.group(1) if match else "utf-8"
response_data.data = response_data.data.decode(encoding)
# deserialize response data # deserialize response data
if response_type: if response_type:
return_data = self.deserialize(response_data, response_type) return_data = self.deserialize(response_data, response_type)

View File

@ -217,11 +217,6 @@ class RESTClientObject(object):
if _preload_content: if _preload_content:
r = RESTResponse(r) r = RESTResponse(r)
# In the python 3, the response.data is bytes.
# we need to decode it to string.
if six.PY3:
r.data = r.data.decode('utf8')
# log response body # log response body
logger.debug("response body: %s", r.data) logger.debug("response body: %s", r.data)

View File

@ -30,8 +30,8 @@ class EnumClass implements ModelInterface
private const MODEL_SCHEMA = <<<'SCHEMA' private const MODEL_SCHEMA = <<<'SCHEMA'
{ {
"type" : "string", "type" : "string",
"default" : "-efg", "enum" : [ "_abc", "-efg", "(xyz)" ],
"enum" : [ "_abc", "-efg", "(xyz)" ] "default" : "-efg"
} }
SCHEMA; SCHEMA;