title: Zipfile closed within context manager
body: <p>The following code is confusing the mess out of me. I've got a zip file which I am opening in a context manager. I'm trying to extract the contents of this zip file to a temporary directory. However, when I execute this code block, it tells me that there was an "Attempt to read ZIP archive that was already closed". I find this very strange, as the zip file in question was opened in (with?) a context manager! I've inserted several print statements for calls to methods/properties associated with the object at hand. They return successfully.</p>
  
  <p>Where have I gone wrong? Why does the file believe itself closed?</p>
  
  <p>Any help would be appreciated!</p>
  
  <p>(Edit) Please find the traceback below.</p>
  
  <p>Also, is there a better way to check if a zipfile is in fact open? Other than checking if .fp is True/False?</p>
  
  <pre><code>if config.get('settings', 'new_quarter') == "Yes":
          #This gets the latest zip file, by year and quarter
          new_statements_path = os.path.join(config.get('cleaning', 'historic_dir'), 'sql_files')
          for directory,dirnames, filenames in os.walk(new_statements_path):
              zips = [f for f in filenames if ".zip" in f]
              highest_quarter = max([z.split('Q')[1].split('.')[0] for z in zips])
              print 'Targeting this quarter for initial tables: %s' % (highest_quarter)
              for z in zips:
                  if 'sql_files' in f:
                      if z.split('Q')[1].split('.')[0] == highest_quarter:
                          with zipfile.ZipFile(os.path.join(directory,z), 'r') as zip_f:
                              print zip_f.fp
                              initial_tables = tempfile.mkdtemp()
                              print 'initial tables', initial_tables, os.path.exists(initial_tables) 
                              #Ensure the file is read/write by the creator only
                              saved_umask = os.umask(0077)
  
                              try:
                                  print zip_f.namelist()
                                  print zip_f.fp
                                  zip_f.printdir()
  
                                  zip_f.extractall(path=initial_tables)
                              except:
                                  print traceback.format_exc()
                                  os.umask(saved_umask)
                                  if os.path.exists(initial_tables) == True:
                                      shutil.rmtree(initial_tables)
  </code></pre>
  
  <p>Traceback: </p>
  
  <pre><code>Traceback (most recent call last):
    File "/Users/n/GitHub/s/s/s/extract/extract.py", line 60, in extract_process
      zip_f.extractall(path=initial_tables)
    File "/Users/n/anaconda/lib/python2.7/zipfile.py", line 1043, in extractall
      self.extract(zipinfo, path, pwd)
    File "/Users/n/anaconda/lib/python2.7/zipfile.py", line 1031, in extract
       return self._extract_member(member, path, pwd)
    File "/Users/n/anaconda/lib/python2.7/zipfile.py", line 1085, in _extract_member
      with self.open(member, pwd=pwd) as source, \
    File "/Users/n/anaconda/lib/python2.7/zipfile.py", line 946, in open
      "Attempt to read ZIP archive that was already closed"
  RuntimeError: Attempt to read ZIP archive that was already closed
  </code></pre>
  
  <p>(SECOND EDIT)</p>
  
  <p>Here's the (reasonably) minimal &amp; complete version. In this case, the code runs fine. Which makes sense, there's nothing fancy going on. What's interesting is I placed the full example (the one below) immediately above the previous example (above). The code below still executes just fine, but the code above still produces the same error. The only difference however is the <strong>new_statements_path</strong> variable. In the code above, this string comes from a config file. Surely, this isn't the root of the error. But I can't see any other differences. </p>
  
  <pre><code>import traceback
  import os
  import zipfile
  import tempfile
  import shutil
  
  new_statements_path = '/Users/n/Official/sql_files'
  for directory,dirnames, filenames in os.walk(new_statements_path):
      zips = [f for f in filenames if ".zip" in f]
      highest_quarter = max([z.split('Q')[1].split('.')[0] for z in zips])
      print 'Targeting this Quarter for initial tables: %s' % (highest_quarter)
      for z in zips:
              if 'sql_files' in f:
                      if z.split('Q')[1].split('.')[0] == highest_quarter:
                              with zipfile.ZipFile(os.path.join(directory,z), 'r') as zip_f:
                                      print zip_f.fp
                                      initial_tables = tempfile.mkdtemp()
                                      print 'initial tables', initial_tables, os.path.exists(initial_tables) 
                                      #Ensure the file is read/write by the creator only
                                      saved_umask = os.umask(0077)
  
                                      try:
                                              print zip_f.namelist()
                                              print zip_f.fp
                                              zip_f.printdir()
                                              zip_f.extractall(path=initial_tables)
                                      except:
                                              print traceback.format_exc()
                                              os.umask(saved_umask)
                                              if os.path.exists(initial_tables) == True:
                                                      shutil.rmtree(initial_tables)
  
      if os.path.exists(initial_tables) == True:
              shutil.rmtree(initial_tables)
  </code></pre>