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:22 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-09 18:22 +0000
1#!/usr/bin/env python3
2""" Which - locate a command
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)
17 .. function:: which_files(file [, mode=os.F_OK | os.X_OK[, path=None[, pathext=None]]])
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.
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).
40"""
41__docformat__ = 'restructuredtext en'
42__all__ = ['F_OK', 'R_OK', 'W_OK', 'X_OK', 'defpath', 'defpathext', 'dirname', 'pathsep', 'which', 'which_files']
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
49windows = sys.platform.startswith('win')
51defpath = environ.get('PATH', defpath).split(pathsep)
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
60 defpathext = [''] + environ.get('PATHEXT',
61 '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC').lower().split(pathsep)
62else:
63 defpathext = ['']
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.
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
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>')
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>')
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>')
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)
113 if filepath:
114 path = (filepath,)
115 elif path is None:
116 path = defpath
117 elif isinstance(path, str):
118 path = path.split(pathsep)
120 if pathext is None:
121 pathext = defpathext
122 elif isinstance(pathext, str):
123 pathext = pathext.split(pathsep)
125 if not '' in pathext:
126 pathext.insert(0, '') # always check command without extension, even for custom pathext
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
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).
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
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()