From 1d9fdff86f9d062e70d026a32d18e29c455e756d Mon Sep 17 00:00:00 2001 From: Raphael Gaschignard Date: Sun, 30 Aug 2020 22:29:17 +0900 Subject: [PATCH] Don't cache exception values in the module cache Exceptions hold tracebacks, which can get very large (especially for highly recursive functions). Especially if the exceptions are being used for control flow instead of actual exception management, we should be throwing them away as fast as possible. This commit deals with this with a bit of a hacky solution, but really the way the module cache handles things ought to be reworked a bit. --- astroid/manager.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/astroid/manager.py b/astroid/manager.py index 82208adf7..5d1c0a386 100644 --- a/astroid/manager.py +++ b/astroid/manager.py @@ -39,6 +39,24 @@ def safe_repr(obj): return "???" +class AstroidImportError: + """ + Error class to keep track of when exceptions happened. + + This error class avoids holding onto the initial exception to avoid + memory usage explosion + """ + + def __init__(self, modname, error): + self.modname = modname + self.error = str(error) + + def __str__(self): + return "AstroidImportError: Failed to import module {modname} with error:\n{error}.".format( + modname=self.modname, error=self.error + ) + + class AstroidManager: """the astroid manager, responsible to build astroid from files or modules. @@ -233,14 +251,12 @@ def file_from_module_name(self, modname, contextfile): modname.split("."), context_file=contextfile ) except ImportError as ex: - value = exceptions.AstroidImportError( - "Failed to import module {modname} with error:\n{error}.", - modname=modname, - error=ex, - ) + value = AstroidImportError(modname=modname, error=ex) self._mod_file_cache[(modname, contextfile)] = value - if isinstance(value, exceptions.AstroidBuildingError): - raise value + if isinstance(value, AstroidImportError): + raise exceptions.AstroidImportError( + str(value), modname=value.modname, error=value.error + ) return value def ast_from_module(self, module, modname=None):