Skip to content

Commit 211fcb3

Browse files
authored
Merge branch 'main' into etree-iterparse
2 parents 501e25c + 4860c36 commit 211fcb3

807 files changed

Lines changed: 15406 additions & 3941 deletions

File tree

Some content is hidden

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

.flake8

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
[flake8]
22
# Y: Flake8 is only used to run flake8-pyi, everything else is in Ruff
3-
# F821: Typeshed is a testing ground for flake8-pyi, which monkeypatches F821
4-
select = Y, F821
3+
select = Y
54
# Ignore rules normally excluded by default
65
extend-ignore = Y090,Y091
76
per-file-ignores =

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ repos:
1111
args: [--fix=lf]
1212
- id: check-case-conflict
1313
- repo: https://github.com/astral-sh/ruff-pre-commit
14-
rev: v0.11.4 # must match requirements-tests.txt
14+
rev: v0.12.2 # must match requirements-tests.txt
1515
hooks:
1616
- id: ruff
1717
name: Run ruff on stubs, tests and scripts
@@ -31,7 +31,7 @@ repos:
3131
hooks:
3232
- id: black
3333
- repo: https://github.com/pycqa/flake8
34-
rev: 7.2.0
34+
rev: 7.3.0
3535
hooks:
3636
- id: flake8
3737
language: python

CONTRIBUTING.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ Note that some tests require extra setup steps to install the required dependenc
7777
Run the following commands from a Windows terminal to install all requirements:
7878

7979
```powershell
80-
> python -m venv .venv
80+
> py -m venv .venv
8181
> .venv\Scripts\activate
82-
(.venv) > pip install -U pip
82+
(.venv) > python -m pip install -U pip
8383
(.venv) > pip install -r requirements-tests.txt
8484
```
8585

@@ -447,7 +447,7 @@ If a package ships its own `py.typed` file, please follow these steps:
447447

