Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type alias expansion sometimes interferes with type variable binding #3924

Open
ilevkivskyi opened this issue Sep 6, 2017 · 6 comments
Open
Labels
bug mypy got something wrong priority-0-high topic-calls Function calls, *args, **kwargs, defaults topic-type-alias TypeAlias and other type alias issues topic-type-variables

Comments

@ilevkivskyi
Copy link
Member

Consider the following two examples, I think they should be equivalent, since logically expansion of type aliases should happen before any other steps. (At least this would be consistent and natural for those familiar with C macros):

from typing import TypeVar, Callable
T = TypeVar('T')

def test1() -> Callable[[T], T]: ...
reveal_type(test1) # Revealed type is 'def () -> def [T] (T`-1) -> T`-1'
reveal_type(test1()) # Revealed type is 'def [T] (T`-1) -> T`-1'

F = Callable[[T], T]
def test2() -> F[T]: ...
reveal_type(test2) # Revealed type is 'def [T] () -> def (T`-1) -> T`-1'
reveal_type(test2()) # Revealed type is 'def (<nothing>) -> <nothing>'

Here test1 works as expected, while if I use an alias something strange happens with test2. Namely notice a subtle difference between their types.

def () -> def [T] (T`-1) -> T`-1
and
def [T] () -> def (T`-1) -> T`-1

I have noticed few similar scenarios, they all seem to be related to Callable.

@gvanrossum
Copy link
Member

Sounds like the code that made -> Callable[[T], T] possible in the first place still has some bugs...

@mvolfik
Copy link

mvolfik commented Feb 3, 2021

I have an issue which is, I believe, related to this:

from typing import TypeVar, Callable

T = TypeVar("T")
Function = Callable[[T], T]

a: Function         = ...
b: Function[T]      = ...
c: Callable[[T], T] = ...

(save as test.pyi, or replace the ellipsis with lambda x: x, function created in function etc.)

Mypy always disallows a, with --strict disallows b and always allows c. Tested with 0.800 and 0.810+dev.9e0e23e97653dab3a558d34340486e7a66f7d6f0.

How much is this related, should I file a separate issue? I would expect either a or b (no idea which one though) to be entirely correct

When I was looking for duplicates, #8922 also looked related

davidszotten added a commit to davidszotten/django-ninja that referenced this issue Jul 6, 2021
unfortunately the alias doesn't work

see e.g. python/mypy#3924

```
from typing import Any, Callable, TypeVar

TCallable = TypeVar("TCallable", bound=Callable[..., Any])
Decorator = Callable[[TCallable], TCallable]

def direct() -> Callable[[TCallable], TCallable]:
    ...

def alias() -> Decorator[TCallable]:
    ...

def half_alias() -> Decorator:
    ...

reveal_type(direct())
reveal_type(alias())
reveal_type(half_alias())
```

```
$ mypy --strict test.py

test.py:15:21: error: Missing type parameters for generic type "Decorator"
test.py:19:13: note: Revealed type is "def [TCallable <: def (*Any, **Any) -> Any] (TCallable`-1) -> TCallable`-1"
test.py:20:13: note: Revealed type is "def (<nothing>) -> <nothing>"
test.py:21:13: note: Revealed type is "def (Any) -> Any"
Found 1 error in 1 file (checked 1 source file)
```
@AlexWaygood AlexWaygood added topic-calls Function calls, *args, **kwargs, defaults topic-type-alias TypeAlias and other type alias issues labels Apr 4, 2022
@AlexWaygood
Copy link
Member

I just closed #8273 as a duplicate of this issue, but there was some interesting discussion about possible causes and solutions in that issue.

rainbow1016 added a commit to rainbow1016/django-master that referenced this issue May 18, 2023
unfortunately the alias doesn't work

see e.g. python/mypy#3924

```
from typing import Any, Callable, TypeVar

TCallable = TypeVar("TCallable", bound=Callable[..., Any])
Decorator = Callable[[TCallable], TCallable]

def direct() -> Callable[[TCallable], TCallable]:
    ...

def alias() -> Decorator[TCallable]:
    ...

def half_alias() -> Decorator:
    ...

reveal_type(direct())
reveal_type(alias())
reveal_type(half_alias())
```

```
$ mypy --strict test.py

test.py:15:21: error: Missing type parameters for generic type "Decorator"
test.py:19:13: note: Revealed type is "def [TCallable <: def (*Any, **Any) -> Any] (TCallable`-1) -> TCallable`-1"
test.py:20:13: note: Revealed type is "def (<nothing>) -> <nothing>"
test.py:21:13: note: Revealed type is "def (Any) -> Any"
Found 1 error in 1 file (checked 1 source file)
```
@sirosen
Copy link

sirosen commented Aug 21, 2023

Coming at this from #13449, where there's some discussion of my case (slightly different from the OP there), I have a question:

Is there a benefit or meaning to allowing <nothing> as a type inference? I'm wondering what the potential benefit and harm would be of making --strict enable rejection of any inference which produces <nothing> as an error.

The only instances of <nothing> which I've seen are avoidable errors related to scoping of type variables. Are there use-cases in which it is the right type to infer and matches the user's intent?

@ilevkivskyi
Copy link
Member Author

<nothing> is a subtype of all types, a.k.a. bottom type, a.k.a. error type, a.k.a. item type of empty collection. It behaves as it is for various reasons (both good and bad). What you are asking about is not related to this issue. If you can clearly describe what exactly do you want (with examples), you can open a new issue.

niceDeve added a commit to niceDeve/django-master that referenced this issue Oct 23, 2024
unfortunately the alias doesn't work

see e.g. python/mypy#3924

```
from typing import Any, Callable, TypeVar

TCallable = TypeVar("TCallable", bound=Callable[..., Any])
Decorator = Callable[[TCallable], TCallable]

def direct() -> Callable[[TCallable], TCallable]:
    ...

def alias() -> Decorator[TCallable]:
    ...

def half_alias() -> Decorator:
    ...

reveal_type(direct())
reveal_type(alias())
reveal_type(half_alias())
```

```
$ mypy --strict test.py

test.py:15:21: error: Missing type parameters for generic type "Decorator"
test.py:19:13: note: Revealed type is "def [TCallable <: def (*Any, **Any) -> Any] (TCallable`-1) -> TCallable`-1"
test.py:20:13: note: Revealed type is "def (<nothing>) -> <nothing>"
test.py:21:13: note: Revealed type is "def (Any) -> Any"
Found 1 error in 1 file (checked 1 source file)
```
@antoniogamizdelgado
Copy link

Any update on this? This is interfering with django ninja api decorator type hints (getting the following error: error: Untyped decorator makes function) when defining endpoints as:

router:: Router = Router()


@router.get(
    "endpoint",
    response={
        200: SomeModel,
        400: Error,
        401: Error,
        404: Error,
        500: Error,
    },
)
def some_endpoint(request: HttpRequest -> SomeModel:
    pass

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong priority-0-high topic-calls Function calls, *args, **kwargs, defaults topic-type-alias TypeAlias and other type alias issues topic-type-variables
Projects
None yet
Development

No branches or pull requests

6 participants