--- pyproject.toml 2026-07-13 17:51:48.000000000 +0800 +++ pyproject.toml 2026-07-14 19:50:02.000000000 +0800 @@ -15,7 +15,6 @@ "types-psutil", "types-setuptools", # required to work around a mypyc import bug - "ast-serialize>=0.6.0,<1.0.0", ] build-backend = "setuptools.build_meta" @@ -59,7 +58,6 @@ "pathspec>=1.0.0", "tomli>=1.1.0; python_version<'3.11'", "librt>=0.13.0; platform_python_implementation != 'PyPy'", - "ast-serialize>=0.6.0,<1.0.0", ] dynamic = ["version"] --- mypy/parse.py 2026-07-08 02:50:24.000000000 +0800 +++ mypy/parse.py 2026-07-08 19:37:31.000000000 +0800 @@ -31,21 +31,24 @@ parse contents from path `fnam` if `source` is `None`. """ if options.native_parser: - import mypy.nativeparse + try: + import mypy.nativeparse - ignore_errors = options.ignore_errors or fnam in errors.ignored_files - # If errors are ignored, we can drop many function bodies to speed up type checking. - strip_function_bodies = ignore_errors and not options.preserve_asts - tree, _, _ = mypy.nativeparse.native_parse( - fnam, options, source, skip_function_bodies=strip_function_bodies - ) - # Set is_stub based on file extension - tree.is_stub = fnam.endswith(".pyi") - # Note: tree.imports is populated directly by load_from_raw() with deserialized - # import metadata, so we don't need to collect imports via AST traversal - if eager and tree.raw_data is not None: - tree = load_from_raw(fnam, module, tree.raw_data, errors, options) - return tree + ignore_errors = options.ignore_errors or fnam in errors.ignored_files + # If errors are ignored, we can drop many function bodies to speed up type checking. + strip_function_bodies = ignore_errors and not options.preserve_asts + tree, _, _ = mypy.nativeparse.native_parse( + fnam, options, source, skip_function_bodies=strip_function_bodies + ) + # Set is_stub based on file extension + tree.is_stub = fnam.endswith(".pyi") + # Note: tree.imports is populated directly by load_from_raw() with deserialized + # import metadata, so we don't need to collect imports via AST traversal + if eager and tree.raw_data is not None: + tree = load_from_raw(fnam, module, tree.raw_data, errors, options) + return tree + except ImportError: + pass if source is None: raise ValueError("Source cannot be `None` when using the old parser") @@ -69,7 +72,12 @@ If imports_only is true, only deserialize imports and return a mostly empty AST. """ - from mypy.nativeparse import State, deserialize_imports, read_statements + try: + from mypy.nativeparse import State, deserialize_imports, read_statements + except ImportError: + raise RuntimeError( + "Native parser is not supported." + ) state = State(options, is_stub=fnam.endswith(".pyi")) if imports_only: --- mypy/nativeparse.py 2026-05-11 23:48:35.000000000 +0800 +++ mypy/nativeparse.py 2026-05-17 05:50:40.000000000 +0800 @@ -20,9 +20,13 @@ import os import time -from typing import Final, cast +from typing import Any, Final, cast + +try: + import ast_serialize # type: ignore[import] # mypy: suppress import-not-found +except Exception: + ast_serialize = None # type: ignore[assignment] -import ast_serialize from librt.internal import ( read_float as read_float_bare, read_int as read_int_bare, --- mypy/main.py 2026-05-11 23:48:35.000000000 +0800 +++ mypy/main.py 2026-05-17 05:35:31.000000000 +0800 @@ -98,8 +98,8 @@ ) if options.num_workers: - # Supporting both parsers would be really tricky, so just support the new one. - options.native_parser = True + # Supporting both parsers would be really tricky, but new one is broken anyway. + options.native_parser = False if options.num_workers < 0: fail("error: Number of workers cannot be negative", stderr, options) if options.cache_dir == os.devnull: