functools.update_wrapper() will not accept descriptor (decorator) as wrapper
Personne n'a encore pris cette issue.
- Langage dominant
- Python
- Étoiles
- 5.1k
- Forks
- 2.1k
- Merge moyen
- 1 j 19 h
- PR mergées (30 j)
- 82
Description
Description:
The type stub for functools.update_wrapper() does not permit a descriptor for the wrapper (first) argument, a legitimate case arising when defining a descriptor-type decorator (like @property is).
https://github.com/python/typeshed/blob/main/stdlib/functools.pyi#L83
@erictraut While perhaps not exactly a regression, this used to work up until this commit of yours here (last week): https://github.com/python/typeshed/commit/9c4bfd5d11b47677e128452baa8ac7eeb1903a8e#diff-02c51ed45b741b6765c365fb5d6578c586510bbbd57b10a1dba10aeba37ae157L70-R84. I say not exactly a regression because the prior constraint introduced here was perhaps overly loose: https://github.com/python/typeshed/pull/4627/files
Example
As an example, the following (pyright) typing error is detected in the lazyproperty descriptor-type decorator defined here: https://gist.github.com/scanny/255f16339b74b2b59e896d67bd459d6b
lazyproperty.py|65 col 34-38 error| Argument of type "Self@lazyproperty[T@lazyproperty]"
cannot be assigned to parameter "wrapper"
of type "(**_PWrapper@update_wrapper) -> _RWapper@update_wrapper"
in function "update_wrapper"
Type "Self@lazyproperty[T@lazyproperty]" cannot be assigned to
type "(**_PWrapper@update_wrapper) -> _RWapper@update_wrapper"
To Reproduce
The gist referenced above has no dependencies other than the stdlib so can be type-checked directly (using pyright v1.1.296):
$ pyright lazyproperty.py
Analysis
The type definition at work constrains wrapper to be a Callable[_PWrapper, _RWapper]. I believe it also needs to permit Descriptor, although I'm not completely sure what that type definition is. My best guess is something like this:
class HasDunderGet(Protocol):
def __get__(self, obj: Any, type: type = None) -> Any: ...
class HasDunderSet(Protocol):
def __set__(self, obj: Any, value: Any) -> None: ...
class HasDunderDelete(Protocol):
def __delete__(self, obj: Any) -> None: ...
Descriptor = Union[HasDunderGet, HasDunderSet, HasDunderDelete]
Expected behavior
As far as I can tell, this is a legitimate usage of functools.update_wrapper() and decorators that produce a descriptor (like @property does) are also legitimate Python. It has certainly worked for a long time and also even typechecked with pyright previously (v1.1.273), maybe six months ago. So I would expect it to be accepted as written.
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Commencez par stdlib/functools.pyi, autour des lignes 82-87, et comparez l’annotation du wrapper avec l’utilisation du descripteur dans le gist lazyproperty.py lié. Exécutez pyright v1.1.296 sur lazyproperty.py pour reproduire l’erreur, puis examinez le commit de typeshed référencé et la pull request précédente pour obtenir le contexte. Le travail est terminé lorsque le décorateur de descripteur légitime passe la vérification de types sans affaiblir le typage de update_wrapper dans les domaines sans rapport.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- python
- Domaine
- developer-experience, tooling
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- À l'abandon
- Clarté
- Plutôt claire
- Accessibilité débutants
- 35/100