incoherence: ids in kv and python code

26 views
Skip to first unread message

Tomek CEDRO

unread,
Nov 30, 2022, 11:54:51 PM11/30/22
to kivy-...@googlegroups.com
Hello world :-)

I just found first totally incoherent thing in Kivy: ids are only for
kv files, but, there are also id and ids fields in the python code of
the components, but they are empty.

I need to create complex messy code to find a component that I need in
my custom components.

Having id and ids both in kv files and python code would make life so
much easier and coherent.

What is the reason behind this incoherence and what are proposed solutions?

I can see lots of people have this problem.

Any hints welcome :-)
Tomek

--
CeDeROM, SQ7MHZ, http://www.tomek.cedro.info

Elliot Garbus

unread,
Dec 1, 2022, 12:03:30 AM12/1/22
to kivy-...@googlegroups.com

The id identifiers are create in the kv file, and when the kv file is processed and ids dict is created.  This dict can be accessed from kv or python.

See: https://kivy.org/doc/stable/api-kivy.lang.html?highlight=lang#ids

https://kivy.org/doc/stable/api-kivy.uix.widget.html?highlight=ids#kivy.uix.widget.Widget.ids

 

if your kv rule has defined id’s and your ids dict is empty – the problem could be that you are trying to access the ids in __init__.  The ids are not yet set at the time the object is created, instead use on_kv_post.  This is called after the widgets kv code has been processed. 

 

From the widget docs: https://kivy.org/doc/stable/api-kivy.uix.widget.html?highlight=widget#kivy.uix.widget.Widget

 

on_kv_post(base_widget, )

Fired after all the kv rules associated with the widget and all other widgets that are in any of those rules have had all their kv rules applied. base_widget is the base-most widget whose instantiation triggered the kv rules (i.e. the widget instantiated from Python, e.g. MyWidget()).

Hope that helps!

--

You received this message because you are subscribed to the Google Groups "Kivy users support" group.

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.

To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CAFYkXjnkMVbNvB6LNNtj30nYAnDB3TXmXcjqD5vUWGNqLQvQvA%40mail.gmail.com.

 

Tomek CEDRO

unread,
Dec 1, 2022, 12:51:53 AM12/1/22
to kivy-...@googlegroups.com
Thanks Elliot for quick response :-)

The problem is that this ids list is empty for every component
(children iterated from root and my component ids) and it is not a
call from __init__().

Call is made from within kv file:
#:import MyComponent lib.components
MyComponent:
id: button
on_press: self.do_something(app=app)

Then I have this lib.components.MyComponent.py with do_something()
async method launch and done_something() callback.

By the way do you know is there any way to access app from withing a
component method without passing app as parameter?

I am trying to work with rest api, using httpx and asyncclient with
asyncio. It works quite well. I was wondering how to put my custorm
handlers and callbacks in the kivy application and found out that I
can create custom components that will do the job while still having
access to app that stores the api session etc. Is this a good
approach? This way I can only load components and import their
dependencies on demand.

Thank you for any hints! :-)

Elliot Garbus

unread,
Dec 1, 2022, 6:01:06 PM12/1/22
to kivy-...@googlegroups.com

By the way do you know is there any way to access app from withing a

component method without passing app as parameter?

 

https://kivy.org/doc/stable/api-kivy.app.html?highlight=get_running#kivy.app.App.get_running_app

 

In the method I typically would write:

app = App.get_running_app()

so the “kv string” looks the same in python or kv.

 

On to ids… in your example

MyComponent:

  id: button

  on_press: self.do_something(app=app)

 

This id will now be added to the ids dict.  It is redundant.  This is the self object to root of the ids dict.

You would use the id to address the nested components.  This works for the root widget or rule.  Each kv rule has its own ids dict.

 

BoxLayout:  # root widget has an ids dict

    Button:

        id:button_1

    Button:

        id: button_2

    MyBoxLayout:

        id: my_boxlayout

 

<MyBoxLayout>:  # kv rule has an ids dict

    Button:

        id:button_1

    Button:

        id: button_2

 

I did not quite understand your question about asyncio and kivy.  I have been using Trio (an asycio framework) with httpx – but have not yet had an opportunity to integrate async with kivy. 