448448
1. Open an issue with the earliest month of removal in the subject.
449449
2. A maintainer will add the
450-
["stubs: removal" label](https://github.com/python/typeshed/labels/stubs%3A%20removal).
450+
["stubs: removal" label](https://github.com/python/typeshed/labels/%22stubs%3A%20removal%22).
451451
3. Open a PR that sets the `obsolete_since` field in the `METADATA.toml`
452452
file to the first version of the package that shipped `py.typed`.
453453
4. After at least six months, open a PR to remove the stubs.
@@ -457,18 +457,19 @@ steps:
457457

458458
1. Open an issue explaining why the stubs should be removed.
459459
2. A maintainer will add the
460-
["stubs: removal" label](https://github.com/python/typeshed/labels/stubs%3A%20removal).
460+
["stubs: removal" label](https://github.com/python/typeshed/labels/%22stubs%3A%20removal%22).
461461
3. Open a PR that sets the `no_longer_updated` field in the `METADATA.toml`
462462
file to `true`.
463463
4. When a new version of the package was automatically uploaded to PyPI
464464
(which can take up to a day), open a PR to remove the stubs.
465465

466-
If feeling kindly, please update [mypy](https://github.com/python/mypy/blob/master/mypy/stubinfo.py)
466+
Don't forget to make sure the library is not in the [`pyrightconfig.stricter.json`](./pyrightconfig.stricter.json)
467+
exclusion list. If feeling kindly, please update [mypy](https://github.com/python/mypy/blob/master/mypy/stubinfo.py)
467468
for any stub obsoletions or removals.
468469

469470
### Marking PRs as "deferred"
470471

471-
We sometimes use the ["status: deferred" label](https://github.com/python/typeshed/labels/status%3A%20deferred)
472+
We sometimes use the ["status: deferred" label](https://github.com/python/typeshed/labels/%22status%3A%20deferred%22)
472473
to mark PRs and issues that we'd like to accept, but that are blocked by some
473474
external factor. Blockers can include:
474475

lib/ts_utils/metadata.py

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from __future__ import annotations
77

8+
import datetime
89
import functools
910
import re
1011
import urllib.parse
@@ -18,6 +19,7 @@
1819
import tomlkit
1920
from packaging.requirements import Requirement
2021
from packaging.specifiers import Specifier
22+
from tomlkit.items import String
2123

2224
from .paths import PYPROJECT_PATH, STUBS_PATH, distribution_path
2325

@@ -26,6 +28,7 @@
2628
"PackageDependencies",
2729
"StubMetadata",
2830
"StubtestSettings",
31+
"get_oldest_supported_python",
2932
"get_recursive_requirements",
3033
"read_dependencies",
3134
"read_metadata",
@@ -139,6 +142,13 @@ def read_stubtest_settings(distribution: str) -> StubtestSettings:
139142
)
140143

141144

145+
@final
146+
@dataclass(frozen=True)
147+
class ObsoleteMetadata:
148+
since_version: Annotated[str, "A string representing a specific version"]
149+
since_date: Annotated[datetime.date, "A date when the package became obsolete"]
150+
151+
142152
@final
143153
@dataclass(frozen=True)
144154
class StubMetadata:
@@ -153,7 +163,7 @@ class StubMetadata:
153163
extra_description: str | None
154164
stub_distribution: Annotated[str, "The name under which the distribution is uploaded to PyPI"]
155165
upstream_repository: Annotated[str, "The URL of the upstream repository"] | None
156-
obsolete_since: Annotated[str, "A string representing a specific version"] | None
166+
obsolete: Annotated[ObsoleteMetadata, "Metadata indicating when the stubs package became obsolete"] | None
157167
no_longer_updated: bool
158168
uploaded_to_pypi: Annotated[bool, "Whether or not a distribution is uploaded to PyPI"]
159169
partial_stub: Annotated[bool, "Whether this is a partial type stub package as per PEP 561."]
@@ -162,7 +172,7 @@ class StubMetadata:
162172

163173
@property
164174
def is_obsolete(self) -> bool:
165-
return self.obsolete_since is not None
175+
return self.obsolete is not None
166176

167177

168178
_KNOWN_METADATA_FIELDS: Final = frozenset(
@@ -213,27 +223,27 @@ def read_metadata(distribution: str) -> StubMetadata:
213223
"""
214224
try:
215225
with metadata_path(distribution).open("rb") as f:
216-
data: dict[str, object] = tomli.load(f)
226+
data = tomlkit.load(f)
217227
except FileNotFoundError:
218228
raise NoSuchStubError(f"Typeshed has no stubs for {distribution!r}!") from None
219229

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

223233
assert "version" in data, f"Missing 'version' field in METADATA.toml for {distribution!r}"
224-
version = data["version"]
234+
version: object = data.get("version") # pyright: ignore[reportUnknownMemberType]
225235
assert isinstance(version, str) and len(version) > 0, f"Invalid 'version' field in METADATA.toml for {distribution!r}"
226236
# Check that the version spec parses
227237
if version[0].isdigit():
228238
version = f"=={version}"
229239
version_spec = Specifier(version)
230240
assert version_spec.operator in {"==", "~="}, f"Invalid 'version' field in METADATA.toml for {distribution!r}"
231241

232-
requires_s: object = data.get("requires", [])
242+
requires_s: object = data.get("requires", []) # pyright: ignore[reportUnknownMemberType]
233243
assert isinstance(requires_s, list)
234244
requires = [parse_requires(distribution, req) for req in requires_s]
235245

236-
extra_description: object = data.get("extra_description")
246+
extra_description: object = data.get("extra_description") # pyright: ignore[reportUnknownMemberType]
237247
assert isinstance(extra_description, (str, type(None)))
238248

239249
if "stub_distribution" in data:
@@ -243,7 +253,7 @@ def read_metadata(distribution: str) -> StubMetadata:
243253
else:
244254
stub_distribution = f"types-{distribution}"
245255

246-
upstream_repository: object = data.get("upstream_repository")
256+
upstream_repository: object = data.get("upstream_repository") # pyright: ignore[reportUnknownMemberType]
247257
assert isinstance(upstream_repository, (str, type(None)))
248258
if isinstance(upstream_repository, str):
249259
parsed_url = urllib.parse.urlsplit(upstream_repository)
@@ -267,21 +277,28 @@ def read_metadata(distribution: str) -> StubMetadata:
267277
)
268278
assert num_url_path_parts == 2, bad_github_url_msg
269279

270-
obsolete_since: object = data.get("obsolete_since")
271-
assert isinstance(obsolete_since, (str, type(None)))
272-
no_longer_updated: object = data.get("no_longer_updated", False)
280+
obsolete_since: object = data.get("obsolete_since") # pyright: ignore[reportUnknownMemberType]
281+
assert isinstance(obsolete_since, (String, type(None)))
282+
if obsolete_since:
283+
comment = obsolete_since.trivia.comment
284+
since_date_string = comment.removeprefix("# Released on ")
285+
since_date = datetime.date.fromisoformat(since_date_string)
286+
obsolete = ObsoleteMetadata(since_version=obsolete_since, since_date=since_date)
287+
else:
288+
obsolete = None
289+
no_longer_updated: object = data.get("no_longer_updated", False) # pyright: ignore[reportUnknownMemberType]
273290
assert type(no_longer_updated) is bool
274-
uploaded_to_pypi: object = data.get("upload", True)
291+
uploaded_to_pypi: object = data.get("upload", True) # pyright: ignore[reportUnknownMemberType]
275292
assert type(uploaded_to_pypi) is bool
276-
partial_stub: object = data.get("partial_stub", True)
293+
partial_stub: object = data.get("partial_stub", True) # pyright: ignore[reportUnknownMemberType]
277294
assert type(partial_stub) is bool
278-
requires_python_str: object = data.get("requires_python")
295+
requires_python_str: object = data.get("requires_python") # pyright: ignore[reportUnknownMemberType]
279296
oldest_supported_python = get_oldest_supported_python()
280297
oldest_supported_python_specifier = Specifier(f">={oldest_supported_python}")
281298
if requires_python_str is None:
282299
requires_python = oldest_supported_python_specifier
283300
else:
284-
assert type(requires_python_str) is str
301+
assert isinstance(requires_python_str, str)
285302
requires_python = Specifier(requires_python_str)
286303
assert requires_python != oldest_supported_python_specifier, f'requires_python="{requires_python}" is redundant'
287304
# Check minimum Python version is not less than the oldest version of Python supported by typeshed
@@ -291,7 +308,7 @@ def read_metadata(distribution: str) -> StubMetadata:
291308
assert requires_python.operator == ">=", "'requires_python' should be a minimum version specifier, use '>=3.x'"
292309

293310
empty_tools: dict[object, object] = {}
294-
tools_settings: object = data.get("tool", empty_tools)
311+
tools_settings: object = data.get("tool", empty_tools) # pyright: ignore[reportUnknownMemberType]
295312
assert isinstance(tools_settings, dict)
296313
assert tools_settings.keys() <= _KNOWN_METADATA_TOOL_FIELDS.keys(), f"Unrecognised tool for {distribution!r}"
297314
for tool, tk in _KNOWN_METADATA_TOOL_FIELDS.items():
@@ -307,7 +324,7 @@ def read_metadata(distribution: str) -> StubMetadata:
307324
extra_description=extra_description,
308325
stub_distribution=stub_distribution,
309326
upstream_repository=upstream_repository,
310-
obsolete_since=obsolete_since,
327+
obsolete=obsolete,
311328
no_longer_updated=no_longer_updated,
312329
uploaded_to_pypi=uploaded_to_pypi,
313330
partial_stub=partial_stub,

lib/ts_utils/paths.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
PYPROJECT_PATH: Final = TS_BASE_PATH / "pyproject.toml"
1313
REQUIREMENTS_PATH: Final = TS_BASE_PATH / "requirements-tests.txt"
1414
GITIGNORE_PATH: Final = TS_BASE_PATH / ".gitignore"
15+
PYRIGHT_CONFIG: Final = TS_BASE_PATH / "pyrightconfig.stricter.json"
1516

1617
TESTS_DIR: Final = "@tests"
1718
TEST_CASES_DIR: Final = "test_cases"

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ ignore = [
159159
# Used for direct, non-subclass type comparison, for example: `type(val) is str`
160160
# see https://github.com/astral-sh/ruff/issues/6465
161161
"E721", # Do not compare types, use `isinstance()`
162+
# Highly opinionated, and it's often necessary to violate it
163+
"PLC0415", # `import` should be at the top-level of a file
162164
# Leave the size and complexity of tests to human interpretation
163165
"PLR09", # Too many ...
164166
# Too many magic number "2" that are preferable inline. https://github.com/astral-sh/ruff/issues/10009

pyrightconfig.stricter.json

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,11 @@
1818
"stdlib/optparse.pyi",
1919
"stdlib/_tkinter.pyi",
2020
"stdlib/tkinter/__init__.pyi",
21-
"stdlib/tkinter/commondialog.pyi",
2221
"stdlib/tkinter/filedialog.pyi",
2322
"stdlib/tkinter/dialog.pyi",
24-
"stdlib/tkinter/messagebox.pyi",
2523
"stdlib/tkinter/scrolledtext.pyi",
2624
"stdlib/tkinter/tix.pyi",
2725
"stdlib/tkinter/ttk.pyi",
28-
"stubs/aiofiles",
2926
"stubs/antlr4-python3-runtime",
3027
"stubs/auth0-python",
3128
"stubs/Authlib",
@@ -34,12 +31,10 @@
3431
"stubs/boltons",
3532
"stubs/braintree",
3633
"stubs/cffi",
37-
"stubs/click-web",
3834
"stubs/dateparser",
3935
"stubs/defusedxml",
4036
"stubs/docker",
4137
"stubs/docutils",
42-
"stubs/flake8-typing-imports",
4338
"stubs/Flask-SocketIO",
4439
"stubs/fpdf2",
4540
"stubs/gdb",
@@ -55,11 +50,10 @@
5550
"stubs/httplib2",
5651
"stubs/hvac",
5752
"stubs/icalendar",
58-
"stubs/jmespath",
5953
"stubs/jsonschema",
6054
"stubs/jwcrypto",
6155
"stubs/ldap3",
62-
"stubs/m3u8",
56+
"stubs/m3u8/m3u8/model.pyi",
6357
"stubs/Markdown",
6458
"stubs/mock/mock/mock.pyi",
6559
"stubs/mysqlclient",
@@ -76,21 +70,18 @@
7670
"stubs/peewee",
7771
"stubs/pexpect",
7872
"stubs/pika",
73+
"stubs/pony",
7974
"stubs/protobuf",
8075
"stubs/psutil",
8176
"stubs/psycopg2",
8277
"stubs/pyasn1",
8378
"stubs/pycurl",
8479
"stubs/Pygments",
8580
"stubs/PyMySQL",
86-
"stubs/python-crontab",
87-
"stubs/python-datemath",
8881
"stubs/python-dateutil",
89-
"stubs/python-http-client",
9082
"stubs/python-jose",
9183
"stubs/pytz/pytz/lazy.pyi",
9284
"stubs/pywin32",
93-
"stubs/pyxdg",
9485
"stubs/PyYAML",
9586
"stubs/reportlab",
9687
"stubs/requests",
@@ -102,7 +93,6 @@
10293
"stubs/tqdm",
10394
"stubs/vobject",
10495
"stubs/workalendar",
105-
"stubs/wurlitzer",
10696
],
10797
"typeCheckingMode": "strict",
10898
// TODO: Complete incomplete stubs

requirements-tests.txt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
# Type checkers that we test our stubs against. These should always
22
# be pinned to a specific version to make failure reproducible.
3-
mypy==1.16.0
4-
pyright==1.1.400
3+
mypy==1.16.1
4+
pyright==1.1.403
55
# pytype can be installed on Windows, but requires building wheels, let's not do that on the CI
66
pytype==2024.10.11; platform_system != "Windows" and python_version >= "3.10" and python_version < "3.13"
77

88
# Libraries used by our various scripts.
99
# TODO (2025-05-09): Installing this on Python 3.14 on Windows fails at
1010
# the moment.
11-
aiohttp==3.11.15; python_version < "3.14"
11+
aiohttp==3.12.14; python_version < "3.14"
1212
# TODO (2025-05-09): No wheels exist for Python 3.14 yet, slowing down CI
1313
# considerably and prone to fail.
1414
grpcio-tools>=1.66.2; python_version < "3.14" # For grpc_tools.protoc
1515
mypy-protobuf==3.6.0
16-
packaging==24.2
16+
packaging==25.0
1717
pathspec>=0.11.1
1818
pre-commit
1919
# Required by create_baseline_stubs.py. Must match .pre-commit-config.yaml.
20-
ruff==0.11.4
20+
ruff==0.12.2
2121
# TODO (2025-05-07): Dependency libcst doesn't support Python 3.14 yet.
2222
stubdefaulter==0.1.0; python_version < "3.14"
2323
termcolor>=2.3
2424
tomli==2.2.1
25-
tomlkit==0.13.2
25+
tomlkit==0.13.3
2626
typing_extensions>=4.14.0rc1
27-
uv==0.7.4
27+
uv==0.7.19
2828

2929
# Utilities for typeshed infrastructure scripts.
3030
ts_utils @ file:lib

scripts/create_baseline_stubs.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@
2323
import aiohttp
2424
import termcolor
2525

26-
from ts_utils.paths import STDLIB_PATH, STUBS_PATH
27-
28-
PYRIGHT_CONFIG = Path("pyrightconfig.stricter.json")
26+
from ts_utils.paths import PYRIGHT_CONFIG, STDLIB_PATH, STUBS_PATH
2927

3028

3129
def search_pip_freeze_output(project: str, output: str) -> tuple[str, str] | None:

0 commit comments

Comments
 (0)