Example #1
0
def parse_sequence(inputH, rootPath, checkExist):
    """
    Files files from a formatted string with expression (TCL %04d,
    Houdini-style $F4, Nuke's ####) are parsed into full file names and tested
    for existence

    Example input:
     >>> someFile = "some_file_$F2.tiff"
     Generator Object containing...
     some_file_00.tiff some_file_01.tiff some_file_02.tiff some_file_03.tiff
     some_file_04.tiff some_file_05.tiff some_file_06.tiff some_file_07.tiff
     some_file_08.tiff some_file_09.tiff

    Args:
        inputH (str): The file/folder path to parse
        rootPath (str): Used for attempting to resolve relative paths and checking
                        File(s)/Folder(s) for existence
        checkExist (bool): True/False

    Yields:
        str: A generator containing all of the parsed strings found
    """
    matchTest = path_leaf(inputH)
    expansionTest = list(fileSeq.expand_sequence(matchTest))

    if expansionTest[0] is not None:
        matchTest = expansionTest
        dirname = os.path.dirname(inputH)
        for m in matchTest:
            mTest = os.path.normpath(os.path.join(dirname, m))
            if is_relative(mTest):
                mTest = os.path.join(rootPath, mTest)
                mTest = os.path.normpath(mTest)

            # attempt hard join
            if checkExist and (not os.path.isfile(mTest) \
                    or not os.path.isdir(mTest)):
                continue  # skip
            elif os.path.isfile(mTest) or os.path.isdir(mTest):
                LOGGER.info("[+] File/Folder: {f} found from, "
                "{f1}".format(f=mTest, f1=inputH))
            # ::AUTHORNOTE:: add support for strings that aren't yet files/folders
            # for examples, strings that represents files that will be rendered
            # assume
            yield mTest
Example #2
0
def get_expanded_str_from_index(inputH, index):
    """
    Returns a given number from a parseable string
    as an expanded string with correct padding

    .. TODO::
     If time, go back and make this function more memory efficient

    Args:
        inputH (str): The full path to a file or filename
        index (int): The numbered frame to retrieve from the expanded string

    Returns:
        str: The expanded string without any expression or formatted text
    """
    matchTest = path_leaf(inputH)
    expansionTest = list(fileSeq.expand_sequence(matchTest))
    return expansionTest[index]
Example #3
0
def get_expanded_str_from_index(inputH, index):
    """
    Returns a given number from a parseable string
    as an expanded string with correct padding

    .. TODO::
     If time, go back and make this function more memory efficient

    Args:
        inputH (str): The full path to a file or filename
        index (int): The numbered frame to retrieve from the expanded string

    Returns:
        str: The expanded string without any expression or formatted text
    """
    matchTest = path_leaf(inputH)
    expansionTest = list(fileSeq.expand_sequence(matchTest))
    return expansionTest[index]
Example #4
0
def parse_sequence(inputH, rootPath, checkExist):
    """
    Files files from a formatted string with expression (TCL %04d,
    Houdini-style $F4, Nuke's ####) are parsed into full file names and tested
    for existence

    Example input:
     >>> someFile = "some_file_$F2.tiff"
     Generator Object containing...
     some_file_00.tiff some_file_01.tiff some_file_02.tiff some_file_03.tiff
     some_file_04.tiff some_file_05.tiff some_file_06.tiff some_file_07.tiff
     some_file_08.tiff some_file_09.tiff

    Args:
        inputH (str): The file/folder path to parse
        rootPath (str): Used for attempting to resolve relative paths and checking
                        File(s)/Folder(s) for existence
        checkExist (bool): True/False

    Yields:
        str: A generator containing all of the parsed strings found
    """
    matchTest = path_leaf(inputH)
    expansionTest = list(fileSeq.expand_sequence(matchTest))

    if expansionTest[0] is not None:
        matchTest = expansionTest
        dirname = os.path.dirname(inputH)
        for m in matchTest:
            mTest = os.path.normpath(os.path.join(dirname, m))
            if is_relative(mTest):
                mTest = os.path.join(rootPath, mTest)
                mTest = os.path.normpath(mTest)

            # attempt hard join
            if checkExist and (not os.path.isfile(mTest) \
                    or not os.path.isdir(mTest)):
                continue  # skip
            elif os.path.isfile(mTest) or os.path.isdir(mTest):
                # LOGGER.info("[+] File/Folder: {f} found from, "
                # "{f1}".format(f=mTest, f1=inputH))
            # ::AUTHORNOTE:: add support for strings that aren't yet files/folders
            # for examples, strings that represents files that will be rendered
            # assume
            yield mTest
