Skip to content
Merged
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
4 changes: 2 additions & 2 deletions Doc/library/annotationlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,8 @@ Functions
annotate functions that support the :attr:`~Format.STRING` format but
do not have access to the code creating the annotations.

For example, this is used to implement the :attr:`~Format.STRING` for
:class:`typing.TypedDict` classes created through the functional syntax:
For example, this is used to implement the :attr:`~Format.STRING` format
for :class:`typing.TypedDict` classes created through the functional syntax:

.. doctest::

Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ _PyLocals_GetKind(PyObject *kinds, int i)
{
assert(PyBytes_Check(kinds));
assert(0 <= i && i < PyBytes_GET_SIZE(kinds));
char *ptr = PyBytes_AS_STRING(kinds);
const char *ptr = PyBytes_AS_STRING(kinds);
return (_PyLocals_Kind)(ptr[i]);
}

Expand Down
12 changes: 12 additions & 0 deletions Lib/asyncio/taskgroups.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,18 @@ async def _aexit(self, et, exc):
assert not self._tasks

if self._base_error is not None:
# self._base_error (SystemExit or KeyboardInterrupt) is about
# to propagate out of this method, which discards any other
# collected task errors silently. Report them instead of
# losing them. See gh-135736.
for suppressed_exc in self._errors:
self._loop.call_exception_handler({
'message': 'TaskGroup task exception was not '
'propagated because the TaskGroup body '
'is being closed with a BaseException',
'exception': suppressed_exc,
'task_group': self,
})
try:
raise self._base_error
finally:
Expand Down
33 changes: 33 additions & 0 deletions Lib/test/test_asyncio/test_taskgroups.py
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,39 @@ async def runner():
get_error_types(cm.exception), {MyBaseExc, ZeroDivisionError}
)

async def test_taskgroup_20b(self):
# Same setup as test_taskgroup_20 (a KeyboardInterrupt from the
# "async with" body itself, alongside a sibling task's exception):
# raising self._base_error out of _aexit() discards self._errors
# silently. The sibling's exception can't be raised alongside
# the KeyboardInterrupt (only one exception can propagate), but
# it must be reported via the loop's exception handler instead
# of being discarded silently. See gh-135736.
async def crash_soon():
await asyncio.sleep(0.1)
1 / 0

async def nested():
try:
await asyncio.sleep(10)
finally:
raise KeyboardInterrupt

async def runner():
async with taskgroups.TaskGroup() as g:
g.create_task(crash_soon())
await nested()

contexts = []
loop = asyncio.get_running_loop()
loop.set_exception_handler(lambda loop, context: contexts.append(context))

with self.assertRaises(KeyboardInterrupt):
await runner()

self.assertEqual(len(contexts), 1)
self.assertIsInstance(contexts[0]['exception'], ZeroDivisionError)

async def _test_taskgroup_21(self):
# This test doesn't work as asyncio, currently, doesn't
# correctly propagate KeyboardInterrupt (or SystemExit) --
Expand Down
6 changes: 6 additions & 0 deletions Lib/test/test_capi/test_bytes.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,10 +315,16 @@ def test_create(self):
self.assertEqual(writer.get_size(), 3)
self.assertEqual(writer.finish(), self.result_type(b'abc'))

def test_finish_with_size(self):
# Test PyBytesWriter_FinishWithSize()
writer = self.create_writer(10, b'abc')
self.assertEqual(writer.get_size(), 10)
self.assertEqual(writer.finish_with_size(3), self.result_type(b'abc'))

writer = self.create_writer(3, b'abc')
with self.assertRaises(SystemError):
writer.finish_with_size(-3)

def test_write_bytes(self):
# Test PyBytesWriter_WriteBytes()
writer = self.create_writer()
Expand Down
16 changes: 14 additions & 2 deletions Lib/test/test_copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class C(object):
def __reduce_ex__(self, proto):
c.append(1)
return ""
def __reduce__(self):
def __reduce__(*args):
self.fail("shouldn't call this")
c = []
x = C()
Expand All @@ -70,9 +70,15 @@ def __reduce__(self):

def test_copy_reduce(self):
class C(object):
def __reduce_ex__(*args):
self.fail("shouldn't call this")
def __reduce__(self):
c.append(1)
return ""
def __getattribute__(self, name):
if name == "__reduce_ex__":
raise AttributeError(name)
return object.__getattribute__(self, name)
c = []
x = C()
y = copy.copy(x)
Expand Down Expand Up @@ -329,7 +335,7 @@ class C(object):
def __reduce_ex__(self, proto):
c.append(1)
return ""
def __reduce__(self):
def __reduce__(*args):
self.fail("shouldn't call this")
c = []
x = C()
Expand All @@ -339,9 +345,15 @@ def __reduce__(self):

def test_deepcopy_reduce(self):
class C(object):
def __reduce_ex__(*args):
self.fail("shouldn't call this")
def __reduce__(self):
c.append(1)
return ""
def __getattribute__(self, name):
if name == "__reduce_ex__":
raise AttributeError(name)
return object.__getattribute__(self, name)
c = []
x = C()
y = copy.deepcopy(x)
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_inspect/test_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -6340,7 +6340,7 @@ def test_socket_module_has_signatures(self):
# depends on the number of the arguments.
methods_no_signature = {'ioctl', 'sendto', 'setsockopt'}
# These have parameters with unrepresentable default values.
methods_unsupported_signature = {'listen', 'sendmsg', 'sendmsg_afalg'}
methods_unsupported_signature = {'listen', 'sendmsg_afalg'}
defined = vars(socket.SocketType).keys()
self._test_module_has_signatures(socket,
no_signature, unsupported_signature,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Fix :class:`asyncio.TaskGroup` silently discarding errors from sibling
tasks whenever the ``async with`` block exits with a :exc:`SystemExit` or
:exc:`KeyboardInterrupt`. These errors are now reported via
:meth:`loop.call_exception_handler() <asyncio.loop.call_exception_handler>`
instead of being lost.
2 changes: 1 addition & 1 deletion Modules/_sqlite/blob.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ subscript_slice(pysqlite_Blob *self, PyObject *item)
return NULL;
}
char *res_buf = PyBytesWriter_GetData(writer);
char *blob_buf = PyBytes_AS_STRING(blob);
const char *blob_buf = PyBytes_AS_STRING(blob);

size_t cur;
Py_ssize_t i;
Expand Down
5 changes: 2 additions & 3 deletions Modules/clinic/socketmodule.c.h

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

8 changes: 4 additions & 4 deletions Modules/socketmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1811,7 +1811,7 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
(in particular, numeric IP addresses). */
struct maybe_idna {
PyObject *obj;
char *buf;
const char *buf;
};

static void
Expand Down Expand Up @@ -4990,9 +4990,9 @@ sock_sendmsg_impl(PySocketSockObject *s, void *data)
_socket.socket.sendmsg
self as s: self(type="PySocketSockObject *")
buffers as data_arg: object
ancdata as cmsg_arg: object = NULL
ancdata as cmsg_arg: object(c_default="NULL") = ()
flags: int = 0
address as addr_arg: object = NULL
address as addr_arg: object(c_default="NULL") = None
/

Send normal and ancillary data to the socket.
Expand All @@ -5016,7 +5016,7 @@ static PyObject *
_socket_socket_sendmsg_impl(PySocketSockObject *s, PyObject *data_arg,
PyObject *cmsg_arg, int flags,
PyObject *addr_arg)
/*[clinic end generated code: output=3b4cb1110644ce39 input=8ae408971a3aa329]*/
/*[clinic end generated code: output=3b4cb1110644ce39 input=5fdf9b49bed3848b]*/

