Using A Websocket Client As A Class In Python
Solution 1:
Package the call inside an anonymous lambda
function to achieve a proper call with the correct self
:
classClient:def__init__(self, db, symbols):
self.ws = websocket.WebSocketApp("wss://the.server.com/api",
on_message = lambda ws,msg:self.on_message(ws, msg),
on_error = lambda ws,msg:self.on_error(ws, msg),
on_close = lambdaws:self.on_close(ws),
on_open = lambdaws:self.on_open(ws))
defon_message(self, ws, message):
msg = json.loads(message)
print(msg)
...
Solution 2:
The WebSocketApp
needs callable objects for its callbacks (both the ones you pass in the constructor, like on_message
, and the one you're setting after the fact, on_open
).
Plain functions are callable objects, so your non-OO version works fine, because you're passing the plain functions.
Bound methods are also callable objects. But your OO version isn't passing bound methods. A bound method is, as the name implies, bound to an object. You do this by using the obj.method
notation. In your case, that's self.on_message
:
self.ws = websocket.WebSocketApp("ws://echo.websocket.org/",
on_message = self.on_message,
on_error = self.on_error,
on_close = self.on_close)
self.ws.on_open = self.on_open
However, you've got another problem. While this will make your error go away, it won't make your code actually work. A normal method has to take self
as its first argument:
defon_message(self, ws, message):
print message
It's also worth noting that you're not really using the class for anything. If you never access anything off self
, the class is just acting like a namespace. Not that this is always a bad thing, but it's usually a sign that you need to at least think through your design. Is there really any state that you need to maintain? If not, why do you want a class in the first place?
You may want to reread the tutorial section on Classes to understand about methods, self
, etc.
Solution 3:
import websocket
try:
import thread
except ImportError:
import _thread as thread
import time
classOnyxGenericClient:
"""
Onyx Client Interface
"""def__init__(self, ):
websocket.enableTrace(True)
ws = websocket.WebSocketApp("ws://localhost:3000/",
on_message=self.on_message,
on_error=self.on_error,
on_close=self.on_close)
self.ws = ws
self.ws.on_open = self.on_open
self.ws.run_forever()
# def initiate(self):defon_message(self, message):
print(message)
return message
defon_error(self, error):
return error
defon_close(self):
print("### closed ###")
defrun(self, *args):
global driver
driver = Truewhile driver:
try:
time.sleep(1)
print("Say something nice")
p = input()
self.ws.send(p)
except KeyboardInterrupt:
driver = False
time.sleep(1)
self.ws.close()
print("thread terminating...")
defon_open(self):
thread.start_new_thread(self.run, ())
if __name__ == "__main__":
websocket.enableTrace(True)
onyx_client = OnyxGenericClient()
I wonder why everyone is still putting the ws
parameter.
Read the error log.
File "venv/lib/python3.7/site-packages/websocket/_app.py", line 343, in _callback callback(*args)
def _callback(self, callback, *args):
if callback:
try:
if inspect.ismethod(callback):
callback(*args)
else:
callback(self, *args)
except Exception as e:
_logging.error("error from callback {}: {}".format(callback, e))
if _logging.isEnabledForDebug():
_, _, tb = sys.exc_info()
traceback.print_tb(tb)
Looking at our callbacks, on_open(self, ws)
When the try
block executes it checks if our callback is a method or a function.
if it is a method it would execute the callback(*args)
already our self from our CustomClient
is already passed as an argument in (*args). Mind you it already has its own self
in def _callback(self, callback, *args)
.
Hence, every callback that is an instance of your CustomClient
should not have the ws argument.
Solution 4:
You need to add "self" to you class methods:
classMySocket(object):
def__init__(self):
websocket.enableTrace(True)
self.ws = websocket.WebSocketApp("ws://echo.websocket.org:12300/foo",
on_message = self.on_message,
on_error = self.on_error,
on_close = self.on_close)
defon_message(self, ws, message):
print message
defon_error(self, ws, error):
print error
defon_close(self, ws):
print"### closed ###"defon_open(self, ws):
ws.send("Hello %d" % i)
Solution 5:
The Self makes those methods as Class methods , Got this one working as the on_error/message/close methods signature will get satisfied if called by self as will refer to the class itself .
classMySocket(object):
def__init__(self,x):
websocket.enableTrace(True)
## Only Keep the object Initialisation here
self.x=x
self.ws=None# call This method from a Object and it will create and run the websocket defws_comm(self):
self.ws = websocket.WebSocketApp(self.WS_URL,on_message =
self.on_message,on_error =self.on_error,on_close = self.on_close)
self.ws.on_open = self.on_open
self.ws.run_forever()
defon_error(self,ws, error):
print"onError", error
defon_close(self,ws):
print"onClosed"#Send some message on open defon_open(self,ws):
self.ws.send(json.dumps(register_msg))
defon_message(self,ws, msg):
self.ws.send(json.dumps(msg))
user1=Userapp('x')
user1.ws_comm()
Post a Comment for "Using A Websocket Client As A Class In Python"