Skip to content

Commit 872fc45

Browse files
committed
Basic pyright configs
1 parent 9b081af commit 872fc45

File tree

10 files changed

+72
-19
lines changed

10 files changed

+72
-19
lines changed

mypy.ini

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
[mypy]
2-
# CI should test for all versions, local development gets hints for oldest supported
3-
python_version = 3.8
2+
# Our testing setup doesn't allow passing CLI arguments, so local devs have to set this manually.
3+
# python_version = 3.8
44
strict = False
55
warn_unused_ignores = True
66
# required to support namespace packages: https://github.com/python/mypy/issues/14057
77
explicit_package_bases = True
88
exclude = (?x)(
99
^build/
1010
| ^.tox/
11+
| ^.eggs/
1112
| ^pkg_resources/tests/data/my-test-package-source/setup.py$ # Duplicate module name
1213
| ^.+?/(_vendor|extern)/ # Vendored
1314
| ^setuptools/_distutils/ # Vendored

pyrightconfig.json

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/microsoft/pyright/main/packages/vscode-pyright/schemas/pyrightconfig.schema.json",
3+
"exclude": [
4+
"build",
5+
".tox",
6+
".eggs",
7+
"**/extern", // Vendored
8+
"**/_vendor", // Vendored
9+
"setuptools/_distutils", // Vendored
10+
"**/tests", // Disabled as long as analyzeUnannotatedFunctions=false to reduce log spam
11+
"**/_*", // Disabled as long as analyzeUnannotatedFunctions=false to reduce log spam
12+
],
13+
// Our testing setup doesn't allow passing CLI arguments, so local devs have to set this manually.
14+
// "pythonVersion": "3.8",
15+
// For now we don't mind if mypy's `type: ignore` comments accidentally suppresses pyright issues
16+
"enableTypeIgnoreComments": true,
17+
"typeCheckingMode": "basic",
18+
// For now, align with mypy's default of skipping unannotated functions, only care about public API which should be annotated
19+
"analyzeUnannotatedFunctions": false,
20+
// Avoid raising issues when importing from "extern" modules, as those are added to path dynamically.
21+
// https://github.com/pypa/setuptools/pull/3979#discussion_r1367968993
22+
"reportMissingImports": "none",
23+
// Too many issues caused by vendoring and dynamic patching, still worth fixing when we can
24+
"reportAttributeAccessIssue": "warning",
25+
// Deferred initialization (initialize_options/finalize_options) causes many "potentially None" issues
26+
// TODO: Fix with type-guards or by changing how it's initialized
27+
"reportCallIssue": "warning",
28+
"reportArgumentType": "warning",
29+
"reportOptionalIterable": "warning",
30+
"reportOptionalMemberAccess": "warning",
31+
"reportGeneralTypeIssues": "warning",
32+
"reportOptionalOperand": "warning",
33+
}

setup.cfg

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ testing =
7373
# for tools/finalize.py
7474
jaraco.develop >= 7.21; python_version >= "3.9" and sys_platform != "cygwin"
7575
pytest-home >= 0.5
76+
pyright
7677
# No Python 3.11 dependencies require tomli, but needed for type-checking since we import it directly
7778
tomli
7879
# No Python 3.12 dependencies require importlib_metadata, but needed for type-checking since we import it directly

setuptools/command/build.py

+6
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,15 @@ def finalize_options(self):
9898

9999
def initialize_options(self):
100100
"""(Required by the original :class:`setuptools.Command` interface)"""
101+
...
101102

102103
def finalize_options(self):
103104
"""(Required by the original :class:`setuptools.Command` interface)"""
105+
...
104106

105107
def run(self):
106108
"""(Required by the original :class:`setuptools.Command` interface)"""
109+
...
107110

108111
def get_source_files(self) -> List[str]:
109112
"""
@@ -115,6 +118,7 @@ def get_source_files(self) -> List[str]:
115118
with all the files necessary to build the distribution.
116119
All files should be strings relative to the project root directory.
117120
"""
121+
...
118122

119123
def get_outputs(self) -> List[str]:
120124
"""
@@ -128,6 +132,7 @@ def get_outputs(self) -> List[str]:
128132
in ``get_output_mapping()`` plus files that are generated during the build
129133
and don't correspond to any source file already present in the project.
130134
"""
135+
...
131136

132137
def get_output_mapping(self) -> Dict[str, str]:
133138
"""
@@ -138,3 +143,4 @@ def get_output_mapping(self) -> Dict[str, str]:
138143
Destination files should be strings in the form of
139144
``"{build_lib}/destination/file/path"``.
140145
"""
146+
...

setuptools/command/build_clib.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from distutils import log
44

55
try:
6-
from distutils._modified import newer_pairwise_group
6+
from distutils._modified import newer_pairwise_group # type: ignore[import-not-found]
77
except ImportError:
88
# fallback for SETUPTOOLS_USE_DISTUTILS=stdlib
99
from .._distutils._modified import newer_pairwise_group

