diff options
| author | Claudiu Popa <pcmanticore@gmail.com> | 2020-03-06 13:21:12 +0100 |
|---|---|---|
| committer | Claudiu Popa <pcmanticore@gmail.com> | 2020-03-06 13:22:41 +0100 |
| commit | 7120d894635662d49b05c0cc5d664b5a25544605 (patch) | |
| tree | 1176b2a0febe1a796d2254013456d24442166327 | |
| parent | 17a5ee681bcf4aacffcc4ec5afbc3436cfdc4537 (diff) | |
| download | astroid-git-7120d894635662d49b05c0cc5d664b5a25544605.tar.gz | |
Raise ``AttributeInferenceError`` when ``getattr()`` receives an empty name
If `Module.getattr` received an empty string (as a result of inference for example),
`astroid` would have returned the same Module again, which leads to false positives
in pylint, since the expected output was of a different type.
Rather than allowing empty names to pass through `getattr()`, we simply raise
an error earlier.
Close PyCQA/pylint#2991
| -rw-r--r-- | ChangeLog | 4 | ||||
| -rw-r--r-- | astroid/scoped_nodes.py | 14 | ||||
| -rw-r--r-- | tests/unittest_inference.py | 14 |
3 files changed, 32 insertions, 0 deletions
@@ -10,6 +10,10 @@ Release Date: TBA Close PyCQA/pylint#3417 +* Raise ``AttributeInferenceError`` when ``getattr()`` receives an empty name + + Close PyCQA/pylint#2991 + * ``NodeNG.bool_value()`` gained an optional ``context`` parameter We need to pass an inference context downstream when inferring the boolean diff --git a/astroid/scoped_nodes.py b/astroid/scoped_nodes.py index 922f4c58..8070f17d 100644 --- a/astroid/scoped_nodes.py +++ b/astroid/scoped_nodes.py @@ -527,6 +527,11 @@ class Module(LocalsDictNodeNG): return "Module" def getattr(self, name, context=None, ignore_locals=False): + if not name: + raise exceptions.AttributeInferenceError( + target=self, attribute=name, context=context + ) + result = [] name_in_locals = name in self.locals @@ -1551,6 +1556,10 @@ class FunctionDef(mixins.MultiLineBlockMixin, node_classes.Statement, Lambda): """this method doesn't look in the instance_attrs dictionary since it's done by an Instance proxy at inference time. """ + if not name: + raise exceptions.AttributeInferenceError( + target=self, attribute=name, context=context + ) if name in self.instance_attrs: return self.instance_attrs[name] if name in self.special_attributes: @@ -2406,6 +2415,11 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG, node_classes.Statement :raises AttributeInferenceError: If the attribute cannot be inferred. """ + if not name: + raise exceptions.AttributeInferenceError( + target=self, attribute=name, context=context + ) + values = self.locals.get(name, []) if name in self.special_attributes and class_context and not values: result = [self.special_attributes.lookup(name)] diff --git a/tests/unittest_inference.py b/tests/unittest_inference.py index 49ff6cdc..7f86de4d 100644 --- a/tests/unittest_inference.py +++ b/tests/unittest_inference.py @@ -5729,5 +5729,19 @@ def test_inferring_properties_multiple_time_does_not_mutate_locals_multiple_time assert len(a_locals) == 2 +def test_getattr_fails_on_empty_values(): + code = """ + import collections + collections + """ + node = extract_node(code) + inferred = next(node.infer()) + with pytest.raises(exceptions.InferenceError): + next(inferred.igetattr("")) + + with pytest.raises(exceptions.AttributeInferenceError): + inferred.getattr("") + + if __name__ == "__main__": unittest.main() |