For light networking in kivy I use urlrequest: https://kivy.org/doc/stable/api-kivy.network.urlrequest.html?highlight=urlrequest#module-kivy.network.urlrequest

It integrates easily into the kivy callback model.    

 

If you have an example where you are having trouble with ids, feel free to share some code.

--

You received this message because you are subscribed to the Google Groups "Kivy users support" group.

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.

Tomek CEDRO

unread,
Dec 2, 2022, 8:13:07 PM12/2/22
to kivy-...@googlegroups.com
Thank you Elliot :-)

I did a simple application to print out the ids.. and it prints them correctly:

#!/usr/bin/env python3

from kivymd.app import MDApp
from kivy.lang import Builder
from kivymd.uix.button import MDFlatButton


class MyButton(MDFlatButton):
def __init__(self, *args, **kwargs):
super(MDFlatButton, self).__init__(*args, **kwargs)

def print_ids(self, app):
print('MyButton.self.ids: ' + str(self.ids.keys()))
print('MyButton/from_kv_app.root.ids: ' + str(app.root.ids.keys()))
a = MDApp.get_running_app()
print('MyButton/MDApp.get_running_app().root.ids: ' +
str(a.root.ids.keys()))

kv = '''
MDBoxLayout:
orientation: 'vertical'
MDFlatButton:
id: mdflatbutton
on_press: print('MDFlatButton.on_click/root.ids: ' +
str(root.ids.keys()))
text: 'MDFlatButton'
MyButton:
id: mybutton
on_press: self.print_ids(app=app)
text: 'MyButton'
'''

class MyApp(MDApp):
def build(self):
return Builder.load_string(kv)

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


But in my bigger application all ids are empty :-(

No matter what I use all ids are empty inside my component's python code:
1. Passing app from kv to py, then app.root.ids is empty.
2. Calling MDApp.get_running_app().ids is empty.
3. self.ids is also empty.

So I tried to print the ids straight from my kv file:
1. When using app.root.ids list is empty.
2. When using root.ids I found the components on the list.

I am clearly doing something wrong, or I do not understand the order
on which things are loaded and then assigned..?

Organization of my project (lets call it mystuff) is following:

./main.py <- app loader
./mystuff <- here is python module
./mystuff/api <- here is rest api part
./mystuff/someothestuff <- other modules as part of the bundle
...
./mystuff/app <- here is the kivy app
./mystuff/app/main.py <- kivy app main
./mystuff/app/myapp.kv <- top level ui kv
./mystuff/app/components <- python code for ui objects
./mystuff/app/components/mybutton.py <- here is my button code
./mystuff/app/screens <- kv screen manager screens
./mystuff/app/screens/screen1.kv <- here is screen that uses mybutton

This is done that way because kivy app is only part of the bigger
module bindle (mystuff) that contains also rest api module etc that
can be used outside kivy app for science data processing with no gui
at all. I am writing a bundle that can be used with no kivy app, but
also kivy app makes use of it.

I also do not import all components in ./mystuff/app/main.py to
conserve memory and load time.. python code of the mybutton is
imported inside kv of the screen that will use it.

Maybe this is the problem?

Question remains why MDApp.get_running_app() returns object with empty
ids? This should be most universal way right no matter where I call it
in the already running application?

The same when I pass app from kv to python code.

This seems to be the same instance of the running app but for some
reason is has empty ids.

Even printing app.root.ids directly from the kv code in my app returns
empty dict.


Any hints appreciated! :-)

Elliot Garbus

unread,
Dec 2, 2022, 8:37:11 PM12/2/22
to kivy-...@googlegroups.com

I’m not sure what the problem is.  Could you have possibly created 2 App instances? 

 

 

From: Tomek CEDRO
Sent: Friday, December 2, 2022 6:13 PM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] incoherence: ids in kv and python code

 

Thank you Elliot :-)

--

You received this message because you are subscribed to the Google Groups "Kivy users support" group.

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.

Elliot Garbus

unread,
Dec 2, 2022, 8:41:30 PM12/2/22
to kivy-...@googlegroups.com

