Skip to content

Commit ec46ffa

Browse files
committed
Type setup method
1 parent c3f486f commit ec46ffa

File tree

3 files changed

+123
-18
lines changed

3 files changed

+123
-18
lines changed

setup.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,8 @@ def _restore_install_lib(self):
5454
self.install_lib = self.install_libbase
5555

5656

57-
setup_params = dict(
58-
cmdclass={'install': install_with_pth},
59-
)
60-
6157
if __name__ == '__main__':
6258
# allow setup.py to run from another directory
63-
# TODO: Use a proper conditional statement here
64-
here and os.chdir(here) # type: ignore[func-returns-value]
65-
dist = setuptools.setup(**setup_params)
59+
if here:
60+
os.chdir(here)
61+
dist = setuptools.setup(cmdclass={'install': install_with_pth})

setuptools/__init__.py

Lines changed: 106 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
import os
1212
import sys
1313
from abc import abstractmethod
14-
from collections.abc import Mapping
15-
from typing import TYPE_CHECKING, TypeVar, overload
14+
from collections.abc import Iterable, Mapping, Sequence
15+
from typing import TYPE_CHECKING, Any, Literal, TypeVar, overload
1616

1717
sys.path.extend(((vendor_path := os.path.join(os.path.dirname(os.path.dirname(__file__)), 'setuptools', '_vendor')) not in sys.path) * [vendor_path]) # fmt: skip
1818
# workaround for #4476
@@ -21,6 +21,7 @@
2121
import _distutils_hack.override # noqa: F401
2222

2323
from . import logging, monkey
24+
from ._path import StrPath
2425
from .depends import Require
2526
from .discovery import PackageFinder, PEP420PackageFinder
2627
from .dist import Distribution
@@ -108,13 +109,106 @@ def _fetch_build_eggs(dist: Distribution):
108109
raise
109110

110111

111-
def setup(**attrs) -> Distribution:
112-
logging.configure()
113-
# Make sure we have any requirements needed to interpret 'attrs'.
114-
_install_setup_requires(attrs)
115-
# Override return type of distutils.core.Distribution with setuptools.dist.Distribution
116-
# (implicitly implemented via `setuptools.monkey.patch_all`).
117-
return distutils.core.setup(**attrs) # type: ignore[return-value]
112+
if TYPE_CHECKING:
113+
from typing_extensions import Never
114+
115+
from setuptools.command.build_clib import _BuildInfo
116+
117+
_DistributionT = TypeVar(
118+
"_DistributionT",
119+
bound=distutils.core.Distribution,
120+
default=Distribution,
121+
)
122+
123+
def setup(
124+
*,
125+
# Attributes from distutils.dist.DistributionMetadata.set_*
126+
# These take priority over attributes from distutils.dist.DistributionMetadata.__init__
127+
keywords: str | Iterable[str] = ...,
128+
platforms: str | Iterable[str] = ...,
129+
classifiers: str | Iterable[str] = ...,
130+
requires: Iterable[str] = ...,
131+
provides: Iterable[str] = ...,
132+
obsoletes: Iterable[str] = ...,
133+
# Attributes from distutils.dist.DistributionMetadata.__init__
134+
# These take priority over attributes from distutils.dist.Distribution.__init__
135+
name: str | None = None,
136+
version: str | None = None,
137+
author: str | None = None,
138+
author_email: str | None = None,
139+
maintainer: str | None = None,
140+
maintainer_email: str | None = None,
141+
url: str | None = None,
142+
license: str | None = None,
143+
description: str | None = None,
144+
long_description: str | None = None,
145+
download_url: str | None = None,
146+
# Attributes from distutils.dist.Distribution.__init__ (except self.metadata)
147+
# These take priority over attributes from distutils.dist.Distribution.display_option_names
148+
verbose=True,
149+
dry_run=False,
150+
help=False,
151+
cmdclass: dict[str, type[_Command]] = {},
152+
command_packages: str | list[str] | None = None,
153+
script_name: StrPath
154+
| None = ..., # default is actually set in distutils.core.setup
155+
script_args: list[str]
156+
| None = ..., # default is actually set in distutils.core.setup
157+
command_options: dict[str, dict[str, tuple[str, str]]] = {},
158+
packages: list[str] | None = None,
159+
package_dir: Mapping[str, str] | None = None,
160+
py_modules: list[str] | None = None,
161+
libraries: list[tuple[str, _BuildInfo]] | None = None,
162+
headers: list[str] | None = None,
163+
ext_modules: Sequence[distutils.core.Extension] | None = None,
164+
ext_package: str | None = None,
165+
include_dirs: list[str] | None = None,
166+
extra_path=None,
167+
scripts: list[str] | None = None,
168+
data_files: list[tuple[str, list[str]]] | None = None,
169+
password: str = '',
170+
command_obj: dict[str, _Command] = {},
171+
have_run: dict[str, bool] = {},
172+
# kwargs used directly in distutils.dist.Distribution.__init__
173+
options: Mapping[str, Mapping[str, str]] | None = None,
174+
licence: Never = ..., # Deprecated
175+
# Attributes from distutils.dist.Distribution.display_option_names
176+
# (this can more easily be copied from the `if TYPE_CHECKING` block)
177+
help_commands: bool = False,
178+
fullname: str | Literal[False] = False,
179+
contact: str | Literal[False] = False,
180+
contact_email: str | Literal[False] = False,
181+
# kwargs used directly in setuptools.dist.Distribution.__init__
182+
# and attributes from setuptools.dist.Distribution.__init__
183+
package_data: dict[str, list[str]] = {},
184+
dist_files: list[tuple[str, str, str]] = [],
185+
include_package_data: bool | None = None,
186+
exclude_package_data: dict[str, list[str]] | None = None,
187+
src_root: str | None = None,
188+
dependency_links: list[str] = [],
189+
setup_requires: list[str] = [],
190+
# From Distribution._DISTUTILS_UNSUPPORTED_METADATA set in Distribution._set_metadata_defaults
191+
long_description_content_type: str | None = None,
192+
project_urls=dict(),
193+
provides_extras=dict(),
194+
license_expression=None,
195+
license_file=None,
196+
license_files=None,
197+
install_requires=list(),
198+
extras_require=dict(),
199+
# kwargs used directly in distutils.core.setup
200+
distclass: type[_DistributionT] = Distribution, # type: ignore[assignment]
201+
# Custom Distributions could accept more params
202+
**attrs: Any,
203+
) -> _DistributionT: ...
204+
205+
else:
206+
207+
def setup(**attrs) -> Distribution:
208+
logging.configure()
209+
# Make sure we have any requirements needed to interpret 'attrs'.
210+
_install_setup_requires(attrs)
211+
return distutils.core.setup(**attrs)
118212

