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}
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 []