| OLD | NEW |
| 1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
| 2 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 2 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
| 3 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr | 3 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
| 4 # | 4 # |
| 5 # This file is part of logilab-common. | 5 # This file is part of logilab-common. |
| 6 # | 6 # |
| 7 # logilab-common is free software: you can redistribute it and/or modify it unde
r | 7 # logilab-common is free software: you can redistribute it and/or modify it unde
r |
| 8 # the terms of the GNU Lesser General Public License as published by the Free | 8 # the terms of the GNU Lesser General Public License as published by the Free |
| 9 # Software Foundation, either version 2.1 of the License, or (at your option) an
y | 9 # Software Foundation, either version 2.1 of the License, or (at your option) an
y |
| 10 # later version. | 10 # later version. |
| 11 # | 11 # |
| 12 # logilab-common is distributed in the hope that it will be useful, but WITHOUT | 12 # logilab-common is distributed in the hope that it will be useful, but WITHOUT |
| 13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 14 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | 14 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
| 15 # details. | 15 # details. |
| 16 # | 16 # |
| 17 # You should have received a copy of the GNU Lesser General Public License along | 17 # You should have received a copy of the GNU Lesser General Public License along |
| 18 # with logilab-common. If not, see <http://www.gnu.org/licenses/>. | 18 # with logilab-common. If not, see <http://www.gnu.org/licenses/>. |
| 19 """Python modules manipulation utility functions. | 19 """Python modules manipulation utility functions. |
| 20 | 20 |
| 21 :type PY_SOURCE_EXTS: tuple(str) | 21 :type PY_SOURCE_EXTS: tuple(str) |
| 22 :var PY_SOURCE_EXTS: list of possible python source file extension | 22 :var PY_SOURCE_EXTS: list of possible python source file extension |
| 23 | 23 |
| 24 :type STD_LIB_DIR: str | 24 :type STD_LIB_DIR: str |
| 25 :var STD_LIB_DIR: directory where standard modules are located | 25 :var STD_LIB_DIR: directory where standard modules are located |
| 26 | 26 |
| 27 :type BUILTIN_MODULES: dict | 27 :type BUILTIN_MODULES: dict |
| 28 :var BUILTIN_MODULES: dictionary with builtin module names has key | 28 :var BUILTIN_MODULES: dictionary with builtin module names has key |
| 29 """ | 29 """ |
| 30 |
| 30 __docformat__ = "restructuredtext en" | 31 __docformat__ = "restructuredtext en" |
| 31 | 32 |
| 32 import sys | 33 import sys |
| 33 import os | 34 import os |
| 34 from os.path import splitext, join, abspath, isdir, dirname, exists, basename | 35 from os.path import splitext, join, abspath, isdir, dirname, exists, basename |
| 35 from imp import find_module, load_module, C_BUILTIN, PY_COMPILED, PKG_DIRECTORY | 36 from imp import find_module, load_module, C_BUILTIN, PY_COMPILED, PKG_DIRECTORY |
| 36 from distutils.sysconfig import get_config_var, get_python_lib, get_python_versi
on | 37 from distutils.sysconfig import get_config_var, get_python_lib, get_python_versi
on |
| 38 from distutils.errors import DistutilsPlatformError |
| 39 |
| 40 from six.moves import range |
| 37 | 41 |
| 38 try: | 42 try: |
| 39 import zipimport | 43 import zipimport |
| 40 except ImportError: | 44 except ImportError: |
| 41 zipimport = None | 45 zipimport = None |
| 42 | 46 |
| 43 ZIPFILE = object() | 47 ZIPFILE = object() |
| 44 | 48 |
| 45 from logilab.common import STD_BLACKLIST, _handle_blacklist | 49 from logilab.common import STD_BLACKLIST, _handle_blacklist |
| 46 | 50 |
| 47 # Notes about STD_LIB_DIR | 51 # Notes about STD_LIB_DIR |
| 48 # Consider arch-specific installation for STD_LIB_DIR definition | 52 # Consider arch-specific installation for STD_LIB_DIR definition |
| 49 # :mod:`distutils.sysconfig` contains to much hardcoded values to rely on | 53 # :mod:`distutils.sysconfig` contains to much hardcoded values to rely on |
| 50 # | 54 # |
| 51 # :see: `Problems with /usr/lib64 builds <http://bugs.python.org/issue1294959>`_ | 55 # :see: `Problems with /usr/lib64 builds <http://bugs.python.org/issue1294959>`_ |
| 52 # :see: `FHS <http://www.pathname.com/fhs/pub/fhs-2.3.html#LIBLTQUALGTALTERNATEF
ORMATESSENTIAL>`_ | 56 # :see: `FHS <http://www.pathname.com/fhs/pub/fhs-2.3.html#LIBLTQUALGTALTERNATEF
ORMATESSENTIAL>`_ |
| 53 if sys.platform.startswith('win'): | 57 if sys.platform.startswith('win'): |
| 54 PY_SOURCE_EXTS = ('py', 'pyw') | 58 PY_SOURCE_EXTS = ('py', 'pyw') |
| 55 PY_COMPILED_EXTS = ('dll', 'pyd') | 59 PY_COMPILED_EXTS = ('dll', 'pyd') |
| 56 STD_LIB_DIR = get_python_lib(standard_lib=1) | |
| 57 else: | 60 else: |
| 58 PY_SOURCE_EXTS = ('py',) | 61 PY_SOURCE_EXTS = ('py',) |
| 59 PY_COMPILED_EXTS = ('so',) | 62 PY_COMPILED_EXTS = ('so',) |
| 60 # extend lib dir with some arch-dependant paths | 63 |
| 61 STD_LIB_DIR = join(get_config_var("LIBDIR"), "python%s" % get_python_version
()) | 64 try: |
| 65 STD_LIB_DIR = get_python_lib(standard_lib=1) |
| 66 # get_python_lib(standard_lib=1) is not available on pypy, set STD_LIB_DIR to |
| 67 # non-valid path, see https://bugs.pypy.org/issue1164 |
| 68 except DistutilsPlatformError: |
| 69 STD_LIB_DIR = '//' |
| 70 |
| 71 EXT_LIB_DIR = get_python_lib() |
| 62 | 72 |
| 63 BUILTIN_MODULES = dict(zip(sys.builtin_module_names, | 73 BUILTIN_MODULES = dict(zip(sys.builtin_module_names, |
| 64 [1]*len(sys.builtin_module_names))) | 74 [1]*len(sys.builtin_module_names))) |
| 65 | 75 |
| 66 | 76 |
| 67 class NoSourceFile(Exception): | 77 class NoSourceFile(Exception): |
| 68 """exception raised when we are not able to get a python | 78 """exception raised when we are not able to get a python |
| 69 source file for a precompiled file | 79 source file for a precompiled file |
| 70 """ | 80 """ |
| 71 | 81 |
| 72 class LazyObject(object): | 82 class LazyObject(object): |
| 73 def __init__(self, module, obj): | 83 def __init__(self, module, obj): |
| 74 self.module = module | 84 self.module = module |
| 75 self.obj = obj | 85 self.obj = obj |
| 76 self._imported = None | 86 self._imported = None |
| 77 | 87 |
| 78 def _getobj(self): | 88 def _getobj(self): |
| 79 if self._imported is None: | 89 if self._imported is None: |
| 80 self._imported = getattr(load_module_from_name(self.module), | 90 self._imported = getattr(load_module_from_name(self.module), |
| 81 self.obj) | 91 self.obj) |
| 82 return self._imported | 92 return self._imported |
| 83 | 93 |
| 84 def __getattribute__(self, attr): | 94 def __getattribute__(self, attr): |
| 85 try: | 95 try: |
| 86 return super(LazyObject, self).__getattribute__(attr) | 96 return super(LazyObject, self).__getattribute__(attr) |
| 87 except AttributeError, ex: | 97 except AttributeError as ex: |
| 88 return getattr(self._getobj(), attr) | 98 return getattr(self._getobj(), attr) |
| 89 | 99 |
| 90 def __call__(self, *args, **kwargs): | 100 def __call__(self, *args, **kwargs): |
| 91 return self._getobj()(*args, **kwargs) | 101 return self._getobj()(*args, **kwargs) |
| 92 | 102 |
| 93 | 103 |
| 94 def load_module_from_name(dotted_name, path=None, use_sys=1): | 104 def load_module_from_name(dotted_name, path=None, use_sys=1): |
| 95 """Load a Python module from it's name. | 105 """Load a Python module from its name. |
| 96 | 106 |
| 97 :type dotted_name: str | 107 :type dotted_name: str |
| 98 :param dotted_name: python name of a module or package | 108 :param dotted_name: python name of a module or package |
| 99 | 109 |
| 100 :type path: list or None | 110 :type path: list or None |
| 101 :param path: | 111 :param path: |
| 102 optional list of path where the module or package should be | 112 optional list of path where the module or package should be |
| 103 searched (use sys.path if nothing or None is given) | 113 searched (use sys.path if nothing or None is given) |
| 104 | 114 |
| 105 :type use_sys: bool | 115 :type use_sys: bool |
| 106 :param use_sys: | 116 :param use_sys: |
| 107 boolean indicating whether the sys.modules dictionary should be | 117 boolean indicating whether the sys.modules dictionary should be |
| 108 used or not | 118 used or not |
| 109 | 119 |
| 110 | 120 |
| 111 :raise ImportError: if the module or package is not found | 121 :raise ImportError: if the module or package is not found |
| 112 | 122 |
| 113 :rtype: module | 123 :rtype: module |
| 114 :return: the loaded module | 124 :return: the loaded module |
| 115 """ | 125 """ |
| 116 return load_module_from_modpath(dotted_name.split('.'), path, use_sys) | 126 return load_module_from_modpath(dotted_name.split('.'), path, use_sys) |
| 117 | 127 |
| 118 | 128 |
| 119 def load_module_from_modpath(parts, path=None, use_sys=1): | 129 def load_module_from_modpath(parts, path=None, use_sys=1): |
| 120 """Load a python module from it's splitted name. | 130 """Load a python module from its splitted name. |
| 121 | 131 |
| 122 :type parts: list(str) or tuple(str) | 132 :type parts: list(str) or tuple(str) |
| 123 :param parts: | 133 :param parts: |
| 124 python name of a module or package splitted on '.' | 134 python name of a module or package splitted on '.' |
| 125 | 135 |
| 126 :type path: list or None | 136 :type path: list or None |
| 127 :param path: | 137 :param path: |
| 128 optional list of path where the module or package should be | 138 optional list of path where the module or package should be |
| 129 searched (use sys.path if nothing or None is given) | 139 searched (use sys.path if nothing or None is given) |
| 130 | 140 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 144 pass | 154 pass |
| 145 modpath = [] | 155 modpath = [] |
| 146 prevmodule = None | 156 prevmodule = None |
| 147 for part in parts: | 157 for part in parts: |
| 148 modpath.append(part) | 158 modpath.append(part) |
| 149 curname = '.'.join(modpath) | 159 curname = '.'.join(modpath) |
| 150 module = None | 160 module = None |
| 151 if len(modpath) != len(parts): | 161 if len(modpath) != len(parts): |
| 152 # even with use_sys=False, should try to get outer packages from sys
.modules | 162 # even with use_sys=False, should try to get outer packages from sys
.modules |
| 153 module = sys.modules.get(curname) | 163 module = sys.modules.get(curname) |
| 164 elif use_sys: |
| 165 # because it may have been indirectly loaded through a parent |
| 166 module = sys.modules.get(curname) |
| 154 if module is None: | 167 if module is None: |
| 155 mp_file, mp_filename, mp_desc = find_module(part, path) | 168 mp_file, mp_filename, mp_desc = find_module(part, path) |
| 156 module = load_module(curname, mp_file, mp_filename, mp_desc) | 169 module = load_module(curname, mp_file, mp_filename, mp_desc) |
| 157 if prevmodule: | 170 if prevmodule: |
| 158 setattr(prevmodule, part, module) | 171 setattr(prevmodule, part, module) |
| 159 _file = getattr(module, '__file__', '') | 172 _file = getattr(module, '__file__', '') |
| 160 if not _file and len(modpath) != len(parts): | 173 if not _file and len(modpath) != len(parts): |
| 161 raise ImportError('no module in %s' % '.'.join(parts[len(modpath):])
) | 174 raise ImportError('no module in %s' % '.'.join(parts[len(modpath):])
) |
| 162 path = [dirname( _file )] | 175 path = [dirname( _file )] |
| 163 prevmodule = module | 176 prevmodule = module |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 if extrapath is not None: | 236 if extrapath is not None: |
| 224 for path_ in extrapath: | 237 for path_ in extrapath: |
| 225 path = abspath(path_) | 238 path = abspath(path_) |
| 226 if path and base[:len(path)] == path: | 239 if path and base[:len(path)] == path: |
| 227 submodpath = [pkg for pkg in base[len(path):].split(os.sep) | 240 submodpath = [pkg for pkg in base[len(path):].split(os.sep) |
| 228 if pkg] | 241 if pkg] |
| 229 if _check_init(path, submodpath[:-1]): | 242 if _check_init(path, submodpath[:-1]): |
| 230 return extrapath[path_].split('.') + submodpath | 243 return extrapath[path_].split('.') + submodpath |
| 231 for path in sys.path: | 244 for path in sys.path: |
| 232 path = abspath(path) | 245 path = abspath(path) |
| 233 if path and base[:len(path)] == path: | 246 if path and base.startswith(path): |
| 234 if filename.find('site-packages') != -1 and \ | |
| 235 path.find('site-packages') == -1: | |
| 236 continue | |
| 237 modpath = [pkg for pkg in base[len(path):].split(os.sep) if pkg] | 247 modpath = [pkg for pkg in base[len(path):].split(os.sep) if pkg] |
| 238 if _check_init(path, modpath[:-1]): | 248 if _check_init(path, modpath[:-1]): |
| 239 return modpath | 249 return modpath |
| 240 raise ImportError('Unable to find module for %s in %s' % ( | 250 raise ImportError('Unable to find module for %s in %s' % ( |
| 241 filename, ', \n'.join(sys.path))) | 251 filename, ', \n'.join(sys.path))) |
| 242 | 252 |
| 243 | 253 |
| 244 | 254 |
| 245 def file_from_modpath(modpath, path=None, context_file=None): | 255 def file_from_modpath(modpath, path=None, context_file=None): |
| 246 """given a mod path (i.e. splitted module / package name), return the | 256 """given a mod path (i.e. splitted module / package name), return the |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 439 source_path = '%s.%s' % (base, ext) | 449 source_path = '%s.%s' % (base, ext) |
| 440 if exists(source_path): | 450 if exists(source_path): |
| 441 return source_path | 451 return source_path |
| 442 if include_no_ext and not orig_ext and exists(base): | 452 if include_no_ext and not orig_ext and exists(base): |
| 443 return base | 453 return base |
| 444 raise NoSourceFile(filename) | 454 raise NoSourceFile(filename) |
| 445 | 455 |
| 446 | 456 |
| 447 def cleanup_sys_modules(directories): | 457 def cleanup_sys_modules(directories): |
| 448 """remove submodules of `directories` from `sys.modules`""" | 458 """remove submodules of `directories` from `sys.modules`""" |
| 449 for modname, module in sys.modules.items(): | 459 cleaned = [] |
| 460 for modname, module in list(sys.modules.items()): |
| 450 modfile = getattr(module, '__file__', None) | 461 modfile = getattr(module, '__file__', None) |
| 451 if modfile: | 462 if modfile: |
| 452 for directory in directories: | 463 for directory in directories: |
| 453 if modfile.startswith(directory): | 464 if modfile.startswith(directory): |
| 465 cleaned.append(modname) |
| 454 del sys.modules[modname] | 466 del sys.modules[modname] |
| 455 break | 467 break |
| 468 return cleaned |
| 456 | 469 |
| 457 | 470 |
| 458 def is_python_source(filename): | 471 def is_python_source(filename): |
| 459 """ | 472 """ |
| 460 rtype: bool | 473 rtype: bool |
| 461 return: True if the filename is a python source file | 474 return: True if the filename is a python source file |
| 462 """ | 475 """ |
| 463 return splitext(filename)[1][1:] in PY_SOURCE_EXTS | 476 return splitext(filename)[1][1:] in PY_SOURCE_EXTS |
| 464 | 477 |
| 465 | 478 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 477 | 490 |
| 478 :rtype: bool | 491 :rtype: bool |
| 479 :return: | 492 :return: |
| 480 true if the module: | 493 true if the module: |
| 481 - is located on the path listed in one of the directory in `std_path` | 494 - is located on the path listed in one of the directory in `std_path` |
| 482 - is a built-in module | 495 - is a built-in module |
| 483 """ | 496 """ |
| 484 modname = modname.split('.')[0] | 497 modname = modname.split('.')[0] |
| 485 try: | 498 try: |
| 486 filename = file_from_modpath([modname]) | 499 filename = file_from_modpath([modname]) |
| 487 except ImportError, ex: | 500 except ImportError as ex: |
| 488 # import failed, i'm probably not so wrong by supposing it's | 501 # import failed, i'm probably not so wrong by supposing it's |
| 489 # not standard... | 502 # not standard... |
| 490 return 0 | 503 return 0 |
| 491 # modules which are not living in a file are considered standard | 504 # modules which are not living in a file are considered standard |
| 492 # (sys and __builtin__ for instance) | 505 # (sys and __builtin__ for instance) |
| 493 if filename is None: | 506 if filename is None: |
| 494 return 1 | 507 return 1 |
| 495 filename = abspath(filename) | 508 filename = abspath(filename) |
| 509 if filename.startswith(EXT_LIB_DIR): |
| 510 return 0 |
| 496 for path in std_path: | 511 for path in std_path: |
| 497 path = abspath(path) | 512 if filename.startswith(abspath(path)): |
| 498 if filename.startswith(path): | 513 return 1 |
| 499 pfx_len = len(path) | |
| 500 if filename[pfx_len+1:pfx_len+14] != 'site-packages': | |
| 501 return 1 | |
| 502 return 0 | |
| 503 return False | 514 return False |
| 504 | 515 |
| 505 | 516 |
| 506 | 517 |
| 507 def is_relative(modname, from_file): | 518 def is_relative(modname, from_file): |
| 508 """return true if the given module name is relative to the given | 519 """return true if the given module name is relative to the given |
| 509 file name | 520 file name |
| 510 | 521 |
| 511 :type modname: str | 522 :type modname: str |
| 512 :param modname: name of the module we are interested in | 523 :param modname: name of the module we are interested in |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 558 elif mtype == PKG_DIRECTORY: | 569 elif mtype == PKG_DIRECTORY: |
| 559 mp_filename = _has_init(mp_filename) | 570 mp_filename = _has_init(mp_filename) |
| 560 return mp_filename | 571 return mp_filename |
| 561 | 572 |
| 562 def _search_zip(modpath, pic): | 573 def _search_zip(modpath, pic): |
| 563 for filepath, importer in pic.items(): | 574 for filepath, importer in pic.items(): |
| 564 if importer is not None: | 575 if importer is not None: |
| 565 if importer.find_module(modpath[0]): | 576 if importer.find_module(modpath[0]): |
| 566 if not importer.find_module('/'.join(modpath)): | 577 if not importer.find_module('/'.join(modpath)): |
| 567 raise ImportError('No module named %s in %s/%s' % ( | 578 raise ImportError('No module named %s in %s/%s' % ( |
| 568 '.'.join(modpath[1:]), file, modpath)) | 579 '.'.join(modpath[1:]), filepath, modpath)) |
| 569 return ZIPFILE, abspath(filepath) + '/' + '/'.join(modpath), fil
epath | 580 return ZIPFILE, abspath(filepath) + '/' + '/'.join(modpath), fil
epath |
| 570 raise ImportError('No module named %s' % '.'.join(modpath)) | 581 raise ImportError('No module named %s' % '.'.join(modpath)) |
| 571 | 582 |
| 583 try: |
| 584 import pkg_resources |
| 585 except ImportError: |
| 586 pkg_resources = None |
| 587 |
| 572 def _module_file(modpath, path=None): | 588 def _module_file(modpath, path=None): |
| 573 """get a module type / file path | 589 """get a module type / file path |
| 574 | 590 |
| 575 :type modpath: list or tuple | 591 :type modpath: list or tuple |
| 576 :param modpath: | 592 :param modpath: |
| 577 splitted module's name (i.e name of a module or package splitted | 593 splitted module's name (i.e name of a module or package splitted |
| 578 on '.'), with leading empty strings for explicit relative import | 594 on '.'), with leading empty strings for explicit relative import |
| 579 | 595 |
| 580 :type path: list or None | 596 :type path: list or None |
| 581 :param path: | 597 :param path: |
| (...skipping 10 matching lines...) Expand all Loading... |
| 592 _path = (path is None and sys.path or path) | 608 _path = (path is None and sys.path or path) |
| 593 for __path in _path: | 609 for __path in _path: |
| 594 if not __path in pic: | 610 if not __path in pic: |
| 595 try: | 611 try: |
| 596 pic[__path] = zipimport.zipimporter(__path) | 612 pic[__path] = zipimport.zipimporter(__path) |
| 597 except zipimport.ZipImportError: | 613 except zipimport.ZipImportError: |
| 598 pic[__path] = None | 614 pic[__path] = None |
| 599 checkeggs = True | 615 checkeggs = True |
| 600 except AttributeError: | 616 except AttributeError: |
| 601 checkeggs = False | 617 checkeggs = False |
| 618 # pkg_resources support (aka setuptools namespace packages) |
| 619 if (pkg_resources is not None |
| 620 and modpath[0] in pkg_resources._namespace_packages |
| 621 and modpath[0] in sys.modules |
| 622 and len(modpath) > 1): |
| 623 # setuptools has added into sys.modules a module object with proper |
| 624 # __path__, get back information from there |
| 625 module = sys.modules[modpath.pop(0)] |
| 626 path = module.__path__ |
| 602 imported = [] | 627 imported = [] |
| 603 while modpath: | 628 while modpath: |
| 629 modname = modpath[0] |
| 630 # take care to changes in find_module implementation wrt builtin modules |
| 631 # |
| 632 # Python 2.6.6 (r266:84292, Sep 11 2012, 08:34:23) |
| 633 # >>> imp.find_module('posix') |
| 634 # (None, 'posix', ('', '', 6)) |
| 635 # |
| 636 # Python 3.3.1 (default, Apr 26 2013, 12:08:46) |
| 637 # >>> imp.find_module('posix') |
| 638 # (None, None, ('', '', 6)) |
| 604 try: | 639 try: |
| 605 _, mp_filename, mp_desc = find_module(modpath[0], path) | 640 _, mp_filename, mp_desc = find_module(modname, path) |
| 606 except ImportError: | 641 except ImportError: |
| 607 if checkeggs: | 642 if checkeggs: |
| 608 return _search_zip(modpath, pic)[:2] | 643 return _search_zip(modpath, pic)[:2] |
| 609 raise | 644 raise |
| 610 else: | 645 else: |
| 611 if checkeggs: | 646 if checkeggs and mp_filename: |
| 612 fullabspath = [abspath(x) for x in _path] | 647 fullabspath = [abspath(x) for x in _path] |
| 613 try: | 648 try: |
| 614 pathindex = fullabspath.index(dirname(abspath(mp_filename))) | 649 pathindex = fullabspath.index(dirname(abspath(mp_filename))) |
| 615 emtype, emp_filename, zippath = _search_zip(modpath, pic) | 650 emtype, emp_filename, zippath = _search_zip(modpath, pic) |
| 616 if pathindex > _path.index(zippath): | 651 if pathindex > _path.index(zippath): |
| 617 # an egg takes priority | 652 # an egg takes priority |
| 618 return emtype, emp_filename | 653 return emtype, emp_filename |
| 619 except ValueError: | 654 except ValueError: |
| 620 # XXX not in _path | 655 # XXX not in _path |
| 621 pass | 656 pass |
| 622 except ImportError: | 657 except ImportError: |
| 623 pass | 658 pass |
| 624 checkeggs = False | 659 checkeggs = False |
| 625 imported.append(modpath.pop(0)) | 660 imported.append(modpath.pop(0)) |
| 626 mtype = mp_desc[2] | 661 mtype = mp_desc[2] |
| 627 if modpath: | 662 if modpath: |
| 628 if mtype != PKG_DIRECTORY: | 663 if mtype != PKG_DIRECTORY: |
| 629 raise ImportError('No module %s in %s' % ('.'.join(modpath), | 664 raise ImportError('No module %s in %s' % ('.'.join(modpath), |
| 630 '.'.join(imported))) | 665 '.'.join(imported))) |
| 631 path = [mp_filename] | 666 # XXX guess if package is using pkgutil.extend_path by looking for |
| 667 # those keywords in the first four Kbytes |
| 668 try: |
| 669 with open(join(mp_filename, '__init__.py')) as stream: |
| 670 data = stream.read(4096) |
| 671 except IOError: |
| 672 path = [mp_filename] |
| 673 else: |
| 674 if 'pkgutil' in data and 'extend_path' in data: |
| 675 # extend_path is called, search sys.path for module/packages |
| 676 # of this name see pkgutil.extend_path documentation |
| 677 path = [join(p, *imported) for p in sys.path |
| 678 if isdir(join(p, *imported))] |
| 679 else: |
| 680 path = [mp_filename] |
| 632 return mtype, mp_filename | 681 return mtype, mp_filename |
| 633 | 682 |
| 634 def _is_python_file(filename): | 683 def _is_python_file(filename): |
| 635 """return true if the given filename should be considered as a python file | 684 """return true if the given filename should be considered as a python file |
| 636 | 685 |
| 637 .pyc and .pyo are ignored | 686 .pyc and .pyo are ignored |
| 638 """ | 687 """ |
| 639 for ext in ('.py', '.so', '.pyd', '.pyw'): | 688 for ext in ('.py', '.so', '.pyd', '.pyw'): |
| 640 if filename.endswith(ext): | 689 if filename.endswith(ext): |
| 641 return True | 690 return True |
| 642 return False | 691 return False |
| 643 | 692 |
| 644 | 693 |
| 645 def _has_init(directory): | 694 def _has_init(directory): |
| 646 """if the given directory has a valid __init__ file, return its path, | 695 """if the given directory has a valid __init__ file, return its path, |
| 647 else return None | 696 else return None |
| 648 """ | 697 """ |
| 649 mod_or_pack = join(directory, '__init__') | 698 mod_or_pack = join(directory, '__init__') |
| 650 for ext in PY_SOURCE_EXTS + ('pyc', 'pyo'): | 699 for ext in PY_SOURCE_EXTS + ('pyc', 'pyo'): |
| 651 if exists(mod_or_pack + '.' + ext): | 700 if exists(mod_or_pack + '.' + ext): |
| 652 return mod_or_pack + '.' + ext | 701 return mod_or_pack + '.' + ext |
| 653 return None | 702 return None |
| OLD | NEW |