Skip to content

Commit 02b79e9

Browse files
authored
Merge branch 'main' into slice_annotations
2 parents 90154fe + ecb0742 commit 02b79e9

File tree

239 files changed

+10994
-1165
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

239 files changed

+10994
-1165
lines changed

.gitattributes

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,5 @@
44
# Set linguist-language to support comments syntax highlight
55
**/stubtest_allowlist*.txt linguist-language=ini
66
**/stubtest_allowlists/*.txt linguist-language=ini
7-
tests/pytype_exclude_list.txt linguist-language=ini
87
pyrightconfig*.json linguist-language=jsonc
98
.vscode/*.json linguist-language=jsonc

.github/renovate.json5

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@
2424
{
2525
groupName: "most test/lint dependencies",
2626
matchManagers: ["pip_requirements", "pre-commit"],
27-
matchPackageNames: ["!pytype", "!pyright"],
27+
matchPackageNames: ["!pyright"],
2828
description: "Quarterly update of most test dependencies",
2929
schedule: ["every 3 months on the first day of the month"]
3030
},
3131
{
32-
"groupName": "pytype and pyright",
32+
"groupName": "pyright",
3333
"matchManagers": ["pip_requirements"],
34-
"matchPackageNames": ["pytype", "pyright"],
35-
"description": "Daily update of pyright and pytype",
34+
"matchPackageNames": ["pyright"],
35+
"description": "Daily update of pyright",
3636
"schedule": ["before 4am"]
3737
}
3838
]

.github/workflows/daily.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ jobs:
117117
# Keep in sync with stub_uploader's check_scripts.yml workflow.
118118
python-version: "3.13"
119119
- uses: astral-sh/setup-uv@v6
120+
with:
121+
version-file: "typeshed/requirements-tests.txt"
120122
- name: Run tests
121123
run: |
122124
cd stub_uploader

.github/workflows/meta_tests.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,7 @@ jobs:
5353
- uses: actions/checkout@v4
5454
- uses: actions/setup-python@v5
5555
with:
56-
# TODO: Since pytype is not available for Python 3.13, and
57-
# pytype_test.py imports pytype, we need to use Python 3.12 for now.
58-
python-version: "3.12"
56+
python-version: "3.13"
5957
- run: curl -LsSf https://astral.sh/uv/install.sh | sh
6058
- run: uv pip install -r requirements-tests.txt --system
6159
- name: Run pyright on typeshed

.github/workflows/tests.yml

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,27 +34,6 @@ jobs:
3434
- run: uv pip install -r requirements-tests.txt --system
3535
- run: python ./tests/check_typeshed_structure.py
3636

37-
pytype:
38-
name: "pytype: Check stubs"
39-
runs-on: ubuntu-latest
40-
steps:
41-
- uses: actions/checkout@v4
42-
- uses: actions/setup-python@v5
43-
with:
44-
# Max supported Python version as of pytype 2024.10.11
45-
python-version: "3.12"
46-
- uses: astral-sh/setup-uv@v6
47-
- run: uv pip install -r requirements-tests.txt --system
48-
- name: Install external dependencies for 3rd-party stubs
49-
run: |
50-
DEPENDENCIES=$( python tests/get_external_stub_requirements.py )
51-
if [ -n "$DEPENDENCIES" ]; then
52-
printf "Installing packages:\n $(echo $DEPENDENCIES | sed 's/ /\n /g')\n"
53-
uv pip install --system $DEPENDENCIES
54-
fi
55-
- run: uv pip freeze
56-
- run: ./tests/pytype_test.py --print-stderr
57-
5837
mypy:
5938
name: "mypy: Check stubs"
6039
runs-on: ubuntu-latest
@@ -120,6 +99,8 @@ jobs:
12099
with:
121100
python-version: "3.13"
122101
- uses: astral-sh/setup-uv@v6
102+
with:
103+
version-file: "requirements-tests.txt"
123104
- name: Install typeshed test-suite requirements
124105
# Install these so we can run `get_external_stub_requirements.py`
125106
run: uv pip install -r requirements-tests.txt --system
@@ -186,6 +167,8 @@ jobs:
186167
# Keep in sync with stub_uploader's check_scripts.yml workflow.
187168
python-version: "3.13"
188169
- uses: astral-sh/setup-uv@v6
170+
with:
171+
version-file: "typeshed/requirements-tests.txt"
189172
- name: Run tests
190173
run: |
191174
cd stub_uploader

CONTRIBUTING.md

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,6 @@ Note that some tests require extra setup steps to install the required dependenc
8383
(.venv) > pip install -r requirements-tests.txt
8484
```
8585

86-
To be able to run pytype tests, you'll also need to install it manually
87-
as it's currently excluded from the requirements file:
88-
89-
```powershell
90-
(.venv) > pip install -U pytype
91-
```
92-
9386
</td>
9487
</tr>
9588
<tr><!-- disables zebra striping --></tr>
@@ -104,10 +97,6 @@ as it's currently excluded from the requirements file:
10497
uv pip install -r requirements-tests.txt
10598
```
10699

107-
```shell
108-
uv pip install -U pytype
109-
```
110-
111100
</td>
112101
</tr>
113102
</table>

MAINTAINERS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ At present the active maintainers are (alphabetically):
55
* Ivan Levkivskyi (@ilevkivskyi)
66
* Sebastian Rittau (@srittau)
77
* Guido van Rossum (@gvanrossum)
8+
* Brian Schubert (@brianschubert)
89
* Shantanu (@hauntsaninja)
910
* Nikita Sobolev (@sobolevn)
1011
* Samuel Therrien (@Avasam)

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ Typeshed supports Python versions 3.9 to 3.14.
2525

2626
## Using
2727

28-
If you're just using a type checker ([mypy](https://github.com/python/mypy/),
29-
[pyright](https://github.com/microsoft/pyright),
30-
[pytype](https://github.com/google/pytype/), PyCharm, ...), as opposed to
28+
If you're just using a type checker (e.g. [mypy](https://github.com/python/mypy/),
29+
[pyright](https://github.com/microsoft/pyright), or PyCharm's built-in type
30+
checker), as opposed to
3131
developing it, you don't need to interact with the typeshed repo at
3232
all: a copy of standard library part of typeshed is bundled with type checkers.
3333
And type stubs for third party packages and modules you are using can

lib/ts_utils/metadata.py

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,26 @@
55

66
from __future__ import annotations
77

8+
import datetime
89
import functools
910
import re
11+
import sys
1012
import urllib.parse
1113
from collections.abc import Mapping
1214
from dataclasses import dataclass
1315
from pathlib import Path
1416
from typing import Annotated, Any, Final, NamedTuple, final
1517
from typing_extensions import TypeGuard
1618

17-
import tomli
19+
if sys.version_info >= (3, 11):
20+
import tomllib
21+
else:
22+
import tomli as tomllib
23+
1824
import tomlkit
1925
from packaging.requirements import Requirement
2026
from packaging.specifiers import Specifier
27+
from tomlkit.items import String
2128

2229
from .paths import PYPROJECT_PATH, STUBS_PATH, distribution_path
2330

@@ -50,7 +57,7 @@ def _is_nested_dict(obj: object) -> TypeGuard[dict[str, dict[str, Any]]]:
5057
@functools.cache
5158
def get_oldest_supported_python() -> str:
5259
with PYPROJECT_PATH.open("rb") as config:
53-
val = tomli.load(config)["tool"]["typeshed"]["oldest_supported_python"]
60+
val = tomllib.load(config)["tool"]["typeshed"]["oldest_supported_python"]
5461
assert type(val) is str
5562
return val
5663

@@ -90,7 +97,7 @@ def system_requirements_for_platform(self, platform: str) -> list[str]:
9097
def read_stubtest_settings(distribution: str) -> StubtestSettings:
9198
"""Return an object describing the stubtest settings for a single stubs distribution."""
9299
with metadata_path(distribution).open("rb") as f:
93-
data: dict[str, object] = tomli.load(f).get("tool", {}).get("stubtest", {})
100+
data: dict[str, object] = tomllib.load(f).get("tool", {}).get("stubtest", {})
94101

95102
skip: object = data.get("skip", False)
96103
apt_dependencies: object = data.get("apt_dependencies", [])
@@ -140,6 +147,13 @@ def read_stubtest_settings(distribution: str) -> StubtestSettings:
140147
)
141148

142149

150+
@final
151+
@dataclass(frozen=True)
152+
class ObsoleteMetadata:
153+
since_version: Annotated[str, "A string representing a specific version"]
154+
since_date: Annotated[datetime.date, "A date when the package became obsolete"]
155+
156+
143157
@final
144158
@dataclass(frozen=True)
145159
class StubMetadata:
@@ -154,7 +168,7 @@ class StubMetadata:
154168
extra_description: str | None
155169
stub_distribution: Annotated[str, "The name under which the distribution is uploaded to PyPI"]
156170
upstream_repository: Annotated[str, "The URL of the upstream repository"] | None
157-
obsolete_since: Annotated[str, "A string representing a specific version"] | None
171+
obsolete: Annotated[ObsoleteMetadata, "Metadata indicating when the stubs package became obsolete"] | None
158172
no_longer_updated: bool
159173
uploaded_to_pypi: Annotated[bool, "Whether or not a distribution is uploaded to PyPI"]
160174
partial_stub: Annotated[bool, "Whether this is a partial type stub package as per PEP 561."]
@@ -163,7 +177,7 @@ class StubMetadata:
163177

164178
@property
165179
def is_obsolete(self) -> bool:
166-
return self.obsolete_since is not None
180+
return self.obsolete is not None
167181

168182

169183
_KNOWN_METADATA_FIELDS: Final = frozenset(
@@ -214,27 +228,27 @@ def read_metadata(distribution: str) -> StubMetadata:
214228
"""
215229
try:
216230
with metadata_path(distribution).open("rb") as f:
217-
data: dict[str, object] = tomli.load(f)
231+
data = tomlkit.load(f)
218232
except FileNotFoundError:
219233
raise NoSuchStubError(f"Typeshed has no stubs for {distribution!r}!") from None
220234

221235
unknown_metadata_fields = data.keys() - _KNOWN_METADATA_FIELDS
222236
assert not unknown_metadata_fields, f"Unexpected keys in METADATA.toml for {distribution!r}: {unknown_metadata_fields}"
223237

224238
assert "version" in data, f"Missing 'version' field in METADATA.toml for {distribution!r}"
225-
version = data["version"]
239+
version: object = data.get("version") # pyright: ignore[reportUnknownMemberType]
226240
assert isinstance(version, str) and len(version) > 0, f"Invalid 'version' field in METADATA.toml for {distribution!r}"
227241
# Check that the version spec parses
228242
if version[0].isdigit():
229243
version = f"=={version}"
230244
version_spec = Specifier(version)
231245
assert version_spec.operator in {"==", "~="}, f"Invalid 'version' field in METADATA.toml for {distribution!r}"
232246

233-
requires_s: object = data.get("requires", [])
247+
requires_s: object = data.get("requires", []) # pyright: ignore[reportUnknownMemberType]
234248
assert isinstance(requires_s, list)
235249
requires = [parse_requires(distribution, req) for req in requires_s]
236250

237-
extra_description: object = data.get("extra_description")
251+
extra_description: object = data.get("extra_description") # pyright: ignore[reportUnknownMemberType]
238252
assert isinstance(extra_description, (str, type(None)))
239253

240254
if "stub_distribution" in data:
@@ -244,7 +258,7 @@ def read_metadata(distribution: str) -> StubMetadata:
244258
else:
245259
stub_distribution = f"types-{distribution}"
246260

247-
upstream_repository: object = data.get("upstream_repository")
261+
upstream_repository: object = data.get("upstream_repository") # pyright: ignore[reportUnknownMemberType]
248262
assert isinstance(upstream_repository, (str, type(None)))
249263
if isinstance(upstream_repository, str):
250264
parsed_url = urllib.parse.urlsplit(upstream_repository)
@@ -268,21 +282,28 @@ def read_metadata(distribution: str) -> StubMetadata:
268282
)
269283
assert num_url_path_parts == 2, bad_github_url_msg
270284

271-
obsolete_since: object = data.get("obsolete_since")
272-
assert isinstance(obsolete_since, (str, type(None)))
273-
no_longer_updated: object = data.get("no_longer_updated", False)
285+
obsolete_since: object = data.get("obsolete_since") # pyright: ignore[reportUnknownMemberType]
286+
assert isinstance(obsolete_since, (String, type(None)))
287+
if obsolete_since:
288+
comment = obsolete_since.trivia.comment
289+
since_date_string = comment.removeprefix("# Released on ")
290+
since_date = datetime.date.fromisoformat(since_date_string)
291+
obsolete = ObsoleteMetadata(since_version=obsolete_since, since_date=since_date)
292+
else:
293+
obsolete = None
294+
no_longer_updated: object = data.get("no_longer_updated", False) # pyright: ignore[reportUnknownMemberType]
274295
assert type(no_longer_updated) is bool
275-
uploaded_to_pypi: object = data.get("upload", True)
296+
uploaded_to_pypi: object = data.get("upload", True) # pyright: ignore[reportUnknownMemberType]
276297
assert type(uploaded_to_pypi) is bool
277-
partial_stub: object = data.get("partial_stub", True)
298+
partial_stub: object = data.get("partial_stub", True) # pyright: ignore[reportUnknownMemberType]
278299
assert type(partial_stub) is bool
279-
requires_python_str: object = data.get("requires_python")
300+
requires_python_str: object = data.get("requires_python") # pyright: ignore[reportUnknownMemberType]
280301
oldest_supported_python = get_oldest_supported_python()
281302
oldest_supported_python_specifier = Specifier(f">={oldest_supported_python}")
282303
if requires_python_str is None:
283304
requires_python = oldest_supported_python_specifier
284305
else:
285-
assert type(requires_python_str) is str
306+
assert isinstance(requires_python_str, str)
286307
requires_python = Specifier(requires_python_str)
287308
assert requires_python != oldest_supported_python_specifier, f'requires_python="{requires_python}" is redundant'
288309
# Check minimum Python version is not less than the oldest version of Python supported by typeshed
@@ -292,7 +313,7 @@ def read_metadata(distribution: str) -> StubMetadata:
292313
assert requires_python.operator == ">=", "'requires_python' should be a minimum version specifier, use '>=3.x'"
293314

294315
empty_tools: dict[object, object] = {}
295-
tools_settings: object = data.get("tool", empty_tools)
316+
tools_settings: object = data.get("tool", empty_tools) # pyright: ignore[reportUnknownMemberType]
296317
assert isinstance(tools_settings, dict)
297318
assert tools_settings.keys() <= _KNOWN_METADATA_TOOL_FIELDS.keys(), f"Unrecognised tool for {distribution!r}"
298319
for tool, tk in _KNOWN_METADATA_TOOL_FIELDS.items():
@@ -308,7 +329,7 @@ def read_metadata(distribution: str) -> StubMetadata:
308329
extra_description=extra_description,
309330
stub_distribution=stub_distribution,
310331
upstream_repository=upstream_repository,
311-
obsolete_since=obsolete_since,
332+
obsolete=obsolete,
312333
no_longer_updated=no_longer_updated,
313334
uploaded_to_pypi=uploaded_to_pypi,
314335
partial_stub=partial_stub,

lib/ts_utils/mypy.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
from __future__ import annotations
22

3+
import sys
34
from collections.abc import Generator, Iterable
45
from contextlib import contextmanager
56
from typing import Any, NamedTuple
67

7-
import tomli
8+
if sys.version_info >= (3, 11):
9+
import tomllib
10+
else:
11+
import tomli as tomllib
812

913
from ts_utils.metadata import StubtestSettings, metadata_path
1014
from ts_utils.utils import NamedTemporaryFile, TemporaryFileWrapper
@@ -26,7 +30,7 @@ class MypyDistConf(NamedTuple):
2630

2731
def mypy_configuration_from_distribution(distribution: str) -> list[MypyDistConf]:
2832
with metadata_path(distribution).open("rb") as f:
29-
data = tomli.load(f)
33+
data = tomllib.load(f)
3034

3135
# TODO: This could be added to ts_utils.metadata
3236
mypy_tests_conf: dict[str, dict[str, Any]] = data.get("mypy-tests", {})

0 commit comments

Comments
 (0)