Skip to content

Make SimplePath path parameters positional-only#543

Open
gaborbernat wants to merge 1 commit into
python:mainfrom
gaborbernat:simplepath-positional-only
Open

Make SimplePath path parameters positional-only#543
gaborbernat wants to merge 1 commit into
python:mainfrom
gaborbernat:simplepath-positional-only

Conversation

@gaborbernat

Copy link
Copy Markdown

Fixes #542.

SimplePath names the joinpath and __truediv__ parameter other without marking it positional-only, so the typing spec requires an implementation to accept other=.... Typeshed names the matching pathlib.Path parameters key and *other, so Path fails the protocol under checkers that compare parameter names:

import pathlib

from importlib_metadata import PathDistribution

PathDistribution(pathlib.Path('x'))

ty 0.0.59 explains it:

info: type `Path` is not assignable to protocol `SimplePath`
info: └── protocol member `__truediv__` is incompatible
info:     └── the parameter named `key` does not match `other` (and can be used as a keyword parameter)

pyrefly 1.1.1 reports the same. mypy 2.1.0 accepts it, which is why the docstring's claim that SimplePath is "A minimal subset of pathlib.Path" has held up until now.

Adding / to both members lets Path satisfy the protocol under ty and pyrefly, and leaves mypy passing. I verified all three against importlib_metadata 9.0.0 with the parameters patched, and checked each protocol member against Path in isolation: joinpath and __truediv__ were the only failures.

ruff format, ruff check and mypy pass. tox -e py fails to collect on this branch, but it fails the same way on a pristine main checkout, so that is unrelated.

pypa/build ran into this while moving off mypy (pypa/build#1135).

pathlib.Path does not satisfy SimplePath under ty or pyrefly. The protocol
names the joinpath and __truediv__ parameter `other`, while typeshed names
Path's `key` and `*other`. Neither side is positional-only, so the typing
spec requires the names to match, and they do not.

Marking the parameters positional-only reflects how both members are called
and lets Path satisfy the protocol. mypy passes before and after.

Closes python#542
gaborbernat pushed a commit to gaborbernat/build that referenced this pull request Jul 16, 2026
Check 3.10, the minimum supported version, rather than 3.14. ty prunes
`sys.version_info` branches statically, so 3.14 left the `< (3, 11)` compat
paths in _builder, env and _compat/tomllib unchecked.

Exclude tests/packages, as the mypy config did. Without it ty checks the
fixture packages and fails on legacy/setup.py; CI only passed because its
type job pins 3.10, whose venv still seeds setuptools.

Enable every rule as an error to recover some of what `strict = true` and
`disallow_any_explicit` enforced. ty has no strict mode, so this is the
closest available. `missing-override-decorator` stays off: `@override` needs
typing_extensions before 3.12, and build takes no runtime deps for typing.

Restore `__spec__.parent` in _ctx: `__package__` is deprecated and stops
being set in 3.15, and the other five modules already use `__spec__.parent`.

Point every suppression and workaround at its upstream issue:

- astral-sh/ty#4017 for `__spec__` typed `ModuleSpec | None`
- astral-sh/ty#3962 for the `warnings.showwarning` assignment
- astral-sh/ty#3699 for the recursive TOMLValue alias degrading to Divergent
- python/importlib_metadata#542 for `Path` failing the SimplePath protocol

The SimplePath rejection is not a ty bug: pyrefly rejects it too, and the
protocol's parameters are not positional-only. python/importlib_metadata#543
fixes it upstream.

Add the changelog fragment the PR template requires.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SimplePath rejects pathlib.Path: joinpath and __truediv__ are not positional-only

1 participant