Last active
February 28, 2025 08:38
-
-
Save catwell/ca31fcd5e13f61bd6142d363b18df833 to your computer and use it in GitHub Desktop.
ParamSpec + Concatenate + higher-order function wrapper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# See https://julien.danjou.info/p/the-hidden-cost-of-badly-typed-python | |
# Simple version (hardcoded types) | |
from collections.abc import Callable | |
from typing import Any, Concatenate, ParamSpec | |
P = ParamSpec("P") | |
def send_request(client: "HttpClient", method: str = "GET", timeout: int = 5) -> str: | |
return f"Request sent to {client.url} with method {method} and timeout {timeout}s" | |
class HttpClient: | |
def __init__(self, url: str): | |
self.url = url | |
def _make_request(f: Callable[Concatenate[HttpClient, P], str]) -> Callable[Concatenate[str, P], str]: | |
def g(url: str, *args: Any, **kwargs: Any) -> str: | |
return f(HttpClient(url), *args, **kwargs) | |
return g | |
make_request = _make_request(send_request) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# See https://julien.danjou.info/p/the-hidden-cost-of-badly-typed-python | |
# Generic version | |
from collections.abc import Callable | |
from typing import Any, Concatenate | |
def send_request(client: "HttpClient", method: str = "GET", timeout: int = 5) -> str: | |
return f"Request sent to {client.url} with method {method} and timeout {timeout}s" | |
class HttpClient: | |
def __init__(self, url: str): | |
self.url = url | |
def _replace_first_arg[**P, Tin, Tout, Tres]( | |
wrapped: Callable[Concatenate[Tout, P], Tres], | |
project: Callable[[Tin], Tout], | |
) -> Callable[Concatenate[Tin, P], Tres]: | |
def wrapper(a: Tin, *args: Any, **kwargs: Any) -> Tres: | |
return wrapped(project(a), *args, **kwargs) | |
return wrapper | |
make_request = _replace_first_arg(send_request, HttpClient) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It works with both pyright and mypy: