Skip to content

Commit

Permalink
New "with ignored(*exceptions)" context manager
Browse files Browse the repository at this point in the history
  • Loading branch information
dbrgn committed Apr 17, 2013
1 parent 24573c5 commit f98b0d7
Show file tree
Hide file tree
Showing 13 changed files with 51 additions and 73 deletions.
10 changes: 4 additions & 6 deletions jedi/api_classes.py
Expand Up @@ -3,6 +3,7 @@
classes are the much bigger part of the whole API, because they contain the
interesting information about completion and goto operations.
"""
from __future__ import with_statement

import re
import os
Expand All @@ -11,6 +12,7 @@

from jedi._compatibility import unicode, next
from jedi import settings
from jedi import common
from jedi import parsing_representation as pr
from jedi import cache
import keywords
Expand Down Expand Up @@ -144,10 +146,8 @@ def path(self):
if not isinstance(self.definition, keywords.Keyword):
par = self.definition
while par is not None:
try:
with common.ignored(AttributeError):
path.insert(0, par.name)
except AttributeError:
pass
par = par.parent
return path

Expand Down Expand Up @@ -295,10 +295,8 @@ def full_name(self):
if not path:
return None # for keywords the path is empty

try:
with common.ignored(KeyError):
path[0] = self._mapping[path[0]]
except KeyError:
pass
for key, repl in self._tuple_mapping.items():
if tuple(path[:len(key)]) == key:
path = [repl] + path[len(key):]
Expand Down
9 changes: 3 additions & 6 deletions jedi/cache.py
Expand Up @@ -30,6 +30,7 @@

from jedi._compatibility import json
from jedi import settings
from jedi import common
from jedi import debug

# memoize caches will be deleted after every action
Expand Down Expand Up @@ -148,12 +149,10 @@ def cache_function_definition(stmt):

def cache_star_import(func):
def wrapper(scope, *args, **kwargs):
try:
with common.ignored(KeyError):
mods = star_import_cache[scope]
if mods[0] + settings.star_import_cache_validity > time.time():
return mods[1]
except KeyError:
pass
# cache is too old and therefore invalid or not available
invalidate_star_import_cache(scope)
mods = func(scope, *args, **kwargs)
Expand All @@ -165,15 +164,13 @@ def wrapper(scope, *args, **kwargs):

def invalidate_star_import_cache(module, only_main=False):
""" Important if some new modules are being reparsed """
try:
with common.ignored(KeyError):
t, mods = star_import_cache[module]

del star_import_cache[module]

for m in mods:
invalidate_star_import_cache(m, only_main=True)
except KeyError:
pass

if not only_main:
# We need a list here because otherwise the list is being changed
Expand Down
10 changes: 10 additions & 0 deletions jedi/common.py
Expand Up @@ -163,3 +163,13 @@ def indent_block(text, indention=' '):
text = text[:-1]
lines = text.split('\n')
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
5 changes: 2 additions & 3 deletions jedi/dynamic.py
Expand Up @@ -59,6 +59,7 @@ def foo(bar):
from jedi import parsing_representation as pr
from jedi import modules
from jedi import settings
from jedi import common
from jedi import debug
from jedi import fast_parser
import api_classes
Expand Down Expand Up @@ -487,10 +488,8 @@ def related_name_add_import_modules(definitions, search_name):
for d in definitions:
if isinstance(d.parent, pr.Import):
s = imports.ImportPath(d.parent, direct_resolve=True)
try:
with common.ignored(IndexError):
new.add(s.follow(is_goto=True)[0])
except IndexError:
pass
return set(definitions) | new


Expand Down
21 changes: 6 additions & 15 deletions jedi/evaluate.py
Expand Up @@ -68,6 +68,7 @@
.. todo:: nonlocal statement, needed or can be ignored? (py3k)
"""
from __future__ import with_statement

import sys
import itertools
Expand Down Expand Up @@ -429,11 +430,9 @@ def descriptor_check(result):
if isinstance(scope, (er.Instance, er.Class)) \
and hasattr(r, 'get_descriptor_return'):
# handle descriptors
try:
with common.ignored(KeyError):
res_new += r.get_descriptor_return(scope)
continue
except KeyError:
pass
res_new.append(r)
return res_new

Expand Down Expand Up @@ -462,19 +461,15 @@ def check_getattr(inst, name_str):
# str is important to lose the NamePart!
module = builtin.Builtin.scope
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])
except KeyError:
pass
if not result:
# this is a little bit special. `__getattribute__` is executed
# before anything else. But: I know no use case, where this
# could be practical and the jedi would return wrong types. If
# you ever have something, let me know!
try:
with common.ignored(KeyError):
result = inst.execute_subscope_by_name('__getattribute__', [name])
except KeyError:
pass
return result


Expand Down Expand Up @@ -536,10 +531,8 @@ def eval_results(index):
debug.warning("invalid tuple lookup %s of result %s in %s"
% (tup, results, seek_name))
else:
try:
with common.ignored(IndexError):
types += func(index)
except IndexError:
pass
return types

result = []
Expand Down Expand Up @@ -648,11 +641,9 @@ def evaluate_list_comprehension(lc, parent=None):
call = next(calls_iterator)
except StopIteration:
break
try:
with common.ignored(AttributeError):
if str(call.name) == 'else':
break
except AttributeError:
pass
continue
result += follow_call(call)
elif call == '*':
Expand Down
10 changes: 4 additions & 6 deletions jedi/evaluate_representation.py
Expand Up @@ -9,6 +9,8 @@
So, why is there also a ``Class`` class here? Well, there are decorators and
they change classes in Python 3.
"""
from __future__ import with_statement

import copy
import itertools

Expand Down Expand Up @@ -61,10 +63,8 @@ def __init__(self, base, var_args=()):
else:
# need to execute the __init__ function, because the dynamic param
# searching needs it.
try:
with common.ignored(KeyError):
self.execute_subscope_by_name('__init__', self.var_args)
except KeyError:
pass
# Generated instances are classes that are just generated by self
# (No var_args) used.
self.is_generated = False
Expand Down Expand Up @@ -804,10 +804,8 @@ def get_index_types(self, index_arr=None):
if isinstance(index, Instance) \
and str(index.name) in ['int', 'str'] \
and len(index.var_args) == 1:
try:
with common.ignored(KeyError, IndexError):
return self.get_exact_index_types(index.var_args[0])
except (KeyError, IndexError):
pass

result = list(self._follow_values(self._array.values))
result += dynamic.check_array_additions(self)
Expand Down
11 changes: 5 additions & 6 deletions jedi/helpers.py
@@ -1,5 +1,8 @@
from __future__ import with_statement

import copy

from jedi import common
from jedi import parsing_representation as pr


Expand All @@ -21,24 +24,20 @@ def recursion(obj):

before = ()
for cls in new_obj.__class__.__mro__:
try:
with common.ignored(AttributeError):
if before == cls.__slots__:
continue
before = cls.__slots__
items += [(n, getattr(new_obj, n)) for n in before]
except AttributeError:
pass

for key, value in items:
# replace parent (first try _parent and then parent)
if key in ['parent', '_parent'] and value is not None:
if key == 'parent' and '_parent' in items:
# parent can be a property
continue
try:
with common.ignored(KeyError):
setattr(new_obj, key, new_elements[value])
except KeyError:
pass
elif key in ['parent_function', 'use_as_parent', '_sub_module']:
continue
elif isinstance(value, list):
Expand Down
10 changes: 3 additions & 7 deletions jedi/imports.py
Expand Up @@ -11,7 +11,6 @@
This module also supports import autocompletion, which means to complete
statements like ``from datetim`` (curser at the end would return ``datetime``).
"""

from __future__ import with_statement

import os
Expand All @@ -21,6 +20,7 @@

from jedi._compatibility import find_module
from jedi import modules
from jedi import common
from jedi import debug
from jedi import parsing_representation as pr
from jedi import cache
Expand Down Expand Up @@ -122,11 +122,9 @@ def get_defined_names(self, on_import_stmt=False):

