From 67d9fbca81924c5738d522e8c7a1339f786d6dc5 Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Tue, 10 Feb 2015 21:24:51 +0100 Subject: [PATCH] run buildout detection only once per buildout script in order to avoid running into the max recursion limit. --- jedi/evaluate/sys_path.py | 45 ++++++++++++------- test/test_evaluate/test_buildout_detection.py | 13 ++++++ 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/jedi/evaluate/sys_path.py b/jedi/evaluate/sys_path.py index 09527827..e2090c67 100644 --- a/jedi/evaluate/sys_path.py +++ b/jedi/evaluate/sys_path.py @@ -8,6 +8,7 @@ from jedi.parser import Parser from jedi.evaluate.cache import memoize_default from jedi import debug from jedi import common +from jedi import cache def get_sys_path(): @@ -152,26 +153,38 @@ def sys_path_with_modifications(evaluator, module): with common.ignored(OSError): os.chdir(os.path.dirname(module.path)) + buildout_script_paths = set() + result = _check_module(evaluator, module) result += _detect_django_path(module.path) - # buildout scripts often contain the same sys.path modifications - # the set here is used to avoid duplicate sys.path entries - buildout_paths = set() - for module_path in _get_buildout_scripts(module.path): - try: - with open(module_path, 'rb') as f: - source = f.read() - except IOError: - pass - else: - p = Parser(evaluator.grammar, common.source_to_unicode(source), module_path) - for path in _check_module(p.module): - if path not in buildout_paths: - buildout_paths.add(path) - result.append(path) + for buildout_script in _get_buildout_scripts(module.path): + for path in _get_paths_from_buildout_script(evaluator, buildout_script): + buildout_script_paths.add(path) # cleanup, back to old directory os.chdir(curdir) - return list(result) + return list(result) + list(buildout_script_paths) + + +def _get_paths_from_buildout_script(evaluator, buildout_script): + def load(buildout_script): + try: + with open(buildout_script, 'rb') as f: + source = common.source_to_unicode(f.read()) + except IOError: + debug.dbg('Error trying to read buildout_script: %s', buildout_script) + return + + p = Parser(evaluator.grammar, source, buildout_script) + cache.save_parser(buildout_script, None, p) + return p.module + + cached = cache.load_parser(buildout_script, None) + module = cached and cached.module or load(buildout_script) + if not module: + return + + for path in _check_module(evaluator, module): + yield path def _traverse_parents(path): diff --git a/test/test_evaluate/test_buildout_detection.py b/test/test_evaluate/test_buildout_detection.py index 45427f21..f3164a7d 100644 --- a/test/test_evaluate/test_buildout_detection.py +++ b/test/test_evaluate/test_buildout_detection.py @@ -4,6 +4,7 @@ from textwrap import dedent from jedi._compatibility import u from jedi.evaluate.sys_path import (_get_parent_dir_with_file, _get_buildout_scripts, + sys_path_with_modifications, _check_module) from jedi.evaluate import Evaluator from jedi.parser import Parser, load_grammar @@ -53,6 +54,18 @@ def test_path_from_invalid_sys_path_assignment(): assert 'invalid' not in paths +@cwd_at('test/test_evaluate/buildout_project/src/proj_name/') +def test_sys_path_with_modifications(): + SRC = dedent(u(""" + import os + """)) + grammar = load_grammar() + p = Parser(grammar, SRC) + p.module.path = os.path.abspath(os.path.join(os.curdir, 'module_name.py')) + paths = sys_path_with_modifications(Evaluator(grammar), p.module) + assert '/tmp/.buildout/eggs/important_package.egg' in paths + + def test_path_from_sys_path_assignment(): SRC = dedent(u(""" #!/usr/bin/python