maestral.utils.path
This module contains functions for common path operations.
Module Contents
- maestral.utils.path.is_child(path, parent)[source]
Checks if
path
semantically is insideparent
. Neither path needs to refer to an actual item on the drive. This function is case-sensitive.
- maestral.utils.path.is_equal_or_child(path, parent)[source]
Checks if
path
semantically is insideparent
or equalsparent
. Neither path needs to refer to an actual item on the drive. This function is case-sensitive.
- maestral.utils.path.normalize_case(string)[source]
Converts a string to lower case. Todo: Follow Python 2.5 / Dropbox conventions.
- maestral.utils.path.normalize_unicode(string)[source]
Normalizes a string to replace all decomposed unicode characters with their single character equivalents.
- maestral.utils.path.normalize(string)[source]
Replicates the path normalization performed by Dropbox servers. This typically only involves converting the path to lower case, with a few (undocumented) exceptions:
Unicode normalization: decomposed characters are converted to composed characters.
Lower casing of non-ascii characters: Dropbox uses the Python 2.5 behavior for conversion to lower case. This means that some cyrillic characters are incorrectly lower-cased. For example: “Ꙋ”.lower() -> “Ꙋ” instead of “ꙋ” “ΣΣΣ”.lower() -> “σσσ” instead of “σσς”
Trailing spaces are stripped from folder names. We do not perform this normalization here because the Dropbox API will raise sync errors for such names anyways.
Note that calling
normalize()
on an already normalized path will return the unmodified input.Todo: Follow Python 2.5 / Dropbox conventions instead of Python 3 conventions.
- maestral.utils.path.is_fs_case_sensitive(path)[source]
Checks if
path
lies on a partition with a case-sensitive file system.
- maestral.utils.path.get_existing_equivalent_paths(path, root=osp.sep, norm_func=normalize)[source]
Given a “normalized” path using an injective (one-directional) normalization function, this method returns a list of matching un-normalized local paths. If no such local paths exist, list will be empty.
- Example
Assume the normalization function is
str.lower()
. If a root directory contains two folders “/parent/subfolder/child” and “/parent/Subfolder/child”, two matches will be returned for “path = /parent/subfolder/child/file.txt”.- Parameters
path (str) – Normalized path relative to
root
.root (str) – Parent directory to search in. There are significant performance improvements if a root directory with a small tree is given.
norm_func (Callable[[str], str]) – Normalization function to use. Defaults to
normalize()
.
- Returns
List of existing paths for which normalized(local_path) == normalized(path).
- Return type
List[str]
- maestral.utils.path.to_existing_unnormalized_path(path, root=osp.sep, norm_func=normalize)[source]
Returns a cased version of the given path if corresponding nodes (with arbitrary casing) exist in the given root directory. If multiple matches are found, only one is returned.
This is similar to
get_existing_equivalent_paths()
but returns only the first candidate or raises aFileNotFoundError
if no candidates can be found.On macOS, we use fcntl F_GETPATH for a more efficient implementation.
- Parameters
path (str) – Original path relative to
root
.root (str) – Parent directory to search in. There are significant performance improvements if a root directory with a small tree is given.
norm_func (Callable[[str], str]) – Normalization function to use. Defaults to
normalize()
.
- Returns
Absolute and cased version of given path.
- Raises
FileNotFoundError – if
path
does not exist in rootroot
orroot
itself does not exist.- Return type
- maestral.utils.path.normalized_path_exists(path, root=osp.sep)[source]
Checks if a
path
exists in givenroot
directory, similar toos.path.exists
but case-insensitive. Normalisation is performed as by Dropbox servers (lower case and unicode normalisation).
- maestral.utils.path.generate_cc_name(path, suffix='conflicting copy')[source]
Generates a path for a conflicting copy of
path
. The file name is created by inserting the givensuffix
between the filename and the extension. For instance:“my_file.txt” -> “my_file (conflicting copy).txt”
If a file with the resulting path already exists (case-insensitive!), we additionally append an integer number, for instance:
“my_file.txt” -> “my_file (conflicting copy 1).txt”
- maestral.utils.path.delete(path, force_case_sensitive=False, raise_error=False)[source]
Deletes a file or folder at
path
. Symlinks will not be followed.- Parameters
path (str) – Path of item to delete.
force_case_sensitive (bool) – Whether to perform the deletion only if the item appears with the same casing as provided in path. This can be used on case-insensitive but preserving file systems to ensure that the intended item is deleted.
raise_error (bool) – Whether to raise errors or return them.
- Returns
Any caught exception during the deletion.
- Return type
Optional[OSError]
- maestral.utils.path.move(src_path, dest_path, raise_error=False, preserve_dest_permissions=False)[source]
Moves a file or folder from
src_path
todest_path
. If either the source or the destination path no longer exist, this function does nothing. Any other exceptions are either raised or returned ifraise_error
is False.- Parameters
src_path (str) – Path of item to move.
dest_path (str) – Destination path. Any existing file at this path will be replaced by the move. Any existing empty folder will be replaced if the source is also a folder.
raise_error (bool) – Whether to raise errors or return them.
preserve_dest_permissions (bool) – Whether to apply the permissions of the source path to the destination path. Permissions will not be set recursively.
- Returns
Any caught exception during the move.
- Return type
Optional[OSError]
- maestral.utils.path.walk(root, listdir=os.scandir)[source]
Iterates recursively over the content of a folder.
- Parameters
root (str) – Root folder to walk.
listdir (Callable[[str], Iterable[os.DirEntry[str]]]) – Function to call to get the folder content.
- Returns
Iterator over (path, stat) results.
- Return type
Iterator[Tuple[str, os.stat_result]]
- maestral.utils.path.content_hash(local_path, chunk_size=65536)[source]
Computes content hash of a local file.
- maestral.utils.path.fs_max_lengths_for_path(path='/')[source]
Return the maximum length of file names and paths allowed on a file system.
- Parameters
path (str) – Path to check. This can be specified because different paths may be residing on different file systems. If the given path does not exist, the first existing parent directory in the tree be taken.
- Returns
Tuple giving the maximum file name and total path lengths.
- Return type
- maestral.utils.path.opener_no_symlink(path, flags)[source]
Opener that does not follow symlinks. Uses
os.open()
under the hood.
- maestral.utils.path.exists(path)[source]
Returns whether an item exists at the path. Returns True for symlinks.
- Parameters
path (_AnyPath) –
- Return type
- maestral.utils.path.isfile(path)[source]
Returns whether a file exists at the path. Returns True for symlinks.
- Parameters
path (_AnyPath) –
- Return type
- maestral.utils.path.isdir(path)[source]
Returns whether a folder exists at the path. Returns False for symlinks.
- Parameters
path (_AnyPath) –
- Return type