code: def fetch(self, url, listener, chunk_size_bytes=None, timeout_secs=None):
      
      if not isinstance(listener, self.Listener):
        raise ValueError('listener must be a Listener instance, given {}'.format(listener))
  
      chunk_size_bytes = chunk_size_bytes or 10 * 1024
      timeout_secs = timeout_secs or 1.0
  
      with closing(self._fetch(url, timeout_secs=timeout_secs)) as resp:
        if resp.status_code != requests.codes.ok:
          listener.status(resp.status_code)
          raise self.PermanentError('Fetch of {} failed with status code {}'
                                    .format(url, resp.status_code),
                                    response_code=resp.status_code)
        listener.status(resp.status_code, content_length=resp.size)
  
        read_bytes = 0
        for data in resp.iter_content(chunk_size_bytes=chunk_size_bytes):
          listener.recv_chunk(data)
          read_bytes += len(data)
        if resp.size and read_bytes != resp.size:
          raise self.Error('Expected {} bytes, read {}'.format(resp.size, read_bytes))
        listener.finished()
docs: Fetches data from the given URL notifying listener of all lifecycle events.
  
      :param string url: the url to GET data from
      :param listener: the listener to notify of all download lifecycle events
      :param chunk_size_bytes: the chunk size to use for buffering data, 10 KB by default
      :param timeout_secs: the maximum time to wait for data to be available, 1 second by default
      :raises: Fetcher.Error if there was a problem fetching all data from the given url