{"action":"created","issue":{"url":"https://api.github.com/repos/kivy/kivy/issues/2860","labels_url":"https://api.github.com/repos/kivy/kivy/issues/2860/labels{/name}","comments_url":"https://api.github.com/repos/kivy/kivy/issues/2860/comments","events_url":"https://api.github.com/repos/kivy/kivy/issues/2860/events","html_url":"https://github.com/kivy/kivy/issues/2860","id":54546747,"number":2860,"title":"Allow property creation for widget instances","user":{"login":"dessant","id":7513068,"avatar_url":"https://avatars.githubusercontent.com/u/7513068?v=3","gravatar_id":"","url":"https://api.github.com/users/dessant","html_url":"https://github.com/dessant","followers_url":"https://api.github.com/users/dessant/followers","following_url":"https://api.github.com/users/dessant/following{/other_user}","gists_url":"https://api.github.com/users/dessant/gists{/gist_id}","starred_url":"https://api.github.com/users/dessant/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dessant/subscriptions","organizations_url":"https://api.github.com/users/dessant/orgs","repos_url":"https://api.github.com/users/dessant/repos","events_url":"https://api.github.com/users/dessant/events{/privacy}","received_events_url":"https://api.github.com/users/dessant/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/kivy/kivy/labels/feature","name":"feature","color":"bfd4f2"},{"url":"https://api.github.com/repos/kivy/kivy/labels/PR","name":"PR","color":"009800"}],"state":"open","locked":false,"assignee":{"login":"matham","id":1644286,"avatar_url":"https://avatars.githubusercontent.com/u/1644286?v=3","gravatar_id":"","url":"https://api.github.com/users/matham","html_url":"https://github.com/matham","followers_url":"https://api.github.com/users/matham/followers","following_url":"https://api.github.com/users/matham/following{/other_user}","gists_url":"https://api.github.com/users/matham/gists{/gist_id}","starred_url":"https://api.github.com/users/matham/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/matham/subscriptions","organizations_url":"https://api.github.com/users/matham/orgs","repos_url":"https://api.github.com/users/matham/repos","events_url":"https://api.github.com/users/matham/events{/privacy}","received_events_url":"https://api.github.com/users/matham/received_events","type":"User","site_admin":false},"milestone":null,"comments":4,"created_at":"2015-01-16T07:16:59Z","updated_at":"2015-03-05T12:37:24Z","closed_at":null,"body":"An often requested feature is to add new kivy properties for widget instances. We already have a similar internal method: https://github.com/kivy/kivy/blob/master/kivy/_event.pyx#L797\r\n\r\n@tito proposed this syntax, i think it is a good fit:\r\n```python\r\nw_instance.create_property(prop_1=StringProperty('bli'), prop_2=NumericProperty(4))\r\n```\r\n\r\n<bountysource-plugin>\r\n---\r\nWant to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/7805332-allow-property-creation-for-widget-instances?utm_campaign=plugin&utm_content=tracker%2F42681&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F42681&utm_medium=issues&utm_source=github).\r\n</bountysource-plugin>"},"comment":{"url":"https://api.github.com/repos/kivy/kivy/issues/comments/77356716","html_url":"https://github.com/kivy/kivy/issues/2860#issuecomment-77356716","issue_url":"https://api.github.com/repos/kivy/kivy/issues/2860","id":77356716,"user":{"login":"denys-duchier","id":966422,"avatar_url":"https://avatars.githubusercontent.com/u/966422?v=3","gravatar_id":"","url":"https://api.github.com/users/denys-duchier","html_url":"https://github.com/denys-duchier","followers_url":"https://api.github.com/users/denys-duchier/followers","following_url":"https://api.github.com/users/denys-duchier/following{/other_user}","gists_url":"https://api.github.com/users/denys-duchier/gists{/gist_id}","starred_url":"https://api.github.com/users/denys-duchier/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/denys-duchier/subscriptions","organizations_url":"https://api.github.com/users/denys-duchier/orgs","repos_url":"https://api.github.com/users/denys-duchier/repos","events_url":"https://api.github.com/users/denys-duchier/events{/privacy}","received_events_url":"https://api.github.com/users/denys-duchier/received_events","type":"User","site_admin":false},"created_at":"2015-03-05T12:37:24Z","updated_at":"2015-03-05T12:37:24Z","body":"Here is one way to get instance-level properties::\r\n\r\n```python\r\nclass Widget(object):\r\n\r\n    def __init__(self):\r\n        self._instance_properties = {}\r\n        self._foo = 56\r\n\r\n    def __getattr__(self, name):\r\n        p = self._instance_properties.get(name, None)\r\n        if p:\r\n            return p.__get__(self, self.__class__)\r\n        else:\r\n            raise AttributeError(name)\r\n\r\n    def __setattr__(self, name, value):\r\n        p = name != '_instance_properties' and self._instance_properties.get(name, None)\r\n        if p:\r\n            p.__set__(self, value)\r\n        else:\r\n            super(Widget, self).__setattr__(name, value)\r\n\r\n    @property\r\n    def foo(self):\r\n        return self._foo\r\n\r\n    @foo.setter\r\n    def foo(self, value):\r\n        self._foo = value\r\n\r\n    def add_props(self, **kwargs):\r\n        self._instance_properties.update(kwargs)\r\n\r\n\r\nclass BazProp(object):\r\n\r\n    def __get__(self, instance, owner):\r\n        return instance.foo + 11\r\n\r\n    def __set__(self, instance, value):\r\n        instance.foo = value - 11\r\n\r\n\r\nx=Widget()\r\nx.add_props(baz=BazProp())\r\nprint(x.foo, x.baz)\r\nx.baz = 0\r\nprint(x.foo, x.baz)\r\n```\r\n\r\ndon't know if it's worth it though."}}