Skip to content

Commit

Permalink
Merge branch 'master' into from_thread_check_cancelled
Browse files Browse the repository at this point in the history
  • Loading branch information
richardsheridan authored Oct 18, 2023
2 parents 96e45c5 + b161fec commit ab092b0
Show file tree
Hide file tree
Showing 14 changed files with 371 additions and 139 deletions.
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
Expand All @@ -14,7 +14,7 @@ repos:
hooks:
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.292
rev: v0.1.0
hooks:
- id: ruff
types: [file]
Expand Down
14 changes: 14 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ def autodoc_process_signature(
def setup(app):
app.add_css_file("hackrtd.css")
app.connect("autodoc-process-signature", autodoc_process_signature)
# After Intersphinx runs, add additional mappings.
app.connect("builder-inited", add_intersphinx, priority=1000)


# -- General configuration ------------------------------------------------
Expand Down Expand Up @@ -131,6 +133,18 @@ def setup(app):
"sniffio": ("https://sniffio.readthedocs.io/en/latest/", None),
}


def add_intersphinx(app) -> None:
"""Add some specific intersphinx mappings."""
# This has been removed in Py3.12, so add a link to the 3.11 version with deprecation warnings.
app.builder.env.intersphinx_inventory["py:method"]["pathlib.Path.link_to"] = (
"Python",
"3.11",
"https://docs.python.org/3.11/library/pathlib.html#pathlib.Path.link_to",
"-",
)


autodoc_member_order = "bysource"

