diff --git a/xonsh/procs/executables.py b/xonsh/procs/executables.py index ec0a50ed1..94e7b4617 100644 --- a/xonsh/procs/executables.py +++ b/xonsh/procs/executables.py @@ -38,16 +38,33 @@ def get_paths(env=None): return tuple(reversed(tuple(clear_paths(env.get("PATH") or [])))) -def is_executable_in_windows(filepath, env=None): - """Check the file is executable in Windows.""" +def is_file(filepath): + """Check that ``filepath`` is file and exist.""" + if isinstance(filepath, str): + filepath = Path(filepath) + try: + if filepath.is_file(): + return True + except OSError: + return False + return False + + +def is_executable_in_windows(filepath, check_file_exist=True, env=None): + """Check the file is executable in Windows. + + Parameters + ---------- + filepath : str + Path to file. + check_file_exist : bool + If ``False`` do not check that file exists. This helps to disable double checking in case the file already + checked in upstream code. This is important for Windows where checking can take a long time. + """ filepath = Path(filepath) try: - try: - if not filepath.is_file(): - return False - except OSError: + if check_file_exist and not is_file(filepath): return False - env = env if env is not None else XSH.env return any(s.lower() == filepath.suffix.lower() for s in env.get("PATHEXT", [])) except FileNotFoundError: @@ -57,10 +74,20 @@ def is_executable_in_windows(filepath, env=None): return False -def is_executable_in_posix(filepath): - """Check the file is executable in POSIX.""" +def is_executable_in_posix(filepath, check_file_exist=True): + """Check the file is executable in POSIX. + + Parameters + ---------- + filepath : str + Path to file. + check_file_exist : bool + If ``False`` do not check that file exists. This made to consistency with ``is_executable_in_windows``. + """ try: - return filepath.is_file() and os.access(filepath, os.X_OK) + if check_file_exist and not is_file(filepath): + return False + return os.access(filepath, os.X_OK) except OSError: # broken Symlink are neither dir not files pass @@ -94,8 +121,8 @@ def locate_relative_path(name, env=None, check_executable=False, use_pathext=Fal for possible_name in possible_names: filepath = p.parent / possible_name try: - if not filepath.is_file() or ( - check_executable and not is_executable(filepath) + if not is_file(filepath) or ( + check_executable and not is_executable(filepath, check_file_exist=False) ): continue return str(p.absolute()) @@ -123,8 +150,8 @@ def locate_file_in_path_env(name, env=None, check_executable=False, use_pathext= for path, possible_name in itertools.product(paths, possible_names): filepath = Path(path) / possible_name try: - if not filepath.is_file() or ( - check_executable and not is_executable(filepath) + if not is_file(filepath) or ( + check_executable and not is_executable(filepath, check_file_exist=False) ): continue return str(filepath)