# end parse_seqence


def is_parseable(string):
    """
    Checks if a file/folder path has text in it that could be considered
    "Able to be parsed" or expanded into a sequence of files

    .. TODO::
     Replace this with a regex that detects if there is ####, $F4, or %04d

    Args:
        string (str): The string to check

    Returns:
        bool: True/False
    """
    if "#" in string:
        return True
    elif "%" in string:
        return True
    elif "$" in string:
        return True
    else:
        return False
# end is_parseable


def replace_sep_with_string(path, inputH):
    """
    Replaces the seperators in a string of text with inputH

    .. Note::
     DEPRECATED in-favor of os.path.normcase()/os.path.normpath()

    Args:
        path (str): The path to replace the separators
        inputH (str or anything): The object to replace separators with

    Returns:
        str: The original path, with eahc of its separators replaced
    """
    matchRe = re.compile(r"//|/|\\*?")  # get all types of separators
    line = matchRe.sub(path, inputH)
    return line
# end replace_sep_with_string


def search_parent_count(string):
    """
    Looks at a relative path and determines how many parent folders back
    the path is refers to, if at all

    Example:
     >>> search_parent_count("../../some/path/foo.bar")
     2

    Args:
        string (str): The (presumably relative path) string to check

    Returns:
        int: The number of parent folders to search back
    """
    reMatch = re.compile(r'(?:\.\./)|(?:\.\.\\)|(?:\./)|(?:\.\\)')
    match = re.findall(reMatch, string)

    if match is None or match == []:
        return None
    elif len(match[0]) == 2:
        return {'match': match[0],
                'count': len(match),
                'is_current_dir': True}
    elif len(match[0]) == 3:
        return {'match': match[0],
                'count': len(match),
                'is_current_dir': False}
# end search_parent_count


def is_current_dir(string):
    """
    Checks if the path has a relative prefix that references
    the current directory

    Args:
        string (str): The filepath that may or may not prefix with ./|.\\

    Returns:
        bool: True/False
    """
    reMatch = re.compile(r'(?:\./)|(?:\.\\)')
    match = re.findall(reMatch, string)

    if search_parent_count(string) is not None and \
       len(search_parent_count(string)['match']) == 3:
        return False  # catch exceptions for ../, ..\, and ..\\
    elif match is None or match == []:
        return False  # nothing found
    else:
        return True  # found ./, .\, or .\\
# end is_current_dir


def is_relative(string):
    """
    OS-Naive method that checks if the current path has a relative prefix

    Args:
        string (str): The filepath to check for relative path markers

    Returns:
        bool: True/False
    """
    _, winfilename = os.path.splitdrive(string)
    if not string.startswith('/') or winfilename != string:
        return True

    if search_parent_count(string) is not None or is_current_dir(string):
        return True
    else:
        return False
# end is_relative


def get_size(startPath='.'):
    """
    Gets size of a folder

    Args:
        startPath (str): The full path that is the base directory of get_size

    Returns:
        int: The total size, in bytes
    """
    totalSize = 0
    for dirpath, dirnames, filenames in os.walk(startPath):
        for f in filenames:
            fp = os.path.join(dirpath, f)
            totalSize += os.path.getsize(fp)
    return totalSize
# end get_size


