Skip to content

Commit 747000c

Browse files
author
Erlend E. Aasland
committed
Sync with main bco. GH-27942
2 parents 06e242c + 24da544 commit 747000c

File tree

19 files changed

+556
-262
lines changed

19 files changed

+556
-262
lines changed

Include/internal/pycore_frame.h

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,9 @@ typedef struct _interpreter_frame {
2929
PyObject *generator;
3030
struct _interpreter_frame *previous;
3131
int f_lasti; /* Last instruction if called */
32-
int stackdepth; /* Depth of value stack */
33-
int nlocalsplus;
34-
PyFrameState f_state; /* What state the frame is in */
35-
PyObject *stack[1];
32+
int stacktop; /* Offset of TOS from localsplus */
33+
PyFrameState f_state; /* What state the frame is in */
34+
PyObject *localsplus[1];
3635
} InterpreterFrame;
3736

3837
static inline int _PyFrame_IsRunnable(InterpreterFrame *f) {
@@ -47,6 +46,26 @@ static inline int _PyFrameHasCompleted(InterpreterFrame *f) {
4746
return f->f_state > FRAME_EXECUTING;
4847
}
4948

49+
static inline PyObject **_PyFrame_Stackbase(InterpreterFrame *f) {
50+
return f->localsplus + f->f_code->co_nlocalsplus;
51+
}
52+
53+
static inline PyObject *_PyFrame_StackPeek(InterpreterFrame *f) {
54+
assert(f->stacktop > f->f_code->co_nlocalsplus);
55+
return f->localsplus[f->stacktop-1];
56+
}
57+
58+
static inline PyObject *_PyFrame_StackPop(InterpreterFrame *f) {
59+
assert(f->stacktop > f->f_code->co_nlocalsplus);
60+
f->stacktop--;
61+
return f->localsplus[f->stacktop];
62+
}
63+
64+
static inline void _PyFrame_StackPush(InterpreterFrame *f, PyObject *value) {
65+
f->localsplus[f->stacktop] = value;
66+
f->stacktop++;
67+
}
68+
5069
#define FRAME_SPECIALS_SIZE ((sizeof(InterpreterFrame)-1)/sizeof(PyObject *))
5170

5271
InterpreterFrame *
@@ -61,8 +80,7 @@ _PyFrame_InitializeSpecials(
6180
frame->f_builtins = Py_NewRef(con->fc_builtins);
6281
frame->f_globals = Py_NewRef(con->fc_globals);
6382
frame->f_locals = Py_XNewRef(locals);
64-
frame->nlocalsplus = nlocalsplus;
65-
frame->stackdepth = 0;
83+
frame->stacktop = nlocalsplus;
6684
frame->frame_obj = NULL;
6785
frame->generator = NULL;
6886
frame->f_lasti = -1;
@@ -75,7 +93,19 @@ _PyFrame_InitializeSpecials(
7593
static inline PyObject**
7694
_PyFrame_GetLocalsArray(InterpreterFrame *frame)
7795
{
78-
return ((PyObject **)frame) - frame->nlocalsplus;
96+
return frame->localsplus;
97+
}
98+
99+
static inline PyObject**
100+
_PyFrame_GetStackPointer(InterpreterFrame *frame)
101+
{
102+
return frame->localsplus+frame->stacktop;
103+
}
104+
105+
static inline void
106+
_PyFrame_SetStackPointer(InterpreterFrame *frame, PyObject **stack_pointer)
107+
{
108+
frame->stacktop = (int)(stack_pointer - frame->localsplus);
79109
}
80110

81111
/* For use by _PyFrame_GetFrameObject

Lib/enum.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,17 +1390,28 @@ def _power_of_two(value):
13901390
return value == 2 ** _high_bit(value)
13911391

13921392
def global_enum_repr(self):
1393-
return '%s.%s' % (self.__class__.__module__, self._name_)
1393+
"""
1394+
use module.enum_name instead of class.enum_name
1395+
1396+
the module is the last module in case of a multi-module name
1397+
"""
1398+
module = self.__class__.__module__.split('.')[-1]
1399+
return '%s.%s' % (module, self._name_)
13941400

13951401
def global_flag_repr(self):
1396-
module = self.__class__.__module__
1402+
"""
1403+
use module.flag_name instead of class.flag_name
1404+
1405+
the module is the last module in case of a multi-module name
1406+
"""
1407+
module = self.__class__.__module__.split('.')[-1]
13971408
cls_name = self.__class__.__name__
13981409
if self._name_ is None:
1399-
return "%x" % (module, cls_name, self._value_)
1410+
return "%s.%s(0x%x)" % (module, cls_name, self._value_)
14001411
if _is_single_bit(self):
14011412
return '%s.%s' % (module, self._name_)
14021413
if self._boundary_ is not FlagBoundary.KEEP:
1403-
return module + module.join(self.name.split('|'))
1414+
return '|'.join(['%s.%s' % (module, name) for name in self.name.split('|')])
14041415
else:
14051416
name = []
14061417
for n in self._name_.split('|'):

Lib/sqlite3/test/dbapi.py

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,17 @@
2222

2323
import contextlib
2424
import sqlite3 as sqlite
25+
import subprocess
2526
import sys
2627
import threading
2728
import unittest
2829

29-
from test.support import check_disallow_instantiation, threading_helper, bigmemtest
30+
from test.support import (
31+
bigmemtest,
32+
check_disallow_instantiation,
33+
threading_helper,
34+
SHORT_TIMEOUT,
35+
)
3036
from test.support.os_helper import TESTFN, unlink
3137

3238

@@ -986,6 +992,77 @@ def test_on_conflict_replace(self):
986992
self.assertEqual(self.cu.fetchall(), [('Very different data!', 'foo')])
987993

988994

995+
class MultiprocessTests(unittest.TestCase):
996+
CONNECTION_TIMEOUT = SHORT_TIMEOUT / 1000. # Defaults to 30 ms
997+
998+
def tearDown(self):
999+
unlink(TESTFN)
1000+
1001+
def test_ctx_mgr_rollback_if_commit_failed(self):
1002+
# bpo-27334: ctx manager does not rollback if commit fails
1003+
SCRIPT = f"""if 1:
1004+
import sqlite3
1005+
def wait():
1006+
print("started")
1007+
assert "database is locked" in input()
1008+
1009+
cx = sqlite3.connect("{TESTFN}", timeout={self.CONNECTION_TIMEOUT})
1010+
cx.create_function("wait", 0, wait)
1011+
with cx:
1012+
cx.execute("create table t(t)")
1013+
try:
1014+
# execute two transactions; both will try to lock the db
1015+
cx.executescript('''
1016+
-- start a transaction and wait for parent
1017+
begin transaction;
1018+
select * from t;
1019+
select wait();
1020+
rollback;
1021+
1022+
-- start a new transaction; would fail if parent holds lock
1023+
begin transaction;
1024+
select * from t;
1025+
rollback;
1026+
''')
1027+
finally:
1028+
cx.close()
1029+
"""
1030+
1031+
# spawn child process
1032+
proc = subprocess.Popen(
1033+
[sys.executable, "-c", SCRIPT],
1034+
encoding="utf-8",
1035+
bufsize=0,
1036+
stdin=subprocess.PIPE,
1037+
stdout=subprocess.PIPE,
1038+
)
1039+
self.addCleanup(proc.communicate)
1040+
1041+
# wait for child process to start
1042+
self.assertEqual("started", proc.stdout.readline().strip())
1043+
1044+
cx = sqlite.connect(TESTFN, timeout=self.CONNECTION_TIMEOUT)
1045+
try: # context manager should correctly release the db lock
1046+
with cx:
1047+
cx.execute("insert into t values('test')")
1048+
except sqlite.OperationalError as exc:
1049+
proc.stdin.write(str(exc))
1050+
else:
1051+
proc.stdin.write("no error")
1052+
finally:
1053+
cx.close()
1054+
1055+
# terminate child process
1056+
self.assertIsNone(proc.returncode)
1057+
try:
1058+
proc.communicate(input="end", timeout=SHORT_TIMEOUT)
1059+
except subprocess.TimeoutExpired:
1060+
proc.kill()
1061+
proc.communicate()
1062+
raise
1063+
self.assertEqual(proc.returncode, 0)
1064+
1065+
9891066
def suite():
9901067
tests = [
9911068
ClosedConTests,
@@ -995,6 +1072,7 @@ def suite():
9951072
CursorTests,
9961073
ExtensionTests,
9971074
ModuleTests,
1075+
MultiprocessTests,
9981076
OpenTests,
9991077
SqliteOnConflictTests,
10001078
ThreadTests,

Lib/test/test_enum.py

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ def load_tests(loader, tests, ignore):
2828
))
2929
return tests
3030

31+
MODULE = ('test.test_enum', '__main__')[__name__=='__main__']
32+
SHORT_MODULE = MODULE.split('.')[-1]
33+
3134
# for pickle tests
3235
try:
3336
class Stooges(Enum):
@@ -143,6 +146,23 @@ def __init__(self, fget=None, fset=None, fdel=None, doc=None):
143146
def __get__(self, instance, ownerclass):
144147
return self.fget(ownerclass)
145148

149+
# for global repr tests
150+
151+
@enum.global_enum
152+
class HeadlightsK(IntFlag, boundary=enum.KEEP):
153+
OFF_K = 0
154+
LOW_BEAM_K = auto()
155+
HIGH_BEAM_K = auto()
156+
FOG_K = auto()
157+
158+
159+
@enum.global_enum
160+
class HeadlightsC(IntFlag, boundary=enum.CONFORM):
161+
OFF_C = 0
162+
LOW_BEAM_C = auto()
163+
HIGH_BEAM_C = auto()
164+
FOG_C = auto()
165+
146166

147167
# tests
148168

@@ -3224,6 +3244,34 @@ def test_repr(self):
32243244
self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
32253245
self.assertEqual(repr(Open(~4)), '-5')
32263246

3247+
def test_global_repr_keep(self):
3248+
self.assertEqual(
3249+
repr(HeadlightsK(0)),
3250+
'%s.OFF_K' % SHORT_MODULE,
3251+
)
3252+
self.assertEqual(
3253+
repr(HeadlightsK(2**0 + 2**2 + 2**3)),
3254+
'%(m)s.LOW_BEAM_K|%(m)s.FOG_K|0x8' % {'m': SHORT_MODULE},
3255+
)
3256+
self.assertEqual(
3257+
repr(HeadlightsK(2**3)),
3258+
'%(m)s.HeadlightsK(0x8)' % {'m': SHORT_MODULE},
3259+
)
3260+
3261+
def test_global_repr_conform1(self):
3262+
self.assertEqual(
3263+
repr(HeadlightsC(0)),
3264+
'%s.OFF_C' % SHORT_MODULE,
3265+
)
3266+
self.assertEqual(
3267+
repr(HeadlightsC(2**0 + 2**2 + 2**3)),
3268+
'%(m)s.LOW_BEAM_C|%(m)s.FOG_C' % {'m': SHORT_MODULE},
3269+
)
3270+
self.assertEqual(
3271+
repr(HeadlightsC(2**3)),
3272+
'%(m)s.OFF_C' % {'m': SHORT_MODULE},
3273+
)
3274+
32273275
def test_format(self):
32283276
Perm = self.Perm
32293277
self.assertEqual(format(Perm.R, ''), '4')
@@ -4085,7 +4133,7 @@ def setUp(self):
40854133
def test_convert_value_lookup_priority(self):
40864134
test_type = enum.IntEnum._convert_(
40874135
'UnittestConvert',
4088-
('test.test_enum', '__main__')[__name__=='__main__'],
4136+
MODULE,
40894137
filter=lambda x: x.startswith('CONVERT_TEST_'))
40904138
# We don't want the reverse lookup value to vary when there are
40914139
# multiple possible names for a given value. It should always
@@ -4095,7 +4143,7 @@ def test_convert_value_lookup_priority(self):
40954143
def test_convert(self):
40964144
test_type = enum.IntEnum._convert_(
40974145
'UnittestConvert',
4098-
('test.test_enum', '__main__')[__name__=='__main__'],
4146+
MODULE,
40994147
filter=lambda x: x.startswith('CONVERT_TEST_'))
41004148
# Ensure that test_type has all of the desired names and values.
41014149
self.assertEqual(test_type.CONVERT_TEST_NAME_F,
@@ -4115,7 +4163,7 @@ def test_convert_warn(self):
41154163
with self.assertWarns(DeprecationWarning):
41164164
enum.IntEnum._convert(
41174165
'UnittestConvert',
4118-
('test.test_enum', '__main__')[__name__=='__main__'],
4166+
MODULE,
41194167
filter=lambda x: x.startswith('CONVERT_TEST_'))
41204168

41214169
@unittest.skipUnless(python_version >= (3, 9),
@@ -4124,16 +4172,15 @@ def test_convert_raise(self):
41244172
with self.assertRaises(AttributeError):
41254173
enum.IntEnum._convert(
41264174
'UnittestConvert',
4127-
('test.test_enum', '__main__')[__name__=='__main__'],
4175+
MODULE,
41284176
filter=lambda x: x.startswith('CONVERT_TEST_'))
41294177

41304178
def test_convert_repr_and_str(self):
4131-
module = ('test.test_enum', '__main__')[__name__=='__main__']
41324179
test_type = enum.IntEnum._convert_(
41334180
'UnittestConvert',
4134-
module,
4181+
MODULE,
41354182
filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
4136-
self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % module)
4183+
self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % SHORT_MODULE)
41374184
self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
41384185
self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
41394186

@@ -4151,7 +4198,7 @@ def setUp(self):
41514198
def test_convert(self):
41524199
test_type = enum.StrEnum._convert_(
41534200
'UnittestConvert',
4154-
('test.test_enum', '__main__')[__name__=='__main__'],
4201+
MODULE,
41554202
filter=lambda x: x.startswith('CONVERT_STR_'))
41564203
# Ensure that test_type has all of the desired names and values.
41574204
self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
@@ -4162,12 +4209,11 @@ def test_convert(self):
41624209
[], msg='Names other than CONVERT_STR_* found.')
41634210

41644211
def test_convert_repr_and_str(self):
4165-
module = ('test.test_enum', '__main__')[__name__=='__main__']
41664212
test_type = enum.StrEnum._convert_(
41674213
'UnittestConvert',
4168-
module,
4214+
MODULE,
41694215
filter=lambda x: x.startswith('CONVERT_STR_'))
4170-
self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % module)
4216+
self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % SHORT_MODULE)
41714217
self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
41724218
self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
41734219

Lib/test/test_marshal.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,31 @@ def test_eof(self):
344344
for i in range(len(data)):
345345
self.assertRaises(EOFError, marshal.loads, data[0: i])
346346

347+
def test_deterministic_sets(self):
348+
# bpo-37596: To support reproducible builds, sets and frozensets need to
349+
# have their elements serialized in a consistent order (even when they
350+
# have been scrambled by hash randomization):
351+
for kind in ("set", "frozenset"):
352+
for elements in (
353+
"float('nan'), b'a', b'b', b'c', 'x', 'y', 'z'",
354+
# Also test for bad interactions with backreferencing:
355+
"('string', 1), ('string', 2), ('string', 3)",
356+
):
357+
s = f"{kind}([{elements}])"
358+
with self.subTest(s):
359+
# First, make sure that our test case still has different
360+
# orders under hash seeds 0 and 1. If this check fails, we
361+
# need to update this test with different elements:
362+
args = ["-c", f"print({s})"]
363+
_, repr_0, _ = assert_python_ok(*args, PYTHONHASHSEED="0")
364+
_, repr_1, _ = assert_python_ok(*args, PYTHONHASHSEED="1")
365+
self.assertNotEqual(repr_0, repr_1)
366+
# Then, perform the actual test:
367+
args = ["-c", f"import marshal; print(marshal.dumps({s}))"]
368+
_, dump_0, _ = assert_python_ok(*args, PYTHONHASHSEED="0")
369+
_, dump_1, _ = assert_python_ok(*args, PYTHONHASHSEED="1")
370+
self.assertEqual(dump_0, dump_1)
371+
347372
LARGE_SIZE = 2**31
348373
pointer_size = 8 if sys.maxsize > 0xFFFFFFFF else 4
349374

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix some edge cases of ``enum.Flag`` string representation in the REPL.
2+
Patch by Pablo Galindo.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The :mod:`sqlite3` context manager now performs a rollback (thus releasing the
2+
database lock) if commit failed. Patch by Luca Citi and Erlend E. Aasland.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Ensure that :class:`set` and :class:`frozenset` objects are always
2+
:mod:`marshalled <marshal>` reproducibly.

0 commit comments

Comments
 (0)