OLD | NEW |
(Empty) | |
| 1 # -*- coding: utf-8 -*- |
| 2 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
| 3 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
| 4 # |
| 5 # This file is part of logilab-common. |
| 6 # |
| 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 |
| 9 # Software Foundation, either version 2.1 of the License, or (at your option) an
y |
| 10 # later version. |
| 11 # |
| 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 |
| 14 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
| 15 # details. |
| 16 # |
| 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/>. |
| 19 """Python modules manipulation utility functions. |
| 20 |
| 21 :type PY_SOURCE_EXTS: tuple(str) |
| 22 :var PY_SOURCE_EXTS: list of possible python source file extension |
| 23 |
| 24 :type STD_LIB_DIR: str |
| 25 :var STD_LIB_DIR: directory where standard modules are located |
| 26 |
| 27 :type BUILTIN_MODULES: dict |
| 28 :var BUILTIN_MODULES: dictionary with builtin module names has key |
| 29 """ |
| 30 |
| 31 __docformat__ = "restructuredtext en" |
| 32 |
| 33 import sys |
| 34 import os |
| 35 from os.path import splitext, join, abspath, isdir, dirname, exists, basename |
| 36 from imp import find_module, load_module, C_BUILTIN, PY_COMPILED, PKG_DIRECTORY |
| 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 |
| 41 |
| 42 try: |
| 43 import zipimport |
| 44 except ImportError: |
| 45 zipimport = None |
| 46 |
| 47 ZIPFILE = object() |
| 48 |
| 49 from logilab.common import STD_BLACKLIST, _handle_blacklist |
| 50 |
| 51 # Notes about STD_LIB_DIR |
| 52 # Consider arch-specific installation for STD_LIB_DIR definition |
| 53 # :mod:`distutils.sysconfig` contains to much hardcoded values to rely on |
| 54 # |
| 55 # :see: `Problems with /usr/lib64 builds <http://bugs.python.org/issue1294959>`_ |
| 56 # :see: `FHS <http://www.pathname.com/fhs/pub/fhs-2.3.html#LIBLTQUALGTALTERNATEF
ORMATESSENTIAL>`_ |
| 57 if sys.platform.startswith('win'): |
| 58 PY_SOURCE_EXTS = ('py', 'pyw') |
| 59 PY_COMPILED_EXTS = ('dll', 'pyd') |
| 60 else: |
| 61 PY_SOURCE_EXTS = ('py',) |
| 62 PY_COMPILED_EXTS = ('so',) |
| 63 |
| 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() |
| 72 |
| 73 BUILTIN_MODULES = dict(zip(sys.builtin_module_names, |
| 74 [1]*len(sys.builtin_module_names))) |
| 75 |
| 76 |
| 77 class NoSourceFile(Exception): |
| 78 """exception raised when we are not able to get a python |
| 79 source file for a precompiled file |
| 80 """ |
| 81 |
| 82 class LazyObject(object): |
| 83 def __init__(self, module, obj): |
| 84 self.module = module |
| 85 self.obj = obj |
| 86 self._imported = None |
| 87 |
| 88 def _getobj(self): |
| 89 if self._imported is None: |
| 90 self._imported = getattr(load_module_from_name(self.module), |
| 91 self.obj) |
| 92 return self._imported |
| 93 |
| 94 def __getattribute__(self, attr): |
| 95 try: |
| 96 return super(LazyObject, self).__getattribute__(attr) |
| 97 except AttributeError as ex: |
| 98 return getattr(self._getobj(), attr) |
| 99 |
| 100 def __call__(self, *args, **kwargs): |
| 101 return self._getobj()(*args, **kwargs) |
| 102 |
| 103 |
| 104 def load_module_from_name(dotted_name, path=None, use_sys=1): |
| 105 """Load a Python module from its name. |
| 106 |
| 107 :type dotted_name: str |
| 108 :param dotted_name: python name of a module or package |
| 109 |
| 110 :type path: list or None |
| 111 :param path: |
| 112 optional list of path where the module or package should be |
| 113 searched (use sys.path if nothing or None is given) |
| 114 |
| 115 :type use_sys: bool |
| 116 :param use_sys: |
| 117 boolean indicating whether the sys.modules dictionary should be |
| 118 used or not |
| 119 |
| 120 |
| 121 :raise ImportError: if the module or package is not found |
| 122 |
| 123 :rtype: module |
| 124 :return: the loaded module |
| 125 """ |
| 126 return load_module_from_modpath(dotted_name.split('.'), path, use_sys) |
| 127 |
| 128 |
| 129 def load_module_from_modpath(parts, path=None, use_sys=1): |
| 130 """Load a python module from its splitted name. |
| 131 |
| 132 :type parts: list(str) or tuple(str) |
| 133 :param parts: |
| 134 python name of a module or package splitted on '.' |
| 135 |
| 136 :type path: list or None |
| 137 :param path: |
| 138 optional list of path where the module or package should be |
| 139 searched (use sys.path if nothing or None is given) |
| 140 |
| 141 :type use_sys: bool |
| 142 :param use_sys: |
| 143 boolean indicating whether the sys.modules dictionary should be used or no
t |
| 144 |
| 145 :raise ImportError: if the module or package is not found |
| 146 |
| 147 :rtype: module |
| 148 :return: the loaded module |
| 149 """ |
| 150 if use_sys: |
| 151 try: |
| 152 return sys.modules['.'.join(parts)] |
| 153 except KeyError: |
| 154 pass |
| 155 modpath = [] |
| 156 prevmodule = None |
| 157 for part in parts: |
| 158 modpath.append(part) |
| 159 curname = '.'.join(modpath) |
| 160 module = None |
| 161 if len(modpath) != len(parts): |
| 162 # even with use_sys=False, should try to get outer packages from sys
.modules |
| 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) |
| 167 if module is None: |
| 168 mp_file, mp_filename, mp_desc = find_module(part, path) |
| 169 module = load_module(curname, mp_file, mp_filename, mp_desc) |
| 170 if prevmodule: |
| 171 setattr(prevmodule, part, module) |
| 172 _file = getattr(module, '__file__', '') |
| 173 if not _file and len(modpath) != len(parts): |
| 174 raise ImportError('no module in %s' % '.'.join(parts[len(modpath):])
) |
| 175 path = [dirname( _file )] |
| 176 prevmodule = module |
| 177 return module |
| 178 |
| 179 |
| 180 def load_module_from_file(filepath, path=None, use_sys=1, extrapath=None): |
| 181 """Load a Python module from it's path. |
| 182 |
| 183 :type filepath: str |
| 184 :param filepath: path to the python module or package |
| 185 |
| 186 :type path: list or None |
| 187 :param path: |
| 188 optional list of path where the module or package should be |
| 189 searched (use sys.path if nothing or None is given) |
| 190 |
| 191 :type use_sys: bool |
| 192 :param use_sys: |
| 193 boolean indicating whether the sys.modules dictionary should be |
| 194 used or not |
| 195 |
| 196 |
| 197 :raise ImportError: if the module or package is not found |
| 198 |
| 199 :rtype: module |
| 200 :return: the loaded module |
| 201 """ |
| 202 modpath = modpath_from_file(filepath, extrapath) |
| 203 return load_module_from_modpath(modpath, path, use_sys) |
| 204 |
| 205 |
| 206 def _check_init(path, mod_path): |
| 207 """check there are some __init__.py all along the way""" |
| 208 for part in mod_path: |
| 209 path = join(path, part) |
| 210 if not _has_init(path): |
| 211 return False |
| 212 return True |
| 213 |
| 214 |
| 215 def modpath_from_file(filename, extrapath=None): |
| 216 """given a file path return the corresponding splitted module's name |
| 217 (i.e name of a module or package splitted on '.') |
| 218 |
| 219 :type filename: str |
| 220 :param filename: file's path for which we want the module's name |
| 221 |
| 222 :type extrapath: dict |
| 223 :param extrapath: |
| 224 optional extra search path, with path as key and package name for the path |
| 225 as value. This is usually useful to handle package splitted in multiple |
| 226 directories using __path__ trick. |
| 227 |
| 228 |
| 229 :raise ImportError: |
| 230 if the corresponding module's name has not been found |
| 231 |
| 232 :rtype: list(str) |
| 233 :return: the corresponding splitted module's name |
| 234 """ |
| 235 base = splitext(abspath(filename))[0] |
| 236 if extrapath is not None: |
| 237 for path_ in extrapath: |
| 238 path = abspath(path_) |
| 239 if path and base[:len(path)] == path: |
| 240 submodpath = [pkg for pkg in base[len(path):].split(os.sep) |
| 241 if pkg] |
| 242 if _check_init(path, submodpath[:-1]): |
| 243 return extrapath[path_].split('.') + submodpath |
| 244 for path in sys.path: |
| 245 path = abspath(path) |
| 246 if path and base.startswith(path): |
| 247 modpath = [pkg for pkg in base[len(path):].split(os.sep) if pkg] |
| 248 if _check_init(path, modpath[:-1]): |
| 249 return modpath |
| 250 raise ImportError('Unable to find module for %s in %s' % ( |
| 251 filename, ', \n'.join(sys.path))) |
| 252 |
| 253 |
| 254 |
| 255 def file_from_modpath(modpath, path=None, context_file=None): |
| 256 """given a mod path (i.e. splitted module / package name), return the |
| 257 corresponding file, giving priority to source file over precompiled |
| 258 file if it exists |
| 259 |
| 260 :type modpath: list or tuple |
| 261 :param modpath: |
| 262 splitted module's name (i.e name of a module or package splitted |
| 263 on '.') |
| 264 (this means explicit relative imports that start with dots have |
| 265 empty strings in this list!) |
| 266 |
| 267 :type path: list or None |
| 268 :param path: |
| 269 optional list of path where the module or package should be |
| 270 searched (use sys.path if nothing or None is given) |
| 271 |
| 272 :type context_file: str or None |
| 273 :param context_file: |
| 274 context file to consider, necessary if the identifier has been |
| 275 introduced using a relative import unresolvable in the actual |
| 276 context (i.e. modutils) |
| 277 |
| 278 :raise ImportError: if there is no such module in the directory |
| 279 |
| 280 :rtype: str or None |
| 281 :return: |
| 282 the path to the module's file or None if it's an integrated |
| 283 builtin module such as 'sys' |
| 284 """ |
| 285 if context_file is not None: |
| 286 context = dirname(context_file) |
| 287 else: |
| 288 context = context_file |
| 289 if modpath[0] == 'xml': |
| 290 # handle _xmlplus |
| 291 try: |
| 292 return _file_from_modpath(['_xmlplus'] + modpath[1:], path, context) |
| 293 except ImportError: |
| 294 return _file_from_modpath(modpath, path, context) |
| 295 elif modpath == ['os', 'path']: |
| 296 # FIXME: currently ignoring search_path... |
| 297 return os.path.__file__ |
| 298 return _file_from_modpath(modpath, path, context) |
| 299 |
| 300 |
| 301 |
| 302 def get_module_part(dotted_name, context_file=None): |
| 303 """given a dotted name return the module part of the name : |
| 304 |
| 305 >>> get_module_part('logilab.common.modutils.get_module_part') |
| 306 'logilab.common.modutils' |
| 307 |
| 308 :type dotted_name: str |
| 309 :param dotted_name: full name of the identifier we are interested in |
| 310 |
| 311 :type context_file: str or None |
| 312 :param context_file: |
| 313 context file to consider, necessary if the identifier has been |
| 314 introduced using a relative import unresolvable in the actual |
| 315 context (i.e. modutils) |
| 316 |
| 317 |
| 318 :raise ImportError: if there is no such module in the directory |
| 319 |
| 320 :rtype: str or None |
| 321 :return: |
| 322 the module part of the name or None if we have not been able at |
| 323 all to import the given name |
| 324 |
| 325 XXX: deprecated, since it doesn't handle package precedence over module |
| 326 (see #10066) |
| 327 """ |
| 328 # os.path trick |
| 329 if dotted_name.startswith('os.path'): |
| 330 return 'os.path' |
| 331 parts = dotted_name.split('.') |
| 332 if context_file is not None: |
| 333 # first check for builtin module which won't be considered latter |
| 334 # in that case (path != None) |
| 335 if parts[0] in BUILTIN_MODULES: |
| 336 if len(parts) > 2: |
| 337 raise ImportError(dotted_name) |
| 338 return parts[0] |
| 339 # don't use += or insert, we want a new list to be created ! |
| 340 path = None |
| 341 starti = 0 |
| 342 if parts[0] == '': |
| 343 assert context_file is not None, \ |
| 344 'explicit relative import, but no context_file?' |
| 345 path = [] # prevent resolving the import non-relatively |
| 346 starti = 1 |
| 347 while parts[starti] == '': # for all further dots: change context |
| 348 starti += 1 |
| 349 context_file = dirname(context_file) |
| 350 for i in range(starti, len(parts)): |
| 351 try: |
| 352 file_from_modpath(parts[starti:i+1], |
| 353 path=path, context_file=context_file) |
| 354 except ImportError: |
| 355 if not i >= max(1, len(parts) - 2): |
| 356 raise |
| 357 return '.'.join(parts[:i]) |
| 358 return dotted_name |
| 359 |
| 360 |
| 361 def get_modules(package, src_directory, blacklist=STD_BLACKLIST): |
| 362 """given a package directory return a list of all available python |
| 363 modules in the package and its subpackages |
| 364 |
| 365 :type package: str |
| 366 :param package: the python name for the package |
| 367 |
| 368 :type src_directory: str |
| 369 :param src_directory: |
| 370 path of the directory corresponding to the package |
| 371 |
| 372 :type blacklist: list or tuple |
| 373 :param blacklist: |
| 374 optional list of files or directory to ignore, default to |
| 375 the value of `logilab.common.STD_BLACKLIST` |
| 376 |
| 377 :rtype: list |
| 378 :return: |
| 379 the list of all available python modules in the package and its |
| 380 subpackages |
| 381 """ |
| 382 modules = [] |
| 383 for directory, dirnames, filenames in os.walk(src_directory): |
| 384 _handle_blacklist(blacklist, dirnames, filenames) |
| 385 # check for __init__.py |
| 386 if not '__init__.py' in filenames: |
| 387 dirnames[:] = () |
| 388 continue |
| 389 if directory != src_directory: |
| 390 dir_package = directory[len(src_directory):].replace(os.sep, '.') |
| 391 modules.append(package + dir_package) |
| 392 for filename in filenames: |
| 393 if _is_python_file(filename) and filename != '__init__.py': |
| 394 src = join(directory, filename) |
| 395 module = package + src[len(src_directory):-3] |
| 396 modules.append(module.replace(os.sep, '.')) |
| 397 return modules |
| 398 |
| 399 |
| 400 |
| 401 def get_module_files(src_directory, blacklist=STD_BLACKLIST): |
| 402 """given a package directory return a list of all available python |
| 403 module's files in the package and its subpackages |
| 404 |
| 405 :type src_directory: str |
| 406 :param src_directory: |
| 407 path of the directory corresponding to the package |
| 408 |
| 409 :type blacklist: list or tuple |
| 410 :param blacklist: |
| 411 optional list of files or directory to ignore, default to the value of |
| 412 `logilab.common.STD_BLACKLIST` |
| 413 |
| 414 :rtype: list |
| 415 :return: |
| 416 the list of all available python module's files in the package and |
| 417 its subpackages |
| 418 """ |
| 419 files = [] |
| 420 for directory, dirnames, filenames in os.walk(src_directory): |
| 421 _handle_blacklist(blacklist, dirnames, filenames) |
| 422 # check for __init__.py |
| 423 if not '__init__.py' in filenames: |
| 424 dirnames[:] = () |
| 425 continue |
| 426 for filename in filenames: |
| 427 if _is_python_file(filename): |
| 428 src = join(directory, filename) |
| 429 files.append(src) |
| 430 return files |
| 431 |
| 432 |
| 433 def get_source_file(filename, include_no_ext=False): |
| 434 """given a python module's file name return the matching source file |
| 435 name (the filename will be returned identically if it's a already an |
| 436 absolute path to a python source file...) |
| 437 |
| 438 :type filename: str |
| 439 :param filename: python module's file name |
| 440 |
| 441 |
| 442 :raise NoSourceFile: if no source file exists on the file system |
| 443 |
| 444 :rtype: str |
| 445 :return: the absolute path of the source file if it exists |
| 446 """ |
| 447 base, orig_ext = splitext(abspath(filename)) |
| 448 for ext in PY_SOURCE_EXTS: |
| 449 source_path = '%s.%s' % (base, ext) |
| 450 if exists(source_path): |
| 451 return source_path |
| 452 if include_no_ext and not orig_ext and exists(base): |
| 453 return base |
| 454 raise NoSourceFile(filename) |
| 455 |
| 456 |
| 457 def cleanup_sys_modules(directories): |
| 458 """remove submodules of `directories` from `sys.modules`""" |
| 459 cleaned = [] |
| 460 for modname, module in list(sys.modules.items()): |
| 461 modfile = getattr(module, '__file__', None) |
| 462 if modfile: |
| 463 for directory in directories: |
| 464 if modfile.startswith(directory): |
| 465 cleaned.append(modname) |
| 466 del sys.modules[modname] |
| 467 break |
| 468 return cleaned |
| 469 |
| 470 |
| 471 def is_python_source(filename): |
| 472 """ |
| 473 rtype: bool |
| 474 return: True if the filename is a python source file |
| 475 """ |
| 476 return splitext(filename)[1][1:] in PY_SOURCE_EXTS |
| 477 |
| 478 |
| 479 |
| 480 def is_standard_module(modname, std_path=(STD_LIB_DIR,)): |
| 481 """try to guess if a module is a standard python module (by default, |
| 482 see `std_path` parameter's description) |
| 483 |
| 484 :type modname: str |
| 485 :param modname: name of the module we are interested in |
| 486 |
| 487 :type std_path: list(str) or tuple(str) |
| 488 :param std_path: list of path considered has standard |
| 489 |
| 490 |
| 491 :rtype: bool |
| 492 :return: |
| 493 true if the module: |
| 494 - is located on the path listed in one of the directory in `std_path` |
| 495 - is a built-in module |
| 496 """ |
| 497 modname = modname.split('.')[0] |
| 498 try: |
| 499 filename = file_from_modpath([modname]) |
| 500 except ImportError as ex: |
| 501 # import failed, i'm probably not so wrong by supposing it's |
| 502 # not standard... |
| 503 return 0 |
| 504 # modules which are not living in a file are considered standard |
| 505 # (sys and __builtin__ for instance) |
| 506 if filename is None: |
| 507 return 1 |
| 508 filename = abspath(filename) |
| 509 if filename.startswith(EXT_LIB_DIR): |
| 510 return 0 |
| 511 for path in std_path: |
| 512 if filename.startswith(abspath(path)): |
| 513 return 1 |
| 514 return False |
| 515 |
| 516 |
| 517 |
| 518 def is_relative(modname, from_file): |
| 519 """return true if the given module name is relative to the given |
| 520 file name |
| 521 |
| 522 :type modname: str |
| 523 :param modname: name of the module we are interested in |
| 524 |
| 525 :type from_file: str |
| 526 :param from_file: |
| 527 path of the module from which modname has been imported |
| 528 |
| 529 :rtype: bool |
| 530 :return: |
| 531 true if the module has been imported relatively to `from_file` |
| 532 """ |
| 533 if not isdir(from_file): |
| 534 from_file = dirname(from_file) |
| 535 if from_file in sys.path: |
| 536 return False |
| 537 try: |
| 538 find_module(modname.split('.')[0], [from_file]) |
| 539 return True |
| 540 except ImportError: |
| 541 return False |
| 542 |
| 543 |
| 544 # internal only functions ##################################################### |
| 545 |
| 546 def _file_from_modpath(modpath, path=None, context=None): |
| 547 """given a mod path (i.e. splitted module / package name), return the |
| 548 corresponding file |
| 549 |
| 550 this function is used internally, see `file_from_modpath`'s |
| 551 documentation for more information |
| 552 """ |
| 553 assert len(modpath) > 0 |
| 554 if context is not None: |
| 555 try: |
| 556 mtype, mp_filename = _module_file(modpath, [context]) |
| 557 except ImportError: |
| 558 mtype, mp_filename = _module_file(modpath, path) |
| 559 else: |
| 560 mtype, mp_filename = _module_file(modpath, path) |
| 561 if mtype == PY_COMPILED: |
| 562 try: |
| 563 return get_source_file(mp_filename) |
| 564 except NoSourceFile: |
| 565 return mp_filename |
| 566 elif mtype == C_BUILTIN: |
| 567 # integrated builtin module |
| 568 return None |
| 569 elif mtype == PKG_DIRECTORY: |
| 570 mp_filename = _has_init(mp_filename) |
| 571 return mp_filename |
| 572 |
| 573 def _search_zip(modpath, pic): |
| 574 for filepath, importer in pic.items(): |
| 575 if importer is not None: |
| 576 if importer.find_module(modpath[0]): |
| 577 if not importer.find_module('/'.join(modpath)): |
| 578 raise ImportError('No module named %s in %s/%s' % ( |
| 579 '.'.join(modpath[1:]), filepath, modpath)) |
| 580 return ZIPFILE, abspath(filepath) + '/' + '/'.join(modpath), fil
epath |
| 581 raise ImportError('No module named %s' % '.'.join(modpath)) |
| 582 |
| 583 try: |
| 584 import pkg_resources |
| 585 except ImportError: |
| 586 pkg_resources = None |
| 587 |
| 588 def _module_file(modpath, path=None): |
| 589 """get a module type / file path |
| 590 |
| 591 :type modpath: list or tuple |
| 592 :param modpath: |
| 593 splitted module's name (i.e name of a module or package splitted |
| 594 on '.'), with leading empty strings for explicit relative import |
| 595 |
| 596 :type path: list or None |
| 597 :param path: |
| 598 optional list of path where the module or package should be |
| 599 searched (use sys.path if nothing or None is given) |
| 600 |
| 601 |
| 602 :rtype: tuple(int, str) |
| 603 :return: the module type flag and the file path for a module |
| 604 """ |
| 605 # egg support compat |
| 606 try: |
| 607 pic = sys.path_importer_cache |
| 608 _path = (path is None and sys.path or path) |
| 609 for __path in _path: |
| 610 if not __path in pic: |
| 611 try: |
| 612 pic[__path] = zipimport.zipimporter(__path) |
| 613 except zipimport.ZipImportError: |
| 614 pic[__path] = None |
| 615 checkeggs = True |
| 616 except AttributeError: |
| 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__ |
| 627 imported = [] |
| 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)) |
| 639 try: |
| 640 _, mp_filename, mp_desc = find_module(modname, path) |
| 641 except ImportError: |
| 642 if checkeggs: |
| 643 return _search_zip(modpath, pic)[:2] |
| 644 raise |
| 645 else: |
| 646 if checkeggs and mp_filename: |
| 647 fullabspath = [abspath(x) for x in _path] |
| 648 try: |
| 649 pathindex = fullabspath.index(dirname(abspath(mp_filename))) |
| 650 emtype, emp_filename, zippath = _search_zip(modpath, pic) |
| 651 if pathindex > _path.index(zippath): |
| 652 # an egg takes priority |
| 653 return emtype, emp_filename |
| 654 except ValueError: |
| 655 # XXX not in _path |
| 656 pass |
| 657 except ImportError: |
| 658 pass |
| 659 checkeggs = False |
| 660 imported.append(modpath.pop(0)) |
| 661 mtype = mp_desc[2] |
| 662 if modpath: |
| 663 if mtype != PKG_DIRECTORY: |
| 664 raise ImportError('No module %s in %s' % ('.'.join(modpath), |
| 665 '.'.join(imported))) |
| 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] |
| 681 return mtype, mp_filename |
| 682 |
| 683 def _is_python_file(filename): |
| 684 """return true if the given filename should be considered as a python file |
| 685 |
| 686 .pyc and .pyo are ignored |
| 687 """ |
| 688 for ext in ('.py', '.so', '.pyd', '.pyw'): |
| 689 if filename.endswith(ext): |
| 690 return True |
| 691 return False |
| 692 |
| 693 |
| 694 def _has_init(directory): |
| 695 """if the given directory has a valid __init__ file, return its path, |
| 696 else return None |
| 697 """ |
| 698 mod_or_pack = join(directory, '__init__') |
| 699 for ext in PY_SOURCE_EXTS + ('pyc', 'pyo'): |
| 700 if exists(mod_or_pack + '.' + ext): |
| 701 return mod_or_pack + '.' + ext |
| 702 return None |
OLD | NEW |