Repository: kivy/kivy

Issue:
AsyncImage does not reload itself
<!--
The issue tracker is a tool to address bugs.
Please use the #kivy IRC channel on freenode or Stack Overflow for
support questions, more information at https://git.io/vM1yQ.

Before opening a new issue, make sure you do the following:
    * check that your issue isn't already filed: https://git.io/vM1iE
    * prepare a short, runnable example that reproduces the issue
    * reproduce the problem with the latest development version of Kivy
    * double-check that the issue is indeed a bug and not a support request
-->

### Versions

* Python: 2.7
* OS: Windows 10
* Kivy: master
* Kivy installation method: pip

### Description

Reloading of image displayed using AsyncImage does not work. Old image is still displayed after method `reload` is called.

### How to reproduce 
Run `main.py` from [kivy_async_image_bug.zip](https://github.com/kivy/kivy/files/2023303/kivy_async_image_bug.zip), wait until image `t1.png` is displayed and click on reload button. Images `t1.png` and `t2.png` will swap names and now new `t1.png` should be displayed, but that is not the case.
AsyncImage does not reload itself
<!--
The issue tracker is a tool to address bugs.
Please use the #kivy IRC channel on freenode or Stack Overflow for
support questions, more information at https://git.io/vM1yQ.

Before opening a new issue, make sure you do the following:
    * check that your issue isn't already filed: https://git.io/vM1iE
    * prepare a short, runnable example that reproduces the issue
    * reproduce the problem with the latest development version of Kivy
    * double-check that the issue is indeed a bug and not a support request
-->

### Versions

* Python: 2.7
* OS: Windows 10
* Kivy: master
* Kivy installation method: pip

### Description

Reloading of image displayed using AsyncImage does not work. Old image is still displayed after method `reload` is called.

### How to reproduce 
Run `main.py` from [kivy_async_image_bug.zip](https://github.com/kivy/kivy/files/2023303/kivy_async_image_bug.zip), wait until image `t1.png` is displayed and click on reload button. Images `t1.png` and `t2.png` will swap names and now new `t1.png` should be displayed, but that is not the case.


Discussion:
One workaround is to put `nocache: True` in the `AsyncImage` block, but i'm looking into a quickfix.
One workaround is to put `nocache: True` in the `AsyncImage` block, but i'm looking into a quickfix.

Resolving patch:
diff --git a/kivy/loader.py b/kivy/loader.py
--- a/kivy/loader.py
+++ b/kivy/loader.py
@@ -466,6 +466,9 @@ def build(self):
 
         return client
 
+    def remove_from_cache(self, filename):
+        Cache.remove('kv.loader', filename)
+
 #
 # Loader implementation
 #
diff --git a/kivy/uix/image.py b/kivy/uix/image.py
--- a/kivy/uix/image.py
+++ b/kivy/uix/image.py
@@ -391,3 +391,12 @@ def _on_tex_change(self, *largs):
 
     def texture_update(self, *largs):
         pass
+
+    def reload(self):
+        if Loader:
+            source = self.source
+            if not self.is_uri(source):
+                source = resource_find(source)
+            Loader.remove_from_cache(source)
+
+        super(AsyncImage, self).reload()


Test patch:
diff --git a/kivy/tests/test_uix_asyncimage.py b/kivy/tests/test_uix_asyncimage.py
--- a/kivy/tests/test_uix_asyncimage.py
+++ b/kivy/tests/test_uix_asyncimage.py
@@ -107,6 +107,29 @@ def check_sequence_frames(self, img, frames, slides=5):
 
         return True
 
+    def test_reload_asyncimage(self):
+        from kivy.resources import resource_find
+        from tempfile import mkdtemp
+        from os import symlink, unlink
+        from shutil import rmtree
+
+        fn = resource_find('data/logo/kivy-icon-16.png')
+        t = mkdtemp()
+        source = join(t, 'source.png')
+        symlink(fn, source)
+        image = AsyncImage(source=source)
+        self.render(image, framecount=2)
+        self.assertEqual(image.texture_size, [16, 16])
+        unlink(source)
+
+        fn = resource_find('data/logo/kivy-icon-32.png')
+        symlink(fn, source)
+        image.reload()
+        self.render(image, framecount=2)
+        self.assertEqual(image.texture_size, [32, 32])
+        unlink(source)
+        rmtree(t)
+
 
 if __name__ == '__main__':
     import unittest