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

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

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

Powered by Google App Engine
This is Rietveld 408576698