Paramspec Mapped Types
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.8k
- Forks
- 302
- Avg merge
- 23h
- Merged PRs (30d)
- 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 😅
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the ParamSpec examples and the requested decorated signature in the issue, then review the current Python typing grammar for parameter packs and callable types. Compare the desired per-parameter transformation with the linked TypeScript mapped-tuple example; done means establishing whether the grammar can express it and documenting the supported equivalent or limitation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- developer-experience
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100