Source code for andes.utils.paths

"""
Utility functions for loading andes stock test cases
"""
import logging
import os
import pathlib
import tempfile

logger = logging.getLogger(__name__)


[docs]class DisplayablePath: display_filename_prefix_middle = '├──' display_filename_prefix_last = '└──' display_parent_prefix_middle = ' ' display_parent_prefix_last = '│ '
[docs] def __init__(self, path, parent_path, is_last): self.path = pathlib.Path(str(path)) self.parent = parent_path self.is_last = is_last if self.parent: self.depth = self.parent.depth + 1 else: self.depth = 0
@property def displayname(self): if self.path.is_dir(): return self.path.name + '/' return self.path.name
[docs] @classmethod def make_tree(cls, root, parent=None, is_last=False, criteria=None): root = pathlib.Path(str(root)) criteria = criteria or cls._default_criteria displayable_root = cls(root, parent, is_last) yield displayable_root children = sorted(list(path for path in root.iterdir() if criteria(path)), key=lambda s: str(s).lower()) count = 1 for path in children: is_last = count == len(children) if path.is_dir(): yield from cls.make_tree(path, parent=displayable_root, is_last=is_last, criteria=criteria) else: yield cls(path, displayable_root, is_last) count += 1
@classmethod def _default_criteria(cls, path): return True
[docs] def displayable(self): if self.parent is None: return self.displayname _filename_prefix = (self.display_filename_prefix_last if self.is_last else self.display_filename_prefix_middle) parts = ['{!s} {!s}'.format(_filename_prefix, self.displayname)] parent = self.parent while parent and parent.parent is not None: parts.append(self.display_parent_prefix_middle if parent.is_last else self.display_parent_prefix_last) parent = parent.parent return ''.join(reversed(parts))
[docs]def andes_root(): """ Return the path to the folder of the ANDES package. """ dir_name = os.path.dirname(os.path.abspath(__file__)) return os.path.normpath(os.path.join(dir_name, '..'))
[docs]def cases_root(): """ Return the root path to the stock cases """ dir_name = os.path.dirname(os.path.abspath(__file__)) return os.path.normpath(os.path.join(dir_name, '..', 'cases'))
[docs]def tests_root(): """ Return the root path to the stock cases """ dir_name = os.path.dirname(os.path.abspath(__file__)) return os.path.normpath(os.path.join(dir_name, '..', '..', 'tests'))
[docs]def get_case(rpath, check=True): """ Return the path to a stock case for a given path relative to ``andes/cases``. To list all cases, use ``andes.list_cases()``. Parameters ---------- check : bool True to check if file exists Examples -------- To get the path to the case `kundur_full.xlsx` under folder `kundur`, do :: andes.get_case('kundur/kundur_full.xlsx') """ case_path = os.path.join(cases_root(), rpath) case_path = os.path.normpath(case_path) if check is True and (not os.path.isfile(case_path)): raise FileNotFoundError(f'"{rpath}" is not a valid relative path to a stock case.') return case_path
[docs]def list_cases(rpath='.', no_print=False): """ List stock cases under a given folder relative to ``andes/cases`` """ case_path = os.path.join(cases_root(), rpath) case_path = os.path.normpath(case_path) tree = DisplayablePath.make_tree(pathlib.Path(case_path)) out = [] for path in tree: out.append(path.displayable()) out = '\n'.join(out) if no_print is False: print(out) else: return out
[docs]def get_config_path(file_name='andes.rc'): """ Return the path of the config file to be loaded. Search Priority: 1. current directory; 2. home directory. Parameters ---------- file_name : str, optional Config file name with the default as ``andes.rc``. Returns ------- Config path in string if found; None otherwise. """ conf_path = None home_dir = os.path.expanduser('~') # test ./andes.conf if os.path.isfile(file_name): conf_path = file_name # test ~/andes.conf elif os.path.isfile(os.path.join(home_dir, '.andes', file_name)): conf_path = os.path.join(home_dir, '.andes', file_name) return conf_path
[docs]def get_pycode_path(pycode_path=None, mkdir=False): """ Get the path to the ``pycode`` folder. """ if pycode_path is None: pycode_path = os.path.join(get_dot_andes_path(), 'pycode') if mkdir is True: os.makedirs(pycode_path, exist_ok=True) return pycode_path
[docs]def get_dot_andes_path(): """ Return the path to ``$HOME/.andes`` """ return os.path.join(str(pathlib.Path.home()), '.andes')
[docs]def get_log_dir(): """ Get the directory for log file. The default is ``<tempdir>/andes``, where ``<tempdir>`` is provided by ``tempfile.gettempdir()``. Returns ------- str The path to the temporary logging directory """ tempdir = tempfile.gettempdir() path = tempfile.mkdtemp(prefix='andes-', dir=tempdir) return path
[docs]def confirm_overwrite(outfile, overwrite=None): """ Confirm overwriting a file. """ try: if os.path.isfile(outfile): if overwrite is None: choice = input(f'File "{outfile}" already exist. Overwrite? [y/N]').lower() if len(choice) == 0 or choice[0] != 'y': logger.warning(f'File "{outfile}" not overwritten.') return False elif overwrite is False: return False except TypeError: pass return True