Jessica Tsui
Jessica Tsui

Reputation: 55

Can't figure out TypeError: __init__() takes exactly 3 arguments (2 given)

I am working on a multi clients/ server chat app that can write input from one client to multi clients. For the client side it's working well, yet for the server side I want to add a part where it can print out the input from the clients on its own screen as well. And when I am working on it I encounter the issue of init()takes exactly 3 arguements (2 given) with the line "self.app = app"

Here is my code

import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.support import install_twisted_reactor
install_twisted_reactor()
from twisted.internet import reactor
from twisted.internet.protocol import Protocol, Factory

class MultiClientEcho(Protocol):

    def __init__(self, factory, app):
        self.factory = factory
        self.app = app

    def connectionMade(self):
        self.factory.clients.append(self)

    def dataReceived(self, data):
        for client in self.factory.clients:
             addtolog = self.factory.app.handle_message(data)
             if addtolog:
               client.transport.write(data)

    def connectionLost(self,reason):
        self.factory.clients.remove(self)

class MultiClientEchoFactory(Factory):
    protocol = MultiClientEcho
    def __init__(self):
        self.clients = []

    def buildProtocol(self, addr):
            return MultiClientEcho(self)


class ServerApp(App):
    def build(self):
        self.label = Label(text="server started\n")
        reactor.listenTCP(8000, MultiClientEchoFactory())
        return self.label

    def handle_message(self, msg):
        self.label.text = "received:  %s\n" % msg
        return msg


if __name__ == '__main__':
    ServerApp().run()

The interesting thing is that I was just adapting from the source code from this site: http://kivy.org/docs/guide/other-frameworks.html , it was working well on its own as well, but once i changed the protocol to MultiClientEcho it immediately resulted in such type error. How can I fix this?

Upvotes: 3

Views: 4034

Answers (3)

n00dl3
n00dl3

Reputation: 21584

you are calling MultiClientEcho(self) in class MultiClientEchoFactory with only one arguments,factory:

def buildProtocol(self, addr):
            return MultiClientEcho(self)

you should try something like

class MultiClientEchoFactory(Factory):
    protocol = MultiClientEcho
    def __init__(self,app):
        self.clients = []
        self.app=app

    def buildProtocol(self, addr):
            return MultiClientEcho(self,app)


class ServerApp(App):
    def build(self):
        self.label = Label(text="server started\n")
        reactor.listenTCP(8000, MultiClientEchoFactory(self))
        return self.label

    def handle_message(self, msg):
        self.label.text = "received:  %s\n" % msg
        return msg


if __name__ == '__main__':
    ServerApp().run()

Upvotes: 2

MasterOdin
MasterOdin

Reputation: 7896

Look at the __init__ definition for MultiClientEchoFactory:

def __init__(self, factory, app):

That requires three parameters to function (or else it'll throw an error).

You call this line here:

return MultiClientEcho(self)

Now, the self in __init__ will get defined automatically for you by this instance of MultiClientEcho. factory will get defined as your instance of MultiClientEchoFactory. However, you haven't passed in a parameter for app, so python cannot continue.

What you probably want to do is pass your instance of ServerApp in the build function into the constructor of MultiClientEchoFactory:

    reactor.listenTCP(8000, MultiClientEchoFactory(self))

change the factory to be:

def __init__(self, app):
    self.app = app
    self.clients = []

def buildProtocol(self, addr):
        return MultiClientEcho(self, self.app)

which will get rid of this error as now you'll be supplying that third app parameter.

Upvotes: 2

Daniel Roseman
Daniel Roseman

Reputation: 599956

The error message seems clear: MultiClientEcho's __init__ method expects three parameters (factory and app as well as the automatic self) but you're only passing self and factory when you instantiate it in the buildProtocol method . Where is it supposed to get app from?

Upvotes: 0

Related Questions