tony / python-questions

For StackOverflow or GitHub questions where an example is needed

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Type annotations: Pass-through questions

tony opened this issue · comments

Where do type annotations really stand?

PEP 612 talks about param specifications, but in reality - it's barely tangential to it, it's apparently syntactic decorators - an narrow, peripheral edge case.

How do you annotate pass-through params on class methods to third party libraries

I do not understand how param passthrough works with Python annotations (as of Python 3.10).

Lay of the land

Python has various forms of callback annotations.

Analogue in TypeScript / React

If you're familiar with TypeScript and React, I'm essentially expecting behavior like (inputProps: Partial<React.HTMLProps<HTMLInputElement>>) => <input {...inputProps} /> (sandbox: https://codesandbox.io/s/react-tsx-param-passthrough-73t8m8)

import React from "react";

const Button: React.FC<
  Partial<Omit<React.HTMLProps<HTMLButtonElement>, "type">>
> = ({ children, ...rest }) => <button {...rest}>{children}</button>;

export default function App() {
  return (
    <div>
      <Button onClick={() => alert("test")}>Click me</Button>
      {/* completions in <Button> show enriched from HTMLInputElement */}
    </div>
  );
}

Example: REST Client

This example class will wrap a third party library and allow passing through any positional or keyword arguments optionally via *args and **kwargs.

Let's assume RestClient, an authenticated REST client built on requests.

Authentication works through requests.auth.Base being instantiated and passed into auth params, e.g. requests.request(method, url, auth=self.auth)

Methods will map to API endpoints, e.g. client.list_items() -> GET {API_URL}/items.

Also, custom authenticated requests will be made possible directly through client.{post,put,patch,get,delete}. These map respectively to requests.{post,put,get,delete,patch}(auth=self.auth, *args, **kwargs).

Specs

Code drafts

import requests
from typing import Literal, Union

HttpMethodLiteral = Union[
    Literal["GET"],
    Literal["POST"],
    Literal["PUT"],
    Literal["DELETE"],
    Literal["OPTIONS"],
]

Example 1: Can get()'s kwargs and response inherit from request()'s?

def request(url: str, method: HttpMethodLiteral) -> requests.Response:
    if method == "GET":
        return requests.get(url)
    elif method == "POST":
        return requests.post(url)
    elif method == "PUT":
        return requests.put(url)
    elif method == "DELETE":
        return requests.delete(url)
    elif method == "OPTIONS":
        return requests.options(url)


def get(url:str, **kwargs):
    return requests(url=url, method='GET', **kwargs)

Example 2:

def request_get(url: str, method: HttpMethodLiteral, **kwargs) -> requests.Response:
    if method == "GET":
        return requests.get(url, **kwargs)

Example 3: Can request_passthrough()'s kwargs access requests.get, requests.put, etc.

def request_passthrough(url: str, method: HttpMethodLiteral, **kwargs) -> requests.Response:
    if method == "GET":
        return requests.get(url, **kwargs)
    elif method == "POST":
        return requests.post(url, **kwargs)
    elif method == "PUT":
        return requests.put(url, **kwargs)
    elif method == "DELETE":
        return requests.delete(url, **kwargs)
    elif method == "OPTIONS":
        return requests.options(url, **kwargs)

Example 4: If Example 2 is possible, can get()'s kwargs ...