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 .github/workflows/jit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ jobs:
include:
- target: i686-pc-windows-msvc/msvc
architecture: Win32
runner: windows-latest
runner: windows-2022
- target: x86_64-pc-windows-msvc/msvc
architecture: x64
runner: windows-latest
runner: windows-2022
- target: aarch64-pc-windows-msvc/msvc
architecture: ARM64
runner: windows-11-arm
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/reusable-windows-msi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ env:
jobs:
build:
name: installer for ${{ inputs.arch }}
runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-latest' }}
runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2022' }}
timeout-minutes: 60
env:
ARCH: ${{ inputs.arch }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/reusable-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ env:
jobs:
build:
name: Build and test (${{ inputs.arch }})
runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-latest' }}
runs-on: ${{ inputs.arch == 'arm64' && 'windows-11-arm' || 'windows-2022' }}
timeout-minutes: 60
env:
ARCH: ${{ inputs.arch }}
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/tail-call.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ jobs:
include:
# - target: i686-pc-windows-msvc/msvc
# architecture: Win32
# runner: windows-latest
# runner: windows-2022
- target: x86_64-pc-windows-msvc/msvc
architecture: x64
runner: windows-latest
runner: windows-2022
# - target: aarch64-pc-windows-msvc/msvc
# architecture: ARM64
# runner: windows-latest
# runner: windows-2022
- target: x86_64-apple-darwin/clang
architecture: x86_64
runner: macos-13
Expand Down
8 changes: 8 additions & 0 deletions Grammar/python.gram
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,14 @@ invalid_assert_stmt:
a, b,
"cannot assign to %s here. Maybe you meant '==' instead of '='?",
_PyPegen_get_expr_name(a)) }
| 'assert' a=expression ':=' b=expression {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(
a, b,
"cannot use named expression without parentheses here") }
| 'assert' expression ',' a=expression ':=' b=expression {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(
a, b,
"cannot use named expression without parentheses here") }
invalid_block:
| NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block") }
invalid_comprehension:
Expand Down
4 changes: 3 additions & 1 deletion Include/internal/pycore_magic_number.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,13 @@ Known values:
Python 3.14b1 3624 (Don't optimize LOAD_FAST when local is killed by DELETE_FAST)
Python 3.14b3 3625 (Fix handling of opcodes that may leave operands on the stack when optimizing LOAD_FAST)
Python 3.14rc2 3626 (Fix missing exception handlers in logical expression)
Python 3.14rc3 3627 (Fix miscompilation of some module-level annotations)
Python 3.15a0 3650 (Initial version)
Python 3.15a1 3651 (Simplify LOAD_CONST)
Python 3.15a1 3652 (Virtual iterators)
Python 3.15a1 3653 (Fix handling of opcodes that may leave operands on the stack when optimizing LOAD_FAST)
Python 3.15a1 3654 (Fix missing exception handlers in logical expression)
Python 3.15a1 3655 (Fix miscompilation of some module-level annotations)


Python 3.16 will start with 3700
Expand All @@ -297,7 +299,7 @@ PC/launcher.c must also be updated.

*/

#define PYC_MAGIC_NUMBER 3654
#define PYC_MAGIC_NUMBER 3655
/* 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
26 changes: 26 additions & 0 deletions Lib/test/test_ctypes/test_prototypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,32 @@ def test_paramflags(self):
self.assertEqual(func(None), None)
self.assertEqual(func(input=None), None)

def test_invalid_paramflags(self):
proto = CFUNCTYPE(c_int, c_char_p)
with self.assertRaises(ValueError):
func = proto(("myprintf", testdll), ((1, "fmt"), (1, "arg1")))

def test_invalid_setattr_argtypes(self):
proto = CFUNCTYPE(c_int, c_char_p)
func = proto(("myprintf", testdll), ((1, "fmt"),))

with self.assertRaisesRegex(TypeError, "_argtypes_ must be a sequence of types"):
func.argtypes = 123
self.assertEqual(func.argtypes, (c_char_p,))

with self.assertRaisesRegex(ValueError, "paramflags must have the same length as argtypes"):
func.argtypes = (c_char_p, c_int)
self.assertEqual(func.argtypes, (c_char_p,))

def test_paramflags_outarg(self):
proto = CFUNCTYPE(c_int, c_char_p, c_int)
with self.assertRaisesRegex(TypeError, "must be a pointer type"):
func = proto(("myprintf", testdll), ((1, "fmt"), (2, "out")))

proto = CFUNCTYPE(c_int, c_char_p, c_void_p)
func = proto(("myprintf", testdll), ((1, "fmt"), (2, "out")))
with self.assertRaisesRegex(TypeError, "must be a pointer type"):
func.argtypes = (c_char_p, c_int)

def test_int_pointer_arg(self):
func = testdll._testfunc_p_p
Expand Down
43 changes: 42 additions & 1 deletion Lib/test/test_inspect/test_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -1778,14 +1778,55 @@ class C(metaclass=M):

class TestFormatAnnotation(unittest.TestCase):
def test_typing_replacement(self):
from test.typinganndata.ann_module9 import ann, ann1
from test.typinganndata.ann_module9 import A, ann, ann1
self.assertEqual(inspect.formatannotation(ann), 'List[str] | int')
self.assertEqual(inspect.formatannotation(ann1), 'List[testModule.typing.A] | int')

self.assertEqual(inspect.formatannotation(A, 'testModule.typing'), 'A')
self.assertEqual(inspect.formatannotation(A, 'other'), 'testModule.typing.A')
self.assertEqual(
inspect.formatannotation(ann1, 'testModule.typing'),
'List[testModule.typing.A] | int',
)

def test_forwardref(self):
fwdref = ForwardRef('fwdref')
self.assertEqual(inspect.formatannotation(fwdref), 'fwdref')

def test_formatannotationrelativeto(self):
from test.typinganndata.ann_module9 import A, ann1

# Builtin types:
self.assertEqual(
inspect.formatannotationrelativeto(object)(type),
'type',
)

# Custom types:
self.assertEqual(
inspect.formatannotationrelativeto(None)(A),
'testModule.typing.A',
)

class B: ...
B.__module__ = 'testModule.typing'

self.assertEqual(
inspect.formatannotationrelativeto(B)(A),
'A',
)

self.assertEqual(
inspect.formatannotationrelativeto(object)(A),
'testModule.typing.A',
)

# Not an instance of "type":
self.assertEqual(
inspect.formatannotationrelativeto(A)(ann1),
'List[testModule.typing.A] | int',
)


class TestIsMethodDescriptor(unittest.TestCase):

Expand Down
9 changes: 7 additions & 2 deletions Lib/test/test_syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -2690,10 +2690,15 @@ def f(x: *b)
Asserts:

>>> assert (a := 1) # ok
>>> # TODO(@sobolevn): improve this message in the next PR
>>> assert 1, (a := 1) # ok

>>> assert a := 1
Traceback (most recent call last):
SyntaxError: invalid syntax
SyntaxError: cannot use named expression without parentheses here

>>> assert 1, a := 1
Traceback (most recent call last):
SyntaxError: cannot use named expression without parentheses here

>>> assert 1 = 2 = 3
Traceback (most recent call last):
Expand Down
37 changes: 37 additions & 0 deletions Lib/test/test_type_annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -835,3 +835,40 @@ def test_complex_comprehension_inlining_exec(self):
genexp = annos["unique_name_2"][0]
lamb = list(genexp)[0]
self.assertEqual(lamb(), 42)

# gh-138349
def test_module_level_annotation_plus_listcomp(self):
cases = [
"""
def report_error():
pass
try:
[0 for name_2 in unique_name_0 if (lambda: name_2)]
except:
pass
annotated_name: 0
""",
"""
class Generic:
pass
try:
[0 for name_2 in unique_name_0 if (0 for unique_name_1 in unique_name_2 for unique_name_3 in name_2)]
except:
pass
annotated_name: 0
""",
"""
class Generic:
pass
annotated_name: 0
try:
[0 for name_2 in [[0]] for unique_name_1 in unique_name_2 if (lambda: name_2)]
except:
pass
""",
]
for code in cases:
with self.subTest(code=code):
mod = build_module(code)
annos = mod.__annotations__
self.assertEqual(annos, {"annotated_name": 0})
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix crash in certain cases where a module contains both a module-level
annotation and a comprehension.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improve :exc:`SyntaxError` message for :keyword:`assert` in cases like
``assert a := b``.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix segmentation faults in the :mod:`ctypes` module due to invalid :attr:`~ctypes._CFuncPtr.argtypes`. Patch by Dung Nguyen.
33 changes: 22 additions & 11 deletions Modules/_ctypes/_ctypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -3634,6 +3634,9 @@ atomic_xgetref(PyObject *obj, PyObject **field)
#endif
}

static int
_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags, PyObject *argtypes);



/*[clinic input]
Expand Down Expand Up @@ -3747,16 +3750,22 @@ static int
_ctypes_CFuncPtr_argtypes_set_impl(PyCFuncPtrObject *self, PyObject *value)
/*[clinic end generated code: output=596a36e2ae89d7d1 input=c4627573e980aa8b]*/
{
PyObject *converters;

if (value == NULL || value == Py_None) {
atomic_xsetref(&self->argtypes, NULL);
atomic_xsetref(&self->converters, NULL);
} else {
ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
converters = converters_from_argtypes(st, value);
PyTypeObject *type = Py_TYPE(self);
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));

PyObject *converters = converters_from_argtypes(st, value);
if (!converters)
return -1;

/* Verify paramflags again due to constraints with argtypes */
if (!_validate_paramflags(st, type, self->paramflags, value)) {
Py_DECREF(converters);
return -1;
}
atomic_xsetref(&self->converters, converters);
Py_INCREF(value);
atomic_xsetref(&self->argtypes, value);
Expand Down Expand Up @@ -3886,10 +3895,9 @@ _check_outarg_type(ctypes_state *st, PyObject *arg, Py_ssize_t index)

/* Returns 1 on success, 0 on error */
static int
_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags)
_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags, PyObject *argtypes)
{
Py_ssize_t i, len;
PyObject *argtypes;

StgInfo *info;
if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) {
Expand All @@ -3900,10 +3908,13 @@ _validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags)
"abstract class");
return 0;
}
argtypes = info->argtypes;
if (argtypes == NULL) {
argtypes = info->argtypes;
}