# Add any paths that contain templates here, relative to this directory.
Expand Down
5 changes: 0 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,6 @@ disallow_untyped_calls = false
# files not yet fully typed
[[tool.mypy.overrides]]
module = [
# internal
"trio/_windows_pipes",

# tests
"trio/testing/_fake_net",
"trio/_core/_tests/test_guest_mode",
Expand All @@ -105,7 +102,6 @@ module = [
"trio/_tests/test_highlevel_open_unix_stream",
"trio/_tests/test_highlevel_serve_listeners",
"trio/_tests/test_highlevel_ssl_helpers",
"trio/_tests/test_path",
"trio/_tests/test_scheduler_determinism",
"trio/_tests/test_ssl",
"trio/_tests/test_subprocess",
Expand All @@ -116,7 +112,6 @@ module = [
"trio/_tests/test_tracing",
"trio/_tests/test_util",
"trio/_tests/test_wait_for_object",
"trio/_tests/test_windows_pipes",
"trio/_tests/tools/test_gen_exports",
]
check_untyped_defs = false
Expand Down
6 changes: 3 additions & 3 deletions trio/_file_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ def tell(self) -> int: ...
class _CanTruncate(Protocol):
def truncate(self, size: int | None = ..., /) -> int: ...

class _CanWrite(Protocol[AnyStr_contra]):
def write(self, data: AnyStr_contra, /) -> int: ...
class _CanWrite(Protocol[T_contra]):
def write(self, data: T_contra, /) -> int: ...

class _CanWriteLines(Protocol[T_contra]):
# The lines parameter varies for bytes/str, so use a typevar to make the async match.
Expand Down Expand Up @@ -334,7 +334,7 @@ async def readlines(self: AsyncIOWrapper[_CanReadLines[AnyStr]]) -> list[AnyStr]
async def seek(self: AsyncIOWrapper[_CanSeek], target: int, whence: int = 0, /) -> int: ...
async def tell(self: AsyncIOWrapper[_CanTell]) -> int: ...
async def truncate(self: AsyncIOWrapper[_CanTruncate], size: int | None = None, /) -> int: ...
async def write(self: AsyncIOWrapper[_CanWrite[AnyStr]], data: AnyStr, /) -> int: ...
async def write(self: AsyncIOWrapper[_CanWrite[T]], data: T, /) -> int: ...
async def writelines(self: AsyncIOWrapper[_CanWriteLines[T]], lines: Iterable[T], /) -> None: ...
async def readinto1(self: AsyncIOWrapper[_CanReadInto1], buffer: Buffer, /) -> int: ...
async def peek(self: AsyncIOWrapper[_CanPeek[AnyStr]], size: int = 0, /) -> AnyStr: ...
Expand Down
143 changes: 92 additions & 51 deletions trio/_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import pathlib
import sys
import types
from collections.abc import Awaitable, Callable, Iterable
from collections.abc import Awaitable, Callable, Iterable, Sequence
from functools import partial
from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper
from typing import (
Expand Down Expand Up @@ -245,7 +245,7 @@ def __fspath__(self) -> str:
return os.fspath(self._wrapped)

@overload
def open(
async def open(
self,
mode: OpenTextMode = "r",
buffering: int = -1,
Expand All @@ -256,7 +256,7 @@ def open(
...

@overload
def open(
async def open(
self,
mode: OpenBinaryMode,
buffering: Literal[0],
Expand All @@ -267,7 +267,7 @@ def open(
...

@overload
def open(
async def open(
self,
mode: OpenBinaryModeUpdating,
buffering: Literal[-1, 1] = -1,
Expand All @@ -278,7 +278,7 @@ def open(
...

@overload
def open(
async def open(
self,
mode: OpenBinaryModeWriting,
buffering: Literal[-1, 1] = -1,
Expand All @@ -289,7 +289,7 @@ def open(
...

@overload
def open(
async def open(
self,
mode: OpenBinaryModeReading,
buffering: Literal[-1, 1] = -1,
Expand All @@ -300,7 +300,7 @@ def open(
...

@overload
def open(
async def open(
self,
mode: OpenBinaryMode,
buffering: int = -1,
Expand All @@ -311,7 +311,7 @@ def open(
...

@overload
def open(
async def open(
self,
mode: str,
buffering: int = -1,
Expand All @@ -338,11 +338,53 @@ async def open(self, *args: Any, **kwargs: Any) -> _AsyncIOWrapper[IO[Any]]:
def __bytes__(self) -> bytes: ...
def __truediv__(self, other: StrPath) -> Path: ...
def __rtruediv__(self, other: StrPath) -> Path: ...
def __lt__(self, other: Path | pathlib.PurePath) -> bool: ...
def __le__(self, other: Path | pathlib.PurePath) -> bool: ...
def __gt__(self, other: Path | pathlib.PurePath) -> bool: ...
def __ge__(self, other: Path | pathlib.PurePath) -> bool: ...

# The following are ordered the same as in typeshed.

# Properties produced by __getattr__() - all synchronous.
@property
def parts(self) -> tuple[str, ...]: ...
@property
def drive(self) -> str: ...
@property
def root(self) -> str: ...
@property
def anchor(self) -> str: ...
@property
def name(self) -> str: ...
@property
def suffix(self) -> str: ...
@property
def suffixes(self) -> list[str]: ...
@property
def stem(self) -> str: ...
@property
def parents(self) -> Sequence[pathlib.Path]: ... # TODO: Convert these to trio Paths?
@property
def parent(self) -> Path: ...

# PurePath methods - synchronous.
def as_posix(self) -> str: ...
def as_uri(self) -> str: ...
def is_absolute(self) -> bool: ...
def is_reserved(self) -> bool: ...
def match(self, path_pattern: str) -> bool: ...
def relative_to(self, *other: StrPath) -> Path: ...
def with_name(self, name: str) -> Path: ...
def with_suffix(self, suffix: str) -> Path: ...
def joinpath(self, *other: StrPath) -> Path: ...

# wrapped methods handled by __getattr__
async def absolute(self) -> Path: ...
async def as_posix(self) -> str: ...
async def as_uri(self) -> str: ...
if sys.version_info >= (3, 9):
def is_relative_to(self, *other: StrPath) -> bool: ...
def with_stem(self, stem: str) -> Path: ...

# pathlib.Path methods and properties - async.
@classmethod
async def cwd(self) -> Path: ...

if sys.version_info >= (3, 10):
async def stat(self, *, follow_symlinks: bool = True) -> os.stat_result: ...
Expand All @@ -351,51 +393,50 @@ async def chmod(self, mode: int, *, follow_symlinks: bool = True) -> None: ...
async def stat(self) -> os.stat_result: ...
async def chmod(self, mode: int) -> None: ...

@classmethod
async def cwd(self) -> Path: ...

async def exists(self) -> bool: ...
async def expanduser(self) -> Path: ...
async def glob(self, pattern: str) -> Iterable[Path]: ...
async def home(self) -> Path: ...
async def is_absolute(self) -> bool: ...
async def is_block_device(self) -> bool: ...
async def is_char_device(self) -> bool: ...
async def is_dir(self) -> bool: ...
async def is_fifo(self) -> bool: ...
async def is_file(self) -> bool: ...
async def is_reserved(self) -> bool: ...
async def is_socket(self) -> bool: ...
async def is_symlink(self) -> bool: ...
async def is_socket(self) -> bool: ...
async def is_fifo(self) -> bool: ...
async def is_block_device(self) -> bool: ...
async def is_char_device(self) -> bool: ...
async def iterdir(self) -> Iterable[Path]: ...
async def joinpath(self, *other: StrPath) -> Path: ...
async def lchmod(self, mode: int) -> None: ...
async def lstat(self) -> os.stat_result: ...
async def match(self, path_pattern: str) -> bool: ...
async def mkdir(self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False) -> None: ...
async def read_bytes(self) -> bytes: ...
async def read_text(self, encoding: str | None = None, errors: str | None = None) -> str: ...
async def relative_to(self, *other: StrPath) -> Path: ...

if sys.platform != "win32":
async def owner(self) -> str: ...
async def group(self) -> str: ...
async def is_mount(self) -> bool: ...
if sys.version_info >= (3, 9):
async def readlink(self) -> Path: ...
if sys.version_info >= (3, 8):
def rename(self, target: str | pathlib.PurePath) -> Path: ...
def replace(self, target: str | pathlib.PurePath) -> Path: ...
async def rename(self, target: StrPath) -> Path: ...
async def replace(self, target: StrPath) -> Path: ...
else:
def rename(self, target: str | pathlib.PurePath) -> None: ...
def replace(self, target: str | pathlib.PurePath) -> None: ...

async def rename(self, target: StrPath) -> None: ...
async def replace(self, target: StrPath) -> None: ...
async def resolve(self, strict: bool = False) -> Path: ...
async def rglob(self, pattern: str) -> Iterable[Path]: ...
async def rmdir(self) -> None: ...
async def samefile(self, other_path: str | bytes | int | Path) -> bool: ...
async def symlink_to(self, target: str | Path, target_is_directory: bool = False) -> None: ...
async def symlink_to(self, target: StrPath, target_is_directory: bool = False) -> None: ...
if sys.version_info >= (3, 10):
async def hardlink_to(self, target: str | pathlib.Path) -> None: ...
async def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None: ...
if sys.version_info >= (3, 8):
def unlink(self, missing_ok: bool = False) -> None: ...
async def unlink(self, missing_ok: bool = False) -> None: ...
else:
def unlink(self) -> None: ...
async def with_name(self, name: str) -> Path: ...
async def with_suffix(self, suffix: str) -> Path: ...
async def unlink(self) -> None: ...
@classmethod
async def home(self) -> Path: ...
async def absolute(self) -> Path: ...
async def expanduser(self) -> Path: ...
async def read_bytes(self) -> bytes: ...
async def read_text(self, encoding: str | None = None, errors: str | None = None) -> str: ...
async def samefile(self, other_path: bytes | int | StrPath) -> bool: ...
async def write_bytes(self, data: bytes) -> int: ...

if sys.version_info >= (3, 10):
Expand All @@ -412,17 +453,6 @@ async def write_text(
errors: str | None = None,
) -> int: ...

if sys.platform != "win32":
async def owner(self) -> str: ...
async def group(self) -> str: ...
async def is_mount(self) -> bool: ...

if sys.version_info >= (3, 9):
async def is_relative_to(self, *other: StrPath) -> bool: ...
async def with_stem(self, stem: str) -> Path: ...
async def readlink(self) -> Path: ...
if sys.version_info >= (3, 10):
async def hardlink_to(self, target: str | pathlib.Path) -> None: ...
if sys.version_info < (3, 12):
async def link_to(self, target: StrPath | bytes) -> None: ...
if sys.version_info >= (3, 12):
Expand All @@ -432,7 +462,7 @@ async def with_segments(self, *pathsegments: StrPath) -> Path: ...


Path.iterdir.__doc__ = """
Like :meth:`pathlib.Path.iterdir`, but async.
Like :meth:`~pathlib.Path.iterdir`, but async.
This is an async method that returns a synchronous iterator, so you
use it like::
Expand All @@ -446,6 +476,17 @@ async def with_segments(self, *pathsegments: StrPath) -> Path: ...
"""

if sys.version_info < (3, 12):
# Since we synthesise methods from the stdlib, this automatically will
# have deprecation warnings, and disappear entirely in 3.12+.
Path.link_to.__doc__ = """
Like Python 3.8-3.11's :meth:`~pathlib.Path.link_to`, but async.
:deprecated: This method was deprecated in Python 3.10 and entirely \
removed in 3.12. Use :meth:`hardlink_to` instead which has \
a more meaningful parameter order.
"""

# The value of Path.absolute.__doc__ makes a reference to
# :meth:~pathlib.Path.absolute, which does not exist. Removing this makes more
# sense than inventing our own special docstring for this.
Expand Down
22 changes: 19 additions & 3 deletions trio/_tests/test_exports.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def iter_modules(
# https://github.com/pypa/setuptools/issues/3274
"ignore:module 'sre_constants' is deprecated:DeprecationWarning",
)
def test_static_tool_sees_all_symbols(tool, modname, tmpdir):
def test_static_tool_sees_all_symbols(tool, modname, tmp_path):
module = importlib.import_module(modname)

def no_underscores(symbols):
Expand Down Expand Up @@ -273,7 +273,7 @@ def no_underscores(symbols):
@pytest.mark.parametrize("module_name", PUBLIC_MODULE_NAMES)
@pytest.mark.parametrize("tool", ["jedi", "mypy"])
def test_static_tool_sees_class_members(
tool: str, module_name: str, tmpdir: Path
tool: str, module_name: str, tmp_path: Path
) -> None:
module = PUBLIC_MODULES[PUBLIC_MODULE_NAMES.index(module_name)]

Expand Down Expand Up @@ -494,9 +494,25 @@ def lookup_symbol(symbol):
missing.remove("__aiter__")
missing.remove("__anext__")

# intentionally hidden behind type guard
# __getattr__ is intentionally hidden behind type guard. That hook then
# forwards property accesses to PurePath, meaning these names aren't directly on
# the class.
if class_ == trio.Path:
missing.remove("__getattr__")
before = len(extra)
extra -= {
"anchor",
"drive",
"name",
"parent",
"parents",
"parts",
"root",
"stem",
"suffix",
"suffixes",
}
assert len(extra) == before - 10

if missing or extra: # pragma: no cover
errors[f"{module_name}.{class_name}"] = {
Expand Down
Loading

0 comments on commit ab092b0

Please sign in to comment.