Skip to content

Commit 0ca330b

Browse files
authored
Merge branch 'main' into fix/15619-pyserial-read-all-cannot-return-none
2 parents f8a2358 + 4076e24 commit 0ca330b

888 files changed

Lines changed: 7707 additions & 7036 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.

.github/workflows/daily.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ jobs:
3535
strategy:
3636
matrix:
3737
os: ["ubuntu-latest", "windows-latest", "macos-latest"]
38-
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
38+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
39+
exclude:
40+
# https://github.com/python/typeshed/issues/15694
41+
- os: "windows-latest"
42+
python-version: "3.10"
3943
fail-fast: false
4044

4145
steps:

.github/workflows/mypy_primer.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
runs-on: ubuntu-latest
2323
strategy:
2424
matrix:
25-
shard-index: [0, 1, 2, 3]
25+
shard-index: [0, 1, 2, 3, 4, 5]
2626
fail-fast: false
2727
steps:
2828
- uses: actions/checkout@v6
@@ -52,7 +52,7 @@ jobs:
5252
--new v${MYPY_VERSION} --old v${MYPY_VERSION} \
5353
--custom-typeshed-repo typeshed_to_test \
5454
--new-typeshed $GITHUB_SHA --old-typeshed upstream_main \
55-
--num-shards 4 --shard-index ${{ matrix.shard-index }} \
55+
--num-shards 6 --shard-index ${{ matrix.shard-index }} \
5656
--debug \
5757
--output concise \
5858
| tee diff_${{ matrix.shard-index }}.txt

.github/workflows/stubtest_stdlib.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ jobs:
3131
strategy:
3232
matrix:
3333
os: ["ubuntu-latest", "windows-latest", "macos-latest"]
34-
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
34+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
35+
exclude:
36+
# https://github.com/python/typeshed/issues/15694
37+
- os: "windows-latest"
38+
python-version: "3.10"
3539
fail-fast: false
3640

3741
steps:

.github/workflows/tests.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
strategy:
4343
matrix:
4444
platform: ["linux", "win32", "darwin"]
45-
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
45+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
4646
fail-fast: false
4747
steps:
4848
- uses: actions/checkout@v6
@@ -83,6 +83,8 @@ jobs:
8383
runs-on: ubuntu-latest
8484
strategy:
8585
matrix:
86+
# TODO: Add 3.15 once pyright CI can avoid installing third-party
87+
# runtime dependency stacks that do not support Python 3.15 yet.
8688
python-platform: ["Linux", "Windows", "Darwin"]
8789
python-version: ["3.11", "3.12", "3.13", "3.14"]
8890
fail-fast: false

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ repos:
3636
- id: flake8
3737
language: python
3838
additional_dependencies:
39-
- "flake8-pyi==25.5.0"
39+
- "flake8-pyi==26.5.0"
4040
types: [file]
4141
types_or: [python, pyi]
4242
- repo: meta

CONTRIBUTING.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -366,10 +366,6 @@ Features from the `typing` module that are not present in all
366366
supported Python versions must be imported from `typing_extensions`
367367
instead in typeshed stubs. This currently affects:
368368

369-
- `TypeAlias` (new in Python 3.10)
370-
- `Concatenate` (new in Python 3.10)
371-
- `ParamSpec` (new in Python 3.10)
372-
- `TypeGuard` (new in Python 3.10)
373369
- `Self` (new in Python 3.11)
374370
- `Never` (new in Python 3.11)
375371
- `LiteralString` (new in Python 3.11)

lib/ts_utils/metadata.py

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
from collections.abc import Mapping
1414
from dataclasses import dataclass
1515
from pathlib import Path
16-
from typing import Annotated, Any, Final, NamedTuple, final
17-
from typing_extensions import TypeGuard
16+
from typing import Annotated, Any, Final, NamedTuple, TypeGuard, cast, final
1817

