Skip to content
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

gh-101819: Isolate _io #101948

Merged
merged 86 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
6d0a37b
Add tests
erlend-aasland Feb 12, 2023
bd19a20
StringIO type
erlend-aasland Feb 11, 2023
9af73fe
PyTextIOWrapper type
erlend-aasland Feb 11, 2023
4bd73bd
Move get_io_state() to main header
erlend-aasland Feb 11, 2023
8d96a7a
PyFileIO type
erlend-aasland Feb 11, 2023
97f382f
Buffered* types
erlend-aasland Feb 12, 2023
eeb5c48
PyBytesIO type
erlend-aasland Feb 12, 2023
4106c1b
PyTextIOBase type
erlend-aasland Feb 12, 2023
3eba873
PyBufferedIOBase type
erlend-aasland Feb 12, 2023
de3acf0
PyIncrementalNewlineDecoder type
erlend-aasland Feb 13, 2023
bc35218
PyBytesIOBuffer type
erlend-aasland Feb 15, 2023
62a91e9
PyWindowsConsoleIO type
erlend-aasland Feb 15, 2023
23b79eb
RawIOBase type
erlend-aasland Feb 15, 2023
be64029
IOBase type
erlend-aasland Feb 15, 2023
55234a2
Remove crud
erlend-aasland Feb 15, 2023
0328a34
Fixup module def init
erlend-aasland Feb 15, 2023
a83cf1f
WIP module state / multi-phase init
erlend-aasland Feb 16, 2023
e9b0a27
Pull in main
erlend-aasland Feb 20, 2023
4e64198
Fix state assignment
kumaraditya303 Feb 20, 2023
bda9b43
Merge branch 'main' into isolate-io/poc
hauntsaninja Feb 20, 2023
a51823a
Experimental: add explicit finalizers to all types
erlend-aasland Feb 20, 2023
0cdd1ea
Fix check readable/writable/seekable methods
erlend-aasland Feb 20, 2023
3a1ed0b
Fix _textiowrapper_decode
erlend-aasland Feb 20, 2023
039b757
Revert "Experimental: add explicit finalizers to all types"
erlend-aasland Feb 20, 2023
17eb640
Purge old exports
erlend-aasland Feb 20, 2023
00d5abb
Revert "Fix check readable/writable/seekable methods"
erlend-aasland Feb 21, 2023
916ae8c
Pull in main
erlend-aasland Feb 23, 2023
fe8c256
Pass state to _check* functions
erlend-aasland Feb 23, 2023
d0a0d54
Windows fix (first of many)
erlend-aasland Feb 23, 2023
741d66b
Merge branch 'main' into isolate-io/poc
kumaraditya303 Mar 6, 2023
ce131d4
Merge branch 'main' of https://github.com/python/cpython into isolate…
kumaraditya303 Mar 14, 2023
2e0d06d
Pull in Kumar's work
erlend-aasland Mar 14, 2023
d9806e5
Merge branch 'python:main' into isolate-io/poc
kumaraditya303 Mar 14, 2023
6a813b4
fix conflict
kumaraditya303 Mar 14, 2023
0689f21
remove duplicate declarations
kumaraditya303 Mar 14, 2023
5e19c48
add missing methods
kumaraditya303 Mar 14, 2023
6099d5b
fix pickling
kumaraditya303 Mar 14, 2023
18de912
Add NEWS
erlend-aasland Mar 14, 2023
c363eb8
fix windows console check
kumaraditya303 Mar 14, 2023
1099d1f
Merge branch 'isolate-io/poc' of github.com:erlend-aasland/cpython in…
kumaraditya303 Mar 14, 2023
73d581c
remove locale
kumaraditya303 Mar 14, 2023
eaf585e
fix all windows checks
kumaraditya303 Mar 15, 2023
5a5bd9a
Merge branch 'main' of https://github.com/python/cpython into isolate…
kumaraditya303 Mar 15, 2023
7a8c2be
Merge branch 'main' into isolate-io/poc
kumaraditya303 Mar 18, 2023
d836b95
Pull in main
erlend-aasland Mar 22, 2023
8d5b6a1
Fix merge
erlend-aasland Mar 22, 2023
be971d1
Pull in main again
erlend-aasland Mar 24, 2023
9083979
Merge branch 'main' into isolate-io/poc
kumaraditya303 Apr 1, 2023
e12eb85
use _PyType_GetModuleState
kumaraditya303 Apr 4, 2023
137fc32
Merge branch 'main' of https://github.com/python/cpython into isolate-io
kumaraditya303 Apr 4, 2023
30b746b
Pull in main
erlend-aasland Apr 8, 2023
f1efcb1
Pull in main
erlend-aasland Apr 13, 2023
53ddde7
Pull in main
erlend-aasland Apr 18, 2023
4c7ca15
Pull in main again
erlend-aasland Apr 19, 2023
408c3b2
WIP
erlend-aasland Apr 19, 2023
142ac7f
Pull in main
erlend-aasland Apr 26, 2023
b4a89e4
Pull in main
erlend-aasland Apr 27, 2023
22b73a1
Visit and clear bytesio buf
erlend-aasland Apr 28, 2023
b3ec63a
Pull in main
erlend-aasland May 6, 2023
21470e6
Update NEWS
erlend-aasland May 6, 2023
ce82d88
Minimise diff a little bit
erlend-aasland May 6, 2023
3a9f582
Add Py_mod_multiple_interpreters mod slot
erlend-aasland May 6, 2023
f287cd5
Pull in main
erlend-aasland May 6, 2023
13700b5
Fix pickling
erlend-aasland May 6, 2023
e8d0b57
Make cannot-pickle function less smelly
erlend-aasland May 6, 2023
c65fcac
Pull in main
erlend-aasland May 7, 2023
f1a5de0
Style nit
erlend-aasland May 7, 2023
7bfbad0
Pull in main
erlend-aasland May 7, 2023
314137f
Pull in main
erlend-aasland May 9, 2023
9ca079f
Pull in main
erlend-aasland May 10, 2023
1078857
Reduce diff
erlend-aasland May 10, 2023
3dad388
Remove duplicate ADD_TYPE(PyBytesIOBuffer_Type...)
erlend-aasland May 10, 2023
8edc6cf
Pull in main and reduce diff further
erlend-aasland May 10, 2023
8df2633
Remove unneeded stylic change
erlend-aasland May 10, 2023
1505872
Reduce diff further
erlend-aasland May 10, 2023
18e8c43
Pull in main
erlend-aasland May 10, 2023
626685c
Pull in main
erlend-aasland May 11, 2023
6d55da9
fixes by Victor
kumaraditya303 May 12, 2023
bd73ab1
Merge branch 'main' of https://github.com/python/cpython into isolate…
kumaraditya303 May 12, 2023
80af518
remove unused functions
kumaraditya303 May 12, 2023
02dbef7
use defining_class
kumaraditya303 May 12, 2023
8518ec5
remove rawiobase_dealloc
kumaraditya303 May 12, 2023
d4b6dcc
Merge branch 'main' of https://github.com/python/cpython into isolate…
kumaraditya303 May 12, 2023
c5a4305
fix merge
kumaraditya303 May 12, 2023
ab1baf4
fix merge
kumaraditya303 May 12, 2023
fe2db1b
Merge branch 'main' into isolate-io/poc
kumaraditya303 May 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Lib/test/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -4242,6 +4242,7 @@ def test_warn_on_dealloc_fd(self):

