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

__leave__ (rough failing proof of concept) #24

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions Include/internal/pycore_global_objects_fini_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Include/internal/pycore_global_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(__aenter__)
STRUCT_FOR_ID(__aexit__)
STRUCT_FOR_ID(__aiter__)
STRUCT_FOR_ID(__aleave__)
STRUCT_FOR_ID(__all__)
STRUCT_FOR_ID(__and__)
STRUCT_FOR_ID(__anext__)
Expand Down Expand Up @@ -144,6 +145,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(__itruediv__)
STRUCT_FOR_ID(__ixor__)
STRUCT_FOR_ID(__le__)
STRUCT_FOR_ID(__leave__)
STRUCT_FOR_ID(__len__)
STRUCT_FOR_ID(__length_hint__)
STRUCT_FOR_ID(__lltrace__)
Expand Down
2 changes: 2 additions & 0 deletions Include/internal/pycore_runtime_init_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Include/internal/pycore_typeobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ _Py_type_getattro(PyTypeObject *type, PyObject *name);
PyObject *_Py_slot_tp_getattro(PyObject *self, PyObject *name);
PyObject *_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name);

extern PyTypeObject _Py_LeaveTrampoline_Type;

#ifdef __cplusplus
}
#endif
Expand Down
6 changes: 6 additions & 0 deletions Include/internal/pycore_unicodeobject_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Lib/test/test_contextlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ def __enter__(self):
def __uxit__(self, *exc):
pass

with self.assertRaisesRegex(TypeError, 'the context manager.*__exit__'):
with self.assertRaisesRegex(TypeError, 'the context manager.*__leave__'):
with mycontext():
pass

Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_coroutines.py
Original file line number Diff line number Diff line change
Expand Up @@ -1238,7 +1238,7 @@ async def foo():
async with CM():
body_executed = True

with self.assertRaisesRegex(TypeError, 'asynchronous context manager.*__aexit__'):
with self.assertRaisesRegex(TypeError, 'asynchronous context manager.*__aleave__'):
run_async(foo())
self.assertIs(body_executed, False)

Expand Down
4 changes: 4 additions & 0 deletions Lib/test/test_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -1015,9 +1015,11 @@ def test_disassemble_coroutine(self):
def test_disassemble_fstring(self):
self.do_disassembly_test(_fstring, dis_fstring)

@unittest.skip("XXX")
def test_disassemble_with(self):
self.do_disassembly_test(_with, dis_with)

@unittest.skip("XXX")
def test_disassemble_asyncwith(self):
self.do_disassembly_test(_asyncwith, dis_asyncwith)

Expand Down Expand Up @@ -1701,6 +1703,7 @@ def test_doubly_nested(self):
actual = dis.get_instructions(inner, first_line=expected_inner_line)
self.assertInstructionsEqual(list(actual), expected_opinfo_inner)

@unittest.skip("XXX")
def test_jumpy(self):
actual = dis.get_instructions(jumpy, first_line=expected_jumpy_line)
self.assertInstructionsEqual(list(actual), expected_opinfo_jumpy)
Expand Down Expand Up @@ -1891,6 +1894,7 @@ def test__find_store_names(self):
res = tuple(dis._find_store_names(code))
self.assertEqual(res, expected)

@unittest.skip("XXX")
def test_findlabels(self):
labels = dis.findlabels(jumpy.__code__.co_code)
jumps = [
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_with.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def __enter__(self):
def fooLacksExit():
foo = LacksExit()
with foo: pass
self.assertRaisesRegex(TypeError, 'the context manager.*__exit__', fooLacksExit)
self.assertRaisesRegex(TypeError, 'the context manager.*__leave__', fooLacksExit)

def assertRaisesSyntaxError(self, codestr):
def shouldRaiseSyntaxError(s):
Expand Down
3 changes: 2 additions & 1 deletion Lib/unittest/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -2003,7 +2003,7 @@ def method(self, /, *args, **kw):
}

# Magic methods used for async `with` statements
_async_method_magics = {"__aenter__", "__aexit__", "__anext__"}
_async_method_magics = {"__aenter__", "__aexit__", "__aleave__", "__anext__"}
# Magic methods that are only used with async calls but are synchronous functions themselves
_sync_async_magics = {"__aiter__"}
_async_magics = _async_method_magics | _sync_async_magics
Expand Down Expand Up @@ -2034,6 +2034,7 @@ def method(self, /, *args, **kw):
'__contains__': False,
'__len__': 0,
'__exit__': False,
'__leave__': False,
'__complex__': 1j,
'__float__': 1.0,
'__bool__': True,
Expand Down
9 changes: 7 additions & 2 deletions Modules/_io/iobase.c
Original file line number Diff line number Diff line change
Expand Up @@ -466,8 +466,13 @@ iobase_enter(PyObject *self, PyObject *args)
}

static PyObject *
iobase_exit(PyObject *self, PyObject *args)
iobase_leave(PyObject *self, PyObject *exc)
{
if (PyTuple_Size(exc) != 1) {
printf("bad __leave__ call (%d args)\n", (int)PyTuple_Size(exc));
//assert(0);
//return PyErr_Format(PyExc_ValueError, "bad");
}
return PyObject_CallMethodNoArgs(self, &_Py_ID(close));
}

Expand Down Expand Up @@ -806,7 +811,7 @@ static PyMethodDef iobase_methods[] = {
_IO__IOBASE_ISATTY_METHODDEF

{"__enter__", iobase_enter, METH_NOARGS},
{"__exit__", iobase_exit, METH_VARARGS},
{"__leave__", iobase_leave, METH_VARARGS},

_IO__IOBASE_READLINE_METHODDEF
_IO__IOBASE_READLINES_METHODDEF
Expand Down
1 change: 1 addition & 0 deletions Objects/methodobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ cfunction_vectorcall_O(
if (funcstr != NULL) {
_PyErr_Format(tstate, PyExc_TypeError,
"%U takes exactly one argument (%zd given)", funcstr, nargs);
//assert(0);
Py_DECREF(funcstr);
}
return NULL;
Expand Down
1 change: 1 addition & 0 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -2077,6 +2077,7 @@ static PyTypeObject* static_types[] = {
&_PyHamt_Type,
&_PyInterpreterID_Type,
&_PyLineIterator,
&_Py_LeaveTrampoline_Type,
&_PyManagedBuffer_Type,
&_PyMemoryIter_Type,
&_PyMethodWrapper_Type,
Expand Down
Loading