kivy / kivy

Open source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS
https://kivy.org
MIT License
17.73k stars 3.07k forks source link

DictProperty and ListProperty creation fails within kv, when values are other than strings or integers #2457

Open dessant opened 10 years ago

dessant commented 10 years ago

I have tested with values like True, False, None and a kivy widget class, other property types may be affected too.

from kivy.app import App
from kivy.lang import Builder
from kivy.factory import Factory
from kivy.uix.button import Button

kv = """
#: import BoxLayout kivy.uix.boxlayout.BoxLayout

<NewB@Widget>:
    l1: [1, 'hgfh']

    l2: [BoxLayout]
    l3: [True, False]
    d: {'id': None}

<Test>:
    text: 'Print property types'
    on_press: root.callback()
"""

Builder.load_string(kv)

class Test(Button):

    def callback(self):
        new = Factory.NewB()
        print(type(new.l1))
        print(type(new.l2))
        print(type(new.l3))
        print(type(new.d))

class TestApp(App):
    def build(self):
        return Test()

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

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

matham commented 10 years ago

The code below is a staring point to fix the issue. I did not check though if it'd work with templates. Also, if the list/dict is using a kv available keyword (e.g. root) it might still not work because at the point that we create the missing props, we have not initialized the idmap with those keywords.

diff --git a/kivy/lang.py b/kivy/lang.py
index 458cef4..d3c9c1f 100755
--- a/kivy/lang.py
+++ b/kivy/lang.py
@@ -224,7 +224,7 @@ Examples of valid statements are:
 An example of a invalid statement:

 .. code-block:: python
-
+
     on_state:
         if self.state == 'normal':
             print('normal')
@@ -1032,7 +1032,12 @@ class ParserRule(object):
                 continue
             value = self.properties[name].co_value
             if type(value) is CodeType:
-                value = None
+                idmap = copy(global_idmap)
+                idmap['self'] = widget.proxy_ref
+                try:
+                    value = eval(value, idmap)
+                except:
+                    value = None
             widget.create_property(name, value)

     def _forbid_selectors(self):
stale[bot] commented 7 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.