python / python/typing

Paramspec Mapped Types

Ouverte
#1,506 5 commentaires 1 réaction 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

topic: other
Langage dominant
Python
Étoiles
1.8k
Forks
302
Merge moyen
23 h
PR mergées (30 j)
8

Description

Apologies if this has already been asked/solved - I can't figure out exactly what this is called so it's very difficult to search for.

I'm writing a simple strongly typed dependency system, based on function closures. I have a decorator function that has this typing:

# This is a stand-in for a full class implementation that has a __call__ method matching
# Callable[P, Awaitable[R]] - I'm just omitting it for brevity
type CallableObject[**P, R] = Callable[P, Awaitable[R]]

def dependency[**P, R](*args: P.args, **kwargs: P.kwargs) -> Callable[
    [Callable[P, Awaitable[R]] | Callable[P, R]], CallableObject
]:
    ...

This works to a degree, but, I want to transform the arguments in P to also accept functions that return the arguments type or an Awaitable of that type. For example:

def one() -> int:
    return 1

def two() -> int:
    return 2

@dependency()
def three(one: int, two: int) -> int:
    return one + two

# I want the decorated three to have this signature
def decorated_three(one: int | Callable[..., Awaitable[int] | int], two: int | Callable[..., Awaitable[int] | int]) -> int:
    ...

Essentially, I want to apply a mapping to every arg and kwarg in P that transforms it into P | Callable[..., Awaitable[P] | P]. Is this possible with the current grammar?

As a reference, I wrote an example that does what I'm attempting to do in typescript, where you can unpack what they call "type tuples" using the keyof syntax to mutate their values:

function dependency<P extends unknown[], R>(wrap: (...args: P) => R): (...args: {[V in keyof P]: P[V] | ((...args: any) => P[V] | Promise<P[V]>)}) => R {
    return wrap as any
}

function one(): number { return 1 }

function two(): number { return 2 }

function three(one: number, two: number): number { return one + two }

// Has type: const decorated_three: (one: number | ((...args: any) => number | Promise<number>), two: number | ((...args: any) => number | Promise<number>)) => number;
const decorated_three = dependency(three)

(Playground where you can see / verify the typing works as expected)

Apologies for dragging in another type system/language - I'm just looking for the python equivalent (if it exists).

Appreciate the help in advance. If this is a duplicate, please close it and mark it with the correct issue - I just couldn't find it 😅

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

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

Commencez par les exemples de ParamSpec et la signature décorée demandée dans l’issue, puis examinez la grammaire actuelle de Python typing pour les parameter packs et les types callable. Comparez la transformation souhaitée pour chaque paramètre avec l’exemple TypeScript lié de mapped-tuple ; le travail est considéré comme terminé lorsqu’il a été établi si la grammaire permet de l’exprimer et que l’équivalent pris en charge ou la limitation a été documenté.

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

Évaluation

Stack technique
python
Domaine
developer-experience
Type d'issue
Fonctionnalité
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
Active
Clarté
Plutôt claire
Accessibilité débutants
38/100

Recevez les nouvelles issues par e-mail

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