TypeError: 'weakproxy' object is not callable

1,133 views
Skip to first unread message

John Boyd

unread,
Jan 1, 2014, 8:18:25 PM1/1/14
to kivy-...@googlegroups.com
Hello ,

I am a new user of of Kivy, and I am also learning Python.

I am doing a Point Of Sale system but I am having a problem fully understanding how to access kv ids from the actual python code.

The idea is that a  barcode will be inputted to the TextInput(id: barcode_input) and on pressing "enter" the necessary info will be retrieved
from the database and a row of information will be added to a GridLayout(id: purchase) located in a ScrollView, finally TextInput(id: barcode_input will get  focus again.

The main class - Invoice has an 'add_row' function which adds a row of info.. For brevity sake, I am reusing the HeaderBar class in place of the database lookup, for asking this question. So far I can successfully add a row, but I am unable to refocus the TextInput widget using
"self.ids.barcode_input(focus=True)" .

I get the following:
Traceback (most recent call last):
   
File "/home/john/kivy-pos5/main.py", line 18, in <module>
     
PosApp().run()
   
File "/usr/lib/python2.7/dist-packages/kivy/app.py", line 600, in run
     runTouchApp
()
   
File "/usr/lib/python2.7/dist-packages/kivy/base.py", line 454, in runTouchApp
     
EventLoop.window.mainloop()
   
File "/usr/lib/python2.7/dist-packages/kivy/core/window/window_pygame.py", line 325, in mainloop
     
self._mainloop()
   
File "/usr/lib/python2.7/dist-packages/kivy/core/window/window_pygame.py", line 292, in _mainloop
     
self.modifiers):
   
File "_event.pyx", line 281, in kivy._event.EventDispatcher.dispatch (kivy/_event.c:4136)
   
File "/usr/lib/python2.7/dist-packages/kivy/core/window/__init__.py", line 129, in _on_window_key_down
     
return self.dispatch('on_key_down', keycode, text, modifiers)
   
File "_event.pyx", line 281, in kivy._event.EventDispatcher.dispatch (kivy/_event.c:4136)
   
File "/usr/lib/python2.7/dist-packages/kivy/uix/textinput.py", line 1630, in _keyboard_on_key_down
     
self._key_down(key)
   
File "/usr/lib/python2.7/dist-packages/kivy/uix/textinput.py", line 1577, in _key_down
     
self.dispatch('on_text_validate')
   
File "_event.pyx", line 281, in kivy._event.EventDispatcher.dispatch (kivy/_event.c:4136)
   
File "/home/john/kivy-pos5/pos.kv", line 1, in <module>
     
#:kivy 1.7.2
   
File "/home/john/kivy-pos5/invoice.py", line 20, in add_row
     
self.ids.barcode_input(focus=True)
 
TypeError: 'weakproxy' object is not callable



I am hoping someone would be kind enough to tell me what I am doing wrong.

See my code below:

pos.kv
#:kivy 1.7.2
<Invoice>:
    rows
:6
    today
:today
    invoice_no
:invoice_no
    barcode_input
: barcode_input
    query_result
:query_result
    purchase
: purchase
   
AdminGrid:
        cols
:4
       
AdminBtn:
            text
: "Admin"
       
AdminBtn:
            text
: "Inventory"
       
AdminBtn:
            text
: "Reports"
       
AdminBtn:
            text
: "Help"
   
GridLayout:
        cols
:2
        size_hint_y
: None
        row_force_default
: True
        row_default_height
: 40
        height
:self.minimum_height
       
Label:
            id
: today
            size_hint_y
: None
            text_size
: self.size
            halign
: "left"
            height
: 40
       
Label:
            id
: invoice_no
            size_hint_y
: None
            text_size
:self.size
            halign
:"right"
            height
:40
   
BarcodeSearch:
       
TextInput:
            id
: barcode_input
            multiline
: False
            on_text_validate
: root.add_row()
       
Label:
            id
