-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
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
shadows around the io truncate() semantics #51188
Comments
Hello I'm having trouble around the behaviour of the io module's truncate However, I see nothing in the documentation of the io module about that, Maybe it requires discusions on the mailing list, but personally I think Also, additional notes about the behaviour of that truncation (reminding Current doc of io in py3k : Cheers |
I can't tell you why it was decided to behave like this. Perhaps it was I'm afraid I don't know anything about the padding differences myself. |
Well, I guess it deserve discussion on the pydev mailing lits, that's Concerning the padding, I guess the semantic doesn't change between the file.truncate([size])¶ Having platform-dependent semantics for a so important type is anyway |
Hello I'm currently finalizing the API of my raw io file implementation, but I still have trouble with the trunk implementation of IOBase.truncate(). If I remember well, in the mailing list topic on this subject, GvR noted that this change of behaviour compared to python 2.x was not intended, and that it would be better to get back to the expected behaviour - not touching the file pointer - and to document the method in this way. Are there new elements, advocating a status quo on this matter ? On a separate note, I'm confused about the "at most" phrase in the current documentation : truncate(size=None)
Truncate the file to at most size bytes. size defaults to the current file position, as returned by tell() According to what I've read so far, a succesful truncate() call will always extend/reduce the file until teh desired size, isn't that so on all platforms ? Regards |
Nothing, it's just lacking a patch from someone interested in the
I suppose it was worded that way because some platforms may not support |
Allright, I'll try to work on it as soon as I manage to gather a decent compilation environment on windows... |
Hi Here is a patch for the python2.6 _fileio.c module, as well as the corresponding testcase. |
Whoups - I forgot to bugfix as well the _bytesio classes... let's just forget about the previous patch. |
Here is the new patch for py2.6, fixing (hopefully) all the truncate() methods. |
And here is the python trunk patch, covering _Pyio and _io modules (+ corresponding tests). |
Is there anything I can do to help this patch making its way to the trunk ? Regards, |
Looking at the patches:
|
Allright, I shall fix all this asap. But it seems the C code for truncate is actually buggy in the current 2.6 _fileio.c, around line 680. posobj = portable_lseek(fd, posobj, 0); -> don't we lose the reference to the old "posobj" there, doing a memory leak ? if (PyErr_Occurred()) return NULL; -> same thing, we return Null without caring about the posobj reference which should be non-Null there ?? If I've understood a little reference counting, "portable_lseek" returns a reference that we own and must Py_DECREF, isn't that so ? -------- if (posobj == Py_None || posobj == NULL) {
/* Get the current position. */
posobj = portable_lseek(fd, NULL, 1);
if (posobj == NULL)
return NULL;
}
else {
/* Move to the position to be truncated. */
posobj = portable_lseek(fd, posobj, 0);
}
#if defined(HAVE_LARGEFILE_SUPPORT)
pos = PyLong_AsLongLong(posobj);
#else
pos = PyLong_AsLong(posobj);
#endif
if (PyErr_Occurred())
return NULL; |
It's a bit more subtle. However, when you get a new "posobj" from portable_lseek() (or most To sum it up and if I'm not mistaken, you must:
If you wanna witness reference counting behaviour, you should build [39542 refs]
>>> f.truncate()
0L
[39547 refs]
>>> f.truncate()
0L
[39547 refs]
>>> f.truncate(2)
2
[39545 refs]
>>> f.truncate(2)
2
[39544 refs] As you see, when posobj is non-None, we actually lose a reference ... |
He, roundup ate part of the code I pasted. Here it is again: >>> import io
[39516 refs]
>>> f = io.open("foo", "wb", buffering=0)
[39542 refs]
>>> f.truncate()
0L
[39544 refs]
>>> f.truncate()
0L
[39544 refs]
>>> f.truncate(2)
2
[39543 refs]
>>> f.truncate(2)
2
[39542 refs]
>>> while True: f.truncate(2)
...
[snip]
Erreur de segmentation |
By the way, you witness the issue (less clearly though) by running the tests in debug mode, too: $ ./python -m test.regrtest -v test_io
test_io
test_BufferedIOBase_destructor (test.test_io.CIOTest) ... ok
test_IOBase_destructor (test.test_io.CIOTest) ... ok
test_RawIOBase_destructor (test.test_io.CIOTest) ... ok
test_TextIOBase_destructor (test.test_io.CIOTest) ... ok
test_append_mode_tell (test.test_io.CIOTest) ... ok
test_array_writes (test.test_io.CIOTest) ... ok
test_buffered_file_io (test.test_io.CIOTest) ... ok
test_close_flushes (test.test_io.CIOTest) ... ok
test_closefd (test.test_io.CIOTest) ... ok
test_closefd_attr (test.test_io.CIOTest) ... ok
test_destructor (test.test_io.CIOTest) ... ok
test_garbage_collection (test.test_io.CIOTest) ... ok
test_invalid_operations (test.test_io.CIOTest) ... ok
test_large_file_ops (test.test_io.CIOTest) ... Fatal Python error: Python/ceval.c:4058 object at 0x2572448 has negative ref count -1
Abandon |
Thanks for the detailed feedback. According to what you said (and to details found in python docs), the current _fileio.truncate is actually quite buggy -> no reference counting ops were done on posobj, even though it's sometimes retrieved from _portable_seek, and returned or not depending on rare error cases (SetEndOfFile failing etc.). Here is a patch fixing all that for python2.6, I've tested it manually in debug mode, and against memoryio/io/fileio tests ; hope it will be OK. As soon as this one is certified, I'll prepare a patch for python2.7 |
First, I get the following compilation warnings under Linux: The two variables should be declared at the beginning of the Windows-specific block instead. Second, there's a test failure in test_io: ====================================================================== Traceback (most recent call last):
File "/home/antoine/cpython/26/Lib/test/test_io.py", line 221, in test_large_file_ops
self.large_file_ops(f)
File "/home/antoine/cpython/26/Lib/test/test_io.py", line 154, in large_file_ops
self.assertEqual(f.tell(), self.LARGE + 1)
AssertionError: 2147483650L != 2147483649 |
Allright - sorry for the failure - I've cleaned my hdd enough to launch large_file tests too. The thing is - are there platforms available to test a patch against the whole test suite of python, and against several OSes ? I've found no such thing around build bots, and since I'm kind of stuck on win32 without a full compilation environment (sqlite, zlib etc. lack some setup), I miss vision depth concerning testing... Anyway, here is a corrected patch, passing the full io-related test suites on win32 (and visibly ready for unix too). |
Hello Just to notify that I've just tested this patch on a fresh python2.6 SVN checkout, on Ubuntu this time (previously, it was only win32), and it passes all IO-related tests I know. |
Thank you. The patch was committed mostly unchanged in r77802 (a few cosmetic fixes). Now trunk and py3k must absolutely be patched in order to conform to the new behaviour. Can you produce a patch for trunk? |
Thanks a lot B-) |
Hello Here is the patch for the python trunk, regarding truncate() behaviour. I've also updated some docstrings, and added tests for untested potential errors around buffered read+write streams, when truncating. |
Your patch lacked a fix for test_largefile (I think it is skipped under Windows). I added this and committed it in r77890. Will port to py3k. |
Committed in py3k (r77895, r77896) and 3.1 (r77897). Thank you Pascal! |
Argh, I had indeed missed some IO-related tests, hadn't noticed the new test_io docstring: Thanks for the commits B-) |
To avoid any confusion in the future, it should be noted that Antoine did not unilaterally make the decision to commit this change to a maintenance branch. This change was discussed on python-dev, with the ultimate decision to update the 3.1 semantics being made by Guido: http://mail.python.org/pipermail/python-dev/2009-September/092247.html |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: