Skip to content

Commit

Permalink
Turn on ParamSpec semanal by default (#10883)
Browse files Browse the repository at this point in the history
This PR does not mean mypy supports PEP 612, but it does do enough to
unblock #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 <>
  • Loading branch information
hauntsaninja authored Aug 4, 2021
1 parent 805bbde commit 67a6ad7
Show file tree
Hide file tree
Showing 10 changed files with 39 additions and 18 deletions.
4 changes: 3 additions & 1 deletion mypy/applytype.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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:
Expand Down
4 changes: 3 additions & 1 deletion mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 4 additions & 1 deletion mypy/expandtype.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 0 additions & 2 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
3 changes: 0 additions & 3 deletions mypy/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -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] = []

Expand Down
2 changes: 0 additions & 2 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
)
Expand Down
4 changes: 3 additions & 1 deletion mypy/typeops.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
25 changes: 23 additions & 2 deletions test-data/unit/check-parameter-specification.test
Original file line number Diff line number Diff line change
@@ -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')
Expand All @@ -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]
1 change: 0 additions & 1 deletion test-data/unit/semanal-errors.test
Original file line number Diff line number Diff line change
Expand Up @@ -1426,7 +1426,6 @@ def g() -> None:
[out]

[case testParamSpec]
# flags: --wip-pep-612
from typing_extensions import ParamSpec

TParams = ParamSpec('TParams')
Expand Down
7 changes: 3 additions & 4 deletions test-data/unit/semanal-types.test
Original file line number Diff line number Diff line change
Expand Up @@ -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()))

0 comments on commit 67a6ad7

Please sign in to comment.