Skip to content

Commit

Permalink
change all instances of 'import typing as ...' to 'from typing import…
Browse files Browse the repository at this point in the history
… ...' (python-trio#2935)

* replace 'import typing as t' to 'from typing import ...' in src/trio/_util.py as used in all other files
* change typing_extensions import in src/trio/_tests/type_tests/check_wraps.py
* clarify import-related comments in src/trio/socket.py and src/trio/lowlevel.py
  • Loading branch information
jakkdl authored Jan 25, 2024
1 parent 0204d04 commit 556df86
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 29 deletions.
4 changes: 2 additions & 2 deletions src/trio/_tests/type_tests/check_wraps.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# https://github.com/python-trio/trio/issues/2775#issuecomment-1702267589
# (except platform independent...)
import trio
import typing_extensions
from typing_extensions import assert_type


async def fn(s: trio.SocketStream) -> None:
result = await s.socket.sendto(b"a", "h")
typing_extensions.assert_type(result, int)
assert_type(result, int)
54 changes: 32 additions & 22 deletions src/trio/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,29 @@
import os
import signal
import threading
import typing as t
from abc import ABCMeta
from functools import update_wrapper
from typing import (
TYPE_CHECKING,
Any,
Awaitable,
Callable,
Generic,
NoReturn,
Sequence,
TypeVar,
final as std_final,
)

from sniffio import thread_local as sniffio_loop

import trio

CallT = t.TypeVar("CallT", bound=t.Callable[..., t.Any])
T = t.TypeVar("T")
RetT = t.TypeVar("RetT")
CallT = TypeVar("CallT", bound=Callable[..., Any])
T = TypeVar("T")
RetT = TypeVar("RetT")

if t.TYPE_CHECKING:
if TYPE_CHECKING:
from types import AsyncGeneratorType, TracebackType

from typing_extensions import ParamSpec, Self, TypeVarTuple, Unpack
Expand All @@ -27,7 +37,7 @@
PosArgsT = TypeVarTuple("PosArgsT")


if t.TYPE_CHECKING:
if TYPE_CHECKING:
# Don't type check the implementation below, pthread_kill does not exist on Windows.
def signal_raise(signum: int) -> None:
...
Expand Down Expand Up @@ -104,9 +114,9 @@ def is_main_thread() -> bool:
# errors for common mistakes. Returns coroutine object.
######
def coroutine_or_error(
async_fn: t.Callable[[Unpack[PosArgsT]], t.Awaitable[RetT]],
async_fn: Callable[[Unpack[PosArgsT]], Awaitable[RetT]],
*args: Unpack[PosArgsT],
) -> collections.abc.Coroutine[object, t.NoReturn, RetT]:
) -> collections.abc.Coroutine[object, NoReturn, RetT]:
def _return_value_looks_like_wrong_library(value: object) -> bool:
# Returned by legacy @asyncio.coroutine functions, which includes
# a surprising proportion of asyncio builtins.
Expand Down Expand Up @@ -231,7 +241,7 @@ def async_wraps(
cls: type[object],
wrapped_cls: type[object],
attr_name: str,
) -> t.Callable[[CallT], CallT]:
) -> Callable[[CallT], CallT]:
"""Similar to wraps, but for async wrappers of non-async functions."""

def decorator(func: CallT) -> CallT:
Expand Down Expand Up @@ -283,7 +293,7 @@ def fix_one(qualname: str, name: str, obj: object) -> None:
# We need ParamSpec to type this "properly", but that requires a runtime typing_extensions import
# to use as a class base. This is only used at runtime and isn't correct for type checkers anyway,
# so don't bother.
class generic_function(t.Generic[RetT]):
class generic_function(Generic[RetT]):
"""Decorator that makes a function indexable, to communicate
non-inferrable generic type parameters to a static type checker.
Expand All @@ -300,18 +310,18 @@ def open_memory_channel(max_buffer_size: int) -> Tuple[
but at least it becomes possible to write those.
"""

def __init__(self, fn: t.Callable[..., RetT]) -> None:
def __init__(self, fn: Callable[..., RetT]) -> None:
update_wrapper(self, fn)
self._fn = fn

