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

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

Issue 739393004: Revert "Revert "pylint: upgrade to 1.3.1"" (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/logilab/common/logging_ext.py ('k') | third_party/logilab/common/optik_ext.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « third_party/logilab/common/logging_ext.py ('k') | third_party/logilab/common/optik_ext.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698