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