1
0
forked from VimPlug/jedi

New "with ignored(*exceptions)" context manager

This commit is contained in:
Danilo Bargen
2013-04-17 23:28:37 +02:00
parent 24573c5ef2
commit f98b0d7b6f
13 changed files with 51 additions and 73 deletions

View File

@@ -3,6 +3,7 @@ The :mod:`api_classes` module contains the return classes of the API. These
classes are the much bigger part of the whole API, because they contain the classes are the much bigger part of the whole API, because they contain the
interesting information about completion and goto operations. interesting information about completion and goto operations.
""" """
from __future__ import with_statement
import re import re
import os import os
@@ -11,6 +12,7 @@ import functools
from jedi._compatibility import unicode, next from jedi._compatibility import unicode, next
from jedi import settings from jedi import settings
from jedi import common
from jedi import parsing_representation as pr from jedi import parsing_representation as pr
from jedi import cache from jedi import cache
import keywords import keywords
@@ -144,10 +146,8 @@ class BaseDefinition(object):
if not isinstance(self.definition, keywords.Keyword): if not isinstance(self.definition, keywords.Keyword):
par = self.definition par = self.definition
while par is not None: while par is not None:
try: with common.ignored(AttributeError):
path.insert(0, par.name) path.insert(0, par.name)
except AttributeError:
pass
par = par.parent par = par.parent
return path return path
@@ -295,10 +295,8 @@ class BaseDefinition(object):
if not path: if not path:
return None # for keywords the path is empty return None # for keywords the path is empty
try: with common.ignored(KeyError):
path[0] = self._mapping[path[0]] path[0] = self._mapping[path[0]]
except KeyError:
pass
for key, repl in self._tuple_mapping.items(): for key, repl in self._tuple_mapping.items():
if tuple(path[:len(key)]) == key: if tuple(path[:len(key)]) == key:
path = [repl] + path[len(key):] path = [repl] + path[len(key):]

View File

@@ -30,6 +30,7 @@ import shutil
from jedi._compatibility import json from jedi._compatibility import json
from jedi import settings from jedi import settings
from jedi import common
from jedi import debug from jedi import debug
# memoize caches will be deleted after every action # memoize caches will be deleted after every action
@@ -148,12 +149,10 @@ def cache_function_definition(stmt):
def cache_star_import(func): def cache_star_import(func):
def wrapper(scope, *args, **kwargs): def wrapper(scope, *args, **kwargs):
try: with common.ignored(KeyError):
mods = star_import_cache[scope] mods = star_import_cache[scope]
if mods[0] + settings.star_import_cache_validity > time.time(): if mods[0] + settings.star_import_cache_validity > time.time():
return mods[1] return mods[1]
except KeyError:
pass
# cache is too old and therefore invalid or not available # cache is too old and therefore invalid or not available
invalidate_star_import_cache(scope) invalidate_star_import_cache(scope)
mods = func(scope, *args, **kwargs) mods = func(scope, *args, **kwargs)
@@ -165,15 +164,13 @@ def cache_star_import(func):
def invalidate_star_import_cache(module, only_main=False): def invalidate_star_import_cache(module, only_main=False):
""" Important if some new modules are being reparsed """ """ Important if some new modules are being reparsed """
try: with common.ignored(KeyError):
t, mods = star_import_cache[module] t, mods = star_import_cache[module]
del star_import_cache[module] del star_import_cache[module]
for m in mods: for m in mods:
invalidate_star_import_cache(m, only_main=True) invalidate_star_import_cache(m, only_main=True)
except KeyError:
pass
if not only_main: if not only_main:
# We need a list here because otherwise the list is being changed # We need a list here because otherwise the list is being changed

View File

@@ -163,3 +163,13 @@ def indent_block(text, indention=' '):
text = text[:-1] text = text[:-1]
lines = text.split('\n') lines = text.split('\n')
return '\n'.join(map(lambda s: indention + s, lines)) + temp return '\n'.join(map(lambda s: indention + s, lines)) + temp
@contextlib.contextmanager
def ignored(*exceptions):
"""Context manager that ignores all of the specified exceptions. This will
be in the standard library starting with Python 3.4."""
try:
yield
except exceptions:
pass

View File

@@ -59,6 +59,7 @@ from jedi import cache
from jedi import parsing_representation as pr from jedi import parsing_representation as pr
from jedi import modules from jedi import modules
from jedi import settings from jedi import settings
from jedi import common
from jedi import debug from jedi import debug
from jedi import fast_parser from jedi import fast_parser
import api_classes import api_classes
@@ -487,10 +488,8 @@ def related_name_add_import_modules(definitions, search_name):
for d in definitions: for d in definitions:
if isinstance(d.parent, pr.Import): if isinstance(d.parent, pr.Import):
s = imports.ImportPath(d.parent, direct_resolve=True) s = imports.ImportPath(d.parent, direct_resolve=True)
try: with common.ignored(IndexError):
new.add(s.follow(is_goto=True)[0]) new.add(s.follow(is_goto=True)[0])
except IndexError:
pass
return set(definitions) | new return set(definitions) | new

