8000 :Merge remote-tracking branch 'upstream/main' into fwdref-format · python/cpython@675f55c · GitHub
[go: up one dir, main page]

Skip to content

Commit 675f55c

Browse files
committed
:Merge remote-tracking branch 'upstream/main' into fwdref-format
2 parents 28be691 + 426449d commit 675f55c

File tree

20 files changed

+270
-84
lines changed

20 files changed

+270
-84
lines changed

Doc/library/struct.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,9 @@ C11 standard) is supported, the following format characters are available:
273273
+--------+--------------------------+--------------------+----------------+------------+
274274
| Format | C Type | Python type | Standard size | Notes |
275275
+========+==========================+====================+================+============+
276-
| ``E`` | :c:expr:`float complex` | complex | 8 | \(10) |
276+
| ``F`` | :c:expr:`float complex` | complex | 8 | \(10) |
277277
+--------+--------------------------+--------------------+----------------+------------+
278-
| ``C`` | :c:expr:`double complex` | complex | 16 | \(10) |
278+
| ``D`` | :c:expr:`double complex` | complex | 16 | \(10) |
279279
+--------+--------------------------+--------------------+----------------+------------+
280280

281281
.. versionchanged:: 3.3
@@ -285,7 +285,7 @@ C11 standard) is supported, the following format characters are available:
285285
Added support for the ``'e'`` format.
286286

287287
.. versionchanged:: 3.14
288-
Added support for the ``'E'`` and ``'C'`` formats.
288+
Added support for the ``'F'`` and ``'D'`` formats.
289289

290290

291291
Notes:

Doc/whatsnew/3.14.rst

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,49 @@ is unchanged.
264264
Improved error messages
265265
-----------------------
266266

267+
* The interpreter now provides helpful suggestions when it detects typos in Python
268+
keywords. When a word that closely resembles a Python keyword is encountered,
269+
the interpreter will suggest the correct keyword in the error message. This
270+
feature helps programmers quickly identify and fix common typing mistakes. For
271+
example:
272+
273+
.. code-block:: python
274+
275+
>>> whille True:
276+
... pass
277+
Traceback (most recent call last):
278+
File "<stdin>", line 1
279+
whille True:
280+
^^^^^^
281+
SyntaxError: invalid syntax. Did you mean 'while'?
282+
283+
>>> asynch def fetch_data():
284+
... pass
285+
Traceback (most recent call last):
286+
File "<stdin>", line 1
287+
asynch def fetch_data():
288+
^^^^^^
289+
SyntaxError: invalid syntax. Did you mean 'async'?
290+
291+
>>> async def foo():
292+
... awaid fetch_data()
293+
Traceback (most recent call last):
294+
File "<stdin>", line 2
295+
awaid fetch_data()
296+
^^^^^
297+
SyntaxError: invalid syntax. Did you mean 'await'?
298+
299+
>>> raisee ValueError("Error")
300+
Traceback (most recent call last):
301+
File "<stdin>", line 1
302+
raisee ValueError("Error")
303+
^^^^^^
304+
SyntaxError: invalid syntax. Did you mean 'raise'?
305+
306+
While the feature focuses on the most common cases, some variations of
307+
misspellings may still result in regular syntax errors.
308+
(Contributed by Pablo Galindo in :gh:`132449`.)
309+
267310
* When unpacking assignment fails due to incorrect number of variables, the
268311
error message prints the received number of values in more cases than before.
269312
(Contributed by Tushar Sadhwani in :gh:`122239`.)
@@ -1130,7 +1173,7 @@ struct
11301173
------
11311174

11321175
* Support the :c:expr:`float complex` and :c:expr:`double complex` C types in
1133-
the :mod:`struct` module (formatting characters ``'E'`` and ``'C'``,
1176+
the :mod:`struct` module (formatting characters ``'F'`` and ``'D'``,
11341177
respectively) if the compiler has C11 complex arithmetic.
11351178
(Contributed by Sergey B Kirpichev in :gh:`121249`.)
11361179

Lib/ctypes/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,13 +209,13 @@ class c_longdouble(_SimpleCData):
209209

210210
try:
211211
class c_double_complex(_SimpleCData):
212-
_type_ = "C"
212+
_type_ = "D"
213213
_check_size(c_double_complex)
214214
class c_float_complex(_SimpleCData):
215-
_type_ = "E"
215+
_type_ = "F"
216216
_check_size(c_float_complex)
217217
class c_longdouble_complex(_SimpleCData):
218-
_type_ = "F"
218+
_type_ = "G"
219219
except AttributeError:
220220
pass
221221

Lib/test/_test_multiprocessing.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,6 +1516,7 @@ def _test_lock_locked_2processes(cls, lock, event, res):
15161516
res.value = lock.locked()
15171517
event.set()
15181518

1519+
@unittest.skipUnless(HAS_SHAREDCTYPES, 'needs sharedctypes')
15191520
def test_lock_locked_2processes(self):
15201521
if self.TYPE != 'processes':
15211522
self.skipTest('test not appropriate for {}'.format(self.TYPE))

Lib/test/test_capi/test_abstract.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,8 @@ def test_mapping_haskey(self):
460460
self.assertFalse(haskey({}, []))
461461
self.assertEqual(cm.unraisable.exc_type, TypeError)
462462
self.assertEqual(str(cm.unraisable.exc_value),
463-
"unhashable type: 'list'")
463+
"cannot use 'list' as a dict key "
464+
"(unhashable type: 'list')")
464465

