diff --git a/jedi/cache.py b/jedi/cache.py index 806575b7..7344c8b5 100644 --- a/jedi/cache.py +++ b/jedi/cache.py @@ -3,7 +3,7 @@ This caching is very important for speed and memory optimizations. There's nothing really spectacular, just some decorators. The following cache types are available: -- module caching (`load_module` and `save_module`), which uses pickle and is +- module caching (`load_parser` and `save_parser`), which uses pickle and is really important to assure low load times of modules like ``numpy``. - ``time_cache`` can be used to cache something for just a limited time span, which can be useful if there's user interaction and the user cannot react @@ -135,18 +135,18 @@ def invalidate_star_import_cache(module, only_main=False): invalidate_star_import_cache(key) -def load_module(path, name): +def load_parser(path, name): """ Returns the module or None, if it fails. """ if path is None and name is None: return None - tim = os.path.getmtime(path) if path else None + p_time = os.path.getmtime(path) if path else None n = name if path is None else path try: parser_cache_item = parser_cache[n] - if not path or tim <= parser_cache_item.change_time: + if not path or p_time <= parser_cache_item.change_time: return parser_cache_item.parser else: # In case there is already a module cached and this module @@ -155,10 +155,10 @@ def load_module(path, name): invalidate_star_import_cache(parser_cache_item.parser.module) except KeyError: if settings.use_filesystem_cache: - return ModulePickling.load_module(n, tim) + return ParserPickling.load_parser(n, p_time) -def save_module(path, name, parser, pickling=True): +def save_parser(path, name, parser, pickling=True): try: p_time = None if not path else os.path.getmtime(path) except OSError: @@ -169,10 +169,10 @@ def save_module(path, name, parser, pickling=True): item = ParserCacheItem(parser, p_time) parser_cache[n] = item if settings.use_filesystem_cache and pickling: - ModulePickling.save_module(n, item) + ParserPickling.save_parser(n, item) -class _ModulePickling(object): +class ParserPickling(object): version = 7 """ @@ -200,7 +200,7 @@ class _ModulePickling(object): .. todo:: Detect interpreter (e.g., PyPy). """ - def load_module(self, path, original_changed_time): + def load_parser(self, path, original_changed_time): try: pickle_changed_time = self._index[path] except KeyError: @@ -221,7 +221,7 @@ class _ModulePickling(object): parser_cache[path] = parser_cache_item return parser_cache_item.parser - def save_module(self, path, parser_cache_item): + def save_parser(self, path, parser_cache_item): self.__index = None try: files = self._index @@ -282,4 +282,4 @@ class _ModulePickling(object): # is a singleton -ModulePickling = _ModulePickling() +ParserPickling = ParserPickling() diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index 84eebb78..1801d825 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -24,7 +24,6 @@ from jedi import common from jedi import debug from jedi.parser import representation as pr from jedi import cache -from jedi.evaluate import builtin class ModuleNotFound(Exception): @@ -359,14 +358,9 @@ class ImportPath(pr.Base): else: source = current_namespace[0].read() current_namespace[0].close() - if path.endswith('.py'): - f = modules.Module(path, source) - else: - f = builtin.BuiltinModule(path=path) + return modules.load_module(path, source), rest else: - f = builtin.BuiltinModule(name=path) - - return f.parser.module, rest + return modules.load_module(name=path), rest def strip_imports(evaluator, scopes): diff --git a/jedi/modules.py b/jedi/modules.py index e166e6f0..f8353eaf 100644 --- a/jedi/modules.py +++ b/jedi/modules.py @@ -29,59 +29,26 @@ from jedi import debug from jedi import common -class CachedModule(object): - """ - The base type for all modules, which is not to be confused with - `parsing_representation.Module`. Caching happens here. - """ +def load_module(path=None, source=None, name=None): + def load(source): + if path.endswith('.py'): + if source is None: + with open(path) as f: + source = f.read() + else: + # TODO refactoring remove + from jedi.evaluate import builtin + return builtin.BuiltinModule(name=path).parser.module + p = path or name + p = fast.FastParser(source_to_unicode(source), p) + cache.save_parser(path, name, p) + return p.module - def __init__(self, path=None, name=None): - self.path = path and os.path.abspath(path) - self.name = name - self._parser = None - - @property - def parser(self): - """ get the parser lazy """ - if self._parser is None: - self._parser = cache.load_module(self.path, self.name) \ - or self._load_module() - return self._parser - - def _get_source(self): - raise NotImplementedError() - - def _load_module(self): - source = self._get_source() - p = self.path or self.name - p = fast.FastParser(source, p) - cache.save_module(self.path, self.name, p) - return p + cached = cache.load_parser(path, name) + return load(source) if cached is None else cached.module -class Module(CachedModule): - """ - Manages all files, that are parsed and caches them. - - :param path: The module path of the file. - :param source: The source code of the file. - """ - def __init__(self, path, source=None): - super(Module, self).__init__(path=path) - if source is None: - with open(path) as f: - source = f.read() - self.source = source_to_unicode(source) - self._line_cache = None - - def _get_source(self): - """ Just one time """ - s = self.source - del self.source # memory efficiency - return s - - -class ModuleWithCursor(Module): +class ModuleWithCursor(object): """ Manages all files, that are parsed and caches them. Important are the params source and path, one of them has to @@ -93,7 +60,7 @@ class ModuleWithCursor(Module): for the main file. """ def __init__(self, path, source, position): - super(ModuleWithCursor, self).__init__(path, source) + super(ModuleWithCursor, self).__init__() self.position = position self.source = source self._path_until_cursor = None @@ -114,7 +81,7 @@ class ModuleWithCursor(Module): # default), therefore fill the cache here. self._parser = fast.FastParser(self.source, self.path, self.position) # don't pickle that module, because it's changing fast - cache.save_module(self.path, self.name, self._parser, + cache.save_parser(self.path, self.name, self._parser, pickling=False) return self._parser @@ -363,14 +330,14 @@ def sys_path_with_modifications(module): os.chdir(os.path.dirname(module.path)) result = check_module(module) - result += detect_django_path(module.path) + result += _detect_django_path(module.path) # cleanup, back to old directory os.chdir(curdir) return result -def detect_django_path(module_path): +def _detect_django_path(module_path): """ Detects the path of the very well known Django library (if used) """ result = [] while True: