python / python/typing

Paramspec Mapped Types

オープン
#1,506 コメント 5 件 リアクション 1 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

topic: other
主要言語
Python
スター
1.8k
フォーク
302
平均マージ
23時間
マージ済み PR(30日)
8

説明

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 😅

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

ParamSpec の例と issue で要求されているデコレートされたシグネチャから始め、次に parameter pack と callable 型に関する現在の Python typing 文法を確認します。パラメーターごとに必要な変換を、リンクされている TypeScript の mapped-tuple の例と比較します。完了条件は、その文法で表現できるかどうかを明らかにし、サポートされる同等の表現または制限を文書化することです。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
python
領域
developer-experience
issue の種類
機能追加
難易度
5/5
見積もり時間
1週間以上
活発さ
活発
明瞭さ
おおむね明確
初心者へのやさしさ
38/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。