From d03f6deb240ff50dba28fa8f6cbf47edcea28dcc Mon Sep 17 00:00:00 2001 From: Alexander Tarasov Date: Wed, 16 Apr 2025 10:46:25 +0300 Subject: [PATCH] httpx -> aiohttp; fixed sync Client --- requirements.txt | 2 +- yndx_disk/api/disk.py | 32 +- yndx_disk/api/operations.py | 35 +- yndx_disk/api/public_resources.py | 128 ++++--- yndx_disk/api/resources.py | 560 ++++++++++++++++++------------ yndx_disk/api/trash_resources.py | 72 ++-- yndx_disk/api/utils.py | 6 +- yndx_disk/clients/async_client.py | 269 +++++++------- yndx_disk/clients/sync_client.py | 47 +-- 9 files changed, 673 insertions(+), 478 deletions(-) diff --git a/requirements.txt b/requirements.txt index 5c9be14..441f310 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -httpx +aiohttp aiofiles sphinx sphinx-book-theme \ No newline at end of file diff --git a/yndx_disk/api/disk.py b/yndx_disk/api/disk.py index 87eb9ab..a32ef30 100644 --- a/yndx_disk/api/disk.py +++ b/yndx_disk/api/disk.py @@ -1,11 +1,12 @@ -import httpx -import yndx_disk.api.utils as utils +from aiohttp import ClientSession, ClientResponse +import yndx_disk.api.utils as utils BASE_URL = "https://cloud-api.yandex.net/v1/disk" -async def get_disk_info(token: str, fields: str = "", timeout: int = 30) -> httpx.Response: +async def get_disk_info(token: str, session: ClientSession = None, fields: str = "", + timeout: int = 30) -> ClientResponse: """ Get information about the disk. @@ -19,14 +20,21 @@ async def get_disk_info(token: str, fields: str = "", timeout: int = 30) -> http """ url = BASE_URL - async with httpx.AsyncClient() as client: - response = await client.get( - url=url, - headers=utils.generate_headers(token=token), - params={ - "fields": fields, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + response = await session.get( + url=url, + headers=utils.generate_headers(token=token), + params={ + "fields": fields, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response diff --git a/yndx_disk/api/operations.py b/yndx_disk/api/operations.py index 82f0dda..246f5d7 100644 --- a/yndx_disk/api/operations.py +++ b/yndx_disk/api/operations.py @@ -1,11 +1,12 @@ -import httpx -import yndx_disk.api.utils as utils +from aiohttp import ClientSession, ClientResponse +import yndx_disk.api.utils as utils BASE_URL = "https://cloud-api.yandex.net/v1/disk/operations" -async def get_operation_status(token: str, operation_id: str, fields: str = "", timeout: int = 30) -> httpx.Response: +async def get_operation_status(token: str, operation_id: str, session: ClientSession = None, fields: str = "", + timeout: int = 30) -> ClientResponse: """ Get the status of an operation on the server. @@ -20,16 +21,22 @@ async def get_operation_status(token: str, operation_id: str, fields: str = "", """ url = BASE_URL + f"/{operation_id}" - async with httpx.AsyncClient() as client: - response = await client.get( - url=url, - headers=utils.generate_headers(token=token), - params={ - "operation_id": operation_id, - "fields": fields, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + response = await session.get( + url=url, + headers=utils.generate_headers(token=token), + params={ + "operation_id": operation_id, + "fields": fields, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response - diff --git a/yndx_disk/api/public_resources.py b/yndx_disk/api/public_resources.py index 760f788..ad48cb2 100644 --- a/yndx_disk/api/public_resources.py +++ b/yndx_disk/api/public_resources.py @@ -1,12 +1,13 @@ -import httpx -import yndx_disk.api.utils as utils +from aiohttp import ClientSession, ClientResponse +import yndx_disk.api.utils as utils BASE_URL = "https://cloud-api.yandex.net/v1/disk/public/resources" -async def get_info(token: str, public_key: str, fields: str = "", path: str = "", preview_size: str = "", - sort: str = "", preview_crop: bool = False, limit: int = 100, offset: int = 0, timeout: int = 30) -> httpx.Response: +async def get_info(token: str, public_key: str, session: ClientSession = None, fields: str = "", path: str = "", + preview_size: str = "", sort: str = "", preview_crop: bool = False, limit: int = 100, + offset: int = 0, timeout: int = 30) -> ClientResponse: """ Get information about a file or directory on the disk. @@ -27,29 +28,37 @@ async def get_info(token: str, public_key: str, fields: str = "", path: str = "" """ url = BASE_URL - async with httpx.AsyncClient() as client: - response = await client.get( - url=url, - headers=utils.generate_headers(token=token), - params={ - "public_key": public_key, - "fields": fields, - "path": utils.parse_path(path), - "preview_size": preview_size, - "sort": sort, - "preview_crop": preview_crop, - "limit": limit, - "offset": offset, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + preview_crop = "true" if preview_crop else "false" + + response = await session.get( + url=url, + headers=utils.generate_headers(token=token), + params={ + "public_key": public_key, + "fields": fields, + "path": utils.parse_path(path), + "preview_size": preview_size, + "sort": sort, + "preview_crop": preview_crop, + "limit": limit, + "offset": offset, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response - - -async def get_url(token: str, public_key: str, fields: str = "", path: str = "", timeout: int = 30) -> httpx.Response: +async def get_url(token: str, public_key: str, session: ClientSession = None, fields: str = "", path: str = "", + timeout: int = 30) -> ClientResponse: """ Get the download URL for a file or directory on the disk. @@ -65,24 +74,31 @@ async def get_url(token: str, public_key: str, fields: str = "", path: str = "", """ url = BASE_URL + "/download" - async with httpx.AsyncClient() as client: - response = await client.get( - url=url, - headers=utils.generate_headers(token=token), - params={ - "public_key": public_key, - "fields": fields, - "path": utils.parse_path(path), - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + response = await session.get( + url=url, + headers=utils.generate_headers(token=token), + params={ + "public_key": public_key, + "fields": fields, + "path": utils.parse_path(path), + }, + timeout=timeout + ) + + if close_session: + await session.close() return response - - -async def save_to_disk(token: str, public_key: str, fields: str = "", name: str = "", path: str = "", save_path: str = "", force_async: bool = False, timeout: int = 30) -> httpx.Response: +async def save_to_disk(token: str, public_key: str, session: ClientSession = None, fields: str = "", name: str = "", + path: str = "", save_path: str = "", force_async: bool = False, + timeout: int = 30) -> ClientResponse: """ Save a file or directory from the disk to your own disk. @@ -101,20 +117,28 @@ async def save_to_disk(token: str, public_key: str, fields: str = "", name: str """ url = BASE_URL + "/save-to-disk" - async with httpx.AsyncClient() as client: - response = await client.post( - url=url, - headers=utils.generate_headers(token=token), - params={ - "public_key": public_key, - "fields": fields, - "name": name, - "path": utils.parse_path(path), - "save_path": save_path, - "force_async": force_async, - }, - timeout=timeout - ) + force_async = "true" if force_async else "false" + + close_session = False + if not session: + session = ClientSession() + close_session = True + + response = await session.post( + url=url, + headers=utils.generate_headers(token=token), + params={ + "public_key": public_key, + "fields": fields, + "name": name, + "path": utils.parse_path(path), + "save_path": save_path, + "force_async": force_async, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response - diff --git a/yndx_disk/api/resources.py b/yndx_disk/api/resources.py index 03c891d..7d8be6d 100644 --- a/yndx_disk/api/resources.py +++ b/yndx_disk/api/resources.py @@ -1,12 +1,12 @@ -import httpx -import yndx_disk.api.utils as utils +from aiohttp import ClientSession, ClientResponse +import yndx_disk.api.utils as utils BASE_URL = "https://cloud-api.yandex.net/v1/disk/resources" -async def delete(token: str, path: str, fields: str = "", md5: str = "", force_async: bool = False, - permanently: bool = False, timeout: int = 30) -> httpx.Response: +async def delete(token: str, path: str, session: ClientSession = None, fields: str = "", md5: str = "", + force_async: bool = False, permanently: bool = False, timeout: int = 30) -> ClientResponse: """ Delete a file or directory from the disk. @@ -20,29 +20,35 @@ async def delete(token: str, path: str, fields: str = "", md5: str = "", force_a - timeout (int, optional): The timeout for the request in seconds. Defaults to 30. Returns: - - httpx.Response: The response from the server after the deletion operation. + - ClientResponse: The response from the server after the deletion operation. """ url = BASE_URL - async with httpx.AsyncClient() as client: - response = await client.delete( - url=url, - headers=utils.generate_headers(token=token), - params={ - "path": utils.parse_path(path), - "fields": fields, - "md5": md5, - "force_async": force_async, - "permanently": permanently, - }, - timeout=timeout - ) + if not session: + session = ClientSession() + + force_async = "true" if force_async else "false" + permanently = "true" if permanently else "false" + + response = await session.delete( + url=url, + headers=utils.generate_headers(token=token), + params={ + "path": utils.parse_path(path), + "fields": fields, + "md5": md5, + "force_async": force_async, + "permanently": permanently, + }, + timeout=timeout + ) return response -async def get_info(token: str, path: str, fields: str = "", preview_size: str = "", sort: str = "", - preview_crop: bool = False, limit: int = 100, offset: int = 0, timeout: int = 30) -> httpx.Response: +async def get_info(token: str, path: str, session: ClientSession = None, fields: str = "", preview_size: str = "", + sort: str = "", preview_crop: str = False, limit: int = 100, offset: int = 0, + timeout: int = 30) -> ClientResponse: """ Get information about a file or directory on the disk. @@ -58,30 +64,40 @@ async def get_info(token: str, path: str, fields: str = "", preview_size: str = - timeout (int, optional): The timeout for the request in seconds. Defaults to 30. Returns: - - httpx.Response: The response from the server containing the information about the file or directory. + - ClientResponse: The response from the server containing the information about the file or directory. """ url = BASE_URL - async with httpx.AsyncClient() as client: - response = await client.get( - url=url, - headers=utils.generate_headers(token=token), - params={ - "path": utils.parse_path(path), - "fields": fields, - "preview_size": preview_size, - "sort": sort, - "preview_crop": preview_crop, - "limit": limit, - "offset": offset, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + preview_crop = "true" if preview_crop else "false" + + response = await session.get( + url=url, + headers=utils.generate_headers(token=token), + params={ + "path": utils.parse_path(path), + "fields": fields, + "preview_size": preview_size, + "sort": sort, + "preview_crop": preview_crop, + "limit": limit, + "offset": offset, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response -async def update_info(token: str, path: str, body: dict, fields: str = "", timeout: int = 30) -> httpx.Response: +async def update_info(token: str, path: str, body: dict, session: ClientSession = None, fields: str = "", + timeout: int = 30) -> ClientResponse: """ Update information about a file or directory on the disk. @@ -93,26 +109,34 @@ async def update_info(token: str, path: str, body: dict, fields: str = "", timeo - timeout (int, optional): The timeout for the request in seconds. Defaults to 30. Returns: - - httpx.Response: The response from the server after the update operation. + - ClientResponse: The response from the server after the update operation. """ url = BASE_URL - async with httpx.AsyncClient() as client: - response = await client.patch( - url=url, - headers=utils.generate_headers(token=token), - params={ - "path": utils.parse_path(path), - "body": body, - "fields": fields, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + response = await session.patch( + url=url, + headers=utils.generate_headers(token=token), + params={ + "path": utils.parse_path(path), + "body": body, + "fields": fields, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response -async def mkdir(token: str, path: str, fields: str = "", timeout: int = 30) -> httpx.Response: +async def mkdir(token: str, path: str, session: ClientSession = None, fields: str = "", + timeout: int = 30) -> ClientResponse: """ Create a new directory on the disk. @@ -123,26 +147,33 @@ async def mkdir(token: str, path: str, fields: str = "", timeout: int = 30) -> h - timeout (int, optional): The timeout for the request in seconds. Defaults to 30. Returns: - - httpx.Response: The response from the server after the creation operation. + - ClientResponse: The response from the server after the creation operation. """ url = BASE_URL - async with httpx.AsyncClient() as client: - response = await client.put( - url=url, - headers=utils.generate_headers(token=token), - params={ - "path": utils.parse_path(path), - "fields": fields, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + response = await session.put( + url=url, + headers=utils.generate_headers(token=token), + params={ + "path": utils.parse_path(path), + "fields": fields, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response -async def copy(token: str, from_path: str, to_path: str, fields: str = "", force_async: bool = False, - overwrite: bool = False, timeout: int = 30) -> httpx.Response: +async def copy(token: str, from_path: str, to_path: str, session: ClientSession = None, fields: str = "", + force_async: bool = False, overwrite: bool = False, timeout: int = 30) -> ClientResponse: """ Copy a file or directory from one location to another on the disk. @@ -156,28 +187,39 @@ async def copy(token: str, from_path: str, to_path: str, fields: str = "", force - timeout (int, optional): The timeout for the request in seconds. Defaults to 30. Returns: - - httpx.Response: The response from the server after the copy operation. + - ClientResponse: The response from the server after the copy operation. """ url = BASE_URL + "/copy" - async with httpx.AsyncClient() as client: - response = await client.post( - url=url, - headers=utils.generate_headers(token=token), - params={ - "from": utils.parse_path(from_path), - "path": utils.parse_path(to_path), - "fields": fields, - "force_async": force_async, - "overwrite": overwrite, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + force_async = "true" if force_async else "false" + overwrite = "true" if overwrite else "false" + + response = await session.post( + url=url, + headers=utils.generate_headers(token=token), + params={ + "from": utils.parse_path(from_path), + "path": utils.parse_path(to_path), + "fields": fields, + "force_async": force_async, + "overwrite": overwrite, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response -async def get_url(token: str, path: str, fields: str = "", timeout: int = 30) -> httpx.Response: +async def get_url(token: str, path: str, session: ClientSession = None, fields: str = "", + timeout: int = 30) -> ClientResponse: """ Get the download URL for a file or directory on the disk. @@ -188,26 +230,34 @@ async def get_url(token: str, path: str, fields: str = "", timeout: int = 30) -> - timeout (int, optional): The timeout for the request in seconds. Defaults to 30. Returns: - - httpx.Response: The response from the server containing the download URL for the file or directory. + - ClientResponse: The response from the server containing the download URL for the file or directory. """ url = BASE_URL + "/download" - async with httpx.AsyncClient() as client: - response = await client.get( - url=url, - headers=utils.generate_headers(token=token), - params={ - "path": utils.parse_path(path), - "fields": fields, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + response = await session.get( + url=url, + headers=utils.generate_headers(token=token), + params={ + "path": utils.parse_path(path), + "fields": fields, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response -async def get_all_files(token: str, fields: str = "", media_type: str = "", preview_size: str = "", sort: str = "", - preview_crop: bool = False, limit: int = 100, offset: int = 0, timeout: int = 30) -> httpx.Response: +async def get_all_files(token: str, session: ClientSession = None, fields: str = "", media_type: str = "", + preview_size: str = "", sort: str = "", preview_crop: bool = False, limit: int = 100, + offset: int = 0, timeout: int = 30) -> ClientResponse: """ Get a list of all files and directories on the disk. @@ -223,31 +273,41 @@ async def get_all_files(token: str, fields: str = "", media_type: str = "", prev - timeout (int, optional): The timeout for the request in seconds. Defaults to 30. Returns: - - httpx.Response: The response from the server containing a list of all files and directories. + - ClientResponse: The response from the server containing a list of all files and directories. """ url = BASE_URL + "/files" - async with httpx.AsyncClient() as client: - response = await client.get( - url=url, - headers=utils.generate_headers(token=token), - params={ - "fields": fields, - "media_type": media_type, - "preview_size": preview_size, - "sort": sort, - "preview_crop": preview_crop, - "limit": limit, - "offset": offset, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + preview_crop = "true" if preview_crop else "false" + + response = await session.get( + url=url, + headers=utils.generate_headers(token=token), + params={ + "fields": fields, + "media_type": media_type, + "preview_size": preview_size, + "sort": sort, + "preview_crop": preview_crop, + "limit": limit, + "offset": offset, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response -async def get_last_uploads(token: str, fields: str = "", media_type: str = "", preview_size: str = "", - preview_crop: bool = False, limit: int = 100, timeout: int = 30) -> httpx.Response: +async def get_last_uploads(token: str, session: ClientSession = None, fields: str = "", media_type: str = "", + preview_size: str = "", preview_crop: bool = False, limit: int = 100, + timeout: int = 30) -> ClientResponse: """ Get a list of the last uploaded files and directories on the disk. @@ -261,31 +321,38 @@ async def get_last_uploads(token: str, fields: str = "", media_type: str = "", p - timeout (int, optional): The timeout for the request in seconds. Defaults to 30. Returns: - - httpx.Response: The response from the server containing a list of the last uploaded files and directories. + - ClientResponse: The response from the server containing a list of the last uploaded files and directories. """ url = BASE_URL + "/last-uploaded" - async with httpx.AsyncClient() as client: - response = await client.get( - url=url, - headers=utils.generate_headers(token=token), - params={ - "fields": fields, - "media_type": media_type, - "preview_size": preview_size, - "preview_crop": preview_crop, - "limit": limit, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + preview_crop = "true" if preview_crop else "false" + + response = await session.get( + url=url, + headers=utils.generate_headers(token=token), + params={ + "fields": fields, + "media_type": media_type, + "preview_size": preview_size, + "preview_crop": preview_crop, + "limit": limit, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response - - -async def move(token: str, from_path: str, to_path: str, fields: str = "", force_async: bool = False, - overwrite: bool = False, timeout: int = 30) -> httpx.Response: +async def move(token: str, from_path: str, to_path: str, session: ClientSession = None, fields: str = "", + force_async: bool = False, overwrite: bool = False, timeout: int = 30) -> ClientResponse: """ Move a file or directory from one location to another on the disk. @@ -299,31 +366,40 @@ async def move(token: str, from_path: str, to_path: str, fields: str = "", force - timeout (int, optional): The timeout for the request in seconds. Defaults to 30. Returns: - - httpx.Response: The response from the server after the move operation. + - ClientResponse: The response from the server after the move operation. """ url = BASE_URL + "/move" - async with httpx.AsyncClient() as client: - response = await client.post( - url=url, - headers=utils.generate_headers(token=token), - params={ - "from": utils.parse_path(from_path), - "path": utils.parse_path(to_path), - "fields": fields, - "force_async": force_async, - "overwrite": overwrite, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + force_async = "true" if force_async else "false" + overwrite = "true" if overwrite else "false" + + response = await session.post( + url=url, + headers=utils.generate_headers(token=token), + params={ + "from": utils.parse_path(from_path), + "path": utils.parse_path(to_path), + "fields": fields, + "force_async": force_async, + "overwrite": overwrite, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response - - -async def get_all_public(token: str, fields: str = "", preview_size: str = "", type_filter: str = "", - preview_crop: bool = False, limit: int = 100, offset: int = 0, timeout: int = 30) -> httpx.Response: +async def get_all_public(token: str, session: ClientSession = None, fields: str = "", preview_size: str = "", + type_filter: str = "", preview_crop: bool = False, limit: int = 100, offset: int = 0, + timeout: int = 30) -> ClientResponse: """ Get a list of all public files and directories on the disk. @@ -338,32 +414,39 @@ async def get_all_public(token: str, fields: str = "", preview_size: str = "", t - timeout (int, optional): The timeout for the request in seconds. Defaults to 30. Returns: - - httpx.Response: The response from the server containing a list of all public files and directories. + - ClientResponse: The response from the server containing a list of all public files and directories. """ url = BASE_URL + "/public" - async with httpx.AsyncClient() as client: - response = await client.get( - url=url, - headers=utils.generate_headers(token=token), - params={ - "fields": fields, - "preview_size": preview_size, - "type_filter": type_filter, - "preview_crop": preview_crop, - "limit": limit, - "offset": offset, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + preview_crop = "true" if preview_crop else "false" + + response = await session.get( + url=url, + headers=utils.generate_headers(token=token), + params={ + "fields": fields, + "preview_size": preview_size, + "type_filter": type_filter, + "preview_crop": preview_crop, + "limit": limit, + "offset": offset, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response - - -async def publish(token: str, path: str, body: dict, fields: str = "", allow_address_access: bool = False, - timeout: int = 30) -> httpx.Response: +async def publish(token: str, path: str, body: dict, session: ClientSession = None, fields: str = "", + allow_address_access: bool = False, timeout: int = 30) -> ClientResponse: """ Publish a file or directory on the disk. @@ -376,29 +459,37 @@ async def publish(token: str, path: str, body: dict, fields: str = "", allow_add - timeout (int, optional): The timeout for the request in seconds. Defaults to 30. Returns: - - httpx.Response: The response from the server after the publish operation. + - ClientResponse: The response from the server after the publish operation. """ url = BASE_URL + "/publish" - async with httpx.AsyncClient() as client: - response = await client.put( - url=url, - headers=utils.generate_headers(token=token), - params={ - "path": utils.parse_path(path), - "body": body, - "fields": fields, - "allow_address_access": allow_address_access, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + allow_address_access = "true" if allow_address_access else "false" + + response = await session.put( + url=url, + headers=utils.generate_headers(token=token), + params={ + "path": utils.parse_path(path), + "body": body, + "fields": fields, + "allow_address_access": allow_address_access, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response - - -async def unpublish(token: str, path: str, fields: str = "", timeout: int = 30) -> httpx.Response: +async def unpublish(token: str, path: str, session: ClientSession = None, fields: str = "", + timeout: int = 30) -> ClientResponse: """ Unpublish a file or directory on the disk. @@ -409,27 +500,33 @@ async def unpublish(token: str, path: str, fields: str = "", timeout: int = 30) - timeout (int, optional): The timeout for the request in seconds. Defaults to 30. Returns: - - httpx.Response: The response from the server after the unpublish operation. + - ClientResponse: The response from the server after the unpublish operation. """ url = BASE_URL + "/unpublish" - async with httpx.AsyncClient() as client: - response = await client.put( - url=url, - headers=utils.generate_headers(token=token), - params={ - "path": utils.parse_path(path), - "fields": fields, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + response = await session.put( + url=url, + headers=utils.generate_headers(token=token), + params={ + "path": utils.parse_path(path), + "fields": fields, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response - - -async def get_upload_url(token: str, path: str, fields: str = "", overwrite: bool = False, timeout: int = 30) -> httpx.Response: +async def get_upload_url(token: str, path: str, session: ClientSession = None, fields: str = "", + overwrite: bool = False, timeout: int = 30) -> ClientResponse: """ Get the upload URL for a file or directory on the disk. @@ -441,28 +538,36 @@ async def get_upload_url(token: str, path: str, fields: str = "", overwrite: boo - timeout (int, optional): The timeout for the request in seconds. Defaults to 30. Returns: - - httpx.Response: The response from the server containing the upload URL for the file or directory. + - ClientResponse: The response from the server containing the upload URL for the file or directory. """ url = BASE_URL + "/upload" - async with httpx.AsyncClient() as client: - response = await client.get( - url=url, - headers=utils.generate_headers(token=token), - params={ - "path": utils.psarse_path(path), - "fields": fields, - "overwrite": overwrite, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + overwrite = "true" if overwrite else "false" + + response = await session.get( + url=url, + headers=utils.generate_headers(token=token), + params={ + "path": utils.parse_path(path), + "fields": fields, + "overwrite": overwrite, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response - - -async def upload(token: str, path: str, upload_url: str, fields: str = "", disable_redirects: bool = False, timeout: int = 30) -> httpx.Response: +async def upload(token: str, path: str, upload_url: str, session: ClientSession = None, fields: str = "", + disable_redirects: bool = False, timeout: int = 30) -> ClientResponse: """ Upload a file or directory to the disk. @@ -475,23 +580,30 @@ async def upload(token: str, path: str, upload_url: str, fields: str = "", disab - timeout (int, optional): The timeout for the request in seconds. Defaults to 30. Returns: - - httpx.Response: The response from the server after the upload operation. + - ClientResponse: The response from the server after the upload operation. """ url = BASE_URL + "/upload" - async with httpx.AsyncClient() as client: - response = await client.post( - url=url, - headers=utils.generate_headers(token=token), - params={ - "path": utils.parse_path(path), - "url": upload_url, - "fields": fields, - "disable_redirects": disable_redirects, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + disable_redirects = "true" if disable_redirects else "false" + + response = await session.post( + url=url, + headers=utils.generate_headers(token=token), + params={ + "path": utils.parse_path(path), + "url": upload_url, + "fields": fields, + "disable_redirects": disable_redirects, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response - - diff --git a/yndx_disk/api/trash_resources.py b/yndx_disk/api/trash_resources.py index 5cf0f0a..2919f3b 100644 --- a/yndx_disk/api/trash_resources.py +++ b/yndx_disk/api/trash_resources.py @@ -1,11 +1,12 @@ -import httpx -import yndx_disk.api.utils as utils +from aiohttp import ClientSession, ClientResponse +import yndx_disk.api.utils as utils BASE_URL = "https://cloud-api.yandex.net/v1/disk/trash/resources" -async def delete(token: str, fields: str = "", path: str = "", force_async: bool = False, timeout: int = 30) -> httpx.Response: +async def delete(token: str, session: ClientSession = None, fields: str = "", path: str = "", force_async: bool = False, + timeout: int = 30) -> ClientResponse: """ Empty the trash on the server. @@ -21,8 +22,13 @@ async def delete(token: str, fields: str = "", path: str = "", force_async: bool """ url = BASE_URL - async with httpx.AsyncClient() as client: - response = await client.delete( + if not session: + session = ClientSession() + + force_async = "true" if force_async else "false" + + async with session: + response = await session.delete( url=url, headers=utils.generate_headers(token=token), params={ @@ -36,9 +42,9 @@ async def delete(token: str, fields: str = "", path: str = "", force_async: bool return response - -async def get_info(token: str, path: str, fields: str = "", preview_size: str = "", sort: str = "", - preview_crop: bool = False, limit: int = 100, offset: int = 0, timeout: int = 30) -> httpx.Response: +async def get_info(token: str, path: str, session: ClientSession = None, fields: str = "", preview_size: str = "", + sort: str = "", preview_crop: bool = False, limit: int = 100, offset: int = 0, + timeout: int = 30) -> ClientResponse: """ Get the content of the trash on the server. @@ -58,8 +64,13 @@ async def get_info(token: str, path: str, fields: str = "", preview_size: str = """ url = BASE_URL - async with httpx.AsyncClient() as client: - response = await client.get( + if not session: + session = ClientSession() + + preview_crop = "true" if preview_crop else "false" + + async with session: + response = await session.get( url=url, headers=utils.generate_headers(token=token), params={ @@ -77,8 +88,8 @@ async def get_info(token: str, path: str, fields: str = "", preview_size: str = return response -async def restore(token: str, path: str, fields: str = "", name: str = "", force_async: bool = False, - overwrite: bool = False, timeout: int = 30) -> httpx.Response: +async def restore(token: str, path: str, session: ClientSession = None, fields: str = "", name: str = "", + force_async: bool = False, overwrite: bool = False, timeout: int = 30) -> ClientResponse: """ Restore a file or directory from the trash on the server. @@ -96,19 +107,28 @@ async def restore(token: str, path: str, fields: str = "", name: str = "", force """ url = BASE_URL + "/restore" - async with httpx.AsyncClient() as client: - response = await client.put( - url=url, - headers=utils.generate_headers(token=token), - params={ - "path": "" if not path else utils.parse_path(path, "trash:/"), - "fields": fields, - "name": name, - "force_async": force_async, - "overwrite": overwrite, - }, - timeout=timeout - ) + close_session = False + if not session: + session = ClientSession() + close_session = True + + force_async = "true" if force_async else "false" + overwrite = "true" if overwrite else "false" + + response = await session.put( + url=url, + headers=utils.generate_headers(token=token), + params={ + "path": "" if not path else utils.parse_path(path, "trash:/"), + "fields": fields, + "name": name, + "force_async": force_async, + "overwrite": overwrite, + }, + timeout=timeout + ) + + if close_session: + await session.close() return response - diff --git a/yndx_disk/api/utils.py b/yndx_disk/api/utils.py index 2c8a50a..f847e25 100644 --- a/yndx_disk/api/utils.py +++ b/yndx_disk/api/utils.py @@ -1,13 +1,11 @@ from pathlib import Path - DEFAULT_HEADERS = { "Accept": "application/json", "Authorization": "OAuth {token}", } - def generate_headers(token: str) -> dict: headers = DEFAULT_HEADERS.copy() @@ -17,7 +15,7 @@ def generate_headers(token: str) -> dict: def parse_path(path: str, prefix: str = "disk:/") -> str: - path = str(Path(path)) # Some kind of check is path valid or not =P + path = str(Path(path)) # Some kind of check is path valid or not =P if path.startswith("/"): path = prefix + path[1:] @@ -25,5 +23,3 @@ def parse_path(path: str, prefix: str = "disk:/") -> str: path = prefix + path return path - - diff --git a/yndx_disk/clients/async_client.py b/yndx_disk/clients/async_client.py index e12384d..deff43a 100644 --- a/yndx_disk/clients/async_client.py +++ b/yndx_disk/clients/async_client.py @@ -1,4 +1,4 @@ -import httpx +from aiohttp import ClientSession import yndx_disk.api.disk as api_disk import yndx_disk.api.resources as api_resources @@ -13,8 +13,7 @@ from yndx_disk.classes import File, Directory import asyncio import aiofiles import os - -from pprint import pprint +import atexit class AsyncDiskClient: @@ -55,7 +54,9 @@ class AsyncDiskClient: revision: int = None - def __init__(self, token: str, auto_update_info: bool = True): + session: ClientSession = None + + def __init__(self, token: str, auto_update_info: bool = True, session: ClientSession = None): """ Initialize an instance of the AsyncDiskClient class. @@ -69,6 +70,22 @@ class AsyncDiskClient: self.token = token self.auto_update_info = auto_update_info + if not session: + loop = asyncio.get_running_loop() + session = ClientSession(loop=loop) + self.session = session + + atexit.register(self._cleanup) + + def _cleanup(self) -> None: + """ + Cleanup on exit. + """ + loop = asyncio.get_running_loop() + loop.run_until_complete(self.session.close()) + + def __del__(self) -> None: + self._cleanup() async def _wait_for_operation_to_finish(self, operation_id: str) -> bool: """ @@ -82,13 +99,16 @@ class AsyncDiskClient: Returns: - bool: True if the operation is successful, False otherwise. """ - operation_status_response = await api_operations.get_operation_status(self.token, operation_id) - operation_status_response_json = operation_status_response.json() + operation_status_response = await api_operations.get_operation_status(token=self.token, + operation_id=operation_id, + session=self.session) + operation_status_response_json = await operation_status_response.json() operation_status = False if operation_status_response_json.get("status", "") == "in-progress" else True while not operation_status: - operation_status_response = await api_operations.get_operation_status(self.token, operation_id) - operation_status_response_json = operation_status_response.json() + operation_status_response = await api_operations.get_operation_status(self.token, operation_id, + self.session) + operation_status_response_json = await operation_status_response.json() operation_status = False if operation_status_response_json.get("status", "") == "in-progress" else True await asyncio.sleep(0.1) @@ -98,7 +118,6 @@ class AsyncDiskClient: return True - async def update_disk_info(self) -> None: """ Update the disk information for the client. @@ -108,11 +127,11 @@ class AsyncDiskClient: Returns: - None """ - response = await api_disk.get_disk_info(self.token) - response_json = response.json() + response = await api_disk.get_disk_info(token=self.token, session=self.session) + response_json = await response.json() - if response.status_code != 200: - raise api_exceptions.YandexDiskAPIException(response.status_code, response_json.get("description", "")) + if response.status != 200: + raise api_exceptions.YandexDiskAPIException(response.status, response_json.get("description", "")) self.user = response_json.get("user", {}) self.system_folders = response_json.get("system_folders", {}) @@ -148,48 +167,48 @@ class AsyncDiskClient: Raises: - YandexDiskAPIException: If the request fails or if the object type cannot be determined. """ - response = await api_resources.get_info(self.token, path, limit=0) + response = await api_resources.get_info(token=self.token, path=path, session=self.session, limit=0) - response_json = response.json() + response_json = await response.json() - if response.status_code != 200: - raise api_exceptions.YandexDiskAPIException(response.status_code, response_json.get("description", "")) + if response.status != 200: + raise api_exceptions.YandexDiskAPIException(response.status, response_json.get("description", "")) object_type = response_json.get("type", "") match object_type: case "file": - return File( - token=self.token, - created_at=response_json.get("created", ""), - modified_at=response_json.get("modified", ""), - name=response_json.get("name", ""), - path=response_json.get("path", ""), - resource_id=response_json.get("resource_id", ""), - revision=response_json.get("revision", 0), - public_key=response_json.get("public_key", ""), - public_url=response_json.get("public_url", ""), - antivirus_status=response_json.get("antivirus_status", ""), - file_url=response_json.get("file", ""), - preview_url=response_json.get("preview", ""), - md5=response_json.get("md5", ""), - sha256=response_json.get("sha256", ""), - media_type=response_json.get("media_type", ""), - mime_type=response_json.get("mime_type", ""), - size=response_json.get("size", 0), - ) + return File( + token=self.token, + created_at=response_json.get("created", ""), + modified_at=response_json.get("modified", ""), + name=response_json.get("name", ""), + path=response_json.get("path", ""), + resource_id=response_json.get("resource_id", ""), + revision=response_json.get("revision", 0), + public_key=response_json.get("public_key", ""), + public_url=response_json.get("public_url", ""), + antivirus_status=response_json.get("antivirus_status", ""), + file_url=response_json.get("file", ""), + preview_url=response_json.get("preview", ""), + md5=response_json.get("md5", ""), + sha256=response_json.get("sha256", ""), + media_type=response_json.get("media_type", ""), + mime_type=response_json.get("mime_type", ""), + size=response_json.get("size", 0), + ) case "dir": - return Directory( - token=self.token, - created_at=response_json.get("created", ""), - modified_at=response_json.get("modified", ""), - name=response_json.get("name", ""), - path=response_json.get("path", ""), - resource_id=response_json.get("resource_id", ""), - revision=response_json.get("revision", 0), - public_key=response_json.get("public_key", ""), - public_url=response_json.get("public_url", ""), - ) + return Directory( + token=self.token, + created_at=response_json.get("created", ""), + modified_at=response_json.get("modified", ""), + name=response_json.get("name", ""), + path=response_json.get("path", ""), + resource_id=response_json.get("resource_id", ""), + revision=response_json.get("revision", 0), + public_key=response_json.get("public_key", ""), + public_url=response_json.get("public_url", ""), + ) case _: raise api_exceptions.YandexDiskAPIException(f"Could not determine object type {path}") @@ -210,12 +229,13 @@ class AsyncDiskClient: Raises: - YandexDiskAPIException: If the request fails or if the object type cannot be determined. """ - response = await api_resources.get_info(self.token, path=path, limit=limit, offset=offset) + response = await api_resources.get_info(token=self.token, session=self.session, path=path, limit=limit, + offset=offset) - response_json = response.json() + response_json = await response.json() - if response.status_code != 200: - raise api_exceptions.YandexDiskAPIException(response.status_code, response_json.get("description", "")) + if response.status != 200: + raise api_exceptions.YandexDiskAPIException(response.status, response_json.get("description", "")) embedded_items = response_json.get("_embedded", {}).get("items", []) directory_contents = [] @@ -283,12 +303,13 @@ class AsyncDiskClient: Raises: - YandexDiskAPIException: If the request fails or if the operation fails. """ - response = await api_resources.delete(self.token, path=path, force_async=True, permanently=permanently) + response = await api_resources.delete(token=self.token, session=self.session, path=path, force_async=True, + permanently=permanently) - response_json = response.json() + response_json = await response.json() - if response.status_code != 202: - raise api_exceptions.YandexDiskAPIException(response.status_code, response_json.get("description", "")) + if response.status != 202: + raise api_exceptions.YandexDiskAPIException(response.status, response_json.get("description", "")) href = response_json.get("href", "") operation_id = href.split("/")[-1] @@ -317,12 +338,13 @@ class AsyncDiskClient: Raises: - YandexDiskAPIException: If the request fails or if the operation fails. """ - response = await api_resources.move(self.token, source_path, destination_path, force_async=True, overwrite=overwrite) + response = await api_resources.move(token=self.token, session=self.session, from_path=source_path, + to_path=destination_path, force_async=True, overwrite=overwrite) - response_json = response.json() + response_json = await response.json() - if response.status_code != 202: - raise api_exceptions.YandexDiskAPIException(response.status_code, response_json.get("description", "")) + if response.status != 202: + raise api_exceptions.YandexDiskAPIException(response.status, response_json.get("description", "")) href = response_json.get("href", "") operation_id = href.split("/")[-1] @@ -348,13 +370,13 @@ class AsyncDiskClient: Raises: - YandexDiskAPIException: If the request fails or if the operation fails. """ - response = await api_resources.copy(self.token, source_path, destination_path, force_async=True, - overwrite=overwrite) + response = await api_resources.copy(token=self.token, session=self.session, from_path=source_path, + to_path=destination_path, force_async=True, overwrite=overwrite) - response_json = response.json() + response_json = await response.json() - if response.status_code != 202: - raise api_exceptions.YandexDiskAPIException(response.status_code, response_json.get("description", "")) + if response.status != 202: + raise api_exceptions.YandexDiskAPIException(response.status, response_json.get("description", "")) href = response_json.get("href", "") operation_id = href.split("/")[-1] @@ -386,33 +408,33 @@ class AsyncDiskClient: body = { "public_settings": { "read_only": False, - "external_organization_id_verbose": { - "enabled": False, - "value": "" - }, - "password_verbose": { - "enabled": False, - "value": "" - }, - "available_until": False, - "accesses": [ - {} - ], - "available_until_verbose": { - "enabled": False, - "value": 0 - }, - "password": "", - "external_organization_id": "" - } + "external_organization_id_verbose": { + "enabled": False, + "value": "" + }, + "password_verbose": { + "enabled": False, + "value": "" + }, + "available_until": False, + "accesses": [ + {} + ], + "available_until_verbose": { + "enabled": False, + "value": 0 + }, + "password": "", + "external_organization_id": "" + } } - response = await api_resources.publish(self.token, path, body) + response = await api_resources.publish(token=self.token, session=self.session, path=path, body=body) - response_json = response.json() + response_json = await response.json() - if response.status_code != 200: - raise api_exceptions.YandexDiskAPIException(response.status_code, response_json.get("description", "")) + if response.status != 200: + raise api_exceptions.YandexDiskAPIException(response.status, response_json.get("description", "")) if return_public_url: obj: File | Directory = await self.get_object(path) @@ -433,12 +455,12 @@ class AsyncDiskClient: Raises: - YandexDiskAPIException: If the request fails. """ - response = await api_resources.unpublish(self.token, path) + response = await api_resources.unpublish(token=self.token, session=self.session, path=path) - response_json = response.json() + response_json = await response.json() - if response.status_code != 200: - raise api_exceptions.YandexDiskAPIException(response.status_code, response_json.get("description", "")) + if response.status != 200: + raise api_exceptions.YandexDiskAPIException(response.status, response_json.get("description", "")) async def upload_file(self, file_path: str, path: str, overwrite: bool = False, chunk_size: int = 1024) -> None: """ @@ -469,12 +491,13 @@ class AsyncDiskClient: elif file_size > self.max_file_size: raise api_exceptions.YandexDiskAPIException(f"File {file_path} is too large.") - response = await api_resources.get_upload_url(self.token, path, overwrite=overwrite) + response = await api_resources.get_upload_url(token=self.token, session=self.session, path=path, + overwrite=overwrite) - response_json = response.json() + response_json = await response.json() - if response.status_code != 200: - raise api_exceptions.YandexDiskAPIException(response.status_code, response_json.get("description", "")) + if response.status != 200: + raise api_exceptions.YandexDiskAPIException(response.status, response_json.get("description", "")) operation_id = response_json.get("operation_id", "") upload_url = response_json.get("href", "") @@ -484,20 +507,16 @@ class AsyncDiskClient: while chunk := await file_.read(chunk_size_): yield chunk - async with httpx.AsyncClient() as client: - async with client.stream("PUT", url=upload_url, data=chunked_file_reader(file_path, chunk_size)) as upload_response: - await upload_response.aread() + upload_response = await self.session.put(url=upload_url, data=chunked_file_reader(file_path, chunk_size)) - match upload_response.status_code: - case 201: - if self.auto_update_info: - await self.update_disk_info() - case 202: - await self._wait_for_operation_to_finish(operation_id) - if self.auto_update_info: - await self.update_disk_info() - case _: - raise api_exceptions.YandexDiskAPIException(upload_response.status_code, upload_response.text) + upload_response_json = await upload_response.json() + + if upload_response.status != 202: + raise api_exceptions.YandexDiskAPIException(upload_response.status, + upload_response_json.get("description", "")) + + if self.auto_update_info: + await self.update_disk_info() async def get_url(self, path: str = "/") -> str: """ @@ -514,12 +533,12 @@ class AsyncDiskClient: Raises: - YandexDiskAPIException: If the request fails (status code other than 200). """ - response = await api_resources.get_url(self.token, path) + response = await api_resources.get_url(token=self.token, session=self.session, path=path) - response_json = response.json() + response_json = await response.json() - if response.status_code != 200: - raise api_exceptions.YandexDiskAPIException(response.status_code, response_json.get("description", "")) + if response.status != 200: + raise api_exceptions.YandexDiskAPIException(response.status, response_json.get("description", "")) return response_json.get("href", "") @@ -540,12 +559,13 @@ class AsyncDiskClient: Raises: - YandexDiskAPIException: If the request fails or if the object type cannot be determined. """ - response = await api_trash_resources.get_info(self.token, path=path, limit=limit, offset=offset) + response = await api_trash_resources.get_info(token=self.token, session=self.session, path=path, limit=limit, + offset=offset) - response_json = response.json() + response_json = await response.json() - if response.status_code != 200: - raise api_exceptions.YandexDiskAPIException(response.status_code, response_json.get("description", "")) + if response.status != 200: + raise api_exceptions.YandexDiskAPIException(response.status, response_json.get("description", "")) embedded_items = response_json.get("_embedded", {}).get("items", []) directory_contents = [] @@ -614,12 +634,12 @@ class AsyncDiskClient: Raises: - YandexDiskAPIException: If the request fails or if the operation fails. """ - response = await api_trash_resources.delete(self.token, path=path, force_async=True) + response = await api_trash_resources.delete(token=self.token, session=self.session, path=path, force_async=True) - response_json = response.json() + response_json = await response.json() - if response.status_code != 202: - raise api_exceptions.YandexDiskAPIException(response.status_code, response_json.get("description", "")) + if response.status != 202: + raise api_exceptions.YandexDiskAPIException(response.status, response_json.get("description", "")) href = response_json.get("href", "") operation_id = href.split("/")[-1] @@ -648,12 +668,13 @@ class AsyncDiskClient: Raises: - YandexDiskAPIException: If the request fails or if the operation fails. """ - response = await api_trash_resources.restore(self.token, path, name=new_name, overwrite=overwrite, force_async=True) + response = await api_trash_resources.restore(token=self.token, session=self.session, path=path, name=new_name, + overwrite=overwrite, force_async=True) - response_json = response.json() + response_json = await response.json() - if response.status_code != 202: - raise api_exceptions.YandexDiskAPIException(response.status_code, response_json.get("description", "")) + if response.status != 202: + raise api_exceptions.YandexDiskAPIException(response.status, response_json.get("description", "")) href = response_json.get("href", "") operation_id = href.split("/")[-1] diff --git a/yndx_disk/clients/sync_client.py b/yndx_disk/clients/sync_client.py index 4d40c99..f3fcc14 100644 --- a/yndx_disk/clients/sync_client.py +++ b/yndx_disk/clients/sync_client.py @@ -1,51 +1,58 @@ +import asyncio +from aiohttp import ClientSession + from yndx_disk.classes import File, Directory from yndx_disk.clients.async_client import AsyncDiskClient -import asyncio - class DiskClient(AsyncDiskClient): - def __init__(self, token: str, auto_update_info: bool = True): - super().__init__(token, auto_update_info) + def __init__(self, token: str, auto_update_info: bool = True, session: ClientSession = None): + if not session: + self._loop = asyncio.new_event_loop() + asyncio.set_event_loop(self._loop) + + session = ClientSession(loop=self._loop) + + super().__init__(token, auto_update_info, session=session) + + def _cleanup(self) -> None: + self._loop.run_until_complete(self.session.close()) def update_disk_info(self) -> None: - return asyncio.run(super().update_disk_info()) + return self._loop.run_until_complete(super().update_disk_info()) def get_object(self, path: str) -> File | Directory: - return asyncio.run(super().get_object(path)) + return self._loop.run_until_complete(super().get_object(path)) def listdir(self, path: str = "/", limit: int = 100, offset: int = 0) -> list[File | Directory]: - return asyncio.run(super().listdir(path, limit, offset)) + return self._loop.run_until_complete(super().listdir(path, limit, offset)) def delete(self, path: str = "", permanently: bool = False) -> None: - return asyncio.run(super().delete(path, permanently)) + return self._loop.run_until_complete(super().delete(path, permanently)) def move(self, source_path: str, destination_path: str, overwrite: bool = False) -> None: - return asyncio.run(super().move(source_path, destination_path, overwrite)) + return self._loop.run_until_complete(super().move(source_path, destination_path, overwrite)) def copy(self, source_path: str, destination_path: str, overwrite: bool = False) -> None: - return asyncio.run(super().copy(source_path, destination_path, overwrite)) + return self._loop.run_until_complete(super().copy(source_path, destination_path, overwrite)) def publish(self, path: str, return_public_url: bool = False) -> str | None: - return asyncio.run(super().publish(path, return_public_url)) + return self._loop.run_until_complete(super().publish(path, return_public_url)) def unpublish(self, path: str): - return asyncio.run(super().unpublish(path)) + return self._loop.run_until_complete(super().unpublish(path)) def upload_file(self, file_path: str, path: str, overwrite: bool = False, chunk_size: int = 1024) -> None: - return asyncio.run(super().upload_file(file_path, path, overwrite, chunk_size)) + return self._loop.run_until_complete(super().upload_file(file_path, path, overwrite, chunk_size)) def get_url(self, path: str = "/") -> str: - return asyncio.run(super().get_url(path)) + return self._loop.run_until_complete(super().get_url(path)) def listdir_trash(self, path: str = "/", limit: int = 100, offset: int = 0) -> list[File | Directory]: - return asyncio.run(super().listdir_trash(path, limit, offset)) + return self._loop.run_until_complete(super().listdir_trash(path, limit, offset)) def delete_trash(self, path: str = ""): - return asyncio.run(super().delete_trash(path)) + return self._loop.run_until_complete(super().delete_trash(path)) def restore_trash(self, path: str, new_name: str = "", overwrite: bool = False): - return asyncio.run(super().restore_trash(path, new_name, overwrite)) - - - + return self._loop.run_until_complete(super().restore_trash(path, new_name, overwrite))