diff --git a/stdlib/2/__builtin__.pyi b/stdlib/2/__builtin__.pyi
index 044819e0fcb7..7ea3c246bb68 100644
--- a/stdlib/2/__builtin__.pyi
+++ b/stdlib/2/__builtin__.pyi
@@ -5,12 +5,13 @@ from typing import (
     TypeVar, Iterator, Iterable, NoReturn, overload, Container,
     Sequence, MutableSequence, Mapping, MutableMapping, Tuple, List, Any, Dict, Callable, Generic,
     Set, AbstractSet, FrozenSet, MutableSet, Sized, Reversible, SupportsInt, SupportsFloat, SupportsAbs,
-    SupportsComplex, IO, BinaryIO, Union,
+    SupportsComplex, IO, BinaryIO, TextIO, Union,
     ItemsView, KeysView, ValuesView, ByteString, Optional, AnyStr, Type, Text,
     Protocol,
 )
 from abc import abstractmethod, ABCMeta
 from ast import mod, AST
+from io import _OpenBinaryMode, _OpenTextMode
 from types import TracebackType, CodeType
 import sys
 
@@ -1354,14 +1355,47 @@ def next(__i: Iterator[_T]) -> _T: ...
 def next(__i: Iterator[_T], default: _VT) -> Union[_T, _VT]: ...
 def oct(__number: Union[int, _SupportsIndex]) -> str: ...
 
-if sys.version_info >= (3, 6):
-    def open(file: Union[str, bytes, int, _PathLike[Any]], mode: str = ..., buffering: int = ..., encoding: Optional[str] = ...,
-             errors: Optional[str] = ..., newline: Optional[str] = ..., closefd: bool = ...,
-             opener: Optional[Callable[[str, int], int]] = ...) -> IO[Any]: ...
-elif sys.version_info >= (3,):
-    def open(file: Union[str, bytes, int], mode: str = ..., buffering: int = ..., encoding: Optional[str] = ...,
-             errors: Optional[str] = ..., newline: Optional[str] = ..., closefd: bool = ...,
-             opener: Optional[Callable[[str, int], int]] = ...) -> IO[Any]: ...
+if sys.version_info >= (3,):
+    if sys.version_info >= (3, 6):
+        # Changed in version 3.6: Support added to accept objects implementing os.PathLike.
+        _OpenFile = Union[str, bytes, int, _PathLike[Any]]
+    else:
+        _OpenFile = Union[str, bytes, int]
+
+    @overload
+    def open(
+        file: _OpenFile,
+        mode: _OpenTextMode = ...,
+        buffering: int = ...,
+        encoding: Optional[str] = ...,
+        errors: Optional[str] = ...,
+        newline: Optional[str] = ...,
+        closefd: bool = ...,
+        opener: Optional[Callable[[str, int], int]] = ...,
+    ) -> TextIO: ...
+    @overload
+    def open(
+        file: _OpenFile,
+        mode: _OpenBinaryMode,
+        buffering: int = ...,
+        encoding: None = ...,
+        errors: None = ...,
+        newline: None = ...,
+        closefd: bool = ...,
+        opener: Optional[Callable[[str, int], int]] = ...,
+    ) -> BinaryIO: ...
+    @overload
+    def open(
+        file: _OpenFile,
+        mode: str,
+        buffering: int = ...,
+        encoding: Optional[str] = ...,
+        errors: Optional[str] = ...,
+        newline: Optional[str] = ...,
+        closefd: bool = ...,
+        opener: Optional[Callable[[str, int], int]] = ...,
+    ) -> IO[Any]: ...
+
 else:
     def open(name: Union[unicode, int], mode: unicode = ..., buffering: int = ...) -> BinaryIO: ...
 
