我需要帮助,为什么我会收到类似
RecursionError
的错误,我正在使用 python-socket
顺便说一句,在继续之前,我想澄清这个问题不是因为套接字配置,它工作正常,简单的测试事件工作正常。
这是我监听特定事件的套接字事件:
@sio_server.on(EVENT.REPLY_ON_TICKET)
async def reply_on_ticket_event(sid:str, data:dict):
sender_id = None
if data["sender_info"]["sender_id"]:
sender_id= data["sender_info"]["sender_id"]
else:
sender_id= data["sender_id"]
payload = {
"ticket_id": data["ticket_id"],
"sender_id": sender_id,
"notify": data["notify"],
"reply": data["reply"],
}
# Obtain a database session manually
db_session = next(get_db())
res = await reply_on_ticket_service(payload, db_session)
if res["success"]:
# the callback data for client socket
return {
"status_code": 200,
"success": True,
"message": "reply data",
"payload": res["data"],
}
return {"status_code": 400, "success": False}
这里是处理回复票证流程的服务:
async def reply_on_ticket_service(data:dict, db_session: Session = Depends(get_db)):
try:
new_reply= TicketReplyModal(reply_text=data["reply"],ticket_id=data["ticket_id"],sender_id=data["sender_id"])
new_reply_id= await db_manager.add_record(new_reply,db_session)
if not new_reply_id:
return {"success":False, 'status_code':400, "message":"Error occurred while creating new replay"}
new_record= await db_manager.get_record_by_id(new_reply_id, TicketReplyModal,db_session)
if not new_record:
return {"success":False, 'status_code':404, "message":"Unable to find record with newly created replay"}
sender_data = db_session.query(UserModel).filter(UserModel.id == new_record.sender_id).first()
if not sender_data:
return {"success":False, 'status_code':404, "message":"Unable to find sender info"}
reply = {
"id":new_record.id,
"created_at":new_record.created_at,
"reply_text":new_record.reply_text,
"ticket_id": new_record.ticket_id,
"sender":{
"id": sender_data.id,
"email": sender_data.email,
"profile_image": sender_data.profile_image,
"username": sender_data.username,
"public_key": sender_data.public_key,
}
}
return {"success": True, "data": reply}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
在
reply_on_ticket_event
返回方法中,如果我注释该行 "payload": res["data"]
然后它就可以正常工作,没有任何问题:
错误代码片段:
Task exception was never retrieved
future: <Task finished name='Task-39' coro=<AsyncServer._handle_event_internal() done, defined at C:\Users\AK\.virtualenvs\BE-hVO0_cLf\Lib\site-packages\socketio\async_server.py:605> exception=RecursionError('maximum recursion depth exceeded')>
Traceback (most recent call last):
File "C:\Users\AK\.virtualenvs\BE-hVO0_cLf\Lib\site-packages\socketio\async_server.py", line 617, in _handle_event_internal
await server._send_packet(eio_sid, self.packet_class(
File "C:\Users\AK\.virtualenvs\BE-hVO0_cLf\Lib\site-packages\socketio\async_server.py", line 518, in _send_packet
encoded_packet = pkt.encode()
^^^^^^^^^^^^
File "C:\Users\AK\.virtualenvs\BE-hVO0_cLf\Lib\site-packages\socketio\packet.py", line 64, in encode
encoded_packet += self.json.dumps(data, separators=(',', ':'))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\Python311\Lib\json\__init__.py", line 238, in dumps
**kw).encode(obj)
^^^^^^^^^^^
File "C:\Program Files\Python311\Lib\json\encoder.py", line 200, in encode
chunks = self.iterencode(o, _one_shot=True)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\Python311\Lib\json\encoder.py", line 258, in iterencode
return _iterencode(o, 0)
^^^^^^^^^^^^^^^^^
File "D:\BE\app.py", line 38, in default
return super().default(obj)
^^^^^^^^^^^^^^^^^^^^
File "D:\BE\app.py", line 38, in default
return super().default(obj)
^^^^^^^^^^^^^^^^^^^^
File "D:\BE\app.py", line 38, in default
return super().default(obj)
^^^^^^^^^^^^^^^^^^^^
[Previous line repeated 972 more times]
RecursionError: maximum recursion depth exceeded
错误所指向的行位于app.py中
class CustomJSONEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, uuid.UUID):
return str(obj)
return super().default(obj)
@app.on_event("startup")
def startup_event():
json.JSONEncoder.default = CustomJSONEncoder().default
我尝试注释上面的@app.on_event(“startup”),然后执行该套接字事件,然后这里抱怨UUID的错误是错误输出:
Task exception was never retrieved
future: <Task finished name='Task-47' coro=<AsyncServer._handle_event_internal() done, defined at C:\Users\AK\.virtualenvs\pw7-BE-hVO0_cLf\Lib\site-packages\socketio\async_server.py:605> exception=TypeError('Object of type UUID is not JSON serializable')>
Traceback (most recent call last):
File "C:\Users\AK\.virtualenvs\pw7-BE-hVO0_cLf\Lib\site-packages\socketio\async_server.py", line 617, in _handle_event_internal
await server._send_packet(eio_sid, self.packet_class(
File "C:\Users\AK\.virtualenvs\pw7-BE-hVO0_cLf\Lib\site-packages\socketio\async_server.py", line 518, in _send_packet
encoded_packet = pkt.encode()
^^^^^^^^^^^^
File "C:\Users\AK\.virtualenvs\pw7-BE-hVO0_cLf\Lib\site-packages\socketio\packet.py", line 64, in encode
encoded_packet += self.json.dumps(data, separators=(',', ':'))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\Python311\Lib\json\__init__.py", line 238, in dumps
**kw).encode(obj)
^^^^^^^^^^^
File "C:\Program Files\Python311\Lib\json\encoder.py", line 200, in encode
chunks = self.iterencode(o, _one_shot=True)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\Python311\Lib\json\encoder.py", line 258, in iterencode
return _iterencode(o, 0)
^^^^^^^^^^^^^^^^^
File "C:\Program Files\Python311\Lib\json\encoder.py", line 180, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type UUID is not JSON serializable
您遇到的问题与此行有关:
json.JSONEncoder.default = CustomJSONEncoder().default
这会将
default
中的 JSONEncoder
方法替换为最初为您的 CustomJSONEncoder
子类编写的自定义版本。但是,该子类版本调用 super()
,它会在其基类中查找实现。基类是JSONEncoder
,所以在你进行方法替换之后,它最终会找到自己。因此,当你有一个不可编码的值时,你不会得到预期的 TypeError
,你会得到递归,直到达到极限并得到 RecursionError
。
至于如何解决这个问题,我认为有两种选择。解决当前症状的一种方法是将对
super().default(obj)
的调用替换为显式 raise TypeError
调用(可能带有描述无法编码的对象的消息)。
但是,除了让您找到触发问题的虚假数据之外,这并不能真正解决方法替换的潜在问题。另一种选择是弄清楚如何正确地将
CustomJSONEncoder
类传递到库框架,以便它将使用它而不是标准库中的原始编码器。这样你就可以继续以推荐的风格编写你自己的 default
方法,而不会因为替换 json.JSONEncoder.default
而破坏东西。