diff --git a/jedi/builtin.py b/jedi/builtin.py index c0e76a8b..301bb10a 100644 --- a/jedi/builtin.py +++ b/jedi/builtin.py @@ -24,7 +24,7 @@ class CachedModule(object): cache = {} def __init__(self, path=None, name=None): - self.path = path + self.path = path and os.path.abspath(path) self.name = name self._parser = None diff --git a/jedi/dynamic.py b/jedi/dynamic.py index 11d4ad7f..e1b35984 100644 --- a/jedi/dynamic.py +++ b/jedi/dynamic.py @@ -41,20 +41,25 @@ def get_directory_modules_for_name(mods, name): if name in source: return modules.Module(path, source).parser.module + # skip non python modules + mods = set(m for m in mods if m.path.endswith('.py')) mod_paths = set() for m in mods: mod_paths.add(m.path) + yield m - new = set() + paths = set(settings.additional_dynamic_modules) for p in mod_paths: d = os.path.dirname(p) for entry in os.listdir(d): if entry not in mod_paths: if entry.endswith('.py'): - c = check_python_file(d + os.path.sep + entry) - if c is not None: - new.add(c) - return set(mods) | new + paths.add(d + os.path.sep + entry) + + for p in paths: + c = check_python_file(p) + if c is not None and c not in mods: + yield c def search_param_memoize(func): @@ -121,7 +126,6 @@ def search_params(param): for p in params: if str(p) == param_name: result += evaluate.follow_statement(p.parent()) - #print listener.param_possibilities, param, result return result @@ -143,9 +147,11 @@ def search_params(param): listener = ParamListener() func.listeners.add(listener) - result = get_params_for_module(current_module) + for mod in get_directory_modules_for_name([current_module], func_name): + result = get_params_for_module(mod) + if result: + break - # TODO check other modules # cleanup: remove the listener; important: should not stick. func.listeners.remove(listener) @@ -380,9 +386,6 @@ def related_names(definitions, search_name, mods): mods |= set([d.get_parent_until() for d in definitions]) names = [] for m in get_directory_modules_for_name(mods, search_name): - if not m.path.endswith('.py'): - # don't search for names in builtin modules - continue try: stmts = m.used_names[search_name] except KeyError: diff --git a/jedi/settings.py b/jedi/settings.py index 02a38fb3..30b469db 100644 --- a/jedi/settings.py +++ b/jedi/settings.py @@ -28,6 +28,10 @@ dynamic_array_additions = True # the params of a function. dynamic_params = True +# Additional modules in which Jedi checks if statements are to be found. This +# is practical for IDE's, that want to administrate their modules themselves. +additional_dynamic_modules = [] + # ---------------- # recursions # ---------------- diff --git a/test/regression.py b/test/regression.py index 9489662d..c144bbe7 100755 --- a/test/regression.py +++ b/test/regression.py @@ -18,7 +18,9 @@ class TestRegression(unittest.TestCase): script = api.Script(src, pos[0], pos[1], '') return script.get_definition() - def complete(self, src, pos): + def complete(self, src, pos=None): + if pos is None: + pos = 1, len(src) script = api.Script(src, pos[0], pos[1], '') return script.complete() @@ -152,5 +154,19 @@ class TestRegression(unittest.TestCase): assert check(self.get_in_function_call(s7), 'center', 0) + def test_add_dynamic_mods(self): + api.settings.additional_dynamic_modules = ['dynamic.py'] + # Fictional module that defines a function. + src1 = "def ret(a): return a" + # Other fictional modules in another place in the fs. + src2 = 'from .. import setup; setup.ret(1)' + # .parser to load the module + api.modules.Module(os.path.abspath('dynamic.py'), src2).parser + script = api.Script(src1, 1, len(src1), '../setup.py') + result = script.get_definition() + assert len(result) == 1 + assert result[0].description == 'class int' + + if __name__ == '__main__': unittest.main()