diff --git a/stdlib/2/io.pyi b/stdlib/2/io.pyi
index 1ab6b9069505..0626df42778f 100644
--- a/stdlib/2/io.pyi
+++ b/stdlib/2/io.pyi
@@ -5,6 +5,7 @@
 # Only a subset of functionality is included.
 
 from typing import List, BinaryIO, TextIO, IO, overload, Iterator, Iterable, Any, Union, Optional
+from typing_extensions import Literal
 import _io
 
 from _io import BlockingIOError as BlockingIOError
@@ -21,6 +22,19 @@ from _io import TextIOWrapper as TextIOWrapper
 from _io import UnsupportedOperation as UnsupportedOperation
 from _io import open as open
 
+_OpenTextMode = Literal[
+    'r', 'r+', '+r', 'rt', 'tr', 'rt+', 'r+t', '+rt', 'tr+', 't+r', '+tr',
+    'w', 'w+', '+w', 'wt', 'tw', 'wt+', 'w+t', '+wt', 'tw+', 't+w', '+tw',
+    'a', 'a+', '+a', 'at', 'ta', 'at+', 'a+t', '+at', 'ta+', 't+a', '+ta',
+    'U', 'rU', 'Ur', 'rtU', 'rUt', 'Urt', 'trU', 'tUr', 'Utr',
+]
+_OpenBinaryMode = Literal[
+    'rb', 'br', 'rb+', 'r+b', '+rb', 'br+', 'b+r', '+br',
+    'wb', 'bw', 'wb+', 'w+b', '+wb', 'bw+', 'b+w', '+bw',
+    'ab', 'ba', 'ab+', 'a+b', '+ab', 'ba+', 'b+a', '+ba',
+    'rbU', 'rUb', 'Urb', 'brU', 'bUr', 'Ubr',
+]
+
 def _OpenWrapper(file: Union[str, unicode, int],
                  mode: unicode = ..., buffering: int = ..., encoding: unicode = ...,
                  errors: unicode = ..., newline: unicode = ...,
diff --git a/stdlib/2and3/builtins.pyi b/stdlib/2and3/builtins.pyi
index 044819e0fcb7..7ea3c246bb68 100644
--- a/stdlib/2and3/builtins.pyi
+++ b/stdlib/2and3/builtins.pyi
@@ -5,12 +5,13 @@ from typing import (
     TypeVar, Iterator, Iterable, NoReturn, overload, Container,
     Sequence, MutableSequence, Mapping, MutableMapping, Tuple, List, Any, Dict, Callable, Generic,
     Set, AbstractSet, FrozenSet, MutableSet, Sized, Reversible, SupportsInt, SupportsFloat, SupportsAbs,
-    SupportsComplex, IO, BinaryIO, Union,
+    SupportsComplex, IO, BinaryIO, TextIO, Union,
     ItemsView, KeysView, ValuesView, ByteString, Optional, AnyStr, Type, Text,
     Protocol,
 )
 from abc import abstractmethod, ABCMeta
 from ast import mod, AST
+from io import _OpenBinaryMode, _OpenTextMode
 from types import TracebackType, CodeType
 import sys
 
@@ -1354,14 +1355,47 @@ def next(__i: Iterator[_T]) -> _T: ...
 def next(__i: Iterator[_T], default: _VT) -> Union[_T, _VT]: ...
 def oct(__number: Union[int, _SupportsIndex]) -> str: ...
 
-if sys.version_info >= (3, 6):
-    def open(file: Union[str, bytes, int, _PathLike[Any]], mode: str = ..., buffering: int = ..., encoding: Optional[str] = ...,
-             errors: Optional[str] = ..., newline: Optional[str] = ..., closefd: bool = ...,
-             opener: Optional[Callable[[str, int], int]] = ...) -> IO[Any]: ...
-elif sys.version_info >= (3,):
-    def open(file: Union[str, bytes, int], mode: str = ..., buffering: int = ..., encoding: Optional[str] = ...,
-             errors: Optional[str] = ..., newline: Optional[str] = ..., closefd: bool = ...,
-             opener: Optional[Callable[[str, int], int]] = ...) -> IO[Any]: ...
+if sys.version_info >= (3,):
+    if sys.version_info >= (3, 6):
+        # Changed in version 3.6: Support added to accept objects implementing os.PathLike.
+        _OpenFile = Union[str, bytes, int, _PathLike[Any]]
+    else:
+        _OpenFile = Union[str, bytes, int]
+
+    @overload
+    def open(
+        file: _OpenFile,
+        mode: _OpenTextMode = ...,
+        buffering: int = ...,
+        encoding: Optional[str] = ...,
+        errors: Optional[str] = ...,
+        newline: Optional[str] = ...,
+        closefd: bool = ...,
+        opener: Optional[Callable[[str, int], int]] = ...,
+    ) -> TextIO: ...
+    @overload
+    def open(
+        file: _OpenFile,
+        mode: _OpenBinaryMode,
+        buffering: int = ...,
+        encoding: None = ...,
+        errors: None = ...,
+        newline: None = ...,
+        closefd: bool = ...,
+        opener: Optional[Callable[[str, int], int]] = ...,
+    ) -> BinaryIO: ...
+    @overload
+    def open(
+        file: _OpenFile,
+        mode: str,
+        buffering: int = ...,
+        encoding: Optional[str] = ...,
+        errors: Optional[str] = ...,
+        newline: Optional[str] = ...,
+        closefd: bool = ...,
+        opener: Optional[Callable[[str, int], int]] = ...,
+    ) -> IO[Any]: ...
+
 else:
     def open(name: Union[unicode, int], mode: unicode = ..., buffering: int = ...) -> BinaryIO: ...
 
diff --git a/stdlib/2and3/bz2.pyi b/stdlib/2and3/bz2.pyi
index 4738ec85ea8b..77658a793482 100644
--- a/stdlib/2and3/bz2.pyi
+++ b/stdlib/2and3/bz2.pyi
@@ -1,25 +1,48 @@
 import io
 import sys
-from typing import Any, IO, Optional, Union
+from os.path import _PathType
+from typing import IO, Any, Optional, TextIO, Union, overload
 
-if sys.version_info >= (3, 6):
-    from os import PathLike
-    _PathOrFile = Union[str, bytes, IO[Any], PathLike[Any]]
-elif sys.version_info >= (3, 3):
-    _PathOrFile = Union[str, bytes, IO[Any]]
+if sys.version_info >= (3, 8):
+    from typing import Literal
 else:
-    _PathOrFile = str
+    from typing_extensions import Literal
+
+_PathOrFile = Union[_PathType, IO[bytes]]
 
 def compress(data: bytes, compresslevel: int = ...) -> bytes: ...
 def decompress(data: bytes) -> bytes: ...
 
 if sys.version_info >= (3, 3):
-    def open(filename: _PathOrFile,
-             mode: str = ...,
-             compresslevel: int = ...,
-             encoding: Optional[str] = ...,
-             errors: Optional[str] = ...,
-             newline: Optional[str] = ...) -> IO[Any]: ...
+    _OpenBinaryMode = Literal["r", "rb", "w", "wb", "x", "xb", "a", "ab"]
+    _OpenTextMode = Literal["rt", "wt", "xt", "at"]
+    @overload
+    def open(
+        filename: _PathOrFile,
+        mode: _OpenBinaryMode = ...,
+        compresslevel: int = ...,
+        encoding: None = ...,
+        errors: None = ...,
+        newline: None = ...,
+    ) -> BZ2File: ...
+    @overload
+    def open(
+        filename: _PathType,
+        mode: _OpenTextMode,
+        compresslevel: int = ...,
+        encoding: Optional[str] = ...,
+        errors: Optional[str] = ...,
+        newline: Optional[str] = ...,
+    ) -> TextIO: ...
+    @overload
+    def open(
+        filename: _PathOrFile,
+        mode: str,
+        compresslevel: int = ...,
+        encoding: Optional[str] = ...,
+        errors: Optional[str] = ...,
+        newline: Optional[str] = ...,
+    ) -> Union[BZ2File, TextIO]: ...
 
 class BZ2File(io.BufferedIOBase, IO[bytes]):  # type: ignore  # python/mypy#5027
     if sys.version_info >= (3, 9):
diff --git a/stdlib/3/gzip.pyi b/stdlib/3/gzip.pyi
index ce8152c34f09..9357a71a2de9 100644
--- a/stdlib/3/gzip.pyi
+++ b/stdlib/3/gzip.pyi
@@ -1,10 +1,45 @@
-from typing import Any, IO, Optional
-from os.path import _PathType
-import _compression
 import sys
 import zlib
+from os.path import _PathType
+from typing import IO, Optional, TextIO, Union, overload
 
-def open(filename, mode: str = ..., compresslevel: int = ..., encoding: Optional[str] = ..., errors: Optional[str] = ..., newline: Optional[str] = ...) -> IO[Any]: ...
+import _compression
+
+if sys.version_info >= (3, 8):
+    from typing import Literal
+else:
+    from typing_extensions import Literal
+
+_OpenBinaryMode = Literal["r", "rb", "a", "ab", "w", "wb", "x", "xb"]
+_OpenTextMode = Literal["rt", "at", "wt", "xt"]
+
+@overload
+def open(
+    filename: Union[_PathType, IO[bytes]],
+    mode: _OpenBinaryMode = ...,
+    compresslevel: int = ...,
+    encoding: None = ...,
+    errors: None = ...,
+    newline: None = ...,
+) -> GzipFile: ...
+@overload
+def open(
+    filename: _PathType,
+    mode: _OpenTextMode,
+    compresslevel: int = ...,
+    encoding: Optional[str] = ...,
+    errors: Optional[str] = ...,
+    newline: Optional[str] = ...,
+) -> TextIO: ...
+@overload
+def open(
+    filename: Union[_PathType, IO[bytes]],
+    mode: str,
+    compresslevel: int = ...,
+    encoding: Optional[str] = ...,
+    errors: Optional[str] = ...,
+    newline: Optional[str] = ...,
+) -> Union[GzipFile, TextIO]: ...
 
 class _PaddedFile:
     file: IO[bytes]
@@ -20,7 +55,14 @@ class GzipFile(_compression.BaseStream):
     name: str
     compress: zlib._Compress
     fileobj: IO[bytes]
-    def __init__(self, filename: Optional[_PathType] = ..., mode: Optional[str] = ..., compresslevel: int = ..., fileobj: Optional[IO[bytes]] = ..., mtime: Optional[float] = ...) -> None: ...
+    def __init__(
+        self,
+        filename: Optional[_PathType] = ...,
+        mode: Optional[str] = ...,
+        compresslevel: int = ...,
+        fileobj: Optional[IO[bytes]] = ...,
+        mtime: Optional[float] = ...,
+    ) -> None: ...
     @property
     def filename(self) -> str: ...
     @property
@@ -48,6 +90,8 @@ class _GzipReader(_compression.DecompressReader):
 
 if sys.version_info >= (3, 8):
     def compress(data, compresslevel: int = ..., *, mtime: Optional[float] = ...) -> bytes: ...
+
 else:
     def compress(data, compresslevel: int = ...) -> bytes: ...
+
 def decompress(data: bytes) -> bytes: ...
diff --git a/stdlib/3/io.pyi b/stdlib/3/io.pyi
index 47fb0d2b6849..6d590939a2ca 100644
--- a/stdlib/3/io.pyi
+++ b/stdlib/3/io.pyi
@@ -8,6 +8,11 @@ from mmap import mmap
 from types import TracebackType
 from typing import TypeVar
 
+if sys.version_info >= (3, 8):
+    from typing import Literal
+else:
+    from typing_extensions import Literal
+
 _bytearray_like = Union[bytearray, mmap]
 
 DEFAULT_BUFFER_SIZE: int
@@ -18,6 +23,21 @@ SEEK_END: int
 
 _T = TypeVar('_T', bound=IOBase)
 
+_OpenTextMode = Literal[
+    'r', 'r+', '+r', 'rt', 'tr', 'rt+', 'r+t', '+rt', 'tr+', 't+r', '+tr',
+    'w', 'w+', '+w', 'wt', 'tw', 'wt+', 'w+t', '+wt', 'tw+', 't+w', '+tw',
+    'a', 'a+', '+a', 'at', 'ta', 'at+', 'a+t', '+at', 'ta+', 't+a', '+ta',
+    'x', 'x+', '+x', 'xt', 'tx', 'xt+', 'x+t', '+xt', 'tx+', 't+x', '+tx',
+    'U', 'rU', 'Ur', 'rtU', 'rUt', 'Urt', 'trU', 'tUr', 'Utr',
+]
+_OpenBinaryMode = Literal[
+    'rb', 'br', 'rb+', 'r+b', '+rb', 'br+', 'b+r', '+br',
+    'wb', 'bw', 'wb+', 'w+b', '+wb', 'bw+', 'b+w', '+bw',
+    'ab', 'ba', 'ab+', 'a+b', '+ab', 'ba+', 'b+a', '+ba',
+    'xb', 'bx', 'xb+', 'x+b', '+xb', 'bx+', 'b+x', '+bx',
+    'rbU', 'rUb', 'Urb', 'brU', 'bUr', 'Ubr',
+]
+
 open = builtins.open
 
 if sys.version_info >= (3, 8):
diff --git a/stdlib/3/lzma.pyi b/stdlib/3/lzma.pyi
index 37009c813cee..f192c43628b8 100644
--- a/stdlib/3/lzma.pyi
+++ b/stdlib/3/lzma.pyi
@@ -1,12 +1,17 @@
 import io
 import sys
-from typing import Any, IO, Mapping, Optional, Sequence, Union
+from os.path import _PathType
+from typing import IO, Any, Mapping, Optional, Sequence, TextIO, Union, overload
 
-if sys.version_info >= (3, 6):
-    from os import PathLike
-    _PathOrFile = Union[str, bytes, IO[Any], PathLike[Any]]
+if sys.version_info >= (3, 8):
+    from typing import Literal
 else:
-    _PathOrFile = Union[str, bytes, IO[Any]]
+    from typing_extensions import Literal
+
+_OpenBinaryWritingMode = Literal["w", "wb", "x", "xb", "a", "ab"]
+_OpenTextWritingMode = Literal["wt", "xt", "at"]
+
+_PathOrFile = Union[_PathType, IO[bytes]]
 
 _FilterChain = Sequence[Mapping[str, Any]]
 
@@ -41,7 +46,9 @@ PRESET_EXTREME: int
 
 # from _lzma.c
 class LZMADecompressor(object):
-    def __init__(self, format: Optional[int] = ..., memlimit: Optional[int] = ..., filters: Optional[_FilterChain] = ...) -> None: ...
+    def __init__(
+        self, format: Optional[int] = ..., memlimit: Optional[int] = ..., filters: Optional[_FilterChain] = ...
+    ) -> None: ...
     def decompress(self, data: bytes, max_length: int = ...) -> bytes: ...
     @property
     def check(self) -> int: ...
@@ -54,27 +61,25 @@ class LZMADecompressor(object):
 
 # from _lzma.c
 class LZMACompressor(object):
-    def __init__(self,
-                 format: Optional[int] = ...,
-                 check: int = ...,
-                 preset: Optional[int] = ...,
-                 filters: Optional[_FilterChain] = ...) -> None: ...
+    def __init__(
+        self, format: Optional[int] = ..., check: int = ..., preset: Optional[int] = ..., filters: Optional[_FilterChain] = ...
+    ) -> None: ...
     def compress(self, data: bytes) -> bytes: ...
     def flush(self) -> bytes: ...
 
-
 class LZMAError(Exception): ...
 
-
 class LZMAFile(io.BufferedIOBase, IO[bytes]):  # type: ignore  # python/mypy#5027
-    def __init__(self,
-                 filename: Optional[_PathOrFile] = ...,
-                 mode: str = ...,
-                 *,
-                 format: Optional[int] = ...,
-                 check: int = ...,
-                 preset: Optional[int] = ...,
-                 filters: Optional[_FilterChain] = ...) -> None: ...
+    def __init__(
+        self,
+        filename: Optional[_PathOrFile] = ...,
+        mode: str = ...,
+        *,
+        format: Optional[int] = ...,
+        check: int = ...,
+        preset: Optional[int] = ...,
+        filters: Optional[_FilterChain] = ...,
+    ) -> None: ...
     def close(self) -> None: ...
     @property
     def closed(self) -> bool: ...
@@ -90,17 +95,73 @@ class LZMAFile(io.BufferedIOBase, IO[bytes]):  # type: ignore  # python/mypy#502
     def seek(self, offset: int, whence: int = ...) -> int: ...
     def tell(self) -> int: ...
 
-
-def open(filename: _PathOrFile,
-         mode: str = ...,
-         *,
-         format: Optional[int] = ...,
-         check: int = ...,
-         preset: Optional[int] = ...,
-         filters: Optional[_FilterChain] = ...,
-         encoding: Optional[str] = ...,
-         errors: Optional[str] = ...,
-         newline: Optional[str] = ...) -> IO[Any]: ...
-def compress(data: bytes, format: int = ..., check: int = ..., preset: Optional[int] = ..., filters: Optional[_FilterChain] = ...) -> bytes: ...
+@overload
+def open(
+    filename: _PathOrFile,
+    mode: Literal["r", "rb"] = ...,
+    *,
+    format: Optional[int] = ...,
+    check: Literal[-1] = ...,
+    preset: None = ...,
+    filters: Optional[_FilterChain] = ...,
+    encoding: None = ...,
+    errors: None = ...,
+    newline: None = ...,
+) -> LZMAFile: ...
+@overload
+def open(
+    filename: _PathOrFile,
+    mode: _OpenBinaryWritingMode,
+    *,
+    format: Optional[int] = ...,
+    check: int = ...,
+    preset: Optional[int] = ...,
+    filters: Optional[_FilterChain] = ...,
+    encoding: None = ...,
+    errors: None = ...,
+    newline: None = ...,
+) -> LZMAFile: ...
+@overload
+def open(
+    filename: _PathType,
+    mode: Literal["rt"],
+    *,
+    format: Optional[int] = ...,
+    check: Literal[-1] = ...,
+    preset: None = ...,
+    filters: Optional[_FilterChain] = ...,
+    encoding: Optional[str] = ...,
+    errors: Optional[str] = ...,
+    newline: Optional[str] = ...,
+) -> TextIO: ...
+@overload
+def open(
+    filename: _PathType,
+    mode: _OpenTextWritingMode,
+    *,
+    format: Optional[int] = ...,
+    check: int = ...,
+    preset: Optional[int] = ...,
+    filters: Optional[_FilterChain] = ...,
+    encoding: Optional[str] = ...,
+    errors: Optional[str] = ...,
+    newline: Optional[str] = ...,
+) -> TextIO: ...
+@overload
+def open(
+    filename: _PathOrFile,
+    mode: str,
+    *,
+    format: Optional[int] = ...,
+    check: int = ...,
+    preset: Optional[int] = ...,
+    filters: Optional[_FilterChain] = ...,
+    encoding: Optional[str] = ...,
+    errors: Optional[str] = ...,
+    newline: Optional[str] = ...,
+) -> Union[LZMAFile, TextIO]: ...
+def compress(
+    data: bytes, format: int = ..., check: int = ..., preset: Optional[int] = ..., filters: Optional[_FilterChain] = ...
+) -> bytes: ...
 def decompress(data: bytes, format: int = ..., memlimit: Optional[int] = ..., filters: Optional[_FilterChain] = ...) -> bytes: ...
 def is_check_supported(check: int) -> bool: ...
diff --git a/stdlib/3/pathlib.pyi b/stdlib/3/pathlib.pyi
index 4c4f9ee72f6a..259bafef796e 100644
--- a/stdlib/3/pathlib.pyi
+++ b/stdlib/3/pathlib.pyi
@@ -1,4 +1,6 @@
-from typing import Any, Generator, IO, Optional, Sequence, Tuple, Type, TypeVar, Union, List
+from io import _OpenBinaryMode, _OpenTextMode
+from typing import (Any, BinaryIO, Generator, IO, List, Optional, Sequence,
+                    TextIO, Tuple, Type, TypeVar, Union, overload)
 from types import TracebackType
 import os
 import sys
@@ -93,8 +95,14 @@ class Path(PurePath):
     else:
         def mkdir(self, mode: int = ..., parents: bool = ...,
                   exist_ok: bool = ...) -> None: ...
-    def open(self, mode: str = ..., buffering: int = ...,
-             encoding: Optional[str] = ..., errors: Optional[str] = ...,
+    @overload
+    def open(self, mode: _OpenTextMode = ..., buffering: int = ..., encoding: Optional[str] = ..., errors: Optional[str] = ...,
+             newline: Optional[str] = ...) -> TextIO: ...
+    @overload
+    def open(self, mode: _OpenBinaryMode, buffering: int = ..., encoding: None = ..., errors: None = ...,
+             newline: None = ...) -> BinaryIO: ...
+    @overload
+    def open(self, mode: str, buffering: int = ..., encoding: Optional[str] = ..., errors: Optional[str] = ...,
              newline: Optional[str] = ...) -> IO[Any]: ...
     def owner(self) -> str: ...
     if sys.version_info >= (3, 8):
diff --git a/third_party/2/pathlib2.pyi b/third_party/2/pathlib2.pyi
index 4c4f9ee72f6a..259bafef796e 100644
--- a/third_party/2/pathlib2.pyi
+++ b/third_party/2/pathlib2.pyi
@@ -1,4 +1,6 @@
-from typing import Any, Generator, IO, Optional, Sequence, Tuple, Type, TypeVar, Union, List
+from io import _OpenBinaryMode, _OpenTextMode
+from typing import (Any, BinaryIO, Generator, IO, List, Optional, Sequence,
+                    TextIO, Tuple, Type, TypeVar, Union, overload)
 from types import TracebackType
 import os
 import sys
@@ -93,8 +95,14 @@ class Path(PurePath):
     else:
         def mkdir(self, mode: int = ..., parents: bool = ...,
                   exist_ok: bool = ...) -> None: ...
-    def open(self, mode: str = ..., buffering: int = ...,
-             encoding: Optional[str] = ..., errors: Optional[str] = ...,
+    @overload
+    def open(self, mode: _OpenTextMode = ..., buffering: int = ..., encoding: Optional[str] = ..., errors: Optional[str] = ...,
+             newline: Optional[str] = ...) -> TextIO: ...
+    @overload
+    def open(self, mode: _OpenBinaryMode, buffering: int = ..., encoding: None = ..., errors: None = ...,
+             newline: None = ...) -> BinaryIO: ...
+    @overload
+    def open(self, mode: str, buffering: int = ..., encoding: Optional[str] = ..., errors: Optional[str] = ...,
              newline: Optional[str] = ...) -> IO[Any]: ...
     def owner(self) -> str: ...
     if sys.version_info >= (3, 8):