title: Should I switch from "urllib.request.urlretrieve(..)" to "urllib.request.urlopen(..)"?
body: <h3>1. Deprecation problem</h3>
  
  <p>In <strong>Python 3.7</strong>, I download a big file from a <code>URL</code> using the <code>urllib.request.urlretrieve(..)</code> function. In the documentation (<a href="https://docs.python.org/3/library/urllib.request.html" rel="nofollow noreferrer">https://docs.python.org/3/library/urllib.request.html</a>) I read the following just above the <code>urllib.request.urlretrieve(..)</code> docs:</p>
  
  <blockquote>
    <p><strong>Legacy interface</strong><br>
    The following functions and classes are ported from the Python 2 module urllib (as opposed to urllib2). They might become deprecated at some point in the future.</p>
  </blockquote>
  
  <p>&nbsp;<br></p>
  
  <h3>2. Searching an alternative</h3>
  
  <p>To keep my code future-proof, I'm on the lookout for an alternative. The official Python docs don't mention a specific one, but it looks like <code>urllib.request.urlopen(..)</code> is the most straightforward candidate. It's at the top of the docs page.</p>
  
  <p>Unfortunately, the alternatives - like <code>urlopen(..)</code> - <em>don't provide the <code>reporthook</code> argument.</em> This argument is a callable you pass to the <code>urlretrieve(..)</code> function. In turn, <code>urlretrieve(..)</code> calls it regularly with the following arguments:</p>
  
  <ul>
  <li>block nr.</li>
  <li>block size</li>
  <li>total file size</li>
  </ul>
  
  <p>I use it to update a progressbar. That's why I miss the <code>reporthook</code> argument in alternatives.</p>
  
  <p>&nbsp;<br></p>
  
  <h3>3. urlretrieve(..) vs urlopen(..) </h3>
  
  <p>I discovered that <em><code>urlretrieve(..)</code> simply uses <code>urlopen(..)</code></em>. See the <code>request.py</code> code file in the Python 3.7 installation (Python37/Lib/urllib/request.py):</p>
  
  <pre class="lang-py prettyprint-override"><code>_url_tempfiles = []
  def urlretrieve(url, filename=None, reporthook=None, data=None):
      """
      Retrieve a URL into a temporary location on disk.
  
      Requires a URL argument. If a filename is passed, it is used as
      the temporary file location. The reporthook argument should be
      a callable that accepts a block number, a read size, and the
      total file size of the URL target. The data argument should be
      valid URL encoded data.
  
      If a filename is passed and the URL points to a local resource,
      the result is a copy from local file to new file.
  
      Returns a tuple containing the path to the newly created
      data file as well as the resulting HTTPMessage object.
      """
      url_type, path = splittype(url)
  
      with contextlib.closing(urlopen(url, data)) as fp:
          headers = fp.info()
  
          # Just return the local path and the "headers" for file://
          # URLs. No sense in performing a copy unless requested.
          if url_type == "file" and not filename:
              return os.path.normpath(path), headers
  
          # Handle temporary file setup.
          if filename:
              tfp = open(filename, 'wb')
          else:
              tfp = tempfile.NamedTemporaryFile(delete=False)
              filename = tfp.name
              _url_tempfiles.append(filename)
  
          with tfp:
              result = filename, headers
              bs = 1024*8
              size = -1
              read = 0
              blocknum = 0
              if "content-length" in headers:
                  size = int(headers["Content-Length"])
  
              if reporthook:
                  reporthook(blocknum, bs, size)
  
              while True:
                  block = fp.read(bs)
                  if not block:
                      break
                  read += len(block)
                  tfp.write(block)
                  blocknum += 1
                  if reporthook:
                      reporthook(blocknum, bs, size)
  
      if size &gt;= 0 and read &lt; size:
          raise ContentTooShortError(
              "retrieval incomplete: got only %i out of %i bytes"
              % (read, size), result)
  
      return result
  </code></pre>
  
  <h3>4. Conclusion</h3>
  
  <p>From all this, I see three possible decisions:</p>
  
  <ol>
  <li><p>I keep my code <strong>unchanged</strong>. Let's hope the <code>urlretrieve(..)</code> function won't get deprecated anytime soon.</p></li>
  <li><p>I write myself a <strong>replacement function</strong> behaving like <code>urlretrieve(..)</code> on the outside and using <code>urlopen(..)</code> on the inside. Actually, such function would be a copy-paste of the code above. It feels unclean to do that - compared to using the official <code>urlretrieve(..)</code>.</p></li>
  <li><p>I write myself a <strong>replacement function</strong> behaving like <code>urlretrieve(..)</code> on the outside and using something entirely different on the inside. But hey, why would I do that? <code>urlopen(..)</code> is not deprecated, so why not use it?</p></li>
  </ol>
  
  <p>What decision would you take?</p>