if (paramflags == NULL || info->argtypes == NULL)
if (paramflags == NULL || argtypes == NULL) {
return 1;
}

if (!PyTuple_Check(paramflags)) {
PyErr_SetString(PyExc_TypeError,
Expand All @@ -3912,7 +3923,7 @@ _validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags)
}

len = PyTuple_GET_SIZE(paramflags);
if (len != PyTuple_GET_SIZE(info->argtypes)) {
if (len != PyTuple_GET_SIZE(argtypes)) {
PyErr_SetString(PyExc_ValueError,
"paramflags must have the same length as argtypes");
return 0;
Expand Down Expand Up @@ -4088,7 +4099,7 @@ PyCFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
#endif
#undef USE_DLERROR
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
if (!_validate_paramflags(st, type, paramflags)) {
if (!_validate_paramflags(st, type, paramflags, NULL)) {
Py_DECREF(ftuple);
return NULL;
}
Expand Down Expand Up @@ -4132,7 +4143,7 @@ PyCFuncPtr_FromVtblIndex(PyTypeObject *type, PyObject *args, PyObject *kwds)
paramflags = NULL;

ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
if (!_validate_paramflags(st, type, paramflags)) {
if (!_validate_paramflags(st, type, paramflags, NULL)) {
return NULL;
}
self = (PyCFuncPtrObject *)generic_pycdata_new(st, type, args, kwds);
Expand Down
Loading
Loading