From 955e9c7da46e12e2c4e02d543ff94c246d304931 Mon Sep 17 00:00:00 2001 From: Daniel Farley Date: Wed, 8 Jan 2020 17:25:36 -0800 Subject: [PATCH] Unify file descriptor definitions (#3584) The _types module can house any common type defintions used throughout the rest of typeshed to keep defintions in sync. First candidate is file descriptors where anything with `fileno()` method is accepted. There were several different implementations in various files that can be unified. --- stdlib/2/fcntl.pyi | 11 +++--- stdlib/2and3/_types.pyi | 10 ++++++ stdlib/2and3/asyncore.pyi | 3 +- stdlib/2and3/select.pyi | 29 ++++++++-------- stdlib/2and3/termios.pyi | 14 ++++---- stdlib/3/asyncio/base_events.pyi | 10 +++--- stdlib/3/asyncio/events.pyi | 10 +++--- stdlib/3/faulthandler.pyi | 15 ++++----- stdlib/3/fcntl.pyi | 11 +++--- stdlib/3/selectors.pyi | 57 +++++++++++++++----------------- 10 files changed, 84 insertions(+), 86 deletions(-) create mode 100644 stdlib/2and3/_types.pyi diff --git a/stdlib/2/fcntl.pyi b/stdlib/2/fcntl.pyi index 5ba64ae8c..04086be62 100644 --- a/stdlib/2/fcntl.pyi +++ b/stdlib/2/fcntl.pyi @@ -1,5 +1,6 @@ from typing import Any, Union, IO import io +from _types import FileDescriptorLike FASYNC: int FD_CLOEXEC: int @@ -72,16 +73,14 @@ LOCK_SH: int LOCK_UN: int LOCK_WRITE: int -_ANYFILE = Union[int, IO] - # TODO All these return either int or bytes depending on the value of # cmd (not on the type of arg). -def fcntl(fd: _ANYFILE, op: int, arg: Union[int, bytes] = ...) -> Any: ... +def fcntl(fd: FileDescriptorLike, op: int, arg: Union[int, bytes] = ...) -> Any: ... # TODO: arg: int or read-only buffer interface or read-write buffer interface -def ioctl(fd: _ANYFILE, op: int, arg: Union[int, bytes] = ..., +def ioctl(fd: FileDescriptorLike, op: int, arg: Union[int, bytes] = ..., mutate_flag: bool = ...) -> Any: ... -def flock(fd: _ANYFILE, op: int) -> None: ... -def lockf(fd: _ANYFILE, op: int, length: int = ..., start: int = ..., +def flock(fd: FileDescriptorLike, op: int) -> None: ... +def lockf(fd: FileDescriptorLike, op: int, length: int = ..., start: int = ..., whence: int = ...) -> Any: ... diff --git a/stdlib/2and3/_types.pyi b/stdlib/2and3/_types.pyi new file mode 100644 index 000000000..493979e09 --- /dev/null +++ b/stdlib/2and3/_types.pyi @@ -0,0 +1,10 @@ +# These types are for typeshed-only objects that don't exist at runtime + +from typing import type_check_only, Protocol, Union + +@type_check_only +class HasFileno(Protocol): + def fileno(self) -> int: ... + +FileDescriptor = int +FileDescriptorLike = Union[int, HasFileno] diff --git a/stdlib/2and3/asyncore.pyi b/stdlib/2and3/asyncore.pyi index 9d0a2c60e..b3801ff32 100644 --- a/stdlib/2and3/asyncore.pyi +++ b/stdlib/2and3/asyncore.pyi @@ -7,6 +7,7 @@ import time import warnings from socket import SocketType from typing import Optional +from _types import FileDescriptorLike from errno import (EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, ENOTCONN, ESHUTDOWN, EINTR, EISCONN, EBADF, ECONNABORTED, @@ -141,5 +142,5 @@ class file_wrapper: def fileno(self) -> int: ... class file_dispatcher(dispatcher): - def __init__(self, fd: int, map: _maptype = ...) -> None: ... + def __init__(self, fd: FileDescriptorLike, map: _maptype = ...) -> None: ... def set_file(self, fd: int) -> None: ... diff --git a/stdlib/2and3/select.pyi b/stdlib/2and3/select.pyi index 6387f52c9..8f54fc05b 100644 --- a/stdlib/2and3/select.pyi +++ b/stdlib/2and3/select.pyi @@ -1,10 +1,7 @@ import sys from typing import Any, Iterable, List, Optional, Protocol, Tuple, Union +from _types import FileDescriptorLike -class _HasFileno(Protocol): - def fileno(self) -> int: ... - -_FileDescriptor = Union[int, _HasFileno] EPOLLERR: int EPOLLET: int @@ -71,9 +68,9 @@ POLLWRNORM: int class poll: def __init__(self) -> None: ... - def register(self, fd: _FileDescriptor, eventmask: int = ...) -> None: ... - def modify(self, fd: _FileDescriptor, eventmask: int) -> None: ... - def unregister(self, fd: _FileDescriptor) -> None: ... + def register(self, fd: FileDescriptorLike, eventmask: int = ...) -> None: ... + def modify(self, fd: FileDescriptorLike, eventmask: int) -> None: ... + def unregister(self, fd: FileDescriptorLike) -> None: ... def poll(self, timeout: Optional[float] = ...) -> List[Tuple[int, int]]: ... def select(rlist: Iterable[Any], wlist: Iterable[Any], xlist: Iterable[Any], @@ -94,7 +91,7 @@ class kevent(object): flags: int ident: int udata: Any - def __init__(self, ident: _FileDescriptor, filter: int = ..., flags: int = ..., fflags: int = ..., data: Any = ..., udata: Any = ...) -> None: ... + def __init__(self, ident: FileDescriptorLike, filter: int = ..., flags: int = ..., fflags: int = ..., data: Any = ..., udata: Any = ...) -> None: ... # BSD only class kqueue(object): @@ -104,7 +101,7 @@ class kqueue(object): def control(self, changelist: Optional[Iterable[kevent]], max_events: int, timeout: float = ...) -> List[kevent]: ... def fileno(self) -> int: ... @classmethod - def fromfd(cls, fd: _FileDescriptor) -> kqueue: ... + def fromfd(cls, fd: FileDescriptorLike) -> kqueue: ... # Linux only class epoll(object): @@ -118,12 +115,12 @@ class epoll(object): def close(self) -> None: ... closed: bool def fileno(self) -> int: ... - def register(self, fd: _FileDescriptor, eventmask: int = ...) -> None: ... - def modify(self, fd: _FileDescriptor, eventmask: int) -> None: ... - def unregister(self, fd: _FileDescriptor) -> None: ... + def register(self, fd: FileDescriptorLike, eventmask: int = ...) -> None: ... + def modify(self, fd: FileDescriptorLike, eventmask: int) -> None: ... + def unregister(self, fd: FileDescriptorLike) -> None: ... def poll(self, timeout: float = ..., maxevents: int = ...) -> List[Tuple[int, int]]: ... @classmethod - def fromfd(cls, fd: _FileDescriptor) -> epoll: ... + def fromfd(cls, fd: FileDescriptorLike) -> epoll: ... if sys.version_info >= (3, 3): # Solaris only @@ -132,7 +129,7 @@ if sys.version_info >= (3, 3): def close(self) -> None: ... closed: bool def fileno(self) -> int: ... - def register(self, fd: _FileDescriptor, eventmask: int = ...) -> None: ... - def modify(self, fd: _FileDescriptor, eventmask: int = ...) -> None: ... - def unregister(self, fd: _FileDescriptor) -> None: ... + def register(self, fd: FileDescriptorLike, eventmask: int = ...) -> None: ... + def modify(self, fd: FileDescriptorLike, eventmask: int = ...) -> None: ... + def unregister(self, fd: FileDescriptorLike) -> None: ... def poll(self, timeout: Optional[float] = ...) -> List[Tuple[int, int]]: ... diff --git a/stdlib/2and3/termios.pyi b/stdlib/2and3/termios.pyi index d788e1632..3e7d3f096 100644 --- a/stdlib/2and3/termios.pyi +++ b/stdlib/2and3/termios.pyi @@ -1,8 +1,8 @@ # Stubs for termios from typing import IO, List, Union +from _types import FileDescriptorLike -_FD = Union[int, IO[str]] _Attr = List[Union[int, List[bytes]]] # TODO constants not really documented @@ -238,11 +238,11 @@ VWERASE: int XCASE: int XTABS: int -def tcgetattr(fd: _FD) -> _Attr: ... -def tcsetattr(fd: _FD, when: int, attributes: _Attr) -> None: ... -def tcsendbreak(fd: _FD, duration: int) -> None: ... -def tcdrain(fd: _FD) -> None: ... -def tcflush(fd: _FD, queue: int) -> None: ... -def tcflow(fd: _FD, action: int) -> None: ... +def tcgetattr(fd: FileDescriptorLike) -> _Attr: ... +def tcsetattr(fd: FileDescriptorLike, when: int, attributes: _Attr) -> None: ... +def tcsendbreak(fd: FileDescriptorLike, duration: int) -> None: ... +def tcdrain(fd: FileDescriptorLike) -> None: ... +def tcflush(fd: FileDescriptorLike, queue: int) -> None: ... +def tcflow(fd: FileDescriptorLike, action: int) -> None: ... class error(Exception): ... diff --git a/stdlib/3/asyncio/base_events.pyi b/stdlib/3/asyncio/base_events.pyi index 3041c2891..86a805285 100644 --- a/stdlib/3/asyncio/base_events.pyi +++ b/stdlib/3/asyncio/base_events.pyi @@ -1,4 +1,3 @@ -import selectors from socket import socket, _Address, _RetAddress import ssl import sys @@ -9,6 +8,7 @@ from asyncio.events import AbstractEventLoop, AbstractServer, Handle, TimerHandl from asyncio.protocols import BaseProtocol from asyncio.tasks import Task from asyncio.transports import BaseTransport +from _types import FileDescriptorLike if sys.version_info >= (3, 7): from contextvars import Context @@ -183,10 +183,10 @@ class BaseEventLoop(AbstractEventLoop, metaclass=ABCMeta): async def subprocess_exec(self, protocol_factory: _ProtocolFactory, *args: Any, stdin: Any = ..., stdout: Any = ..., stderr: Any = ..., **kwargs: Any) -> _TransProtPair: ... - def add_reader(self, fd: selectors._FileObject, callback: Callable[..., Any], *args: Any) -> None: ... - def remove_reader(self, fd: selectors._FileObject) -> None: ... - def add_writer(self, fd: selectors._FileObject, callback: Callable[..., Any], *args: Any) -> None: ... - def remove_writer(self, fd: selectors._FileObject) -> None: ... + def add_reader(self, fd: FileDescriptorLike, callback: Callable[..., Any], *args: Any) -> None: ... + def remove_reader(self, fd: FileDescriptorLike) -> None: ... + def add_writer(self, fd: FileDescriptorLike, callback: Callable[..., Any], *args: Any) -> None: ... + def remove_writer(self, fd: FileDescriptorLike) -> None: ... # Completion based I/O methods returning Futures prior to 3.7 if sys.version_info >= (3, 7): async def sock_recv(self, sock: socket, nbytes: int) -> bytes: ... diff --git a/stdlib/3/asyncio/events.pyi b/stdlib/3/asyncio/events.pyi index 84e61910e..70d04051a 100644 --- a/stdlib/3/asyncio/events.pyi +++ b/stdlib/3/asyncio/events.pyi @@ -1,4 +1,3 @@ -import selectors from socket import socket, _Address, _RetAddress import ssl import sys @@ -8,6 +7,7 @@ from asyncio.futures import Future from asyncio.protocols import BaseProtocol from asyncio.tasks import Task from asyncio.transports import BaseTransport +from _types import FileDescriptorLike _T = TypeVar('_T') _Context = Dict[str, Any] @@ -253,13 +253,13 @@ class AbstractEventLoop(metaclass=ABCMeta): stdout: Any = ..., stderr: Any = ..., **kwargs: Any) -> _TransProtPair: ... @abstractmethod - def add_reader(self, fd: selectors._FileObject, callback: Callable[..., Any], *args: Any) -> None: ... + def add_reader(self, fd: FileDescriptorLike, callback: Callable[..., Any], *args: Any) -> None: ... @abstractmethod - def remove_reader(self, fd: selectors._FileObject) -> None: ... + def remove_reader(self, fd: FileDescriptorLike) -> None: ... @abstractmethod - def add_writer(self, fd: selectors._FileObject, callback: Callable[..., Any], *args: Any) -> None: ... + def add_writer(self, fd: FileDescriptorLike, callback: Callable[..., Any], *args: Any) -> None: ... @abstractmethod - def remove_writer(self, fd: selectors._FileObject) -> None: ... + def remove_writer(self, fd: FileDescriptorLike) -> None: ... # Completion based I/O methods returning Futures prior to 3.7 if sys.version_info >= (3, 7): @abstractmethod diff --git a/stdlib/3/faulthandler.pyi b/stdlib/3/faulthandler.pyi index 736a4539c..afd739462 100644 --- a/stdlib/3/faulthandler.pyi +++ b/stdlib/3/faulthandler.pyi @@ -1,17 +1,14 @@ +import io import sys from typing import Union, Protocol - -class _HasFileno(Protocol): - def fileno(self) -> int: ... - -_File = Union[_HasFileno, int] +from _types import FileDescriptorLike def cancel_dump_traceback_later() -> None: ... def disable() -> None: ... -def dump_traceback(file: _File = ..., all_threads: bool = ...) -> None: ... -def dump_traceback_later(timeout: float, repeat: bool = ..., file: _File = ..., exit: bool = ...) -> None: ... -def enable(file: _File = ..., all_threads: bool = ...) -> None: ... +def dump_traceback(file: FileDescriptorLike = ..., all_threads: bool = ...) -> None: ... +def dump_traceback_later(timeout: float, repeat: bool = ..., file: FileDescriptorLike = ..., exit: bool = ...) -> None: ... +def enable(file: FileDescriptorLike = ..., all_threads: bool = ...) -> None: ... def is_enabled() -> bool: ... if sys.platform != "win32": - def register(signum: int, file: _File = ..., all_threads: bool = ..., chain: bool = ...) -> None: ... + def register(signum: int, file: FileDescriptorLike = ..., all_threads: bool = ..., chain: bool = ...) -> None: ... def unregister(signum: int) -> None: ... diff --git a/stdlib/3/fcntl.pyi b/stdlib/3/fcntl.pyi index fdcb4fcf8..6f9bdf232 100644 --- a/stdlib/3/fcntl.pyi +++ b/stdlib/3/fcntl.pyi @@ -1,6 +1,7 @@ # Stubs for fcntl from io import IOBase from typing import Any, IO, Union +from _types import FileDescriptorLike FASYNC: int FD_CLOEXEC: int @@ -75,21 +76,19 @@ LOCK_SH: int LOCK_UN: int LOCK_WRITE: int -_AnyFile = Union[int, IO[Any], IOBase] - # TODO All these return either int or bytes depending on the value of # cmd (not on the type of arg). -def fcntl(fd: _AnyFile, +def fcntl(fd: FileDescriptorLike, cmd: int, arg: Union[int, bytes] = ...) -> Any: ... # TODO This function accepts any object supporting a buffer interface, # as arg, is there a better way to express this than bytes? -def ioctl(fd: _AnyFile, +def ioctl(fd: FileDescriptorLike, request: int, arg: Union[int, bytes] = ..., mutate_flag: bool = ...) -> Any: ... -def flock(fd: _AnyFile, operation: int) -> None: ... -def lockf(fd: _AnyFile, +def flock(fd: FileDescriptorLike, operation: int) -> None: ... +def lockf(fd: FileDescriptorLike, cmd: int, len: int = ..., start: int = ..., diff --git a/stdlib/3/selectors.pyi b/stdlib/3/selectors.pyi index 99e311daa..777874d78 100644 --- a/stdlib/3/selectors.pyi +++ b/stdlib/3/selectors.pyi @@ -3,82 +3,77 @@ from abc import ABCMeta, abstractmethod from typing import Any, List, Mapping, NamedTuple, Optional, Protocol, Tuple, Union +from _types import FileDescriptor, FileDescriptorLike -class _HasFileno(Protocol): - def fileno(self) -> int: ... - -# Type aliases added mainly to preserve some context -_FileObject = Union[int, _HasFileno] -_FileDescriptor = int _EventMask = int EVENT_READ: _EventMask EVENT_WRITE: _EventMask class SelectorKey(NamedTuple): - fileobj: _FileObject - fd: _FileDescriptor + fileobj: FileDescriptorLike + fd: FileDescriptor events: _EventMask data: Any class BaseSelector(metaclass=ABCMeta): @abstractmethod - def register(self, fileobj: _FileObject, events: _EventMask, data: Any = ...) -> SelectorKey: ... + def register(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... @abstractmethod - def unregister(self, fileobj: _FileObject) -> SelectorKey: ... + def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... - def modify(self, fileobj: _FileObject, events: _EventMask, data: Any = ...) -> SelectorKey: ... + def modify(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... @abstractmethod def select(self, timeout: Optional[float] = ...) -> List[Tuple[SelectorKey, _EventMask]]: ... def close(self) -> None: ... - def get_key(self, fileobj: _FileObject) -> SelectorKey: ... + def get_key(self, fileobj: FileDescriptorLike) -> SelectorKey: ... @abstractmethod - def get_map(self) -> Mapping[_FileObject, SelectorKey]: ... + def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... def __enter__(self) -> BaseSelector: ... def __exit__(self, *args: Any) -> None: ... class SelectSelector(BaseSelector): - def register(self, fileobj: _FileObject, events: _EventMask, data: Any = ...) -> SelectorKey: ... - def unregister(self, fileobj: _FileObject) -> SelectorKey: ... + def register(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... + def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... def select(self, timeout: Optional[float] = ...) -> List[Tuple[SelectorKey, _EventMask]]: ... - def get_map(self) -> Mapping[_FileObject, SelectorKey]: ... + def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... class PollSelector(BaseSelector): - def register(self, fileobj: _FileObject, events: _EventMask, data: Any = ...) -> SelectorKey: ... - def unregister(self, fileobj: _FileObject) -> SelectorKey: ... + def register(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... + def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... def select(self, timeout: Optional[float] = ...) -> List[Tuple[SelectorKey, _EventMask]]: ... - def get_map(self) -> Mapping[_FileObject, SelectorKey]: ... + def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... class EpollSelector(BaseSelector): def fileno(self) -> int: ... - def register(self, fileobj: _FileObject, events: _EventMask, data: Any = ...) -> SelectorKey: ... - def unregister(self, fileobj: _FileObject) -> SelectorKey: ... + def register(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... + def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... def select(self, timeout: Optional[float] = ...) -> List[Tuple[SelectorKey, _EventMask]]: ... - def get_map(self) -> Mapping[_FileObject, SelectorKey]: ... + def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... class DevpollSelector(BaseSelector): def fileno(self) -> int: ... - def register(self, fileobj: _FileObject, events: _EventMask, data: Any = ...) -> SelectorKey: ... - def unregister(self, fileobj: _FileObject) -> SelectorKey: ... + def register(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... + def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... def select(self, timeout: Optional[float] = ...) -> List[Tuple[SelectorKey, _EventMask]]: ... - def get_map(self) -> Mapping[_FileObject, SelectorKey]: ... + def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... class KqueueSelector(BaseSelector): def fileno(self) -> int: ... - def register(self, fileobj: _FileObject, events: _EventMask, data: Any = ...) -> SelectorKey: ... - def unregister(self, fileobj: _FileObject) -> SelectorKey: ... + def register(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... + def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... def select(self, timeout: Optional[float] = ...) -> List[Tuple[SelectorKey, _EventMask]]: ... - def get_map(self) -> Mapping[_FileObject, SelectorKey]: ... + def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... class DefaultSelector(BaseSelector): - def register(self, fileobj: _FileObject, events: _EventMask, data: Any = ...) -> SelectorKey: ... - def unregister(self, fileobj: _FileObject) -> SelectorKey: ... + def register(self, fileobj: FileDescriptorLike, events: _EventMask, data: Any = ...) -> SelectorKey: ... + def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... def select(self, timeout: Optional[float] = ...) -> List[Tuple[SelectorKey, _EventMask]]: ... - def get_map(self) -> Mapping[_FileObject, SelectorKey]: ... + def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ...