summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2016-12-03 14:45:56 +0200
committerClaudiu Popa <pcmanticore@gmail.com>2016-12-03 14:45:56 +0200
commiteb9642ffeeab679b952e785be88916a450d317f7 (patch)
tree1d4f51deb400141c029fbc3915ac0944832b3df8
parentac3e82e9bd8678086325a71a927a06bbc43d415e (diff)
downloadastroid-git-eb9642ffeeab679b952e785be88916a450d317f7.tar.gz
Let the type error propagate as an AstroidTypeError.
-rw-r--r--astroid/exceptions.py8
-rw-r--r--astroid/inference.py4
-rw-r--r--astroid/node_classes.py64
-rw-r--r--astroid/protocols.py8
4 files changed, 55 insertions, 29 deletions
diff --git a/astroid/exceptions.py b/astroid/exceptions.py
index ea2b9b07..8b3f2522 100644
--- a/astroid/exceptions.py
+++ b/astroid/exceptions.py
@@ -196,6 +196,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 153e269d..9ce078a2 100644
--- a/astroid/inference.py
+++ b/astroid/inference.py
@@ -257,7 +257,9 @@ def infer_subscript(self, context=None):
try:
assigned = value.getitem(index_value, context)
- except (IndexError, TypeError, AttributeError) as exc:
+ except (exceptions.AstroidTypeError,
+ exceptions.AstroidIndexError,
+ AttributeError) as exc:
util.reraise(exceptions.InferenceError(node=self, error=exc,
context=context))
diff --git a/astroid/node_classes.py b/astroid/node_classes.py
index 5c44b158..9a8c5bb1 100644
--- a/astroid/node_classes.py
+++ b/astroid/node_classes.py
@@ -173,17 +173,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
+ )
class NodeNG(object):
@@ -1238,19 +1248,26 @@ class Const(NodeNG, bases.Instance):
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
@@ -1353,7 +1370,7 @@ class Dict(NodeNG, bases.Instance):
if isinstance(key, DictUnpack):
try:
return value.getitem(index, context)
- except IndexError:
+ except (exceptions.AstroidTypeError, exceptions.AstroidIndexError):
continue
for inferredkey in key.infer(context):
if inferredkey is util.Uninferable:
@@ -1361,9 +1378,8 @@ class Dict(NodeNG, bases.Instance):
if isinstance(inferredkey, Const) and isinstance(index, Const):
if inferredkey.value == index.value:
return value
- # This should raise KeyError, but all call sites only catch
- # IndexError. Let's leave it like that for now.
- raise IndexError(index)
+
+ raise exceptions.AstroidIndexError(index)
def bool_value(self):
return bool(self.items)
diff --git a/astroid/protocols.py b/astroid/protocols.py
index 93ec7a61..73954fb6 100644
--- a/astroid/protocols.py
+++ b/astroid/protocols.py
@@ -219,9 +219,9 @@ def _resolve_looppart(parts, asspath, context):
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 asspath:
# we achieved to resolved the assignment path,
@@ -370,7 +370,7 @@ def _resolve_asspart(parts, asspath, context):
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 asspath:
# we achieved to resolved the assignment path, don't infer the