Source code for oasislmf.utils.path

__all__ = [
    'as_path',
    'empty_dir',
    'PathCleaner',
    'import_from_string',
    'get_custom_module',
    'setcwd'
]

import os
import sys
import importlib
import re
import shutil

from contextlib import contextmanager

from .exceptions import OasisException


[docs] def as_path(path, label, is_dir=False, preexists=True, null_is_valid=True): """ Processes the path and returns the absolute path. If the path does not exist and ``preexists`` is true an ``OasisException`` is raised. :param path: The path to process :type path: str :param label: Human-readable label of the path (used for error reporting) :type label: str :param is_dir: Whether the path is a directory :type is_dir: bool :param preexists: Flag whether to raise an error if the path does not exist. :type preexists: bool :param null_is_valid: flag to indicate if None is a valid value :type null_is_valid: bool :return: The absolute path of the input path """ if path is None and null_is_valid: return if not isinstance(path, str): if preexists: raise OasisException(f'The path {path} ({label}) is indicated as preexisting but is not a valid path') else: return if not os.path.isabs(path): path = os.path.abspath(path) if preexists and not os.path.exists(path): raise OasisException(f'The path {path} ({label}) is indicated as preexisting but does not exist') if is_dir and preexists and not os.path.isdir(path): raise OasisException(f'The path {path} ({label}) is indicated as a preexisting directory but is not actually a directory') return os.path.normpath(path)
[docs] def empty_dir(dir_fp): """ Empties the contents of a directory, but leaves the directory in place. :param dir_fp: A pre-existing directory path :type dir_fp: str """ _dir_fp = as_path(dir_fp, dir_fp, is_dir=True) for p in (os.path.join(_dir_fp, fn) for fn in os.listdir(_dir_fp)): os.remove(p) if os.path.isfile(p) else (shutil.rmtree(p) if os.path.isdir(p) else None)
[docs] class PathCleaner(object): """ A callable that generates the absolute path of the given path and checks that it exists if indicated as preexisting. :param label: A user-friendly label for the path (used for error reporting) :type label: str :param preexists: Flag whether to raise an error if the path does not exist. :type preexists: bool """ def __init__(self, label, preexists=True):
[docs] self.label = label
[docs] self.preexists = preexists
def __call__(self, path): return as_path(path, self.label, preexists=self.preexists)
[docs] def import_from_string(name): """ return the object or module from the path given >>> import os.path >>> mod = import_from_string('os.path') >>> os.path is mod True >>> from os.path import isabs >>> cls = import_from_string('os.path.isabs') >>> isabs is cls True """ components = name.split('.') res = __import__(components[0]) for comp in components[1:]: res = getattr(res, comp) return res
[docs] def get_custom_module(custom_module_path, label): """ return the custom module present at the custom_module_path. the try loop allow for the custom module to work even if it depends on other module of its package by testing recursively for the presence of __init__.py file (ex: this module "path" is using from .exceptions import OasisException so it can only be imported as part of the utils package => sys.path.insert(0, path_to_utils);importlib.import_module('utils.path')) >>> mod = get_custom_module(__file__, "test module") >>> mod.__name__.rsplit('.', 1)[-1] 'path' """ custom_module_path = as_path(custom_module_path, label, preexists=True, null_is_valid=False) package_dir = os.path.dirname(custom_module_path) module_name = re.sub(r'\.py$', '', os.path.basename(custom_module_path)) while True: sys.path.insert(0, package_dir) try: custom_module = importlib.import_module(module_name) importlib.reload(custom_module) return custom_module except ImportError: if '__init__.py' in os.listdir(package_dir): module_name = os.path.basename(package_dir) + '.' + module_name package_dir, old_package_dir = os.path.dirname(package_dir), package_dir if package_dir == old_package_dir: raise else: raise finally: sys.path.pop(0)
@contextmanager
[docs] def setcwd(path): orig_path = os.getcwd() try: os.chdir(str(path)) yield path finally: os.chdir(orig_path)
if __name__ == '__main__': import doctest doctest.testmod()