def get_maya_files(inputH, level, endswith):
    """
    Gets all files that match a certain extension from a list of files
    and folders. Supports recursion

    .. Note::
     Written with Maya files in mind but actually supports any file-type

    Args:
        inputH (str): an iterable which contains full paths to folders
        level (int): The number of subfolders allowed to search for maya files.
                     Set to a large number to mimic the behavior of a fully
                     recursive query (once it reaches the end it will terminate
                     on its own)
        endswith (str or tuple of strs): The file extension to search for.
                                         If you want to return all files, use *

    Yields:
        str: An iterable of full paths to files
    """
    for entry in inputH:
        if os.path.isdir(entry):
            getListings = walk_level(entry, level)
            files = list(getListings)
            files = [f for f in files if os.path.isfile(f)]
            files = [f for f in files if f.endswith(endswith)]
        elif os.path.isfile(entry):
            files = [entry]
        else:
            temp = '[-] The following input, "{f}", is not a valid '\
                   'file or folder'.format(f=f)
            # LOGGER.error(temp)

        for f in files:
            yield f
# end get_maya_files


# def ignore_paths(path):
#     """
#     Designates which files to ignore in a struct-tree representing
#     file(s)/folder(s). For an example of how it's used, see: :ref:`syncmeister`
#     """
#     def ignoref(p, files):
#         return (f for f in files if os.abspath(os.path.join(p, f)) == path)
#     return ignoref
# # end ignore_paths

def get_common_parent_dir_pair(path1, path2, mustExist=True, mustMatch=True):
    """
    Compares two paths for a common prefix much like os.path.commonprefix() but
    has the additional functionality of checking if the results are not partial
    matches and whether or not the match exists as a file/folder

    Args:
        path1 (str): One of the paths to be compared
        path2 (str): Another path to be compared
        mustExist (bool): Requires that the prefix obtained must actually exist

    Returns:
        bool: True/False
    """
    if len(path1) > len(path2):
        # swap the strings if the user input them out of order
        path1, path2 = path2, path1

    commonPrefix = os.path.commonprefix([path1, path2])
    if commonPrefix == "":
        return None
    elif commonPrefix != "" and not mustMatch and mustExist \
                                              and os.path.exists(commonPrefix):
        return commonPrefix
    elif commonPrefix != "" and not mustExist and not mustMatch:
        return commonPrefix

    _, commonPath = os.path.splitdrive(commonPrefix)
    _, path = os.path.splitdrive(path2)  # only one path is needed for testing

    commonPathSplit = os_path_split_asunder(commonPath)
    pathSplit = os_path_split_asunder(path)

    for index, folder in enumerate(pathSplit):
        # this is a precaution to make sure partial commonprefixes
        if commonPathSplit[-1] == folder:
            return os.path.join(commonPathSplit)
    return None
# end get_common_parent_dir_pair


def has_common_parent_dir(path, comparisonPaths,
                          mustExist=True, mustMatch=True):
    """
    has_common_parent_dir is built for the purpose of determining if a given
    iterable (list or iterable) contains a string that is a parent directory.
    This function was made because os.path.commonprefix() frequently returns
    directories starting with "/|\\|\\\\" or a substring of files/folders that
    don't exist and there's no way to error check it.

    Example of why os.path.commonprefix sucks:
     >>> path1 = "some/directory/within/project.txt"
     >>> path2 = "some/directory/withstanding/project.txt"
     >>> os.path.commonprefix([path1, path2])
     "some/directory/with"  # This is not necessarily a file or folder!

    .. TODO::
     It may be worth doing in the future to remake this as a wrapper function
     to os.path.commonprefix() and simply test if any folder starts with the
     substring match and, if that same matched folder is the [-1] index of the
     checked file(s)/folder(s) it could return True and still do the same thing

    Args:
        path (str): The path that supposedly is the root of all other paths listed
                    in comparisonPaths
        comparisonPaths (iterable of strs): An iterable of paths to check
                                            against path for a common parent
                                            directory

    Returns:
        bool: True/False
    """
    for index, item in enumerate(comparisonPaths):
        # temp paths - remove the instance of path in list
        if path != item:
            hasCommonDir = get_common_parent_dir_pair(path,
                                                      item,
                                                      mustExist=mustExist,
                                                      mustMatch=mustMatch)
            if hasCommonDir is not None:
                break
    else:
        return False

    return True
# end has_common_parent_dir


if __name__ == '__main__':
    print(__doc__)