Uh oh!
There was an error while loading. Please reload this page.
gh-111495: Add PyFile_* CAPI tests - #111709
Conversation
Tests fail on Windows (I have a very limited experience with this platform): Is it correct? |
serhiy-storchaka
left a comment
There was a problem hiding this comment.
This family has little functions, but they should be tested with many cases.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
serhiy-storchaka
commented
Nov 4, 2023
Because the default encoding on Windows is not UTF-8. Always specify encoding for text files. |
Uh oh!
There was an error while loading. Please reload this page.
sobolevn
commented
Nov 5, 2023
@serhiy-storchaka thanks a lot for your detailed review! You are one of the best reviewers I know :) |
sobolevn
commented
Nov 5, 2023
Address sanitizer build fails with: Maybe I should use a different string? Suggestions? |
Uh oh!
There was an error while loading. Please reload this page.
vstinner
commented
Nov 10, 2023
It's unrelated to Address sanitizer. It's just that this CI builds Python is release mode. And in release mode, the error handler is only used if the string cannot be decoded (decoding error). In debug mode, the error handler is always checked. You can skip this test if |
vstinner
commented
Nov 10, 2023
To reproduce the Address Sanitizer issue, I used: |
serhiy-storchaka
left a comment
There was a problem hiding this comment.
Sorry, I have not finished the review yet. It is difficult with so many tests. So I can find other issues later.
The main problem is that they incorrectly create non-decodable files. You should use binary files to write them.
It would be nice also to reduce the number of lines where it is possible.
| def test_name_invalid_utf(self): | ||
| with open(os_helper.TESTFN, "w", encoding="utf-8") as f: | ||
| file_obj = _testcapi.file_from_fd( | ||
| f.fileno(), "abc\xe9", "w", |
There was a problem hiding this comment.
It is not invalid UTF-8. When you pass the Python string, it is encoded to UTF-8, therefore the C string is always valid UTF-8. You have to pass a bytes object, e.g. b'\xff'. See for example tests for PyDict_GetItemString() or PyObject_GetAttrString().
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| first_line = "\xc3\x28\n" | ||
| with open(os_helper.TESTFN, "w", encoding="utf-8") as f: | ||
| f.writelines([first_line]) |
There was a problem hiding this comment.
Again, it does not create invalid UTF-8.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| with open(os_helper.TESTFN, "w", encoding="utf-8") as f: | ||
| f.writelines([first_line, second_line]) |
There was a problem hiding this comment.
Many tests can use StringIO. E.g.
f=io.StringIO('first_line\nsecond_line\n')There was a problem hiding this comment.
I have explicit tests for both file object and io.StringIO:
deftest_file_get_multiple_lines(self):
first_line="text with юникод 统一码\n"second_line="second line\n"withopen(os_helper.TESTFN, "w", encoding="utf-8") asf:
f.writelines([first_line, second_line])
withopen(os_helper.TESTFN, encoding="utf-8") asf:
self.assertEqual(self.get_line(f, 0), first_line)
self.assertEqual(self.get_line(f, 0), second_line)
deftest_file_get_line_from_file_like(self):
first_line="text with юникод 统一码\n"second_line="second line\n"contents=io.StringIO(f"{first_line}{second_line}")
self.assertEqual(self.get_line(contents, 0), first_line)
self.assertEqual(self.get_line(contents, 0), second_line)vstinner
commented
Aug 26, 2024
@sobolevn: What's the status of this PR? Do you plan to attempt to address @serhiy-storchaka's latest review? |
sobolevn
commented
Aug 26, 2024
yes, sure! adding this to my queue. |
sobolevn
commented
Sep 7, 2024
@serhiy-storchaka@vstinner I partially addressed your review. The only part that I didn't implement is invalid utf8 tests. I want to ask for advice on how it should be done. For example, right now I cannot pass if (!PyArg_ParseTuple(args, "izzizzzi",
&fd,
&name, &mode,
&buffering,
&encoding, &errors, &newline,
&closefd)) {
returnNULL;
}What is the best way to pass staticPyObject*file_from_fd_with_bytes(PyObject*Py_UNUSED(self), PyObject*args)and allow passing bytes there? |
serhiy-storchaka
commented
Sep 7, 2024
What are your issues with passing a bytes object? |
| raise ValueError("str raised") | ||
| with self.assertRaisesRegex(ValueError, "str raised"): | ||
| self.write_and_return(StrRaises(), flags=_testcapi.Py_PRINT_RAW) |
There was a problem hiding this comment.
It is not clear what is the difference between these tests if it raises in any case. You should either define __str__ and __repr__ that do not raise in corresponding classes and test both classes with and without Py_PRINT_RAW, or just make both __str__ and __repr__ in the same class raising different exceptions and test that writing with and without Py_PRINT_RAW gives different errors. The former option will duplicate other tests, so I suggest the later way.
Oh, and you do not need to use write_and_return here.
| self.assertRaises(AttributeError, self.write, NULL, object(), 0) | ||
| self.assertRaises(TypeError, self.write, NULL, NULL, 0) | ||
| wr = self.write | ||
| self.assertRaises(TypeError, wr, object(), io.BytesIO(), 0) |
There was a problem hiding this comment.
Use a string instead of object(). It will be clearer what you write and why this fails.
Oh no, I did it again :-( I forgot about this PR and I wrote a new one (that I just merged): #129449. Sorry about that. It seems like this PR has more tests. |
sobolevn
commented
Jan 30, 2025
@vstinner thanks a lot for your PR, I forgot about that one several times already :) You can port some of the tests from here to your version if it helps. |
vstinner
commented
Jan 30, 2025
I will try to add tests from this PR. |
Looks like
PyFile_SetOpenCodeHookis already tested here:cpython/Programs/_testembed.c
Lines 1177 to 1232 in 20cfab9