python / python/mypy

`functools.partial` plugin is only triggered on calls

Ouverte
#17,620 1 commentaire 1 réaction 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

bug topic-plugins
Langage dominant
Python
Étoiles
20.6k
Forks
3.3k
Métriques de merge des PR
Métriques de PR en attente

Description

Bug Report

partial support is too fragile and easy to fool.

To Reproduce

import typing as t
from functools import partial

# 1.
# uncomment this to get type error
# partial(lambda x, y: x + y, 10)()

# 2.
# But this silly little thing passes type-check
silly: t.Callable[[], int] = partial(lambda x, y: x + y, 10)
silly()

Expected Behavior

Fail to coerce partial into incompatible callable type.

Actual Behavior

Success: no issues found in 1 source file

Your Environment

  • Mypy version used: master
  • Mypy command-line flags: no
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: 3.12

Looks like we carry information about needed arguments somewhere anyways, since 1 fails type check due to not enough arguments, so why we allow to coerce that partial into incompatible callable?
Perhaps this is due to this definition of partial:

    def __call__(self, /, *args: Any, **kwargs: Any) -> _T: ...

But, for example, pyright takes that into account and fails as expected:

[nix-shell:/tmp]$ pyright issue.py
/tmp/issue.py
  /tmp/issue.py:10:30 - error: Expression of type "partial[Unknown]" is incompatible with declared type "() -> int"
    Type "partial[Unknown]" is incompatible with type "() -> int"
      Extra parameter "y" (reportAssignmentType)
1 error, 0 warnings, 0 informations

I think it worth fixing, since we support partial and it is useful to rely on that support. It can be fixed, for example, as viewing partial result internally not as partial[int] type, but as something like

class FakePartial(Protocol[P, Ret]):
    @property
    def args(self) -> tuple[Any, ...]: ...
    
    @property
    def keywords(self) -> dict[any, ...]: ...

    @property
    def func(self) -> t.Callable[..., Ret]: ...

    def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Ret: ...

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Reproduisez les deux exemples avec Python 3.12 et mypy master, puis comparez le comportement avec la définition de typeshed functools.pyi référencée dans l’issue. Suivez la prise en charge existante de functools.partial et ses informations sur les arguments. Le travail est terminé lorsque l’affectation incompatible à un callable sans argument est rejetée, tandis que les appels valides à partial continuent de passer la vérification de types.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
devtools
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
30/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.