Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(761)

Side by Side Diff: third_party/logilab/astroid/modutils.py

Issue 753543006: pylint: upgrade to 1.4.0 (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/logilab/astroid/mixins.py ('k') | third_party/logilab/astroid/node_classes.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « third_party/logilab/astroid/mixins.py ('k') | third_party/logilab/astroid/node_classes.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698