Arran Duff
Arran Duff

Reputation: 1474

Under what circumstances is a class member function not passed self as the first parameter?

Problem

I am using a library to facilitate client side websocket communication with a server.

For example

from websocket import WebSocketApp
import websocket
class X(object):

    def run(self):
        self.ws  = WebSocketApp('wss://api.bitfinex.com/ws/2'
                            ,on_open=self.on_open
                            ,on_message=self.on_message
                            ,on_error=self.on_error
                            ,on_close=self.on_close)
        websocket.enableTrace(True)
        self.ws.run_forever()


    def on_open(self, ws):
        print('open')
    def on_close(self, ws):
        print('close')
    def on_message(self, ws, message):
        print('message')
    def on_error(self, ws, error):
        print('error')


if __name__=='__main__':
    x = X().run()

Output

error from callback <bound method X.on_open of <__main__.X object at 0x7fd7635e87f0>>: on_open() missing 1 required positional argument: 'ws'
  File "/home/arran/.local/lib/python3.6/site-packages/websocket/_app.py", line 343, in _callback
callback(*args)

I am probably missing something basic here. But any help would be greatly appreciated

Edit

Looks like this might be a version specific issue with the websocket-client library https://github.com/home-assistant/home-assistant/issues/17532

I have downgraded to an earlier version and fixed my problem. I would still be curious to know how this issue can arise though. My understanding was that class instance methods will always be passed self as the first parameter

Upvotes: 0

Views: 187

Answers (2)

miraculixx
miraculixx

Reputation: 10379

I am probably missing something basic here.

No, you were spot on. However, the on_open callback does not get called with the ws argument, although it should according to the documentation:

class WebSocketApp(object):
    (...)
        on_open: callable object which is called at opening websocket.
          this function has one argument. The argument is this class object.
    (...)

This is a known bug that was closed despite some discussion around the way it was fixed.

would still be curious to know how this issue can arise though.

I guess it's an honest mistake in an attempted bug fix. As there is no test for your particular scenario, it did not get caught.

enter image description here

I have downgraded to an earlier version and fixed my problem

Please kindly submit a bug report or write a pull request to fix the problem.

My understanding was that class instance methods will always be passed self as the first parameter

Yes, your understanding is correct. Here is an example mirroring what you tried.

class Server(object):
    def __init__(self, callback):
        self.callback = callback

    def run(self):
        self.callback(5)

class Client(object):
    def on_message(self, n):
        print("got", n)

client = Client()
server = Server(client.on_message)
server.run()

Upvotes: 0

hoodakaushal
hoodakaushal

Reputation: 1293

It looks to be an issue with the WebSocket class not passing the ws argument that your on_open method expects. I tried to reproduce it with my own dummy class, and it works fine.

class WS:
    def __init__(self, on_call):
        self.on_call = on_call
    def call(self):
        print("hi")
        self.on_call(self)


class X:
    def on_call(self, ws):
        print(ws)
    def run(self):
        self.ws = WS(self.on_call)
        self.ws.call()

X().run()
hi
<__main__.WS instance at 0x029AB698>

Upvotes: 1

Related Questions