if self.import_stmt.relative_count:
rel_path = self.get_relative_path() + '/__init__.py'
try:
with common.ignored(IOError):
m = modules.Module(rel_path)
names += m.parser.module.get_defined_names()
except IOError:
pass
else:
if on_import_stmt and isinstance(scope, pr.Module) \
and scope.path.endswith('__init__.py'):
Expand Down Expand Up @@ -274,10 +272,8 @@ def module_not_found():
and len(self.import_path) == 1:
# follow `from . import some_variable`
rel_path = self.get_relative_path()
try:
with common.ignored(ImportError):
current_namespace = follow_str(rel_path, '__init__')
except ImportError:
pass
if current_namespace[1]:
rest = self.import_path[i:]
else:
Expand Down
7 changes: 4 additions & 3 deletions jedi/keywords.py
@@ -1,7 +1,10 @@
from __future__ import with_statement

import pydoc
import keyword

from jedi._compatibility import is_py3k
from jedi import common
import builtin

try:
Expand Down Expand Up @@ -63,12 +66,10 @@ def imitate_pydoc(string):
# with unicode strings)
string = str(string)
h = pydoc.help
try:
with common.ignored(KeyError):
# try to access symbols
string = h.symbols[string]
string, _, related = string.partition(' ')
except KeyError:
pass

get_target = lambda s: h.topics.get(s, h.keywords.get(s))
while isinstance(string, str):
Expand Down
13 changes: 4 additions & 9 deletions jedi/modules.py
Expand Up @@ -27,6 +27,7 @@
from jedi import fast_parser
from jedi import debug
from jedi import settings
from jedi import common


class CachedModule(object):
Expand Down Expand Up @@ -107,11 +108,9 @@ def __init__(self, path, source, position):
def parser(self):
""" get the parser lazy """
if not self._parser:
try:
with common.ignored(KeyError):
parser = cache.parser_cache[self.path].parser
cache.invalidate_star_import_cache(parser.module)
except KeyError:
pass
# Call the parser already here, because it will be used anyways.
# Also, the position is here important (which will not be used by
# default), therefore fill the cache here.
Expand Down Expand Up @@ -348,10 +347,8 @@ def check_module(module):
return [] # support for modules without a path is intentionally bad.

curdir = os.path.abspath(os.curdir)
try:
with common.ignored(OSError):
os.chdir(os.path.dirname(module.path))
except OSError:
pass

result = check_module(module)
result += detect_django_path(module.path)
Expand All @@ -372,12 +369,10 @@ def detect_django_path(module_path):
else:
module_path = new

try:
with common.ignored(IOError):
with open(module_path + os.path.sep + 'manage.py'):
debug.dbg('Found django path: %s' % module_path)
result.append(module_path)
except IOError:
pass
return result


Expand Down
5 changes: 2 additions & 3 deletions jedi/parsing.py
Expand Up @@ -15,6 +15,7 @@
complexity of the ``Parser`` (there's another parser sitting inside
``Statement``, which produces ``Array`` and ``Call``).
"""
from __future__ import with_statement

import tokenize
import keyword
Expand Down Expand Up @@ -396,7 +397,7 @@ def _parse_statement(self, pre_used_token=None, added_breaks=None,
self._check_user_stmt(stmt)

# Attribute docstring (PEP 257) support
try:
with common.ignored(IndexError, AttributeError):
# If string literal is being parsed
first_tok = stmt.token_list[0]
if (not stmt.set_vars and
Expand All @@ -405,8 +406,6 @@ def _parse_statement(self, pre_used_token=None, added_breaks=None,
first_tok[0] == tokenize.STRING):
# ... then set it as a docstring
self.scope.statements[-1].add_docstr(first_tok[1])
except (IndexError, AttributeError):
pass

if tok in always_break + not_first_break:
self._gen.push_last_back()
Expand Down

0 comments on commit f98b0d7

Please sign in to comment.