summaryrefslogtreecommitdiff
path: root/astroid
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2016-12-03 14:45:56 +0200
committerClaudiu Popa <pcmanticore@gmail.com>2016-12-30 13:25:20 +0200
commitc96049a10b0ff58ed0688eb2d83cc546fd6a67d0 (patch)
treeb24b63da970dcf57f439446633e97b312b3ed9d4 /astroid
parente9e5c7fc61748b8b7cc73c948556fc9a830c162c (diff)
downloadastroid-git-c96049a10b0ff58ed0688eb2d83cc546fd6a67d0.tar.gz
Let the type error propagate as an AstroidTypeError.
Diffstat (limited to 'astroid')
-rw-r--r--astroid/exceptions.py8
-rw-r--r--astroid/inference.py3
-rw-r--r--astroid/protocols.py8
-rw-r--r--astroid/tree/node_classes.py62
4 files changed, 53 insertions, 28 deletions
diff --git a/astroid/exceptions.py b/astroid/exceptions.py
index 9dc80710..3b34ae54 100644
--- a/astroid/exceptions.py
+++ b/astroid/exceptions.py
@@ -206,6 +206,14 @@ class _NonDeducibleTypeHierarchy(Exception):
"""Raised when is_subtype / is_supertype can't deduce the relation between two types."""
+class AstroidIndexError(AstroidError):
+ """Raised when an Indexable / Mapping does not have an index / key."""
+
+
+class AstroidTypeError(AstroidError):
+ """Raised when a TypeError would be expected in Python code."""
+
+
# Backwards-compatibility aliases
OperationError = util.BadOperationMessage
UnaryOperationError = util.BadUnaryOperationMessage
diff --git a/astroid/inference.py b/astroid/inference.py
index f87adc9d..aeb06baf 100644
--- a/astroid/inference.py
+++ b/astroid/inference.py
@@ -254,7 +254,8 @@ def infer_subscript(self, context=None):
try:
assigned = value.getitem(index_value, context)
- except (IndexError, TypeError) as exc:
+ except (exceptions.AstroidTypeError,
+ exceptions.AstroidIndexError) as exc:
util.reraise(exceptions.InferenceError(node=self, error=exc,
context=context))
diff --git a/astroid/protocols.py b/astroid/protocols.py
index e72ea69b..cb071a02 100644
--- a/astroid/protocols.py
+++ b/astroid/protocols.py
@@ -247,9 +247,9 @@ def _resolve_looppart(parts, assign_path, context, nodes):
index_node = nodes.Const(index)
try:
assigned = stmt.getitem(index_node, context)
- except (AttributeError, IndexError):
- continue
- except TypeError: # stmt is unsubscriptable Const
+ except (AttributeError,
+ exceptions.AstroidTypeError,
+ exceptions.AstroidIndexError):
continue
if not assign_path:
# we achieved to resolved the assignment path,
@@ -404,7 +404,7 @@ def _resolve_asspart(parts, assign_path, context, nodes):
assigned = part.getitem(index_node, context)
# XXX raise a specific exception to avoid potential hiding of
# unexpected exception ?
- except (TypeError, IndexError):
+ except (exceptions.AstroidTypeError, exceptions.AstroidIndexError):
return
if not assign_path:
# we achieved to resolved the assignment path, don't infer the
diff --git a/astroid/tree/node_classes.py b/astroid/tree/node_classes.py
index a9460337..05f11a82 100644
--- a/astroid/tree/node_classes.py
+++ b/astroid/tree/node_classes.py
@@ -76,16 +76,27 @@ def _infer_slice(node, context=None):
def _container_getitem(instance, elts, index, context=None):
"""Get a slice or an item, using the given *index*, for the given sequence."""
- if isinstance(index, Slice):
- index_slice = _infer_slice(index, context=context)
- new_cls = instance.__class__()
- new_cls.elts = elts[index_slice]
- new_cls.parent = instance.parent
- return new_cls
- elif isinstance(index, Const):
- return elts[index.value]
-
- raise TypeError('Could not use %s as subscript index' % index)
+ try:
+ if isinstance(index, Slice):
+ index_slice = _infer_slice(index, context=context)
+ new_cls = instance.__class__()
+ new_cls.elts = elts[index_slice]
+ new_cls.parent = instance.parent
+ return new_cls
+ elif isinstance(index, Const):
+ return elts[index.value]
+ except IndexError:
+ util.reraise(exceptions.AstroidIndexError(
+ message='Index {index!s} out of range',
+ node=instance, index=index, context=context))
+ except TypeError as exc:
+ util.reraise(exceptions.AstroidIndexError(
+ message='Type error {error!r}', error=exc,
+ node=instance, index=index, context=context))
+
+ raise exceptions.AstroidTypeError(
+ 'Could not use %s as subscript index' % index
+ )
@util.register_implementation(treeabc.Statement)
class Statement(base.NodeNG):
@@ -553,19 +564,26 @@ class Const(base.NodeNG, objects.BaseInstance):
elif isinstance(index, Slice):
index_value = _infer_slice(index, context=context)
else:
- raise TypeError(
+ raise exceptions.AstroidTypeError(
'Could not use type {} as subscript index'.format(type(index))
)
- if isinstance(self.value, six.string_types):
- return Const(self.value[index_value])
- if isinstance(self.value, bytes) and six.PY3:
- # Bytes aren't instances of six.string_types
- # on Python 3. Also, indexing them should return
- # integers.
- return Const(self.value[index_value])
+ try:
+ if isinstance(self.value, six.string_types):
+ return Const(self.value[index_value])
+ if isinstance(self.value, bytes) and six.PY3:
+ # Bytes aren't instances of six.string_types
+ # on Python 3. Also, indexing them should return
+ # integers.
+ return Const(self.value[index_value])
+ except TypeError:
+ # The object does not support this operation, let the
+ # following error be raised instead.
+ pass
- raise TypeError('%r (value=%s)' % (self, self.value))
+ raise exceptions.AstroidTypeError(
+ '%r (value=%s)' % (self, self.value)
+ )
def has_dynamic_getattr(self):
return False
@@ -699,7 +717,7 @@ class Dict(base.NodeNG, objects.DictInstance):
if isinstance(key, DictUnpack):
try:
return value.getitem(lookup_key, context)
- except IndexError:
+ except (exceptions.AstroidTypeError, exceptions.AstroidIndexError):
continue
for inferredkey in key.infer(context):
if inferredkey is util.Uninferable:
@@ -707,9 +725,7 @@ class Dict(base.NodeNG, objects.DictInstance):
if isinstance(inferredkey, Const) and isinstance(lookup_key, Const):
if inferredkey.value == lookup_key.value:
return value
- # This should raise KeyError, but all call sites only catch
- # IndexError. Let's leave it like that for now.
- raise IndexError(lookup_key)
+ raise exceptions.AstroidIndexError(index)
def bool_value(self):
return bool(self.keys)