Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stubtest, fix incorrect stubs #73

Merged
merged 1 commit into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ jobs:
- python: '3.9'
check_typing: '1'
extra_name: ', type check'
- python: '3.9'
check_stubs: '1'
extra_name: ', stubtest'
- python: 'pypy-3.8'
runtime_only: '1'
extra_name: ', runtime only'
Expand All @@ -45,6 +48,7 @@ jobs:
env:
CHECK_FORMATTING: '${{ matrix.check_formatting }}'
CHECK_TYPING: '${{ matrix.check_typing }}'
CHECK_STUBS: '${{ matrix.check_stubs }}'
RUNTIME_ONLY: '${{ matrix.runtime_only }}'
# Should match 'name:' up above
JOB_NAME: 'Ubuntu (${{ matrix.python }}${{ matrix.extra_name }})'
165 changes: 165 additions & 0 deletions allowlist.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# not present at runtime (but maybe should be?)
trio.AsyncBinaryIO
trio.AsyncBufferedFileIO
trio.AsyncFileIO
trio.AsyncIO
trio.AsyncTextFileIO
trio.AsyncTextIO
trio.NoHandshakeError
trio.SSLStream.cipher
trio.SSLStream.compression
trio.SSLStream.get_channel_binding
trio.SSLStream.getpeercert
trio.SSLStream.pending
trio.SSLStream.selected_alpn_protocol
trio.SSLStream.selected_npn_protocol
trio.SSLStream.session
trio.SSLStream.session_reused
trio.SSLStream.shared_ciphers
trio.lowlevel.WaitForSingleObject
trio.socket.AF_AAL5
trio.socket.AF_BLUETOOTH
trio.socket.AF_DECnet
trio.socket.AF_LINK
trio.socket.AF_SYSTEM
trio.socket.AI_DEFAULT
trio.socket.AI_MASK
trio.socket.AI_V4MAPPED_CFG
trio.socket.EAGAIN
trio.socket.EAI_BADHINTS
trio.socket.EAI_MAX
trio.socket.EAI_PROTOCOL
trio.socket.IPPROTO_BIP
trio.socket.IPPROTO_EON
trio.socket.IPPROTO_GGP
trio.socket.IPPROTO_HELLO
trio.socket.IPPROTO_IPCOMP
trio.socket.IPPROTO_IPV4
trio.socket.IPPROTO_MAX
trio.socket.IPPROTO_MOBILE
trio.socket.IPPROTO_ND
trio.socket.IPPROTO_VRRP
trio.socket.IPPROTO_XTP
trio.socket.IPV6_USE_MIN_MTU
trio.socket.IPX_TYPE
trio.socket.IP_RECVDSTADDR
trio.socket.LOCAL_PEERCRED
trio.socket.MSG_BCAST
trio.socket.MSG_BTAG
trio.socket.MSG_EOF
trio.socket.MSG_ETAG
trio.socket.MSG_MCAST
trio.socket.MSG_NOTIFICATION
trio.socket.RDS_CANCEL_SENT_TO
trio.socket.RDS_CMSG_RDMA_ARGS
trio.socket.RDS_CMSG_RDMA_DEST
trio.socket.RDS_CMSG_RDMA_MAP
trio.socket.RDS_CMSG_RDMA_STATUS
trio.socket.RDS_CMSG_RDMA_UPDATE
trio.socket.RDS_CONG_MONITOR
trio.socket.RDS_FREE_MR
trio.socket.RDS_GET_MR
trio.socket.RDS_GET_MR_FOR_DEST
trio.socket.RDS_RDMA_DONTWAIT
trio.socket.RDS_RDMA_FENCE
trio.socket.RDS_RDMA_INVALIDATE
trio.socket.RDS_RDMA_NOTIFY_ME
trio.socket.RDS_RDMA_READWRITE
trio.socket.RDS_RDMA_SILENT
trio.socket.RDS_RDMA_USE_ONCE
trio.socket.RDS_RECVERR
trio.socket.SCM_CREDS
trio.socket.SOL_ATALK
trio.socket.SOL_AX25
trio.socket.SOL_HCI
trio.socket.SOL_IPX
trio.socket.SOL_NETROM
trio.socket.SOL_ROSE
trio.socket.SO_EXCLUSIVEADDRUSE
trio.socket.SO_SETFIB
trio.socket.SO_USELOOPBACK
trio.socket.SocketType.__enter__
trio.socket.SocketType.__exit__
trio.socket.SocketType.accept
trio.socket.SocketType.bind
trio.socket.SocketType.close
trio.socket.SocketType.connect
trio.socket.SocketType.detach
trio.socket.SocketType.dup
trio.socket.SocketType.fileno
trio.socket.SocketType.get_inheritable
trio.socket.SocketType.getpeername
trio.socket.SocketType.getsockname
trio.socket.SocketType.getsockopt
trio.socket.SocketType.is_readable
trio.socket.SocketType.listen
trio.socket.SocketType.recv
trio.socket.SocketType.recv_into
trio.socket.SocketType.recvfrom
trio.socket.SocketType.recvfrom_into
trio.socket.SocketType.recvmsg
trio.socket.SocketType.recvmsg_into
trio.socket.SocketType.send
trio.socket.SocketType.sendmsg
trio.socket.SocketType.sendto
trio.socket.SocketType.set_inheritable
trio.socket.SocketType.setsockopt
trio.socket.SocketType.share
trio.socket.SocketType.shutdown
trio.socket.SocketType.wait_writable
trio.socket.fromshare
trio.socket.ntohl

