Coverage for adhoc-cicd-odoo-odoo / odoo / tools / which.py: 22%

43 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-09 18:15 +0000

1#!/usr/bin/env python3 

2""" Which - locate a command 

3 

4 * adapted from Brian Curtin's http://bugs.python.org/file15381/shutil_which.patch 

5 * see http://bugs.python.org/issue444582 

6 * uses ``PATHEXT`` on Windows 

7 * searches current directory before ``PATH`` on Windows, 

8 but not before an explicitly passed path 

9 * accepts both string or iterable for an explicitly passed path, or pathext 

10 * accepts an explicitly passed empty path, or pathext (either '' or []) 

11 * does not search ``PATH`` for files that have a path specified in their name already 

12 * moved defpath and defpathext lists initialization to module level, 

13 instead of initializing them on each function call 

14 * changed interface: which_files() returns generator, which() returns first match, 

15 or raises IOError(errno.ENOENT) 

16 

17 .. function:: which_files(file [, mode=os.F_OK | os.X_OK[, path=None[, pathext=None]]]) 

18 

19 Return a generator which yields full paths in which the *file* name exists 

20 in a directory that is part of the file name, or on *path*, 

21 and has the given *mode*. 

22 By default, *mode* matches an inclusive OR of os.F_OK and os.X_OK - an  

23 existing executable file. 

24 The *path* is, by default, the ``PATH`` variable on the platform, 

25 or the string/iterable passed in as *path*. 

26 In the event that a ``PATH`` variable is not found, :const:`os.defpath` is used. 

27 On Windows, a current directory is searched before using the ``PATH`` variable, 

28 but not before an explicitly passed *path*. 

29 The *pathext* is only used on Windows to match files with given extensions appended as well. 

30 It defaults to the ``PATHEXT`` variable, or the string/iterable passed in as *pathext*. 

31 In the event that a ``PATHEXT`` variable is not found, 

32 default value for Windows XP/Vista is used. 

33 The command is always searched without extension first, 

34 even when *pathext* is explicitly passed. 

35 

36 .. function:: which(file [, mode=os.F_OK | os.X_OK[, path=None[, pathext=None]]]) 

37 Return first match generated by which_files(file, mode, path, pathext), 

38 or raise IOError(errno.ENOENT). 

39 

40""" 

41__docformat__ = 'restructuredtext en' 

42__all__ = ['F_OK', 'R_OK', 'W_OK', 'X_OK', 'defpath', 'defpathext', 'dirname', 'pathsep', 'which', 'which_files'] 

43 

44import sys 

45from os import access, defpath, pathsep, environ, F_OK, R_OK, W_OK, X_OK 

46from os.path import exists, dirname, split, join 

47ENOENT = 2 

48 

49windows = sys.platform.startswith('win') 

50 

51defpath = environ.get('PATH', defpath).split(pathsep) 

52 

53if windows: 53 ↛ 54line 53 didn't jump to line 54 because the condition on line 53 was never true

54 defpath.insert(0, '.') # can insert without checking, when duplicates are removed 

55 # given the quite usual mess in PATH on Windows, let's rather remove duplicates 

56 seen = set() 

57 defpath = [dir for dir in defpath if dir.lower() not in seen and not seen.add(dir.lower())] 

58 del seen 

59 

60 defpathext = [''] + environ.get('PATHEXT', 

61 '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC').lower().split(pathsep) 

62else: 

63 defpathext = [''] 

64 

65def which_files(file, mode=F_OK | X_OK, path=None, pathext=None): 