setuptools/command/easy_install.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2012,7 +2012,7 @@ def is_python_script(script_text, filename):
20122012

20132013

20142014
try:
2015-
from os import chmod as _chmod
2015+
from os import chmod as _chmod # pyright: ignore[reportAssignmentType] # Loosing type-safety w/ pyright, but that's ok
20162016
except ImportError:
20172017
# Jython compatibility
20182018
def _chmod(*args: object, **kwargs: object) -> None: # type: ignore[misc] # Mypy re-uses the imported definition anyway

setuptools/command/editable_wheel.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
from .install_scripts import install_scripts as install_scripts_cls
6060

6161
if TYPE_CHECKING:
62-
from wheel.wheelfile import WheelFile # type:ignore[import-untyped] # noqa
62+
from wheel.wheelfile import WheelFile # type: ignore[import-untyped] # noqa
6363

6464
_P = TypeVar("_P", bound=StrPath)
6565
_logger = logging.getLogger(__name__)

setuptools/config/pyprojecttoml.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,10 @@ def _obtain(self, dist: "Distribution", field: str, package_dir: Mapping[str, st
297297
def _obtain_version(self, dist: "Distribution", package_dir: Mapping[str, str]):
298298
# Since plugins can set version, let's silently skip if it cannot be obtained
299299
if "version" in self.dynamic and "version" in self.dynamic_cfg:
300-
return _expand.version(self._obtain(dist, "version", package_dir))
300+
return _expand.version(
301+
# We already do an early check for the presence of "version"
302+
self._obtain(dist, "version", package_dir) # pyright: ignore[reportArgumentType]
303+
)
301304
return None
302305

303306
def _obtain_readme(self, dist: "Distribution") -> Optional[Dict[str, str]]:
@@ -307,9 +310,10 @@ def _obtain_readme(self, dist: "Distribution") -> Optional[Dict[str, str]]:
307310
dynamic_cfg = self.dynamic_cfg
308311
if "readme" in dynamic_cfg:
309312
return {
313+
# We already do an early check for the presence of "readme"
310314
"text": self._obtain(dist, "readme", {}),
311315
"content-type": dynamic_cfg["readme"].get("content-type", "text/x-rst"),
312-
}
316+
} # pyright: ignore[reportReturnType]
313317

314318
self._ensure_previously_set(dist, "readme")
315319
return None

setuptools/monkey.py

+19-12
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88
import sys
99
import types
1010
from importlib import import_module
11-
from typing import List, TypeVar
11+
from typing import List, Optional, Type, TypeVar, Union, cast, overload
1212

1313
import distutils.filelist
1414

1515

1616
_T = TypeVar("_T")
17+
_UnpatchT = TypeVar("_UnpatchT", type, types.FunctionType)
18+
1719

1820
__all__: List[str] = []
1921
"""
@@ -36,25 +38,30 @@ def _get_mro(cls):
3638
return inspect.getmro(cls)
3739

3840

39-
def get_unpatched(item: _T) -> _T:
40-
lookup = (
41-
get_unpatched_class
42-
if isinstance(item, type)
43-
else get_unpatched_function
44-
if isinstance(item, types.FunctionType)
45-
else lambda item: None
46-
)
47-
return lookup(item)
41+
@overload
42+
def get_unpatched(item: _UnpatchT) -> _UnpatchT: ... # type: ignore[overload-overlap]
43+
@overload
44+
def get_unpatched(item: object) -> None: ...
45+
def get_unpatched(
46+
item: Union[type, types.FunctionType, object],
47+
) -> Optional[Union[type, types.FunctionType]]:
48+
if isinstance(item, type):
49+
return get_unpatched_class(item)
50+
if isinstance(item, types.FunctionType):
51+
return get_unpatched_function(item)
52+
return None
4853

4954

50-
def get_unpatched_class(cls):
55+
def get_unpatched_class(cls: Type[_T]) -> Type[_T]:
5156
"""Protect against re-patching the distutils if reloaded
5257
5358
Also ensures that no other distutils extension monkeypatched the distutils
5459
first.
5560
"""
5661
external_bases = (
57-
cls for cls in _get_mro(cls) if not cls.__module__.startswith('setuptools')
62+
cast(Type[_T], cls)
63+
for cls in _get_mro(cls)
64+
if not cls.__module__.startswith('setuptools')
5865
)
5966
base = next(external_bases)
6067
if not base.__module__.startswith('distutils'):

tox.ini

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ setenv =
77
SETUPTOOLS_ENFORCE_DEPRECATION = {env:SETUPTOOLS_ENFORCE_DEPRECATION:0}
88
# ^-- Temporarily disable enforcement so CI don't fail on due dates
99
commands =
10+
pyright .
1011
pytest {posargs}
1112
usedevelop = True
1213
extras =

0 commit comments

Comments
 (0)