Updated script that can be controled by Nodejs web app
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
from functools import partial, update_wrapper
|
||||
from inspect import cleandoc
|
||||
from typing import IO, TYPE_CHECKING, Any, BinaryIO, ClassVar, TypeVar, overload
|
||||
|
||||
from trio._file_io import AsyncIOWrapper, wrap_file
|
||||
from trio._util import final
|
||||
from trio.to_thread import run_sync
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Awaitable, Callable, Iterable
|
||||
from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper
|
||||
|
||||
from _typeshed import (
|
||||
OpenBinaryMode,
|
||||
OpenBinaryModeReading,
|
||||
OpenBinaryModeUpdating,
|
||||
OpenBinaryModeWriting,
|
||||
OpenTextMode,
|
||||
)
|
||||
from typing_extensions import Concatenate, Literal, ParamSpec, Self
|
||||
|
||||
P = ParamSpec("P")
|
||||
|
||||
PathT = TypeVar("PathT", bound="Path")
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def _wraps_async(
|
||||
wrapped: Callable[..., Any],
|
||||
) -> Callable[[Callable[P, T]], Callable[P, Awaitable[T]]]:
|
||||
def decorator(fn: Callable[P, T]) -> Callable[P, Awaitable[T]]:
|
||||
async def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
|
||||
return await run_sync(partial(fn, *args, **kwargs))
|
||||
|
||||
update_wrapper(wrapper, wrapped)
|
||||
if wrapped.__doc__:
|
||||
wrapper.__doc__ = (
|
||||
f"Like :meth:`~{wrapped.__module__}.{wrapped.__qualname__}`, but async.\n"
|
||||
f"\n"
|
||||
f"{cleandoc(wrapped.__doc__)}\n"
|
||||
)
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def _wrap_method(
|
||||
fn: Callable[Concatenate[pathlib.Path, P], T],
|
||||
) -> Callable[Concatenate[Path, P], Awaitable[T]]:
|
||||
@_wraps_async(fn)
|
||||
def wrapper(self: Path, /, *args: P.args, **kwargs: P.kwargs) -> T:
|
||||
return fn(self._wrapped_cls(self), *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def _wrap_method_path(
|
||||
fn: Callable[Concatenate[pathlib.Path, P], pathlib.Path],
|
||||
) -> Callable[Concatenate[PathT, P], Awaitable[PathT]]:
|
||||
@_wraps_async(fn)
|
||||
def wrapper(self: PathT, /, *args: P.args, **kwargs: P.kwargs) -> PathT:
|
||||
return self.__class__(fn(self._wrapped_cls(self), *args, **kwargs))
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def _wrap_method_path_iterable(
|
||||
fn: Callable[Concatenate[pathlib.Path, P], Iterable[pathlib.Path]],
|
||||
) -> Callable[Concatenate[PathT, P], Awaitable[Iterable[PathT]]]:
|
||||
@_wraps_async(fn)
|
||||
def wrapper(self: PathT, /, *args: P.args, **kwargs: P.kwargs) -> Iterable[PathT]:
|
||||
return map(self.__class__, [*fn(self._wrapped_cls(self), *args, **kwargs)])
|
||||
|
||||
if wrapper.__doc__:
|
||||
wrapper.__doc__ += (
|
||||
f"\n"
|
||||
f"This is an async method that returns a synchronous iterator, so you\n"
|
||||
f"use it like:\n"
|
||||
f"\n"
|
||||
f".. code:: python\n"
|
||||
f"\n"
|
||||
f" for subpath in await mypath.{fn.__name__}():\n"
|
||||
f" ...\n"
|
||||
f"\n"
|
||||
f".. note::\n"
|
||||
f"\n"
|
||||
f" The iterator is loaded into memory immediately during the initial\n"
|
||||
f" call (see `issue #501\n"
|
||||
f" <https://github.com/python-trio/trio/issues/501>`__ for discussion).\n"
|
||||
)
|
||||
return wrapper
|
||||
|
||||
|
||||
class Path(pathlib.PurePath):
|
||||
"""An async :class:`pathlib.Path` that executes blocking methods in :meth:`trio.to_thread.run_sync`.
|
||||
|
||||
Instantiating :class:`Path` returns a concrete platform-specific subclass, one of :class:`PosixPath` or
|
||||
:class:`WindowsPath`.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
_wrapped_cls: ClassVar[type[pathlib.Path]]
|
||||
|
||||
def __new__(cls, *args: str | os.PathLike[str]) -> Self:
|
||||
if cls is Path:
|
||||
cls = WindowsPath if os.name == "nt" else PosixPath # type: ignore[assignment]
|
||||
return super().__new__(cls, *args)
|
||||
|
||||
@classmethod
|
||||
@_wraps_async(pathlib.Path.cwd)
|
||||
def cwd(cls) -> Self:
|
||||
return cls(pathlib.Path.cwd())
|
||||
|
||||
@classmethod
|
||||
@_wraps_async(pathlib.Path.home)
|
||||
def home(cls) -> Self:
|
||||
return cls(pathlib.Path.home())
|
||||
|
||||
@overload
|
||||
async def open(
|
||||
self,
|
||||
mode: OpenTextMode = "r",
|
||||
buffering: int = -1,
|
||||
encoding: str | None = None,
|
||||
errors: str | None = None,
|
||||
newline: str | None = None,
|
||||
) -> AsyncIOWrapper[TextIOWrapper]: ...
|
||||
|
||||
@overload
|
||||
async def open(
|
||||
self,
|
||||
mode: OpenBinaryMode,
|
||||
buffering: Literal[0],
|
||||
encoding: None = None,
|
||||
errors: None = None,
|
||||
newline: None = None,
|
||||
) -> AsyncIOWrapper[FileIO]: ...
|
||||
|
||||
@overload
|
||||
async def open(
|
||||
self,
|
||||
mode: OpenBinaryModeUpdating,
|
||||
buffering: Literal[-1, 1] = -1,
|
||||
encoding: None = None,
|
||||
errors: None = None,
|
||||
newline: None = None,
|
||||
) -> AsyncIOWrapper[BufferedRandom]: ...
|
||||
|
||||
@overload
|
||||
async def open(
|
||||
self,
|
||||
mode: OpenBinaryModeWriting,
|
||||
buffering: Literal[-1, 1] = -1,
|
||||
encoding: None = None,
|
||||
errors: None = None,
|
||||
newline: None = None,
|
||||
) -> AsyncIOWrapper[BufferedWriter]: ...
|
||||
|
||||
@overload
|
||||
async def open(
|
||||
self,
|
||||
mode: OpenBinaryModeReading,
|
||||
buffering: Literal[-1, 1] = -1,
|
||||
encoding: None = None,
|
||||
errors: None = None,
|
||||
newline: None = None,
|
||||
) -> AsyncIOWrapper[BufferedReader]: ...
|
||||
|
||||
@overload
|
||||
async def open(
|
||||
self,
|
||||
mode: OpenBinaryMode,
|
||||
buffering: int = -1,
|
||||
encoding: None = None,
|
||||
errors: None = None,
|
||||
newline: None = None,
|
||||
) -> AsyncIOWrapper[BinaryIO]: ...
|
||||
|
||||
@overload
|
||||
async def open( # type: ignore[misc] # Any usage matches builtins.open().
|
||||
self,
|
||||
mode: str,
|
||||
buffering: int = -1,
|
||||
encoding: str | None = None,
|
||||
errors: str | None = None,
|
||||
newline: str | None = None,
|
||||
) -> AsyncIOWrapper[IO[Any]]: ...
|
||||
|
||||
@_wraps_async(pathlib.Path.open) # type: ignore[misc] # Overload return mismatch.
|
||||
def open(self, *args: Any, **kwargs: Any) -> AsyncIOWrapper[IO[Any]]:
|
||||
return wrap_file(self._wrapped_cls(self).open(*args, **kwargs))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"trio.Path({str(self)!r})"
|
||||
|
||||
stat = _wrap_method(pathlib.Path.stat)
|
||||
chmod = _wrap_method(pathlib.Path.chmod)
|
||||
exists = _wrap_method(pathlib.Path.exists)
|
||||
glob = _wrap_method_path_iterable(pathlib.Path.glob)
|
||||
rglob = _wrap_method_path_iterable(pathlib.Path.rglob)
|
||||
is_dir = _wrap_method(pathlib.Path.is_dir)
|
||||
is_file = _wrap_method(pathlib.Path.is_file)
|
||||
is_symlink = _wrap_method(pathlib.Path.is_symlink)
|
||||
is_socket = _wrap_method(pathlib.Path.is_socket)
|
||||
is_fifo = _wrap_method(pathlib.Path.is_fifo)
|
||||
is_block_device = _wrap_method(pathlib.Path.is_block_device)
|
||||
is_char_device = _wrap_method(pathlib.Path.is_char_device)
|
||||
if sys.version_info >= (3, 12):
|
||||
is_junction = _wrap_method(pathlib.Path.is_junction)
|
||||
iterdir = _wrap_method_path_iterable(pathlib.Path.iterdir)
|
||||
lchmod = _wrap_method(pathlib.Path.lchmod)
|
||||
lstat = _wrap_method(pathlib.Path.lstat)
|
||||
mkdir = _wrap_method(pathlib.Path.mkdir)
|
||||
if sys.platform != "win32":
|
||||
owner = _wrap_method(pathlib.Path.owner)
|
||||
group = _wrap_method(pathlib.Path.group)
|
||||
if sys.platform != "win32" or sys.version_info >= (3, 12):
|
||||
is_mount = _wrap_method(pathlib.Path.is_mount)
|
||||
if sys.version_info >= (3, 9):
|
||||
readlink = _wrap_method_path(pathlib.Path.readlink)
|
||||
rename = _wrap_method_path(pathlib.Path.rename)
|
||||
replace = _wrap_method_path(pathlib.Path.replace)
|
||||
resolve = _wrap_method_path(pathlib.Path.resolve)
|
||||
rmdir = _wrap_method(pathlib.Path.rmdir)
|
||||
symlink_to = _wrap_method(pathlib.Path.symlink_to)
|
||||
if sys.version_info >= (3, 10):
|
||||
hardlink_to = _wrap_method(pathlib.Path.hardlink_to)
|
||||
touch = _wrap_method(pathlib.Path.touch)
|
||||
unlink = _wrap_method(pathlib.Path.unlink)
|
||||
absolute = _wrap_method_path(pathlib.Path.absolute)
|
||||
expanduser = _wrap_method_path(pathlib.Path.expanduser)
|
||||
read_bytes = _wrap_method(pathlib.Path.read_bytes)
|
||||
read_text = _wrap_method(pathlib.Path.read_text)
|
||||
samefile = _wrap_method(pathlib.Path.samefile)
|
||||
write_bytes = _wrap_method(pathlib.Path.write_bytes)
|
||||
write_text = _wrap_method(pathlib.Path.write_text)
|
||||
if sys.version_info < (3, 12):
|
||||
link_to = _wrap_method(pathlib.Path.link_to)
|
||||
if sys.version_info >= (3, 13):
|
||||
full_match = _wrap_method(pathlib.Path.full_match)
|
||||
|
||||
|
||||
@final
|
||||
class PosixPath(Path, pathlib.PurePosixPath):
|
||||
"""An async :class:`pathlib.PosixPath` that executes blocking methods in :meth:`trio.to_thread.run_sync`."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
_wrapped_cls: ClassVar[type[pathlib.Path]] = pathlib.PosixPath
|
||||
|
||||
|
||||
@final
|
||||
class WindowsPath(Path, pathlib.PureWindowsPath):
|
||||
"""An async :class:`pathlib.WindowsPath` that executes blocking methods in :meth:`trio.to_thread.run_sync`."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
_wrapped_cls: ClassVar[type[pathlib.Path]] = pathlib.WindowsPath
|
||||
Reference in New Issue
Block a user