-1

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()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
Mike - SMT
  • 14,784
  • 4
  • 35
  • 79
  • 1
    Why are you explicitly passing `self`? – Stephen Rauch Jun 02 '18 at 01:37
  • @StephenRauch well I have been passing self in lots of programs I made as the controller and they all seam to work as expected. Is there something wrong with passing self? I must be severely mistaken on the use here. – Mike - SMT Jun 02 '18 at 01:38
  • 1
    `self` is passed implicitly when you call an instance method on an instance. – user3483203 Jun 02 '18 at 01:38
  • @chrisz Interesting. I need to go back and look at all my other projects and see why my code is working as expected even though I am passing self implicitly. Just when I thought I knew how classes worked I find myself making a code breaking error. – Mike - SMT Jun 02 '18 at 01:40
  • @chrisz But self is not passed implicitly otherwise. It is perfectly normal to pass self to a function, especially in GUI programming where each window needs a parent. That parent is often self. – Paul Cornelius Jun 02 '18 at 01:41
  • There are cases when you pass self explicitly, but those cases are generally not the norm. – Stephen Rauch Jun 02 '18 at 01:42
  • @StephenRauch well removing self is not helping here. I just end up getting `AttributeError: 'str' object has no attribute 'tk'` and now that problem seams to be less obvious to me then it probably should be. I have not had this problem in the past when passing arguments to other classes that inherit from tk modules. – Mike - SMT Jun 02 '18 at 01:47
  • Nowhere in this code snippet is self passed implicitly. That would occur, for example, if you inserted the line `App.fakeError()` immediately after `App=MintApp()`. Python will call the function `fakeError` in the class `MintApp` and supply self implicitly. In that case `self` would be the same object as `App`. This is basic Python OOP. – Paul Cornelius Jun 02 '18 at 01:48
  • @chrisz the Q/A you linked is not the same issue. That is an issue with methods inside of a class not sending arguments to a different class. – Mike - SMT Jun 02 '18 at 01:49
  • @PaulCornelius Thank you for the info that was something I did not know. However I am still unable to correct the error I am having and I do not see what is the cause. I have been looking all over for half the day and just don't see this problem somewhere else and not sure what the solution would be. I am sure once I figure it out it will be one of those things that seams obvious. – Mike - SMT Jun 02 '18 at 01:51
  • If the traceback says you are passing 4 and you are actually passing only 3, does the function call look something like `a.f(b, c, d)`? In that case, the function will probably be a member function of an object you have named "a". Python will automatically supply a fourth argument, which becomes "self" in the method declaration of the function. That variable, "self", represents the object 'a' in the context of the function. The function declaration, inside a class statement, will look like `def f(self, b, c, d)`. Four arguments, not three. – Paul Cornelius Jun 02 '18 at 01:57
  • @PaulCornelius I am calling the toplevel class with `topErrorWindow(self, message, detail)` so it is not `a.f()` but just `f()`. Maybe I just dont see what you mean. If you look at my last section of code please tell me where the actual issue is. I just don't see it. I have been passing self as an argument for so many programs I have wrote without running into this issue. – Mike - SMT Jun 02 '18 at 02:02
  • I guess I will just have to sleep on it. I am not seeing the problem and no one seams to want to point it out directly. Side note the downvote is not very helpful without knowing why the vote was casted. I think my answer fits perfectly well withing good question guidelines and I do not see any linked "duplicates" that are actually duplicates and help with the problem. – Mike - SMT Jun 02 '18 at 02:06
  • 1
    `tk.Toplevel.__init__()` takes one optional parameter, `master`. You are also passing it your `message` and `detail` parameters, which it has no idea what to do with - thus the error. – jasonharper Jun 02 '18 at 02:21
  • @jasonharper and there it is. The simple mistake I should have seen and no one wanted to point out. Thanks Jason that was a lot more of a headache then it should have been. That fixed the problem. – Mike - SMT Jun 02 '18 at 02:30
  • @Mike-SMT, please be careful with the language of *"No one wanted to point it out"*. This language assumes that someone knew the answer but withheld it for some reason. I looked at this, and couldn't see the problem. I tried to point out what I saw as odd, which was the best I could manage. I was trying to help. Please assume that others were also trying to help. You got one random downvote, but this is very minor. Just write it off to someone in bad mood. Cheers, --Stephen – Stephen Rauch Jun 02 '18 at 02:37
  • You might be interested in https://docs.python.org/3/tutorial/classes.html, the Python tutorial, section 9.3.4. The meaning of self in classes and functions is explained there. – Paul Cornelius Jun 02 '18 at 04:26
  • 1
    @chrisz: in this specific case, passing `self` is the right thing to do because it is _not_ implicitly passed. Calling the `__init__` of a superclass inside the `__init__` of a subclass is the proper thing to do. – Bryan Oakley Jun 02 '18 at 12:37
  • @StephenRauch You miss quoted me. "no one `seams` to want to point it out ". Is not the same thing. When you are quoting someone and you remove or add words you are altering the meaning. I didn't say you didn't try to help. In fact I appreciate all the input. I always do. Lastly I always ask for a reason for a downvote if I get them. I cannot improve my questions if I don't know why the downvote exist. – Mike - SMT Jun 02 '18 at 14:35

1 Answers1

2

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)
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Thanks Bryan. It was one of those problems that I needed to walk away from and come back to in order to see the obvious issue. I should have been able to see this but for some reason no mater how much I stared at the code it never hit me. – Mike - SMT Jun 02 '18 at 14:39
  • Is there any comment you can make on the portion of my test code. It prints 3 lines and the first line is a period. I think I was expecting to see the self object print at the first line so what is the period coming from? – Mike - SMT Jun 02 '18 at 14:41
  • @Mike-SMT: the period is the internal name of the root window, which is what you get when you get the string representation of the window. – Bryan Oakley Jun 02 '18 at 14:44
  • Oh. Interesting. I guess I need to find some more documentation on classes and self. There are several things I am unclear on that I just found out about. Thanks again as always your input is educational. – Mike - SMT Jun 02 '18 at 14:45