diff --git a/jedi/evaluate/compiled/access.py b/jedi/evaluate/compiled/access.py index 5dfa6b14..3117c326 100644 --- a/jedi/evaluate/compiled/access.py +++ b/jedi/evaluate/compiled/access.py @@ -385,6 +385,17 @@ class DirectObjectAccess(object): def is_super_class(self, exception): return issubclass(exception, self._obj) + def get_dir_infos(self): + """ + Used to return a couple of infos that are needed when accessing the sub + objects of an objects + """ + tuples = dict( + (name, self.is_allowed_getattr(name)) + for name in self.dir() + ) + return self.needs_type_completions(), tuples + def _is_class_instance(obj): """Like inspect.* methods.""" diff --git a/jedi/evaluate/compiled/context.py b/jedi/evaluate/compiled/context.py index 7ba0a783..e00881f2 100644 --- a/jedi/evaluate/compiled/context.py +++ b/jedi/evaluate/compiled/context.py @@ -298,27 +298,48 @@ class CompiledObjectFilter(AbstractFilter): self._compiled_object = compiled_object self._is_instance = is_instance - @memoize_method def get(self, name): name = str(name) + return self._get( + name, + lambda: self._compiled_object.access_handle.is_allowed_getattr(name), + lambda: self._compiled_object.access_handle.dir(), + ) + + def _get(self, name, allowed_getattr_callback, dir_callback): + """ + To remove quite a few access calls we introduced the callback here. + """ try: - if not self._compiled_object.access_handle.is_allowed_getattr(name): - return [EmptyCompiledName(self._evaluator, name)] + if not allowed_getattr_callback(): + return [self._get_cached_name(name, is_empty=True)] except AttributeError: return [] - if self._is_instance and name not in self._compiled_object.access_handle.dir(): + if self._is_instance and name not in dir_callback(): return [] - return [self._create_name(name)] + return [self._get_cached_name(name)] + + @memoize_method + def _get_cached_name(self, name, is_empty=False): + if is_empty: + return EmptyCompiledName(self._evaluator, name) + else: + return self._create_name(name) def values(self): from jedi.evaluate.compiled import builtin_from_name names = [] - for name in self._compiled_object.access_handle.dir(): - names += self.get(name) + needs_type_completions, dir_infos = self._compiled_object.access_handle.get_dir_infos() + for name in dir_infos: + names += self._get( + name, + lambda: dir_infos[name], + lambda: dir_infos.keys(), + ) # ``dir`` doesn't include the type names. - if not self._is_instance and self._compiled_object.access_handle.needs_type_completions(): + if not self._is_instance and needs_type_completions: for filter in builtin_from_name(self._evaluator, 'type').get_filters(): names += filter.values() return names diff --git a/jedi/evaluate/compiled/subprocess/functions.py b/jedi/evaluate/compiled/subprocess/functions.py index d5602436..11b36d5f 100644 --- a/jedi/evaluate/compiled/subprocess/functions.py +++ b/jedi/evaluate/compiled/subprocess/functions.py @@ -12,6 +12,8 @@ def load_module(evaluator, path=None, name=None): def get_compiled_method_return(evaluator, id, attribute, *args, **kwargs): handle = evaluator.compiled_subprocess.get_access_handle(id) + #print >> sys.stderr, handle, attribute, args, kwargs + #print(id, attribute, args, kwargs, file=sys.stderr) return getattr(handle.access, attribute)(*args, **kwargs)