From 67a6ad7245d0486034a1e001292229b98314caa9 Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Wed, 4 Aug 2021 00:11:52 -0700 Subject: [PATCH] Turn on ParamSpec semanal by default (#10883) This PR does not mean mypy supports PEP 612, but it does do enough to unblock /~https://github.com/python/mypy/pull/10862 mypy should now treat Callable[P, T] as Callable[..., T] and the code paths with incomplete support will no longer crash (but will not do what you'd want) Co-authored-by: hauntsaninja <> --- mypy/applytype.py | 4 ++- mypy/checkexpr.py | 4 ++- mypy/expandtype.py | 5 +++- mypy/main.py | 2 -- mypy/options.py | 3 --- mypy/semanal.py | 2 -- mypy/typeops.py | 4 ++- .../unit/check-parameter-specification.test | 25 +++++++++++++++++-- test-data/unit/semanal-errors.test | 1 - test-data/unit/semanal-types.test | 7 +++--- 10 files changed, 39 insertions(+), 18 deletions(-) diff --git a/mypy/applytype.py b/mypy/applytype.py index d034c8f37969..e3eaf129b84f 100644 --- a/mypy/applytype.py +++ b/mypy/applytype.py @@ -5,7 +5,7 @@ from mypy.expandtype import expand_type from mypy.types import ( Type, TypeVarId, TypeVarType, CallableType, AnyType, PartialType, get_proper_types, - TypeVarDef, TypeVarLikeDef, ProperType + TypeVarDef, TypeVarLikeDef, ProperType, ParamSpecDef ) from mypy.nodes import Context @@ -19,6 +19,8 @@ def get_target_type( skip_unsatisfied: bool ) -> Optional[Type]: # TODO(shantanu): fix for ParamSpecDef + if isinstance(tvar, ParamSpecDef): + return None assert isinstance(tvar, TypeVarDef) values = get_proper_types(tvar.values) if values: diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 0c587494b86b..4a15374f2286 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -18,7 +18,7 @@ Type, AnyType, CallableType, Overloaded, NoneType, TypeGuardType, TypeVarDef, TupleType, TypedDictType, Instance, TypeVarType, ErasedType, UnionType, PartialType, DeletedType, UninhabitedType, TypeType, TypeOfAny, LiteralType, LiteralValue, - is_named_instance, FunctionLike, + is_named_instance, FunctionLike, ParamSpecDef, StarType, is_optional, remove_optional, is_generic_instance, get_proper_type, ProperType, get_proper_types, flatten_nested_unions ) @@ -4481,6 +4481,8 @@ def merge_typevars_in_callables_by_name( name = tvdef.fullname if name not in unique_typevars: # TODO(shantanu): fix for ParamSpecDef + if isinstance(tvdef, ParamSpecDef): + continue assert isinstance(tvdef, TypeVarDef) unique_typevars[name] = TypeVarType(tvdef) variables.append(tvdef) diff --git a/mypy/expandtype.py b/mypy/expandtype.py index f6ae0f494bf8..cee942cabf88 100644 --- a/mypy/expandtype.py +++ b/mypy/expandtype.py @@ -5,7 +5,8 @@ NoneType, TypeVarType, Overloaded, TupleType, TypedDictType, UnionType, ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, TypeVarId, FunctionLike, TypeVarDef, LiteralType, get_proper_type, ProperType, - TypeAliasType) + TypeAliasType, ParamSpecDef +) def expand_type(typ: Type, env: Mapping[TypeVarId, Type]) -> Type: @@ -41,6 +42,8 @@ def freshen_function_type_vars(callee: F) -> F: tvmap: Dict[TypeVarId, Type] = {} for v in callee.variables: # TODO(shantanu): fix for ParamSpecDef + if isinstance(v, ParamSpecDef): + continue assert isinstance(v, TypeVarDef) tvdef = TypeVarDef.new_unification_variable(v) tvdefs.append(tvdef) diff --git a/mypy/main.py b/mypy/main.py index 90134de9c438..9ecd345126f4 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -852,8 +852,6 @@ def add_invertible_flag(flag: str, # Must be followed by another flag or by '--' (and then only file args may follow). parser.add_argument('--cache-map', nargs='+', dest='special-opts:cache_map', help=argparse.SUPPRESS) - # PEP 612 support is a work in progress, hide it from users - parser.add_argument('--wip-pep-612', action="store_true", help=argparse.SUPPRESS) # options specifying code to check code_group = parser.add_argument_group( diff --git a/mypy/options.py b/mypy/options.py index 310fff5dbfe5..3a56add0d0ad 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -242,9 +242,6 @@ def __init__(self) -> None: # mypy. (Like mypyc.) self.preserve_asts = False - # PEP 612 support is a work in progress, hide it from users - self.wip_pep_612 = False - # Paths of user plugins self.plugins: List[str] = [] diff --git a/mypy/semanal.py b/mypy/semanal.py index 1c39aa0de256..5bf6316ca2d9 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -3151,8 +3151,6 @@ def process_paramspec_declaration(self, s: AssignmentStmt) -> bool: In the future, ParamSpec may accept bounds and variance arguments, in which case more aggressive sharing of code with process_typevar_declaration should be pursued. """ - if not self.options.wip_pep_612: - return False call = self.get_typevarlike_declaration( s, ("typing_extensions.ParamSpec", "typing.ParamSpec") ) diff --git a/mypy/typeops.py b/mypy/typeops.py index ef428729462f..d2ffebdfd97b 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -14,7 +14,7 @@ TupleType, Instance, FunctionLike, Type, CallableType, TypeVarDef, TypeVarLikeDef, Overloaded, TypeVarType, UninhabitedType, FormalArgument, UnionType, NoneType, TypedDictType, AnyType, TypeOfAny, TypeType, ProperType, LiteralType, get_proper_type, get_proper_types, - copy_type, TypeAliasType, TypeQuery + copy_type, TypeAliasType, TypeQuery, ParamSpecDef ) from mypy.nodes import ( FuncBase, FuncItem, OverloadedFuncDef, TypeInfo, ARG_STAR, ARG_STAR2, ARG_POS, @@ -512,6 +512,8 @@ def true_or_false(t: Type) -> ProperType: def erase_def_to_union_or_bound(tdef: TypeVarLikeDef) -> Type: # TODO(shantanu): fix for ParamSpecDef + if isinstance(tdef, ParamSpecDef): + return AnyType(TypeOfAny.from_error) assert isinstance(tdef, TypeVarDef) if tdef.values: return make_simplified_union(tdef.values) diff --git a/test-data/unit/check-parameter-specification.test b/test-data/unit/check-parameter-specification.test index c7f6594eb20d..a817ae8064c6 100644 --- a/test-data/unit/check-parameter-specification.test +++ b/test-data/unit/check-parameter-specification.test @@ -1,11 +1,9 @@ [case testBasicParamSpec] -# flags: --wip-pep-612 from typing_extensions import ParamSpec P = ParamSpec('P') [builtins fixtures/tuple.pyi] [case testParamSpecLocations] -# flags: --wip-pep-612 from typing import Callable, List from typing_extensions import ParamSpec, Concatenate P = ParamSpec('P') @@ -29,3 +27,26 @@ def foo5(x: Callable[[int, str], P]) -> None: ... # E: Invalid location for Par def foo6(x: Callable[[P], int]) -> None: ... # E: Invalid location for ParamSpec "P" \ # N: You can use ParamSpec as the first argument to Callable, e.g., 'Callable[P, int]' [builtins fixtures/tuple.pyi] + +[case testParamSpecTemporaryAnyBehaviour] +# This is a test of mypy's temporary behaviour in lieu of full support for ParamSpec +from typing import Callable, List, Iterator, TypeVar +from typing_extensions import ParamSpec +P = ParamSpec('P') +T = TypeVar('T') + +def changes_return_type_to_str(x: Callable[P, int]) -> Callable[P, str]: ... + +def returns_int(a: str, b: bool) -> int: ... + +reveal_type(changes_return_type_to_str(returns_int)) # N: Revealed type is "def (*Any, **Any) -> builtins.str" + +def tmpcontextmanagerlike(x: Callable[P, Iterator[T]]) -> Callable[P, List[T]]: ... + +@tmpcontextmanagerlike +def whatever(x: int) -> Iterator[int]: + yield x + +reveal_type(whatever) # N: Revealed type is "def (*Any, **Any) -> builtins.list[builtins.int*]" +reveal_type(whatever(217)) # N: Revealed type is "builtins.list[builtins.int*]" +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/semanal-errors.test b/test-data/unit/semanal-errors.test index 3a1fad61556a..9dc75a4930e4 100644 --- a/test-data/unit/semanal-errors.test +++ b/test-data/unit/semanal-errors.test @@ -1426,7 +1426,6 @@ def g() -> None: [out] [case testParamSpec] -# flags: --wip-pep-612 from typing_extensions import ParamSpec TParams = ParamSpec('TParams') diff --git a/test-data/unit/semanal-types.test b/test-data/unit/semanal-types.test index 19d2d037e032..334bf2e62c49 100644 --- a/test-data/unit/semanal-types.test +++ b/test-data/unit/semanal-types.test @@ -1500,12 +1500,11 @@ MypyFile:1( [case testParamSpec] -# flags: --wip-pep-612 from typing import ParamSpec P = ParamSpec("P") [out] MypyFile:1( - ImportFrom:2(typing, [ParamSpec]) - AssignmentStmt:3( + ImportFrom:1(typing, [ParamSpec]) + AssignmentStmt:2( NameExpr(P* [__main__.P]) - ParamSpecExpr:3())) + ParamSpecExpr:2()))