Skip to content

Commit

Permalink
Merge branch 'main' into modulelocals
Browse files Browse the repository at this point in the history
* main:
  pythongh-105540: Fix code generator tests (python#105707)
  pythongh-105375: Explicitly initialise all {Pickler,Unpickler}Object fields (python#105686)
  pythongh-105331: Change `asyncio.sleep` to raise ``ValueError` for nan (python#105641)
  Remove support for legacy bytecode instructions (python#105705)
  • Loading branch information
carljm committed Jun 12, 2023
2 parents 5609f64 + 8da9d1b commit 2fae889
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 187 deletions.
3 changes: 3 additions & 0 deletions Doc/library/asyncio-task.rst
Expand Up @@ -426,6 +426,9 @@ Sleeping
.. versionchanged:: 3.10
Removed the *loop* parameter.

.. versionchanged:: 3.13
Raises :exc:`ValueError` if *delay* is :data:`~math.nan`.


Running Tasks Concurrently
==========================
Expand Down
4 changes: 4 additions & 0 deletions Lib/asyncio/tasks.py
Expand Up @@ -15,6 +15,7 @@
import functools
import inspect
import itertools
import math
import types
import warnings
import weakref
Expand Down Expand Up @@ -646,6 +647,9 @@ async def sleep(delay, result=None):
await __sleep0()
return result

if math.isnan(delay):
raise ValueError("Invalid delay: NaN (not a number)")

loop = events.get_running_loop()
future = loop.create_future()
h = loop.call_later(delay,
Expand Down
15 changes: 15 additions & 0 deletions Lib/test/test_asyncio/test_tasks.py
Expand Up @@ -1609,6 +1609,21 @@ async def sleeper(dt, arg):
self.assertEqual(t.result(), 'yeah')
self.assertAlmostEqual(0.1, loop.time())

def test_sleep_when_delay_is_nan(self):

def gen():
yield

loop = self.new_test_loop(gen)

async def sleeper():
await asyncio.sleep(float("nan"))

t = self.new_task(loop, sleeper())

with self.assertRaises(ValueError):
loop.run_until_complete(t)

def test_sleep_cancel(self):

def gen():
Expand Down
@@ -0,0 +1,2 @@
Raise :exc:`ValueError` if the ``delay`` argument to :func:`asyncio.sleep` is a NaN (matching :func:`time.sleep`).

90 changes: 53 additions & 37 deletions Modules/_pickle.c
Expand Up @@ -1145,42 +1145,49 @@ _Pickler_Write(PicklerObject *self, const char *s, Py_ssize_t data_len)
static PicklerObject *
_Pickler_New(PickleState *st)
{
PicklerObject *self;

self = PyObject_GC_New(PicklerObject, st->Pickler_Type);
if (self == NULL)
PyMemoTable *memo = PyMemoTable_New();
if (memo == NULL) {
return NULL;
}

const Py_ssize_t max_output_len = WRITE_BUF_SIZE;
PyObject *output_buffer = PyBytes_FromStringAndSize(NULL, max_output_len);
if (output_buffer == NULL) {
goto error;
}

PicklerObject *self = PyObject_GC_New(PicklerObject, st->Pickler_Type);
if (self == NULL) {
goto error;
}

self->memo = memo;
self->pers_func = NULL;
self->pers_func_self = NULL;
self->dispatch_table = NULL;
self->buffer_callback = NULL;
self->reducer_override = NULL;
self->write = NULL;
self->output_buffer = output_buffer;
self->output_len = 0;
self->max_output_len = max_output_len;
self->proto = 0;
self->bin = 0;
self->framing = 0;
self->frame_start = -1;
self->buf_size = 0;
self->fast = 0;
self->fast_nesting = 0;
self->fix_imports = 0;
self->fast_memo = NULL;
self->max_output_len = WRITE_BUF_SIZE;
self->output_len = 0;
self->reducer_override = NULL;

self->memo = PyMemoTable_New();
if (self->memo == NULL) {
Py_DECREF(self);
return NULL;
}
self->output_buffer = PyBytes_FromStringAndSize(NULL,
self->max_output_len);
if (self->output_buffer == NULL) {
Py_DECREF(self);
return NULL;
}
self->buffer_callback = NULL;

PyObject_GC_Track(self);
return self;

error:
PyMem_Free(memo);
Py_XDECREF(output_buffer);
return NULL;
}

static int
Expand Down Expand Up @@ -1628,14 +1635,31 @@ _Unpickler_MemoCleanup(UnpicklerObject *self)
static UnpicklerObject *
_Unpickler_New(PyObject *module)
{
UnpicklerObject *self;
const int MEMO_SIZE = 32;
PyObject **memo = _Unpickler_NewMemo(MEMO_SIZE);
if (memo == NULL) {
return NULL;
}

PickleState *st = _Pickle_GetState(module);
PyObject *stack = Pdata_New(st);
if (stack == NULL) {
goto error;
}

self = PyObject_GC_New(UnpicklerObject, st->Unpickler_Type);
if (self == NULL)
return NULL;
UnpicklerObject *self = PyObject_GC_New(UnpicklerObject,
st->Unpickler_Type);
if (self == NULL) {
goto error;
}

self->stack = (Pdata *)stack;
self->memo = memo;
self->memo_size = MEMO_SIZE;
self->memo_len = 0;
self->pers_func = NULL;
self->pers_func_self = NULL;
memset(&self->buffer, 0, sizeof(Py_buffer));
self->input_buffer = NULL;
self->input_line = NULL;
self->input_len = 0;
Expand All @@ -1653,22 +1677,14 @@ _Unpickler_New(PyObject *module)
self->marks_size = 0;
self->proto = 0;
self->fix_imports = 0;
memset(&self->buffer, 0, sizeof(Py_buffer));
self->memo_size = 32;
self->memo_len = 0;
self->memo = _Unpickler_NewMemo(self->memo_size);
if (self->memo == NULL) {
Py_DECREF(self);
return NULL;
}
self->stack = (Pdata *)Pdata_New(st);
if (self->stack == NULL) {
Py_DECREF(self);
return NULL;
}

PyObject_GC_Track(self);
return self;

error:
PyMem_Free(memo);
Py_XDECREF(stack);
return NULL;
}

/* Returns -1 (with an exception set) on failure, 0 on success. This may
Expand Down
4 changes: 1 addition & 3 deletions Tools/cases_generator/generate_cases.py
Expand Up @@ -230,7 +230,7 @@ class Instruction:

# Parts of the underlying instruction definition
inst: parser.InstDef
kind: typing.Literal["inst", "op", "legacy"] # Legacy means no (input -- output)
kind: typing.Literal["inst", "op"]
name: str
block: parser.Block
block_text: list[str] # Block.text, less curlies, less PREDICT() calls
Expand Down Expand Up @@ -856,8 +856,6 @@ def get_stack_effect_info(
self, thing: parser.InstDef | parser.Macro | parser.Pseudo
) -> tuple[AnyInstruction | None, str, str]:
def effect_str(effects: list[StackEffect]) -> str:
if getattr(thing, "kind", None) == "legacy":
return str(-1)
n_effect, sym_effect = list_effect_size(effects)
if sym_effect:
return f"{sym_effect} + {n_effect}" if n_effect else sym_effect
Expand Down
7 changes: 2 additions & 5 deletions Tools/cases_generator/parser.py
Expand Up @@ -101,7 +101,7 @@ class OpName(Node):
class InstHeader(Node):
override: bool
register: bool
kind: Literal["inst", "op", "legacy"] # Legacy means no (inputs -- outputs)
kind: Literal["inst", "op"]
name: str
inputs: list[InputEffect]
outputs: list[OutputEffect]
Expand All @@ -111,7 +111,7 @@ class InstHeader(Node):
class InstDef(Node):
override: bool
register: bool
kind: Literal["inst", "op", "legacy"]
kind: Literal["inst", "op"]
name: str
inputs: list[InputEffect]
outputs: list[OutputEffect]
Expand Down Expand Up @@ -174,9 +174,6 @@ def inst_header(self) -> InstHeader | None:
if self.expect(lx.RPAREN):
if (tkn := self.peek()) and tkn.kind == lx.LBRACE:
return InstHeader(override, register, kind, name, inp, outp)
elif self.expect(lx.RPAREN) and kind == "inst":
# No legacy stack effect if kind is "op".
return InstHeader(override, register, "legacy", name, [], [])
return None

def io_effect(self) -> tuple[list[InputEffect], list[OutputEffect]]:
Expand Down

0 comments on commit 2fae889

Please sign in to comment.