-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
[2.7] bpo-33038: gzip.GzipFile assumes non-None name attribute #6095
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Lib/gzip.py
Outdated
@@ -95,7 +95,11 @@ def __init__(self, filename=None, mode=None, | |||
if filename is None: | |||
# Issue #13781: os.fdopen() creates a fileobj with a bogus name | |||
# attribute. Avoid saving this in the gzip header's filename field. | |||
if hasattr(fileobj, 'name') and fileobj.name != '<fdopen>': | |||
if ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to backport the code from 3.x (with adding a special case for '<fdopen>'
).
@@ -0,0 +1,2 @@ | |||
Using a tempfile.SpooledTemporaryFile object with gzip.GzipFile no longer | |||
produces an AttributeError exception. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add "Patch by yourname."
@@ -359,6 +360,13 @@ def test_read_with_extra(self): | |||
with gzip.GzipFile(fileobj=io.BytesIO(gzdata)) as f: | |||
self.assertEqual(f.read(), b'Test') | |||
|
|||
def test_fileobj_without_name(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to backport test_fileobj_from_fdopen
from 3.x.
And add a similar test with fileobj=io.open(fd, 'wb')
instead of fileobj=os.fdopen(fd, 'wb')
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All right then.
Lib/gzip.py
Outdated
else: | ||
filename = getattr(fileobj, 'name', '') | ||
if ( | ||
not isinstance(filename, (str, unicode)) or |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
basestring
Lib/gzip.py
Outdated
filename = fileobj.name | ||
else: | ||
filename = getattr(fileobj, 'name', '') | ||
if ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This formatting looks uncommon. I suggest to remove suspicious newlines. Could it fit in one line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even with basestring
, it's one char too long to fit on a line. This format is in PEP8 (and flake8 and company are fine with it). I prefer it to this:
if (not isinstance(filename, basestring) or
filename == '<fdopen>'):
filename = ''
because it is hard to see from the next line. If you'd rather some other style that's fine, but there doesn't seem to be a precedent in this file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can write it in the line of length 79. This is in the PEP 8 limit. Even if it be out of the limit, PEP 8 suggests the following options:
- No extra indentation.
if (not isinstance(filename, basestring) or
filename == '<fdopen>'):
filename = ''
- Add a comment, which will provide some distinction in editors supporting syntax highlighting.
if (not isinstance(filename, basestring) or
filename == '<fdopen>'):
# comment
filename = ''
- Add some extra indentation on the conditional continuation line.
if (not isinstance(filename, basestring)
or filename == '<fdopen>'):
filename = ''
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'm familiar with the PEP. I got rid of the parens and put everything on one line.
@@ -359,6 +360,13 @@ def test_read_with_extra(self): | |||
with gzip.GzipFile(fileobj=io.BytesIO(gzdata)) as f: | |||
self.assertEqual(f.read(), b'Test') | |||
|
|||
def test_fileobj_without_name(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All right then.
# a .name attribute use a non-None value. | ||
with tempfile.SpooledTemporaryFile() as f: | ||
with gzip.GzipFile(fileobj=f, mode='wb') as archive: | ||
archive.write(b'data') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add an assertion for name
here?
@@ -0,0 +1,2 @@ | |||
Using a tempfile.SpooledTemporaryFile object with gzip.GzipFile no longer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mention also the case of io.open() with a file descriptor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I don't think this is a new addition? That wasn't what the bug was aimed at - only for special file objects that (a) have a name
attribute, but (b) don't set it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR fixes a case when fileobj has a non-string name attribute. tempfile.SpooledTemporaryFile
is one example. io.open()
with a file descriptor is other example. Maybe there are other examples in the stdlib. And it can fix also cases with third-party file-like objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I understand - in that case the name
attribute is an int
.
@@ -0,0 +1,2 @@ | |||
Using a tempfile.SpooledTemporaryFile object with gzip.GzipFile no longer | |||
produces an AttributeError exception. Patch by Bo Bayles. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have noticed that your name is not in Misc/ACKS in this branch. Please add it.
In Python 2.7
gzip.GzipFile
doeshasattr(fileobj, 'name')
to see iffileobj
has a.name
attribute, but then assumes that attribute is notNone
.This isn't always a good assumption - for example,
tempfile.SpooledTemporaryFile
defines.name
, but it can beNone
:https://github.com/python/cpython/blob/2.7/Lib/tempfile.py#L597
Python 3's
GzipFile
doesn't have this issue, thankfully.https://bugs.python.org/issue33038