kivy/kivy — pull request #1758 by matham (2014-01-13 06:36:19+00:00)
Title: Fix filechooser .path infnitie loop.

Filechooser goes into a infinite loop when running the following code and double clicking on a folder:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.filechooser import FileChooserListView

class TestApp(App):
view = None

def build(self):
self.view = FileChooserListView(multiselect=True)
self.view.bind(path=self.set_path)
return self.view

def set_path(self, obj, value):
self.view.path = value

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

which results in the following crash:

...
self.view.path = value
File "properties.pyx", line 322, in kivy.properties.Property.__set__ (kivy\properties.c:3574)
File "properties.pyx", line 354, in kivy.properties.Property.set (kivy\properties.c:4049)
File "properties.pyx", line 408, in kivy.properties.Property.dispatch (kivy\properties.c:4642)
File "C:\kivy-dev\kivy\kivy\uix\filechooser.py", line 397, in _save_previous_path
self.path = path
File "properties.pyx", line 322, in kivy.properties.Property.__set__ (kivy\properties.c:3574)
File "properties.pyx", line 354, in kivy.properties.Property.set (kivy\properties.c:4049)
File "properties.pyx", line 408, in kivy.properties.Property.dispatch (kivy\properties.c:4642)
File "C:\kivy-dev\kivy\kivy\uix\filechooser.py", line 395, in _save_previous_path
path = realpath(path)
File "C:\kivy-dev\Python\lib\ntpath.py", line 478, in abspath
return normpath(path)
File "C:\kivy-dev\Python\lib\ntpath.py", line 401, in normpath
backslash, dot = (u'\\', u'.') if isinstance(path, unicode) else ('\\', '.')
RuntimeError: maximum recursion depth exceeded while calling a Python object

Here's how it happens. self.path starts at / (C:\). I double click on the folder FFmpeg (C:\FFmpeg) to open it (since multiselect is True). The function open_entry is called and at line 474, self.path is initially '/', and entry.path is '\FFmpeg'. self.path now becomes '\FFmpeg'.

Because path changed, _save_previous_path is called. At line 395, value is '\FFmpeg' and path is 'C:\FFmpeg'. Because value != path, self.path is asigned path ('C:\FFmpeg'). But because I bound to path, my set_path function is called setting path back to '\FFmpeg' and the loop continues cycling between setting path to 'C:\FFmpeg' and '\FFmpeg'.

Now I know that my set_path function may not be the greatest idea, still I cannot see a reason for changing self.path when value != path. So I removed that code. This is a __really bad idea__ anyway becuase a user might set self.path to e.g. '\FFmpeg' directly everytime path changes which would result in a infinite loop as well. Yet there's no docs in self.path saying that it cannot be a non-realpath. In fact, since value was assigned to self.path there's no reason to do realpath on it because on cancel it'd just be assigned back to path and it won't be any worse that the first time it was self.path...