119213

120214
setup.__doc__ = distutils.core.setup.__doc__
@@ -167,7 +261,9 @@ class Command(_Command):
167261
command_consumes_arguments = False
168262
distribution: Distribution # override distutils.dist.Distribution with setuptools.dist.Distribution
169263

170-
def __init__(self, dist: Distribution, **kw) -> None:
264+
# Any: The kwargs could match any Command attribute including from subclasses
265+
# and subclasses can further override it to include any type.
266+
def __init__(self, dist: Distribution, **kw: Any) -> None:
171267
"""
172268
Construct the command for dist, updating
173269
vars(self) with any keyword parameters.

setuptools/command/build_clib.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
from __future__ import annotations
2+
3+
from collections.abc import Iterable
4+
from typing import NotRequired, TypedDict
5+
16
from ..dist import Distribution
27
from ..modified import newer_pairwise_group
38

@@ -6,6 +11,14 @@
611
from distutils.errors import DistutilsSetupError
712

813

14+
class _BuildInfo(TypedDict):
15+
sources: list[str] | tuple[str, ...]
16+
obj_deps: NotRequired[dict[str, list[str] | tuple[str, ...]]]
17+
macros: NotRequired[list[tuple[str] | tuple[str, str | None]]]
18+
include_dirs: NotRequired[list[str]]
19+
cflags: NotRequired[list[str]]
20+
21+
922
class build_clib(orig.build_clib):
1023
"""
1124
Override the default build_clib behaviour to do the following:
@@ -24,7 +37,7 @@ class build_clib(orig.build_clib):
2437

2538
distribution: Distribution # override distutils.dist.Distribution with setuptools.dist.Distribution
2639

27-
def build_libraries(self, libraries) -> None:
40+
def build_libraries(self, libraries: Iterable[tuple[str, _BuildInfo]]) -> None:
2841
for lib_name, build_info in libraries:
2942
sources = build_info.get('sources')
3043
if sources is None or not isinstance(sources, (list, tuple)):

0 commit comments

Comments
 (0)