This question already has answers here:
Takes exactly 3 arguments (4 given)
(2 answers)
Closed 4 years ago.
I have been trying to find the problem here for hours. From what I can find online people are actually passing more arguments than they think for all the post I can find related to this TypeError. For some reason this problem seams to only happen when I am creating a class that inherits from Toplevel.
Tackback:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Program Files\Python36\lib\tkinter\__init__.py", line 1699, in __call__
return self.func(*args)
File "C:\Users\Makin Bacon\workspace\stuff\MINT-master\test3.py", line 12, in fake_error
topErrorWindow(self, message, detail)
File "C:\Users\Makin Bacon\workspace\stuff\MINT-master\test3.py", line 17, in __init__
tk.Toplevel.__init__(self, master, message, detail)
TypeError: __init__() takes from 1 to 3 positional arguments but 4 were given
I even tried to send my arguments to a dummy function that just prints all the arguments and it only printed 3 arguments.
Here is the code I used to test to see what arguments were being passed.
import tkinter as tk
class MintApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
tk.Button(self, text="test error", command=self.fake_error).pack()
def fake_error(self):
message = "test"
detail = "test detail"
topErrorWindow(self, message, detail)
def topErrorWindow(*items):
for item in items:
print("TEST: ", item)
if __name__ == "__main__":
App = MintApp()
App.mainloop()
Here are the results:
TEST: .
TEST: test
TEST: test detail
Now I do not know for sure why I am getting a . for the argument self and I am thinking this might be part of the problem but I cannot find any related issues online.
Here is my code that in my mind should create a top level window with a simple label. Instead I get the trackback error listed above.
import tkinter as tk
class MintApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
tk.Button(self, text="test error", command=self.fake_error).pack()
def fake_error(self):
message = "test"
detail = "test detail"
topErrorWindow(self, message, detail)
class topErrorWindow(tk.Toplevel):
def __init__(self, master, message, detail):
tk.Toplevel.__init__(self, master, message, detail)
tk.Label(self, text = "{}, {}".format(message, detail)).grid(row=0, column=0, sticky="nsew")
if __name__ == "__main__":
App = MintApp()
App.mainloop()
When you do this:
tk.Toplevel.__init__(self, master, message, detail)
You are passing four arguments to __init__: self, master, message, detail. However, as the error clearly states, Toplevel.__init__ takes from one to three arguments.
I don't know what you expect the tkinter Toplevel class to do with message and detail, but they don't map to any of the arguments of a Toplevel.
The solution is to not pass the useless arguments to the superclass constructor since they have meaning to your subclass but not to the superclass:
tk.Toplevel.__init__(self, master)
Related
I've read at least 25 similar questions on this site, and I simply cannot get this working.
As it stands i'm just trying to build a simple chat app with a client and server. The GUI will be running on a separate thread to the logic to ensure things stay fluid and don't lock up. I've trimmed most of the logic out of the code to isolate the problem
import socket, csv, datetime, tkinter as tk, threading
from tkinter import ttk
interface = tk.Tk()
test = tk.StringVar()
test.set("String Var Test")
class serverInterface():
def __init__(self, interface):
global test
self.messageLog = tk.Text(interface, height=10, state="disabled", yscrollcommand="scrollBar.set")
self.scrollBar = ttk.Scrollbar(interface, command=self.messageLog.yview).grid(row=0, column=2, sticky="nsew")
self.messageLog.grid(row=0, column=0, columnspan=2)
test.trace("w", serverInterface.guiUpdate(self))
def guiUpdate(self):
self.messageLog.insert(tk.END, test)
class server():
def __init__(self):
global test
print("Server thread")
while True:
test.set("Updated from server object")
interface.title("Server")
serverInterface = threading.Thread(target=serverInterface(interface)) #Create serverInterface object
server = threading.Thread(target=server, daemon=True) # Create server object
server.start()
interface.mainloop()
This results in the console being spammed with Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\thoma\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 1883, in __call__ return self.func(*args) TypeError: 'NoneType' object is not callable
I've also tried to make use of Queue() as I've seen others suggest, but that just results in a different set of errors and I feel using StringVar() is probably the better way of doing this.
I appreciate that there's probably some lines in this code that don't need to be there, they're just leftovers from all the different attempts at bodging it :/
Any solutions would be appreciated.
The error you're asking about is due to this line:
test.trace("w", serverInterface.guiUpdate(self))
That line is functionally identical to this:
result = serverInterface.guiUpdate(self)
test.trace("w", result)
Since guiUpdate(self) returns None, you're asking tkinter to call None. Hence the error TypeError: 'NoneType' object is not callable
The trace method must be given a callable (ie: a reference to a function). In this specific case you need to use self.guiUpdate.
The trace will automatically pass arguments to the function, so you need to properly define the function to accept those arguments. You also have a bug where you're trying to insert an object (test) in the text widget rather than the text contained in the object.
I'm trying to create a simple Gui with tkinter using classes.
But I don't really understand how to make the for-loop work inside the count method, could anyone tell me where should I add the missing argument?
from tkinter import *
import time
class App:
def __init__(self, master):
self.container1 = Frame(master)
self.container1.pack()
self.button1 = Button(self.container1, text="count")
self.button1.bind("<Button-1>", self.count)
self.button1.pack()
def count(self):
for i in range(100):
self.button1["text"] = str(i)
time.sleep(1)
root = Tk()
Myapp = App(root)
root.mainloop()
The error is:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.5/tkinter/__init__.py", line 1553, in __call__
return self.func(*args)
TypeError: count() takes 1 positional argument but 2 were given
When you bind an event, a positional argument event is provided to the callback function.
Change your count method to this:
def count(self, event):
You will also need to get rid of time.sleep(1) since .sleep() is a blocking call, which means that it will block the tkinter mainloop which will cause your program to not respond.
I have the code below:
from tkinter import *
class Window(Frame):
def __init__(self, master = None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title("COD:WWII Codes")
self.pack(fill=BOTH, expand=1)
codeButton = Button(
self,
text="Generate Code",
command=self.generatecode
)
codeButton.place(x=0, y=0)
def generatecode(self):
f = open("C:/Programs/codes.txt", "r")
t.insert(1.0. f.red())
root = Tk()
root.geometry("400x300")
app = Window(root)
root.mainloop()
Then, I got the error below:
TypeError: generatecode() takes 0 positional arguments but 1 was given
So, how can I solve the error?
When you call a method on a class (such as generatecode() in this case), Python automatically passes self as the first argument to the function. So when you call self.my_func(), it's more like calling MyClass.my_func(self).
So when Python tells you "generatecode() takes 0 positional arguments but 1 was given", it's telling you that your method is set up to take no arguments, but the self argument is still being passed when the method is called, so in fact it is receiving one argument.
Adding self to your method definition should resolve the problem.
def generatecode(self):
pass # Do stuff here
Alternatively, you can make the method static, in which case Python will not pass self as the first argument:
#staticmethod
def generatecode():
pass # Do stuff here
I got the same error:
TypeError: test() takes 0 positional arguments but 1 was given
When defining an instance method without self and I called it as shown below:
class Person:
# ↓↓ Without "self"
def test():
print("Test")
obj = Person()
obj.test() # Here
So, I put self to the instance method and called it:
class Person:
# ↓↓ Put "self"
def test(self):
print("Test")
obj = Person()
obj.test() # Here
Then, the error was solved:
Test
In addition, even if defining an instance method with self, we cannot call it directly by class name as shown below:
class Person:
# Here
def test(self):
print("Test")
Person.test() # Cannot call it directly by class name
Then, the error below occurs:
TypeError: test() missing 1 required positional argument: 'self'
But, if defining an instance method without self, we can call it directly by class name as shown below:
class Person:
# ↓↓ Without "self"
def test():
print("Test")
Person.test() # Can call it directly by class name
Then, we can get the result below without any errors:
Test
In detail, I explain about instance method in my answer for What is an "instance method" in Python? and also explain about #staticmethod and #classmethod in my answer for #classmethod vs #staticmethod in Python.
The most upvoted answer does solve this issue,
And just in case anyone is doing this inside of a jupyternotebook. You must restart the kernel of the jupyternotebook in order for changes to update in the notebook
Some environment basics
Python Version: 3.4.2
OS: Windows 8.1
Searching so far, I suspect this other question is related to my issue at hand, but I'm not sure how I'm replicating enough of the same conditions--probably my lack of in-depth python knowledge.
Simplified code to reproduce issue:
Base Class
from PySide.QtGui import *
class Interface(QWidget):
'''
Wrapper base class for GUI input QWidgets:
- buttons
- text fields
- checkboxes
- line edit
- dropdown menu (combo box)
'''
def __init__(self, parent, name, title_txt=None, qt_obj=None,
update_log_method=None):
print('Interface base class constructor has been called.') #DEBUG
self._parent = parent
self.title = None
self.name = name #also text that appears on component
self.qt_obj = qt_obj
self.inheritted_log_method = update_log_method
# don't want to create an empty text QLabel, or one with
# the text reading "None".
if title_txt:
self.title = QLabel(text=title_txt, parent=parent)
print('Interface base class constructor has been completed.') #DEBUG
def get_name(self):
return self.name
def update_log(self, message, level="INFO"):
''' '''
self.inheritted_log_method(message, level)
Inheriting Class
class IFPushButton(Interface):
''' '''
def __init__(self, name, parent, icon=None, update_log_method=None):
''' '''
# print('\n\nCHECKPOINT: pre IFPushButton super()\n\n') #DEBUG
super(IFPushButton, self).__init__(
parent=parent,
name=name,
qt_obj=QPushButton(icon, name, parent),
update_log_method=update_log_method)
self.behaviors = {}
self.qt_obj.clicked.connect(self.activate)
Something to kick it all off
if __name__ == '__main__':
# setup
import sys
app = QApplication(sys.argv)
qmw = QMainWindow()
qcw = QWidget() #central widget
qcl = QVBoxLayout(qcw) #central layout
# experimental
name = 'named button'
ifpb = IFPushButton(name=name, parent=None, icon=None, update_log_method=None)
print("as long a I don't touch the ifpb instance, everything seems to be okay.")
print("...but the second I do...")
qcl.addWidget(ifpb)
self.show()
print("name of created push button:", ifpb.get_name())
# proper teardown
sys.exit(app.exec_())
I run this all inside one module, interface.py, and when I run it...
C:\Path\To\Module> python interface.py
Interface base class constructor has been called.
Interface base class constructor has been completed.
as long a I don't touch the ifpb instance, everything seems to be okay.
...but the second I do...
Traceback (most recent call last):
File "c_interface.py", line 167, in <module>
qcl.addWidget(ifpb)
RuntimeError: '__init__' method of object's base class (IFPushButton) not called.
The part that confuses me is how the print statements in the base class, Intefrace, are obviously being called as they are printing--but it still raises a RuntimeError saying that it hasn't been initialized, and of course fails to get so far as to create the app window. Most of the related messages I've found on stackoverflow are related to people initializing things incorrectly with the super() method--but I have quintuple-checked my super inits, and everything I see tells me it should be working, with the exception of what I linked above.
If I could understand more about why this is happening I'm hoping I can find a way to work around it. Any assistance is much appreciated--thanks in advance!
In the meantime I'm going to try to find how I might be unintentionally deepcopy-ing a C++ object...
EDIT: included the url in the link to other stack overflow post.
Adding a super call to the Interface class constructor is required:
def __init__(self, parent, name, title_txt=None, qt_obj=None, update_log_method=None):
super(Interface, self).__init__(parent)
...
Also, you're calling self.show(), where you probably mean qmw.show().
When I run this code I get the error message:
File "Start.py", line 22, in <module>
c.lo()
TypeError: lo() takes no arguments (1 given)
I don't know exactly why I am getting this error could someone please explain?
I know it's saying that I put an argument when calling that function but I don't understand why that is?
If someone could shed some light on this issue that would be great.
import subprocess as sp
import Tkinter as Tk
from Tkinter import *
root = Tk()
text = Text(root)
class Console:
def Start():
proc = sp.Popen(["java", "-Xmx1536M", "-Xms1536M", "-jar", ".jar"],stdin=sp.PIPE,stdout=sp.PIPE,)
def lo():
while True:
line = proc.stdout.readline()
text.insert(INSERT,line)
text.pack()
if (line == "Read Time Out"):
proc.stdin.write('stop')
if (line == "Unloading Dimension"):
text.insert(INSERT,"Ready for command")
text.pack()
c = Console()
c.Start()
c.lo()
root.mainloop()
Methods always get the instance as the first argument.
Your method definitions should look like:
def some_method(self):
# do_stuff
In short, that is because lo() is a method of the class Console which is always passed the instance as first argument. So lo() must define a parameter (mostly called self) to hold that argument:
class Console:
def start(self): # functions and methods should have lowercase names
self.proc = sp.Popen(...)
def lo(self):
line = self.proc.stdout.readline()
...
I am surprised that your Start() call worked; it has the same issue.