OLD | NEW |
1 # copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 1 # copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr | 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
3 # | 3 # |
4 # This file is part of astroid. | 4 # This file is part of astroid. |
5 # | 5 # |
6 # astroid is free software: you can redistribute it and/or modify it under | 6 # astroid is free software: you can redistribute it and/or modify it under |
7 # the terms of the GNU Lesser General Public License as published by the Free | 7 # the terms of the GNU Lesser General Public License as published by the Free |
8 # Software Foundation, either version 2.1 of the License, or (at your option) an
y | 8 # Software Foundation, either version 2.1 of the License, or (at your option) an
y |
9 # later version. | 9 # later version. |
10 # | 10 # |
11 # astroid is distributed in the hope that it will be useful, but WITHOUT | 11 # astroid is distributed in the hope that it will be useful, but WITHOUT |
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | 13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
14 # details. | 14 # details. |
15 # | 15 # |
16 # You should have received a copy of the GNU Lesser General Public License along | 16 # You should have received a copy of the GNU Lesser General Public License along |
17 # with astroid. If not, see <http://www.gnu.org/licenses/>. | 17 # with astroid. If not, see <http://www.gnu.org/licenses/>. |
18 """Python modules manipulation utility functions. | 18 """Python modules manipulation utility functions. |
19 | 19 |
20 :type PY_SOURCE_EXTS: tuple(str) | 20 :type PY_SOURCE_EXTS: tuple(str) |
21 :var PY_SOURCE_EXTS: list of possible python source file extension | 21 :var PY_SOURCE_EXTS: list of possible python source file extension |
22 | 22 |
23 :type STD_LIB_DIR: str | 23 :type STD_LIB_DIRS: list of str |
24 :var STD_LIB_DIR: directory where standard modules are located | 24 :var STD_LIB_DIRS: directories where standard modules are located |
25 | 25 |
26 :type BUILTIN_MODULES: dict | 26 :type BUILTIN_MODULES: dict |
27 :var BUILTIN_MODULES: dictionary with builtin module names has key | 27 :var BUILTIN_MODULES: dictionary with builtin module names has key |
28 """ | 28 """ |
29 from __future__ import with_statement | 29 from __future__ import with_statement |
30 | 30 |
31 __docformat__ = "restructuredtext en" | 31 __docformat__ = "restructuredtext en" |
32 | 32 |
| 33 import imp |
| 34 import os |
33 import sys | 35 import sys |
34 import os | |
35 from os.path import splitext, join, abspath, isdir, dirname, exists | |
36 from imp import find_module, load_module, C_BUILTIN, PY_COMPILED, PKG_DIRECTORY | |
37 from distutils.sysconfig import get_python_lib | 36 from distutils.sysconfig import get_python_lib |
38 from distutils.errors import DistutilsPlatformError | 37 from distutils.errors import DistutilsPlatformError |
| 38 import zipimport |
39 | 39 |
40 try: | 40 try: |
41 import zipimport | 41 import pkg_resources |
42 except ImportError: | 42 except ImportError: |
43 zipimport = None | 43 pkg_resources = None |
44 | |
45 ZIPFILE = object() | |
46 | 44 |
47 from logilab.common import _handle_blacklist | 45 from logilab.common import _handle_blacklist |
48 | 46 |
49 # Notes about STD_LIB_DIR | 47 PY_ZIPMODULE = object() |
50 # Consider arch-specific installation for STD_LIB_DIR definition | 48 |
51 # :mod:`distutils.sysconfig` contains to much hardcoded values to rely on | |
52 # | |
53 # :see: `Problems with /usr/lib64 builds <http://bugs.python.org/issue1294959>`_ | |
54 # :see: `FHS <http://www.pathname.com/fhs/pub/fhs-2.3.html#LIBLTQUALGTALTERNATEF
ORMATESSENTIAL>`_ | |
55 if sys.platform.startswith('win'): | 49 if sys.platform.startswith('win'): |
56 PY_SOURCE_EXTS = ('py', 'pyw') | 50 PY_SOURCE_EXTS = ('py', 'pyw') |
57 PY_COMPILED_EXTS = ('dll', 'pyd') | 51 PY_COMPILED_EXTS = ('dll', 'pyd') |
58 else: | 52 else: |
59 PY_SOURCE_EXTS = ('py',) | 53 PY_SOURCE_EXTS = ('py',) |
60 PY_COMPILED_EXTS = ('so',) | 54 PY_COMPILED_EXTS = ('so',) |
61 | 55 |
| 56 # Notes about STD_LIB_DIRS |
| 57 # Consider arch-specific installation for STD_LIB_DIR definition |
| 58 # :mod:`distutils.sysconfig` contains to much hardcoded values to rely on |
| 59 # |
| 60 # :see: `Problems with /usr/lib64 builds <http://bugs.python.org/issue1294959>`_ |
| 61 # :see: `FHS <http://www.pathname.com/fhs/pub/fhs-2.3.html#LIBLTQUALGTALTERNATEF
ORMATESSENTIAL>`_ |
62 try: | 62 try: |
63 STD_LIB_DIR = get_python_lib(standard_lib=1) | 63 # The explicit prefix is to work around a patch in virtualenv that |
| 64 # replaces the 'real' sys.prefix (i.e. the location of the binary) |
| 65 # with the prefix from which the virtualenv was created. This throws |
| 66 # off the detection logic for standard library modules, thus the |
| 67 # workaround. |
| 68 STD_LIB_DIRS = [ |
| 69 get_python_lib(standard_lib=True, prefix=sys.prefix), |
| 70 get_python_lib(standard_lib=True)] |
| 71 if os.name == 'nt': |
| 72 STD_LIB_DIRS.append(os.path.join(sys.prefix, 'dlls')) |
| 73 try: |
| 74 # real_prefix is defined when running inside virtualenv. |
| 75 STD_LIB_DIRS.append(os.path.join(sys.real_prefix, 'dlls')) |
| 76 except AttributeError: |
| 77 pass |
64 # get_python_lib(standard_lib=1) is not available on pypy, set STD_LIB_DIR to | 78 # get_python_lib(standard_lib=1) is not available on pypy, set STD_LIB_DIR to |
65 # non-valid path, see https://bugs.pypy.org/issue1164 | 79 # non-valid path, see https://bugs.pypy.org/issue1164 |
66 except DistutilsPlatformError: | 80 except DistutilsPlatformError: |
67 STD_LIB_DIR = '//' | 81 STD_LIB_DIRS = [] |
68 | 82 |
69 EXT_LIB_DIR = get_python_lib() | 83 EXT_LIB_DIR = get_python_lib() |
70 | 84 |
71 BUILTIN_MODULES = dict(zip(sys.builtin_module_names, | 85 BUILTIN_MODULES = dict(zip(sys.builtin_module_names, |
72 [1]*len(sys.builtin_module_names))) | 86 [1]*len(sys.builtin_module_names))) |
73 | 87 |
74 | 88 |
75 class NoSourceFile(Exception): | 89 class NoSourceFile(Exception): |
76 """exception raised when we are not able to get a python | 90 """exception raised when we are not able to get a python |
77 source file for a precompiled file | 91 source file for a precompiled file |
78 """ | 92 """ |
79 | 93 |
| 94 def _normalize_path(path): |
| 95 return os.path.normcase(os.path.abspath(path)) |
| 96 |
| 97 |
| 98 _NORM_PATH_CACHE = {} |
| 99 |
| 100 def _cache_normalize_path(path): |
| 101 """abspath with caching""" |
| 102 # _module_file calls abspath on every path in sys.path every time it's |
| 103 # called; on a larger codebase this easily adds up to half a second just |
| 104 # assembling path components. This cache alleviates that. |
| 105 try: |
| 106 return _NORM_PATH_CACHE[path] |
| 107 except KeyError: |
| 108 if not path: # don't cache result for '' |
| 109 return _normalize_path(path) |
| 110 result = _NORM_PATH_CACHE[path] = _normalize_path(path) |
| 111 return result |
80 | 112 |
81 def load_module_from_name(dotted_name, path=None, use_sys=1): | 113 def load_module_from_name(dotted_name, path=None, use_sys=1): |
82 """Load a Python module from its name. | 114 """Load a Python module from its name. |
83 | 115 |
84 :type dotted_name: str | 116 :type dotted_name: str |
85 :param dotted_name: python name of a module or package | 117 :param dotted_name: python name of a module or package |
86 | 118 |
87 :type path: list or None | 119 :type path: list or None |
88 :param path: | 120 :param path: |
89 optional list of path where the module or package should be | 121 optional list of path where the module or package should be |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 modpath.append(part) | 167 modpath.append(part) |
136 curname = '.'.join(modpath) | 168 curname = '.'.join(modpath) |
137 module = None | 169 module = None |
138 if len(modpath) != len(parts): | 170 if len(modpath) != len(parts): |
139 # even with use_sys=False, should try to get outer packages from sys
.modules | 171 # even with use_sys=False, should try to get outer packages from sys
.modules |
140 module = sys.modules.get(curname) | 172 module = sys.modules.get(curname) |
141 elif use_sys: | 173 elif use_sys: |
142 # because it may have been indirectly loaded through a parent | 174 # because it may have been indirectly loaded through a parent |
143 module = sys.modules.get(curname) | 175 module = sys.modules.get(curname) |
144 if module is None: | 176 if module is None: |
145 mp_file, mp_filename, mp_desc = find_module(part, path) | 177 mp_file, mp_filename, mp_desc = imp.find_module(part, path) |
146 module = load_module(curname, mp_file, mp_filename, mp_desc) | 178 module = imp.load_module(curname, mp_file, mp_filename, mp_desc) |
| 179 # mp_file still needs to be closed. |
| 180 if mp_file: |
| 181 mp_file.close() |
147 if prevmodule: | 182 if prevmodule: |
148 setattr(prevmodule, part, module) | 183 setattr(prevmodule, part, module) |
149 _file = getattr(module, '__file__', '') | 184 _file = getattr(module, '__file__', '') |
150 if not _file and len(modpath) != len(parts): | 185 if not _file and len(modpath) != len(parts): |
151 raise ImportError('no module in %s' % '.'.join(parts[len(modpath):])
) | 186 raise ImportError('no module in %s' % '.'.join(parts[len(modpath):])
) |
152 path = [dirname(_file)] | 187 path = [os.path.dirname(_file)] |
153 prevmodule = module | 188 prevmodule = module |
154 return module | 189 return module |
155 | 190 |
156 | 191 |
157 def load_module_from_file(filepath, path=None, use_sys=1, extrapath=None): | 192 def load_module_from_file(filepath, path=None, use_sys=1, extrapath=None): |
158 """Load a Python module from it's path. | 193 """Load a Python module from it's path. |
159 | 194 |
160 :type filepath: str | 195 :type filepath: str |
161 :param filepath: path to the python module or package | 196 :param filepath: path to the python module or package |
162 | 197 |
(...skipping 13 matching lines...) Expand all Loading... |
176 :rtype: module | 211 :rtype: module |
177 :return: the loaded module | 212 :return: the loaded module |
178 """ | 213 """ |
179 modpath = modpath_from_file(filepath, extrapath) | 214 modpath = modpath_from_file(filepath, extrapath) |
180 return load_module_from_modpath(modpath, path, use_sys) | 215 return load_module_from_modpath(modpath, path, use_sys) |
181 | 216 |
182 | 217 |
183 def _check_init(path, mod_path): | 218 def _check_init(path, mod_path): |
184 """check there are some __init__.py all along the way""" | 219 """check there are some __init__.py all along the way""" |
185 for part in mod_path: | 220 for part in mod_path: |
186 path = join(path, part) | 221 path = os.path.join(path, part) |
187 if not _has_init(path): | 222 if not _has_init(path): |
188 return False | 223 return False |
189 return True | 224 return True |
190 | 225 |
191 | 226 |
192 def modpath_from_file(filename, extrapath=None): | 227 def modpath_from_file(filename, extrapath=None): |
193 """given a file path return the corresponding splitted module's name | 228 """given a file path return the corresponding splitted module's name |
194 (i.e name of a module or package splitted on '.') | 229 (i.e name of a module or package splitted on '.') |
195 | 230 |
196 :type filename: str | 231 :type filename: str |
197 :param filename: file's path for which we want the module's name | 232 :param filename: file's path for which we want the module's name |
198 | 233 |
199 :type extrapath: dict | 234 :type extrapath: dict |
200 :param extrapath: | 235 :param extrapath: |
201 optional extra search path, with path as key and package name for the path | 236 optional extra search path, with path as key and package name for the path |
202 as value. This is usually useful to handle package splitted in multiple | 237 as value. This is usually useful to handle package splitted in multiple |
203 directories using __path__ trick. | 238 directories using __path__ trick. |
204 | 239 |
205 | 240 |
206 :raise ImportError: | 241 :raise ImportError: |
207 if the corresponding module's name has not been found | 242 if the corresponding module's name has not been found |
208 | 243 |
209 :rtype: list(str) | 244 :rtype: list(str) |
210 :return: the corresponding splitted module's name | 245 :return: the corresponding splitted module's name |
211 """ | 246 """ |
212 base = splitext(abspath(filename))[0] | 247 base = os.path.splitext(os.path.abspath(filename))[0] |
213 if extrapath is not None: | 248 if extrapath is not None: |
214 for path_ in extrapath: | 249 for path_ in extrapath: |
215 path = _abspath(path_) | 250 path = os.path.abspath(path_) |
216 if path and base[:len(path)] == path: | 251 if path and os.path.normcase(base[:len(path)]) == os.path.normcase(p
ath): |
217 submodpath = [pkg for pkg in base[len(path):].split(os.sep) | 252 submodpath = [pkg for pkg in base[len(path):].split(os.sep) |
218 if pkg] | 253 if pkg] |
219 if _check_init(path, submodpath[:-1]): | 254 if _check_init(path, submodpath[:-1]): |
220 return extrapath[path_].split('.') + submodpath | 255 return extrapath[path_].split('.') + submodpath |
221 for path in sys.path: | 256 for path in sys.path: |
222 path = _abspath(path) | 257 path = _cache_normalize_path(path) |
223 if path and base.startswith(path): | 258 if path and os.path.normcase(base).startswith(path): |
224 modpath = [pkg for pkg in base[len(path):].split(os.sep) if pkg] | 259 modpath = [pkg for pkg in base[len(path):].split(os.sep) if pkg] |
225 if _check_init(path, modpath[:-1]): | 260 if _check_init(path, modpath[:-1]): |
226 return modpath | 261 return modpath |
227 raise ImportError('Unable to find module for %s in %s' % ( | 262 raise ImportError('Unable to find module for %s in %s' % ( |
228 filename, ', \n'.join(sys.path))) | 263 filename, ', \n'.join(sys.path))) |
229 | 264 |
230 | 265 |
| 266 def file_from_modpath(modpath, path=None, context_file=None): |
| 267 return file_info_from_modpath(modpath, path, context_file)[0] |
231 | 268 |
232 def file_from_modpath(modpath, path=None, context_file=None): | 269 def file_info_from_modpath(modpath, path=None, context_file=None): |
233 """given a mod path (i.e. splitted module / package name), return the | 270 """given a mod path (i.e. splitted module / package name), return the |
234 corresponding file, giving priority to source file over precompiled | 271 corresponding file, giving priority to source file over precompiled |
235 file if it exists | 272 file if it exists |
236 | 273 |
237 :type modpath: list or tuple | 274 :type modpath: list or tuple |
238 :param modpath: | 275 :param modpath: |
239 splitted module's name (i.e name of a module or package splitted | 276 splitted module's name (i.e name of a module or package splitted |
240 on '.') | 277 on '.') |
241 (this means explicit relative imports that start with dots have | 278 (this means explicit relative imports that start with dots have |
242 empty strings in this list!) | 279 empty strings in this list!) |
243 | 280 |
244 :type path: list or None | 281 :type path: list or None |
245 :param path: | 282 :param path: |
246 optional list of path where the module or package should be | 283 optional list of path where the module or package should be |
247 searched (use sys.path if nothing or None is given) | 284 searched (use sys.path if nothing or None is given) |
248 | 285 |
249 :type context_file: str or None | 286 :type context_file: str or None |
250 :param context_file: | 287 :param context_file: |
251 context file to consider, necessary if the identifier has been | 288 context file to consider, necessary if the identifier has been |
252 introduced using a relative import unresolvable in the actual | 289 introduced using a relative import unresolvable in the actual |
253 context (i.e. modutils) | 290 context (i.e. modutils) |
254 | 291 |
255 :raise ImportError: if there is no such module in the directory | 292 :raise ImportError: if there is no such module in the directory |
256 | 293 |
257 :rtype: str or None | 294 :rtype: (str or None, import type) |
258 :return: | 295 :return: |
259 the path to the module's file or None if it's an integrated | 296 the path to the module's file or None if it's an integrated |
260 builtin module such as 'sys' | 297 builtin module such as 'sys' |
261 """ | 298 """ |
262 if context_file is not None: | 299 if context_file is not None: |
263 context = dirname(context_file) | 300 context = os.path.dirname(context_file) |
264 else: | 301 else: |
265 context = context_file | 302 context = context_file |
266 if modpath[0] == 'xml': | 303 if modpath[0] == 'xml': |
267 # handle _xmlplus | 304 # handle _xmlplus |
268 try: | 305 try: |
269 return _file_from_modpath(['_xmlplus'] + modpath[1:], path, context) | 306 return _file_from_modpath(['_xmlplus'] + modpath[1:], path, context) |
270 except ImportError: | 307 except ImportError: |
271 return _file_from_modpath(modpath, path, context) | 308 return _file_from_modpath(modpath, path, context) |
272 elif modpath == ['os', 'path']: | 309 elif modpath == ['os', 'path']: |
273 # FIXME: currently ignoring search_path... | 310 # FIXME: currently ignoring search_path... |
274 return os.path.__file__ | 311 return os.path.__file__, imp.PY_SOURCE |
275 return _file_from_modpath(modpath, path, context) | 312 return _file_from_modpath(modpath, path, context) |
276 | 313 |
277 | 314 |
278 | |
279 def get_module_part(dotted_name, context_file=None): | 315 def get_module_part(dotted_name, context_file=None): |
280 """given a dotted name return the module part of the name : | 316 """given a dotted name return the module part of the name : |
281 | 317 |
282 >>> get_module_part('logilab.common.modutils.get_module_part') | 318 >>> get_module_part('logilab.common.modutils.get_module_part') |
283 'logilab.common.modutils' | 319 'logilab.common.modutils' |
284 | 320 |
285 :type dotted_name: str | 321 :type dotted_name: str |
286 :param dotted_name: full name of the identifier we are interested in | 322 :param dotted_name: full name of the identifier we are interested in |
287 | 323 |
288 :type context_file: str or None | 324 :type context_file: str or None |
(...skipping 27 matching lines...) Expand all Loading... |
316 # don't use += or insert, we want a new list to be created ! | 352 # don't use += or insert, we want a new list to be created ! |
317 path = None | 353 path = None |
318 starti = 0 | 354 starti = 0 |
319 if parts[0] == '': | 355 if parts[0] == '': |
320 assert context_file is not None, \ | 356 assert context_file is not None, \ |
321 'explicit relative import, but no context_file?' | 357 'explicit relative import, but no context_file?' |
322 path = [] # prevent resolving the import non-relatively | 358 path = [] # prevent resolving the import non-relatively |
323 starti = 1 | 359 starti = 1 |
324 while parts[starti] == '': # for all further dots: change context | 360 while parts[starti] == '': # for all further dots: change context |
325 starti += 1 | 361 starti += 1 |
326 context_file = dirname(context_file) | 362 context_file = os.path.dirname(context_file) |
327 for i in range(starti, len(parts)): | 363 for i in range(starti, len(parts)): |
328 try: | 364 try: |
329 file_from_modpath(parts[starti:i+1], path=path, | 365 file_from_modpath(parts[starti:i+1], path=path, |
330 context_file=context_file) | 366 context_file=context_file) |
331 except ImportError: | 367 except ImportError: |
332 if not i >= max(1, len(parts) - 2): | 368 if not i >= max(1, len(parts) - 2): |
333 raise | 369 raise |
334 return '.'.join(parts[:i]) | 370 return '.'.join(parts[:i]) |
335 return dotted_name | 371 return dotted_name |
336 | 372 |
(...skipping 18 matching lines...) Expand all Loading... |
355 """ | 391 """ |
356 files = [] | 392 files = [] |
357 for directory, dirnames, filenames in os.walk(src_directory): | 393 for directory, dirnames, filenames in os.walk(src_directory): |
358 _handle_blacklist(blacklist, dirnames, filenames) | 394 _handle_blacklist(blacklist, dirnames, filenames) |
359 # check for __init__.py | 395 # check for __init__.py |
360 if not '__init__.py' in filenames: | 396 if not '__init__.py' in filenames: |
361 dirnames[:] = () | 397 dirnames[:] = () |
362 continue | 398 continue |
363 for filename in filenames: | 399 for filename in filenames: |
364 if _is_python_file(filename): | 400 if _is_python_file(filename): |
365 src = join(directory, filename) | 401 src = os.path.join(directory, filename) |
366 files.append(src) | 402 files.append(src) |
367 return files | 403 return files |
368 | 404 |
369 | 405 |
370 def get_source_file(filename, include_no_ext=False): | 406 def get_source_file(filename, include_no_ext=False): |
371 """given a python module's file name return the matching source file | 407 """given a python module's file name return the matching source file |
372 name (the filename will be returned identically if it's a already an | 408 name (the filename will be returned identically if it's a already an |
373 absolute path to a python source file...) | 409 absolute path to a python source file...) |
374 | 410 |
375 :type filename: str | 411 :type filename: str |
376 :param filename: python module's file name | 412 :param filename: python module's file name |
377 | 413 |
378 | 414 |
379 :raise NoSourceFile: if no source file exists on the file system | 415 :raise NoSourceFile: if no source file exists on the file system |
380 | 416 |
381 :rtype: str | 417 :rtype: str |
382 :return: the absolute path of the source file if it exists | 418 :return: the absolute path of the source file if it exists |
383 """ | 419 """ |
384 base, orig_ext = splitext(abspath(filename)) | 420 base, orig_ext = os.path.splitext(os.path.abspath(filename)) |
385 for ext in PY_SOURCE_EXTS: | 421 for ext in PY_SOURCE_EXTS: |
386 source_path = '%s.%s' % (base, ext) | 422 source_path = '%s.%s' % (base, ext) |
387 if exists(source_path): | 423 if os.path.exists(source_path): |
388 return source_path | 424 return source_path |
389 if include_no_ext and not orig_ext and exists(base): | 425 if include_no_ext and not orig_ext and os.path.exists(base): |
390 return base | 426 return base |
391 raise NoSourceFile(filename) | 427 raise NoSourceFile(filename) |
392 | 428 |
393 | 429 |
394 def is_python_source(filename): | 430 def is_python_source(filename): |
395 """ | 431 """ |
396 rtype: bool | 432 rtype: bool |
397 return: True if the filename is a python source file | 433 return: True if the filename is a python source file |
398 """ | 434 """ |
399 return splitext(filename)[1][1:] in PY_SOURCE_EXTS | 435 return os.path.splitext(filename)[1][1:] in PY_SOURCE_EXTS |
400 | 436 |
401 | 437 |
402 def is_standard_module(modname, std_path=(STD_LIB_DIR,)): | 438 def is_standard_module(modname, std_path=None): |
403 """try to guess if a module is a standard python module (by default, | 439 """try to guess if a module is a standard python module (by default, |
404 see `std_path` parameter's description) | 440 see `std_path` parameter's description) |
405 | 441 |
406 :type modname: str | 442 :type modname: str |
407 :param modname: name of the module we are interested in | 443 :param modname: name of the module we are interested in |
408 | 444 |
409 :type std_path: list(str) or tuple(str) | 445 :type std_path: list(str) or tuple(str) |
410 :param std_path: list of path considered has standard | 446 :param std_path: list of path considered has standard |
411 | 447 |
412 | 448 |
413 :rtype: bool | 449 :rtype: bool |
414 :return: | 450 :return: |
415 true if the module: | 451 true if the module: |
416 - is located on the path listed in one of the directory in `std_path` | 452 - is located on the path listed in one of the directory in `std_path` |
417 - is a built-in module | 453 - is a built-in module |
418 """ | 454 """ |
419 modname = modname.split('.')[0] | 455 modname = modname.split('.')[0] |
420 try: | 456 try: |
421 filename = file_from_modpath([modname]) | 457 filename = file_from_modpath([modname]) |
422 except ImportError: | 458 except ImportError: |
423 # import failed, i'm probably not so wrong by supposing it's | 459 # import failed, i'm probably not so wrong by supposing it's |
424 # not standard... | 460 # not standard... |
425 return False | 461 return False |
426 # modules which are not living in a file are considered standard | 462 # modules which are not living in a file are considered standard |
427 # (sys and __builtin__ for instance) | 463 # (sys and __builtin__ for instance) |
428 if filename is None: | 464 if filename is None: |
429 return True | 465 return True |
430 filename = abspath(filename) | 466 filename = _normalize_path(filename) |
431 if filename.startswith(EXT_LIB_DIR): | 467 if filename.startswith(_cache_normalize_path(EXT_LIB_DIR)): |
432 return False | 468 return False |
| 469 if std_path is None: |
| 470 std_path = STD_LIB_DIRS |
433 for path in std_path: | 471 for path in std_path: |
434 if filename.startswith(_abspath(path)): | 472 if filename.startswith(_cache_normalize_path(path)): |
435 return True | 473 return True |
436 return False | 474 return False |
437 | 475 |
438 | 476 |
439 | 477 |
440 def is_relative(modname, from_file): | 478 def is_relative(modname, from_file): |
441 """return true if the given module name is relative to the given | 479 """return true if the given module name is relative to the given |
442 file name | 480 file name |
443 | 481 |
444 :type modname: str | 482 :type modname: str |
445 :param modname: name of the module we are interested in | 483 :param modname: name of the module we are interested in |
446 | 484 |
447 :type from_file: str | 485 :type from_file: str |
448 :param from_file: | 486 :param from_file: |
449 path of the module from which modname has been imported | 487 path of the module from which modname has been imported |
450 | 488 |
451 :rtype: bool | 489 :rtype: bool |
452 :return: | 490 :return: |
453 true if the module has been imported relatively to `from_file` | 491 true if the module has been imported relatively to `from_file` |
454 """ | 492 """ |
455 if not isdir(from_file): | 493 if not os.path.isdir(from_file): |
456 from_file = dirname(from_file) | 494 from_file = os.path.dirname(from_file) |
457 if from_file in sys.path: | 495 if from_file in sys.path: |
458 return False | 496 return False |
459 try: | 497 try: |
460 find_module(modname.split('.')[0], [from_file]) | 498 stream, _, _ = imp.find_module(modname.split('.')[0], [from_file]) |
| 499 |
| 500 # Close the stream to avoid ResourceWarnings. |
| 501 if stream: |
| 502 stream.close() |
461 return True | 503 return True |
462 except ImportError: | 504 except ImportError: |
463 return False | 505 return False |
464 | 506 |
465 | 507 |
466 # internal only functions ##################################################### | 508 # internal only functions ##################################################### |
467 | 509 |
468 def _file_from_modpath(modpath, path=None, context=None): | 510 def _file_from_modpath(modpath, path=None, context=None): |
469 """given a mod path (i.e. splitted module / package name), return the | 511 """given a mod path (i.e. splitted module / package name), return the |
470 corresponding file | 512 corresponding file |
471 | 513 |
472 this function is used internally, see `file_from_modpath`'s | 514 this function is used internally, see `file_from_modpath`'s |
473 documentation for more information | 515 documentation for more information |
474 """ | 516 """ |
475 assert len(modpath) > 0 | 517 assert len(modpath) > 0 |
476 if context is not None: | 518 if context is not None: |
477 try: | 519 try: |
478 mtype, mp_filename = _module_file(modpath, [context]) | 520 mtype, mp_filename = _module_file(modpath, [context]) |
479 except ImportError: | 521 except ImportError: |
480 mtype, mp_filename = _module_file(modpath, path) | 522 mtype, mp_filename = _module_file(modpath, path) |
481 else: | 523 else: |
482 mtype, mp_filename = _module_file(modpath, path) | 524 mtype, mp_filename = _module_file(modpath, path) |
483 if mtype == PY_COMPILED: | 525 if mtype == imp.PY_COMPILED: |
484 try: | 526 try: |
485 return get_source_file(mp_filename) | 527 return get_source_file(mp_filename), imp.PY_SOURCE |
486 except NoSourceFile: | 528 except NoSourceFile: |
487 return mp_filename | 529 return mp_filename, imp.PY_COMPILED |
488 elif mtype == C_BUILTIN: | 530 elif mtype == imp.C_BUILTIN: |
489 # integrated builtin module | 531 # integrated builtin module |
490 return None | 532 return None, imp.C_BUILTIN |
491 elif mtype == PKG_DIRECTORY: | 533 elif mtype == imp.PKG_DIRECTORY: |
492 mp_filename = _has_init(mp_filename) | 534 mp_filename = _has_init(mp_filename) |
493 return mp_filename | 535 mtype = imp.PY_SOURCE |
| 536 return mp_filename, mtype |
494 | 537 |
495 def _search_zip(modpath, pic): | 538 def _search_zip(modpath, pic): |
496 for filepath, importer in pic.items(): | 539 for filepath, importer in pic.items(): |
497 if importer is not None: | 540 if importer is not None: |
498 if importer.find_module(modpath[0]): | 541 if importer.find_module(modpath[0]): |
499 if not importer.find_module(os.path.sep.join(modpath)): | 542 if not importer.find_module(os.path.sep.join(modpath)): |
500 raise ImportError('No module named %s in %s/%s' % ( | 543 raise ImportError('No module named %s in %s/%s' % ( |
501 '.'.join(modpath[1:]), filepath, modpath)) | 544 '.'.join(modpath[1:]), filepath, modpath)) |
502 return ZIPFILE, abspath(filepath) + os.path.sep + os.path.sep.jo
in(modpath), filepath | 545 return PY_ZIPMODULE, os.path.abspath(filepath) + os.path.sep + o
s.path.sep.join(modpath), filepath |
503 raise ImportError('No module named %s' % '.'.join(modpath)) | 546 raise ImportError('No module named %s' % '.'.join(modpath)) |
504 | 547 |
505 | 548 |
506 def _abspath(path, _abspathcache={}): #pylint: disable=dangerous-default-value | |
507 """abspath with caching""" | |
508 # _module_file calls abspath on every path in sys.path every time it's | |
509 # called; on a larger codebase this easily adds up to half a second just | |
510 # assembling path components. This cache alleviates that. | |
511 try: | |
512 return _abspathcache[path] | |
513 except KeyError: | |
514 if not path: # don't cache result for '' | |
515 return abspath(path) | |
516 _abspathcache[path] = abspath(path) | |
517 return _abspathcache[path] | |
518 | |
519 try: | |
520 import pkg_resources | |
521 except ImportError: | |
522 pkg_resources = None | |
523 | |
524 def _module_file(modpath, path=None): | 549 def _module_file(modpath, path=None): |
525 """get a module type / file path | 550 """get a module type / file path |
526 | 551 |
527 :type modpath: list or tuple | 552 :type modpath: list or tuple |
528 :param modpath: | 553 :param modpath: |
529 splitted module's name (i.e name of a module or package splitted | 554 splitted module's name (i.e name of a module or package splitted |
530 on '.'), with leading empty strings for explicit relative import | 555 on '.'), with leading empty strings for explicit relative import |
531 | 556 |
532 :type path: list or None | 557 :type path: list or None |
533 :param path: | 558 :param path: |
(...skipping 11 matching lines...) Expand all Loading... |
545 for __path in _path: | 570 for __path in _path: |
546 if not __path in pic: | 571 if not __path in pic: |
547 try: | 572 try: |
548 pic[__path] = zipimport.zipimporter(__path) | 573 pic[__path] = zipimport.zipimporter(__path) |
549 except zipimport.ZipImportError: | 574 except zipimport.ZipImportError: |
550 pic[__path] = None | 575 pic[__path] = None |
551 checkeggs = True | 576 checkeggs = True |
552 except AttributeError: | 577 except AttributeError: |
553 checkeggs = False | 578 checkeggs = False |
554 # pkg_resources support (aka setuptools namespace packages) | 579 # pkg_resources support (aka setuptools namespace packages) |
555 if pkg_resources is not None and modpath[0] in pkg_resources._namespace_pack
ages and len(modpath) > 1: | 580 if (pkg_resources is not None |
| 581 and modpath[0] in pkg_resources._namespace_packages |
| 582 and modpath[0] in sys.modules |
| 583 and len(modpath) > 1): |
556 # setuptools has added into sys.modules a module object with proper | 584 # setuptools has added into sys.modules a module object with proper |
557 # __path__, get back information from there | 585 # __path__, get back information from there |
558 module = sys.modules[modpath.pop(0)] | 586 module = sys.modules[modpath.pop(0)] |
559 path = module.__path__ | 587 path = module.__path__ |
560 imported = [] | 588 imported = [] |
561 while modpath: | 589 while modpath: |
562 modname = modpath[0] | 590 modname = modpath[0] |
563 # take care to changes in find_module implementation wrt builtin modules | 591 # take care to changes in find_module implementation wrt builtin modules |
564 # | 592 # |
565 # Python 2.6.6 (r266:84292, Sep 11 2012, 08:34:23) | 593 # Python 2.6.6 (r266:84292, Sep 11 2012, 08:34:23) |
566 # >>> imp.find_module('posix') | 594 # >>> imp.find_module('posix') |
567 # (None, 'posix', ('', '', 6)) | 595 # (None, 'posix', ('', '', 6)) |
568 # | 596 # |
569 # Python 3.3.1 (default, Apr 26 2013, 12:08:46) | 597 # Python 3.3.1 (default, Apr 26 2013, 12:08:46) |
570 # >>> imp.find_module('posix') | 598 # >>> imp.find_module('posix') |
571 # (None, None, ('', '', 6)) | 599 # (None, None, ('', '', 6)) |
572 try: | 600 try: |
573 _, mp_filename, mp_desc = find_module(modname, path) | 601 stream, mp_filename, mp_desc = imp.find_module(modname, path) |
574 except ImportError: | 602 except ImportError: |
575 if checkeggs: | 603 if checkeggs: |
576 return _search_zip(modpath, pic)[:2] | 604 return _search_zip(modpath, pic)[:2] |
577 raise | 605 raise |
578 else: | 606 else: |
| 607 # Don't forget to close the stream to avoid |
| 608 # spurious ResourceWarnings. |
| 609 if stream: |
| 610 stream.close() |
| 611 |
579 if checkeggs and mp_filename: | 612 if checkeggs and mp_filename: |
580 fullabspath = [_abspath(x) for x in _path] | 613 fullabspath = [_cache_normalize_path(x) for x in _path] |
581 try: | 614 try: |
582 pathindex = fullabspath.index(dirname(abspath(mp_filename))) | 615 pathindex = fullabspath.index(os.path.dirname(_normalize_pat
h(mp_filename))) |
583 emtype, emp_filename, zippath = _search_zip(modpath, pic) | 616 emtype, emp_filename, zippath = _search_zip(modpath, pic) |
584 if pathindex > _path.index(zippath): | 617 if pathindex > _path.index(zippath): |
585 # an egg takes priority | 618 # an egg takes priority |
586 return emtype, emp_filename | 619 return emtype, emp_filename |
587 except ValueError: | 620 except ValueError: |
588 # XXX not in _path | 621 # XXX not in _path |
589 pass | 622 pass |
590 except ImportError: | 623 except ImportError: |
591 pass | 624 pass |
592 checkeggs = False | 625 checkeggs = False |
593 imported.append(modpath.pop(0)) | 626 imported.append(modpath.pop(0)) |
594 mtype = mp_desc[2] | 627 mtype = mp_desc[2] |
595 if modpath: | 628 if modpath: |
596 if mtype != PKG_DIRECTORY: | 629 if mtype != imp.PKG_DIRECTORY: |
597 raise ImportError('No module %s in %s' % ('.'.join(modpath), | 630 raise ImportError('No module %s in %s' % ('.'.join(modpath), |
598 '.'.join(imported))) | 631 '.'.join(imported))) |
599 # XXX guess if package is using pkgutil.extend_path by looking for | 632 # XXX guess if package is using pkgutil.extend_path by looking for |
600 # those keywords in the first four Kbytes | 633 # those keywords in the first four Kbytes |
601 try: | 634 try: |
602 with open(join(mp_filename, '__init__.py')) as stream: | 635 with open(os.path.join(mp_filename, '__init__.py'), 'rb') as str
eam: |
603 data = stream.read(4096) | 636 data = stream.read(4096) |
604 except IOError: | 637 except IOError: |
605 path = [mp_filename] | 638 path = [mp_filename] |
606 else: | 639 else: |
607 if 'pkgutil' in data and 'extend_path' in data: | 640 if b'pkgutil' in data and b'extend_path' in data: |
608 # extend_path is called, search sys.path for module/packages | 641 # extend_path is called, search sys.path for module/packages |
609 # of this name see pkgutil.extend_path documentation | 642 # of this name see pkgutil.extend_path documentation |
610 path = [join(p, *imported) for p in sys.path | 643 path = [os.path.join(p, *imported) for p in sys.path |
611 if isdir(join(p, *imported))] | 644 if os.path.isdir(os.path.join(p, *imported))] |
612 else: | 645 else: |
613 path = [mp_filename] | 646 path = [mp_filename] |
614 return mtype, mp_filename | 647 return mtype, mp_filename |
615 | 648 |
616 def _is_python_file(filename): | 649 def _is_python_file(filename): |
617 """return true if the given filename should be considered as a python file | 650 """return true if the given filename should be considered as a python file |
618 | 651 |
619 .pyc and .pyo are ignored | 652 .pyc and .pyo are ignored |
620 """ | 653 """ |
621 for ext in ('.py', '.so', '.pyd', '.pyw'): | 654 for ext in ('.py', '.so', '.pyd', '.pyw'): |
622 if filename.endswith(ext): | 655 if filename.endswith(ext): |
623 return True | 656 return True |
624 return False | 657 return False |
625 | 658 |
626 | 659 |
627 def _has_init(directory): | 660 def _has_init(directory): |
628 """if the given directory has a valid __init__ file, return its path, | 661 """if the given directory has a valid __init__ file, return its path, |
629 else return None | 662 else return None |
630 """ | 663 """ |
631 mod_or_pack = join(directory, '__init__') | 664 mod_or_pack = os.path.join(directory, '__init__') |
632 for ext in PY_SOURCE_EXTS + ('pyc', 'pyo'): | 665 for ext in PY_SOURCE_EXTS + ('pyc', 'pyo'): |
633 if exists(mod_or_pack + '.' + ext): | 666 if os.path.exists(mod_or_pack + '.' + ext): |
634 return mod_or_pack + '.' + ext | 667 return mod_or_pack + '.' + ext |
635 return None | 668 return None |
OLD | NEW |