最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【已解决】Python的Flask中自定义的枚举对象序列化为JSON时出错:TypeError is not JSON serializable

Flask crifan 4732浏览 0评论

代码:

def jsonToStr(jsonDict, indent=2):
    return json.dumps(jsonDict, indent=2, ensure_ascii=False)

去把一个对象,其中属性中包含一个自定义的enum对象:

class RatingType(enum.Enum):
    NoStar = “NoStar”
    OneStar = “OneStar”
    TwoStar = “TwoStar”
    ThreeStar = “ThreeStar”
    FourStar = “FourStar”
    FiveStar = “FiveStar”

去序列化为JSON字符串,结果出错了:

auto convert json dict into string

<div–<——————————————————————————

Traceback (most recent call last):
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/gevent/pywsgi.py”, line 884, in handle_one_response
    self.run_application()
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/geventwebsocket/handler.py”, line 88, in run_application
    return super(WebSocketHandler, self).run_application()
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/gevent/pywsgi.py”, line 870, in run_application
    self.result = self.application(self.environ, self.start_response)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py”, line 2000, in __call__
    return self.wsgi_app(environ, start_response)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask_sockets.py”, line 48, in __call__
    return self.wsgi_app(environ, start_response)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py”, line 1991, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask_restful/__init__.py”, line 271, in error_router
    return original_handler(e)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py”, line 1567, in handle_exception
    reraise(exc_type, exc_value, tb)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask_restful/__init__.py”, line 268, in error_router
    return self.handle_error(e)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py”, line 1988, in wsgi_app
    response = self.full_dispatch_request()
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py”, line 1641, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask_restful/__init__.py”, line 271, in error_router
    return original_handler(e)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py”, line 1544, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask_restful/__init__.py”, line 268, in error_router
    return self.handle_error(e)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py”, line 1639, in full_dispatch_request
    rv = self.dispatch_request()
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py”, line 1625, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask_restful/__init__.py”, line 477, in wrapper
    resp = resource(*args, **kwargs)
  File “/root/RunningFast/stable/runningfast/resources/Accesstoken.py”, line 167, in decorated_function
    return f(*args, **kwargs)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask/views.py”, line 84, in view
    return self.dispatch_request(*args, **kwargs)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask_restful/__init__.py”, line 587, in dispatch_request
    resp = meth(*args, **kwargs)
  File “/root/RunningFast/stable/runningfast/resources/Task.py”, line 527, in put
    wsNotifyTaskCompleted(curTask)
  File “/root/RunningFast/stable/runningfast/resources/Websocket.py”, line 236, in wsNotifyTaskCompleted
    return wsNotifyTaskStatusChanged(curTask)
  File “/root/RunningFast/stable/runningfast/resources/Websocket.py”, line 302, in wsNotifyTaskStatusChanged
    wsSendUserMessage(toNotifUserId, respTaskStatusChangedDict)
  File “/root/RunningFast/stable/runningfast/resources/Websocket.py”, line 339, in wsSendUserMessage
    wsSendMessage(userWs, respInfoDict)
  File “/root/RunningFast/stable/runningfast/resources/Websocket.py”, line 65, in wsSendMessage
    respMessageStr = jsonToStr(respMsgDictOrStr)
  File “/root/RunningFast/stable/runningfast/common/utils.py”, line 48, in jsonToStr
    return json.dumps(jsonDict, indent=2, ensure_ascii=False)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask/json.py”, line 126, in dumps
    rv = _json.dumps(obj, **kwargs)
  File “/usr/local/lib/python2.7/json/__init__.py”, line 251, in dumps
    sort_keys=sort_keys, **kw).encode(obj)
  File “/usr/local/lib/python2.7/json/encoder.py”, line 209, in encode
    chunks = list(chunks)
  File “/usr/local/lib/python2.7/json/encoder.py”, line 434, in _iterencode
    for chunk in _iterencode_dict(o, _current_indent_level):
  File “/usr/local/lib/python2.7/json/encoder.py”, line 408, in _iterencode_dict
    for chunk in chunks:
  File “/usr/local/lib/python2.7/json/encoder.py”, line 408, in _iterencode_dict
    for chunk in chunks:
  File “/usr/local/lib/python2.7/json/encoder.py”, line 442, in _iterencode
    o = _default(o)
  File “/root/Envs/RunningFast/lib/python2.7/site-packages/flask/json.py”, line 83, in default
    return _json.JSONEncoder.default(self, o)
  File “/usr/local/lib/python2.7/json/encoder.py”, line 184, in default
    raise TypeError(repr(o) + ” is not JSON serializable”)
