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
2 changes: 1 addition & 1 deletion Include/internal/pycore_flowgraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ int _PyCfg_OptimizeCodeUnit(struct _PyCfgBuilder *g, PyObject *consts, PyObject
struct _PyCfgBuilder* _PyCfg_FromInstructionSequence(_PyInstructionSequence *seq);
int _PyCfg_ToInstructionSequence(struct _PyCfgBuilder *g, _PyInstructionSequence *seq);
int _PyCfg_OptimizedCfgToInstructionSequence(struct _PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd,
int code_flags, int *stackdepth, int *nlocalsplus,
int *stackdepth, int *nlocalsplus,
_PyInstructionSequence *seq);

PyCodeObject *
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_instruction_sequence.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ int _PyInstructionSequence_SetAnnotationsCode(_PyInstructionSequence *seq,
_PyInstructionSequence *annotations);
int _PyInstructionSequence_AddNested(_PyInstructionSequence *seq, _PyInstructionSequence *nested);
void PyInstructionSequence_Fini(_PyInstructionSequence *seq);
_PyInstruction _PyInstructionSequence_GetInstruction(_PyInstructionSequence *seq, int pos);

extern PyTypeObject _PyInstructionSequence_Type;
#define _PyInstructionSequence_Check(v) Py_IS_TYPE((v), &_PyInstructionSequence_Type)
Expand Down
3 changes: 2 additions & 1 deletion Include/internal/pycore_magic_number.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ Known values:
Python 3.15a4 3657 (Add BINARY_OP_SUBSCR_USTR_INT)
Python 3.15a4 3658 (Optimize bytecode for list/set called on genexp)
Python 3.15a4 3659 (Add CALL_FUNCTION_EX specialization)
Python 3.15a4 3660 (Change generator preamble code)
Python 3.16 will start with 3700
Expand All @@ -303,7 +304,7 @@ PC/launcher.c must also be updated.
*/

#define PYC_MAGIC_NUMBER 3659
#define PYC_MAGIC_NUMBER 3660
/* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes
(little-endian) and then appending b'\r\n'. */
#define PYC_MAGIC_NUMBER_TOKEN \
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1298,7 +1298,7 @@ def return_genexp():
x
in
y)
genexp_lines = [0, 4, 2, 0, 4]
genexp_lines = [4, 0, 4, 2, 0, 4]