def test_pickling(self):
# Pickling file objects is forbidden
msg = "cannot pickle"
for kwargs in [
{"mode": "w"},
{"mode": "wb"},
Expand All @@ -4256,8 +4257,10 @@ def test_pickling(self):
if "b" not in kwargs["mode"]:
kwargs["encoding"] = "utf-8"
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
with self.open(os_helper.TESTFN, **kwargs) as f:
self.assertRaises(TypeError, pickle.dumps, f, protocol)
with self.subTest(protocol=protocol, kwargs=kwargs):
with self.open(os_helper.TESTFN, **kwargs) as f:
with self.assertRaisesRegex(TypeError, msg):
pickle.dumps(f, protocol)

@unittest.skipIf(
support.is_emscripten, "fstat() of a pipe fd is not supported"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Isolate the :mod:`io` extension module by applying :pep:`687`. Patch by
Kumar Aditya, Victor Stinner, and Erlend E. Aasland.
138 changes: 41 additions & 97 deletions Modules/_io/_iomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -561,25 +561,9 @@ PyNumber_AsOff_t(PyObject *item, PyObject *err)
return result;
}

_PyIO_State *
_PyIO_get_module_state(void)
{
PyObject *mod = PyState_FindModule(&_PyIO_Module);
_PyIO_State *state;
if (mod == NULL || (state = get_io_state(mod)) == NULL) {
PyErr_SetString(PyExc_RuntimeError,
"could not find io module state "
"(interpreter shutdown?)");
return NULL;
}
return state;
}

static int
iomodule_traverse(PyObject *mod, visitproc visit, void *arg) {
_PyIO_State *state = get_io_state(mod);
if (!state->initialized)
return 0;
Py_VISIT(state->unsupported_operation);

Py_VISIT(state->PyIOBase_Type);
Expand All @@ -606,8 +590,6 @@ iomodule_traverse(PyObject *mod, visitproc visit, void *arg) {
static int
iomodule_clear(PyObject *mod) {
_PyIO_State *state = get_io_state(mod);
if (!state->initialized)
return 0;
Py_CLEAR(state->unsupported_operation);

Py_CLEAR(state->PyIOBase_Type);
Expand Down Expand Up @@ -652,115 +634,57 @@ static PyMethodDef module_methods[] = {
{NULL, NULL}
};

struct PyModuleDef _PyIO_Module = {
PyModuleDef_HEAD_INIT,
"io",
module_doc,
sizeof(_PyIO_State),
module_methods,
NULL,
iomodule_traverse,
iomodule_clear,
(freefunc)iomodule_free,
};


static PyTypeObject* static_types[] = {
// Base classes
&PyIOBase_Type,

// PyIOBase_Type subclasses
&PyBufferedIOBase_Type,
&PyRawIOBase_Type,
&PyTextIOBase_Type,
};


PyStatus
_PyIO_InitTypes(PyInterpreterState *interp)
{
for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) {
PyTypeObject *type = static_types[i];
if (_PyStaticType_InitBuiltin(interp, type) < 0) {
return _PyStatus_ERR("Can't initialize builtin type");
}
}

return _PyStatus_OK();
}

void
_PyIO_FiniTypes(PyInterpreterState *interp)
{
// Deallocate types in the reverse order to deallocate subclasses before
// their base classes.
for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types) - 1; i >= 0; i--) {
PyTypeObject *type = static_types[i];
_PyStaticType_Dealloc(interp, type);
}
}

#define ADD_TYPE(module, type, spec, base) \
do { \
type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec, \
(PyObject *)base); \
if (type == NULL) { \
goto fail; \
return -1; \
} \
if (PyModule_AddType(module, type) < 0) { \
goto fail; \
return -1; \
} \
} while (0)