# Not present in stub (but maybe should be?)
trio.DTLSChannel
trio.DTLSEndpoint
trio.MultiError.derive
trio.NeedHandshakeError
trio.Path.hardlink_to
trio.Path.is_mount
trio.Path.link_to
trio.Path.readlink
trio.Process.encoding
trio.Process.errors
trio.Process.universal_newlines
trio.TrioDeprecationWarning
trio.lowlevel.FdStream.close
trio.lowlevel.open_process

# NoPublicConstructor
trio.MemoryReceiveChannel.__init__
trio.MemorySendChannel.__init__
trio.Nursery.__init__
trio.Process.__init__
trio.lowlevel.Task.__init__
trio.lowlevel.TrioToken.__init__

# wraps pathlib.Path, so arg inspection fails
# should maybe list all of them
trio.Path.__init__
trio.Path.absolute
trio.Path.cwd
trio.Path.exists
trio.Path.expanduser
trio.Path.group
trio.Path.home
trio.Path.is_block_device
trio.Path.is_char_device
trio.Path.is_dir
trio.Path.is_fifo
trio.Path.is_file
trio.Path.is_socket
trio.Path.is_symlink
trio.Path.iterdir
trio.Path.lstat
trio.Path.owner
trio.Path.read_bytes
trio.Path.rmdir
trio.Path.stat
trio.Path.unlink

# magic special case function
trio.run_process

