| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -250,7 +250,7 @@ def read(self, filename, strict=True): | |||
| 250 | 250 | list of standard types, else to the list of non-standard | |
| 251 | 251 | types. | |
| 252 | 252 | """ | |
| 253 | - with open(filename, encoding='utf-8') as fp: | ||
| 253 | + with open(filename, encoding='utf-8', errors='surrogateescape') as fp: | ||
| 254 | 254 | self.readfp(fp, strict) | |
| 255 | 255 | ||
| 256 | 256 | def readfp(self, fp, strict=True): | |
@@ -444,7 +444,7 @@ def init(files=None): | |||
| 444 | 444 | ||
| 445 | 445 | def read_mime_types(file): | |
| 446 | 446 | try: | |
| 447 | - f = open(file, encoding='utf-8') | ||
| 447 | + f = open(file, encoding='utf-8', errors='surrogateescape') | ||
| 448 | 448 | except OSError: | |
| 449 | 449 | return None | |
| 450 | 450 | with f: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -232,3 +232,23 @@ def reset_worker(): | |||
| 232 | 232 | decoder.reset() | |
| 233 | 233 | ||
| 234 | 234 | run_concurrently([decode_worker] * 2 + [reset_worker] * 2) | |
| 235 | + | ||
| 236 | + | ||
| 237 | + class TextIOWrapperTest(TestCase): | ||
| 238 | + def test_buffer_detach_race(self): | ||
| 239 | + make = lambda: io.TextIOWrapper(io.BytesIO()) | ||
| 240 | + slot = [make()] | ||
| 241 | + | ||
| 242 | + def reader(): | ||
| 243 | + for _ in range(1000): | ||
| 244 | + try: | ||
| 245 | + slot[0].buffer | ||
| 246 | + except ValueError: | ||
| 247 | + pass | ||
| 248 | + | ||
| 249 | + def detacher(): | ||
| 250 | + for _ in range(1000): | ||
| 251 | + slot[0] = make() | ||
| 252 | + slot[0].detach() | ||
| 253 | + | ||
| 254 | + run_concurrently([reader, detacher]) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -67,9 +67,50 @@ def test_read_mime_types(self): | |||
| 67 | 67 | with unittest.mock.patch.object(mimetypes, 'open', | |
| 68 | 68 | return_value=fp) as mock_open: | |
| 69 | 69 | mime_dict = mimetypes.read_mime_types(filename) | |
| 70 | - mock_open.assert_called_with(filename, encoding='utf-8') | ||
| 70 | + mock_open.assert_called_with(filename, encoding='utf-8', | ||
| 71 | + errors='surrogateescape') | ||
| 71 | 72 | eq(mime_dict[".Français"], "application/no-mans-land") | |
| 72 | 73 | ||
| 74 | + def test_read_mime_types_invalid_utf8_comment(self): | ||
| 75 | + with os_helper.temp_dir() as directory: | ||
| 76 | + data = (b"# non-UTF-8 comment: \x83\n" | ||
| 77 | + b"x-application/x-unittest pyunit\n") | ||
| 78 | + file = os.path.join(directory, "sample.mimetype") | ||
| 79 | + with open(file, "wb") as f: | ||
| 80 | + f.write(data) | ||
| 81 | + | ||
| 82 | + mime_dict = mimetypes.read_mime_types(file) | ||
| 83 | + self.assertEqual( | ||
| 84 | + mime_dict[".pyunit"], "x-application/x-unittest") | ||
| 85 | + | ||
| 86 | + db = mimetypes.MimeTypes() | ||
| 87 | + db.read(file) | ||
| 88 | + self.assertEqual( | ||
| 89 | + db.guess_file_type("sample.pyunit")[0], | ||
| 90 | + "x-application/x-unittest") | ||
| 91 | + | ||
| 92 | + mimetypes.init(files=[file]) | ||
| 93 | + self.assertEqual( | ||
| 94 | + mimetypes.guess_file_type("sample.pyunit")[0], | ||
| 95 | + "x-application/x-unittest") | ||
| 96 | + | ||
| 97 | + def test_read_mime_types_invalid_utf8_type(self): | ||
| 98 | + # A non-UTF-8 byte in a type or extension (not only in a comment) is | ||
| 99 | + # preserved via surrogateescape, so the mapping is not corrupted. | ||
| 100 | + with os_helper.temp_dir() as directory: | ||
| 101 | + data = (b"x-application/x-unittest pyunit\n" | ||
| 102 | + b"application/bad\x83 badext\x83\n") | ||
| 103 | + file = os.path.join(directory, "sample.mimetype") | ||
| 104 | + with open(file, "wb") as f: | ||
| 105 | + f.write(data) | ||
| 106 | + | ||
| 107 | + bad_type = b"application/bad\x83".decode("utf-8", "surrogateescape") | ||
| 108 | + bad_ext = b".badext\x83".decode("utf-8", "surrogateescape") | ||
| 109 | + | ||
| 110 | + mime_dict = mimetypes.read_mime_types(file) | ||
| 111 | + self.assertEqual(mime_dict[".pyunit"], "x-application/x-unittest") | ||
| 112 | + self.assertEqual(mime_dict[bad_ext], bad_type) | ||
| 113 | + | ||
| 73 | 114 | def test_init_reinitializes(self): | |
| 74 | 115 | # Issue 4936: make sure an init starts clean | |
| 75 | 116 | # First, put some poison into the types table | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + Fix :mod:`mimetypes` initialization from MIME map files containing invalid | ||
| 2 | + UTF-8 bytes. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + Fixed data-race when calling :meth:`io.TextIOBase.detach` in | ||
| 2 | + :term:`free-threaded build`. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3424,6 +3424,19 @@ _io_TextIOWrapper__CHUNK_SIZE_set_impl(textio *self, PyObject *value) | |||
| 3424 | 3424 | return 0; | |
| 3425 | 3425 | } | |
| 3426 | 3426 | ||
| 3427 | + /*[clinic input] | ||
| 3428 | + @critical_section | ||
| 3429 | + @getter | ||
| 3430 | + _io.TextIOWrapper.buffer | ||
| 3431 | + [clinic start generated code]*/ | ||
| 3432 | + | ||
| 3433 | + static PyObject * | ||
| 3434 | + _io_TextIOWrapper_buffer_get_impl(textio *self) | ||
| 3435 | + /*[clinic end generated code: output=d265a34555aa5d4b input=5951cfa148f7350a]*/ | ||
| 3436 | + { | ||
| 3437 | + return Py_XNewRef(buffer_access_safe(self)); | ||
| 3438 | + } | ||
| 3439 | + | ||
| 3427 | 3440 | static PyMethodDef incrementalnewlinedecoder_methods[] = { | |
| 3428 | 3441 | _IO_INCREMENTALNEWLINEDECODER_DECODE_METHODDEF | |
| 3429 | 3442 | _IO_INCREMENTALNEWLINEDECODER_GETSTATE_METHODDEF | |
@@ -3482,7 +3495,6 @@ static PyMethodDef textiowrapper_methods[] = { | |||
| 3482 | 3495 | ||
| 3483 | 3496 | static PyMemberDef textiowrapper_members[] = { | |
| 3484 | 3497 | {"encoding", _Py_T_OBJECT, offsetof(textio, encoding), Py_READONLY}, | |
| 3485 | - {"buffer", _Py_T_OBJECT, offsetof(textio, buffer), Py_READONLY}, | ||
| 3486 | 3498 | {"line_buffering", Py_T_BOOL, offsetof(textio, line_buffering), Py_READONLY}, | |
| 3487 | 3499 | {"write_through", Py_T_BOOL, offsetof(textio, write_through), Py_READONLY}, | |
| 3488 | 3500 | {"_finalizing", Py_T_BOOL, offsetof(textio, finalizing), 0}, | |
@@ -3497,6 +3509,7 @@ static PyGetSetDef textiowrapper_getset[] = { | |||
| 3497 | 3509 | _IO_TEXTIOWRAPPER_NEWLINES_GETSETDEF | |
| 3498 | 3510 | _IO_TEXTIOWRAPPER_ERRORS_GETSETDEF | |
| 3499 | 3511 | _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF | |
| 3512 | + _IO_TEXTIOWRAPPER_BUFFER_GETSETDEF | ||
| 3500 | 3513 | {NULL} | |
| 3501 | 3514 | }; | |
| 3502 | 3515 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,7 +1,7 @@ | |||
| 1 | 1 | # Any data that can vary between Python versions is to be kept in this file. | |
| 2 | 2 | # This allows for blanket copying of the Emscripten build code between supported | |
| 3 | 3 | # Python versions. | |
| 4 | - emscripten-version = "6.0.4" | ||
| 4 | + emscripten-version = "6.0.5" | ||
| 5 | 5 | node-version = "24" | |
| 6 | 6 | test-args = [ | |
| 7 | 7 | "-m", "test", | |
| Back | FazBrowse Home | New Git URL |
0 commit comments