PyMODINIT_FUNC
PyInit__io(void)
static int
iomodule_exec(PyObject *m)
{
PyObject *m = PyModule_Create(&_PyIO_Module);
_PyIO_State *state = NULL;
if (m == NULL)
return NULL;
state = get_io_state(m);
state->initialized = 0;
_PyIO_State *state = get_io_state(m);

/* DEFAULT_BUFFER_SIZE */
if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0)
goto fail;
return -1;

/* UnsupportedOperation inherits from ValueError and OSError */
state->unsupported_operation = PyObject_CallFunction(
(PyObject *)&PyType_Type, "s(OO){}",
"UnsupportedOperation", PyExc_OSError, PyExc_ValueError);
if (state->unsupported_operation == NULL)
goto fail;
return -1;
if (PyModule_AddObjectRef(m, "UnsupportedOperation",
state->unsupported_operation) < 0)
{
goto fail;
return -1;
}

/* BlockingIOError, for compatibility */
if (PyModule_AddObjectRef(m, "BlockingIOError",
(PyObject *) PyExc_BlockingIOError) < 0) {
goto fail;
}

// Add types
for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) {
PyTypeObject *type = static_types[i];
if (PyModule_AddType(m, type) < 0) {
goto fail;
}
return -1;
}

// Base classes
state->PyIOBase_Type = (PyTypeObject *)Py_NewRef(&PyIOBase_Type);
ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &nldecoder_spec, NULL);
ADD_TYPE(m, state->PyBytesIOBuffer_Type, &bytesiobuf_spec, NULL);
ADD_TYPE(m, state->PyIOBase_Type, &iobase_spec, NULL);

