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 |