genexp_code = return_genexp.__code__.co_consts[0]
code_lines = self.get_code_lines(genexp_code)
Expand Down
8 changes: 4 additions & 4 deletions Lib/test/test_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -875,11 +875,11 @@ def foo(x):
Disassembly of <code object <genexpr> at 0x..., file "%s", line %d>:
-- COPY_FREE_VARS 1
%4d RETURN_GENERATOR
%4d LOAD_FAST 0 (.0)
GET_ITER
RETURN_GENERATOR
POP_TOP
L1: RESUME 0
LOAD_FAST 0 (.0)
GET_ITER
L2: FOR_ITER 14 (to L3)
STORE_FAST 1 (z)
LOAD_DEREF 2 (x)
Expand All @@ -897,7 +897,7 @@ def foo(x):
-- L4: CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR)
RERAISE 1
ExceptionTable:
L1 to L4 -> L4 [0] lasti
L1 to L4 -> L4 [2] lasti
""" % (dis_nested_1,
__file__,
_h.__code__.co_firstlineno + 3,
Expand Down
34 changes: 19 additions & 15 deletions Lib/test/test_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,21 +357,25 @@ def gen(it):
yield x
return gen(range(10))

def process_tests(self, get_generator):
for obj in self.iterables:
g_obj = get_generator(obj)
with self.subTest(g_obj=g_obj, obj=obj):
self.assertListEqual(list(g_obj), list(obj))
def process_tests(self, get_generator, changes_iterable):
if changes_iterable:
for obj in self.iterables:
g_obj = get_generator(obj)
with self.subTest(g_obj=g_obj, obj=obj):
self.assertListEqual(list(g_obj), list(obj))

g_iter = get_generator(iter(obj))
with self.subTest(g_iter=g_iter, obj=obj):
self.assertListEqual(list(g_iter), list(obj))
g_iter = get_generator(iter(obj))
with self.subTest(g_iter=g_iter, obj=obj):
self.assertListEqual(list(g_iter), list(obj))

err_regex = "'.*' object is not iterable"
for obj in self.non_iterables:
g_obj = get_generator(obj)
with self.subTest(g_obj=g_obj):
self.assertRaisesRegex(TypeError, err_regex, list, g_obj)
if changes_iterable:
self.assertRaisesRegex(TypeError, err_regex, list, g_obj)
else:
next(g_obj)

def test_modify_f_locals(self):
def modify_f_locals(g, local, obj):
Expand All @@ -384,22 +388,22 @@ def get_generator_genexpr(obj):
def get_generator_genfunc(obj):
return modify_f_locals(self.genfunc(), 'it', obj)

self.process_tests(get_generator_genexpr)
self.process_tests(get_generator_genfunc)
self.process_tests(get_generator_genexpr, False)
self.process_tests(get_generator_genfunc, True)

def test_new_gen_from_gi_code(self):
def new_gen_from_gi_code(g, obj):
generator_func = types.FunctionType(g.gi_code, {})
return generator_func(obj)

def get_generator_genexpr(obj):
return new_gen_from_gi_code(self.genexpr(), obj)
for obj in self.non_iterables:
with self.assertRaises(TypeError):
new_gen_from_gi_code(self.genexpr(), obj)

def get_generator_genfunc(obj):
return new_gen_from_gi_code(self.genfunc(), obj)

self.process_tests(get_generator_genexpr)
self.process_tests(get_generator_genfunc)
self.process_tests(get_generator_genfunc, True)


class ExceptionTest(unittest.TestCase):
Expand Down
77 changes: 42 additions & 35 deletions Lib/test/test_struct.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,56 +433,63 @@ def test_unpack_from(self):
self.assertEqual(s.unpack_from(buffer=test_string, offset=2),
(b'cd01',))

def test_pack_into(self):
def _test_pack_into(self, pack_into):
test_string = b'Reykjavik rocks, eow!'
writable_buf = array.array('b', b' '*100)
fmt = '21s'
s = struct.Struct(fmt)
writable_buf = memoryview(array.array('b', b' '*100))

# Test without offset
s.pack_into(writable_buf, 0, test_string)
pack_into(writable_buf, 0, test_string)
from_buf = writable_buf.tobytes()[:len(test_string)]
self.assertEqual(from_buf, test_string)

# Test with offset.
s.pack_into(writable_buf, 10, test_string)
pack_into(writable_buf, 10, test_string)
from_buf = writable_buf.tobytes()[:len(test_string)+10]
self.assertEqual(from_buf, test_string[:10] + test_string)

# Test with negative offset.
pack_into(writable_buf, -30, test_string)
from_buf = writable_buf.tobytes()[-30:-30+len(test_string)]
self.assertEqual(from_buf, test_string)

# Go beyond boundaries.
small_buf = array.array('b', b' '*10)
self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
test_string)
self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
test_string)
with self.assertRaises((ValueError, struct.error)):
pack_into(small_buf, 0, test_string)
with self.assertRaises((ValueError, struct.error)):
pack_into(writable_buf, 90, test_string)
with self.assertRaises((ValueError, struct.error)):
pack_into(writable_buf, -10, test_string)
with self.assertRaises((ValueError, struct.error)):
pack_into(writable_buf, 150, test_string)
with self.assertRaises((ValueError, struct.error)):
pack_into(writable_buf, -150, test_string)

# Test invalid buffer.
self.assertRaises(TypeError, pack_into, b' '*100, 0, test_string)
self.assertRaises(TypeError, pack_into, ' '*100, 0, test_string)
self.assertRaises(TypeError, pack_into, [0]*100, 0, test_string)
self.assertRaises(TypeError, pack_into, None, 0, test_string)
self.assertRaises(TypeError, pack_into, writable_buf[::2], 0, test_string)
self.assertRaises(TypeError, pack_into, writable_buf[::-1], 0, test_string)

# Test bogus offset (issue bpo-3694)
with self.assertRaises(TypeError):
pack_into(writable_buf, None, test_string)
with self.assertRaises(TypeError):
pack_into(writable_buf, 0.0, test_string)
with self.assertRaises((IndexError, OverflowError)):
pack_into(writable_buf, 2**1000, test_string)
with self.assertRaises((IndexError, OverflowError)):
pack_into(writable_buf, -2**1000, test_string)

# Test bogus offset (issue 3694)
sb = small_buf
self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,
None)
def test_pack_into(self):
s = struct.Struct('21s')
self._test_pack_into(s.pack_into)

def test_pack_into_fn(self):
test_string = b'Reykjavik rocks, eow!'
writable_buf = array.array('b', b' '*100)
fmt = '21s'
pack_into = lambda *args: struct.pack_into(fmt, *args)

# Test without offset.
pack_into(writable_buf, 0, test_string)
from_buf = writable_buf.tobytes()[:len(test_string)]
self.assertEqual(from_buf, test_string)

# Test with offset.
pack_into(writable_buf, 10, test_string)
from_buf = writable_buf.tobytes()[:len(test_string)+10]
self.assertEqual(from_buf, test_string[:10] + test_string)

# Go beyond boundaries.
small_buf = array.array('b', b' '*10)
self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0,
test_string)
self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,
test_string)
pack_into = lambda *args: struct.pack_into('21s', *args)
self._test_pack_into(pack_into)

def test_unpack_with_buffer(self):
# SF bug 1563759: struct.unpack doesn't support buffer protocol objects
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Generator expressions in 3.15 now conform to the documented behavior when
the iterable does not support iteration. This matches the behavior in 3.14
and earlier
5 changes: 3 additions & 2 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -3189,14 +3189,15 @@ dummy_func(
#ifdef Py_STATS
_Py_GatherStats_GetIter(iterable);
#endif
/* before: [obj]; after [getiter(obj)] */
PyTypeObject *tp = PyStackRef_TYPE(iterable);
if (tp == &PyTuple_Type || tp == &PyList_Type) {
/* Leave iterable on stack and pushed tagged 0 */
iter = iterable;
DEAD(iterable);
index_or_null = PyStackRef_TagInt(0);
}
else {
/* Pop iterable, and push iterator then NULL */
PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable));
PyStackRef_CLOSE(iterable);
ERROR_IF(iter_o == NULL);
Expand Down Expand Up @@ -5033,7 +5034,7 @@ dummy_func(
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
ERROR_IF(gen == NULL);
assert(STACK_LEVEL() == 0);
assert(STACK_LEVEL() <= 2);
SAVE_STACK();
_PyInterpreterFrame *gen_frame = &gen->gi_iframe;
frame->instr_ptr++;
Expand Down
Loading
Loading