465466
with support.catch_unraisable_exception() as cm:
466467
self.assertFalse(haskey([], 1))

Lib/test/test_ctypes/test_c_simple_type_meta.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,11 @@ def test_bad_type_message(self):
160160
class F(metaclass=PyCSimpleType):
161161
_type_ = "\0"
162162
message = str(cm.exception)
163-
expected_type_chars = list('cbBhHiIlLdCEFfuzZqQPXOv?g')
163+
expected_type_chars = list('cbBhHiIlLdDFGfuzZqQPXOv?g')
164164
if not hasattr(ctypes, 'c_float_complex'):
165-
expected_type_chars.remove('C')
166-
expected_type_chars.remove('E')
167165
expected_type_chars.remove('F')
166+
expected_type_chars.remove('D')
167+
expected_type_chars.remove('G')
168168
if not MS_WINDOWS:
169169
expected_type_chars.remove('X')
170170
self.assertIn("'" + ''.join(expected_type_chars) + "'", message)

Lib/test/test_dict.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import gc
44
import pickle
55
import random
6+
import re
67
import string
78
import sys
89
import unittest
@@ -1487,6 +1488,47 @@ def make_pairs():
14871488
self.assertEqual(d.get(key3_3), 44)
14881489
self.assertGreaterEqual(eq_count, 1)
14891490

1491+
def test_unhashable_key(self):
1492+
d = {'a': 1}
1493+
key = [1, 2, 3]
1494+
1495+
def check_unhashable_key():
1496+
msg = "cannot use 'list' as a dict key (unhashable type: 'list')"
1497+
return self.assertRaisesRegex(TypeError, re.escape(msg))
1498+
1499+
with check_unhashable_key():
1500+
key in d
1501+
with check_unhashable_key():
1502+
d[key]
1503+
with check_unhashable_key():
1504+
d[key] = 2
1505+
with check_unhashable_key():
1506+
d.setdefault(key, 2)
1507+
with check_unhashable_key():
1508+
d.pop(key)
1509+
with check_unhashable_key():
1510+
d.get(key)
1511+
1512+
# Only TypeError exception is overriden,
1513+
# other exceptions are left unchanged.
1514+
class HashError:
1515+
def __hash__(self):
1516+
raise KeyError('error')
1517+
1518+
key2 = HashError()
1519+
with self.assertRaises(KeyError):
1520+
key2 in d
1521+
with self.assertRaises(KeyError):
1522+
d[key2]
1523+
with self.assertRaises(KeyError):
1524+
d[key2] = 2
1525+
with self.assertRaises(KeyError):
1526+
d.setdefault(key2, 2)
1527+
with self.assertRaises(KeyError):
1528+
d.pop(key2)
1529+
with self.assertRaises(KeyError):
1530+
d.get(key2)
1531+
14901532

14911533
class CAPITest(unittest.TestCase):
14921534

Lib/test/test_import/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,7 +1055,7 @@ class substr(str):
10551055
""")
10561056
popen = script_helper.spawn_python("main.py", cwd=tmp)
10571057
stdout, stderr = popen.communicate()
1058-
self.assertEqual(stdout.rstrip(), b"unhashable type: 'substr'")
1058+
self.assertIn(b"unhashable type: 'substr'", stdout.rstrip())
10591059

10601060
with open(os.path.join(tmp, "main.py"), "w", encoding='utf-8') as f:
10611061
f.write("""
@@ -1072,7 +1072,7 @@ class substr(str):
10721072

10731073
popen = script_helper.spawn_python("main.py", cwd=tmp)
10741074
stdout, stderr = popen.communicate()
1075-
self.assertEqual(stdout.rstrip(), b"unhashable type: 'substr'")
1075+
self.assertIn(b"unhashable type: 'substr'", stdout.rstrip())
10761076

10771077
# Various issues with sys module
10781078
with open(os.path.join(tmp, "main.py"), "w", encoding='utf-8') as f:

Lib/test/test_set.py

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
import unittest
2-
from test import support
3-
from test.support import warnings_helper
1+
import collections.abc
2+
import copy
43
import gc
5-
import weakref
4+
import itertools
65
import operator
7-
import copy
86
import pickle
9-
from random import randrange, shuffle
7+
import re
8+
import unittest
109
import warnings
11-
import collections
12-
import collections.abc
13-
import itertools
10+
import weakref
11+
from random import randrange, shuffle
12+
from test import support
13+
from test.support import warnings_helper
14+
1415

