diff options
author | noptuno <repollo.marrero@gmail.com> | 2023-04-28 02:29:30 +0200 |
---|---|---|
committer | noptuno <repollo.marrero@gmail.com> | 2023-04-28 02:29:30 +0200 |
commit | 355dee533bb34a571b9367820a63cccb668cf866 (patch) | |
tree | 838af886b4fec07320aeb10f0d1e74ba79e79b5c /venv/lib/python3.9/site-packages/trio/_path.py | |
parent | added pyproject.toml file (diff) | |
download | gpt4free-355dee533bb34a571b9367820a63cccb668cf866.tar gpt4free-355dee533bb34a571b9367820a63cccb668cf866.tar.gz gpt4free-355dee533bb34a571b9367820a63cccb668cf866.tar.bz2 gpt4free-355dee533bb34a571b9367820a63cccb668cf866.tar.lz gpt4free-355dee533bb34a571b9367820a63cccb668cf866.tar.xz gpt4free-355dee533bb34a571b9367820a63cccb668cf866.tar.zst gpt4free-355dee533bb34a571b9367820a63cccb668cf866.zip |
Diffstat (limited to 'venv/lib/python3.9/site-packages/trio/_path.py')
-rw-r--r-- | venv/lib/python3.9/site-packages/trio/_path.py | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/venv/lib/python3.9/site-packages/trio/_path.py b/venv/lib/python3.9/site-packages/trio/_path.py new file mode 100644 index 00000000..4077c449 --- /dev/null +++ b/venv/lib/python3.9/site-packages/trio/_path.py @@ -0,0 +1,206 @@ +# type: ignore + +from functools import wraps, partial +import os +import types +import pathlib + +import trio +from trio._util import async_wraps, Final + + +# re-wrap return value from methods that return new instances of pathlib.Path +def rewrap_path(value): + if isinstance(value, pathlib.Path): + value = Path(value) + return value + + +def _forward_factory(cls, attr_name, attr): + @wraps(attr) + def wrapper(self, *args, **kwargs): + attr = getattr(self._wrapped, attr_name) + value = attr(*args, **kwargs) + return rewrap_path(value) + + return wrapper + + +def _forward_magic(cls, attr): + sentinel = object() + + @wraps(attr) + def wrapper(self, other=sentinel): + if other is sentinel: + return attr(self._wrapped) + if isinstance(other, cls): + other = other._wrapped + value = attr(self._wrapped, other) + return rewrap_path(value) + + return wrapper + + +def iter_wrapper_factory(cls, meth_name): + @async_wraps(cls, cls._wraps, meth_name) + async def wrapper(self, *args, **kwargs): + meth = getattr(self._wrapped, meth_name) + func = partial(meth, *args, **kwargs) + # Make sure that the full iteration is performed in the thread + # by converting the generator produced by pathlib into a list + items = await trio.to_thread.run_sync(lambda: list(func())) + return (rewrap_path(item) for item in items) + + return wrapper + + +def thread_wrapper_factory(cls, meth_name): + @async_wraps(cls, cls._wraps, meth_name) + async def wrapper(self, *args, **kwargs): + meth = getattr(self._wrapped, meth_name) + func = partial(meth, *args, **kwargs) + value = await trio.to_thread.run_sync(func) + return rewrap_path(value) + + return wrapper + + +def classmethod_wrapper_factory(cls, meth_name): + @classmethod + @async_wraps(cls, cls._wraps, meth_name) + async def wrapper(cls, *args, **kwargs): + meth = getattr(cls._wraps, meth_name) + func = partial(meth, *args, **kwargs) + value = await trio.to_thread.run_sync(func) + return rewrap_path(value) + + return wrapper + + +class AsyncAutoWrapperType(Final): + def __init__(cls, name, bases, attrs): + super().__init__(name, bases, attrs) + + cls._forward = [] + type(cls).generate_forwards(cls, attrs) + type(cls).generate_wraps(cls, attrs) + type(cls).generate_magic(cls, attrs) + type(cls).generate_iter(cls, attrs) + + def generate_forwards(cls, attrs): + # forward functions of _forwards + for attr_name, attr in cls._forwards.__dict__.items(): + if attr_name.startswith("_") or attr_name in attrs: + continue + + if isinstance(attr, property): + cls._forward.append(attr_name) + elif isinstance(attr, types.FunctionType): + wrapper = _forward_factory(cls, attr_name, attr) + setattr(cls, attr_name, wrapper) + else: + raise TypeError(attr_name, type(attr)) + + def generate_wraps(cls, attrs): + # generate wrappers for functions of _wraps + for attr_name, attr in cls._wraps.__dict__.items(): + # .z. exclude cls._wrap_iter + if attr_name.startswith("_") or attr_name in attrs: + continue + if isinstance(attr, classmethod): + wrapper = classmethod_wrapper_factory(cls, attr_name) + setattr(cls, attr_name, wrapper) + elif isinstance(attr, types.FunctionType): + wrapper = thread_wrapper_factory(cls, attr_name) + setattr(cls, attr_name, wrapper) + else: + raise TypeError(attr_name, type(attr)) + + def generate_magic(cls, attrs): + # generate wrappers for magic + for attr_name in cls._forward_magic: + attr = getattr(cls._forwards, attr_name) + wrapper = _forward_magic(cls, attr) + setattr(cls, attr_name, wrapper) + + def generate_iter(cls, attrs): + # generate wrappers for methods that return iterators + for attr_name, attr in cls._wraps.__dict__.items(): + if attr_name in cls._wrap_iter: + wrapper = iter_wrapper_factory(cls, attr_name) + setattr(cls, attr_name, wrapper) + + +class Path(metaclass=AsyncAutoWrapperType): + """A :class:`pathlib.Path` wrapper that executes blocking methods in + :meth:`trio.to_thread.run_sync`. + + """ + + _wraps = pathlib.Path + _forwards = pathlib.PurePath + _forward_magic = [ + "__str__", + "__bytes__", + "__truediv__", + "__rtruediv__", + "__eq__", + "__lt__", + "__le__", + "__gt__", + "__ge__", + "__hash__", + ] + _wrap_iter = ["glob", "rglob", "iterdir"] + + def __init__(self, *args): + self._wrapped = pathlib.Path(*args) + + def __getattr__(self, name): + if name in self._forward: + value = getattr(self._wrapped, name) + return rewrap_path(value) + raise AttributeError(name) + + def __dir__(self): + return super().__dir__() + self._forward + + def __repr__(self): + return "trio.Path({})".format(repr(str(self))) + + def __fspath__(self): + return os.fspath(self._wrapped) + + @wraps(pathlib.Path.open) + async def open(self, *args, **kwargs): + """Open the file pointed to by the path, like the :func:`trio.open_file` + function does. + + """ + + func = partial(self._wrapped.open, *args, **kwargs) + value = await trio.to_thread.run_sync(func) + return trio.wrap_file(value) + + +Path.iterdir.__doc__ = """ + Like :meth:`pathlib.Path.iterdir`, but async. + + This is an async method that returns a synchronous iterator, so you + use it like:: + + for subpath in await mypath.iterdir(): + ... + + Note that it actually loads the whole directory list into memory + immediately, during the initial call. (See `issue #501 + <https://github.com/python-trio/trio/issues/501>`__ for discussion.) + +""" + +# 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. +del Path.absolute.__doc__ + +os.PathLike.register(Path) |