From 2edaf35ec1f91c139dfe1930b1b0d1e1cac59599 Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Sun, 2 Jul 2023 18:59:35 -0700 Subject: [PATCH] Drop support for running with Python 3.7 (#15566) --- .github/workflows/docs.yml | 2 +- .github/workflows/test.yml | 49 ++-- build-requirements.txt | 1 - docs/source/additional_features.rst | 7 +- docs/source/getting_started.rst | 2 +- misc/build-debug-python.sh | 2 +- mypy-requirements.txt | 4 +- mypy/defaults.py | 2 +- mypy/dmypy_server.py | 2 - mypy/fastparse.py | 271 +++++------------- mypy/messages.py | 2 + mypy/pyinfo.py | 8 +- mypy/test/meta/test_update_data.py | 5 +- mypy/test/testcheck.py | 4 +- mypy/test/testdaemon.py | 4 - mypy/test/testfinegrained.py | 5 +- mypy/test/testpep561.py | 5 - mypy/test/teststubgen.py | 1 + mypy/test/teststubtest.py | 73 +++-- mypy/util.py | 6 +- mypy_self_check.ini | 2 +- mypyc/test/test_run.py | 6 +- pyproject.toml | 5 +- setup.py | 13 +- test-data/unit/check-columns.test | 4 - test-data/unit/check-incremental.test | 4 +- .../unit/check-parameter-specification.test | 7 - test-data/unit/check-typeguard.test | 4 - test-data/unit/cmdline.test | 21 -- test-data/unit/daemon.test | 8 +- test-data/unit/fine-grained-blockers.test | 10 - .../unit/fine-grained-cache-incremental.test | 6 +- test-data/unit/fine-grained.test | 22 -- test-data/unit/pythoneval.test | 2 +- test-data/unit/semanal-errors.test | 38 --- test-data/unit/semanal-statements.test | 2 - 36 files changed, 163 insertions(+), 446 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 3e06b5e909f1..5dc86a1159f4 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: '3.7' + python-version: '3.8' - name: Install tox run: pip install --upgrade 'setuptools!=50' tox==4.4.4 - name: Setup tox environment diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5bd20f2773c5..05e52ad95a17 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,37 +26,27 @@ jobs: fail-fast: false matrix: include: - - name: Test suite with py37-windows-64 - python: '3.7' - arch: x64 - os: windows-latest - toxenv: py37 - - name: Test suite with py38-ubuntu + # Make sure to run mypyc compiled unit tests for both + # the oldest and newest supported Python versions + - name: Test suite with py38-ubuntu, mypyc-compiled python: '3.8' arch: x64 os: ubuntu-latest toxenv: py tox_extra_args: "-n 2" - - name: Test suite with py39-ubuntu - python: '3.9' - arch: x64 - os: ubuntu-latest - toxenv: py - tox_extra_args: "-n 2" - - name: Test suite with py37-ubuntu, mypyc-compiled - python: '3.7' + test_mypyc: true + - name: Test suite with py38-windows-64 + python: '3.8' arch: x64 - os: ubuntu-latest - toxenv: py + os: windows-latest + toxenv: py38 tox_extra_args: "-n 2" - test_mypyc: true - - name: Test suite with py310-ubuntu, mypyc-compiled - python: '3.10' + - name: Test suite with py39-ubuntu + python: '3.9' arch: x64 os: ubuntu-latest toxenv: py tox_extra_args: "-n 2" - test_mypyc: true - name: Test suite with py310-ubuntu python: '3.10' arch: x64 @@ -70,29 +60,32 @@ jobs: toxenv: py tox_extra_args: "-n 2" test_mypyc: true - - name: mypyc runtime tests with py37-macos - python: '3.7' + + - name: mypyc runtime tests with py38-macos + python: '3.8.17' arch: x64 os: macos-latest toxenv: py tox_extra_args: "-n 2 mypyc/test/test_run.py mypyc/test/test_external.py" - - name: mypyc runtime tests with py37-debug-build-ubuntu - python: '3.7.13' + - name: mypyc runtime tests with py38-debug-build-ubuntu + python: '3.8.17' arch: x64 os: ubuntu-latest toxenv: py tox_extra_args: "-n 2 mypyc/test/test_run.py mypyc/test/test_external.py" debug_build: true - - name: Type check our own code (py37-ubuntu) - python: '3.7' + + - name: Type check our own code (py38-ubuntu) + python: '3.8' arch: x64 os: ubuntu-latest toxenv: type - - name: Type check our own code (py37-windows-64) - python: '3.7' + - name: Type check our own code (py38-windows-64) + python: '3.8' arch: x64 os: windows-latest toxenv: type + # We also run these checks with pre-commit in CI, # but it's useful to run them with tox too, # to ensure the tox env works as expected diff --git a/build-requirements.txt b/build-requirements.txt index 0b1e6d43103a..aac1b95eddf7 100644 --- a/build-requirements.txt +++ b/build-requirements.txt @@ -2,4 +2,3 @@ -r mypy-requirements.txt types-psutil types-setuptools -types-typed-ast>=1.5.8.5,<1.6.0 diff --git a/docs/source/additional_features.rst b/docs/source/additional_features.rst index 10122e9b2fa9..5dd136476eaa 100644 --- a/docs/source/additional_features.rst +++ b/docs/source/additional_features.rst @@ -9,10 +9,9 @@ of the previous sections. Dataclasses *********** -In Python 3.7, a new :py:mod:`dataclasses` module has been added to the standard library. -This module allows defining and customizing simple boilerplate-free classes. -They can be defined using the :py:func:`@dataclasses.dataclass -` decorator: +The :py:mod:`dataclasses` module allows defining and customizing simple +boilerplate-free classes. They can be defined using the +:py:func:`@dataclasses.dataclass ` decorator: .. code-block:: python diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 9b927097cfd2..11f915005695 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -16,7 +16,7 @@ may not make much sense otherwise. Installing and running mypy *************************** -Mypy requires Python 3.7 or later to run. You can install mypy using pip: +Mypy requires Python 3.8 or later to run. You can install mypy using pip: .. code-block:: shell diff --git a/misc/build-debug-python.sh b/misc/build-debug-python.sh index f652d6ad9937..8dd1bff4c9ed 100755 --- a/misc/build-debug-python.sh +++ b/misc/build-debug-python.sh @@ -26,7 +26,7 @@ fi curl -O https://www.python.org/ftp/python/$VERSION/Python-$VERSION.tgz tar zxf Python-$VERSION.tgz cd Python-$VERSION -CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS" ./configure CFLAGS="-DPy_DEBUG -DPy_TRACE_REFS -DPYMALLOC_DEBUG" --with-pydebug --prefix=$PREFIX +CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS" ./configure CFLAGS="-DPy_DEBUG -DPy_TRACE_REFS -DPYMALLOC_DEBUG" --with-pydebug --prefix=$PREFIX --with-trace-refs make -j4 make install $PREFIX/bin/python3 -m pip install virtualenv diff --git a/mypy-requirements.txt b/mypy-requirements.txt index ba6f069661ad..f81412be761e 100644 --- a/mypy-requirements.txt +++ b/mypy-requirements.txt @@ -1,6 +1,4 @@ # NOTE: this needs to be kept in sync with the "requires" list in pyproject.toml -typing_extensions>=4.1.0; python_version >= '3.8' -typing_extensions>=4.7.0; python_version < '3.8' +typing_extensions>=4.1.0 mypy_extensions>=1.0.0 -typed_ast>=1.4.0,<2; python_version<'3.8' tomli>=1.1.0; python_version<'3.11' diff --git a/mypy/defaults.py b/mypy/defaults.py index d167997464f4..59a99cd58888 100644 --- a/mypy/defaults.py +++ b/mypy/defaults.py @@ -8,7 +8,7 @@ # Earliest fully supported Python 3.x version. Used as the default Python # version in tests. Mypy wheels should be built starting with this version, # and CI tests should be run on this version (and later versions). -PYTHON3_VERSION: Final = (3, 7) +PYTHON3_VERSION: Final = (3, 8) # Earliest Python 3.x version supported via --python-version 3.x. To run # mypy, at least version PYTHON3_VERSION is needed. diff --git a/mypy/dmypy_server.py b/mypy/dmypy_server.py index 54544f4c01ce..2427f83c5767 100644 --- a/mypy/dmypy_server.py +++ b/mypy/dmypy_server.py @@ -896,8 +896,6 @@ def cmd_inspect( force_reload: bool = False, ) -> dict[str, object]: """Locate and inspect expression(s).""" - if sys.version_info < (3, 8): - return {"error": 'Python 3.8 required for "inspect" command'} if not self.fine_grained_manager: return { "error": 'Command "inspect" is only valid after a "check" command' diff --git a/mypy/fastparse.py b/mypy/fastparse.py index fe59ff48bdfc..3f4e2f4c927d 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -118,123 +118,57 @@ ) from mypy.util import bytes_to_human_readable_repr, unnamed_function -try: - # pull this into a final variable to make mypyc be quiet about the - # the default argument warning - PY_MINOR_VERSION: Final = sys.version_info[1] - - # Check if we can use the stdlib ast module instead of typed_ast. - if sys.version_info >= (3, 8): - import ast as ast3 - - assert ( - "kind" in ast3.Constant._fields - ), f"This 3.8.0 alpha ({sys.version.split()[0]}) is too old; 3.8.0a3 required" - # TODO: Num, Str, Bytes, NameConstant, Ellipsis are deprecated in 3.8. - # TODO: Index, ExtSlice are deprecated in 3.9. - from ast import ( - AST, - Attribute, - Bytes, - Call, - Ellipsis as ast3_Ellipsis, - Expression as ast3_Expression, - FunctionType, - Index, - Name, - NameConstant, - Num, - Starred, - Str, - UnaryOp, - USub, - ) +# pull this into a final variable to make mypyc be quiet about the +# the default argument warning +PY_MINOR_VERSION: Final = sys.version_info[1] - def ast3_parse( - source: str | bytes, filename: str, mode: str, feature_version: int = PY_MINOR_VERSION - ) -> AST: - return ast3.parse( - source, - filename, - mode, - type_comments=True, # This works the magic - feature_version=feature_version, - ) +import ast as ast3 - NamedExpr = ast3.NamedExpr - Constant = ast3.Constant - else: - from typed_ast import ast3 - from typed_ast.ast3 import ( - AST, - Attribute, - Bytes, - Call, - Ellipsis as ast3_Ellipsis, - Expression as ast3_Expression, - FunctionType, - Index, - Name, - NameConstant, - Num, - Starred, - Str, - UnaryOp, - USub, - ) +# TODO: Index, ExtSlice are deprecated in 3.9. +from ast import AST, Attribute, Call, FunctionType, Index, Name, Starred, UnaryOp, USub - def ast3_parse( - source: str | bytes, filename: str, mode: str, feature_version: int = PY_MINOR_VERSION - ) -> AST: - return ast3.parse(source, filename, mode, feature_version=feature_version) - - # These don't exist before 3.8 - NamedExpr = Any - Constant = Any - - if sys.version_info >= (3, 10): - Match = ast3.Match - MatchValue = ast3.MatchValue - MatchSingleton = ast3.MatchSingleton - MatchSequence = ast3.MatchSequence - MatchStar = ast3.MatchStar - MatchMapping = ast3.MatchMapping - MatchClass = ast3.MatchClass - MatchAs = ast3.MatchAs - MatchOr = ast3.MatchOr - AstNode = Union[ast3.expr, ast3.stmt, ast3.pattern, ast3.ExceptHandler] - else: - Match = Any - MatchValue = Any - MatchSingleton = Any - MatchSequence = Any - MatchStar = Any - MatchMapping = Any - MatchClass = Any - MatchAs = Any - MatchOr = Any - AstNode = Union[ast3.expr, ast3.stmt, ast3.ExceptHandler] - if sys.version_info >= (3, 11): - TryStar = ast3.TryStar - else: - TryStar = Any -except ImportError: - try: - from typed_ast import ast35 # type: ignore[attr-defined] # noqa: F401 - except ImportError: - print( - "The typed_ast package is not installed.\n" - "You can install it with `python3 -m pip install typed-ast`.", - file=sys.stderr, - ) - else: - print( - "You need a more recent version of the typed_ast package.\n" - "You can update to the latest version with " - "`python3 -m pip install -U typed-ast`.", - file=sys.stderr, - ) - sys.exit(1) + +def ast3_parse( + source: str | bytes, filename: str, mode: str, feature_version: int = PY_MINOR_VERSION +) -> AST: + return ast3.parse( + source, + filename, + mode, + type_comments=True, # This works the magic + feature_version=feature_version, + ) + + +NamedExpr = ast3.NamedExpr +Constant = ast3.Constant + +if sys.version_info >= (3, 10): + Match = ast3.Match + MatchValue = ast3.MatchValue + MatchSingleton = ast3.MatchSingleton + MatchSequence = ast3.MatchSequence + MatchStar = ast3.MatchStar + MatchMapping = ast3.MatchMapping + MatchClass = ast3.MatchClass + MatchAs = ast3.MatchAs + MatchOr = ast3.MatchOr + AstNode = Union[ast3.expr, ast3.stmt, ast3.pattern, ast3.ExceptHandler] +else: + Match = Any + MatchValue = Any + MatchSingleton = Any + MatchSequence = Any + MatchStar = Any + MatchMapping = Any + MatchClass = Any + MatchAs = Any + MatchOr = Any + AstNode = Union[ast3.expr, ast3.stmt, ast3.ExceptHandler] +if sys.version_info >= (3, 11): + TryStar = ast3.TryStar +else: + TryStar = Any N = TypeVar("N", bound=Node) @@ -370,7 +304,7 @@ def parse_type_comment( raise SyntaxError else: ignored = None - assert isinstance(typ, ast3_Expression) + assert isinstance(typ, ast3.Expression) converted = TypeConverter( errors, line=line, override_column=column, is_evaluated=False ).visit(typ.body) @@ -961,8 +895,10 @@ def do_func_def( func_type_ast = ast3_parse(n.type_comment, "", "func_type") assert isinstance(func_type_ast, FunctionType) # for ellipsis arg - if len(func_type_ast.argtypes) == 1 and isinstance( - func_type_ast.argtypes[0], ast3_Ellipsis + if ( + len(func_type_ast.argtypes) == 1 + and isinstance(func_type_ast.argtypes[0], Constant) + and func_type_ast.argtypes[0].value is Ellipsis ): if n.returns: # PEP 484 disallows both type annotations and type comments @@ -1052,15 +988,9 @@ def do_func_def( func_type.line = lineno if n.decorator_list: - if sys.version_info < (3, 8): - # Before 3.8, [typed_]ast the line number points to the first decorator. - # In 3.8, it points to the 'def' line, where we want it. - deco_line = lineno - lineno += len(n.decorator_list) # this is only approximately true - else: - # Set deco_line to the old pre-3.8 lineno, in order to keep - # existing "# type: ignore" comments working: - deco_line = n.decorator_list[0].lineno + # Set deco_line to the old pre-3.8 lineno, in order to keep + # existing "# type: ignore" comments working: + deco_line = n.decorator_list[0].lineno var = Var(func_def.name) var.is_ready = False @@ -1188,12 +1118,9 @@ def visit_ClassDef(self, n: ast3.ClassDef) -> ClassDef: cdef.decorators = self.translate_expr_list(n.decorator_list) # Set lines to match the old mypy 0.700 lines, in order to keep # existing "# type: ignore" comments working: - if sys.version_info < (3, 8): - cdef.line = n.lineno + len(n.decorator_list) - cdef.deco_line = n.lineno - else: - cdef.line = n.lineno - cdef.deco_line = n.decorator_list[0].lineno if n.decorator_list else None + cdef.line = n.lineno + cdef.deco_line = n.decorator_list[0].lineno if n.decorator_list else None + cdef.column = n.col_offset cdef.end_line = getattr(n, "end_lineno", None) cdef.end_column = getattr(n, "end_col_offset", None) @@ -1580,9 +1507,9 @@ def visit_Constant(self, n: Constant) -> Any: if val is None: e = NameExpr("None") elif isinstance(val, str): - e = StrExpr(n.s) + e = StrExpr(val) elif isinstance(val, bytes): - e = BytesExpr(bytes_to_human_readable_repr(n.s)) + e = BytesExpr(bytes_to_human_readable_repr(val)) elif isinstance(val, bool): # Must check before int! e = NameExpr(str(val)) elif isinstance(val, int): @@ -1597,28 +1524,6 @@ def visit_Constant(self, n: Constant) -> Any: raise RuntimeError("Constant not implemented for " + str(type(val))) return self.set_line(e, n) - # Num(object n) -- a number as a PyObject. - def visit_Num(self, n: ast3.Num) -> IntExpr | FloatExpr | ComplexExpr: - # The n field has the type complex, but complex isn't *really* - # a parent of int and float, and this causes isinstance below - # to think that the complex branch is always picked. Avoid - # this by throwing away the type. - val: object = n.n - if isinstance(val, int): - e: IntExpr | FloatExpr | ComplexExpr = IntExpr(val) - elif isinstance(val, float): - e = FloatExpr(val) - elif isinstance(val, complex): - e = ComplexExpr(val) - else: - raise RuntimeError("num not implemented for " + str(type(val))) - return self.set_line(e, n) - - # Str(string s) - def visit_Str(self, n: Str) -> StrExpr: - e = StrExpr(n.s) - return self.set_line(e, n) - # JoinedStr(expr* values) def visit_JoinedStr(self, n: ast3.JoinedStr) -> Expression: # Each of n.values is a str or FormattedValue; we just concatenate @@ -1643,7 +1548,7 @@ def visit_FormattedValue(self, n: ast3.FormattedValue) -> Expression: # to allow mypyc to support f-strings with format specifiers and conversions. val_exp = self.visit(n.value) val_exp.set_line(n.lineno, n.col_offset) - conv_str = "" if n.conversion is None or n.conversion < 0 else "!" + chr(n.conversion) + conv_str = "" if n.conversion < 0 else "!" + chr(n.conversion) format_string = StrExpr("{" + conv_str + ":{}}") format_spec_exp = self.visit(n.format_spec) if n.format_spec is not None else StrExpr("") format_string.set_line(n.lineno, n.col_offset) @@ -1654,21 +1559,6 @@ def visit_FormattedValue(self, n: ast3.FormattedValue) -> Expression: ) return self.set_line(result_expression, n) - # Bytes(bytes s) - def visit_Bytes(self, n: ast3.Bytes) -> BytesExpr | StrExpr: - e = BytesExpr(bytes_to_human_readable_repr(n.s)) - return self.set_line(e, n) - - # NameConstant(singleton value) - def visit_NameConstant(self, n: NameConstant) -> NameExpr: - e = NameExpr(str(n.value)) - return self.set_line(e, n) - - # Ellipsis - def visit_Ellipsis(self, n: ast3_Ellipsis) -> EllipsisExpr: - e = EllipsisExpr() - return self.set_line(e, n) - # Attribute(expr value, identifier attr, expr_context ctx) def visit_Attribute(self, n: Attribute) -> MemberExpr | SuperExpr: value = n.value @@ -1955,9 +1845,9 @@ def translate_argument_list(self, l: Sequence[ast3.expr]) -> TypeList: return TypeList([self.visit(e) for e in l], line=self.line) def _extract_argument_name(self, n: ast3.expr) -> str | None: - if isinstance(n, Str): - return n.s.strip() - elif isinstance(n, NameConstant) and str(n.value) == "None": + if isinstance(n, Constant) and isinstance(n.value, str): + return n.value.strip() + elif isinstance(n, Constant) and n.value is None: return None self.fail( message_registry.ARG_NAME_EXPECTED_STRING_LITERAL.format(type(n).__name__), @@ -1983,12 +1873,6 @@ def visit_BinOp(self, n: ast3.BinOp) -> Type: uses_pep604_syntax=True, ) - def visit_NameConstant(self, n: NameConstant) -> Type: - if isinstance(n.value, bool): - return RawExpressionType(n.value, "builtins.bool", line=self.line) - else: - return UnboundType(str(n.value), line=self.line, column=n.col_offset) - # Only for 3.8 and newer def visit_Constant(self, n: Constant) -> Type: val = n.value @@ -2041,23 +1925,6 @@ def numeric_type(self, value: object, n: AST) -> Type: numeric_value, type_name, line=self.line, column=getattr(n, "col_offset", -1) ) - # These next three methods are only used if we are on python < - # 3.8, using typed_ast. They are defined unconditionally because - # mypyc can't handle conditional method definitions. - - # Num(number n) - def visit_Num(self, n: Num) -> Type: - return self.numeric_type(n.n, n) - - # Str(string s) - def visit_Str(self, n: Str) -> Type: - return parse_type_string(n.s, "builtins.str", self.line, n.col_offset) - - # Bytes(bytes s) - def visit_Bytes(self, n: Bytes) -> Type: - contents = bytes_to_human_readable_repr(n.s) - return RawExpressionType(contents, "builtins.bytes", self.line, column=n.col_offset) - def visit_Index(self, n: ast3.Index) -> Type: # cast for mypyc's benefit on Python 3.9 value = self.visit(cast(Any, n).value) @@ -2086,10 +1953,10 @@ def visit_Subscript(self, n: ast3.Subscript) -> Type: for s in dims: if getattr(s, "col_offset", None) is None: if isinstance(s, ast3.Index): - s.col_offset = s.value.col_offset # type: ignore[attr-defined] + s.col_offset = s.value.col_offset elif isinstance(s, ast3.Slice): assert s.lower is not None - s.col_offset = s.lower.col_offset # type: ignore[attr-defined] + s.col_offset = s.lower.col_offset sliceval = ast3.Tuple(dims, n.ctx) empty_tuple_index = False @@ -2130,10 +1997,6 @@ def visit_Attribute(self, n: Attribute) -> Type: else: return self.invalid_type(n) - # Ellipsis - def visit_Ellipsis(self, n: ast3_Ellipsis) -> Type: - return EllipsisType(line=self.line) - # List(expr* elts, expr_context ctx) def visit_List(self, n: ast3.List) -> Type: assert isinstance(n.ctx, ast3.Load) diff --git a/mypy/messages.py b/mypy/messages.py index ea7923c59778..8e59e7329168 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -235,6 +235,8 @@ def span_from_context(ctx: Context) -> Iterable[int]: Current logic is a bit tricky, to keep as much backwards compatibility as possible. We may reconsider this to always be a single line (or otherwise simplify it) when we drop Python 3.7. + + TODO: address this in follow up PR """ if isinstance(ctx, (ClassDef, FuncDef)): return range(ctx.deco_line or ctx.line, ctx.line + 1) diff --git a/mypy/pyinfo.py b/mypy/pyinfo.py index 778b0b163ce6..f262ac8b2132 100644 --- a/mypy/pyinfo.py +++ b/mypy/pyinfo.py @@ -2,10 +2,10 @@ """Utilities to find the site and prefix information of a Python executable. -This file MUST remain compatible with all Python 3.7+ versions. Since we cannot make any assumptions about the -Python being executed, this module should not use *any* dependencies outside of the standard -library found in Python 3.7. This file is run each mypy run, so it should be kept as fast as -possible. +This file MUST remain compatible with all Python 3.8+ versions. Since we cannot make any +assumptions about the Python being executed, this module should not use *any* dependencies outside +of the standard library found in Python 3.8. This file is run each mypy run, so it should be kept +as fast as possible. """ import sys diff --git a/mypy/test/meta/test_update_data.py b/mypy/test/meta/test_update_data.py index 67f9a7f56ebd..4e4bdd193dbf 100644 --- a/mypy/test/meta/test_update_data.py +++ b/mypy/test/meta/test_update_data.py @@ -29,10 +29,7 @@ def _run_pytest_update_data(self, data_suite: str, *, max_attempts: int) -> str: test_nodeid = f"mypy/test/testcheck.py::TypeCheckSuite::{p.name}" args = [sys.executable, "-m", "pytest", "-n", "0", "-s", "--update-data", test_nodeid] - if sys.version_info >= (3, 8): - cmd = shlex.join(args) - else: - cmd = " ".join(args) + cmd = shlex.join(args) for i in range(max_attempts - 1, -1, -1): res = subprocess.run(args, cwd=p_root) if res.returncode == 0: diff --git a/mypy/test/testcheck.py b/mypy/test/testcheck.py index 58c0ee803359..20dfbb77f3e0 100644 --- a/mypy/test/testcheck.py +++ b/mypy/test/testcheck.py @@ -36,9 +36,7 @@ # Includes all check-* files with the .test extension in the test-data/unit directory typecheck_files = find_test_files(pattern="check-*.test") -# Tests that use Python 3.8-only AST features (like expression-scoped ignores): -if sys.version_info < (3, 8): - typecheck_files.remove("check-python38.test") +# Tests that use Python version specific features: if sys.version_info < (3, 9): typecheck_files.remove("check-python39.test") if sys.version_info < (3, 10): diff --git a/mypy/test/testdaemon.py b/mypy/test/testdaemon.py index e3cdf44d89f2..7115e682e60d 100644 --- a/mypy/test/testdaemon.py +++ b/mypy/test/testdaemon.py @@ -13,8 +13,6 @@ import tempfile import unittest -import pytest - from mypy.dmypy_server import filter_out_missing_top_level_packages from mypy.fscache import FileSystemCache from mypy.modulefinder import SearchPaths @@ -30,8 +28,6 @@ class DaemonSuite(DataSuite): files = daemon_files def run_case(self, testcase: DataDrivenTestCase) -> None: - if testcase.name.endswith("_python38") and sys.version_info < (3, 8): - pytest.skip("Not supported on this version of Python") try: test_daemon(testcase) finally: diff --git a/mypy/test/testfinegrained.py b/mypy/test/testfinegrained.py index 5b4c816b5c38..ba0526d32558 100644 --- a/mypy/test/testfinegrained.py +++ b/mypy/test/testfinegrained.py @@ -16,7 +16,6 @@ import os import re -import sys import unittest from typing import Any @@ -70,9 +69,6 @@ def should_skip(self, testcase: DataDrivenTestCase) -> bool: else: if testcase.only_when == "-only_when_cache": return True - - if "Inspect" in testcase.name and sys.version_info < (3, 8): - return True return False def run_case(self, testcase: DataDrivenTestCase) -> None: @@ -321,6 +317,7 @@ def maybe_suggest(self, step: int, server: Server, src: str, tmp_dir: str) -> li # JSON contains already escaped \ on Windows, so requires a bit of care. val = val.replace("\\\\", "\\") val = val.replace(os.path.realpath(tmp_dir) + os.path.sep, "") + val = val.replace(os.path.abspath(tmp_dir) + os.path.sep, "") output.extend(val.strip().split("\n")) return normalize_messages(output) diff --git a/mypy/test/testpep561.py b/mypy/test/testpep561.py index da5025faef03..48d0658cd1e9 100644 --- a/mypy/test/testpep561.py +++ b/mypy/test/testpep561.py @@ -98,11 +98,6 @@ def test_pep561(testcase: DataDrivenTestCase) -> None: assert testcase.old_cwd is not None, "test was not properly set up" python = sys.executable - if sys.version_info < (3, 8) and testcase.location[-1] == "testTypedPkgSimpleEditable": - # Python 3.7 doesn't ship with new enough pip to support PEP 660 - # This is a quick hack to skip the test; we'll drop Python 3.7 support soon enough - return - assert python is not None, "Should be impossible" pkgs, pip_args = parse_pkgs(testcase.input[0]) mypy_args = parse_mypy_args(testcase.input[1]) diff --git a/mypy/test/teststubgen.py b/mypy/test/teststubgen.py index b21e06c0896a..884cf87ac5d8 100644 --- a/mypy/test/teststubgen.py +++ b/mypy/test/teststubgen.py @@ -677,6 +677,7 @@ class StubgenPythonSuite(DataSuite): base_path = "." files = ["stubgen.test"] + @unittest.skipIf(sys.platform == "win32", "clean up fails on Windows") def run_case(self, testcase: DataDrivenTestCase) -> None: with local_sys_path_set(): self.run_case_inner(testcase) diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index 275b09c3a240..661d46e9fd8a 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -232,17 +232,16 @@ def test_arg_name(self) -> Iterator[Case]: runtime="def bad(num, text) -> None: pass", error="bad", ) - if sys.version_info >= (3, 8): - yield Case( - stub="def good_posonly(__number: int, text: str) -> None: ...", - runtime="def good_posonly(num, /, text): pass", - error=None, - ) - yield Case( - stub="def bad_posonly(__number: int, text: str) -> None: ...", - runtime="def bad_posonly(flag, /, text): pass", - error="bad_posonly", - ) + yield Case( + stub="def good_posonly(__number: int, text: str) -> None: ...", + runtime="def good_posonly(num, /, text): pass", + error=None, + ) + yield Case( + stub="def bad_posonly(__number: int, text: str) -> None: ...", + runtime="def bad_posonly(flag, /, text): pass", + error="bad_posonly", + ) yield Case( stub=""" class BadMethod: @@ -283,22 +282,21 @@ def test_arg_kind(self) -> Iterator[Case]: runtime="def stub_posonly(number, text): pass", error="stub_posonly", ) - if sys.version_info >= (3, 8): - yield Case( - stub="def good_posonly(__number: int, text: str) -> None: ...", - runtime="def good_posonly(number, /, text): pass", - error=None, - ) - yield Case( - stub="def runtime_posonly(number: int, text: str) -> None: ...", - runtime="def runtime_posonly(number, /, text): pass", - error="runtime_posonly", - ) - yield Case( - stub="def stub_posonly_570(number: int, /, text: str) -> None: ...", - runtime="def stub_posonly_570(number, text): pass", - error="stub_posonly_570", - ) + yield Case( + stub="def good_posonly(__number: int, text: str) -> None: ...", + runtime="def good_posonly(number, /, text): pass", + error=None, + ) + yield Case( + stub="def runtime_posonly(number: int, text: str) -> None: ...", + runtime="def runtime_posonly(number, /, text): pass", + error="runtime_posonly", + ) + yield Case( + stub="def stub_posonly_570(number: int, /, text: str) -> None: ...", + runtime="def stub_posonly_570(number, text): pass", + error="stub_posonly_570", + ) @collect_cases def test_default_presence(self) -> Iterator[Case]: @@ -582,17 +580,16 @@ def f4(a: str, *args, b: int, **kwargs) -> str: ... runtime="def f4(a, *args, b, **kwargs): pass", error=None, ) - if sys.version_info >= (3, 8): - yield Case( - stub=""" - @overload - def f5(__a: int) -> int: ... - @overload - def f5(__b: str) -> str: ... - """, - runtime="def f5(x, /): pass", - error=None, - ) + yield Case( + stub=""" + @overload + def f5(__a: int) -> int: ... + @overload + def f5(__b: str) -> str: ... + """, + runtime="def f5(x, /): pass", + error=None, + ) @collect_cases def test_property(self) -> Iterator[Case]: diff --git a/mypy/util.py b/mypy/util.py index 2c225c7fe651..2960818d0984 100644 --- a/mypy/util.py +++ b/mypy/util.py @@ -421,10 +421,10 @@ def get_unique_redefinition_name(name: str, existing: Container[str]) -> str: def check_python_version(program: str) -> None: """Report issues with the Python used to run mypy, dmypy, or stubgen""" # Check for known bad Python versions. - if sys.version_info[:2] < (3, 7): + if sys.version_info[:2] < (3, 8): sys.exit( - "Running {name} with Python 3.6 or lower is not supported; " - "please upgrade to 3.7 or newer".format(name=program) + "Running {name} with Python 3.7 or lower is not supported; " + "please upgrade to 3.8 or newer".format(name=program) ) diff --git a/mypy_self_check.ini b/mypy_self_check.ini index 62083d144621..7413e6407d4f 100644 --- a/mypy_self_check.ini +++ b/mypy_self_check.ini @@ -6,7 +6,7 @@ show_traceback = True pretty = True always_false = MYPYC plugins = misc/proper_plugin.py -python_version = 3.7 +python_version = 3.8 exclude = mypy/typeshed/|mypyc/test-data/|mypyc/lib-rt/ enable_error_code = ignore-without-code,redundant-expr show_error_code_links = True diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index a4071b9c3de5..2dd1c025123f 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -64,12 +64,10 @@ "run-dunders.test", "run-singledispatch.test", "run-attrs.test", + "run-python37.test", + "run-python38.test", ] -files.append("run-python37.test") -if sys.version_info >= (3, 8): - files.append("run-python38.test") - if sys.version_info >= (3, 10): files.append("run-match.test") diff --git a/pyproject.toml b/pyproject.toml index 96a05d545946..0f2712be52dd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,15 +6,12 @@ requires = [ "setuptools >= 40.6.2", "wheel >= 0.30.0", # the following is from mypy-requirements.txt - "typing_extensions>=4.1.0; python_version >= '3.8'", - "typing_extensions>=4.7.0; python_version < '3.8'", + "typing_extensions>=4.1.0", "mypy_extensions>=1.0.0", - "typed_ast>=1.4.0,<2; python_version<'3.8'", "tomli>=1.1.0; python_version<'3.11'", # the following is from build-requirements.txt "types-psutil", "types-setuptools", - "types-typed-ast>=1.5.8.5,<1.6.0", ] build-backend = "setuptools.build_meta" diff --git a/setup.py b/setup.py index 85d412540013..bbb655ea4537 100644 --- a/setup.py +++ b/setup.py @@ -8,8 +8,8 @@ import sys from typing import TYPE_CHECKING, Any -if sys.version_info < (3, 7, 0): - sys.stderr.write("ERROR: You need Python 3.7 or later to use mypy.\n") +if sys.version_info < (3, 8, 0): + sys.stderr.write("ERROR: You need Python 3.8 or later to use mypy.\n") exit(1) # we'll import stuff from the source tree, let's ensure is on the sys path @@ -186,7 +186,6 @@ def run(self): "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", @@ -221,20 +220,18 @@ def run(self): cmdclass=cmdclass, # When changing this, also update mypy-requirements.txt. install_requires=[ - "typed_ast >= 1.4.0, < 2; python_version<'3.8'", - "typing_extensions>=4.1.0; python_version >= '3.8'", - "typing_extensions>=4.7.0; python_version < '3.8'", + "typing_extensions>=4.1.0", "mypy_extensions >= 1.0.0", "tomli>=1.1.0; python_version<'3.11'", ], # Same here. extras_require={ "dmypy": "psutil >= 4.0", - "python2": "typed_ast >= 1.4.0, < 2", + "python2": "", "reports": "lxml", "install-types": "pip", }, - python_requires=">=3.7", + python_requires=">=3.8", include_package_data=True, project_urls={ "News": "https://mypy-lang.org/news.html", diff --git a/test-data/unit/check-columns.test b/test-data/unit/check-columns.test index 7d1114ceab7a..9d9a7d9ac039 100644 --- a/test-data/unit/check-columns.test +++ b/test-data/unit/check-columns.test @@ -386,10 +386,6 @@ f(g( )) x[0] [out] -main:2:10:2:10: error: Incompatible types in assignment (expression has type "str", variable has type "int") -main:6:3:6:3: error: Argument 1 to "f" has incompatible type "int"; expected "str" -main:8:1:8:1: error: Value of type "int" is not indexable -[out version>=3.8] main:2:10:2:17: error: Incompatible types in assignment (expression has type "str", variable has type "int") main:6:3:7:1: error: Argument 1 to "f" has incompatible type "int"; expected "str" main:8:1:8:4: error: Value of type "int" is not indexable diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 661afca807f4..c3153cd8643a 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -3740,7 +3740,7 @@ import b [file b.py] -- This is a heinous hack, but we simulate having a invalid cache by clobbering -- the proto deps file with something with mtime mismatches. -[file ../.mypy_cache/3.7/@deps.meta.json.2] +[file ../.mypy_cache/3.8/@deps.meta.json.2] {"snapshot": {"__main__": "a7c958b001a45bd6a2a320f4e53c4c16", "a": "d41d8cd98f00b204e9800998ecf8427e", "b": "d41d8cd98f00b204e9800998ecf8427e", "builtins": "c532c89da517a4b779bcf7a964478d67"}, "deps_meta": {"@root": {"path": "@root.deps.json", "mtime": 0}, "__main__": {"path": "__main__.deps.json", "mtime": 0}, "a": {"path": "a.deps.json", "mtime": 0}, "b": {"path": "b.deps.json", "mtime": 0}, "builtins": {"path": "builtins.deps.json", "mtime": 0}}} [file ../.mypy_cache/.gitignore] # Another hack to not trigger a .gitignore creation failure "false positive" @@ -3775,7 +3775,7 @@ import b [file b.py] -- This is a heinous hack, but we simulate having a invalid cache by deleting -- the proto deps file. -[delete ../.mypy_cache/3.7/@deps.meta.json.2] +[delete ../.mypy_cache/3.8/@deps.meta.json.2] [file b.py.2] # uh -- Every file should get reloaded, since the cache was invalidated diff --git a/test-data/unit/check-parameter-specification.test b/test-data/unit/check-parameter-specification.test index bebbbf4b1676..3d05faed74f1 100644 --- a/test-data/unit/check-parameter-specification.test +++ b/test-data/unit/check-parameter-specification.test @@ -592,8 +592,6 @@ def f2(c: Callable[P, R]) -> Callable[Concatenate[int, P], R]: f2(lambda x: 42)(42, x=42) [builtins fixtures/paramspec.pyi] [out] -main:10: error: invalid syntax; you likely need to run mypy using Python 3.8 or newer -[out version>=3.8] main:17: error: Incompatible return value type (got "Callable[[Arg(int, 'x'), **P], R]", expected "Callable[[int, **P], R]") main:17: note: This is likely because "result" has named arguments: "x". Consider marking them positional-only @@ -620,9 +618,6 @@ def f2(c: Callable[P, R]) -> Callable[Concatenate[int, P], R]: # reason for rejection: f2(lambda x: 42)(42, x=42) [builtins fixtures/paramspec.pyi] -[out] -main:11: error: invalid syntax; you likely need to run mypy using Python 3.8 or newer -[out version>=3.8] [case testParamSpecConcatenateWithTypeVar] from typing_extensions import ParamSpec, Concatenate @@ -662,8 +657,6 @@ reveal_type(abc) bar(abc) [builtins fixtures/paramspec.pyi] [out] -main:13: error: invalid syntax; you likely need to run mypy using Python 3.8 or newer -[out version>=3.8] main:16: note: Revealed type is "__main__.Foo[[builtins.int, b: builtins.str]]" [case testSolveParamSpecWithSelfType] diff --git a/test-data/unit/check-typeguard.test b/test-data/unit/check-typeguard.test index b4c007148903..a307e4c8b6a0 100644 --- a/test-data/unit/check-typeguard.test +++ b/test-data/unit/check-typeguard.test @@ -620,10 +620,6 @@ def bad_typeguard(*, x: object) -> TypeGuard[int]: # line 15 [builtins fixtures/classmethod.pyi] [out] main:4: error: TypeGuard functions must have a positional argument -main:11: error: TypeGuard functions must have a positional argument -main:15: error: TypeGuard functions must have a positional argument -[out version>=3.8] -main:4: error: TypeGuard functions must have a positional argument main:12: error: TypeGuard functions must have a positional argument main:15: error: TypeGuard functions must have a positional argument diff --git a/test-data/unit/cmdline.test b/test-data/unit/cmdline.test index b87bb7f17eb0..6e9fdf6dab65 100644 --- a/test-data/unit/cmdline.test +++ b/test-data/unit/cmdline.test @@ -1122,19 +1122,6 @@ class AnotherCustomClassDefinedBelow: def another_even_more_interesting_method(self, arg: Union[int, str, float]) -> None: self.very_important_attribute_with_long_name: OneCustomClassName = OneCustomClassName().some_interesting_method(arg) [out] -some_file.py:3: error: Unsupported operand types for + ("int" and "str") - 42 + 'no way' - ^ -some_file.py:11: error: Incompatible types in assignment (expression has type -"AnotherCustomClassDefinedBelow", variable has type "OneCustomClassName") - ...t_attribute_with_long_name: OneCustomClassName = OneCustomClassName().... - ^ -some_file.py:11: error: Argument 1 to "some_interesting_method" of -"OneCustomClassName" has incompatible type "Union[int, str, float]"; expected -"AnotherCustomClassDefinedBelow" - ...OneCustomClassName = OneCustomClassName().some_interesting_method(arg) - ^ -[out version>=3.8] some_file.py:3: error: Unsupported operand types for + ("int" and "str") 42 + 'no way' ^~~~~~~~ @@ -1165,14 +1152,6 @@ def test_tabs() -> str: def test_between(x: str) -> None: ... test_between(1 + 1) [out] -tabs.py:2: error: Incompatible return value type (got "None", expected "str") - return None - ^ -tabs.py:4: error: Argument 1 to "test_between" has incompatible type "int"; -expected "str" - test_between(1 + 1) - ^ -[out version>=3.8] tabs.py:2: error: Incompatible return value type (got "None", expected "str") return None ^~~~ diff --git a/test-data/unit/daemon.test b/test-data/unit/daemon.test index 1fae1514111c..f208b4e78e54 100644 --- a/test-data/unit/daemon.test +++ b/test-data/unit/daemon.test @@ -360,7 +360,7 @@ def bar() -> None: x = foo('abc') # type: str foo(arg='xyz') -[case testDaemonGetType_python38] +[case testDaemonGetType] $ dmypy start --log-file log.txt -- --follow-imports=error --no-error-summary --python-version 3.8 Daemon started $ dmypy inspect foo:1:2:3:4 @@ -423,7 +423,7 @@ def unreachable(x: int) -> None: return x # line 17 -[case testDaemonGetTypeInexact_python38] +[case testDaemonGetTypeInexact] $ dmypy start --log-file log.txt -- --follow-imports=error --no-error-summary Daemon started $ dmypy check foo.py --export-types @@ -478,7 +478,7 @@ def unreachable(x: int, y: int) -> None: return x and y # line 11 -[case testDaemonGetAttrs_python38] +[case testDaemonGetAttrs] $ dmypy start --log-file log.txt -- --follow-imports=error --no-error-summary Daemon started $ dmypy check foo.py bar.py --export-types @@ -520,7 +520,7 @@ class B: var: Union[A, B] var # line 10 -[case testDaemonGetDefinition_python38] +[case testDaemonGetDefinition] $ dmypy start --log-file log.txt -- --follow-imports=error --no-error-summary Daemon started $ dmypy check foo.py bar/baz.py bar/__init__.py --export-types diff --git a/test-data/unit/fine-grained-blockers.test b/test-data/unit/fine-grained-blockers.test index a134fb1d4301..33dedd887114 100644 --- a/test-data/unit/fine-grained-blockers.test +++ b/test-data/unit/fine-grained-blockers.test @@ -48,16 +48,6 @@ a.py:1: error: invalid syntax [syntax] def f(x: int) -> ^ == -main:3: error: Missing positional argument "x" in call to "f" [call-arg] - a.f() - ^ -== -[out version>=3.8] -== -a.py:1: error: invalid syntax [syntax] - def f(x: int) -> - ^ -== main:3: error: Missing positional argument "x" in call to "f" [call-arg] a.f() ^~~~~ diff --git a/test-data/unit/fine-grained-cache-incremental.test b/test-data/unit/fine-grained-cache-incremental.test index 50f93dd35af3..00157333efd7 100644 --- a/test-data/unit/fine-grained-cache-incremental.test +++ b/test-data/unit/fine-grained-cache-incremental.test @@ -202,7 +202,7 @@ a.py:8: note: x: expected "int", got "str" [file b.py] -- This is a heinous hack, but we simulate having a invalid cache by clobbering -- the proto deps file with something with mtime mismatches. -[file ../.mypy_cache/3.7/@deps.meta.json.2] +[file ../.mypy_cache/3.8/@deps.meta.json.2] {"snapshot": {"__main__": "a7c958b001a45bd6a2a320f4e53c4c16", "a": "d41d8cd98f00b204e9800998ecf8427e", "b": "d41d8cd98f00b204e9800998ecf8427e", "builtins": "c532c89da517a4b779bcf7a964478d67"}, "deps_meta": {"@root": {"path": "@root.deps.json", "mtime": 0}, "__main__": {"path": "__main__.deps.json", "mtime": 0}, "a": {"path": "a.deps.json", "mtime": 0}, "b": {"path": "b.deps.json", "mtime": 0}, "builtins": {"path": "builtins.deps.json", "mtime": 0}}} [file b.py.2] @@ -234,8 +234,8 @@ x = 10 [file p/c.py] class C: pass -[delete ../.mypy_cache/3.7/b.meta.json.2] -[delete ../.mypy_cache/3.7/p/c.meta.json.2] +[delete ../.mypy_cache/3.8/b.meta.json.2] +[delete ../.mypy_cache/3.8/p/c.meta.json.2] [out] == diff --git a/test-data/unit/fine-grained.test b/test-data/unit/fine-grained.test index a0d7d302fd08..3cb234364a58 100644 --- a/test-data/unit/fine-grained.test +++ b/test-data/unit/fine-grained.test @@ -95,11 +95,6 @@ class A: def g(self, a: A) -> None: pass [out] == -main:5: error: Missing positional argument "a" in call to "g" of "A" [call-arg] - a.g() # E - ^ -[out version>=3.8] -== main:5: error: Missing positional argument "a" in call to "g" of "A" [call-arg] a.g() # E ^~~~~ @@ -10101,23 +10096,6 @@ object + 1 1() [out] -b.py:1: error: Unsupported left operand type for + ("Type[object]") - object + 1 - ^ -a.py:1: error: Unsupported operand types for + ("int" and "str") - 1 + '' - ^ -== -b.py:1: error: Unsupported left operand type for + ("Type[object]") - object + 1 - ^ -b.py:2: error: "int" not callable - 1() - ^ -a.py:1: error: Unsupported operand types for + ("int" and "str") - 1 + '' - ^ -[out version>=3.8] b.py:1: error: Unsupported left operand type for + ("Type[object]") object + 1 ^~~~~~~~~~ diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 1460002e1b65..e4eecc33871c 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -1441,7 +1441,7 @@ accepts_named_tuple(b) accepts_named_tuple(1) accepts_named_tuple((1, 2)) [out] -_testNamedTupleTypeInheritanceSpecialCase.py:8: note: Revealed type is "collections.OrderedDict[builtins.str, Any]" +_testNamedTupleTypeInheritanceSpecialCase.py:8: note: Revealed type is "builtins.dict[builtins.str, Any]" _testNamedTupleTypeInheritanceSpecialCase.py:9: note: Revealed type is "builtins.tuple[builtins.str, ...]" _testNamedTupleTypeInheritanceSpecialCase.py:10: note: Revealed type is "builtins.dict[builtins.str, Any]" _testNamedTupleTypeInheritanceSpecialCase.py:17: error: Argument 1 to "accepts_named_tuple" has incompatible type "int"; expected "NamedTuple" diff --git a/test-data/unit/semanal-errors.test b/test-data/unit/semanal-errors.test index 9c6ac2833c8b..a098dd8791d4 100644 --- a/test-data/unit/semanal-errors.test +++ b/test-data/unit/semanal-errors.test @@ -361,8 +361,6 @@ main:2: error: "yield" outside function [case testInvalidLvalues1] 1 = 1 [out] -main:1: error: can't assign to literal -[out version>=3.8] main:1: error: cannot assign to literal [out version>=3.10] main:1: error: cannot assign to literal here. Maybe you meant '==' instead of '='? @@ -370,8 +368,6 @@ main:1: error: cannot assign to literal here. Maybe you meant '==' instead of '= [case testInvalidLvalues2] (1) = 1 [out] -main:1: error: can't assign to literal -[out version>=3.8] main:1: error: cannot assign to literal [out version>=3.10] main:1: error: cannot assign to literal here. Maybe you meant '==' instead of '='? @@ -379,37 +375,27 @@ main:1: error: cannot assign to literal here. Maybe you meant '==' instead of '= [case testInvalidLvalues3] (1, 1) = 1 [out] -main:1: error: can't assign to literal -[out version>=3.8] main:1: error: cannot assign to literal [case testInvalidLvalues4] [1, 1] = 1 [out] -main:1: error: can't assign to literal -[out version>=3.8] main:1: error: cannot assign to literal [case testInvalidLvalues6] x = y = z = 1 # ok x, (y, 1) = 1 [out] -main:2: error: can't assign to literal -[out version>=3.8] main:2: error: cannot assign to literal [case testInvalidLvalues7] x, [y, 1] = 1 [out] -main:1: error: can't assign to literal -[out version>=3.8] main:1: error: cannot assign to literal [case testInvalidLvalues8] x, [y, [z, 1]] = 1 [out] -main:1: error: can't assign to literal -[out version>=3.8] main:1: error: cannot assign to literal [case testInvalidLvalues9] @@ -417,15 +403,11 @@ x, (y) = 1 # ok x, (y, (z, z)) = 1 # ok x, (y, (z, 1)) = 1 [out] -main:3: error: can't assign to literal -[out version>=3.8] main:3: error: cannot assign to literal [case testInvalidLvalues10] x + x = 1 [out] -main:1: error: can't assign to operator -[out version>=3.8] main:1: error: cannot assign to operator [out version>=3.10] main:1: error: cannot assign to expression here. Maybe you meant '==' instead of '='? @@ -433,8 +415,6 @@ main:1: error: cannot assign to expression here. Maybe you meant '==' instead of [case testInvalidLvalues11] -x = 1 [out] -main:1: error: can't assign to operator -[out version>=3.8] main:1: error: cannot assign to operator [out version>=3.10] main:1: error: cannot assign to expression here. Maybe you meant '==' instead of '='? @@ -442,8 +422,6 @@ main:1: error: cannot assign to expression here. Maybe you meant '==' instead of [case testInvalidLvalues12] 1.1 = 1 [out] -main:1: error: can't assign to literal -[out version>=3.8] main:1: error: cannot assign to literal [out version>=3.10] main:1: error: cannot assign to literal here. Maybe you meant '==' instead of '='? @@ -451,8 +429,6 @@ main:1: error: cannot assign to literal here. Maybe you meant '==' instead of '= [case testInvalidLvalues13] 'x' = 1 [out] -main:1: error: can't assign to literal -[out version>=3.8] main:1: error: cannot assign to literal [out version>=3.10] main:1: error: cannot assign to literal here. Maybe you meant '==' instead of '='? @@ -460,8 +436,6 @@ main:1: error: cannot assign to literal here. Maybe you meant '==' instead of '= [case testInvalidLvalues14] x() = 1 [out] -main:1: error: can't assign to function call -[out version>=3.8] main:1: error: cannot assign to function call [out version>=3.10] main:1: error: cannot assign to function call here. Maybe you meant '==' instead of '='? @@ -518,16 +492,12 @@ main:2: error: Can use starred expression only as assignment target x = 1 del x(1) [out] -main:2: error: can't delete function call -[out version>=3.8] main:2: error: cannot delete function call [case testInvalidDel2] x = 1 del x + 1 [out] -main:2: error: can't delete operator -[out version>=3.8] main:2: error: cannot delete operator [out version>=3.10] main:2: error: cannot delete expression @@ -927,8 +897,6 @@ import typing def f(): pass f() = 1 # type: int [out] -main:3: error: can't assign to function call -[out version>=3.8] main:3: error: cannot assign to function call [out version>=3.10] main:3: error: cannot assign to function call here. Maybe you meant '==' instead of '='? @@ -1007,8 +975,6 @@ x, y = 1, 2 # type: int # E: Tuple type expected for multiple variables a = 1 a() = None # type: int [out] -main:2: error: can't assign to function call -[out version>=3.8] main:2: error: cannot assign to function call [out version>=3.10] main:2: error: cannot assign to function call here. Maybe you meant '==' instead of '='? @@ -1311,8 +1277,6 @@ main:2: note: Did you forget to import it from "typing"? (Suggestion: "from typi def f(): pass with f() as 1: pass [out] -main:2: error: can't assign to literal -[out version>=3.8] main:2: error: cannot assign to literal [case testInvalidTypeAnnotation] @@ -1327,8 +1291,6 @@ import typing def f() -> None: f() = 1 # type: int [out] -main:3: error: can't assign to function call -[out version>=3.8] main:3: error: cannot assign to function call [out version>=3.10] main:3: error: cannot assign to function call here. Maybe you meant '==' instead of '='? diff --git a/test-data/unit/semanal-statements.test b/test-data/unit/semanal-statements.test index 9b43a5b853c0..c143805f4564 100644 --- a/test-data/unit/semanal-statements.test +++ b/test-data/unit/semanal-statements.test @@ -557,8 +557,6 @@ MypyFile:1( def f(x, y) -> None: del x, y + 1 [out] -main:2: error: can't delete operator -[out version>=3.8] main:2: error: cannot delete operator [out version>=3.10] main:2: error: cannot delete expression