def __call__(self, *args: t.Any, **kwargs: t.Any) -> RetT:
def __call__(self, *args: Any, **kwargs: Any) -> RetT:
return self._fn(*args, **kwargs)

def __getitem__(self, subscript: object) -> Self:
return self


def _init_final_cls(cls: type[object]) -> t.NoReturn:
def _init_final_cls(cls: type[object]) -> NoReturn:
"""Raises an exception when a final class is subclassed."""
raise TypeError(f"{cls.__module__}.{cls.__qualname__} does not support subclassing")

Expand All @@ -335,10 +345,10 @@ class SomeClass:
# matter what the original did (if anything).
decorated.__init_subclass__ = classmethod(_init_final_cls) # type: ignore[assignment]
# Apply the typing decorator, in 3.11+ it adds a __final__ marker attribute.
return t.final(decorated)
return std_final(decorated)


if t.TYPE_CHECKING:
if TYPE_CHECKING:
from typing import final
else:
final = _final_impl
Expand Down Expand Up @@ -374,7 +384,7 @@ def _create(cls: type[T], *args: object, **kwargs: object) -> T:
return super().__call__(*args, **kwargs) # type: ignore


def name_asyncgen(agen: AsyncGeneratorType[object, t.NoReturn]) -> str:
def name_asyncgen(agen: AsyncGeneratorType[object, NoReturn]) -> str:
"""Return the fully-qualified name of the async generator function
that produced the async generator iterator *agen*.
"""
Expand All @@ -392,14 +402,14 @@ def name_asyncgen(agen: AsyncGeneratorType[object, t.NoReturn]) -> str:


# work around a pyright error
if t.TYPE_CHECKING:
Fn = t.TypeVar("Fn", bound=t.Callable[..., object])
if TYPE_CHECKING:
Fn = TypeVar("Fn", bound=Callable[..., object])

def wraps(
wrapped: t.Callable[..., object],
assigned: t.Sequence[str] = ...,
updated: t.Sequence[str] = ...,
) -> t.Callable[[Fn], Fn]:
wrapped: Callable[..., object],
assigned: Sequence[str] = ...,
updated: Sequence[str] = ...,
) -> Callable[[Fn], Fn]:
...

else:
Expand Down
4 changes: 4 additions & 0 deletions src/trio/lowlevel.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
but useful for extending Trio's functionality.
"""

# imports are renamed with leading underscores to indicate they are not part of the public API

import select as _select

# static checkers don't understand if importing this as _sys, so it's deleted later
import sys
import typing as _t

Expand Down
11 changes: 6 additions & 5 deletions src/trio/socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@
# implementation in an underscored module, and then re-export the public parts
# here.
# We still have some underscore names though but only a few.
# Uses `from x import y as y` for compatibility with `pyright --verifytypes` (#2625)
#
# Dynamically re-export whatever constants this particular Python happens to
# have:
import socket as _stdlib_socket

# static checkers don't understand if importing this as _sys, so it's deleted later
import sys
import typing as _t

Expand All @@ -24,6 +22,8 @@
# (you can still get it from stdlib socket, of course, if you want it)
_bad_symbols.add("SO_REUSEADDR")

# Dynamically re-export whatever constants this particular Python happens to
# have:
globals().update(
{
_name: getattr(_stdlib_socket, _name)
Expand All @@ -35,6 +35,7 @@
# import the overwrites
from contextlib import suppress as _suppress

# Uses `from x import y as y` for compatibility with `pyright --verifytypes` (#2625)
from ._socket import (
SocketType as SocketType,
from_stdlib_socket as from_stdlib_socket,
Expand Down Expand Up @@ -104,7 +105,7 @@
# re-export them. Since the exact set of constants varies depending on Python
# version, platform, the libc installed on the system where Python was built,
# etc., we figure out which constants to re-export dynamically at runtime (see
# below). But that confuses static analysis tools like jedi and mypy. So this
# above). But that confuses static analysis tools like jedi and mypy. So this
# import statement statically lists every constant that *could* be
# exported. There's a test in test_exports.py to make sure that the list is
# kept up to date.
Expand Down

0 comments on commit 556df86

Please sign in to comment.