Skip to content

Commit 846d922

Browse files
ilai-deutelJelleZijlstrasrittau
authored
More precise return types for open(), Path.open(), bz2.open(), etc. (#3371)
Co-authored-by: Jelle Zijlstra <[email protected]> Co-authored-by: Sebastian Rittau <[email protected]>
1 parent adafaf1 commit 846d922

File tree

9 files changed

+321
-75
lines changed

9 files changed

+321
-75
lines changed

stdlib/2/__builtin__.pyi

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ from typing import (
55
TypeVar, Iterator, Iterable, NoReturn, overload, Container,
66
Sequence, MutableSequence, Mapping, MutableMapping, Tuple, List, Any, Dict, Callable, Generic,
77
Set, AbstractSet, FrozenSet, MutableSet, Sized, Reversible, SupportsInt, SupportsFloat, SupportsAbs,
8-
SupportsComplex, IO, BinaryIO, Union,
8+
SupportsComplex, IO, BinaryIO, TextIO, Union,
99
ItemsView, KeysView, ValuesView, ByteString, Optional, AnyStr, Type, Text,
1010
Protocol,
1111
)
1212
from abc import abstractmethod, ABCMeta
1313
from ast import mod, AST
14+
from io import _OpenBinaryMode, _OpenTextMode
1415
from types import TracebackType, CodeType
1516
import sys
1617

@@ -1357,14 +1358,47 @@ def next(__i: Iterator[_T]) -> _T: ...
13571358
def next(__i: Iterator[_T], default: _VT) -> Union[_T, _VT]: ...
13581359
def oct(__number: Union[int, _SupportsIndex]) -> str: ...
13591360

1360-
if sys.version_info >= (3, 6):
1361-
def open(file: Union[str, bytes, int, _PathLike[Any]], mode: str = ..., buffering: int = ..., encoding: Optional[str] = ...,
1362-
errors: Optional[str] = ..., newline: Optional[str] = ..., closefd: bool = ...,
1363-
opener: Optional[Callable[[str, int], int]] = ...) -> IO[Any]: ...
1364-
elif sys.version_info >= (3,):
1365-
def open(file: Union[str, bytes, int], mode: str = ..., buffering: int = ..., encoding: Optional[str] = ...,
1366-
errors: Optional[str] = ..., newline: Optional[str] = ..., closefd: bool = ...,
1367-
opener: Optional[Callable[[str, int], int]] = ...) -> IO[Any]: ...
1361+
if sys.version_info >= (3,):
1362+
if sys.version_info >= (3, 6):
1363+
# Changed in version 3.6: Support added to accept objects implementing os.PathLike.
1364+
_OpenFile = Union[str, bytes, int, _PathLike[Any]]
1365+
else:
1366+
_OpenFile = Union[str, bytes, int]
1367+
1368+
@overload
1369+
def open(
1370+
file: _OpenFile,
1371+
mode: _OpenTextMode = ...,
1372+
buffering: int = ...,
1373+
encoding: Optional[str] = ...,
1374+
errors: Optional[str] = ...,
1375+
newline: Optional[str] = ...,
1376+
closefd: bool = ...,
1377+
opener: Optional[Callable[[str, int], int]] = ...,
1378+
) -> TextIO: ...
1379+
@overload
1380+
def open(
1381+
file: _OpenFile,
1382+
mode: _OpenBinaryMode,
1383+
buffering: int = ...,
1384+
encoding: None = ...,
1385+
errors: None = ...,
1386+
newline: None = ...,
1387+
closefd: bool = ...,
1388+
opener: Optional[Callable[[str, int], int]] = ...,
1389+
) -> BinaryIO: ...
1390+
@overload
1391+
def open(
1392+
file: _OpenFile,
1393+
mode: str,
1394+
buffering: int = ...,
1395+
encoding: Optional[str] = ...,
1396+
errors: Optional[str] = ...,
1397+
newline: Optional[str] = ...,
1398+
closefd: bool = ...,
1399+
opener: Optional[Callable[[str, int], int]] = ...,
1400+
) -> IO[Any]: ...
1401+
13681402
else:
13691403
def open(name: Union[unicode, int], mode: unicode = ..., buffering: int = ...) -> BinaryIO: ...
13701404

stdlib/2/io.pyi

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# Only a subset of functionality is included.
66

77
from typing import List, BinaryIO, TextIO, IO, overload, Iterator, Iterable, Any, Union, Optional
8+
from typing_extensions import Literal
89
import _io
910

1011
from _io import BlockingIOError as BlockingIOError
@@ -21,6 +22,19 @@ from _io import TextIOWrapper as TextIOWrapper
2122
from _io import UnsupportedOperation as UnsupportedOperation
2223
from _io import open as open
2324

25+
_OpenTextMode = Literal[
26+
'r', 'r+', '+r', 'rt', 'tr', 'rt+', 'r+t', '+rt', 'tr+', 't+r', '+tr',
27+
'w', 'w+', '+w', 'wt', 'tw', 'wt+', 'w+t', '+wt', 'tw+', 't+w', '+tw',
28+
'a', 'a+', '+a', 'at', 'ta', 'at+', 'a+t', '+at', 'ta+', 't+a', '+ta',
29+
'U', 'rU', 'Ur', 'rtU', 'rUt', 'Urt', 'trU', 'tUr', 'Utr',
30+
]
31+
_OpenBinaryMode = Literal[
32+
'rb', 'br', 'rb+', 'r+b', '+rb', 'br+', 'b+r', '+br',
33+
'wb', 'bw', 'wb+', 'w+b', '+wb', 'bw+', 'b+w', '+bw',
34+
'ab', 'ba', 'ab+', 'a+b', '+ab', 'ba+', 'b+a', '+ba',
35+
'rbU', 'rUb', 'Urb', 'brU', 'bUr', 'Ubr',
36+
]
37+
2438
def _OpenWrapper(file: Union[str, unicode, int],
2539
mode: unicode = ..., buffering: int = ..., encoding: unicode = ...,
2640
errors: unicode = ..., newline: unicode = ...,

stdlib/2and3/builtins.pyi

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ from typing import (
55
TypeVar, Iterator, Iterable, NoReturn, overload, Container,
66
Sequence, MutableSequence, Mapping, MutableMapping, Tuple, List, Any, Dict, Callable, Generic,
77
Set, AbstractSet, FrozenSet, MutableSet, Sized, Reversible, SupportsInt, SupportsFloat, SupportsAbs,
8-
SupportsComplex, IO, BinaryIO, Union,
8+
SupportsComplex, IO, BinaryIO, TextIO, Union,
99
ItemsView, KeysView, ValuesView, ByteString, Optional, AnyStr, Type, Text,
1010
Protocol,
1111
)
1212
from abc import abstractmethod, ABCMeta
1313
from ast import mod, AST
14+
from io import _OpenBinaryMode, _OpenTextMode
1415
from types import TracebackType, CodeType
1516
import sys
1617

@@ -1357,14 +1358,47 @@ def next(__i: Iterator[_T]) -> _T: ...
13571358
def next(__i: Iterator[_T], default: _VT) -> Union[_T, _VT]: ...
13581359
def oct(__number: Union[int, _SupportsIndex]) -> str: ...
13591360

1360-
if sys.version_info >= (3, 6):
1361-
def open(file: Union[str, bytes, int, _PathLike[Any]], mode: str = ..., buffering: int = ..., encoding: Optional[str] = ...,
1362-
errors: Optional[str] = ..., newline: Optional[str] = ..., closefd: bool = ...,
1363-
opener: Optional[Callable[[str, int], int]] = ...) -> IO[Any]: ...
1364-
elif sys.version_info >= (3,):
1365-
def open(file: Union[str, bytes, int], mode: str = ..., buffering: int = ..., encoding: Optional[str] = ...,
1366-
errors: Optional[str] = ..., newline: Optional[str] = ..., closefd: bool = ...,
1367-
opener: Optional[Callable[[str, int], int]] = ...) -> IO[Any]: ...
1361+
if sys.version_info >= (3,):
1362+
if sys.version_info >= (3, 6):
1363+
# Changed in version 3.6: Support added to accept objects implementing os.PathLike.
1364+
_OpenFile = Union[str, bytes, int, _PathLike[Any]]
1365+
else:
1366+
_OpenFile = Union[str, bytes, int]
1367+
1368+
@overload
1369+
def open(
1370+
file: _OpenFile,
1371+
mode: _OpenTextMode = ...,
1372+
buffering: int = ...,
1373+
encoding: Optional[str] = ...,
1374+
errors: Optional[str] = ...,
1375+
newline: Optional[str] = ...,
1376+
closefd: bool = ...,
1377+
opener: Optional[Callable[[str, int], int]] = ...,
1378+
) -> TextIO: ...
1379+
@overload
1380+
def open(
1381+
file: _OpenFile,
1382+
mode: _OpenBinaryMode,
1383+
buffering: int = ...,
1384+
encoding: None = ...,
1385+
errors: None = ...,
1386+
newline: None = ...,
1387+
closefd: bool = ...,
1388+
opener: Optional[Callable[[str, int], int]] = ...,
1389+
) -> BinaryIO: ...
1390+
@overload
1391+
def open(
1392+
file: _OpenFile,
1393+
mode: str,
1394+
buffering: int = ...,
1395+
encoding: Optional[str] = ...,
1396+
errors: Optional[str] = ...,
1397+
newline: Optional[str] = ...,
1398+
closefd: bool = ...,
1399+
opener: Optional[Callable[[str, int], int]] = ...,
1400+
) -> IO[Any]: ...
1401+
13681402
else:
13691403
def open(name: Union[unicode, int], mode: unicode = ..., buffering: int = ...) -> BinaryIO: ...
13701404

stdlib/2and3/bz2.pyi

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,48 @@
11
import io
22
import sys
3-
from typing import Any, IO, Optional, Union
3+
from os.path import _PathType
4+
from typing import IO, Any, Optional, TextIO, Union, overload
45

5-
if sys.version_info >= (3, 6):
6-
from os import PathLike
7-
_PathOrFile = Union[str, bytes, IO[Any], PathLike[Any]]
8-
elif sys.version_info >= (3, 3):
9-
_PathOrFile = Union[str, bytes, IO[Any]]
6+
if sys.version_info >= (3, 8):
7+
from typing import Literal
108
else:
11-
_PathOrFile = str
9+
from typing_extensions import Literal
10+
11+
_PathOrFile = Union[_PathType, IO[bytes]]
1212

1313
def compress(data: bytes, compresslevel: int = ...) -> bytes: ...
1414
def decompress(data: bytes) -> bytes: ...
1515

1616
if sys.version_info >= (3, 3):
17-
def open(filename: _PathOrFile,
18-
mode: str = ...,
19-
compresslevel: int = ...,
20-
encoding: Optional[str] = ...,
21-
errors: Optional[str] = ...,
22-
newline: Optional[str] = ...) -> IO[Any]: ...
17+
_OpenBinaryMode = Literal["r", "rb", "w", "wb", "x", "xb", "a", "ab"]
18+
_OpenTextMode = Literal["rt", "wt", "xt", "at"]
19+
@overload
20+
def open(
21+
filename: _PathOrFile,
22+
mode: _OpenBinaryMode = ...,
23+
compresslevel: int = ...,
24+
encoding: None = ...,
25+
errors: None = ...,
26+
newline: None = ...,
27+
) -> BZ2File: ...
28+
@overload
29+
def open(
30+
filename: _PathType,
31+
mode: _OpenTextMode,
32+
compresslevel: int = ...,
33+
encoding: Optional[str] = ...,
34+
errors: Optional[str] = ...,
35+
newline: Optional[str] = ...,
36+
) -> TextIO: ...
37+
@overload
38+
def open(
39+
filename: _PathOrFile,
40+
mode: str,
41+
compresslevel: int = ...,
42+
encoding: Optional[str] = ...,
43+
errors: Optional[str] = ...,
44+
newline: Optional[str] = ...,
45+
) -> Union[BZ2File, TextIO]: ...
2346

2447
class BZ2File(io.BufferedIOBase, IO[bytes]): # type: ignore # python/mypy#5027
2548
if sys.version_info >= (3, 9):

stdlib/3/gzip.pyi

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,45 @@
1-
from typing import Any, IO, Optional
2-
from os.path import _PathType
3-
import _compression
41
import sys
52
import zlib
3+
from os.path import _PathType
4+
from typing import IO, Optional, TextIO, Union, overload
65

7-
def open(filename, mode: str = ..., compresslevel: int = ..., encoding: Optional[str] = ..., errors: Optional[str] = ..., newline: Optional[str] = ...) -> IO[Any]: ...
6+
import _compression
7+
8+
if sys.version_info >= (3, 8):
9+
from typing import Literal
10+
else:
11+
from typing_extensions import Literal
12+
13+
_OpenBinaryMode = Literal["r", "rb", "a", "ab", "w", "wb", "x", "xb"]
14+
_OpenTextMode = Literal["rt", "at", "wt", "xt"]
15+
16+
@overload
17+
def open(
18+
filename: Union[_PathType, IO[bytes]],
19+
mode: _OpenBinaryMode = ...,
20+
compresslevel: int = ...,
21+
encoding: None = ...,
22+
errors: None = ...,
23+
newline: None = ...,
24+
) -> GzipFile: ...
25+
@overload
26+
def open(
27+
filename: _PathType,
28+
mode: _OpenTextMode,
29+
compresslevel: int = ...,
30+
encoding: Optional[str] = ...,
31+
errors: Optional[str] = ...,
32+
newline: Optional[str] = ...,
33+
) -> TextIO: ...
34+
@overload
35+
def open(
36+
filename: Union[_PathType, IO[bytes]],
37+
mode: str,
38+
compresslevel: int = ...,
39+
encoding: Optional[str] = ...,
40+
errors: Optional[str] = ...,
41+
newline: Optional[str] = ...,
42+
) -> Union[GzipFile, TextIO]: ...
843

944
class _PaddedFile:
1045
file: IO[bytes]
@@ -20,7 +55,14 @@ class GzipFile(_compression.BaseStream):
2055
name: str
2156
compress: zlib._Compress
2257
fileobj: IO[bytes]
23-
def __init__(self, filename: Optional[_PathType] = ..., mode: Optional[str] = ..., compresslevel: int = ..., fileobj: Optional[IO[bytes]] = ..., mtime: Optional[float] = ...) -> None: ...
58+
def __init__(
59+
self,
60+
filename: Optional[_PathType] = ...,
61+
mode: Optional[str] = ...,
62+
compresslevel: int = ...,
63+
fileobj: Optional[IO[bytes]] = ...,
64+
mtime: Optional[float] = ...,
65+
) -> None: ...
2466
@property
2567
def filename(self) -> str: ...
2668
@property
@@ -48,6 +90,8 @@ class _GzipReader(_compression.DecompressReader):
4890

4991
if sys.version_info >= (3, 8):
5092
def compress(data, compresslevel: int = ..., *, mtime: Optional[float] = ...) -> bytes: ...
93+
5194
else:
5295
def compress(data, compresslevel: int = ...) -> bytes: ...
96+
5397
def decompress(data: bytes) -> bytes: ...

stdlib/3/io.pyi

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ from mmap import mmap
88
from types import TracebackType
99
from typing import TypeVar
1010

11+
if sys.version_info >= (3, 8):
12+
from typing import Literal
13+
else:
14+
from typing_extensions import Literal
15+
1116
_bytearray_like = Union[bytearray, mmap]
1217

1318
DEFAULT_BUFFER_SIZE: int
@@ -18,6 +23,21 @@ SEEK_END: int
1823

1924
_T = TypeVar('_T', bound=IOBase)
2025

26+
_OpenTextMode = Literal[
27+
'r', 'r+', '+r', 'rt', 'tr', 'rt+', 'r+t', '+rt', 'tr+', 't+r', '+tr',
28+
'w', 'w+', '+w', 'wt', 'tw', 'wt+', 'w+t', '+wt', 'tw+', 't+w', '+tw',
29+
'a', 'a+', '+a', 'at', 'ta', 'at+', 'a+t', '+at', 'ta+', 't+a', '+ta',
30+
'x', 'x+', '+x', 'xt', 'tx', 'xt+', 'x+t', '+xt', 'tx+', 't+x', '+tx',
31+
'U', 'rU', 'Ur', 'rtU', 'rUt', 'Urt', 'trU', 'tUr', 'Utr',
32+
]
33+
_OpenBinaryMode = Literal[
34+
'rb', 'br', 'rb+', 'r+b', '+rb', 'br+', 'b+r', '+br',
35+
'wb', 'bw', 'wb+', 'w+b', '+wb', 'bw+', 'b+w', '+bw',
36+
'ab', 'ba', 'ab+', 'a+b', '+ab', 'ba+', 'b+a', '+ba',
37+
'xb', 'bx', 'xb+', 'x+b', '+xb', 'bx+', 'b+x', '+bx',
38+
'rbU', 'rUb', 'Urb', 'brU', 'bUr', 'Ubr',
39+
]
40+
2141
open = builtins.open
2242

2343
if sys.version_info >= (3, 8):

0 commit comments

Comments
 (0)