# written as a class so you can say open_memory_channel[int](5)
trio.open_memory_channel
12 changes: 12 additions & 0 deletions ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ fi
python setup.py sdist --formats=zip
pip install dist/*.zip

if [ "$CHECK_STUBS" = "1" ]; then
pip install mypy==${MYPY_VERSION}
mkdir empty; cd empty
ln -s ../async_generator-stubs async_generator
ln -s ../outcome-stubs outcome
ln -s ../trio-stubs trio
ln -s ../trio_typing trio_typing
python -m mypy.stubtest --allowlist=../allowlist.txt --ignore-unused-allowlist trio
exit $?
fi

# Actual tests
pip install -Ur test-requirements.txt

Expand All @@ -59,3 +70,4 @@ else
pip install mypy==${MYPY_VERSION}
pytest -W error -W ignore:::distutils -ra -v -p trio_typing._tests.datadriven --pyargs trio_typing
fi

45 changes: 34 additions & 11 deletions trio-stubs/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ from typing import (
IO,
overload,
)
from types import TracebackType

from _typeshed import StrOrBytesPath
from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer
Expand Down Expand Up @@ -84,7 +85,12 @@ class Cancelled(BaseException, _NotConstructible, metaclass=ABCMeta):
# _core._multierror
class MultiError(BaseException):
exceptions: List[BaseException]
def __init__(self, exceptions: Sequence[BaseException]): ...
def __init__(
self, exceptions: Sequence[BaseException], *, _collapse: bool = ...
): ...
def __new__(
cls: T, exceptions: Sequence[BaseException], *, _collapse: bool = ...
) -> T: ...
Comment on lines +88 to +93
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better to not expose this param in stubs, since it's got a leading underscore and use of MultiError is deprecated anyway!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, it is just a stub - and not an official API/documentation. If there weren't a stub file, type checkers would see the parameters, and in error messages and the like you could see references to it. So I think I'm leaning towards keeping it.
I think having fewer lines in the allowlist also is a good thing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant "have a stub for MultiError, which omits the _collapse parameter", I think we agree on the first part but I miscommunicated about the second?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah no that's how I interpreted you 😅 So the miscommunication must be on my part! :D

I think adding trio.MultiError.__init__ and trio.MultiError.__new__ to allowlist.txt isn't great. Another reason for keeping the stubs technically correct is to ease a transition away from having separate stub files at all, and if exposing _collapse is bad for some reason that should be addressed in trio - rather than hidden by having an "incorrect" type for the function in the stub.

@classmethod
def filter(
cls,
Expand All @@ -106,7 +112,12 @@ class CancelScope:
cancelled_caught: bool
def __init__(self, *, deadline: float = ..., shield: bool = ...): ...
def __enter__(self) -> CancelScope: ...
def __exit__(self, *exc: object) -> bool: ...
def __exit__(
self,
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> None: ...
def cancel(self) -> None: ...

class Nursery(_NotConstructible, metaclass=ABCMeta):
Expand Down Expand Up @@ -160,7 +171,9 @@ class Nursery(_NotConstructible, metaclass=ABCMeta):
name: object = None,
) -> T: ...

def open_nursery() -> AsyncContextManager[Nursery]: ...
def open_nursery(
strict_exception_groups: bool | None = ...,
) -> AsyncContextManager[Nursery]: ...
def current_effective_deadline() -> float: ...
def current_time() -> float: ...
@takes_callable_and_args
Expand Down Expand Up @@ -268,7 +281,12 @@ class MemorySendChannel(trio.abc.SendChannel[T_contra]):
def statistics(self) -> _Statistics: ...
def close(self) -> None: ...
def __enter__(self) -> MemorySendChannel[T_contra]: ...
def __exit__(self, *exc: object) -> None: ...
def __exit__(
self,
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> None: ...

class MemoryReceiveChannel(trio.abc.ReceiveChannel[T_co]):
def receive_nowait(self) -> T_co: ...
Expand All @@ -278,7 +296,12 @@ class MemoryReceiveChannel(trio.abc.ReceiveChannel[T_co]):
def statistics(self) -> _Statistics: ...
def close(self) -> None: ...
def __enter__(self) -> MemoryReceiveChannel[T_co]: ...
def __exit__(self, *exc: object) -> None: ...
def __exit__(
self,
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> None: ...

# written as a class so you can say open_memory_channel[int](5)
class open_memory_channel(Tuple[MemorySendChannel[T], MemoryReceiveChannel[T]]):
Expand All @@ -298,9 +321,9 @@ class SocketStream(trio.abc.HalfCloseableStream):
def __init__(self, socket: trio.socket.SocketType) -> None: ...
def setsockopt(self, level: int, option: int, value: Union[int, bytes]) -> None: ...
@overload
def getsockopt(self, level: int, optname: int) -> int: ...
def getsockopt(self, level: int, option: int) -> int: ...
@overload
def getsockopt(self, level: int, optname: int, buflen: int) -> bytes: ...
def getsockopt(self, level: int, option: int, buffersize: int) -> bytes: ...
async def aclose(self) -> None: ...
async def send_all(self, data: Union[bytes, memoryview]) -> None: ...
async def wait_send_all_might_not_block(self) -> None: ...
Expand Down Expand Up @@ -447,13 +470,13 @@ async def open_file(
opener: Optional[_Opener] = ...,
) -> AsyncIO[Any]: ...
@overload
def wrap_file(obj: Union[TextIO, io.TextIOBase]) -> AsyncTextIO: ...
def wrap_file(file: Union[TextIO, io.TextIOBase]) -> AsyncTextIO: ...
@overload
def wrap_file(obj: Union[BinaryIO, io.BufferedIOBase]) -> AsyncBinaryIO: ...
def wrap_file(file: Union[BinaryIO, io.BufferedIOBase]) -> AsyncBinaryIO: ...
@overload
def wrap_file(obj: io.RawIOBase) -> AsyncBinaryIO: ...
def wrap_file(file: io.RawIOBase) -> AsyncBinaryIO: ...
@overload
def wrap_file(obj: Union[IO[Any], io.IOBase]) -> AsyncIO[Any]: ...
def wrap_file(file: Union[IO[Any], io.IOBase]) -> AsyncIO[Any]: ...

# _path
class Path(pathlib.PurePath):
Expand Down
4 changes: 2 additions & 2 deletions trio-stubs/lowlevel.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ if sys.platform == "win32":

# _core._traps
class Abort(enum.Enum):
SUCCEEDED = ...
FAILED = ...
SUCCEEDED = 1
FAILED = 2

async def cancel_shielded_checkpoint() -> None: ...
async def wait_task_rescheduled(
Expand Down
4 changes: 3 additions & 1 deletion trio-stubs/socket.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,10 @@ class SocketType:
def fromfd(fd: int, family: int, type: int, proto: int = ...) -> SocketType: ...
def fromshare(data: bytes) -> SocketType: ...
def from_stdlib_socket(sock: _stdlib_socket.socket) -> SocketType: ...

# https://github.com/python/typeshed/blob/4ca5ee98df5654d0db7f5b24cd2bd3b3fe54f313/stdlib/socket.pyi#L750
def socketpair(
family: int = ..., type: int = ..., proto: int = ...
family: int | None = ..., type: int = ..., proto: int = ...
) -> Tuple[SocketType, SocketType]: ...
def socket(
family: int = ..., type: int = ..., proto: int = ..., fileno: Optional[int] = ...
Expand Down