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

Side by Side Diff: third_party/logilab/astng/manager.py

Issue 719313003: Revert "pylint: upgrade to 1.3.1" (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
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
« no previous file with comments | « third_party/logilab/astng/inspector.py ('k') | third_party/logilab/astng/mixins.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 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 # copyright 2003-2010 Sylvain Thenault, all rights reserved.
4 # contact mailto:thenault@gmail.com
3 # 5 #
4 # This file is part of astroid. 6 # This file is part of logilab-astng.
5 # 7 #
6 # astroid is free software: you can redistribute it and/or modify it 8 # logilab-astng is free software: you can redistribute it and/or modify it
7 # under the terms of the GNU Lesser General Public License as published by the 9 # under the terms of the GNU Lesser General Public License as published by the
8 # Free Software Foundation, either version 2.1 of the License, or (at your 10 # Free Software Foundation, either version 2.1 of the License, or (at your
9 # option) any later version. 11 # option) any later version.
10 # 12 #
11 # astroid is distributed in the hope that it will be useful, but 13 # logilab-astng is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 15 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
14 # for more details. 16 # for more details.
15 # 17 #
16 # You should have received a copy of the GNU Lesser General Public License along 18 # You should have received a copy of the GNU Lesser General Public License along
17 # with astroid. If not, see <http://www.gnu.org/licenses/>. 19 # with logilab-astng. If not, see <http://www.gnu.org/licenses/>.
18 """astroid manager: avoid multiple astroid build of a same module when 20 """astng manager: avoid multiple astng build of a same module when
19 possible by providing a class responsible to get astroid representation 21 possible by providing a class responsible to get astng representation
20 from various source and using a cache of built modules) 22 from various source and using a cache of built modules)
21 """ 23 """
22 24
23 __docformat__ = "restructuredtext en" 25 __docformat__ = "restructuredtext en"
24 26
27 import sys
25 import os 28 import os
26 from os.path import dirname, join, isdir, exists 29 from os.path import dirname, basename, abspath, join, isdir, exists
27 from warnings import warn
28 30
31 from logilab.common.modutils import NoSourceFile, is_python_source, \
32 file_from_modpath, load_module_from_name, modpath_from_file, \
33 get_module_files, get_source_file, zipimport
29 from logilab.common.configuration import OptionsProviderMixIn 34 from logilab.common.configuration import OptionsProviderMixIn
30 35
31 from astroid.exceptions import AstroidBuildingException 36 from logilab.astng.exceptions import ASTNGBuildingException
32 from astroid.modutils import NoSourceFile, is_python_source, \
33 file_from_modpath, load_module_from_name, modpath_from_file, \
34 get_module_files, get_source_file, zipimport
35 37
36 38 def astng_wrapper(func, modname):
37 def astroid_wrapper(func, modname): 39 """wrapper to give to ASTNGManager.project_from_files"""
38 """wrapper to give to AstroidManager.project_from_files"""
39 print 'parsing %s...' % modname 40 print 'parsing %s...' % modname
40 try: 41 try:
41 return func(modname) 42 return func(modname)
42 except AstroidBuildingException, exc: 43 except ASTNGBuildingException, exc:
43 print exc 44 print exc
44 except Exception, exc: 45 except Exception, exc:
45 import traceback 46 import traceback
46 traceback.print_exc() 47 traceback.print_exc()
47 48
48 def _silent_no_wrap(func, modname): 49 def _silent_no_wrap(func, modname):
49 """silent wrapper that doesn't do anything; can be used for tests""" 50 """silent wrapper that doesn't do anything; can be used for tests"""
50 return func(modname) 51 return func(modname)
51 52
52 def safe_repr(obj): 53 def safe_repr(obj):
53 try: 54 try:
54 return repr(obj) 55 return repr(obj)
55 except: 56 except:
56 return '???' 57 return '???'
57 58
58 59
59 60
60 class AstroidManager(OptionsProviderMixIn): 61 class ASTNGManager(OptionsProviderMixIn):
61 """the astroid manager, responsible to build astroid from files 62 """the astng manager, responsible to build astng from files
62 or modules. 63 or modules.
63 64
64 Use the Borg pattern. 65 Use the Borg pattern.
65 """ 66 """
66 67
67 name = 'astroid loader' 68 name = 'astng loader'
68 options = (("ignore", 69 options = (("ignore",
69 {'type' : "csv", 'metavar' : "<file>", 70 {'type' : "csv", 'metavar' : "<file>",
70 'dest' : "black_list", "default" : ('CVS',), 71 'dest' : "black_list", "default" : ('CVS',),
71 'help' : "add <file> (may be a directory) to the black list\ 72 'help' : "add <file> (may be a directory) to the black list\
72 . It should be a base name, not a path. You may set this option multiple times\ 73 . It should be a base name, not a path. You may set this option multiple times\
73 ."}), 74 ."}),
74 ("project", 75 ("project",
75 {'default': "No Name", 'type' : 'string', 'short': 'p', 76 {'default': "No Name", 'type' : 'string', 'short': 'p',
76 'metavar' : '<project name>', 77 'metavar' : '<project name>',
77 'help' : 'set the project name.'}), 78 'help' : 'set the project name.'}),
78 ) 79 )
79 brain = {} 80 brain = {}
80 def __init__(self): 81 def __init__(self):
81 self.__dict__ = AstroidManager.brain 82 self.__dict__ = ASTNGManager.brain
82 if not self.__dict__: 83 if not self.__dict__:
83 OptionsProviderMixIn.__init__(self) 84 OptionsProviderMixIn.__init__(self)
84 self.load_defaults() 85 self.load_defaults()
85 # NOTE: cache entries are added by the [re]builder 86 # NOTE: cache entries are added by the [re]builder
86 self.astroid_cache = {} 87 self.astng_cache = {}
87 self._mod_file_cache = {} 88 self._mod_file_cache = {}
88 self.transforms = {} 89 self.transformers = []
89 90
90 def ast_from_file(self, filepath, modname=None, fallback=True, source=False) : 91 def astng_from_file(self, filepath, modname=None, fallback=True, source=Fals e):
91 """given a module name, return the astroid object""" 92 """given a module name, return the astng object"""
92 try: 93 try:
93 filepath = get_source_file(filepath, include_no_ext=True) 94 filepath = get_source_file(filepath, include_no_ext=True)
94 source = True 95 source = True
95 except NoSourceFile: 96 except NoSourceFile:
96 pass 97 pass
97 if modname is None: 98 if modname is None:
98 try: 99 try:
99 modname = '.'.join(modpath_from_file(filepath)) 100 modname = '.'.join(modpath_from_file(filepath))
100 except ImportError: 101 except ImportError:
101 modname = filepath 102 modname = filepath
102 if modname in self.astroid_cache and self.astroid_cache[modname].file == filepath: 103 if modname in self.astng_cache:
103 return self.astroid_cache[modname] 104 return self.astng_cache[modname]
104 if source: 105 if source:
105 from astroid.builder import AstroidBuilder 106 from logilab.astng.builder import ASTNGBuilder
106 return AstroidBuilder(self).file_build(filepath, modname) 107 return ASTNGBuilder(self).file_build(filepath, modname)
107 elif fallback and modname: 108 elif fallback and modname:
108 return self.ast_from_module_name(modname) 109 return self.astng_from_module_name(modname)
109 raise AstroidBuildingException('unable to get astroid for file %s' % 110 raise ASTNGBuildingException('unable to get astng for file %s' %
110 filepath) 111 filepath)
111 112
112 def ast_from_module_name(self, modname, context_file=None): 113 def astng_from_module_name(self, modname, context_file=None):
113 """given a module name, return the astroid object""" 114 """given a module name, return the astng object"""
114 if modname in self.astroid_cache: 115 if modname in self.astng_cache:
115 return self.astroid_cache[modname] 116 return self.astng_cache[modname]
116 if modname == '__main__': 117 if modname == '__main__':
117 from astroid.builder import AstroidBuilder 118 from logilab.astng.builder import ASTNGBuilder
118 return AstroidBuilder(self).string_build('', modname) 119 return ASTNGBuilder(self).string_build('', modname)
119 old_cwd = os.getcwd() 120 old_cwd = os.getcwd()
120 if context_file: 121 if context_file:
121 os.chdir(dirname(context_file)) 122 os.chdir(dirname(context_file))
122 try: 123 try:
123 filepath = self.file_from_module_name(modname, context_file) 124 filepath = self.file_from_module_name(modname, context_file)
124 if filepath is not None and not is_python_source(filepath): 125 if filepath is not None and not is_python_source(filepath):
125 module = self.zip_import_data(filepath) 126 module = self.zip_import_data(filepath)
126 if module is not None: 127 if module is not None:
127 return module 128 return module
128 if filepath is None or not is_python_source(filepath): 129 if filepath is None or not is_python_source(filepath):
129 try: 130 try:
130 module = load_module_from_name(modname) 131 module = load_module_from_name(modname)
131 except Exception, ex: 132 except Exception, ex:
132 msg = 'Unable to load module %s (%s)' % (modname, ex) 133 msg = 'Unable to load module %s (%s)' % (modname, ex)
133 raise AstroidBuildingException(msg) 134 raise ASTNGBuildingException(msg)
134 return self.ast_from_module(module, modname) 135 return self.astng_from_module(module, modname)
135 return self.ast_from_file(filepath, modname, fallback=False) 136 return self.astng_from_file(filepath, modname, fallback=False)
136 finally: 137 finally:
137 os.chdir(old_cwd) 138 os.chdir(old_cwd)
138 139
139 def zip_import_data(self, filepath): 140 def zip_import_data(self, filepath):
140 if zipimport is None: 141 if zipimport is None:
141 return None 142 return None
142 from astroid.builder import AstroidBuilder 143 from logilab.astng.builder import ASTNGBuilder
143 builder = AstroidBuilder(self) 144 builder = ASTNGBuilder(self)
144 for ext in ('.zip', '.egg'): 145 for ext in ('.zip', '.egg'):
145 try: 146 try:
146 eggpath, resource = filepath.rsplit(ext + '/', 1) 147 eggpath, resource = filepath.rsplit(ext + '/', 1)
147 except ValueError: 148 except ValueError:
148 continue 149 continue
149 try: 150 try:
150 importer = zipimport.zipimporter(eggpath + ext) 151 importer = zipimport.zipimporter(eggpath + ext)
151 zmodname = resource.replace('/', '.') 152 zmodname = resource.replace('/', '.')
152 if importer.is_package(resource): 153 if importer.is_package(resource):
153 zmodname = zmodname + '.__init__' 154 zmodname = zmodname + '.__init__'
154 module = builder.string_build(importer.get_source(resource), 155 module = builder.string_build(importer.get_source(resource),
155 zmodname, filepath) 156 zmodname, filepath)
156 return module 157 return module
157 except: 158 except:
158 continue 159 continue
159 return None 160 return None
160 161
161 def file_from_module_name(self, modname, contextfile): 162 def file_from_module_name(self, modname, contextfile):
162 try: 163 try:
163 value = self._mod_file_cache[(modname, contextfile)] 164 value = self._mod_file_cache[(modname, contextfile)]
164 except KeyError: 165 except KeyError:
165 try: 166 try:
166 value = file_from_modpath(modname.split('.'), 167 value = file_from_modpath(modname.split('.'),
167 context_file=contextfile) 168 context_file=contextfile)
168 except ImportError, ex: 169 except ImportError, ex:
169 msg = 'Unable to load module %s (%s)' % (modname, ex) 170 msg = 'Unable to load module %s (%s)' % (modname, ex)
170 value = AstroidBuildingException(msg) 171 value = ASTNGBuildingException(msg)
171 self._mod_file_cache[(modname, contextfile)] = value 172 self._mod_file_cache[(modname, contextfile)] = value
172 if isinstance(value, AstroidBuildingException): 173 if isinstance(value, ASTNGBuildingException):
173 raise value 174 raise value
174 return value 175 return value
175 176
176 def ast_from_module(self, module, modname=None): 177 def astng_from_module(self, module, modname=None):
177 """given an imported module, return the astroid object""" 178 """given an imported module, return the astng object"""
178 modname = modname or module.__name__ 179 modname = modname or module.__name__
179 if modname in self.astroid_cache: 180 if modname in self.astng_cache:
180 return self.astroid_cache[modname] 181 return self.astng_cache[modname]
181 try: 182 try:
182 # some builtin modules don't have __file__ attribute 183 # some builtin modules don't have __file__ attribute
183 filepath = module.__file__ 184 filepath = module.__file__
184 if is_python_source(filepath): 185 if is_python_source(filepath):
185 return self.ast_from_file(filepath, modname) 186 return self.astng_from_file(filepath, modname)
186 except AttributeError: 187 except AttributeError:
187 pass 188 pass
188 from astroid.builder import AstroidBuilder 189 from logilab.astng.builder import ASTNGBuilder
189 return AstroidBuilder(self).module_build(module, modname) 190 return ASTNGBuilder(self).module_build(module, modname)
190 191
191 def ast_from_class(self, klass, modname=None): 192 def astng_from_class(self, klass, modname=None):
192 """get astroid for the given class""" 193 """get astng for the given class"""
193 if modname is None: 194 if modname is None:
194 try: 195 try:
195 modname = klass.__module__ 196 modname = klass.__module__
196 except AttributeError: 197 except AttributeError:
197 raise AstroidBuildingException( 198 raise ASTNGBuildingException(
198 'Unable to get module for class %s' % safe_repr(klass)) 199 'Unable to get module for class %s' % safe_repr(klass))
199 modastroid = self.ast_from_module_name(modname) 200 modastng = self.astng_from_module_name(modname)
200 return modastroid.getattr(klass.__name__)[0] # XXX 201 return modastng.getattr(klass.__name__)[0] # XXX
201 202
202 203
203 def infer_ast_from_something(self, obj, context=None): 204 def infer_astng_from_something(self, obj, context=None):
204 """infer astroid for the given class""" 205 """infer astng for the given class"""
205 if hasattr(obj, '__class__') and not isinstance(obj, type): 206 if hasattr(obj, '__class__') and not isinstance(obj, type):
206 klass = obj.__class__ 207 klass = obj.__class__
207 else: 208 else:
208 klass = obj 209 klass = obj
209 try: 210 try:
210 modname = klass.__module__ 211 modname = klass.__module__
211 except AttributeError: 212 except AttributeError:
212 raise AstroidBuildingException( 213 raise ASTNGBuildingException(
213 'Unable to get module for %s' % safe_repr(klass)) 214 'Unable to get module for %s' % safe_repr(klass))
214 except Exception, ex: 215 except Exception, ex:
215 raise AstroidBuildingException( 216 raise ASTNGBuildingException(
216 'Unexpected error while retrieving module for %s: %s' 217 'Unexpected error while retrieving module for %s: %s'
217 % (safe_repr(klass), ex)) 218 % (safe_repr(klass), ex))
218 try: 219 try:
219 name = klass.__name__ 220 name = klass.__name__
220 except AttributeError: 221 except AttributeError:
221 raise AstroidBuildingException( 222 raise ASTNGBuildingException(
222 'Unable to get name for %s' % safe_repr(klass)) 223 'Unable to get name for %s' % safe_repr(klass))
223 except Exception, ex: 224 except Exception, ex:
224 raise AstroidBuildingException( 225 raise ASTNGBuildingException(
225 'Unexpected error while retrieving name for %s: %s' 226 'Unexpected error while retrieving name for %s: %s'
226 % (safe_repr(klass), ex)) 227 % (safe_repr(klass), ex))
227 # take care, on living object __module__ is regularly wrong :( 228 # take care, on living object __module__ is regularly wrong :(
228 modastroid = self.ast_from_module_name(modname) 229 modastng = self.astng_from_module_name(modname)
229 if klass is obj: 230 if klass is obj:
230 for infered in modastroid.igetattr(name, context): 231 for infered in modastng.igetattr(name, context):
231 yield infered 232 yield infered
232 else: 233 else:
233 for infered in modastroid.igetattr(name, context): 234 for infered in modastng.igetattr(name, context):
234 yield infered.instanciate_class() 235 yield infered.instanciate_class()
235 236
236 def project_from_files(self, files, func_wrapper=astroid_wrapper, 237 def project_from_files(self, files, func_wrapper=astng_wrapper,
237 project_name=None, black_list=None): 238 project_name=None, black_list=None):
238 """return a Project from a list of files or modules""" 239 """return a Project from a list of files or modules"""
239 # build the project representation 240 # build the project representation
240 project_name = project_name or self.config.project 241 project_name = project_name or self.config.project
241 black_list = black_list or self.config.black_list 242 black_list = black_list or self.config.black_list
242 project = Project(project_name) 243 project = Project(project_name)
243 for something in files: 244 for something in files:
244 if not exists(something): 245 if not exists(something):
245 fpath = file_from_modpath(something.split('.')) 246 fpath = file_from_modpath(something.split('.'))
246 elif isdir(something): 247 elif isdir(something):
247 fpath = join(something, '__init__.py') 248 fpath = join(something, '__init__.py')
248 else: 249 else:
249 fpath = something 250 fpath = something
250 astroid = func_wrapper(self.ast_from_file, fpath) 251 astng = func_wrapper(self.astng_from_file, fpath)
251 if astroid is None: 252 if astng is None:
252 continue 253 continue
253 # XXX why is first file defining the project.path ? 254 # XXX why is first file defining the project.path ?
254 project.path = project.path or astroid.file 255 project.path = project.path or astng.file
255 project.add_module(astroid) 256 project.add_module(astng)
256 base_name = astroid.name 257 base_name = astng.name
257 # recurse in package except if __init__ was explicitly given 258 # recurse in package except if __init__ was explicitly given
258 if astroid.package and something.find('__init__') == -1: 259 if astng.package and something.find('__init__') == -1:
259 # recurse on others packages / modules if this is a package 260 # recurse on others packages / modules if this is a package
260 for fpath in get_module_files(dirname(astroid.file), 261 for fpath in get_module_files(dirname(astng.file),
261 black_list): 262 black_list):
262 astroid = func_wrapper(self.ast_from_file, fpath) 263 astng = func_wrapper(self.astng_from_file, fpath)
263 if astroid is None or astroid.name == base_name: 264 if astng is None or astng.name == base_name:
264 continue 265 continue
265 project.add_module(astroid) 266 project.add_module(astng)
266 return project 267 return project
267 268
268 def register_transform(self, node_class, transform, predicate=None): 269 def register_transformer(self, transformer):
269 """Register `transform(node)` function to be applied on the given 270 self.transformers.append(transformer)
270 Astroid's `node_class` if `predicate` is None or return a true value
271 when called with the node as argument.
272 271
273 The transform function may return a value which is then used to 272 class Project:
274 substitute the original node in the tree.
275 """
276 self.transforms.setdefault(node_class, []).append((transform, predicate) )
277
278 def unregister_transform(self, node_class, transform, predicate=None):
279 """Unregister the given transform."""
280 self.transforms[node_class].remove((transform, predicate))
281
282 def transform(self, node):
283 """Call matching transforms for the given node if any and return the
284 transformed node.
285 """
286 cls = node.__class__
287 if cls not in self.transforms:
288 # no transform registered for this class of node
289 return node
290
291 transforms = self.transforms[cls]
292 orig_node = node # copy the reference
293 for transform_func, predicate in transforms:
294 if predicate is None or predicate(node):
295 ret = transform_func(node)
296 # if the transformation function returns something, it's
297 # expected to be a replacement for the node
298 if ret is not None:
299 if node is not orig_node:
300 # node has already be modified by some previous
301 # transformation, warn about it
302 warn('node %s substituted multiple times' % node)
303 node = ret
304 return node
305
306 def cache_module(self, module):
307 """Cache a module if no module with the same name is known yet."""
308 self.astroid_cache.setdefault(module.name, module)
309
310 def clear_cache(self):
311 self.astroid_cache.clear()
312 # force bootstrap again, else we may ends up with cache inconsistency
313 # between the manager and CONST_PROXY, making
314 # unittest_lookup.LookupTC.test_builtin_lookup fail depending on the
315 # test order
316 from astroid.raw_building import astroid_bootstrapping
317 astroid_bootstrapping()
318
319
320 class Project(object):
321 """a project handle a set of modules / packages""" 273 """a project handle a set of modules / packages"""
322 def __init__(self, name=''): 274 def __init__(self, name=''):
323 self.name = name 275 self.name = name
324 self.path = None 276 self.path = None
325 self.modules = [] 277 self.modules = []
326 self.locals = {} 278 self.locals = {}
327 self.__getitem__ = self.locals.__getitem__ 279 self.__getitem__ = self.locals.__getitem__
328 self.__iter__ = self.locals.__iter__ 280 self.__iter__ = self.locals.__iter__
329 self.values = self.locals.values 281 self.values = self.locals.values
330 self.keys = self.locals.keys 282 self.keys = self.locals.keys
331 self.items = self.locals.items 283 self.items = self.locals.items
332 284
333 def add_module(self, node): 285 def add_module(self, node):
334 self.locals[node.name] = node 286 self.locals[node.name] = node
335 self.modules.append(node) 287 self.modules.append(node)
336 288
337 def get_module(self, name): 289 def get_module(self, name):
338 return self.locals[name] 290 return self.locals[name]
339 291
340 def get_children(self): 292 def get_children(self):
341 return self.modules 293 return self.modules
342 294
343 def __repr__(self): 295 def __repr__(self):
344 return '<Project %r at %s (%s modules)>' % (self.name, id(self), 296 return '<Project %r at %s (%s modules)>' % (self.name, id(self),
345 len(self.modules)) 297 len(self.modules))
346 298
347 299
OLDNEW
« no previous file with comments | « third_party/logilab/astng/inspector.py ('k') | third_party/logilab/astng/mixins.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698