Skip to content

Instantly share code, notes, and snippets.

@mypy-play
Created July 11, 2025 11:27
Show Gist options
  • Save mypy-play/933181c4bd375bb5d70abed67da7d864 to your computer and use it in GitHub Desktop.
Save mypy-play/933181c4bd375bb5d70abed67da7d864 to your computer and use it in GitHub Desktop.
Shared via mypy Playground
# distutils/extension.py
from __future__ import annotations
import os
from collections.abc import Iterable
from typing import TYPE_CHECKING, TypedDict, Union
if TYPE_CHECKING:
from typing_extensions import TypeAlias, Unpack
class _Kwargs(TypedDict, total=False):
include_dirs: list[str] | None = []
define_macros: list[tuple[str, str | None]] | None = []
undef_macros: list[str] | None = []
library_dirs: list[str] | None = []
libraries: list[str] | None = []
runtime_library_dirs: list[str] | None = []
extra_objects: list[str] | None = []
extra_compile_args: list[str] | None = []
extra_link_args: list[str] | None = []
export_symbols: list[str] | None = []
swig_opts: list[str] | None = []
depends: list[str] | None = []
language: str | None = None
optional: bool | None = None
_Args: TypeAlias = Union[ # Catch-all
list[str], None, list[tuple[str, Union[str, None]]], bool, str
]
class distutils_Extension:
def __init__(
self,
name: str,
sources: Iterable[str | os.PathLike[str]],
*args: _Args,
**kw: Unpack[_Kwargs],
):
if not isinstance(name, str):
raise TypeError("'name' must be a string")
# handle the string case first; since strings are iterable, disallow them
if isinstance(sources, str):
raise TypeError(
"'sources' must be an iterable of strings or PathLike objects, not a string"
)
# now we check if it's iterable and contains valid types
try:
self.sources = list(map(os.fspath, sources))
except TypeError:
raise TypeError(
"'sources' must be an iterable of strings or PathLike objects"
)
keywords = _Kwargs().keys() # ordered list of keyword arguments
optional = _Kwargs(zip(keywords, args))
kwargs = _Kwargs(**optional, **kw)
self.name = name
self.include_dirs = kwargs.get("include_dirs") or []
self.define_macros = kwargs.get("define_macros") or []
self.undef_macros = kwargs.get("undef_macros") or []
self.library_dirs = kwargs.get("library_dirs") or []
self.libraries = kwargs.get("libraries") or []
self.runtime_library_dirs = kwargs.get("runtime_library_dirs") or []
self.extra_objects = kwargs.get("extra_objects") or []
self.extra_compile_args = kwargs.get("extra_compile_args") or []
self.extra_link_args = kwargs.get("extra_link_args") or []
self.export_symbols = kwargs.get("export_symbols") or []
self.swig_opts = kwargs.get("swig_opts") or []
self.depends = kwargs.get("depends") or []
self.language = kwargs.get("language")
self.optional = kwargs.get("optional")
reveal_type(self.include_dirs)
reveal_type(self.define_macros)
reveal_type(self.optional)
# setuptools/extension.py
class setuptools_Extension(distutils_Extension):
def __init__(
self,
name: str,
sources: Iterable[str | os.PathLike[str]],
*args: _Args,
py_limited_api: bool = False,
**kw: Unpack[_Kwargs],
) -> None:
# The *args is needed for compatibility as calls may use positional
# arguments. py_limited_api may be set only via keyword.
self.py_limited_api = py_limited_api
super().__init__(name, sources, *args, **kw)
reveal_type(self.py_limited_api)
reveal_type(self.include_dirs)
reveal_type(self.define_macros)
reveal_type(self.optional)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment