async def copy(self, source: Union[str, "os.PathLike[str]"], destination: Union[str, "os.PathLike[str]"], depth: Optional[int] = 1) -> None: """ Copies resource from one place to another on WebDAV server. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_COPY Parameters: source (``str``): The path to resource which will be copied. destination (``str``): the path where resource will be copied. depth (``int``, *optional*): Folder depth to copy. Default is 1 """ urn_from = Urn(source) if not (await self.exists(urn_from.path())): raise RemoteResourceNotFound(urn_from.path()) urn_to = Urn(destination) if not (await self.exists(urn_to.parent())): raise RemoteParentNotFound(urn_to.path()) headers = {"Destination": self._get_url(urn_to.quote())} if (await self.is_directory(urn_from.path())): headers["Depth"] = depth await self._execute_request(action='copy', path=urn_from.quote(), headers_ext=headers)
async def move(self, source: Union[str, "os.PathLike[str]"], destination: Union[str, "os.PathLike[str]"], overwrite: Optional[bool] = False) -> None: """ Moves resource from one place to another on WebDAV server. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_MOVE Parameters: source (``str``): The path to resource which will be moved. destination (``str``): the path where resource will be moved. overwrite (``bool``, *optional*): The flag, overwrite file if it exists. Defaults is False. """ urn_from = Urn(source) if not (await self.exists(urn_from.path())): raise RemoteResourceNotFound(urn_from.path()) urn_to = Urn(destination) if not (await self.exists(urn_to.parent())): raise RemoteParentNotFound(urn_to.path()) headers = { 'Destination': self._get_url(urn_to.quote()), 'Overwrite': ('T' if overwrite else 'F') } await self._execute_request(action='move', path=urn_from.quote(), headers_ext=headers)
async def create_directory(self, path: Union[str, "os.PathLike[str]"]) -> bool: """ Makes new directory on WebDAV server. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_MKCOL Parameters: path (``str``): Path to remote directory. Returns: :obj:`bool`: True if request executed with code 200 or 201 and False otherwise. """ directory_urn = Urn(path, directory=True) if not (await self.exists(directory_urn.parent())): raise RemoteParentNotFound(directory_urn.path()) try: response = await self._execute_request(action='mkdir', path=directory_urn.quote()) except MethodNotSupported: # Yandex WebDAV returns 405 status code when directory already exists return True return response.status in (200, 201)
async def is_directory(self, path: Union[str, "os.PathLike[str]"]) -> bool: """ Checks is the remote resource directory. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_PROPFINDL Parameters: path (``str``): Path to remote directory. Returns: :obj:`bool`: True in case the remote resource is directory and False otherwise. """ urn = Urn(path) parent_urn = Urn(urn.parent()) await self._check_remote_resource(path, urn) response = await self._execute_request(action='info', path=parent_urn.quote()) text = await response.text() path = self.get_full_path(urn) return WebDavXmlUtils.parse_is_dir_response(content=text, path=path, hostname=self._hostname)
async def upload_to( self, path: Union[str, "os.PathLike[str]"], buffer: Union[IO, AsyncGenerator[bytes, None]], buffer_size: Optional[int] = None, progress: Optional[Callable[[int, int, Tuple], None]] = None, progress_args: Optional[Tuple] = () ) -> None: """ Uploads file from buffer to remote path on WebDAV server. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_PUT Parameters: path (``str``): The path to remote resource buffer (``IO``) IO like object to read the data or a asynchronous generator to get buffer data. In order do you select use a async generator `progress` callback cannot be called. progress (``callable``, *optional*): Pass a callback function to view the file transmission progress. The function must take *(current, total)* as positional arguments (look at Other Parameters below for a detailed description) and will be called back each time a new file chunk has been successfully transmitted. progress_args (``tuple``, *optional*): Extra custom arguments for the progress callback function. You can pass anything you need to be available in the progress callback scope. Other Parameters: current (``int``): The amount of bytes transmitted so far. total (``int``): The total size of the file. *args (``tuple``, *optional*): Extra custom arguments as defined in the ``progress_args`` parameter. You can either keep ``*args`` or add every single extra argument in your function signature. Example: .. code-block:: python ... # Keep track of the progress while uploading def progress(current, total): print(f"{current * 100 / total:.1f}%") async with aiofiles.open('file.zip', 'rb') as file: await client.upload_to('/path/to/file.zip', file, progress=progress) ... """ urn = Urn(path) if urn.is_dir(): raise OptionNotValid(name="path", value=path) if not (await self.exists(urn.parent())): raise RemoteParentNotFound(urn.path()) if callable(progress) and not asyncio.iscoroutinefunction(buffer): async def file_sender(buff: IO): current = 0 if asyncio.iscoroutinefunction(progress): await progress(current, buffer_size, *progress_args) else: progress(current, buffer_size, *progress_args) while current < buffer_size: chunk = await buffer.read(self._chunk_size) if isinstance(buffer, AsyncBufferedIOBase) \ else buffer.read(self._chunk_size) if not chunk: break current += len(chunk) if asyncio.iscoroutinefunction(progress): await progress(current, buffer_size, *progress_args) else: progress(current, buffer_size, *progress_args) yield chunk await self._execute_request(action='upload', path=urn.quote(), data=file_sender(buffer)) else: await self._execute_request(action='upload', path=urn.quote(), data=buffer)