1516
class PassThru(Exception):
1617
pass
@@ -645,6 +646,35 @@ def test_set_membership(self):
645646
self.assertRaises(KeyError, myset.remove, set(range(1)))
646647
self.assertRaises(KeyError, myset.remove, set(range(3)))
647648

649+
def test_unhashable_element(self):
650+
myset = {'a'}
651+
elem = [1, 2, 3]
652+
653+
def check_unhashable_element():
654+
msg = "cannot use 'list' as a set element (unhashable type: 'list')"
655+
return self.assertRaisesRegex(TypeError, re.escape(msg))
656+
657+
with check_unhashable_element():
658+
elem in myset
659+
with check_unhashable_element():
660+
myset.add(elem)
661+
with check_unhashable_element():
662+
myset.discard(elem)
663+
664+
# Only TypeError exception is overriden,
665+
# other exceptions are left unchanged.
666+
class HashError:
667+
def __hash__(self):
668+
raise KeyError('error')
669+
670+
elem2 = HashError()
671+
with self.assertRaises(KeyError):
672+
elem2 in myset
673+
with self.assertRaises(KeyError):
674+
myset.add(elem2)
675+
with self.assertRaises(KeyError):
676+
myset.discard(elem2)
677+
648678

649679
class SetSubclass(set):
650680
pass

Lib/test/test_struct.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
NAN = float('nan')
2424

2525
try:
26-
struct.pack('C', 1j)
26+
struct.pack('D', 1j)
2727
have_c_complex = True
2828
except struct.error:
2929
have_c_complex = False
@@ -801,23 +801,23 @@ def test_c_complex_round_trip(self):
801801
values = [complex(*_) for _ in combinations([1, -1, 0.0, -0.0, 2,
802802
-3, INF, -INF, NAN], 2)]
803803
for z in values:
804-
for f in ['E', 'C', '>E', '>C', '<E', '<C']:
804+
for f in ['F', 'D', '>F', '>D', '<F', '<D']:
805805
with self.subTest(z=z, format=f):
806806
round_trip = struct.unpack(f, struct.pack(f, z))[0]
807807
self.assertComplexesAreIdentical(z, round_trip)
808808

809809
@unittest.skipIf(have_c_complex, "requires no C11 complex type support")
810810
def test_c_complex_error(self):
811-
msg1 = "'E' format not supported on this system"
812-
msg2 = "'C' format not supported on this system"
811+
msg1 = "'F' format not supported on this system"
812+
msg2 = "'D' format not supported on this system"
813813
with self.assertRaisesRegex(struct.error, msg1):
814-
struct.pack('E', 1j)
814+
struct.pack('F', 1j)
815815
with self.assertRaisesRegex(struct.error, msg1):
816-
struct.unpack('E', b'1')
816+
struct.unpack('F', b'1')
817817
with self.assertRaisesRegex(struct.error, msg2):
818-
struct.pack('C', 1j)
818+
struct.pack('D', 1j)
819819
with self.assertRaisesRegex(struct.error, msg2):
820-
struct.unpack('C', b'1')
820+
struct.unpack('D', b'1')
821821

822822

823823
class UnpackIteratorTest(unittest.TestCase):

Lib/test/test_syntax.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,6 +1838,12 @@
18381838
Traceback (most recent call last):
18391839
SyntaxError: invalid syntax. Did you mean 'for'?
18401840
1841+
1842+
>>> for x im n:
1843+
... pass
1844+
Traceback (most recent call last):
1845+
SyntaxError: invalid syntax. Did you mean 'in'?
1846+
18411847
>>> f(a=23, a=234)
18421848
Traceback (most recent call last):
18431849
...

Lib/traceback.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,10 +1339,14 @@ def _find_keyword_typos(self):
13391339
if tokens_left_to_process < 0:
13401340
break
13411341
# Limit the number of possible matches to try
1342-
matches = difflib.get_close_matches(wrong_name, keyword.kwlist, n=3)
1343-
if not matches and _suggestions is not None:
1342+
max_matches = 3
1343+
matches = []
1344+
if _suggestions is not None:
13441345
suggestion = _suggestions._generate_suggestions(keyword.kwlist, wrong_name)
1345-
matches = [suggestion] if suggestion is not None else matches
1346+
if suggestion:
1347+
matches.append(suggestion)
1348+
matches.extend(difflib.get_close_matches(wrong_name, keyword.kwlist, n=max_matches, cutoff=0.5))
1349+
matches = matches[:max_matches]
13461350
for suggestion in matches:
13471351
if not suggestion or suggestion == wrong_name:
13481352
continue
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Enhance unhashable key/element error messages for :class:`dict` and
2+
:class:`set`. Patch by Victor Stinner.

Modules/_ctypes/callproc.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -648,14 +648,14 @@ union result {
648648
int i;
649649
long l;
650650
long long q;
651-
long double D;
651+
long double g;
652652
double d;
653653
float f;
654654
void *p;
655655
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
656-
double complex C;
657-
float complex E;
658-
long double complex F;
656+
double complex D;
657+
float complex F;
658+
long double complex G;
659659
#endif
660660
};
661661

0 commit comments

Comments
 (0)
0