Another possibility – are you sure you are only loading the kv files once?  Kivy will try to load a kv file with the name of your app by default.  If you have a kv file with the name of your app – it is possible that it is being loaded twice.

 

Example:

class MyExcellentApp(MDApp):

 

Will load myexcellent.kv automagically. If you are also loading this file with a Builder.load_file() this could cause a problem.

Tomek CEDRO

unread,
Dec 2, 2022, 8:48:46 PM12/2/22
to kivy-...@googlegroups.com
On Sat, Dec 3, 2022 at 2:41 AM Elliot Garbus wrote:
>
> Another possibility – are you sure you are only loading the kv files once? Kivy will try to load a kv file with the name of your app by default. If you have a kv file with the name of your app – it is possible that it is being loaded twice.
>
> Example:
> class MyExcellentApp(MDApp):
> …
> Will load myexcellent.kv automagically. If you are also loading this file with a Builder.load_file() this could cause a problem.

Nope, no Build.load_files() used, kv file is named as the app and it
is loaded by kivy.

All seems to work fine except ids..


> I’m not sure what the problem is. Could you have possibly created 2 App instances?

Only one instance.


I think similar problem is described here:
https://github.com/kivy/kivy/issues/7607#issuecomment-1333159029


o_O

Elliot Garbus

unread,
Dec 2, 2022, 11:02:10 PM12/2/22
to kivy-...@googlegroups.com
The reported GitHub issue does not look like a bug, it looks like a user issue.

If you can share your code I’ll take a look.

Sent from my iPhone

> On Dec 2, 2022, at 6:48 PM, Tomek CEDRO <to...@cedro.info> wrote:
> --
> You received this message because you are subscribed to the Google Groups "Kivy users support" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/CAFYkXjk4N1iom8_bEMLTNkQkpmq4JeE2%2BuLSK0v%2BjJ%2B23SKd%3Dg%40mail.gmail.com.

Elliot Garbus

unread,
Dec 2, 2022, 11:16:24 PM12/2/22
to kivy-...@googlegroups.com

I thought this might be helpful…

Looking at the code in the github issue:

The root widget is a ScreenManager declared in the build method, and 2 screens are added.  There for:

self.root is the screen manager.  self.root.ids should be empty, the ids are in the screens.  To get the ids from the screen named ‘menu’, would require:

 

self – In this context self is MDApp

self.root – The screenmanager

self.root.get_screen(‘menu’) – The menu screen

self.root.get_screen(‘menu’).ids

 

Let me know if this helps…

 

 

From: Elliot Garbus
Sent: Friday, December 2, 2022 9:02 PM
To: kivy-...@googlegroups.com
Subject: Re: [kivy-users] incoherence: ids in kv and python code

 

The reported GitHub issue does not look like a bug, it looks like a user issue.

Tomek CEDRO

unread,
Dec 2, 2022, 11:23:02 PM12/2/22
to kivy-...@googlegroups.com
On Sat, Dec 3, 2022 at 5:16 AM Elliot Garbus wrote:
> I thought this might be helpful…
> Looking at the code in the github issue:
>
> The root widget is a ScreenManager declared in the build method, and 2 screens are added. There for:
>
> self.root is the screen manager. self.root.ids should be empty, the ids are in the screens. To get the ids from the screen named ‘menu’, would require:
>
> self – In this context self is MDApp
>
> self.root – The screenmanager
>
> self.root.get_screen(‘menu’) – The menu screen
>
> self.root.get_screen(‘menu’).ids

MAAAAN YOU ARE MY HERO!!!!! THANK YOU ELLIOT!!! :-)

I think this IDS part needs some more explanation in the docs.. its
not that obvious at first with multiple screens.. lots of people seems
to stop here :-) :-) :-)

How can I get you a beer? :-) :-)

Thanks again!! :-)
Tomek

Elliot Garbus

unread,
Dec 2, 2022, 11:28:21 PM12/2/22
to kivy-...@googlegroups.com
😎
Glad to hear that solved your problem!  

Sent from my iPhone

On Dec 2, 2022, at 9:23 PM, Tomek CEDRO <to...@cedro.info> wrote:

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages