Skip to content

Commit 84f6de9

Browse files
committed
Patch #1517891: Make 'a' create the file if it doesn't exist.
Fixes #1514451.
1 parent c6d626e commit 84f6de9

File tree

4 files changed

+38
-1
lines changed

4 files changed

+38
-1
lines changed

Doc/lib/libzipfile.tex

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ \subsection{ZipFile Objects \label{zipfile-objects}}
101101
\end{verbatim}
102102

103103
also works, and at least \program{WinZip} can read such files.
104+
If \var{mode} is \code{a} and the file does not exist at all,
105+
it is created.
104106
\var{compression} is the ZIP compression method to use when writing
105107
the archive, and should be \constant{ZIP_STORED} or
106108
\constant{ZIP_DEFLATED}; unrecognized values will cause
@@ -114,6 +116,9 @@ \subsection{ZipFile Objects \label{zipfile-objects}}
114116
ZIP file would require ZIP64 extensions. ZIP64 extensions are disabled by
115117
default because the default \program{zip} and \program{unzip} commands on
116118
\UNIX{} (the InfoZIP utilities) don't support these extensions.
119+
120+
\versionchanged[If the file does not exist, it is created if the
121+
mode is 'a']{2.6}
117122
\end{classdesc}
118123

119124
\begin{methoddesc}{close}{}

Lib/test/test_zipfile.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,28 @@ def testWritePythonDirectory(self):
307307

308308

309309
class OtherTests(unittest.TestCase):
310+
def testCreateNonExistentFileForAppend(self):
311+
if os.path.exists(TESTFN):
312+
os.unlink(TESTFN)
313+
314+
filename = 'testfile.txt'
315+
content = 'hello, world. this is some content.'
316+
317+
try:
318+
zf = zipfile.ZipFile(TESTFN, 'a')
319+
zf.writestr(filename, content)
320+
zf.close()
321+
except IOError, (errno, errmsg):
322+
self.fail('Could not append data to a non-existent zip file.')
323+
324+
self.assert_(os.path.exists(TESTFN))
325+
326+
zf = zipfile.ZipFile(TESTFN, 'r')
327+
self.assertEqual(zf.read(filename), content)
328+
zf.close()
329+
330+
os.unlink(TESTFN)
331+
310332
def testCloseErroneousFile(self):
311333
# This test checks that the ZipFile constructor closes the file object
312334
# it opens if there's an error in the file. If it doesn't, the traceback

Lib/zipfile.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,14 @@ def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=False):
396396
self._filePassed = 0
397397
self.filename = file
398398
modeDict = {'r' : 'rb', 'w': 'wb', 'a' : 'r+b'}
399-
self.fp = open(file, modeDict[mode])
399+
try:
400+
self.fp = open(file, modeDict[mode])
401+
except IOError:
402+
if mode == 'a':
403+
mode = key = 'w'
404+
self.fp = open(file, modeDict[mode])
405+
else:
406+
raise
400407
else:
401408
self._filePassed = 1
402409
self.fp = file

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ Core and builtins
128128
Library
129129
-------
130130

131+
- Patch #1517891: Mode 'a' for ZipFile now creates the file if it
132+
doesn't exist.
133+
131134
- Patch #698833: Support file decryption in zipfile.
132135

133136
- Patch #685268: Consider a package's __path__ in imputil.

0 commit comments

Comments
 (0)