1918
if sys.version_info >= (3, 11):
2019
import tomllib
@@ -239,27 +238,32 @@ def read_metadata(distribution: str) -> StubMetadata:
239238
"""
240239
try:
241240
with metadata_path(distribution).open("rb") as f:
242-
data = tomlkit.load(f)
241+
# This cast is necessary for pyright to understand that the
242+
# variable is a dict with object values. Just using
243+
# `data: dict[str, object] = tomlkit.load(f)` doesn't work because
244+
# pyright still infers TOMLDocument which derives from
245+
# dict[Unknown, Unknown].
246+
data = cast(dict[str, object], tomlkit.load(f))
243247
except FileNotFoundError:
244248
raise NoSuchStubError(f"Typeshed has no stubs for {distribution!r}!") from None
245249

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

249253
assert "version" in data, f"Missing 'version' field in METADATA.toml for {distribution!r}"
250-
version: object = data.get("version") # pyright: ignore[reportUnknownMemberType]
254+
version = data.get("version")
251255
assert isinstance(version, str) and len(version) > 0, f"Invalid 'version' field in METADATA.toml for {distribution!r}"
252256
# Check that the version spec parses
253257
if version[0].isdigit():
254258
version = f"=={version}"
255259
version_spec = Specifier(version)
256260
assert version_spec.operator in {"==", "~="}, f"Invalid 'version' field in METADATA.toml for {distribution!r}"
257261

258-
dependencies_s: object = data.get("dependencies", []) # pyright: ignore[reportUnknownMemberType]
262+
dependencies_s = data.get("dependencies", [])
259263
assert isinstance(dependencies_s, list)
260264
dependencies = [parse_dependencies(distribution, dep) for dep in dependencies_s]
261265

262-
extra_description: object = data.get("extra-description") # pyright: ignore[reportUnknownMemberType]
266+
extra_description = data.get("extra-description")
263267
assert isinstance(extra_description, (str, type(None)))
264268

265269
if "stub-distribution" in data:
@@ -269,7 +273,7 @@ def read_metadata(distribution: str) -> StubMetadata:
269273
else:
270274
stub_distribution = f"types-{distribution}"
271275

272-
upstream_repository: object = data.get("upstream-repository") # pyright: ignore[reportUnknownMemberType]
276+
upstream_repository = data.get("upstream-repository")
273277
assert isinstance(upstream_repository, (str, type(None)))
274278
if isinstance(upstream_repository, str):
275279
parsed_url = urllib.parse.urlsplit(upstream_repository)
@@ -293,7 +297,7 @@ def read_metadata(distribution: str) -> StubMetadata:
293297
)
294298
assert num_url_path_parts == 2, bad_github_url_msg
295299

296-
obsolete_since: object = data.get("obsolete-since") # pyright: ignore[reportUnknownMemberType]
300+
obsolete_since = data.get("obsolete-since")
297301
assert isinstance(obsolete_since, (String, type(None)))
298302
if obsolete_since:
299303
comment = obsolete_since.trivia.comment
@@ -302,13 +306,13 @@ def read_metadata(distribution: str) -> StubMetadata:
302306
obsolete = ObsoleteMetadata(since_version=obsolete_since, since_date=since_date)
303307
else:
304308
obsolete = None
305-
no_longer_updated: object = data.get("no-longer-updated", False) # pyright: ignore[reportUnknownMemberType]
309+
no_longer_updated = data.get("no-longer-updated", False)
306310
assert type(no_longer_updated) is bool
307-
uploaded_to_pypi: object = data.get("upload", True) # pyright: ignore[reportUnknownMemberType]
311+
uploaded_to_pypi = data.get("upload", True)
308312
assert type(uploaded_to_pypi) is bool
309-
partial_stub: object = data.get("partial-stub", True) # pyright: ignore[reportUnknownMemberType]
313+
partial_stub = data.get("partial-stub", True)
310314
assert type(partial_stub) is bool
311-
requires_python_str: object = data.get("requires-python") # pyright: ignore[reportUnknownMemberType]
315+
requires_python_str = data.get("requires-python")
312316
oldest_supported_python = get_oldest_supported_python()
313317
oldest_supported_python_specifier = Specifier(f">={oldest_supported_python}")
314318
if requires_python_str is None:
@@ -324,11 +328,11 @@ def read_metadata(distribution: str) -> StubMetadata:
324328
assert requires_python.operator == ">=", "'requires-python' should be a minimum version specifier, use '>=3.x'"
325329

326330
empty_tools: dict[object, object] = {}
327-
tools_settings: object = data.get("tool", empty_tools) # pyright: ignore[reportUnknownMemberType]
331+
tools_settings = data.get("tool", empty_tools)
328332
assert isinstance(tools_settings, dict)
329333
assert tools_settings.keys() <= _KNOWN_METADATA_TOOL_FIELDS.keys(), f"Unrecognised tool for {distribution!r}"
330334
for tool, tk in _KNOWN_METADATA_TOOL_FIELDS.items():
331-
settings_for_tool: object = tools_settings.get(tool, {}) # pyright: ignore[reportUnknownMemberType]
335+
settings_for_tool = cast(dict[str, object], tools_settings).get(tool, {})
332336
assert isinstance(settings_for_tool, dict)
333337
for key in settings_for_tool:
334338
assert key in tk, f"Unrecognised {tool} key {key!r} for {distribution!r}"
@@ -349,23 +353,28 @@ def read_metadata(distribution: str) -> StubMetadata:
349353
)
350354

351355

352-
def update_metadata(distribution: str, **new_values: object) -> tomlkit.TOMLDocument:
356+
def update_metadata(distribution: str, **new_values: object) -> dict[str, object]:
353357
"""Update a distribution's METADATA.toml.
354358
355359
Return the updated TOML dictionary for use without having to open the file separately.
356360
"""
357361
path = metadata_path(distribution)
358362
try:
359-
with path.open("rb") as file:
360-
data = tomlkit.load(file)
363+
with path.open("rb") as f:
364+
# This cast is necessary for pyright to understand that the
365+
# variable is a dict with object values. Just using
366+
# `data: dict[str, object] = tomlkit.load(f)` doesn't work because
367+
# pyright still infers TOMLDocument which derives from
368+
# dict[Unknown, Unknown].
369+
data = cast(dict[str, object], tomlkit.load(f))
361370
except FileNotFoundError:
362371
raise NoSuchStubError(f"Typeshed has no stubs for {distribution!r}!") from None
363-
data.update(new_values) # pyright: ignore[reportUnknownMemberType] # tomlkit.TOMLDocument.update is partially typed
372+
data.update(new_values)
364373
for key in list(data.keys()):
365-
new_key = key.replace("_", "-") # pyright: ignore[reportUnknownMemberType] # tomlkit.TOMLDocument.keys is partially typed
366-
data[new_key] = data.pop(key) # pyright: ignore[reportUnknownMemberType] # tomlkit.TOMLDocument.pop is partially typed
367-
with path.open("w", encoding="UTF-8") as file:
368-
tomlkit.dump(data, file) # pyright: ignore[reportUnknownMemberType] # tomlkit.dump has partially unknown Mapping type
374+
new_key = key.replace("_", "-")
375+
data[new_key] = data.pop(key)
376+
with path.open("w", encoding="UTF-8") as f:
377+
tomlkit.dump(data, f) # pyright: ignore[reportUnknownMemberType] # tomlkit.dump has partially unknown Mapping type
369378
return data
370379

371380

lib/ts_utils/py315.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""Helpers for Python 3.15 test infrastructure."""
2+
3+
# These stubs require runtime dependencies that do not install cleanly on Python 3.15 yet.
4+
PY315_INCOMPATIBLE_RUNTIME_DEPENDENCIES = {
5+
# Depend on numpy, which does not provide Python 3.15 wheels yet.
6+
"JACK-Client",
7+
"geopandas",
8+
"hnswlib",
9+
"networkx",
10+
"pycocotools",
11+
"resampy",
12+
"shapely",
13+
"tensorflow",
14+
# Depends on referencing, which depends on rpds-py. rpds-py currently uses
15+
# PyO3, which rejects Python 3.15.
16+
"jsonschema",
17+
# Depends on matplotlib, which depends on contourpy. contourpy does not
18+
# provide Python 3.15 wheels yet.
19+
"seaborn",
20+
}

