Skip to content

Commit 1c184fe

Browse files
authored
Simplify Traversable signature (#10934)
Simplify Traversable.open() signature. This is necessary so that implentors can reasonanbly implement this method. For example `zipfile.Path.open()` (which is considered a `Traversable`) only supports this subset. Make `Traversable.__truediv__` and `joinpath` arguments pos-only. The arguments are named differently in both `pathlib.Path` and `zipfile.Path`.
1 parent a08d4c8 commit 1c184fe

File tree

6 files changed

+40
-70
lines changed

6 files changed

+40
-70
lines changed

stdlib/importlib/abc.pyi

Lines changed: 12 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,12 @@
11
import _ast
22
import sys
33
import types
4-
from _typeshed import (
5-
OpenBinaryMode,
6-
OpenBinaryModeReading,
7-
OpenBinaryModeUpdating,
8-
OpenBinaryModeWriting,
9-
OpenTextMode,
10-
ReadableBuffer,
11-
StrPath,
12-
)
4+
from _typeshed import ReadableBuffer, StrPath
135
from abc import ABCMeta, abstractmethod
146
from collections.abc import Iterator, Mapping, Sequence
157
from importlib.machinery import ModuleSpec
16-
from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper
17-
from typing import IO, Any, BinaryIO, Protocol, overload, runtime_checkable
8+
from io import BufferedReader
9+
from typing import IO, Any, Protocol, overload, runtime_checkable
1810
from typing_extensions import Literal
1911

2012
if sys.version_info >= (3, 11):
@@ -139,75 +131,25 @@ if sys.version_info >= (3, 9):
139131
def joinpath(self, *descendants: str) -> Traversable: ...
140132
else:
141133
@abstractmethod
142-
def joinpath(self, child: str) -> Traversable: ...
143-
# The .open method comes from pathlib.pyi and should be kept in sync.
144-
@overload
145-
@abstractmethod
146-
def open(
147-
self,
148-
mode: OpenTextMode = "r",
149-
buffering: int = ...,
150-
encoding: str | None = ...,
151-
errors: str | None = ...,
152-
newline: str | None = ...,
153-
) -> TextIOWrapper: ...
154-
# Unbuffered binary mode: returns a FileIO
155-
@overload
156-
@abstractmethod
157-
def open(
158-
self, mode: OpenBinaryMode, buffering: Literal[0], encoding: None = None, errors: None = None, newline: None = None
159-
) -> FileIO: ...
160-
# Buffering is on: return BufferedRandom, BufferedReader, or BufferedWriter
161-
@overload
162-
@abstractmethod
163-
def open(
164-
self,
165-
mode: OpenBinaryModeUpdating,
166-
buffering: Literal[-1, 1] = ...,
167-
encoding: None = None,
168-
errors: None = None,
169-
newline: None = None,
170-
) -> BufferedRandom: ...
171-
@overload
172-
@abstractmethod
173-
def open(
174-
self,
175-
mode: OpenBinaryModeWriting,
176-
buffering: Literal[-1, 1] = ...,
177-
encoding: None = None,
178-
errors: None = None,
179-
newline: None = None,
180-
) -> BufferedWriter: ...
181-
@overload
182-
@abstractmethod
183-
def open(
184-
self,
185-
mode: OpenBinaryModeReading,
186-
buffering: Literal[-1, 1] = ...,
187-
encoding: None = None,
188-
errors: None = None,
189-
newline: None = None,
190-
) -> BufferedReader: ...
191-
# Buffering cannot be determined: fall back to BinaryIO
134+
def joinpath(self, __child: str) -> Traversable: ...
135+
136+
# The documentation and runtime protocol allows *args, **kwargs arguments,
137+
# but this would mean that all implementors would have to support them,
138+
# which is not the case.
192139
@overload
193140
@abstractmethod
194-
def open(
195-
self, mode: OpenBinaryMode, buffering: int = ..., encoding: None = None, errors: None = None, newline: None = None
196-
) -> BinaryIO: ...
197-
# Fallback if mode is not specified
141+
def open(self, mode: Literal["r", "w"] = "r", *, encoding: str | None = None, errors: str | None = None) -> IO[str]: ...
198142
@overload
199143
@abstractmethod
200-
def open(
201-
self, mode: str, buffering: int = ..., encoding: str | None = ..., errors: str | None = ..., newline: str | None = ...
202-
) -> IO[Any]: ...
144+
def open(self, mode: Literal["rb", "wb"]) -> IO[bytes]: ...
203145
@property
204146
@abstractmethod
205147
def name(self) -> str: ...
206148
if sys.version_info >= (3, 10):
207-
def __truediv__(self, child: str) -> Traversable: ...
149+
def __truediv__(self, __child: str) -> Traversable: ...
208150
else:
209151
@abstractmethod
210-
def __truediv__(self, child: str) -> Traversable: ...
152+
def __truediv__(self, __child: str) -> Traversable: ...
211153

212154
@abstractmethod
213155
def read_bytes(self) -> bytes: ...

test_cases/stdlib/check_importlib.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import importlib.abc
2+
import pathlib
3+
import sys
4+
import zipfile
5+
6+
# Assert that some Path classes are Traversable.
7+
if sys.version_info >= (3, 9):
8+
9+
def traverse(t: importlib.abc.Traversable) -> None:
10+
pass
11+
12+
traverse(pathlib.Path())
13+
traverse(zipfile.Path(""))

tests/stubtest_allowlists/py310.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ typing.ParamSpec(Args|Kwargs).__origin__
152152
# https://github.com/python/mypy/issues/15302
153153
typing.NewType.__call__
154154

155+
# Problematic protocol signatures at runtime, see source code comments.
156+
importlib.abc.Traversable.joinpath
157+
importlib.abc.Traversable.open
158+
155159
# Super-special typing primitives
156160
typing\.NamedTuple
157161
typing\.Annotated

tests/stubtest_allowlists/py311.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ platform.uname_result.processor
107107
unittest.TestCase.__init_subclass__
108108
unittest.case.TestCase.__init_subclass__
109109

110+
# Problematic protocol signature at runtime, see source code comments.
111+
importlib.abc.Traversable.open
112+
importlib.resources.abc.Traversable.open
113+
110114
# Super-special typing primitives
111115
typing\._SpecialForm.*
112116
typing\.NamedTuple

tests/stubtest_allowlists/py312.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ platform.uname_result.processor
9696
unittest.TestCase.__init_subclass__
9797
unittest.case.TestCase.__init_subclass__
9898

99+
# Problematic protocol signature at runtime, see source code comments.
100+
importlib.abc.Traversable.open
101+
importlib.resources.abc.Traversable.open
102+
99103
# Super-special typing primitives
100104
typing\._SpecialForm.*
101105
typing\.NamedTuple

tests/stubtest_allowlists/py39.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ types.MemberDescriptorType.__get__
141141
types.MethodDescriptorType.__get__
142142
types.WrapperDescriptorType.__get__
143143

144+
# Problematic protocol signature at runtime, see source code comments.
145+
importlib.abc.Traversable.open
146+
144147
# Super-special typing primitives
145148
typing\.NamedTuple
146149
typing\.Annotated

0 commit comments

Comments
 (0)