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