lib/ts_utils/utils.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99
from collections.abc import Iterable, Mapping
1010
from pathlib import Path
1111
from types import MethodType
12-
from typing import TYPE_CHECKING, Any, Final, NamedTuple
13-
from typing_extensions import TypeAlias
12+
from typing import TYPE_CHECKING, Any, Final, NamedTuple, TypeAlias
1413

1514
import pathspec
1615
from packaging.requirements import Requirement
@@ -261,12 +260,12 @@ def close(self: TemporaryFileWrapper[str]) -> None:
261260

262261

263262
@functools.cache
264-
def get_gitignore_spec() -> pathspec.PathSpec:
263+
def get_gitignore_spec() -> pathspec.GitIgnoreSpec:
265264
with GITIGNORE_PATH.open(encoding="UTF-8") as f:
266265
return pathspec.GitIgnoreSpec.from_lines(f)
267266

268267

269-
def spec_matches_path(spec: pathspec.PathSpec, path: Path) -> bool:
268+
def spec_matches_path(spec: pathspec.PathSpec[Any], path: Path) -> bool:
270269
normalized_path = path.as_posix()
271270
if path.is_dir():
272271
normalized_path += "/"

pyproject.toml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ select = [
106106
"PYI044", # `from __future__ import annotations` has no effect in stub files, since type checkers automatically treat stubs as having those semantics
107107
"PYI055", # Multiple `type[T]` usages in a union. Combine them into one, e.g., `type[{union_str}]`.
108108
"PYI058", # Use `{return_type}` as the return value for simple `{method}` methods
109-
# "PYI059", # TODO: Add when dropping Python 3.9 support
109+
"PYI059", # Checks for classes inheriting from typing.Generic[] where Generic[] is not the last base class in the bases tuple
110110
"PYI061", # Use `None` rather than `Literal[None]`
111111
"PYI062", # Duplicate literal member `{}`
112112
"PYI064", # `Final[Literal[{literal}]]` can be replaced with a bare Final
@@ -147,12 +147,6 @@ extend-safe-fixes = [
147147
"UP036", # Remove unnecessary `sys.version_info` blocks
148148
]
149149
ignore = [
150-
###
151-
# TODO: Disabled temporarily, until Python 3.9 support is fully removed in
152-
# May 2026.
153-
###
154-
"UP035", # import from typing
155-
"UP036", # Remove unnecessary `sys.version_info` blocks
156150
###
157151
# Rules that can conflict with the formatter (Black)
158152
# https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
@@ -238,6 +232,7 @@ ignore = [
238232
"D", # pydocstyle
239233
# See comment on black's force-exclude config above
240234
"E501", # Line too long
235+
"UP036", # Remove unnecessary `sys.version_info` blocks
241236
]
242237

243238
[tool.ruff.lint.pydocstyle]

0 commit comments

Comments
 (0)