# -*- coding: utf-8 -*-"""Relative Path implementation."""importtypingasTfrom..importutilsifT.TYPE_CHECKING:# pragma: no coverfrom.s3pathimportS3Path
[docs]classRelativePathAPIMixin:""" A mixin class that implements the relative path concept. """
[docs]@classmethoddefmake_relpath(cls:T.Type["S3Path"],*parts:str,)->"S3Path":""" A construct method that create a relative S3 Path. Definition of relative path: - no bucket (self.bucket is None) - has some parts or no part. when no part, it is a special relative path. Any path add this relative path resulting to itself. We call this special relative path **Void relative path**. A **Void relative path** is logically equivalent to **Void s3 path**. - relative path can be a file (object) or a directory. The **Void relative path** is neither a file or a directory. :param parts: .. versionadded:: 1.0.1 **中文文档** 相对路径的概念是 p1 + p2 = p3, 其中 p1 和 p3 都是实际存在的路径, 而 p2 则是 相对路径. 相对路径的功能是如果 p3 - p1 = p2, 那么 p1 + p2 必须还能等于 p3. 有一个特殊情况是 如果 p1 - p1 = p0, 两个相同的绝对路径之间的相对路径是 p0, 我们还是需要满足 p1 + p0 = p1 以保证逻辑上的一致. """_parts=list()last_non_empty_part=Noneforpartinparts:chunks=utils.split_parts(part)iflen(chunks):last_non_empty_part=partfor_partinchunks:_parts.append(_part)iflen(_parts):_is_dir=last_non_empty_part.endswith("/")else:_is_dir=Nonereturncls._from_parsed_parts(bucket=None,parts=_parts,is_dir=_is_dir,)
[docs]defrelative_to(self:"S3Path",other:"S3Path")->"S3Path":""" Return the relative path to another path. If the operation is not possible (because this is not a sub path of the other path), raise ``ValueError``. ``-`` is a syntax sugar for ``relative_to``. See more information at :meth:`~RelativePathAPIMixin.__sub__`. The relative path usually works with :meth:`~s3pathlib.core.joinpath.JoinPathAPIMixin.joinpath` to form a new path. Or you can use the ``/`` syntax sugar as well. Examples:: >>> S3Path("bucket", "a/b/c").relative_to(S3Path("bucket", "a")).parts ['b', 'c'] >>> S3Path("bucket", "a").relative_to(S3Path("bucket", "a")).parts [] >>> S3Path("bucket", "a").relative_to(S3Path("bucket", "a/b/c")).parts ValueError ... >>> S3Path("bucket") / S3Path("new_bucket/file.txt").relative_to(S3Path("new_bucket")) S3Path('s3://bucket/file.txt') :param other: other :class:`S3Path` instance. :return: a relative path object, which is a special version of S3Path .. versionadded:: 1.0.1 """if((self._bucket!=other._bucket)or(self._bucketisNone)or(other._bucketisNone)):msg=("both 'from path' {} and 'to path' {} has to be concrete path!").format(self,other)raiseValueError(msg)n=len(other._parts)ifself._parts[:n]!=other._parts:msg="{} does not start with {}".format(self.uri,other.uri,)raiseValueError(msg)rel_parts=self._parts[n:]iflen(rel_parts):is_dir=self._is_direlse:is_dir=Nonereturnself._from_parsed_parts(bucket=None,parts=rel_parts,is_dir=is_dir,)
[docs]defis_relpath(self:"S3Path")->bool:""" Relative path is a special path supposed to join with other concrete path. **Definition** A long full path relating to its parent directory is a relative path. A :meth:`void <is_void>` path also a special relative path. .. versionadded:: 1.0.1 """ifself._bucketisNone:iflen(self._parts)==0:ifself._is_dirisNone:returnTrueelse:returnFalseelse:returnTrueelse:returnFalse
def__sub__(self:"S3Path",other:"S3Path")->"S3Path":""" A syntax sugar. Basically ``s3path1 - s3path2`` is equal to ``s3path2.relative_to(s3path1)`` .. versionadded:: 1.0.11 """returnself.relative_to(other)
[docs]defensure_relpath(self:"S3Path")->None:""" A validator method that ensure it represents a S3 relative path. .. versionadded:: 1.2.1 """ifself.is_relpath()isnotTrue:raiseTypeError(f"{self} IS a s3 relative path!")
[docs]defensure_not_relpath(self:"S3Path")->None:""" A validator method that ensure it represents a S3 relative path. Can be used if you want to raise error if it is not a relative path. .. versionadded:: 1.0.1 """ifself.is_relpath()isTrue:raiseTypeError(f"{self} is not a valid s3 relative path!")