Issue
I'm trying to code a socket server on my raspberry pi. I'm trying to use a decorator to connect a client to a server(which will be my raspberry pi). But my code for it is keeping on throwing a NoneType error. I'm a bit new to asynchronous decorators, and need some help on them. Can you please see where my error is coming from, and please correct my code a bit? I will list my code and the error messages down below.
My error message:
C:\Users\####\AppData\Local\Programs\Python\Python36-32\python.exe C:/Users/#####/Desktop/autorank/server/client.py
Traceback (most recent call last):
File "C:/Users/#####/Desktop/autorank/server/client.py", line 5, in <module>
@client.connection(("192.168.0.11", 56500))
TypeError: 'NoneType' object is not callable
My client code for the package:
import socket, asyncio
class Client:
def __init__(self):
self.s = None
self.data = None
def connection(self, addr):
"""An asynchronous decorator for any server mainloop. Just decorate it with this and add a Client parameter."""
def wrapper1(func):
async def wrapper2(*args):
self.connect(addr)
await func(self)
self.close_conn()
return await func(self)
return wrapper2
async def connect(self, addr):
"""Connects to the desired server. You can make a server mainloop with the connection decorator."""
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.connect(addr)
self.addr = addr
print(f"Connected to {addr}")
async def close_conn(self):
"""Closes connection with the address connected to."""
self.s.close()
print(f"Disconnected from {self.addr}")
del self.addr
async def send_bytes(self, bytes_data):
"""Sends bytedata through a pipe to connected address"""
self.s.sendall(bytes_data)
print(f"Sent {bytes_data.decode()} in bytedata format to {self.addr}")
async def recv(self, buf_size):
"""Recieves data from a server in bytedata format"""
self.data = self.s.recv(buf_size)
And finally, my main.py:
import asyncserver
client = asyncserver.Client()
@client.connection(("192.168.0.11", 56500))
def mainloop(cli):
cli.send_bytes(b'Hello!!')
cli.recv(1024)
print(cli.data.decode())
Please say if I should improve my question, and any answers are appreciated!
Solution
The connection
decorator correctly defines wrapper1
, but fails to return it. It implicitly returns None
, and that's what gets used as mainloop
at top-level, resulting in the error.
Note that wrapper2
awaits func(self)
, which might lead to another error, about None
not being awaitable. If you plan to await the function you decorate, you should either make it async (async def mainloop(cli): ...
) or have it return an awaitable object.
Finally, wrapper2
shouldn't accept arbitrary *args
if it will not use them. That will cause something like mainloop(1, 2, 3)
to appear to work while ignoring the arguments. Normally the point of a wrapper accepting *args
is to forward them to the wrapped function. If you don't want or need that, just make the wrapper2
accept no arguments.
Answered By - user4815162342
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.