The problem here is this line:
zipfile = file+'.zip'
After that, zipfile
no longer refers to the module, but to this string. So, when you do this:
output = zipfile.ZipFile(zipfile, 'wb')
You're asking a string, not a module, to call ZipFile
.
Hence this error:
AttributeError: 'str' object has no attribute 'ZipFile'
The fix is to not call your variable zipfile
.
As Jeff Langemeier says, the key is:
Don't use variable names that are the same as your imports that's just asking for trouble. B: Don't use variable names that are the same as your imports it makes it impossible to read. C: Don't use variable names that are the same as your imports.
More generally, don't use the same name for two different things.
For your second question:
how do specify the compression level
You can't. This is intentional, for the same reason that the zip
command-line tool no longer documents 10 levels of compression, just -0
for store (no compression), and -9
for "compress better". There's almost never any good use for anything but store or the default. -9
often doesn't really compress better than the default—or it compresses some files better and others worse. If you need better compression, you need a better algorithm—e.g., use .tar.bz2
instead of .zip
, or use p7zip
(which can create zip-compatible files) instead of plain zip
.
So, Python's library only gives you two choices: store or default. As the docs show:
class zipfile.ZipFile(file[, mode[, compression[, allowZip64]]])
…
compression is the ZIP compression method to use when writing the archive, and should be ZIP_STORED or ZIP_DEFLATED
And likewise for the write
/writestr
methods.
If you really want to do this, you can call zlib.compress
directly, create a ZipInfo
object directly, and add it to the archive yourself. If you look at the source (which is linked from the docs), you can see what writestr
does—it's really not complicated once you strip out all the irrelevant conditions and type checks.
But really, I don't think you want to do this.