summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmile Anclin <emile.anclin@logilab.fr>2010-03-17 12:56:04 +0100
committerEmile Anclin <emile.anclin@logilab.fr>2010-03-17 12:56:04 +0100
commita246fa3f8175bdcba9282439b8cab413de285a43 (patch)
treee43611815377cfa6b998dd91741137939e789e66
parente1bbf73e1b36b5039f86769edbd2faf2988d2b38 (diff)
downloadastroid-a246fa3f8175bdcba9282439b8cab413de285a43.tar.gz
refactor cache handling to avoid infinite recursion error while infering assignments during build, which potentially tried to rebuild a module we were currently building
-rw-r--r--builder.py13
-rw-r--r--manager.py87
-rw-r--r--rebuilder.py10
3 files changed, 55 insertions, 55 deletions
diff --git a/builder.py b/builder.py
index 6484480..6df3657 100644
--- a/builder.py
+++ b/builder.py
@@ -62,7 +62,7 @@ class ASTNGBuilder:
self._module = None
self._file = None
self._done = None
- self.rebuilder = TreeRebuilder()
+ self.rebuilder = TreeRebuilder(manager)
self._dyn_modname_map = {'gtk': 'gtk._gtk'}
def module_build(self, module, modname=None):
@@ -87,10 +87,12 @@ class ASTNGBuilder:
because it's a built-in module or because the .py is not available)
"""
self._module = module
- node = build_module(modname or module.__name__, module.__doc__)
+ if modname is None:
+ modname = module.__name__
+ node = build_module(modname, module.__doc__)
node.file = node.path = path and abspath(path) or path
if self._manager is not None:
- self._manager._cache[node.file] = self._manager._cache[node.name] = node
+ self._manager._cache[modname] = node
node.package = hasattr(module, '__path__')
self._done = {}
self.object_build(node, module)
@@ -144,11 +146,6 @@ class ASTNGBuilder:
newnode.pure_python = True
newnode.package = package
newnode.file = newnode.path = node_file
- newnode.name = modname
- if self._manager is not None:
- self._manager._cache[newnode.file] = newnode
- if self._file:
- self._manager._cache[abspath(self._file)] = newnode
return newnode
# astng from living objects ###############################################
diff --git a/manager.py b/manager.py
index c001870..32194e9 100644
--- a/manager.py
+++ b/manager.py
@@ -28,7 +28,7 @@ import os
from os.path import dirname, basename, abspath, join, isdir, exists
from logilab.common.modutils import NoSourceFile, is_python_source, \
- file_from_modpath, load_module_from_name, \
+ file_from_modpath, load_module_from_name, modpath_from_file, \
get_module_files, get_source_file, zipimport
from logilab.common.configuration import OptionsProviderMixIn
@@ -101,6 +101,7 @@ class ASTNGManager(OptionsProviderMixIn):
def set_cache_size(self, cache_size):
"""set the cache size (flush it as a side effect!)"""
+ # NOTE: cache entries are added by the [re]builder
self._cache = {} #Cache(cache_size)
self._mod_file_cache = {}
@@ -117,52 +118,51 @@ class ASTNGManager(OptionsProviderMixIn):
source = True
except NoSourceFile:
source = False
+ if modname is None:
+ modname = '.'.join(modpath_from_file(filepath))
+ print >>sys.stderr, 'astng from file', filepath, modname
try:
- return self._cache[filepath]
+ return self._cache[modname]
except KeyError:
- if source:
- try:
- from logilab.astng.builder import ASTNGBuilder
- astng = ASTNGBuilder(self).file_build(filepath, modname)
- except (SyntaxError, KeyboardInterrupt, SystemExit):
- raise
- except Exception, ex:
- if __debug__:
- print 'error while building astng for', filepath
- import traceback
- traceback.print_exc()
- msg = 'Unable to load module %s (%s)' % (modname, ex)
- raise ASTNGBuildingException(msg), None, sys.exc_info()[-1]
- elif fallback and modname:
- return self.astng_from_module_name(modname)
- else:
- raise ASTNGBuildingException('unable to get astng for file %s' %
- filepath)
- self._cache[filepath] = astng
- return astng
-
- from_file = astng_from_file # backward compat
+ pass
+ if source:
+ try:
+ from logilab.astng.builder import ASTNGBuilder
+ return ASTNGBuilder(self).file_build(filepath, modname)
+ except (SyntaxError, KeyboardInterrupt, SystemExit):
+ raise
+ except Exception, ex:
+ raise
+ if __debug__:
+ print 'error while building astng for', filepath
+ import traceback
+ traceback.print_exc()
+ msg = 'Unable to load module %s (%s)' % (modname, ex)
+ raise ASTNGBuildingException(msg), None, sys.exc_info()[-1]
+ elif fallback and modname:
+ return self.astng_from_module_name(modname)
+ raise ASTNGBuildingException('unable to get astng for file %s' %
+ filepath)
def astng_from_module_name(self, modname, context_file=None):
"""given a module name, return the astng object"""
+ try:
+ return self._cache[modname]
+ except KeyError:
+ pass
old_cwd = os.getcwd()
if context_file:
os.chdir(dirname(context_file))
try:
filepath = self.file_from_module_name(modname, context_file)
if filepath is not None and not is_python_source(filepath):
- try:
- return self._cache[filepath]
- except KeyError:
- data, zmodname = zip_import_data(filepath)
- if data is not None:
- from logilab.astng.builder import ASTNGBuilder
- try:
- astng = ASTNGBuilder(self).string_build(data, zmodname, filepath)
- except (SyntaxError, KeyboardInterrupt, SystemExit):
- raise
- self._cache[filepath] = astng
- return astng
+ data, zmodname = zip_import_data(filepath)
+ if data is not None:
+ from logilab.astng.builder import ASTNGBuilder
+ try:
+ return ASTNGBuilder(self).string_build(data, zmodname, filepath)
+ except (SyntaxError, KeyboardInterrupt, SystemExit):
+ raise
if filepath is None or not is_python_source(filepath):
try:
module = load_module_from_name(modname)
@@ -192,6 +192,10 @@ class ASTNGManager(OptionsProviderMixIn):
def astng_from_module(self, module, modname=None):
"""given an imported module, return the astng object"""
modname = modname or module.__name__
+ try:
+ return self._cache[modname]
+ except KeyError:
+ pass
filepath = modname
try:
# some builtin modules don't have __file__ attribute
@@ -200,15 +204,8 @@ class ASTNGManager(OptionsProviderMixIn):
return self.astng_from_file(filepath, modname)
except AttributeError:
pass
- try:
- return self._cache[filepath]
- except KeyError:
- from logilab.astng.builder import ASTNGBuilder
- astng = ASTNGBuilder(self).module_build(module, modname)
- # update caches (filepath and astng.file are not necessarily the
- # same (.pyc pb))
- self._cache[filepath] = self._cache[astng.file] = astng
- return astng
+ from logilab.astng.builder import ASTNGBuilder
+ return ASTNGBuilder(self).module_build(module, modname)
def astng_from_class(self, klass, modname=None):
"""get astng for the given class"""
diff --git a/rebuilder.py b/rebuilder.py
index b527ce0..2cab247 100644
--- a/rebuilder.py
+++ b/rebuilder.py
@@ -30,7 +30,8 @@ from logilab.astng.bases import YES, Instance
class RebuildVisitor(ASTVisitor):
"""Visitor to transform an AST to an ASTNG
"""
- def __init__(self):
+ def __init__(self, manager):
+ self._manager = manager
self.asscontext = None
self._metaclass = None
self._global_names = None
@@ -183,7 +184,12 @@ class RebuildVisitor(ASTVisitor):
"""visit an Module node to become astng"""
self._metaclass = ['']
self._global_names = []
- return self._visit_module(node, parent)
+ module = self._visit_module(node, parent)
+ # init module cache here else we may get some infinite recursion
+ # errors while infering delayed assignments
+ if self._manager is not None:
+ self._manager._cache[module.name] = module
+ return module
def visit_pass(self, node, parent):
"""visit a Pass node by returning a fresh instance of it"""