python / python/typing

Paramspec Mapped Types

Abierto
#1,506 5 comentarios 1 reacción 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

topic: other
Lenguaje dominante
Python
Estrellas
1.8k
Forks
302
Merge medio
23 h
PR fusionados (30 d)
8

Descripción

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 😅

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comienza con los ejemplos de ParamSpec y la firma decorada solicitada en el issue; después, revisa la gramática actual de Python typing para parameter packs y tipos callable. Compara la transformación deseada por parámetro con el ejemplo enlazado de TypeScript de mapped-tuple; se considera terminado cuando se haya establecido si la gramática puede expresarlo y se haya documentado el equivalente compatible o la limitación.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
developer-experience
Tipo de issue
Nueva funcionalidad
Dificultad
5/5
Tiempo estimado
Más de una semana
Estado de actividad
Activo
Claridad
Bastante claro
Aptitud para principiantes
38/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.