[med-svn] [Git][python-team/packages/mypy][upstream] New upstream version 0.982
Michael R. Crusoe (@crusoe)
gitlab at salsa.debian.org
Tue Oct 4 13:35:33 BST 2022
Michael R. Crusoe pushed to branch upstream at Debian Python Team / packages / mypy
Commits:
11c69ae6 by Michael R. Crusoe at 2022-10-04T10:29:29+02:00
New upstream version 0.982
- - - - -
10 changed files:
- PKG-INFO
- mypy.egg-info/PKG-INFO
- mypy/checker.py
- mypy/meet.py
- mypy/subtypes.py
- mypy/version.py
- test-data/unit/check-classes.test
- test-data/unit/check-inference.test
- test-data/unit/check-overloading.test
- test-data/unit/check-typevar-unbound.test
Changes:
=====================================
PKG-INFO
=====================================
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: mypy
-Version: 0.981
+Version: 0.982
Summary: Optional static typing for Python
Home-page: http://www.mypy-lang.org/
Author: Jukka Lehtosalo
=====================================
mypy.egg-info/PKG-INFO
=====================================
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: mypy
-Version: 0.981
+Version: 0.982
Summary: Optional static typing for Python
Home-page: http://www.mypy-lang.org/
Author: Jukka Lehtosalo
=====================================
mypy/checker.py
=====================================
@@ -752,14 +752,14 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
# Is the overload alternative's arguments subtypes of the implementation's?
if not is_callable_compatible(
- impl, sig1, is_compat=is_subtype_no_promote, ignore_return=True
+ impl, sig1, is_compat=is_subtype, ignore_return=True
):
self.msg.overloaded_signatures_arg_specific(i + 1, defn.impl)
# Is the overload alternative's return type a subtype of the implementation's?
if not (
- is_subtype_no_promote(sig1.ret_type, impl.ret_type)
- or is_subtype_no_promote(impl.ret_type, sig1.ret_type)
+ is_subtype(sig1.ret_type, impl.ret_type)
+ or is_subtype(impl.ret_type, sig1.ret_type)
):
self.msg.overloaded_signatures_ret_specific(i + 1, defn.impl)
@@ -1235,13 +1235,23 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
def check_unbound_return_typevar(self, typ: CallableType) -> None:
"""Fails when the return typevar is not defined in arguments."""
- if typ.ret_type in typ.variables:
- arg_type_visitor = CollectArgTypes()
+ if isinstance(typ.ret_type, TypeVarType) and typ.ret_type in typ.variables:
+ arg_type_visitor = CollectArgTypeVarTypes()
for argtype in typ.arg_types:
argtype.accept(arg_type_visitor)
if typ.ret_type not in arg_type_visitor.arg_types:
self.fail(message_registry.UNBOUND_TYPEVAR, typ.ret_type, code=TYPE_VAR)
+ upper_bound = get_proper_type(typ.ret_type.upper_bound)
+ if not (
+ isinstance(upper_bound, Instance)
+ and upper_bound.type.fullname == "builtins.object"
+ ):
+ self.note(
+ "Consider using the upper bound "
+ f"{format_type(typ.ret_type.upper_bound)} instead",
+ context=typ.ret_type,
+ )
def check_default_args(self, item: FuncItem, body_is_trivial: bool) -> None:
for arg in item.arguments:
@@ -6156,7 +6166,7 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
)
-class CollectArgTypes(TypeTraverserVisitor):
+class CollectArgTypeVarTypes(TypeTraverserVisitor):
"""Collects the non-nested argument types in a set."""
def __init__(self) -> None:
@@ -6496,7 +6506,7 @@ def is_unsafe_overlapping_overload_signatures(
return is_callable_compatible(
signature,
other,
- is_compat=is_overlapping_types_no_promote,
+ is_compat=is_overlapping_types_no_promote_no_uninhabited,
is_compat_return=lambda l, r: not is_subtype_no_promote(l, r),
ignore_return=False,
check_args_covariantly=True,
@@ -6504,7 +6514,7 @@ def is_unsafe_overlapping_overload_signatures(
) or is_callable_compatible(
other,
signature,
- is_compat=is_overlapping_types_no_promote,
+ is_compat=is_overlapping_types_no_promote_no_uninhabited,
is_compat_return=lambda l, r: not is_subtype_no_promote(r, l),
ignore_return=False,
check_args_covariantly=False,
@@ -6988,8 +6998,12 @@ def is_subtype_no_promote(left: Type, right: Type) -> bool:
return is_subtype(left, right, ignore_promotions=True)
-def is_overlapping_types_no_promote(left: Type, right: Type) -> bool:
- return is_overlapping_types(left, right, ignore_promotions=True)
+def is_overlapping_types_no_promote_no_uninhabited(left: Type, right: Type) -> bool:
+ # For the purpose of unsafe overload checks we consider list[<nothing>] and list[int]
+ # non-overlapping. This is consistent with how we treat list[int] and list[str] as
+ # non-overlapping, despite [] belongs to both. Also this will prevent false positives
+ # for failed type inference during unification.
+ return is_overlapping_types(left, right, ignore_promotions=True, ignore_uninhabited=True)
def is_private(node_name: str) -> bool:
=====================================
mypy/meet.py
=====================================
@@ -215,6 +215,7 @@ def is_overlapping_types(
right: Type,
ignore_promotions: bool = False,
prohibit_none_typevar_overlap: bool = False,
+ ignore_uninhabited: bool = False,
) -> bool:
"""Can a value of type 'left' also be of type 'right' or vice-versa?
@@ -239,6 +240,7 @@ def is_overlapping_types(
right,
ignore_promotions=ignore_promotions,
prohibit_none_typevar_overlap=prohibit_none_typevar_overlap,
+ ignore_uninhabited=ignore_uninhabited,
)
# We should never encounter this type.
@@ -286,8 +288,10 @@ def is_overlapping_types(
):
return True
- if is_proper_subtype(left, right, ignore_promotions=ignore_promotions) or is_proper_subtype(
- right, left, ignore_promotions=ignore_promotions
+ if is_proper_subtype(
+ left, right, ignore_promotions=ignore_promotions, ignore_uninhabited=ignore_uninhabited
+ ) or is_proper_subtype(
+ right, left, ignore_promotions=ignore_promotions, ignore_uninhabited=ignore_uninhabited
):
return True
@@ -429,8 +433,10 @@ def is_overlapping_types(
if isinstance(left, Instance) and isinstance(right, Instance):
# First we need to handle promotions and structural compatibility for instances
# that came as fallbacks, so simply call is_subtype() to avoid code duplication.
- if is_subtype(left, right, ignore_promotions=ignore_promotions) or is_subtype(
- right, left, ignore_promotions=ignore_promotions
+ if is_subtype(
+ left, right, ignore_promotions=ignore_promotions, ignore_uninhabited=ignore_uninhabited
+ ) or is_subtype(
+ right, left, ignore_promotions=ignore_promotions, ignore_uninhabited=ignore_uninhabited
):
return True
@@ -471,7 +477,7 @@ def is_overlapping_types(
# Note: it's unclear however, whether returning False is the right thing
# to do when inferring reachability -- see https://github.com/python/mypy/issues/5529
- assert type(left) != type(right)
+ assert type(left) != type(right), f"{type(left)} vs {type(right)}"
return False
=====================================
mypy/subtypes.py
=====================================
@@ -68,7 +68,7 @@ IS_SETTABLE: Final = 1
IS_CLASSVAR: Final = 2
IS_CLASS_OR_STATIC: Final = 3
-TypeParameterChecker: _TypeAlias = Callable[[Type, Type, int, bool], bool]
+TypeParameterChecker: _TypeAlias = Callable[[Type, Type, int, bool, "SubtypeContext"], bool]
class SubtypeContext:
@@ -81,6 +81,7 @@ class SubtypeContext:
ignore_declared_variance: bool = False,
# Supported for both proper and non-proper
ignore_promotions: bool = False,
+ ignore_uninhabited: bool = False,
# Proper subtype flags
erase_instances: bool = False,
keep_erased_types: bool = False,
@@ -90,6 +91,7 @@ class SubtypeContext:
self.ignore_pos_arg_names = ignore_pos_arg_names
self.ignore_declared_variance = ignore_declared_variance
self.ignore_promotions = ignore_promotions
+ self.ignore_uninhabited = ignore_uninhabited
self.erase_instances = erase_instances
self.keep_erased_types = keep_erased_types
self.options = options
@@ -116,6 +118,7 @@ def is_subtype(
ignore_pos_arg_names: bool = False,
ignore_declared_variance: bool = False,
ignore_promotions: bool = False,
+ ignore_uninhabited: bool = False,
options: Options | None = None,
) -> bool:
"""Is 'left' subtype of 'right'?
@@ -135,6 +138,7 @@ def is_subtype(
ignore_pos_arg_names=ignore_pos_arg_names,
ignore_declared_variance=ignore_declared_variance,
ignore_promotions=ignore_promotions,
+ ignore_uninhabited=ignore_uninhabited,
options=options,
)
else:
@@ -144,6 +148,7 @@ def is_subtype(
ignore_pos_arg_names,
ignore_declared_variance,
ignore_promotions,
+ ignore_uninhabited,
options,
}
), "Don't pass both context and individual flags"
@@ -178,6 +183,7 @@ def is_proper_subtype(
*,
subtype_context: SubtypeContext | None = None,
ignore_promotions: bool = False,
+ ignore_uninhabited: bool = False,
erase_instances: bool = False,
keep_erased_types: bool = False,
) -> bool:
@@ -193,12 +199,19 @@ def is_proper_subtype(
if subtype_context is None:
subtype_context = SubtypeContext(
ignore_promotions=ignore_promotions,
+ ignore_uninhabited=ignore_uninhabited,
erase_instances=erase_instances,
keep_erased_types=keep_erased_types,
)
else:
assert not any(
- {ignore_promotions, erase_instances, keep_erased_types}
+ {
+ ignore_promotions,
+ ignore_uninhabited,
+ erase_instances,
+ keep_erased_types,
+ ignore_uninhabited,
+ }
), "Don't pass both context and individual flags"
if TypeState.is_assumed_proper_subtype(left, right):
return True
@@ -216,6 +229,7 @@ def is_equivalent(
ignore_type_params: bool = False,
ignore_pos_arg_names: bool = False,
options: Options | None = None,
+ subtype_context: SubtypeContext | None = None,
) -> bool:
return is_subtype(
a,
@@ -223,16 +237,20 @@ def is_equivalent(
ignore_type_params=ignore_type_params,
ignore_pos_arg_names=ignore_pos_arg_names,
options=options,
+ subtype_context=subtype_context,
) and is_subtype(
b,
a,
ignore_type_params=ignore_type_params,
ignore_pos_arg_names=ignore_pos_arg_names,
options=options,
+ subtype_context=subtype_context,
)
-def is_same_type(a: Type, b: Type, ignore_promotions: bool = True) -> bool:
+def is_same_type(
+ a: Type, b: Type, ignore_promotions: bool = True, subtype_context: SubtypeContext | None = None
+) -> bool:
"""Are these types proper subtypes of each other?
This means types may have different representation (e.g. an alias, or
@@ -242,8 +260,10 @@ def is_same_type(a: Type, b: Type, ignore_promotions: bool = True) -> bool:
# considered not the same type (which is the case at runtime).
# Also Union[bool, int] (if it wasn't simplified before) will be different
# from plain int, etc.
- return is_proper_subtype(a, b, ignore_promotions=ignore_promotions) and is_proper_subtype(
- b, a, ignore_promotions=ignore_promotions
+ return is_proper_subtype(
+ a, b, ignore_promotions=ignore_promotions, subtype_context=subtype_context
+ ) and is_proper_subtype(
+ b, a, ignore_promotions=ignore_promotions, subtype_context=subtype_context
)
@@ -307,11 +327,15 @@ def _is_subtype(
return left.accept(SubtypeVisitor(orig_right, subtype_context, proper_subtype))
-# TODO: should we pass on the original flags here and in couple other places?
-# This seems logical but was never done in the past for some reasons.
-def check_type_parameter(lefta: Type, righta: Type, variance: int, proper_subtype: bool) -> bool:
+def check_type_parameter(
+ lefta: Type, righta: Type, variance: int, proper_subtype: bool, subtype_context: SubtypeContext
+) -> bool:
def check(left: Type, right: Type) -> bool:
- return is_proper_subtype(left, right) if proper_subtype else is_subtype(left, right)
+ return (
+ is_proper_subtype(left, right, subtype_context=subtype_context)
+ if proper_subtype
+ else is_subtype(left, right, subtype_context=subtype_context)
+ )
if variance == COVARIANT:
return check(lefta, righta)
@@ -319,11 +343,18 @@ def check_type_parameter(lefta: Type, righta: Type, variance: int, proper_subtyp
return check(righta, lefta)
else:
if proper_subtype:
- return is_same_type(lefta, righta)
- return is_equivalent(lefta, righta)
+ # We pass ignore_promotions=False because it is a default for subtype checks.
+ # The actual value will be taken from the subtype_context, and it is whatever
+ # the original caller passed.
+ return is_same_type(
+ lefta, righta, ignore_promotions=False, subtype_context=subtype_context
+ )
+ return is_equivalent(lefta, righta, subtype_context=subtype_context)
-def ignore_type_parameter(lefta: Type, righta: Type, variance: int, proper_subtype: bool) -> bool:
+def ignore_type_parameter(
+ lefta: Type, righta: Type, variance: int, proper_subtype: bool, subtype_context: SubtypeContext
+) -> bool:
return True
@@ -386,7 +417,11 @@ class SubtypeVisitor(TypeVisitor[bool]):
return True
def visit_uninhabited_type(self, left: UninhabitedType) -> bool:
- return True
+ # We ignore this for unsafe overload checks, so that and empty list and
+ # a list of int will be considered non-overlapping.
+ if isinstance(self.right, UninhabitedType):
+ return True
+ return not self.subtype_context.ignore_uninhabited
def visit_erased_type(self, left: ErasedType) -> bool:
# This may be encountered during type inference. The result probably doesn't
@@ -522,12 +557,12 @@ class SubtypeVisitor(TypeVisitor[bool]):
for lefta, righta, tvar in type_params:
if isinstance(tvar, TypeVarType):
if not self.check_type_parameter(
- lefta, righta, tvar.variance, self.proper_subtype
+ lefta, righta, tvar.variance, self.proper_subtype, self.subtype_context
):
nominal = False
else:
if not self.check_type_parameter(
- lefta, righta, COVARIANT, self.proper_subtype
+ lefta, righta, COVARIANT, self.proper_subtype, self.subtype_context
):
nominal = False
if nominal:
@@ -697,6 +732,7 @@ class SubtypeVisitor(TypeVisitor[bool]):
if not left.names_are_wider_than(right):
return False
for name, l, r in left.zip(right):
+ # TODO: should we pass on the full subtype_context here and below?
if self.proper_subtype:
check = is_same_type(l, r)
else:
@@ -847,6 +883,10 @@ class SubtypeVisitor(TypeVisitor[bool]):
if isinstance(right, TypeType):
return self._is_subtype(left.item, right.item)
if isinstance(right, CallableType):
+ if self.proper_subtype and not right.is_type_obj():
+ # We can't accept `Type[X]` as a *proper* subtype of Callable[P, X]
+ # since this will break transitivity of subtyping.
+ return False
# This is unsound, we don't check the __init__ signature.
return self._is_subtype(left.item, right.ret_type)
if isinstance(right, Instance):
=====================================
mypy/version.py
=====================================
@@ -8,7 +8,7 @@ from mypy import git
# - Release versions have the form "0.NNN".
# - Dev versions have the form "0.NNN+dev" (PLUS sign to conform to PEP 440).
# - For 1.0 we'll switch back to 1.2.3 form.
-__version__ = "0.981"
+__version__ = "0.982"
base_version = __version__
mypy_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
=====================================
test-data/unit/check-classes.test
=====================================
@@ -3233,6 +3233,7 @@ def error(u_c: Type[U]) -> P: # Error here, see below
[out]
main:11: note: Revealed type is "__main__.WizUser"
main:12: error: A function returning TypeVar should receive at least one argument containing the same Typevar
+main:12: note: Consider using the upper bound "ProUser" instead
main:13: error: Value of type variable "P" of "new_pro" cannot be "U"
main:13: error: Incompatible return value type (got "U", expected "P")
=====================================
test-data/unit/check-inference.test
=====================================
@@ -3264,3 +3264,13 @@ from typing import Dict, Iterable, Tuple, Union
def foo(x: Union[Tuple[str, Dict[str, int], str], Iterable[object]]) -> None: ...
foo(("a", {"a": "b"}, "b"))
[builtins fixtures/dict.pyi]
+
+[case testUnionTypeCallableInference]
+from typing import Callable, Type, TypeVar, Union
+
+class A:
+ def __init__(self, x: str) -> None: ...
+
+T = TypeVar("T")
+def type_or_callable(value: T, tp: Union[Type[T], Callable[[int], T]]) -> T: ...
+reveal_type(type_or_callable(A("test"), A)) # N: Revealed type is "__main__.A"
=====================================
test-data/unit/check-overloading.test
=====================================
@@ -6467,3 +6467,29 @@ spam: Callable[..., str] = lambda x, y: 'baz'
reveal_type(func(spam)) # N: Revealed type is "def (*Any, **Any) -> builtins.str"
[builtins fixtures/paramspec.pyi]
+
+[case testGenericOverloadOverlapWithType]
+import m
+
+[file m.pyi]
+from typing import TypeVar, Type, overload, Callable
+
+T = TypeVar("T", bound=str)
+ at overload
+def foo(x: Type[T] | int) -> int: ...
+ at overload
+def foo(x: Callable[[int], bool]) -> str: ...
+
+[case testGenericOverloadOverlapWithCollection]
+import m
+
+[file m.pyi]
+from typing import TypeVar, Sequence, overload, List
+
+T = TypeVar("T", bound=str)
+
+ at overload
+def foo(x: List[T]) -> str: ...
+ at overload
+def foo(x: Sequence[int]) -> int: ...
+[builtins fixtures/list.pyi]
=====================================
test-data/unit/check-typevar-unbound.test
=====================================
@@ -1,4 +1,3 @@
-
[case testUnboundTypeVar]
from typing import TypeVar
@@ -6,9 +5,19 @@ T = TypeVar('T')
def f() -> T: # E: A function returning TypeVar should receive at least one argument containing the same Typevar
...
-
f()
+U = TypeVar('U', bound=int)
+
+def g() -> U: # E: A function returning TypeVar should receive at least one argument containing the same Typevar \
+ # N: Consider using the upper bound "int" instead
+ ...
+
+V = TypeVar('V', int, str)
+
+# TODO: this should also give an error
+def h() -> V:
+ ...
[case testInnerFunctionTypeVar]
@@ -21,7 +30,6 @@ def g(a: T) -> T:
...
return f()
-
[case testUnboundIterableOfTypeVars]
from typing import Iterable, TypeVar
@@ -29,7 +37,6 @@ T = TypeVar('T')
def f() -> Iterable[T]:
...
-
f()
[case testBoundTypeVar]
@@ -40,7 +47,6 @@ T = TypeVar('T')
def f(a: T, b: T, c: int) -> T:
...
-
[case testNestedBoundTypeVar]
from typing import Callable, List, Union, Tuple, TypeVar
View it on GitLab: https://salsa.debian.org/python-team/packages/mypy/-/commit/11c69ae6a6dc155b25bd63381b55c973d8f682b0
--
View it on GitLab: https://salsa.debian.org/python-team/packages/mypy/-/commit/11c69ae6a6dc155b25bd63381b55c973d8f682b0
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20221004/f442490f/attachment-0001.htm>
More information about the debian-med-commit
mailing list