View File

@@ -68,6 +68,7 @@ backtracking algorithm.
.. todo:: nonlocal statement, needed or can be ignored? (py3k) .. todo:: nonlocal statement, needed or can be ignored? (py3k)
""" """
from __future__ import with_statement
import sys import sys
import itertools import itertools
@@ -429,11 +430,9 @@ def find_name(scope, name_str, position=None, search_global=False,
if isinstance(scope, (er.Instance, er.Class)) \ if isinstance(scope, (er.Instance, er.Class)) \
and hasattr(r, 'get_descriptor_return'): and hasattr(r, 'get_descriptor_return'):
# handle descriptors # handle descriptors
try: with common.ignored(KeyError):
res_new += r.get_descriptor_return(scope) res_new += r.get_descriptor_return(scope)
continue continue
except KeyError:
pass
res_new.append(r) res_new.append(r)
return res_new return res_new
@@ -462,19 +461,15 @@ def check_getattr(inst, name_str):
# str is important to lose the NamePart! # str is important to lose the NamePart!
module = builtin.Builtin.scope module = builtin.Builtin.scope
name = pr.Call(module, str(name_str), pr.Call.STRING, (0, 0), inst) name = pr.Call(module, str(name_str), pr.Call.STRING, (0, 0), inst)
try: with common.ignored(KeyError):
result = inst.execute_subscope_by_name('__getattr__', [name]) result = inst.execute_subscope_by_name('__getattr__', [name])
except KeyError:
pass
if not result: if not result:
# this is a little bit special. `__getattribute__` is executed # this is a little bit special. `__getattribute__` is executed
# before anything else. But: I know no use case, where this # before anything else. But: I know no use case, where this
# could be practical and the jedi would return wrong types. If # could be practical and the jedi would return wrong types. If
# you ever have something, let me know! # you ever have something, let me know!
try: with common.ignored(KeyError):
result = inst.execute_subscope_by_name('__getattribute__', [name]) result = inst.execute_subscope_by_name('__getattribute__', [name])
except KeyError:
pass
return result return result
@@ -536,10 +531,8 @@ def assign_tuples(tup, results, seek_name):
debug.warning("invalid tuple lookup %s of result %s in %s" debug.warning("invalid tuple lookup %s of result %s in %s"
% (tup, results, seek_name)) % (tup, results, seek_name))
else: else:
try: with common.ignored(IndexError):
types += func(index) types += func(index)
except IndexError:
pass
return types return types
result = [] result = []
@@ -648,11 +641,9 @@ def follow_call_list(call_list, follow_array=False):
call = next(calls_iterator) call = next(calls_iterator)
except StopIteration: except StopIteration:
break break
try: with common.ignored(AttributeError):
if str(call.name) == 'else': if str(call.name) == 'else':
break break
except AttributeError:
pass
continue continue
result += follow_call(call) result += follow_call(call)
elif call == '*': elif call == '*':

View File

@@ -9,6 +9,8 @@ instantiated. This class represents these cases.
So, why is there also a ``Class`` class here? Well, there are decorators and So, why is there also a ``Class`` class here? Well, there are decorators and
they change classes in Python 3. they change classes in Python 3.
""" """
from __future__ import with_statement
import copy import copy
import itertools import itertools
@@ -61,10 +63,8 @@ class Instance(use_metaclass(cache.CachedMetaClass, Executable)):
else: else:
# need to execute the __init__ function, because the dynamic param # need to execute the __init__ function, because the dynamic param
# searching needs it. # searching needs it.
try: with common.ignored(KeyError):
self.execute_subscope_by_name('__init__', self.var_args) self.execute_subscope_by_name('__init__', self.var_args)
except KeyError:
pass
# Generated instances are classes that are just generated by self # Generated instances are classes that are just generated by self
# (No var_args) used. # (No var_args) used.
self.is_generated = False self.is_generated = False
@@ -804,10 +804,8 @@ class Array(use_metaclass(cache.CachedMetaClass, pr.Base)):
if isinstance(index, Instance) \ if isinstance(index, Instance) \
and str(index.name) in ['int', 'str'] \ and str(index.name) in ['int', 'str'] \
and len(index.var_args) == 1: and len(index.var_args) == 1:
try: with common.ignored(KeyError, IndexError):
return self.get_exact_index_types(index.var_args[0]) return self.get_exact_index_types(index.var_args[0])
except (KeyError, IndexError):
pass
result = list(self._follow_values(self._array.values)) result = list(self._follow_values(self._array.values))
result += dynamic.check_array_additions(self) result += dynamic.check_array_additions(self)

View File

@@ -1,5 +1,8 @@
from __future__ import with_statement
import copy import copy
from jedi import common
from jedi import parsing_representation as pr from jedi import parsing_representation as pr
@@ -21,13 +24,11 @@ def fast_parent_copy(obj):
before = () before = ()
for cls in new_obj.__class__.__mro__: for cls in new_obj.__class__.__mro__:
try: with common.ignored(AttributeError):
if before == cls.__slots__: if before == cls.__slots__:
continue continue
before = cls.__slots__ before = cls.__slots__
items += [(n, getattr(new_obj, n)) for n in before] items += [(n, getattr(new_obj, n)) for n in before]
except AttributeError:
pass
for key, value in items: for key, value in items:
# replace parent (first try _parent and then parent) # replace parent (first try _parent and then parent)
@@ -35,10 +36,8 @@ def fast_parent_copy(obj):
if key == 'parent' and '_parent' in items: if key == 'parent' and '_parent' in items:
# parent can be a property # parent can be a property
continue continue
try: with common.ignored(KeyError):
setattr(new_obj, key, new_elements[value]) setattr(new_obj, key, new_elements[value])
except KeyError:
pass
elif key in ['parent_function', 'use_as_parent', '_sub_module']: elif key in ['parent_function', 'use_as_parent', '_sub_module']:
continue continue
elif isinstance(value, list): elif isinstance(value, list):

View File

@@ -11,7 +11,6 @@ correct implementation is delegated to _compatibility.
This module also supports import autocompletion, which means to complete This module also supports import autocompletion, which means to complete
statements like ``from datetim`` (curser at the end would return ``datetime``). statements like ``from datetim`` (curser at the end would return ``datetime``).
""" """
from __future__ import with_statement from __future__ import with_statement
import os import os
@@ -21,6 +20,7 @@ import itertools
from jedi._compatibility import find_module from jedi._compatibility import find_module
from jedi import modules from jedi import modules
from jedi import common
from jedi import debug from jedi import debug
from jedi import parsing_representation as pr from jedi import parsing_representation as pr
from jedi import cache from jedi import cache
@@ -122,11 +122,9 @@ class ImportPath(pr.Base):
if self.import_stmt.relative_count: if self.import_stmt.relative_count:
rel_path = self.get_relative_path() + '/__init__.py' rel_path = self.get_relative_path() + '/__init__.py'
try: with common.ignored(IOError):
m = modules.Module(rel_path) m = modules.Module(rel_path)
names += m.parser.module.get_defined_names() names += m.parser.module.get_defined_names()
except IOError:
pass
else: else:
if on_import_stmt and isinstance(scope, pr.Module) \ if on_import_stmt and isinstance(scope, pr.Module) \
and scope.path.endswith('__init__.py'): and scope.path.endswith('__init__.py'):
@@ -274,10 +272,8 @@ class ImportPath(pr.Base):
and len(self.import_path) == 1: and len(self.import_path) == 1:
# follow `from . import some_variable` # follow `from . import some_variable`
rel_path = self.get_relative_path() rel_path = self.get_relative_path()
try: with common.ignored(ImportError):
current_namespace = follow_str(rel_path, '__init__') current_namespace = follow_str(rel_path, '__init__')
except ImportError:
pass
if current_namespace[1]: if current_namespace[1]:
rest = self.import_path[i:] rest = self.import_path[i:]
else: else:

View File

@@ -1,7 +1,10 @@
from __future__ import with_statement
import pydoc import pydoc
import keyword import keyword
from jedi._compatibility import is_py3k from jedi._compatibility import is_py3k
from jedi import common
import builtin import builtin
try: try:
@@ -63,12 +66,10 @@ def imitate_pydoc(string):
# with unicode strings) # with unicode strings)
string = str(string) string = str(string)
h = pydoc.help h = pydoc.help
try: with common.ignored(KeyError):
# try to access symbols # try to access symbols
string = h.symbols[string] string = h.symbols[string]
string, _, related = string.partition(' ') string, _, related = string.partition(' ')
except KeyError:
pass
get_target = lambda s: h.topics.get(s, h.keywords.get(s)) get_target = lambda s: h.topics.get(s, h.keywords.get(s))
while isinstance(string, str): while isinstance(string, str):

View File

@@ -27,6 +27,7 @@ from jedi import parsing_representation as pr
from jedi import fast_parser from jedi import fast_parser
from jedi import debug from jedi import debug
from jedi import settings from jedi import settings
from jedi import common
class CachedModule(object): class CachedModule(object):
@@ -107,11 +108,9 @@ class ModuleWithCursor(Module):
def parser(self): def parser(self):
""" get the parser lazy """ """ get the parser lazy """
if not self._parser: if not self._parser:
try: with common.ignored(KeyError):
parser = cache.parser_cache[self.path].parser parser = cache.parser_cache[self.path].parser
cache.invalidate_star_import_cache(parser.module) cache.invalidate_star_import_cache(parser.module)
except KeyError:
pass
# Call the parser already here, because it will be used anyways. # Call the parser already here, because it will be used anyways.
# Also, the position is here important (which will not be used by # Also, the position is here important (which will not be used by
# default), therefore fill the cache here. # default), therefore fill the cache here.
@@ -348,10 +347,8 @@ def sys_path_with_modifications(module):
return [] # support for modules without a path is intentionally bad. return [] # support for modules without a path is intentionally bad.
curdir = os.path.abspath(os.curdir) curdir = os.path.abspath(os.curdir)
try: with common.ignored(OSError):
os.chdir(os.path.dirname(module.path)) os.chdir(os.path.dirname(module.path))
except OSError:
pass
result = check_module(module) result = check_module(module)
result += detect_django_path(module.path) result += detect_django_path(module.path)
@@ -372,12 +369,10 @@ def detect_django_path(module_path):
else: else:
module_path = new module_path = new
try: with common.ignored(IOError):
with open(module_path + os.path.sep + 'manage.py'): with open(module_path + os.path.sep + 'manage.py'):
debug.dbg('Found django path: %s' % module_path) debug.dbg('Found django path: %s' % module_path)
result.append(module_path) result.append(module_path)
except IOError:
pass
return result return result

View File

@@ -15,6 +15,7 @@ within the statement. This lowers memory usage and cpu time and reduces the
complexity of the ``Parser`` (there's another parser sitting inside complexity of the ``Parser`` (there's another parser sitting inside
``Statement``, which produces ``Array`` and ``Call``). ``Statement``, which produces ``Array`` and ``Call``).
""" """
from __future__ import with_statement
import tokenize import tokenize
import keyword import keyword
@@ -396,7 +397,7 @@ class Parser(object):
self._check_user_stmt(stmt) self._check_user_stmt(stmt)
# Attribute docstring (PEP 257) support # Attribute docstring (PEP 257) support
try: with common.ignored(IndexError, AttributeError):
# If string literal is being parsed # If string literal is being parsed
first_tok = stmt.token_list[0] first_tok = stmt.token_list[0]
if (not stmt.set_vars and if (not stmt.set_vars and
@@ -405,8 +406,6 @@ class Parser(object):
first_tok[0] == tokenize.STRING): first_tok[0] == tokenize.STRING):
# ... then set it as a docstring # ... then set it as a docstring
self.scope.statements[-1].add_docstr(first_tok[1]) self.scope.statements[-1].add_docstr(first_tok[1])
except (IndexError, AttributeError):
pass
if tok in always_break + not_first_break: if tok in always_break + not_first_break:
self._gen.push_last_back() self._gen.push_last_back()