{
Py_ssize_t i, ndatabufs = 0, ncmsgs, ncmsgbufs = 0;
Expand Down
2 changes: 1 addition & 1 deletion Objects/stringlib/codecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ STRINGLIB(utf8_encoder)(PyObject *unicode,
writer->overallocate = (newpos < size);
}

char *rep_str;
const char *rep_str;
Py_ssize_t rep_len;
if (PyBytes_Check(rep)) {
rep_str = PyBytes_AS_STRING(rep);
Expand Down
2 changes: 1 addition & 1 deletion Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -7314,7 +7314,7 @@ unicode_encode_ucs1(PyObject *unicode,
writer->overallocate = (newpos < size);
}

char *rep_str;
const char *rep_str;
Py_ssize_t rep_len;
if (PyBytes_Check(rep)) {
/* Directly copy bytes result to output. */
Expand Down
4 changes: 2 additions & 2 deletions Parser/action_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1481,7 +1481,7 @@ expr_ty _PyPegen_decoded_constant_from_token(Parser* p, Token* tok) {
}

expr_ty _PyPegen_constant_from_token(Parser* p, Token* tok) {
char* bstr = PyBytes_AsString(tok->bytes);
const char* bstr = PyBytes_AsString(tok->bytes);
if (bstr == NULL) {
return NULL;
}
Expand All @@ -1499,7 +1499,7 @@ expr_ty _PyPegen_constant_from_token(Parser* p, Token* tok) {
}

expr_ty _PyPegen_constant_from_string(Parser* p, Token* tok) {
char* the_str = PyBytes_AsString(tok->bytes);
const char* the_str = PyBytes_AsString(tok->bytes);
if (the_str == NULL) {
return NULL;
}
Expand Down
2 changes: 1 addition & 1 deletion Parser/string_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ warn_invalid_escape_sequence(Parser *p, const char* buffer, const char *first_in
char first_quote = 0;
if (lineno == t->lineno) {
int quote_count = 0;
char* tok = PyBytes_AsString(t->bytes);
const char* tok = PyBytes_AsString(t->bytes);
for (int i = 0; i < PyBytes_Size(t->bytes); i++) {
if (tok[i] == '\'' || tok[i] == '\"') {
if (quote_count == 0) {
Expand Down
31 changes: 18 additions & 13 deletions Python/assemble.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ struct assembler {
int a_except_table_off; /* offset into exception table */
/* Location Info */
int a_lineno; /* lineno of last emitted instruction */
PyObject* a_linetable; /* bytes containing location info */
PyBytesWriter *a_linetable_writer; /* writer containing location info */
PyObject *a_linetable; /* bytes object containing location info */
int a_location_off; /* offset of last written location info frame */
};

Expand All @@ -63,15 +64,12 @@ assemble_init(struct assembler *a, int firstlineno)
{
memset(a, 0, sizeof(struct assembler));
a->a_lineno = firstlineno;
a->a_linetable = NULL;
a->a_location_off = 0;
a->a_except_table = NULL;
a->a_bytecode = PyBytes_FromStringAndSize(NULL, DEFAULT_CODE_SIZE);
if (a->a_bytecode == NULL) {
goto error;
}
a->a_linetable = PyBytes_FromStringAndSize(NULL, DEFAULT_CNOTAB_SIZE);
if (a->a_linetable == NULL) {
a->a_linetable_writer = PyBytesWriter_Create(DEFAULT_CNOTAB_SIZE);
if (a->a_linetable_writer == NULL) {
goto error;
}
a->a_except_table = PyBytes_FromStringAndSize(NULL, DEFAULT_LNOTAB_SIZE);
Expand All @@ -81,7 +79,7 @@ assemble_init(struct assembler *a, int firstlineno)
return SUCCESS;
error:
Py_CLEAR(a->a_bytecode);
Py_CLEAR(a->a_linetable);
PyBytesWriter_Discard(a->a_linetable_writer);
Py_CLEAR(a->a_except_table);
return ERROR;
}
Expand All @@ -90,6 +88,7 @@ static void
assemble_free(struct assembler *a)
{
Py_XDECREF(a->a_bytecode);
PyBytesWriter_Discard(a->a_linetable_writer);
Py_XDECREF(a->a_linetable);
Py_XDECREF(a->a_except_table);
}
Expand Down Expand Up @@ -195,16 +194,17 @@ assemble_exception_table(struct assembler *a, instr_sequence *instrs)
static void
write_location_byte(struct assembler* a, int val)
{
PyBytes_AS_STRING(a->a_linetable)[a->a_location_off] = val&255;
uint8_t *linetable = PyBytesWriter_GetData(a->a_linetable_writer);
linetable[a->a_location_off] = val & 255;
a->a_location_off++;
}


static uint8_t *
location_pointer(struct assembler* a)
{
return (uint8_t *)PyBytes_AS_STRING(a->a_linetable) +
a->a_location_off;
uint8_t *linetable = PyBytesWriter_GetData(a->a_linetable_writer);
return linetable + a->a_location_off;
}

static void
Expand Down Expand Up @@ -285,10 +285,10 @@ write_location_info_no_column(struct assembler* a, int length, int line_delta)
static int
write_location_info_entry(struct assembler* a, location loc, int isize)
{
Py_ssize_t len = PyBytes_GET_SIZE(a->a_linetable);
Py_ssize_t len = PyBytesWriter_GetSize(a->a_linetable_writer);
if (a->a_location_off + THEORETICAL_MAX_ENTRY_SIZE >= len) {
assert(len > THEORETICAL_MAX_ENTRY_SIZE);
RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, len*2));
RETURN_IF_ERROR(PyBytesWriter_Resize(a->a_linetable_writer, len * 2));
}
if (loc.lineno == NO_LOCATION.lineno) {
write_location_info_none(a, isize);
Expand Down Expand Up @@ -447,7 +447,12 @@ assemble_emit(struct assembler *a, instr_sequence *instrs,
RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, a->a_except_table_off));
RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_except_table));

RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, a->a_location_off));
a->a_linetable = PyBytesWriter_FinishWithSize(a->a_linetable_writer,
a->a_location_off);
a->a_linetable_writer = NULL;
if (a->a_linetable == NULL) {
return ERROR;
}
RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_linetable));

RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, a->a_offset * sizeof(_Py_CODEUNIT)));
Expand Down
Loading