: query_result
   
HeaderBar:
   
ScrollView:
        scroll_y
:0
       
ScrollBox:
            id
: purchase
           
           
<ScrollBox@GridLayout>:
    cols
:1
    height
: self.minimum_height
    size_hint
:1, None
<BarcodeSearch@GridLayout>:
    cols
:2
    size_hint_y
: None
    row_force_default
: True
    row_default_height
: 40
    height
:self.minimum_height
<HeaderBar>:
    row_default_height
: 40
    row_force_default
: True
    cols
: 9
    height
:self.minimum_height
<AdminGrid@GridLayout>:
    size_hint_y
: None
    row_force_default
: True
    row_default_height
: 40
    height
:self.minimum_height
<AdminBtn@Button>:
    size_hint_y
: None
    height
:40

headerbar.py
import kivy

from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label

HEADER_NAMES
=["", "Barcode", "Description", "Price", "Vat", "Qty", "Vat Sub.", "Total",""]
LABEL_SIZES
= [.04, .16, .30, .10, .04, .06, .13, .15, .04]

class HeaderBar(GridLayout):
   
def __init__(self, **kwargs):
       
super(HeaderBar, self).__init__(**kwargs)
       
       
for name, size in zip(HEADER_NAMES, LABEL_SIZES):
           
self.add_widget(Label(text=name, size_hint_x=size))


invoice.py
import kivy
kivy
.require('1.7.2')
from kivy.uix.gridlayout import GridLayout

from kivy.properties import ObjectProperty
from headerbar import HeaderBar

class Invoice(GridLayout):
    today
= ObjectProperty(None)
    invoice_no
= ObjectProperty(None)
    barcode_input
= ObjectProperty(None)
    query_result
= ObjectProperty(None)
    purchase
= ObjectProperty(None)
   
def __init__(self, **kwargs):
       
super(Invoice, self).__init__(**kwargs)
       
   
def add_row(self):
        line
= HeaderBar()
       
self.purchase.add_widget(line)
       
self.ids.barcode_input(focus=True)
       
print self.ids

and finally;

main.py
import kivy
kivy
.require('1.7.2')
from kivy.uix.gridlayout import GridLayout

from kivy.properties import ObjectProperty
from headerbar import HeaderBar

class Invoice(GridLayout):
    today
= ObjectProperty(None)
    invoice_no
= ObjectProperty(None)
    barcode_input
= ObjectProperty(None)
    query_result
= ObjectProperty(None)
    purchase
= ObjectProperty(None)
   
def __init__(self, **kwargs):
       
super(Invoice, self).__init__(**kwargs)
       
   
def add_row(self):
        line
= HeaderBar()
       
self.purchase.add_widget(line)
       
self.ids.barcode_input(focus=True)
       
print self.ids

Best Regards and Happy New Year to All,

John

 

John Boyd

unread,
Jan 1, 2014, 8:28:12 PM1/1/14
to kivy-...@googlegroups.com


Sorry,

main.py should be :
import kivy
kivy
.require('1.7.2')

from kivy.app import App
from kivy.config import Config
Config.set("graphics", "width", "1000")
Config.set("graphics", "height", "600")
from kivy.core.window import Window

from invoice import Invoice


class PosApp(App):
   
def build(self):
       
return Invoice()
   
if __name__ == "__main__":
   
PosApp().run()

 

 

ZenCODE

unread,
Jan 2, 2014, 3:02:55 PM1/2/14
to kivy-...@googlegroups.com
Greetings

I think that should be (in your py file):

    self.ids.barcode_input.focus=True

Cheers

John Boyd

unread,
Jan 2, 2014, 4:25:50 PM1/2/14
to kivy-...@googlegroups.com
Thanks for the reply ZenCODE,

When I do as suggested, the error message(s) disappear but the TextInput widget does not take focus.

John.




On Wednesday, January 1, 2014 9:18:25 PM UTC-4, John Boyd wrote:

ZenCODE

