aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/anyio/_core/_fileio.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/anyio/_core/_fileio.py')
-rw-r--r--.venv/lib/python3.12/site-packages/anyio/_core/_fileio.py742
1 files changed, 742 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/anyio/_core/_fileio.py b/.venv/lib/python3.12/site-packages/anyio/_core/_fileio.py
new file mode 100644
index 00000000..a0d61984
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anyio/_core/_fileio.py
@@ -0,0 +1,742 @@
+from __future__ import annotations
+
+import os
+import pathlib
+import sys
+from collections.abc import (
+ AsyncIterator,
+ Callable,
+ Iterable,
+ Iterator,
+ Sequence,
+)
+from dataclasses import dataclass
+from functools import partial
+from os import PathLike
+from typing import (
+ IO,
+ TYPE_CHECKING,
+ Any,
+ AnyStr,
+ ClassVar,
+ Final,
+ Generic,
+ overload,
+)
+
+from .. import to_thread
+from ..abc import AsyncResource
+
+if TYPE_CHECKING:
+ from types import ModuleType
+
+ from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer
+else:
+ ReadableBuffer = OpenBinaryMode = OpenTextMode = WriteableBuffer = object
+
+
+class AsyncFile(AsyncResource, Generic[AnyStr]):
+ """
+ An asynchronous file object.
+
+ This class wraps a standard file object and provides async friendly versions of the
+ following blocking methods (where available on the original file object):
+
+ * read
+ * read1
+ * readline
+ * readlines
+ * readinto
+ * readinto1
+ * write
+ * writelines
+ * truncate
+ * seek
+ * tell
+ * flush
+
+ All other methods are directly passed through.
+
+ This class supports the asynchronous context manager protocol which closes the
+ underlying file at the end of the context block.
+
+ This class also supports asynchronous iteration::
+
+ async with await open_file(...) as f:
+ async for line in f:
+ print(line)
+ """
+
+ def __init__(self, fp: IO[AnyStr]) -> None:
+ self._fp: Any = fp
+
+ def __getattr__(self, name: str) -> object:
+ return getattr(self._fp, name)
+
+ @property
+ def wrapped(self) -> IO[AnyStr]:
+ """The wrapped file object."""
+ return self._fp
+
+ async def __aiter__(self) -> AsyncIterator[AnyStr]:
+ while True:
+ line = await self.readline()
+ if line:
+ yield line
+ else:
+ break
+
+ async def aclose(self) -> None:
+ return await to_thread.run_sync(self._fp.close)
+
+ async def read(self, size: int = -1) -> AnyStr:
+ return await to_thread.run_sync(self._fp.read, size)
+
+ async def read1(self: AsyncFile[bytes], size: int = -1) -> bytes:
+ return await to_thread.run_sync(self._fp.read1, size)
+
+ async def readline(self) -> AnyStr:
+ return await to_thread.run_sync(self._fp.readline)
+
+ async def readlines(self) -> list[AnyStr]:
+ return await to_thread.run_sync(self._fp.readlines)
+
+ async def readinto(self: AsyncFile[bytes], b: WriteableBuffer) -> int:
+ return await to_thread.run_sync(self._fp.readinto, b)
+
+ async def readinto1(self: AsyncFile[bytes], b: WriteableBuffer) -> int:
+ return await to_thread.run_sync(self._fp.readinto1, b)
+
+ @overload
+ async def write(self: AsyncFile[bytes], b: ReadableBuffer) -> int: ...
+
+ @overload
+ async def write(self: AsyncFile[str], b: str) -> int: ...
+
+ async def write(self, b: ReadableBuffer | str) -> int:
+ return await to_thread.run_sync(self._fp.write, b)
+
+ @overload
+ async def writelines(
+ self: AsyncFile[bytes], lines: Iterable[ReadableBuffer]
+ ) -> None: ...
+
+ @overload
+ async def writelines(self: AsyncFile[str], lines: Iterable[str]) -> None: ...
+
+ async def writelines(self, lines: Iterable[ReadableBuffer] | Iterable[str]) -> None:
+ return await to_thread.run_sync(self._fp.writelines, lines)
+
+ async def truncate(self, size: int | None = None) -> int:
+ return await to_thread.run_sync(self._fp.truncate, size)
+
+ async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int:
+ return await to_thread.run_sync(self._fp.seek, offset, whence)
+
+ async def tell(self) -> int:
+ return await to_thread.run_sync(self._fp.tell)
+
+ async def flush(self) -> None:
+ return await to_thread.run_sync(self._fp.flush)
+
+
+@overload
+async def open_file(
+ file: str | PathLike[str] | int,
+ mode: OpenBinaryMode,
+ buffering: int = ...,
+ encoding: str | None = ...,
+ errors: str | None = ...,
+ newline: str | None = ...,
+ closefd: bool = ...,
+ opener: Callable[[str, int], int] | None = ...,
+) -> AsyncFile[bytes]: ...
+
+
+@overload
+async def open_file(
+ file: str | PathLike[str] | int,
+ mode: OpenTextMode = ...,
+ buffering: int = ...,
+ encoding: str | None = ...,
+ errors: str | None = ...,
+ newline: str | None = ...,
+ closefd: bool = ...,
+ opener: Callable[[str, int], int] | None = ...,
+) -> AsyncFile[str]: ...
+
+
+async def open_file(
+ file: str | PathLike[str] | int,
+ mode: str = "r",
+ buffering: int = -1,
+ encoding: str | None = None,
+ errors: str | None = None,
+ newline: str | None = None,
+ closefd: bool = True,
+ opener: Callable[[str, int], int] | None = None,
+) -> AsyncFile[Any]:
+ """
+ Open a file asynchronously.
+
+ The arguments are exactly the same as for the builtin :func:`open`.
+
+ :return: an asynchronous file object
+
+ """
+ fp = await to_thread.run_sync(
+ open, file, mode, buffering, encoding, errors, newline, closefd, opener
+ )
+ return AsyncFile(fp)
+
+
+def wrap_file(file: IO[AnyStr]) -> AsyncFile[AnyStr]:
+ """
+ Wrap an existing file as an asynchronous file.
+
+ :param file: an existing file-like object
+ :return: an asynchronous file object
+
+ """
+ return AsyncFile(file)
+
+
+@dataclass(eq=False)
+class _PathIterator(AsyncIterator["Path"]):
+ iterator: Iterator[PathLike[str]]
+
+ async def __anext__(self) -> Path:
+ nextval = await to_thread.run_sync(
+ next, self.iterator, None, abandon_on_cancel=True
+ )
+ if nextval is None:
+ raise StopAsyncIteration from None
+
+ return Path(nextval)
+
+
+class Path:
+ """
+ An asynchronous version of :class:`pathlib.Path`.
+
+ This class cannot be substituted for :class:`pathlib.Path` or
+ :class:`pathlib.PurePath`, but it is compatible with the :class:`os.PathLike`
+ interface.
+
+ It implements the Python 3.10 version of :class:`pathlib.Path` interface, except for
+ the deprecated :meth:`~pathlib.Path.link_to` method.
+
+ Some methods may be unavailable or have limited functionality, based on the Python
+ version:
+
+ * :meth:`~pathlib.Path.copy` (available on Python 3.14 or later)
+ * :meth:`~pathlib.Path.copy_into` (available on Python 3.14 or later)
+ * :meth:`~pathlib.Path.from_uri` (available on Python 3.13 or later)
+ * :meth:`~pathlib.PurePath.full_match` (available on Python 3.13 or later)
+ * :attr:`~pathlib.Path.info` (available on Python 3.14 or later)
+ * :meth:`~pathlib.Path.is_junction` (available on Python 3.12 or later)
+ * :meth:`~pathlib.PurePath.match` (the ``case_sensitive`` parameter is only
+ available on Python 3.13 or later)
+ * :meth:`~pathlib.Path.move` (available on Python 3.14 or later)
+ * :meth:`~pathlib.Path.move_into` (available on Python 3.14 or later)
+ * :meth:`~pathlib.PurePath.relative_to` (the ``walk_up`` parameter is only available
+ on Python 3.12 or later)
+ * :meth:`~pathlib.Path.walk` (available on Python 3.12 or later)
+
+ Any methods that do disk I/O need to be awaited on. These methods are:
+
+ * :meth:`~pathlib.Path.absolute`
+ * :meth:`~pathlib.Path.chmod`
+ * :meth:`~pathlib.Path.cwd`
+ * :meth:`~pathlib.Path.exists`
+ * :meth:`~pathlib.Path.expanduser`
+ * :meth:`~pathlib.Path.group`
+ * :meth:`~pathlib.Path.hardlink_to`
+ * :meth:`~pathlib.Path.home`
+ * :meth:`~pathlib.Path.is_block_device`
+ * :meth:`~pathlib.Path.is_char_device`
+ * :meth:`~pathlib.Path.is_dir`
+ * :meth:`~pathlib.Path.is_fifo`
+ * :meth:`~pathlib.Path.is_file`
+ * :meth:`~pathlib.Path.is_junction`
+ * :meth:`~pathlib.Path.is_mount`
+ * :meth:`~pathlib.Path.is_socket`
+ * :meth:`~pathlib.Path.is_symlink`
+ * :meth:`~pathlib.Path.lchmod`
+ * :meth:`~pathlib.Path.lstat`
+ * :meth:`~pathlib.Path.mkdir`
+ * :meth:`~pathlib.Path.open`
+ * :meth:`~pathlib.Path.owner`
+ * :meth:`~pathlib.Path.read_bytes`
+ * :meth:`~pathlib.Path.read_text`
+ * :meth:`~pathlib.Path.readlink`
+ * :meth:`~pathlib.Path.rename`
+ * :meth:`~pathlib.Path.replace`
+ * :meth:`~pathlib.Path.resolve`
+ * :meth:`~pathlib.Path.rmdir`
+ * :meth:`~pathlib.Path.samefile`
+ * :meth:`~pathlib.Path.stat`
+ * :meth:`~pathlib.Path.symlink_to`
+ * :meth:`~pathlib.Path.touch`
+ * :meth:`~pathlib.Path.unlink`
+ * :meth:`~pathlib.Path.walk`
+ * :meth:`~pathlib.Path.write_bytes`
+ * :meth:`~pathlib.Path.write_text`
+
+ Additionally, the following methods return an async iterator yielding
+ :class:`~.Path` objects:
+
+ * :meth:`~pathlib.Path.glob`
+ * :meth:`~pathlib.Path.iterdir`
+ * :meth:`~pathlib.Path.rglob`
+ """
+
+ __slots__ = "_path", "__weakref__"
+
+ __weakref__: Any
+
+ def __init__(self, *args: str | PathLike[str]) -> None:
+ self._path: Final[pathlib.Path] = pathlib.Path(*args)
+
+ def __fspath__(self) -> str:
+ return self._path.__fspath__()
+
+ def __str__(self) -> str:
+ return self._path.__str__()
+
+ def __repr__(self) -> str:
+ return f"{self.__class__.__name__}({self.as_posix()!r})"
+
+ def __bytes__(self) -> bytes:
+ return self._path.__bytes__()
+
+ def __hash__(self) -> int:
+ return self._path.__hash__()
+
+ def __eq__(self, other: object) -> bool:
+ target = other._path if isinstance(other, Path) else other
+ return self._path.__eq__(target)
+
+ def __lt__(self, other: pathlib.PurePath | Path) -> bool:
+ target = other._path if isinstance(other, Path) else other
+ return self._path.__lt__(target)
+
+ def __le__(self, other: pathlib.PurePath | Path) -> bool:
+ target = other._path if isinstance(other, Path) else other
+ return self._path.__le__(target)
+
+ def __gt__(self, other: pathlib.PurePath | Path) -> bool:
+ target = other._path if isinstance(other, Path) else other
+ return self._path.__gt__(target)
+
+ def __ge__(self, other: pathlib.PurePath | Path) -> bool:
+ target = other._path if isinstance(other, Path) else other
+ return self._path.__ge__(target)
+
+ def __truediv__(self, other: str | PathLike[str]) -> Path:
+ return Path(self._path / other)
+
+ def __rtruediv__(self, other: str | PathLike[str]) -> Path:
+ return Path(other) / self
+
+ @property
+ def parts(self) -> tuple[str, ...]:
+ return self._path.parts
+
+ @property
+ def drive(self) -> str:
+ return self._path.drive
+
+ @property
+ def root(self) -> str:
+ return self._path.root
+
+ @property
+ def anchor(self) -> str:
+ return self._path.anchor
+
+ @property
+ def parents(self) -> Sequence[Path]:
+ return tuple(Path(p) for p in self._path.parents)
+
+ @property
+ def parent(self) -> Path:
+ return Path(self._path.parent)
+
+ @property
+ def name(self) -> str:
+ return self._path.name
+
+ @property
+ def suffix(self) -> str:
+ return self._path.suffix
+
+ @property
+ def suffixes(self) -> list[str]:
+ return self._path.suffixes
+
+ @property
+ def stem(self) -> str:
+ return self._path.stem
+
+ async def absolute(self) -> Path:
+ path = await to_thread.run_sync(self._path.absolute)
+ return Path(path)
+
+ def as_posix(self) -> str:
+ return self._path.as_posix()
+
+ def as_uri(self) -> str:
+ return self._path.as_uri()
+
+ if sys.version_info >= (3, 13):
+ parser: ClassVar[ModuleType] = pathlib.Path.parser
+
+ @classmethod
+ def from_uri(cls, uri: str) -> Path:
+ return Path(pathlib.Path.from_uri(uri))
+
+ def full_match(
+ self, path_pattern: str, *, case_sensitive: bool | None = None
+ ) -> bool:
+ return self._path.full_match(path_pattern, case_sensitive=case_sensitive)
+
+ def match(
+ self, path_pattern: str, *, case_sensitive: bool | None = None
+ ) -> bool:
+ return self._path.match(path_pattern, case_sensitive=case_sensitive)
+ else:
+
+ def match(self, path_pattern: str) -> bool:
+ return self._path.match(path_pattern)
+
+ if sys.version_info >= (3, 14):
+
+ @property
+ def info(self) -> Any: # TODO: add return type annotation when Typeshed gets it
+ return self._path.info
+
+ async def copy(
+ self,
+ target: str | os.PathLike[str],
+ *,
+ follow_symlinks: bool = True,
+ dirs_exist_ok: bool = False,
+ preserve_metadata: bool = False,
+ ) -> Path:
+ func = partial(
+ self._path.copy,
+ follow_symlinks=follow_symlinks,
+ dirs_exist_ok=dirs_exist_ok,
+ preserve_metadata=preserve_metadata,
+ )
+ return Path(await to_thread.run_sync(func, target))
+
+ async def copy_into(
+ self,
+ target_dir: str | os.PathLike[str],
+ *,
+ follow_symlinks: bool = True,
+ dirs_exist_ok: bool = False,
+ preserve_metadata: bool = False,
+ ) -> Path:
+ func = partial(
+ self._path.copy_into,
+ follow_symlinks=follow_symlinks,
+ dirs_exist_ok=dirs_exist_ok,
+ preserve_metadata=preserve_metadata,
+ )
+ return Path(await to_thread.run_sync(func, target_dir))
+
+ async def move(self, target: str | os.PathLike[str]) -> Path:
+ # Upstream does not handle anyio.Path properly as a PathLike
+ target = pathlib.Path(target)
+ return Path(await to_thread.run_sync(self._path.move, target))
+
+ async def move_into(
+ self,
+ target_dir: str | os.PathLike[str],
+ ) -> Path:
+ return Path(await to_thread.run_sync(self._path.move_into, target_dir))
+
+ def is_relative_to(self, other: str | PathLike[str]) -> bool:
+ try:
+ self.relative_to(other)
+ return True
+ except ValueError:
+ return False
+
+ async def chmod(self, mode: int, *, follow_symlinks: bool = True) -> None:
+ func = partial(os.chmod, follow_symlinks=follow_symlinks)
+ return await to_thread.run_sync(func, self._path, mode)
+
+ @classmethod
+ async def cwd(cls) -> Path:
+ path = await to_thread.run_sync(pathlib.Path.cwd)
+ return cls(path)
+
+ async def exists(self) -> bool:
+ return await to_thread.run_sync(self._path.exists, abandon_on_cancel=True)
+
+ async def expanduser(self) -> Path:
+ return Path(
+ await to_thread.run_sync(self._path.expanduser, abandon_on_cancel=True)
+ )
+
+ def glob(self, pattern: str) -> AsyncIterator[Path]:
+ gen = self._path.glob(pattern)
+ return _PathIterator(gen)
+
+ async def group(self) -> str:
+ return await to_thread.run_sync(self._path.group, abandon_on_cancel=True)
+
+ async def hardlink_to(
+ self, target: str | bytes | PathLike[str] | PathLike[bytes]
+ ) -> None:
+ if isinstance(target, Path):
+ target = target._path
+
+ await to_thread.run_sync(os.link, target, self)
+
+ @classmethod
+ async def home(cls) -> Path:
+ home_path = await to_thread.run_sync(pathlib.Path.home)
+ return cls(home_path)
+
+ def is_absolute(self) -> bool:
+ return self._path.is_absolute()
+
+ async def is_block_device(self) -> bool:
+ return await to_thread.run_sync(
+ self._path.is_block_device, abandon_on_cancel=True
+ )
+
+ async def is_char_device(self) -> bool:
+ return await to_thread.run_sync(
+ self._path.is_char_device, abandon_on_cancel=True
+ )
+
+ async def is_dir(self) -> bool:
+ return await to_thread.run_sync(self._path.is_dir, abandon_on_cancel=True)
+
+ async def is_fifo(self) -> bool:
+ return await to_thread.run_sync(self._path.is_fifo, abandon_on_cancel=True)
+
+ async def is_file(self) -> bool:
+ return await to_thread.run_sync(self._path.is_file, abandon_on_cancel=True)
+
+ if sys.version_info >= (3, 12):
+
+ async def is_junction(self) -> bool:
+ return await to_thread.run_sync(self._path.is_junction)
+
+ async def is_mount(self) -> bool:
+ return await to_thread.run_sync(
+ os.path.ismount, self._path, abandon_on_cancel=True
+ )
+
+ def is_reserved(self) -> bool:
+ return self._path.is_reserved()
+
+ async def is_socket(self) -> bool:
+ return await to_thread.run_sync(self._path.is_socket, abandon_on_cancel=True)
+
+ async def is_symlink(self) -> bool:
+ return await to_thread.run_sync(self._path.is_symlink, abandon_on_cancel=True)
+
+ async def iterdir(self) -> AsyncIterator[Path]:
+ gen = (
+ self._path.iterdir()
+ if sys.version_info < (3, 13)
+ else await to_thread.run_sync(self._path.iterdir, abandon_on_cancel=True)
+ )
+ async for path in _PathIterator(gen):
+ yield path
+
+ def joinpath(self, *args: str | PathLike[str]) -> Path:
+ return Path(self._path.joinpath(*args))
+
+ async def lchmod(self, mode: int) -> None:
+ await to_thread.run_sync(self._path.lchmod, mode)
+
+ async def lstat(self) -> os.stat_result:
+ return await to_thread.run_sync(self._path.lstat, abandon_on_cancel=True)
+
+ async def mkdir(
+ self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False
+ ) -> None:
+ await to_thread.run_sync(self._path.mkdir, mode, parents, exist_ok)
+
+ @overload
+ async def open(
+ self,
+ mode: OpenBinaryMode,
+ buffering: int = ...,
+ encoding: str | None = ...,
+ errors: str | None = ...,
+ newline: str | None = ...,
+ ) -> AsyncFile[bytes]: ...
+
+ @overload
+ async def open(
+ self,
+ mode: OpenTextMode = ...,
+ buffering: int = ...,
+ encoding: str | None = ...,
+ errors: str | None = ...,
+ newline: str | None = ...,
+ ) -> AsyncFile[str]: ...
+
+ async def open(
+ self,
+ mode: str = "r",
+ buffering: int = -1,
+ encoding: str | None = None,
+ errors: str | None = None,
+ newline: str | None = None,
+ ) -> AsyncFile[Any]:
+ fp = await to_thread.run_sync(
+ self._path.open, mode, buffering, encoding, errors, newline
+ )
+ return AsyncFile(fp)
+
+ async def owner(self) -> str:
+ return await to_thread.run_sync(self._path.owner, abandon_on_cancel=True)
+
+ async def read_bytes(self) -> bytes:
+ return await to_thread.run_sync(self._path.read_bytes)
+
+ async def read_text(
+ self, encoding: str | None = None, errors: str | None = None
+ ) -> str:
+ return await to_thread.run_sync(self._path.read_text, encoding, errors)
+
+ if sys.version_info >= (3, 12):
+
+ def relative_to(
+ self, *other: str | PathLike[str], walk_up: bool = False
+ ) -> Path:
+ return Path(self._path.relative_to(*other, walk_up=walk_up))
+
+ else:
+
+ def relative_to(self, *other: str | PathLike[str]) -> Path:
+ return Path(self._path.relative_to(*other))
+
+ async def readlink(self) -> Path:
+ target = await to_thread.run_sync(os.readlink, self._path)
+ return Path(target)
+
+ async def rename(self, target: str | pathlib.PurePath | Path) -> Path:
+ if isinstance(target, Path):
+ target = target._path
+
+ await to_thread.run_sync(self._path.rename, target)
+ return Path(target)
+
+ async def replace(self, target: str | pathlib.PurePath | Path) -> Path:
+ if isinstance(target, Path):
+ target = target._path
+
+ await to_thread.run_sync(self._path.replace, target)
+ return Path(target)
+
+ async def resolve(self, strict: bool = False) -> Path:
+ func = partial(self._path.resolve, strict=strict)
+ return Path(await to_thread.run_sync(func, abandon_on_cancel=True))
+
+ def rglob(self, pattern: str) -> AsyncIterator[Path]:
+ gen = self._path.rglob(pattern)
+ return _PathIterator(gen)
+
+ async def rmdir(self) -> None:
+ await to_thread.run_sync(self._path.rmdir)
+
+ async def samefile(self, other_path: str | PathLike[str]) -> bool:
+ if isinstance(other_path, Path):
+ other_path = other_path._path
+
+ return await to_thread.run_sync(
+ self._path.samefile, other_path, abandon_on_cancel=True
+ )
+
+ async def stat(self, *, follow_symlinks: bool = True) -> os.stat_result:
+ func = partial(os.stat, follow_symlinks=follow_symlinks)
+ return await to_thread.run_sync(func, self._path, abandon_on_cancel=True)
+
+ async def symlink_to(
+ self,
+ target: str | bytes | PathLike[str] | PathLike[bytes],
+ target_is_directory: bool = False,
+ ) -> None:
+ if isinstance(target, Path):
+ target = target._path
+
+ await to_thread.run_sync(self._path.symlink_to, target, target_is_directory)
+
+ async def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
+ await to_thread.run_sync(self._path.touch, mode, exist_ok)
+
+ async def unlink(self, missing_ok: bool = False) -> None:
+ try:
+ await to_thread.run_sync(self._path.unlink)
+ except FileNotFoundError:
+ if not missing_ok:
+ raise
+
+ if sys.version_info >= (3, 12):
+
+ async def walk(
+ self,
+ top_down: bool = True,
+ on_error: Callable[[OSError], object] | None = None,
+ follow_symlinks: bool = False,
+ ) -> AsyncIterator[tuple[Path, list[str], list[str]]]:
+ def get_next_value() -> tuple[pathlib.Path, list[str], list[str]] | None:
+ try:
+ return next(gen)
+ except StopIteration:
+ return None
+
+ gen = self._path.walk(top_down, on_error, follow_symlinks)
+ while True:
+ value = await to_thread.run_sync(get_next_value)
+ if value is None:
+ return
+
+ root, dirs, paths = value
+ yield Path(root), dirs, paths
+
+ def with_name(self, name: str) -> Path:
+ return Path(self._path.with_name(name))
+
+ def with_stem(self, stem: str) -> Path:
+ return Path(self._path.with_name(stem + self._path.suffix))
+
+ def with_suffix(self, suffix: str) -> Path:
+ return Path(self._path.with_suffix(suffix))
+
+ def with_segments(self, *pathsegments: str | PathLike[str]) -> Path:
+ return Path(*pathsegments)
+
+ async def write_bytes(self, data: bytes) -> int:
+ return await to_thread.run_sync(self._path.write_bytes, data)
+
+ async def write_text(
+ self,
+ data: str,
+ encoding: str | None = None,
+ errors: str | None = None,
+ newline: str | None = None,
+ ) -> int:
+ # Path.write_text() does not support the "newline" parameter before Python 3.10
+ def sync_write_text() -> int:
+ with self._path.open(
+ "w", encoding=encoding, errors=errors, newline=newline
+ ) as fp:
+ return fp.write(data)
+
+ return await to_thread.run_sync(sync_write_text)
+
+
+PathLike.register(Path)