Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into bugfix/st-paramsp…
Browse files Browse the repository at this point in the history
…ec-with-functools-partial
  • Loading branch information
sterliakov committed Oct 25, 2024
2 parents 4d55122 + 9323b88 commit b077063
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 13 deletions.
4 changes: 2 additions & 2 deletions docs/source/type_narrowing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -400,11 +400,11 @@ Mypy supports TypeIs (:pep:`742`).

A `TypeIs narrowing function <https://typing.readthedocs.io/en/latest/spec/narrowing.html#typeis>`_
allows you to define custom type checks that can narrow the type of a variable
in `both the if and else <https://docs.python.org/3.13/library/typing.html#typing.TypeIs>_`
in `both the if and else <https://docs.python.org/3.13/library/typing.html#typing.TypeIs>`_
branches of a conditional, similar to how the built-in isinstance() function works.

TypeIs is new in Python 3.13 — for use in older Python versions, use the backport
from `typing_extensions <https://typing-extensions.readthedocs.io/en/latest/>_`
from `typing_extensions <https://typing-extensions.readthedocs.io/en/latest/>`_

Consider the following example using TypeIs:

Expand Down
6 changes: 4 additions & 2 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -2785,7 +2785,7 @@ def plausible_overload_call_targets(
) -> list[CallableType]:
"""Returns all overload call targets that having matching argument counts.
If the given args contains a star-arg (*arg or **kwarg argument, including
If the given args contains a star-arg (*arg or **kwarg argument, except for
ParamSpec), this method will ensure all star-arg overloads appear at the start
of the list, instead of their usual location.
Expand Down Expand Up @@ -2820,7 +2820,9 @@ def has_shape(typ: Type) -> bool:
# ParamSpec can be expanded in a lot of different ways. We may try
# to expand it here instead, but picking an impossible overload
# is safe: it will be filtered out later.
star_matches.append(typ)
# Unlike other var-args signatures, ParamSpec produces essentially
# a fixed signature, so there's no need to push them to the top.
matches.append(typ)
elif self.check_argument_count(
typ, arg_types, arg_kinds, arg_names, formal_to_actual, None
):
Expand Down
6 changes: 5 additions & 1 deletion mypy/meet.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,11 @@ def get_possible_variants(typ: Type) -> list[Type]:
else:
return [typ.upper_bound]
elif isinstance(typ, ParamSpecType):
return [typ.upper_bound]
# Extract 'object' from the final mro item
upper_bound = get_proper_type(typ.upper_bound)
if isinstance(upper_bound, Instance):
return [Instance(upper_bound.type.mro[-1], [])]
return [AnyType(TypeOfAny.implementation_artifact)]
elif isinstance(typ, TypeVarTupleType):
return [typ.upper_bound]
elif isinstance(typ, UnionType):
Expand Down
8 changes: 8 additions & 0 deletions mypy/stubtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1893,6 +1893,8 @@ class _Arguments:
custom_typeshed_dir: str | None
check_typeshed: bool
version: str
show_traceback: bool
pdb: bool


# typeshed added a stub for __main__, but that causes stubtest to check itself
Expand Down Expand Up @@ -1938,6 +1940,8 @@ def test_stubs(args: _Arguments, use_builtins_fixtures: bool = False) -> int:
options.abs_custom_typeshed_dir = os.path.abspath(options.custom_typeshed_dir)
options.config_file = args.mypy_config_file
options.use_builtins_fixtures = use_builtins_fixtures
options.show_traceback = args.show_traceback
options.pdb = args.pdb

if options.config_file:

Expand Down Expand Up @@ -2091,6 +2095,10 @@ def parse_options(args: list[str]) -> _Arguments:
parser.add_argument(
"--version", action="version", version="%(prog)s " + mypy.version.__version__
)
parser.add_argument("--pdb", action="store_true", help="Invoke pdb on fatal error")
parser.add_argument(
"--show-traceback", "--tb", action="store_true", help="Show traceback on fatal error"
)

return parser.parse_args(args, namespace=_Arguments())

Expand Down
10 changes: 3 additions & 7 deletions mypyc/irbuild/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -979,17 +979,13 @@ def _analyze_iterable_item_type(self, expr: Expression) -> Type:

def is_native_module(self, module: str) -> bool:
"""Is the given module one compiled by mypyc?"""
return module in self.mapper.group_map
return self.mapper.is_native_module(module)

def is_native_ref_expr(self, expr: RefExpr) -> bool:
if expr.node is None:
return False
if "." in expr.node.fullname:
return self.is_native_module(expr.node.fullname.rpartition(".")[0])
return True
return self.mapper.is_native_ref_expr(expr)

def is_native_module_ref_expr(self, expr: RefExpr) -> bool:
return self.is_native_ref_expr(expr) and expr.kind == GDEF
return self.mapper.is_native_module_ref_expr(expr)

def is_synthetic_type(self, typ: TypeInfo) -> bool:
"""Is a type something other than just a class we've created?"""
Expand Down
4 changes: 3 additions & 1 deletion mypyc/irbuild/mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def __init__(self, group_map: dict[str, str | None]) -> None:
self.group_map = group_map
self.type_to_ir: dict[TypeInfo, ClassIR] = {}
self.func_to_decl: dict[SymbolNode, FuncDecl] = {}
self.symbol_fullnames: set[str] = set()