66 """ Locate a file in a path supplied as a part of the file name, 

67 or the user's path, or a supplied path. 

68 The function yields full paths (not necessarily absolute paths), 

69 in which the given file name matches an existing file in a directory on the path. 

70 

71 >>> def test_which(expected, *args, **argd): 

72 ... result = list(which_files(*args, **argd)) 

73 ... assert all(path in result for path in expected) if expected else not result, 'which_files: %s != %s' % (result, expected) 

74 ... 

75 ... try: 

76 ... result = which(*args, **argd) 

77 ... path = expected[0] 

78 ... assert split(result)[1] == split(expected[0])[1], 'which: %s not same binary %s' % (result, expected) 

79 ... except IOError: 

80 ... result = None 

81 ... assert not expected, 'which: expecting %s' % expected 

82 

83 >>> if windows: cmd = environ['COMSPEC'] 

84 >>> if windows: test_which([cmd], 'cmd') 

85 >>> if windows: test_which([cmd], 'cmd.exe') 

86 >>> if windows: test_which([cmd], 'cmd', path=dirname(cmd)) 

87 >>> if windows: test_which([cmd], 'cmd', pathext='.exe') 

88 >>> if windows: test_which([cmd], cmd) 

89 >>> if windows: test_which([cmd], cmd, path='<nonexistent>') 

90 >>> if windows: test_which([cmd], cmd, pathext='<nonexistent>') 

91 >>> if windows: test_which([cmd], cmd[:-4]) 

92 >>> if windows: test_which([cmd], cmd[:-4], path='<nonexistent>') 

93 

94 >>> if windows: test_which([], 'cmd', path='<nonexistent>') 

95 >>> if windows: test_which([], 'cmd', pathext='<nonexistent>') 

96 >>> if windows: test_which([], '<nonexistent>/cmd') 

97 >>> if windows: test_which([], cmd[:-4], pathext='<nonexistent>') 

98 

99 >>> if not windows: sh = '/bin/sh' 

100 >>> if not windows: test_which([sh], 'sh') 

101 >>> if not windows: test_which([sh], 'sh', path=dirname(sh)) 

102 >>> if not windows: test_which([sh], 'sh', pathext='<nonexistent>') 

103 >>> if not windows: test_which([sh], sh) 

104 >>> if not windows: test_which([sh], sh, path='<nonexistent>') 

105 >>> if not windows: test_which([sh], sh, pathext='<nonexistent>') 

106 

107 >>> if not windows: test_which([], 'sh', mode=W_OK) # not running as root, are you? 

108 >>> if not windows: test_which([], 'sh', path='<nonexistent>') 

109 >>> if not windows: test_which([], '<nonexistent>/sh') 

110 """ 

111 filepath, file = split(file) 

112 

113 if filepath: 

114 path = (filepath,) 

115 elif path is None: 

116 path = defpath 

117 elif isinstance(path, str): 

118 path = path.split(pathsep) 

119 

120 if pathext is None: 

121 pathext = defpathext 

122 elif isinstance(pathext, str): 

123 pathext = pathext.split(pathsep) 

124 

125 if not '' in pathext: 

126 pathext.insert(0, '') # always check command without extension, even for custom pathext 

127 

128 for dir in path: 

129 basepath = join(dir, file) 

130 for ext in pathext: 

131 fullpath = basepath + ext 

132 if exists(fullpath) and access(fullpath, mode): 

133 yield fullpath 

134 

135def which(file, mode=F_OK | X_OK, path=None, pathext=None): 

136 """ Locate a file in a path supplied as a part of the file name, 

137 or the user's path, or a supplied path. 

138 The function returns full path (not necessarily absolute path), 

139 in which the given file name matches an existing file in a directory on the path, 

140 or raises IOError(errno.ENOENT). 

141 

142 >>> # for doctest see which_files() 

143 """ 

144 path = next(which_files(file, mode, path, pathext), None) 

145 if path is None: 

146 raise IOError(ENOENT, '%s not found' % (mode & X_OK and 'command' or 'file'), file) 

147 return path 

148 

149if __name__ == '__main__': 149 ↛ 150line 149 didn't jump to line 150 because the condition on line 149 was never true

150 import doctest 

151 doctest.testmod()