TypeError: <RatingType.NoStar: ‘NoStar’> is not JSON serializable
{‘CONTENT_LENGTH’: ‘0’,
‘CONTENT_TYPE’: ‘application/x-www-form-urlencoded’,
‘GATEWAY_INTERFACE’: ‘CGI/1.1’,
‘HTTP_ACCEPT_ENCODING’: ‘gzip’,
‘HTTP_AUTHORIZATION’: ‘o7ZuoJZ1bwPQSbageYeKFN08UJJw7Rh9’,
‘HTTP_CONNECTION’: ‘Keep-Alive’,
‘HTTP_HOST’: ‘115.29.173.126:21084’,
‘HTTP_USER_AGENT’: ‘Dalvik/1.6.0 (Linux; U; Android 4.4.4; HM 2A MIUI/V8.0.1.0.KHLCNDG)’,
‘PATH_INFO’: ‘/runningfast/api/v1.0/tasks/task-c7895fe7-be59-48ad-bbc3-b44c7187797f/users/user-74f41a28-7dba-4f5f-a202-782a774c4902/complete’,
‘QUERY_STRING’: ”,
‘REMOTE_ADDR’: ‘58.209.20.165’,
‘REMOTE_PORT’: ‘9738’,
‘REQUEST_METHOD’: ‘PUT’,
‘SCRIPT_NAME’: ”,
‘SERVER_NAME’: ‘AY140128113754462e2eZ’,
‘SERVER_PORT’: ‘21084’,
‘SERVER_PROTOCOL’: ‘HTTP/1.1’,
‘SERVER_SOFTWARE’: ‘gevent/1.1.2 gunicorn/19.6.0’,
‘werkzeug.request’: <Request ‘http://115.29.173.126:21084/runningfast/api/v1.0/tasks/task-c7895fe7-be59-48ad-bbc3-b44c7187797f/users/user-74f41a28-7dba-4f5f-a202-782a774c4902/complete’ [PUT]>,
‘wsgi.errors’: <gunicorn.http.wsgi.WSGIErrorsWrapper object at 0x7f9eed93ced0>,
‘wsgi.file_wrapper’: <class ‘gunicorn.http.wsgi.FileWrapper’>,
‘wsgi.input’: <gevent.pywsgi.Input object at 0x7f9eea8cd870>,
‘wsgi.multiprocess’: False,
‘wsgi.multithread’: True,
‘wsgi.run_once’: False,
‘wsgi.url_scheme’: ‘http’,
‘wsgi.version’: (1, 0)} failed with TypeError

flask json TypeError is not JSON serializable

python json enum TypeError is not JSON serializable

serialization – Serialising an Enum member to JSON – Stack Overflow

->

里面的方案,貌似不错:

14
down vote
accepted
If you want to encode an arbitrary enum.Enum member to JSON and then decode it as the same enum member (rather than simply the enum member’s value attribute), you can do so by writing a custom JSONEncoder class, and a decoding function to pass as the object_hook argument to json.load() or json.loads():
class EnumEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Enum):
            return {“__enum__”: str(obj)}
        return json.JSONEncoder.default(self, obj)
def as_enum(d):
    if “__enum__” in d:
        name, member = d[“__enum__”].split(“.”)
        return getattr(globals()[name], member)
    else:
        return d