View File

@@ -34,6 +34,7 @@ statements in this scope. Check this out:
See also :attr:`Scope.subscopes` and :attr:`Scope.statements`. See also :attr:`Scope.subscopes` and :attr:`Scope.statements`.
""" """
from __future__ import with_statement
import os import os
import re import re
@@ -1280,11 +1281,8 @@ class Array(Call):
inner = [] inner = []
for i, stmt in enumerate(self.values): for i, stmt in enumerate(self.values):
s = '' s = ''
try: with common.ignored(IndexError):
key = self.keys[i] key = self.keys[i]
except IndexError:
pass
else:
s += key.get_code(new_line=False) + ': ' s += key.get_code(new_line=False) + ': '
s += stmt.get_code(new_line=False) s += stmt.get_code(new_line=False)
inner.append(s) inner.append(s)

View File

@@ -12,11 +12,11 @@ following functions (sometimes bug-prone):
- extract variable - extract variable
- inline variable - inline variable
""" """
from __future__ import with_statement from __future__ import with_statement
import difflib import difflib
from jedi import common
from jedi import modules from jedi import modules
from jedi import helpers from jedi import helpers
from jedi import parsing_representation as pr from jedi import parsing_representation as pr
@@ -168,7 +168,7 @@ def inline(script):
dct = {} dct = {}
definitions = script.goto() definitions = script.goto()
try: with common.ignored(AssertionError):
assert len(definitions) == 1 assert len(definitions) == 1
stmt = definitions[0].definition stmt = definitions[0].definition
related_names = script.related_names() related_names = script.related_names()
@@ -202,7 +202,4 @@ def inline(script):
else: else:
new_lines.pop(index) new_lines.pop(index)
except AssertionError:
pass
return Refactoring(dct) return Refactoring(dct)