def type_to_rtype(self, typ: Type | None) -> RType:
if typ is None:
Expand Down Expand Up @@ -217,7 +218,8 @@ def is_native_ref_expr(self, expr: RefExpr) -> bool:
if expr.node is None:
return False
if "." in expr.node.fullname:
return self.is_native_module(expr.node.fullname.rpartition(".")[0])
name = expr.node.fullname.rpartition(".")[0]
return self.is_native_module(name) or name in self.symbol_fullnames
return True

def is_native_module_ref_expr(self, expr: RefExpr) -> bool:
Expand Down
2 changes: 2 additions & 0 deletions mypyc/irbuild/prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ def build_type_map(
if not options.global_opts:
class_ir.children = None
mapper.type_to_ir[cdef.info] = class_ir
mapper.symbol_fullnames.add(class_ir.fullname)

# Populate structural information in class IR for extension classes.
for module, cdef in classes:
Expand Down Expand Up @@ -149,6 +150,7 @@ def load_type_map(mapper: Mapper, modules: list[MypyFile], deser_ctx: DeserMaps)
if isinstance(node.node, TypeInfo) and is_from_module(node.node, module):
ir = deser_ctx.classes[node.node.fullname]
mapper.type_to_ir[node.node] = ir
mapper.symbol_fullnames.add(node.node.fullname)
mapper.func_to_decl[node.node] = ir.ctor

for module in modules:
Expand Down
12 changes: 12 additions & 0 deletions mypyc/test-data/run-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -2594,3 +2594,15 @@ def test_class_final_attribute_inherited() -> None:
assert C().b == 2
assert B().c == 3
assert C().c == 3

[case testClassWithFinalAttributeAccess]
from typing import Final

class C:
a: Final = {'x': 'y'}
b: Final = C.a

def test_final_attribute() -> None:
assert C.a['x'] == 'y'
assert C.b['x'] == 'y'
assert C.a is C.b
35 changes: 35 additions & 0 deletions test-data/unit/check-parameter-specification.test
Original file line number Diff line number Diff line change
Expand Up @@ -2304,6 +2304,41 @@ reveal_type(capture(err)) # N: Revealed type is "builtins.int"

[builtins fixtures/paramspec.pyi]

[case testRunParamSpecOverlappingOverloadsOrder]
from typing import Any, Callable, overload
from typing_extensions import ParamSpec

P = ParamSpec("P")

class Base:
pass
class Child(Base):
def __call__(self) -> str: ...
class NotChild:
def __call__(self) -> str: ...

@overload
def handle(func: Base) -> int: ...
@overload
def handle(func: Callable[P, str], *args: P.args, **kwargs: P.kwargs) -> str: ...
def handle(func: Any, *args: Any, **kwargs: Any) -> Any:
return func(*args, **kwargs)

@overload
def handle_reversed(func: Callable[P, str], *args: P.args, **kwargs: P.kwargs) -> str: ...
@overload
def handle_reversed(func: Base) -> int: ...
def handle_reversed(func: Any, *args: Any, **kwargs: Any) -> Any:
return func(*args, **kwargs)

reveal_type(handle(Child())) # N: Revealed type is "builtins.int"
reveal_type(handle(NotChild())) # N: Revealed type is "builtins.str"

reveal_type(handle_reversed(Child())) # N: Revealed type is "builtins.str"
reveal_type(handle_reversed(NotChild())) # N: Revealed type is "builtins.str"

[builtins fixtures/paramspec.pyi]

[case testBindPartial]
from functools import partial
from typing_extensions import ParamSpec
Expand Down
38 changes: 38 additions & 0 deletions test-data/unit/check-selftype.test
Original file line number Diff line number Diff line change
Expand Up @@ -2176,3 +2176,41 @@ class count:
def foo(x: Union[range[int], count]) -> None:
for item in x:
reveal_type(item) # N: Revealed type is "builtins.int"

[case testGenericDescriptorWithSelfTypeAnnotationsAndOverloads]
from __future__ import annotations
from typing import Any, overload, Callable, TypeVar, Generic, ParamSpec
from typing_extensions import Concatenate

C = TypeVar("C", bound=Callable[..., Any])
S = TypeVar("S")
P = ParamSpec("P")
R = TypeVar("R")

class Descriptor(Generic[C]):
def __init__(self, impl: C) -> None: ...

@overload
def __get__(
self: Descriptor[C], instance: None, owner: type | None
) -> Descriptor[C]: ...

@overload
def __get__(
self: Descriptor[Callable[Concatenate[S, P], R]], instance: S, owner: type | None,
) -> Callable[P, R]: ...

def __get__(self, *args, **kwargs): ...

class Test:
@Descriptor
def method(self, foo: int, bar: str) -> bytes: ...

reveal_type(Test().method) # N: Revealed type is "def (foo: builtins.int, bar: builtins.str) -> builtins.bytes"

class Test2:
@Descriptor
def method(self, foo: int, *, bar: str) -> bytes: ...

reveal_type(Test2().method) # N: Revealed type is "def (foo: builtins.int, *, bar: builtins.str) -> builtins.bytes"
[builtins fixtures/tuple.pyi]

0 comments on commit b077063

Please sign in to comment.