Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use type literals, overloads, and GitHub's OpenAPI spec for tighter type checking #146

Open
brettcannon opened this issue Dec 29, 2020 · 0 comments
Labels

Comments

@brettcannon
Copy link
Collaborator

Inspired by how @octokit/core handles typing with TypeScript, it should be possible to automatically generate much tighter type hints using type literals (and especially @overload w/ literals) and GitHub's OpenAPI definition.

For example, take getting the list of changed files for a PR. It's a GET request with a template URL of /repos/{owner}/{repo}/pulls/{pull_number}/files. If we added a new parameter to gidgethub.abc.GitHubAPI.getiter() to manage the query parameters for a URL separate from the template parameters (already covered by url_vars), and automatically handled the addition of the query parameters, then we could type things as:

from typing import TypeDict


class PullsListFilesURLVars(TypedDict):
    owner: str
    repo: str
    # Anything not `str` would be a breaking change thanks to `url_vars` being typed to `Dict[str, str]`.
    pull_number: int


class PullsListFilesQueryVars(TypedDict, partial=True):
    per_page: int
    page: int


class PullsListFilesReturnValue(TypedDict, partial=True):
    sha: str
    filename: str
    status: str
    additions: int
    deletions: int
    changes: int
    blob_url: str
    raw_url: str
    contents_url: str
    patch: str
    previous_filename: str  # Optional; may not be included.

class GitHubAPI:
    async def getiter(
        self,
        url: Literal["/repos/{owner}/{repo}/pulls/{pull_number}/files"],
        url_vars: PullsListFilesURLVars,
        # Keyword-only? Or keys obvious enough to differentiate from `url_vars`?
        query_vars: PullsListFilesQueryVars,
        *,
        accept: str = sansio.accept_format(),
        jwt: Opt[str] = None,
        oauth_token: Opt[str] = None,
    ) -> AsyncGenerator[PullsListFilesReturnValue, None]:
        ...

A default overload that fell back to the current generic typing can exist for those that don't want to migrate. This could be applied to all public methods of GitHubAPI.

Thanks to the OpenAPI definition this could all be automated and put into an abc.pyi file to keep it out of the way of the code that people edit. And a GitHub Action could be used to make sure that the file is continuously updated and released.

I don't know if this is worth the amount of effort it would take to implement (80% of it is easy; it's any potential edge cases along with how to handle things in the API itself that may be tricky), but the possibility is there if people still prefer gidgethub over ghapi but want the best typing possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant