def ensure_filename(filename, yields=False):
    '''Ensures the existence of a file with a given filename.

    If the filename is taken and is not pointing to a file (or a link to a
    file) an OSError is raised.  If `exist_ok` is False the filename must not
    be taken; an OSError is raised otherwise.

    The function creates all directories if needed. See :func:`makedirs` for
    restrictions.

    If `yields` is True, returns the file object.  This way you may open a
    file for writing like this::

      with ensure_filename('/tmp/good-name-87.txt', yields=True) as fh:
          fh.write('Do it!')

    The file is open in mode 'w+b'.

    .. versionadded:: 1.6.1  Added parameter `yield`.

    '''
    if not os.path.exists(filename):
        filename = normalize_path(filename)
        dirname = os.path.dirname(filename)
        makedirs(dirname, exist_ok=True)
        # TODO: Better hanlding of mode for reading/writing.
        fh = open(filename, 'w+b')
        if not yields:
            fh.close()
        else:
            return fh
    else:
        if not os.path.isfile(filename):
            raise OSError('Expected a file but another thing is found \'%s\'' %
                          filename)
def iter_dict_files(top='.', regex=None, wrong=None, followlinks=False):
    '''
    Iterate filenames recursively.

    :param top: The top directory for recurse into.
    :param regex: Regular expression with group definitions to match.
    :param wrong: A key to store full name of not matching files.
    :param followlinks: The same meaning that in `os.walk`.

                        .. versionadded:: 1.2.1

    .. versionadded:: 1.2.0

    '''
    if regex:
        from xoutil.eight import string_types
        if isinstance(regex, string_types):
            regex = _rcompile(regex)
    else:
        regex = _REGEX_DEFAULT_ALLFILES
    for dirpath, _dirs, filenames in os.walk(normalize_path(top),
                                             followlinks=followlinks):
        for filename in filenames:
            path = os.path.join(dirpath, filename)
            match = regex.match(path)
            if match:
                yield match.groupdict()
            elif wrong is not None:
                yield {wrong: path}
Exemple #3
0
def iter_dirs(top='.', pattern=None, regex_pattern=None, shell_pattern=None):
    '''
    Iterate directories recursively.

    The params have analagous meaning that in :func:`iter_files` and the same
    restrictions.
    '''
    regex = _get_regex(pattern, regex_pattern, shell_pattern)
    for path, _dirs, _files in os.walk(normalize_path(top)):
        if (regex is None) or regex.search(path):
            yield path
def rmdirs(top='.', pattern=None, regex_pattern=None, shell_pattern=None,
           exclude=None, confirm=None):
    '''Removes all empty dirs at `top`.

    :param top: The top directory to recurse into.

    :param pattern: A pattern of the dirs you want to remove.
                    It should be a string. If it starts with "(?" it will be
                    regarded as a regular expression, otherwise a shell
                    pattern.

    :param exclude: A pattern of the dirs you DON'T want to remove.  It should
                    be a string. If it starts with "(?" it will be regarded as
                    a regular expression, otherwise a shell pattern. This is a
                    simple commodity to have you not to negate complex
                    patterns.

    :param regex_pattern: An *alternative* to `pattern`. This will always be
                          regarded as a regular expression.

    :param shell_pattern: An *alternative* to `pattern`. This should be a
                          shell pattern.

    :param confirm: A callable that accepts a single argument, which is
                    the path of the directory to be deleted. `confirm`
                    should return True to allow the directory to be
                    deleted. If `confirm` is None, then all matched dirs
                    are deleted.

    .. note:: In order to avoid common mistakes we won't attempt to
              remove mount points.

    .. versionadded:: 1.1.3

    '''
    regex = _get_regex(pattern, regex_pattern, shell_pattern)
    exclude = _get_regex(exclude)
    if confirm is None:
        confirm = lambda _: True
    for path, _dirs, _files in os.walk(normalize_path(top)):
        # XXX: Make clearest next condition
        if ((regex is None or regex.search(path)) and
                (exclude is None or not exclude.search(path)) and
                not _dirs and
                not _files and
                confirm(path) and
                not os.path.ismount(path)):
            os.rmdir(path)
def iter_files(top='.', pattern=None, regex_pattern=None, shell_pattern=None,
               followlinks=False, maxdepth=None):
    '''Iterate filenames recursively.

    :param top: The top directory for recurse into.
    :param pattern: A pattern of the files you want to get from the iterator.
                    It should be a string. If it starts with "(?" it will be
                    regarded as a regular expression, otherwise a shell
                    pattern.

    :param regex_pattern: An *alternative* to `pattern`. This will always be
                          regarded as a regular expression.

    :param shell_pattern: An *alternative* to `pattern`. This should be a
                          shell pattern.

    :param followlinks: The same meaning that in `os.walk`.

                        .. versionadded:: 1.2.1

    :param maxdepth: Only files above this level will be yielded. If None, no
                     limit is placed.

                     .. versionadded:: 1.2.1

    .. warning:: It's an error to pass more than pattern argument.

    '''
    regex = _get_regex(pattern, regex_pattern, shell_pattern)
    depth = 0
    for dirpath, _dirs, filenames in os.walk(normalize_path(top),
                                             topdown=True,
                                             followlinks=followlinks):
        for filename in filenames:
            path = os.path.join(dirpath, filename)
            if (regex is None) or regex.search(path):
                yield path
        if maxdepth is not None:
            depth += 1
            if depth >= maxdepth:
                _dirs[:] = []
def get_module_path(module):
    '''Gets the absolute path of a `module`.

    :param module: Either module object or a (dotted) string for the module.

    :returns: The path of the module.

    If the module is a package, returns the directory path (not the path to the
    ``__init__``).

    If `module` is a string and it's not absolute, raises a TypeError.

    '''
    from importlib import import_module
    from xoutil.fs.path import normalize_path
    from xoutil.eight import string_types as strs
    mod = import_module(module) if isinstance(module, strs) else module
    # The __path__ only exists for packages and does not include the
    # __init__.py
    path = mod.__path__[0] if hasattr(mod, '__path__') else mod.__file__
    return normalize_path(path)
def listdir(path):
    '''Same as ``os.listdir`` but normalizes `path` and raises no error.'''
    try:
        return os.listdir(normalize_path(path))
    except os.error:
        return []