Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8fec43c

Browse files
authored
Merge branch 'main' into gh-25949
2 parents ec1f2fe + f042646 commit 8fec43c

11 files changed

Lines changed: 550 additions & 396 deletions

File tree

Doc/tutorial/datastructures.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ An example that uses most of the list methods::
122122

123123
You might have noticed that methods like ``insert``, ``remove`` or ``sort`` that
124124
only modify the list have no return value printed -- they return the default
125-
``None``. [1]_ This is a design principle for all mutable data structures in
125+
``None``. [#]_ This is a design principle for all mutable data structures in
126126
Python.
127127

128128
Another thing you might notice is that not all data can be sorted or
@@ -731,5 +731,5 @@ interpreter will raise a :exc:`TypeError` exception.
731731

732732
.. rubric:: Footnotes
733733

734-
.. [1] Other languages may return the mutated object, which allows method
734+
.. [#] Other languages may return the mutated object, which allows method
735735
chaining, such as ``d->insert("a")->remove("b")->sort();``.

Doc/whatsnew/3.12.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,18 @@ Important deprecations, removals or restrictions:
7070

7171
* :pep:`623`, Remove wstr from Unicode
7272

73+
Improved Error Messages
74+
=======================
75+
76+
* Improve the :exc:`SyntaxError` error message when the user types ``import x
77+
from y`` instead of ``from y import x``. Contributed by Pablo Galindo in :gh:`98931`.
78+
79+
>>> import a.y.z from b.y.z
80+
Traceback (most recent call last):
81+
File "<stdin>", line 1
82+
import a.y.z from b.y.z
83+
^^^^^^^^^^^^^^^^^^^^^^^
84+
SyntaxError: Did you mean to use 'from ... import ...' instead?
7385

7486
New Features
7587
============

Grammar/python.gram

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,10 @@ yield_stmt[stmt_ty]: y=yield_expr { _PyAST_Expr(y, EXTRA) }
194194

195195
assert_stmt[stmt_ty]: 'assert' a=expression b=[',' z=expression { z }] { _PyAST_Assert(a, b, EXTRA) }
196196

197-
import_stmt[stmt_ty]: import_name | import_from
197+
import_stmt[stmt_ty]:
198+
| invalid_import
199+
| import_name
200+
| import_from
198201

199202
# Import statements
200203
# -----------------
@@ -1230,6 +1233,10 @@ invalid_group:
12301233
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use starred expression here") }
12311234
| '(' a='**' expression ')' {
12321235
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use double starred expression here") }
1236+
invalid_import:
1237+
| a='import' dotted_name 'from' dotted_name {
1238+
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "Did you mean to use 'from ... import ...' instead?") }
1239+
12331240
invalid_import_from_targets:
12341241
| import_from_as_names ',' NEWLINE {
12351242
RAISE_SYNTAX_ERROR("trailing comma not allowed without surrounding parentheses") }

Lib/collections/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,8 +1011,8 @@ def __len__(self):
10111011

10121012
def __iter__(self):
10131013
d = {}
1014-
for mapping in reversed(self.maps):
1015-
d.update(dict.fromkeys(mapping)) # reuses stored hash values if possible
1014+
for mapping in map(dict.fromkeys, reversed(self.maps)):
1015+
d |= mapping # reuses stored hash values if possible
10161016
return iter(d)
10171017

10181018
def __contains__(self, key):

Lib/test/test_syntax.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,6 +1584,22 @@
15841584
Traceback (most recent call last):
15851585
SyntaxError: trailing comma not allowed without surrounding parentheses
15861586
1587+
>>> import a from b
1588+
Traceback (most recent call last):
1589+
SyntaxError: Did you mean to use 'from ... import ...' instead?
1590+
1591+
>>> import a.y.z from b.y.z
1592+
Traceback (most recent call last):
1593+
SyntaxError: Did you mean to use 'from ... import ...' instead?
1594+
1595+
>>> import a from b as bar
1596+
Traceback (most recent call last):
1597+
SyntaxError: Did you mean to use 'from ... import ...' instead?
1598+
1599+
>>> import a.y.z from b.y.z as bar
1600+
Traceback (most recent call last):
1601+
SyntaxError: Did you mean to use 'from ... import ...' instead?
1602+
15871603
# Check that we dont raise the "trailing comma" error if there is more
15881604
# input to the left of the valid part that we parsed.
15891605

Lib/test/test_typing.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3916,6 +3916,34 @@ class A:
39163916
# C version of GenericAlias
39173917
self.assertEqual(list[A()].__parameters__, (T,))
39183918

3919+
def test_non_generic_subscript(self):
3920+
T = TypeVar('T')
3921+
class G(Generic[T]):
3922+
pass
3923+
class A:
3924+
__parameters__ = (T,)
3925+
3926+
for s in (int, G, A, List, list,
3927+
TypeVar, TypeVarTuple, ParamSpec,
3928+
types.GenericAlias, types.UnionType):
3929+
3930+
for t in Tuple, tuple:
3931+
with self.subTest(tuple=t, sub=s):
3932+
self.assertEqual(t[s, T][int], t[s, int])
3933+
self.assertEqual(t[T, s][int], t[int, s])
3934+
a = t[s]
3935+
with self.assertRaises(TypeError):
3936+
a[int]
3937+
3938+
for c in Callable, collections.abc.Callable:
3939+
with self.subTest(callable=c, sub=s):
3940+
self.assertEqual(c[[s], T][int], c[[s], int])
3941+
self.assertEqual(c[[T], s][int], c[[int], s])
3942+
a = c[[s], s]
3943+
with self.assertRaises(TypeError):
3944+
a[int]
3945+
3946+
39193947
class ClassVarTests(BaseTestCase):
39203948

39213949
def test_basics(self):

Lib/typing.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,6 +1437,10 @@ def _determine_new_args(self, args):
14371437
new_args = []
14381438
for old_arg in self.__args__:
14391439

1440+
if isinstance(old_arg, type):
1441+
new_args.append(old_arg)
1442+
continue
1443+
14401444
substfunc = getattr(old_arg, '__typing_subst__', None)
14411445
if substfunc:
14421446
new_arg = substfunc(new_arg_by_param[old_arg])
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fix subscription of type aliases containing bare generic types or types like
2+
:class:`~typing.TypeVar`: for example ``tuple[A, T][int]`` and
3+
``tuple[TypeVar, T][int]``, where ``A`` is a generic type, and ``T`` is a
4+
type variable.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve the :exc:`SyntaxError` error message when the user types ``import x
2+
from y`` instead of ``from y import x``. Patch by Pablo Galindo

Objects/genericaliasobject.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,13 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje
458458
}
459459
for (Py_ssize_t iarg = 0, jarg = 0; iarg < nargs; iarg++) {
460460
PyObject *arg = PyTuple_GET_ITEM(args, iarg);
461+
if (PyType_Check(arg)) {
462+
Py_INCREF(arg);
463+
PyTuple_SET_ITEM(newargs, jarg, arg);
464+
jarg++;
465+
continue;
466+
}
467+
461468
int unpack = _is_unpacked_typevartuple(arg);
462469
if (unpack < 0) {
463470
Py_DECREF(newargs);

0 commit comments

Comments
 (0)