// PyIOBase_Type subclasses
state->PyRawIOBase_Type = (PyTypeObject *)Py_NewRef(&PyRawIOBase_Type);
state->PyBufferedIOBase_Type = (PyTypeObject *)Py_NewRef(&PyBufferedIOBase_Type);
state->PyTextIOBase_Type = (PyTypeObject *)Py_NewRef(&PyTextIOBase_Type);
ADD_TYPE(m, state->PyTextIOBase_Type, &textiobase_spec,
state->PyIOBase_Type);
ADD_TYPE(m, state->PyBufferedIOBase_Type, &bufferediobase_spec,
state->PyIOBase_Type);
ADD_TYPE(m, state->PyRawIOBase_Type, &rawiobase_spec,
state->PyIOBase_Type);

// PyBufferedIOBase_Type(PyIOBase_Type) subclasses
ADD_TYPE(m, state->PyBytesIO_Type, &bytesio_spec, state->PyBufferedIOBase_Type);
Expand All @@ -775,6 +699,7 @@ PyInit__io(void)

// PyRawIOBase_Type(PyIOBase_Type) subclasses
ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, state->PyRawIOBase_Type);

#ifdef HAVE_WINDOWS_CONSOLE_IO
ADD_TYPE(m, state->PyWindowsConsoleIO_Type, &winconsoleio_spec,
state->PyRawIOBase_Type);
Expand All @@ -785,11 +710,30 @@ PyInit__io(void)
ADD_TYPE(m, state->PyTextIOWrapper_Type, &textiowrapper_spec,
state->PyTextIOBase_Type);

state->initialized = 1;
#undef ADD_TYPE
return 0;
}

return m;
static struct PyModuleDef_Slot iomodule_slots[] = {
{Py_mod_exec, iomodule_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
{0, NULL},
};

fail:
Py_DECREF(m);
return NULL;
struct PyModuleDef _PyIO_Module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "io",
.m_doc = module_doc,
.m_size = sizeof(_PyIO_State),
.m_methods = module_methods,
.m_traverse = iomodule_traverse,
.m_clear = iomodule_clear,
.m_free = iomodule_free,
.m_slots = iomodule_slots,
};

PyMODINIT_FUNC
PyInit__io(void)
{
return PyModuleDef_Init(&_PyIO_Module);
}
15 changes: 5 additions & 10 deletions Modules/_io/_iomodule.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,20 @@
#include "pycore_typeobject.h" // _PyType_GetModuleState()
#include "structmember.h"

/* ABCs */
extern PyTypeObject PyIOBase_Type;
extern PyTypeObject PyRawIOBase_Type;
extern PyTypeObject PyBufferedIOBase_Type;
extern PyTypeObject PyTextIOBase_Type;

/* Type specs */
extern PyType_Spec bufferediobase_spec;
extern PyType_Spec bufferedrandom_spec;
extern PyType_Spec bufferedreader_spec;
extern PyType_Spec bufferedrwpair_spec;
extern PyType_Spec bufferedwriter_spec;
extern PyType_Spec bytesio_spec;
extern PyType_Spec bytesiobuf_spec;
extern PyType_Spec fileio_spec;
extern PyType_Spec iobase_spec;
extern PyType_Spec nldecoder_spec;
extern PyType_Spec rawiobase_spec;
extern PyType_Spec stringio_spec;
extern PyType_Spec textiobase_spec;
extern PyType_Spec textiowrapper_spec;

#ifdef HAVE_WINDOWS_CONSOLE_IO
Expand Down Expand Up @@ -168,9 +166,6 @@ struct _io_state {
#endif
};

#define IO_MOD_STATE(mod) ((_PyIO_State *)PyModule_GetState(mod))
#define IO_STATE() _PyIO_get_module_state()

static inline _PyIO_State *
get_io_state(PyObject *module)
{
Expand All @@ -195,7 +190,7 @@ find_io_state_by_def(PyTypeObject *type)
return get_io_state(mod);
}

extern _PyIO_State *_PyIO_get_module_state(void);
extern PyObject *_PyIOBase_cannot_pickle(PyObject *self, PyObject *args);

#ifdef HAVE_WINDOWS_CONSOLE_IO
extern char _PyIO_get_console_type(PyObject *);
Expand Down
Loading