The as_enum function relies on:
The relevant Enum existing in the global namespace.
The JSON having been encoded using EnumEncoder, or something which behaves identically to it.
Example usage:
>>> data = {
…     “action”: “frobnicate”,
…     “status”: Status.success
… }
>>> text = json.dumps(data, cls=EnumEncoder)
>>> text
‘{“status”: {“__enum__”: “Status.success”}, “action”: “frobnicate”}’
>>> json.loads(text, object_hook=as_enum)
{‘status’: <Status.success: 0>, ‘action’: ‘frobnicate’}

-》

不过我此处不需要这么用

因为我要去返回:

NoStar

而不是:

RatingType.NoStar

from enum import IntEnum
import json
class Status(IntEnum):
    success = 0
    failure = 1
json.dumps(Status.success)

这个方案不错

不过需要我此处:

找到的确存在:

String的Enum

这种系统自带的枚举

以及把函数改为:

class RatingType(StringEnum):

所以先去找:

【记录】寻找Python中是否有已实现好的类似于IntEnum的String的Enum

结果找到但是安装不了。

python json enum TypeError

python json dumps  enum string TypeError

Python JSON Module Tutorial – w3resource

8.13. enum — Support for enumerations — Python 3.5.2 documentation

python – Enum vs String as a parameter in a function – Stack Overflow

讨论了:

对于简单的枚举,到底是直接用string还是用enum,哪个更好。

答案是:各有所长。

python – Is it possible to dump an enum in json without passing an encoder to json.dumps()? – Stack Overflow

class FooBarType:

    standard = 0

    foo = 1

    bar = 2

dict = {‘type’: FooBarType.foo}

json.dumps(dict)

class EnumIntValue(int):

    def __new__(cls, name, value):

        c = int.__new__(cls, int(value))

        c.name = name

        return c

    def __repr__(self):

        return self.name

    def __str__(self):

        return self.name

class FooBarType:

    standard = EnumIntValue(‘standard’,0)

    foo = EnumIntValue(‘foo’,0)

    bar = EnumIntValue(‘bar’,2)

dict = {‘type’: FooBarType.foo}

json.dumps(dict)

也是一种办法。但是就是:

不能继承Enum了,逻辑不是足够的清晰

-》并且我要是改为这种,后续的alembic去升级数据库时,也要额外修改东西,就麻烦了。

算了,还是简单点吧:

把我自己的Enum的值,传递进去:

curTask.errandorRatingType.value

curTask.cancelByUserType.value

curTask.initiatorCancelReasonType.value

curTask.errandorCancelReasonType.value

,就不用json去解析出错了:

    elif curTask.statusType == TaskStatus.Completed:
        eventValue = “Completed”
        if curTask.errandorRatingType == RatingType.NoStar:
            toNotifUserId = curTask.initiatorId
        elif curTask.errandorRatingType != RatingType.NoStar:
            toNotifUserId = curTask.errandorId
        dataValue[“errandorRatingType”] = curTask.errandorRatingType.value
    elif curTask.statusType == TaskStatus.Canceled:
        eventValue = “Canceled”
        dataValue[“cancelByUserType”] = curTask.cancelByUserType.value
        dataValue[“initiatorCancelReasonType”] = curTask.initiatorCancelReasonType.value
        dataValue[“errandorCancelReasonType”] = curTask.errandorCancelReasonType.value

【总结】

此处,由于各种原因,最后是把:

已有的枚举定义,不变:

class RatingType(enum.Enum):
    NoStar = “NoStar”
    OneStar = “OneStar”
    TwoStar = “TwoStar”
    ThreeStar = “ThreeStar”
    FourStar = “FourStar”
    FiveStar = “FiveStar”

然后在给(字典变量)传递值时,不是赋值enum枚举值,而是赋值枚举值的原始址value:

dataValue[“errandorRatingType”] = curTask.errandorRatingType.value

这样之后再去调用:

json.dumps

时,就不会出错了。

转载请注明:在路上 » 【已解决】Python的Flask中自定义的枚举对象序列化为JSON时出错:TypeError is not JSON serializable

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

网友最新评论 (1)

  1. 可以模仿IntEnum,自己造一个 class StrEnum(str, Enum): pass
    Phantom016年前 (2019-05-13)回复
92 queries in 0.231 seconds, using 22.17MB memory