1

I am using Kivy with Python 3.5. I'm trying to set up an App where a button press schedules a function call. A premise: this is my first application with Kivy, and I am not very good with Python. Here's my simplified code:

class MyApp(App):
    def build(self):
        layout = GridLayout(cols=2)
        TextStream = Label(text = 'Something will be written here: ')
        StartButton = Button(text = 'Start writing')
        StartButton.bind(on_press=lambda x:self.start_program(freq=10))
        layout.add_widget(TextStream)
        layout.add_widget(StartButton)
        return layout

    def start_program(self, freq):
        Clock.schedule_interval(self.write_something, 1.0/freq)
        # Also tried Clock.schedule_interval(self.write_something(), 1.0/freq)

    def write_something(self):
        TextStream.text =+ 'Something '

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

What I get when I run the script is:

TypeError: write_something() takes 1 positional argument but 2 were given

Reading the answers to this question, about this specific error, I understood that methods in Python are actually implemented differently from how they appear in code.

More precisely, from this comment I understand that properly declaring the method write_something giving it self as argument is the correct way to do it. Also, from this answer I get that the number of passed arguments counted by Python should be 1+N, where N are passed in the call. I am not passing any argument in the call however.

So, are there some silent arguments passed with Kivy? Am I calling the method in the wrong way?

Edit - Error stack

As suggested by a comment, I include the entire error stack:

Traceback (most recent call last):

  File "<ipython-input-1-5d17b5569154>", line 1, in <module>
    runfile('/home/raggot/Projects/MyApp/scripts/_test_kivy.py', wdir='/home/raggot/Projects/MyApp/scripts')

  File "/usr/local/lib/python3.5/dist-packages/spyder/utils/site/sitecustomize.py", line 705, in runfile
    execfile(filename, namespace)

  File "/usr/local/lib/python3.5/dist-packages/spyder/utils/site/sitecustomize.py", line 102, in execfile
    exec(compile(f.read(), filename, 'exec'), namespace)

  File "/home/raggot/Projects/MyApp/scripts/_test_kivy_camera.py", line 78, in <module>
    MyApp().run()

  File "/usr/local/lib/python3.5/dist-packages/kivy/app.py", line 826, in run
    runTouchApp()

  File "/usr/local/lib/python3.5/dist-packages/kivy/base.py", line 502, in runTouchApp
    EventLoop.window.mainloop()

  File "/usr/local/lib/python3.5/dist-packages/kivy/core/window/window_pygame.py", line 403, in mainloop
    self._mainloop()

  File "/usr/local/lib/python3.5/dist-packages/kivy/core/window/window_pygame.py", line 289, in _mainloop
    EventLoop.idle()

  File "/usr/local/lib/python3.5/dist-packages/kivy/base.py", line 337, in idle
    Clock.tick()

  File "/usr/local/lib/python3.5/dist-packages/kivy/clock.py", line 581, in tick
    self._process_events()

  File "kivy/_clock.pyx", line 384, in kivy._clock.CyClockBase._process_events

  File "kivy/_clock.pyx", line 414, in kivy._clock.CyClockBase._process_events

  File "kivy/_clock.pyx", line 412, in kivy._clock.CyClockBase._process_events

  File "kivy/_clock.pyx", line 167, in kivy._clock.ClockEvent.tick

TypeError: write_something() takes 1 positional argument but 2 were given
raggot
  • 992
  • 15
  • 38
  • 1
    What happens if you remove `()` from `self.write_something()` in `start_program()`? Please include the full traceback – roganjosh Oct 06 '18 at 21:03
  • change to `Clock.schedule_interval(self.write_something, 1.0/freq)`. schedule_interval you want to pass the function, and you are passing the evaluated function. – eyllanesc Oct 06 '18 at 21:14
  • what is `InfoStream`? – eyllanesc Oct 06 '18 at 21:15
  • @roganjosh, I actually tried both. The resulting error was the same – raggot Oct 06 '18 at 21:49
  • @raggot change to `Clock.schedule_interval(self.write_something, 1.0/freq)` and `def write_something(self, *args):` – eyllanesc Oct 06 '18 at 21:53
  • @eyllanesc: Thank you, that worked! Or well, it triggered another error because `write_something` does not have access to the object `TextStream`, but at least the call goes through. If you can elaborate what happens in an answer I'll be happy to accept it. – raggot Oct 06 '18 at 21:58

1 Answers1

1

When it connects any event, in this case schedule_interval Kivy passes additional arguments to it, for that reason it throws you that error, in your case it only uses args and you don't have any problem. In the case of Clock, it passes the dt which is the exact call time.

def start_program(self, freq):
    Clock.schedule_interval(self.write_something, 1.0/freq)

def write_something(self, *args):
    print(args)
raggot
  • 992
  • 15
  • 38
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thanks! Now I understand why examples scripts of Kivy included `**kwargs` as an extra input. Do you know why the `**kwargs` rather than `*args`? – raggot Oct 06 '18 at 22:09
  • @raggot Do you understand that they are the `*args`, and `**kwargs`? Do you know the difference? – eyllanesc Oct 06 '18 at 22:13
  • Google just instructed me about it. Appreciate your help! – raggot Oct 06 '18 at 22:18