##// END OF EJS Templates
add shutil.which backport to py3compat
Min RK -
Show More
@@ -4,6 +4,7 b' import functools'
4 import os
4 import os
5 import sys
5 import sys
6 import re
6 import re
7 import shutil
7 import types
8 import types
8
9
9 from .encoding import DEFAULT_ENCODING
10 from .encoding import DEFAULT_ENCODING
@@ -75,6 +76,70 b' def safe_unicode(e):'
75
76
76 return u'Unrecoverably corrupt evalue'
77 return u'Unrecoverably corrupt evalue'
77
78
79 # shutil.which from Python 3.4
80 def _shutil_which(cmd, mode=os.F_OK | os.X_OK, path=None):
81 """Given a command, mode, and a PATH string, return the path which
82 conforms to the given mode on the PATH, or None if there is no such
83 file.
84
85 `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
86 of os.environ.get("PATH"), or can be overridden with a custom search
87 path.
88
89 This is a backport of shutil.which from Python 3.4
90 """
91 # Check that a given file can be accessed with the correct mode.
92 # Additionally check that `file` is not a directory, as on Windows
93 # directories pass the os.access check.
94 def _access_check(fn, mode):
95 return (os.path.exists(fn) and os.access(fn, mode)
96 and not os.path.isdir(fn))
97
98 # If we're given a path with a directory part, look it up directly rather
99 # than referring to PATH directories. This includes checking relative to the
100 # current directory, e.g. ./script
101 if os.path.dirname(cmd):
102 if _access_check(cmd, mode):
103 return cmd
104 return None
105
106 if path is None:
107 path = os.environ.get("PATH", os.defpath)
108 if not path:
109 return None
110 path = path.split(os.pathsep)
111
112 if sys.platform == "win32":
113 # The current directory takes precedence on Windows.
114 if not os.curdir in path:
115 path.insert(0, os.curdir)
116
117 # PATHEXT is necessary to check on Windows.
118 pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
119 # See if the given file matches any of the expected path extensions.
120 # This will allow us to short circuit when given "python.exe".
121 # If it does match, only test that one, otherwise we have to try
122 # others.
123 if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
124 files = [cmd]
125 else:
126 files = [cmd + ext for ext in pathext]
127 else:
128 # On other platforms you don't have things like PATHEXT to tell you
129 # what file suffixes are executable, so just pass on cmd as-is.
130 files = [cmd]
131
132 seen = set()
133 for dir in path:
134 normdir = os.path.normcase(dir)
135 if not normdir in seen:
136 seen.add(normdir)
137 for thefile in files:
138 name = os.path.join(dir, thefile)
139 if _access_check(name, mode):
140 return name
141 return None
142
78 if sys.version_info[0] >= 3:
143 if sys.version_info[0] >= 3:
79 PY3 = True
144 PY3 = True
80
145
@@ -97,6 +162,8 b' if sys.version_info[0] >= 3:'
97 string_types = (str,)
162 string_types = (str,)
98 unicode_type = str
163 unicode_type = str
99
164
165 which = shutil.which
166
100 def isidentifier(s, dotted=False):
167 def isidentifier(s, dotted=False):
101 if dotted:
168 if dotted:
102 return all(isidentifier(a) for a in s.split("."))
169 return all(isidentifier(a) for a in s.split("."))
@@ -184,6 +251,8 b' else:'
184 def get_closure(f):
251 def get_closure(f):
185 """Get a function's closure attribute"""
252 """Get a function's closure attribute"""
186 return f.func_closure
253 return f.func_closure
254
255 which = _shutil_which
187
256
188 # Abstract u'abc' syntax:
257 # Abstract u'abc' syntax:
189 @_modify_str_or_docstring
258 @_modify_str_or_docstring
General Comments 0
You need to be logged in to leave comments. Login now