Using websocket client as a class in python

I'm trying to access some data using websockets, but I can't seem to get around the examples provided in the websockets documentation.

I have this code ( https://pypi.org/project/websocket_client/ ) and I want to convert it to a class.

import websocket
import thread
import time

def on_message(ws, message):
    print message

def on_error(ws, error):
    print error

def on_close(ws):
    print "### closed ###"

def on_open(ws):
    def run(*args):
        for i in range(3):
            time.sleep(1)
            ws.send("Hello %d" % i)
        time.sleep(1)
        ws.close()
        print "thread terminating..."
    thread.start_new_thread(run, ())


if __name__ == "__main__":
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp("ws://echo.websocket.org/",
                                on_message = on_message,
                                on_error = on_error,
                                on_close = on_close)
    ws.on_open = on_open

    ws.run_forever()

      

The idea is to have all this websocket functionality in a class so that I can just create an object of that class.

I tried to start doing this, but I can't even get past this:

class MySocket(object):
    def __init__(self):
        websocket.enableTrace(True)
        self.ws = websocket.WebSocketApp("ws://echo.websocket.org:12300/foo",
                                    on_message = on_message,
                                    on_error = on_error,
                                    on_close = on_close)

    def on_message(ws, message):
        print message

    def on_error(ws, error):
        print error

    def on_close(ws):
        print "### closed ###"

    def on_open(ws):
    ws.send("Hello %d" % i)

      

The error starts right off on_message

saying that this is an "unresolved link".

+6


source to share


7 replies


Call batch inside anonymous lambda

function for correct call with correct self

:



class Client:
    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   = lambda ws:     self.on_close(ws),
                    on_open    = lambda ws:     self.on_open(ws))

    def on_message(self, ws, message):
            msg = json.loads(message)
            print(msg)
    ...

      

+8


source


WebSocketApp

need callable objects for their callbacks (both the ones you pass in the constructor, for example on_message

, and the one you set after the fact on_open

).

Regular functions are callable objects, so your non-OO version works fine because you are passing simple functions.

Bound methods are also callable objects. But your OO version doesn't pass associated methods. A bound method, as the name suggests, is bound to an object. You do this using notation obj.method

. In your case, this is 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 have another problem. While this will make your mistake go away, it will not make your code actually work. A normal method should take self

as its first argument:

def on_message(self, ws, message):
    print message

      

It's also worth noting that you are not actually using this class for anything. If you never get anything from self

, the class just acts like a namespace. Not that it's always a bad thing, but it's usually a sign that you need to at least think through your design. Is there any state you need to maintain? If not, why do you need a class?

You can reread the section on Classes to understand about methods, self

etc.

+5


source


You need to add "self" to your class methods:

class MySocket(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)

    def on_message(self, ws, message):
        print message

    def on_error(self, ws, error):
        print error

    def on_close(self, ws):
        print "### closed ###"

    def on_open(self, ws):
        ws.send("Hello %d" % i)

      

+1


source


"I" makes these methods as class methods. Got this one working as the signature of the on_error / message / close method, will be satisfied if called itself, as will be the case for the class itself.

 class MySocket(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 
    def ws_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()

    def on_error(self,ws, error):
        print "onError", error

    def on_close(self,ws):
       print "onClosed"

    #Send some message on open 
    def on_open(self,ws):
       self.ws.send(json.dumps(register_msg))

    def on_message(self,ws, msg):
       self.ws.send(json.dumps(msg))


 user1=Userapp('x')
 user1.ws_comm()

      

+1


source


I would like to try:

class FooClient(object):
    def __init__(self):
        def on_message(ws, message):
            print message
            # use 'self' variable to access other resource
            # handle message from websocket server like this
            self.handler.handle(message)

        def on_error(ws, error):
            print error

        def on_close(ws):
            print "### closed ###"

        def on_open(ws):
            ws.send("Hello %d" % i)

        # assign to 'self.handler'
        self.handler = FooHandler()
        # maybe there are another module should be initiated
        # ...

        websocket.enableTrace(True)
        self.ws = websocket.WebSocketApp("ws://echo.websocket.org:12300/foo",
                                         on_message = on_message,
                                         on_error = on_error,
                                         on_close = on_close)

    def run_forever(self):
        self.ws.run_forever()

    def close(self):
        """clean other resources"""
        pass

      

Using an inner function in a method __init__(self)

could avoid the problem that the method's number arguments on_message(self, ws, message)

do not match the number it WebSocketApp

provides its argument on_message

(a class method has one more argument self

).

I have handler

above for handling a message, a method close(self)

to clean up some resources, if I have one, run_forever(self)

to start a websocket.

0


source


It works:

class MySocket(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)

    @staticmethod
    def on_message(ws, message):
        print message

    @staticmethod
    def on_error(ws, error):
        print error

    @staticmethod
    def on_close(ws):
        print "### closed ###"

    @staticmethod
    def on_open(ws):
        ws.send("Hello %d" % i)

      

But you don't have access to yourself

0


source


import websocket

try:
    import thread
except ImportError:
    import _thread as thread
import time


class OnyxGenericClient:
    """
    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):

    def on_message(self, message):
        print(message)
        return message

    def on_error(self, error):
        return error

    def on_close(self):
        print("### closed ###")

    def run(self, *args):
        global driver
        driver = True
        while 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...")

    def on_open(self):
        thread.start_new_thread(self.run, ())


if __name__ == "__main__":
    websocket.enableTrace(True)
    onyx_client = OnyxGenericClient()

      

I wonder why the parameter is still being exposed ws

?

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 block is executed, try

it checks if our callback is a method or a function. if it's a method, it will execute callback(*args)

already our own from our CustomClient

already passed as an argument to (* args). Keep in mind, it already has its own self

c def _callback(self, callback, *args)

. Hence, every callback that is an instance of yours CustomClient

should not have a ws argument.

0


source







All Articles