Skip to content

Commit 14743a1

Browse files
authored
Bump minimum Python type check target version to 3.7 (#15668)
1 parent 1958cb6 commit 14743a1

33 files changed

+75
-314
lines changed

mypy/checkexpr.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3072,7 +3072,7 @@ def visit_op_expr(self, e: OpExpr) -> Type:
30723072
# Expressions of form [...] * e get special type inference.
30733073
return self.check_list_multiply(e)
30743074
if e.op == "%":
3075-
if isinstance(e.left, BytesExpr) and self.chk.options.python_version >= (3, 5):
3075+
if isinstance(e.left, BytesExpr):
30763076
return self.strfrm_checker.check_str_interpolation(e.left, e.right)
30773077
if isinstance(e.left, StrExpr):
30783078
return self.strfrm_checker.check_str_interpolation(e.left, e.right)

mypy/checkstrformat.py

-15
Original file line numberDiff line numberDiff line change
@@ -682,14 +682,6 @@ def check_str_interpolation(self, expr: FormatStringExpr, replacements: Expressi
682682
self.exprchk.accept(expr)
683683
specifiers = parse_conversion_specifiers(expr.value)
684684
has_mapping_keys = self.analyze_conversion_specifiers(specifiers, expr)
685-
if isinstance(expr, BytesExpr) and self.chk.options.python_version < (3, 5):
686-
self.msg.fail(
687-
"Bytes formatting is only supported in Python 3.5 and later",
688-
replacements,
689-
code=codes.STRING_FORMATTING,
690-
)
691-
return AnyType(TypeOfAny.from_error)
692-
693685
if has_mapping_keys is None:
694686
pass # Error was reported
695687
elif has_mapping_keys:
@@ -1023,13 +1015,6 @@ def conversion_type(
10231015
NUMERIC_TYPES = NUMERIC_TYPES_NEW if format_call else NUMERIC_TYPES_OLD
10241016
INT_TYPES = REQUIRE_INT_NEW if format_call else REQUIRE_INT_OLD
10251017
if p == "b" and not format_call:
1026-
if self.chk.options.python_version < (3, 5):
1027-
self.msg.fail(
1028-
'Format character "b" is only supported in Python 3.5 and later',
1029-
context,
1030-
code=codes.STRING_FORMATTING,
1031-
)
1032-
return None
10331018
if not isinstance(expr, BytesExpr):
10341019
self.msg.fail(
10351020
'Format character "b" is only supported on bytes patterns',

mypy/defaults.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
# Earliest Python 3.x version supported via --python-version 3.x. To run
1212
# mypy, at least version PYTHON3_VERSION is needed.
13-
PYTHON3_VERSION_MIN: Final = (3, 4)
13+
PYTHON3_VERSION_MIN: Final = (3, 7) # Keep in sync with typeshed's python support
1414

1515
CACHE_DIR: Final = ".mypy_cache"
1616
CONFIG_FILE: Final = ["mypy.ini", ".mypy.ini"]

mypy/messages.py

+2-11
Original file line numberDiff line numberDiff line change
@@ -1728,7 +1728,6 @@ def need_annotation_for_var(
17281728
self, node: SymbolNode, context: Context, python_version: tuple[int, int] | None = None
17291729
) -> None:
17301730
hint = ""
1731-
has_variable_annotations = not python_version or python_version >= (3, 6)
17321731
pep604_supported = not python_version or python_version >= (3, 10)
17331732
# type to recommend the user adds
17341733
recommended_type = None
@@ -1749,18 +1748,10 @@ def need_annotation_for_var(
17491748
type_dec = f"{type_dec}, {type_dec}"
17501749
recommended_type = f"{alias}[{type_dec}]"
17511750
if recommended_type is not None:
1752-
if has_variable_annotations:
1753-
hint = f' (hint: "{node.name}: {recommended_type} = ...")'
1754-
else:
1755-
hint = f' (hint: "{node.name} = ... # type: {recommended_type}")'
1756-
1757-
if has_variable_annotations:
1758-
needed = "annotation"
1759-
else:
1760-
needed = "comment"
1751+
hint = f' (hint: "{node.name}: {recommended_type} = ...")'
17611752

17621753
self.fail(
1763-
f'Need type {needed} for "{unmangle(node.name)}"{hint}',
1754+
f'Need type annotation for "{unmangle(node.name)}"{hint}',
17641755
context,
17651756
code=codes.VAR_ANNOTATED,
17661757
)

mypy/semanal.py

+4-14
Original file line numberDiff line numberDiff line change
@@ -2521,12 +2521,7 @@ def visit_import_from(self, imp: ImportFrom) -> None:
25212521
elif fullname in self.missing_modules:
25222522
missing_submodule = True
25232523
# If it is still not resolved, check for a module level __getattr__
2524-
if (
2525-
module
2526-
and not node
2527-
and (module.is_stub or self.options.python_version >= (3, 7))
2528-
and "__getattr__" in module.names
2529-
):
2524+
if module and not node and "__getattr__" in module.names:
25302525
# We store the fullname of the original definition so that we can
25312526
# detect whether two imported names refer to the same thing.
25322527
fullname = module_id + "." + id
@@ -5446,11 +5441,8 @@ def visit_yield_expr(self, e: YieldExpr) -> None:
54465441
blocker=True,
54475442
)
54485443
elif self.function_stack[-1].is_coroutine:
5449-
if self.options.python_version < (3, 6):
5450-
self.fail('"yield" in async function', e, serious=True, blocker=True)
5451-
else:
5452-
self.function_stack[-1].is_generator = True
5453-
self.function_stack[-1].is_async_generator = True
5444+
self.function_stack[-1].is_generator = True
5445+
self.function_stack[-1].is_async_generator = True
54545446
else:
54555447
self.function_stack[-1].is_generator = True
54565448
if e.expr:
@@ -5721,9 +5713,7 @@ def get_module_symbol(self, node: MypyFile, name: str) -> SymbolTableNode | None
57215713
sym = SymbolTableNode(GDEF, self.modules[fullname])
57225714
elif self.is_incomplete_namespace(module):
57235715
self.record_incomplete_ref()
5724-
elif "__getattr__" in names and (
5725-
node.is_stub or self.options.python_version >= (3, 7)
5726-
):
5716+
elif "__getattr__" in names:
57275717
gvar = self.create_getattr_var(names["__getattr__"], name, fullname)
57285718
if gvar:
57295719
sym = SymbolTableNode(GDEF, gvar)

mypy/semanal_namedtuple.py

-3
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,6 @@ def check_namedtuple_classdef(
142142
* valid statements
143143
or None, if any of the types are not ready.
144144
"""
145-
if self.options.python_version < (3, 6) and not is_stub_file:
146-
self.fail("NamedTuple class syntax is only supported in Python 3.6", defn)
147-
return [], [], {}, []
148145
if len(defn.base_type_exprs) > 1:
149146
self.fail("NamedTuple should be a single base", defn)
150147
items: list[str] = []

mypy/semanal_pass1.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,9 @@ class SemanticAnalyzerPreAnalysis(TraverserVisitor):
4545
4646
import sys
4747
48-
def do_stuff():
49-
# type: () -> None:
50-
if sys.python_version < (3,):
51-
import xyz # Only available in Python 2
48+
def do_stuff() -> None:
49+
if sys.version_info >= (3, 10):
50+
import xyz # Only available in Python 3.10+
5251
xyz.whatever()
5352
...
5453

test-data/unit/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ feature you added. If you added a new `check-*.test` file, it will be autodiscov
1212
Add the test in this format anywhere in the file:
1313

1414
[case testNewSyntaxBasics]
15-
# flags: --python-version 3.6
15+
# flags: --python-version 3.10
1616
x: int
1717
x = 5
1818
y: int = 5

test-data/unit/check-async-await.test

+5-35
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ async def f() -> None:
183183
[typing fixtures/typing-async.pyi]
184184

185185
[case testAsyncForComprehension]
186-
# flags: --python-version 3.6
187186
from typing import Generic, Iterable, TypeVar, AsyncIterator, Tuple
188187

189188
T = TypeVar('T')
@@ -223,7 +222,6 @@ async def generatorexp(obj: Iterable[int]):
223222
[typing fixtures/typing-async.pyi]
224223

225224
[case testAsyncForComprehensionErrors]
226-
# flags: --python-version 3.6
227225
from typing import Generic, Iterable, TypeVar, AsyncIterator, Tuple
228226

229227
T = TypeVar('T')
@@ -240,16 +238,10 @@ class asyncify(Generic[T], AsyncIterator[T]):
240238
raise StopAsyncIteration
241239

242240
async def wrong_iterable(obj: Iterable[int]):
243-
[i async for i in obj]
244-
[i for i in asyncify(obj)]
245-
{i: i async for i in obj}
246-
{i: i for i in asyncify(obj)}
247-
248-
[out]
249-
main:18: error: "Iterable[int]" has no attribute "__aiter__" (not async iterable)
250-
main:19: error: "asyncify[int]" has no attribute "__iter__"; maybe "__aiter__"? (not iterable)
251-
main:20: error: "Iterable[int]" has no attribute "__aiter__" (not async iterable)
252-
main:21: error: "asyncify[int]" has no attribute "__iter__"; maybe "__aiter__"? (not iterable)
241+
[i async for i in obj] # E: "Iterable[int]" has no attribute "__aiter__" (not async iterable)
242+
[i for i in asyncify(obj)] # E: "asyncify[int]" has no attribute "__iter__"; maybe "__aiter__"? (not iterable)
243+
{i: i async for i in obj} # E: "Iterable[int]" has no attribute "__aiter__" (not async iterable)
244+
{i: i for i in asyncify(obj)} # E: "asyncify[int]" has no attribute "__iter__"; maybe "__aiter__"? (not iterable)
253245
[builtins fixtures/async_await.pyi]
254246
[typing fixtures/typing-async.pyi]
255247

@@ -340,17 +332,6 @@ async def f() -> None:
340332
[builtins fixtures/async_await.pyi]
341333
[typing fixtures/typing-async.pyi]
342334

343-
[case testNoYieldInAsyncDef]
344-
# flags: --python-version 3.5
345-
346-
async def f():
347-
yield None # E: "yield" in async function
348-
async def g():
349-
yield # E: "yield" in async function
350-
async def h():
351-
x = yield # E: "yield" in async function
352-
[builtins fixtures/async_await.pyi]
353-
354335
[case testNoYieldFromInAsyncDef]
355336

356337
async def f():
@@ -422,7 +403,6 @@ def f() -> Generator[int, str, int]:
422403
-- ---------------------------------------------------------------------
423404

424405
[case testAsyncGenerator]
425-
# flags: --python-version 3.6
426406
from typing import AsyncGenerator, Generator
427407

428408
async def f() -> int:
@@ -450,7 +430,6 @@ async def wrong_return() -> Generator[int, None, None]: # E: The return type of
450430
[typing fixtures/typing-async.pyi]
451431

452432
[case testAsyncGeneratorReturnIterator]
453-
# flags: --python-version 3.6
454433
from typing import AsyncIterator
455434

456435
async def gen() -> AsyncIterator[int]:
@@ -466,7 +445,6 @@ async def use_gen() -> None:
466445
[typing fixtures/typing-async.pyi]
467446

468447
[case testAsyncGeneratorManualIter]
469-
# flags: --python-version 3.6
470448
from typing import AsyncGenerator
471449

472450
async def genfunc() -> AsyncGenerator[int, None]:
@@ -484,7 +462,6 @@ async def user() -> None:
484462
[typing fixtures/typing-async.pyi]
485463

486464
[case testAsyncGeneratorAsend]
487-
# flags: --python-version 3.6
488465
from typing import AsyncGenerator
489466

490467
async def f() -> None:
@@ -505,7 +482,6 @@ async def h() -> None:
505482
[typing fixtures/typing-async.pyi]
506483

507484
[case testAsyncGeneratorAthrow]
508-
# flags: --python-version 3.6
509485
from typing import AsyncGenerator
510486

511487
async def gen() -> AsyncGenerator[str, int]:
@@ -524,25 +500,20 @@ async def h() -> None:
524500
[typing fixtures/typing-async.pyi]
525501

526502
[case testAsyncGeneratorNoSyncIteration]
527-
# flags: --python-version 3.6
528503
from typing import AsyncGenerator
529504

530505
async def gen() -> AsyncGenerator[int, None]:
531506
for i in [1, 2, 3]:
532507
yield i
533508

534509
def h() -> None:
535-
for i in gen():
510+
for i in gen(): # E: "AsyncGenerator[int, None]" has no attribute "__iter__"; maybe "__aiter__"? (not iterable)
536511
pass
537512

538513
[builtins fixtures/dict.pyi]
539514
[typing fixtures/typing-async.pyi]
540515

541-
[out]
542-
main:9: error: "AsyncGenerator[int, None]" has no attribute "__iter__"; maybe "__aiter__"? (not iterable)
543-
544516
[case testAsyncGeneratorNoYieldFrom]
545-
# flags: --python-version 3.6
546517
from typing import AsyncGenerator
547518

548519
async def f() -> AsyncGenerator[int, None]:
@@ -555,7 +526,6 @@ async def gen() -> AsyncGenerator[int, None]:
555526
[typing fixtures/typing-async.pyi]
556527

557528
[case testAsyncGeneratorNoReturnWithValue]
558-
# flags: --python-version 3.6
559529
from typing import AsyncGenerator
560530

561531
async def return_int() -> AsyncGenerator[int, None]:

0 commit comments

Comments
 (0)