title: Download file with Kivy app without locking event loop
body: <p>Here's a Kivy application that has a button and a progress bar.  When the button is pressed, a ZIP file is downloaded from the web and unzipped.  The progress bar advances to mark the download's progress.</p>
  
  <p>The problem is, the downloading locks the Kivy event loop, freezing the application during the download.  How can I download and unzip a file in the background?</p>
  
  <pre><code>from __future__ import division
  import os
  import requests
  import zipfile
  from kivy.app import App
  from kivy.lang import Builder
  from kivy.uix.boxlayout import BoxLayout
  
  ZIP_URL = 'https://www.python.org/ftp/python/3.5.1/python-3.5.1-embed-win32.zip'
  ZIP_FILENAME = 'Python351.zip'
  
  kv_string = """
  &lt;RootWidget&gt;
      BoxLayout:
          orientation: "vertical"
          Button:
              id: download_button
              text: "Download content"
              on_press: self.parent.parent.download_content()
          ProgressBar:
              id: download_progress_bar
              max: 1
              value: 0.1
  """
  
  Builder.load_string(kv_string)
  
  
  class RootWidget(BoxLayout):
      def __init__(self, **kwargs):
          super(RootWidget, self).__init__(**kwargs)
  
      def download_content(self):
          self.ids["download_button"].disabled = True
  
          total_size_KiB = 6023182 / 1024 # DEBUG: hardcoded
          print("Downloading file: %s" % ZIP_URL)
          with open(ZIP_FILENAME, 'wb') as handle:
              response = requests.get(ZIP_URL, stream=True)
  
              if not response.ok:
                  print("Something went wrong.")
                  return
  
              current_size_KiB = 0
              for block in response.iter_content(1024):
                  percent_downloaded = current_size_KiB / total_size_KiB
                  if not current_size_KiB % 100:
                      print("%.2f%% downloaded so far" % (percent_downloaded * 100))
                  self.ids['download_progress_bar'].value = percent_downloaded
  
                  handle.write(block)
  
                  current_size_KiB += 1
  
          self.unzip_content()
  
      def unzip_content(self):
          print("Unzipping file")
          fh = open(ZIP_FILENAME, 'rb')
          z = zipfile.ZipFile(fh)
          ZIP_EXTRACT_FOLDER = ZIP_FILENAME + '_extracted'
          if not os.path.exists(ZIP_EXTRACT_FOLDER):
              os.makedirs(ZIP_EXTRACT_FOLDER)
          z.extractall(ZIP_EXTRACT_FOLDER)
          fh.close()
          os.remove(ZIP_FILENAME)
  
          print("Done")
  
  
  class MyApp(App):
  
      def build(self):
          return RootWidget()
  
  
  if __name__ == '__main__':
      MyApp().run()
  </code></pre>