unread,
Jan 2, 2014, 9:36:55 PM1/2/14
to kivy-...@googlegroups.com
Hmm. That might be because it's being called from the TextInput "on_text_validate" which also removes focus from the TextInput. It might be worth putting in the a clock callback, something like:

    clock.schedule_once(lambda dt:self.ids.barcode_input.focus=True)



John Boyd

unread,
Jan 3, 2014, 12:29:32 AM1/3/14
to kivy-...@googlegroups.com
Thanks ZenCODE,

I must confess that I do not understand the use of lambda intuitively as yet, so when I added "Clock.schedule_once(lambda dt:self.ids.barcode_input.focus=True)" to my add_row function. I got the following error message :

    Clock.schedule_once(lambda dt:self.ids.barcode_input.focus=True)
 
SyntaxError: lambda cannot contain assignment

However after reading the kivy.clock docs I wrote a callback in invoice.py:
def input_focus(self, dt):
       
self.ids.barcode_input.focus=True

Then in the add_row function I added:
Clock.schedule_once(self.input_focus)

And now the TextInput is getting focus and it is working as I want it to.

I do have to figure out how these lambda statements work though. : )

John.

P.S. Feel free to comment about the lambda error if you wish.










 

On Wednesday, January 1, 2014 9:18:25 PM UTC-4, John Boyd wrote:

ZenCODE

unread,
Jan 3, 2014, 3:14:11 AM1/3/14
to kivy-...@googlegroups.com
Great, glad that worked for you.

As far as lambda's go, they are just shorthand for function definitions. What you did was exactly the same as what I was trying.

So,

    add2 = lambda x, y: x + y

creates a function that accepts two parameters and adds them. It's exactly the same as.

    def add2(x, y)
        return x + y

Both allow

    >>> add2(1, 2)
    3

It's just shorter, but has limitations, as we've just seen by your errors. But still, they are very nice for creates function on the fly..

http://www.secnetix.de/~olli/Python/lambda_functions.hawk

Cheers

John Boyd

unread,
Jan 3, 2014, 10:35:54 AM1/3/14
to kivy-...@googlegroups.com
Thanks for lambda resource ZenCODE,

I read the tutorial, I also read : http://pythonconquerstheuniverse.wordpress.com/2011/08/29/lambda_tutorial/
which was more understandable to me.

Based on what I read, and the lambda error message that came up, did the lambda method not work because "lambda dt:self.ids.barcode_input.focus=True" does not return a value ?

I quote( from my lambda tutorial link):

And for that question, I think a few simple rules of thumb will be sufficient.

  • If it doesn’t return a value, it isn’t an expression and can’t be put into a lambda.
  • If you can imagine it in an assignment statement, on the right-hand side of the equals sign, it is an expression and can be put into a lambda.

John.
 
On Wednesday, January 1, 2014 9:18:25 PM UTC-4, John Boyd wrote:

ZenCODE

unread,
Jan 3, 2014, 1:07:55 PM1/3/14
to kivy-...@googlegroups.com
Yes, exactly. lambda functions implicitly return a value, so can only contain expressions that evaluate to something. Funny, I've used the lots, but only really clarified this now. Guess I luckily just always used them that way. Thanks ;-)

ZenCODE

unread,
Jan 3, 2014, 1:16:00 PM1/3/14
to kivy-...@googlegroups.com
Just as an example of how they can be really nice because you can really re-use functions, minimizing the amount to functions you need to do complex thigns.

   
def some_cool_func(self, *args, **kwargs):
       
# Black magic happens here

    button1
.bind(on_release=lambda btn: self.some_cool_func(1, 2))
    button2
.bind(on_release=lambda btn: self.some_cool_func(reset=True))
    button3
.bind(on_release=lambda btn: self.some_cool_func(1, 2, button=btn))



No need to define callbacks for each button. You gotta love the snake ;-)

Peace.


Reply all
Reply to author
Forward
0 new messages