diff options
author | Claudiu Popa <pcmanticore@gmail.com> | 2015-10-08 02:07:59 +0300 |
---|---|---|
committer | Claudiu Popa <pcmanticore@gmail.com> | 2015-10-08 02:07:59 +0300 |
commit | 57fe8b8721a1463a44d7542b2b002603b1b66ab2 (patch) | |
tree | 76c2318a578a25f52f7095d967e1b67fe6c5fc1a | |
parent | b6455a5aeb20e868c24094d6f6b9962bb52f8127 (diff) | |
download | astroid-57fe8b8721a1463a44d7542b2b002603b1b66ab2.tar.gz |
Support PEP 448 unpackings in dict calls.
-rw-r--r-- | astroid/brain/builtin_inference.py | 32 | ||||
-rw-r--r-- | astroid/tests/unittest_inference.py | 26 |
2 files changed, 47 insertions, 11 deletions
diff --git a/astroid/brain/builtin_inference.py b/astroid/brain/builtin_inference.py index 022a009..c6245be 100644 --- a/astroid/brain/builtin_inference.py +++ b/astroid/brain/builtin_inference.py @@ -7,6 +7,7 @@ from textwrap import dedent import six from astroid import (MANAGER, UseInferenceDefault, NotFoundError, inference_tip, InferenceError, UnresolvableName) +from astroid import arguments from astroid.builder import AstroidBuilder from astroid import helpers from astroid import nodes @@ -229,25 +230,34 @@ def infer_dict(node, context=None): If a case can't be inferred, we'll fallback to default inference. """ - if not node.args and not node.keywords: + call = arguments.CallSite.from_call(node) + if call.has_invalid_arguments() or call.has_invalid_keywords(): + raise UseInferenceDefault + + args = call.positional_arguments + kwargs = list(call.keyword_arguments.items()) + + if not args and not kwargs: # dict() return nodes.Dict() - elif node.keywords and not node.args: + elif kwargs and not args: # dict(a=1, b=2, c=4) - items = [(nodes.Const(arg.arg), arg.value) for arg in node.keywords] - elif len(node.args) == 1 and node.keywords: + items = [(nodes.Const(key), value) for key, value in kwargs] + elif len(args) == 1 and kwargs: # dict(some_iterable, b=2, c=4) - elts = _get_elts(node.args[0], context) - keys = [(nodes.Const(arg.arg), arg.value) for arg in node.keywords] + elts = _get_elts(args[0], context) + keys = [(nodes.Const(key), value) for key, value in kwargs] items = elts + keys - elif len(node.args) == 1: - items = _get_elts(node.args[0], context) + elif len(args) == 1: + items = _get_elts(args[0], context) else: raise UseInferenceDefault() - empty = nodes.Dict() - empty.items = items - return empty + value = nodes.Dict(col_offset=node.col_offset, + lineno=node.lineno, + parent=node.parent) + value.postinit(items) + return value def infer_super(node, context=None): diff --git a/astroid/tests/unittest_inference.py b/astroid/tests/unittest_inference.py index ed13fc2..9c80a92 100644 --- a/astroid/tests/unittest_inference.py +++ b/astroid/tests/unittest_inference.py @@ -1720,6 +1720,32 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): self.assertIsInstance(inferred, Instance) self.assertEqual(inferred.qname(), "{}.dict".format(BUILTINS)) + def test_dict_inference_kwargs(self): + ast_node = test_utils.extract_node('''dict(a=1, b=2, **{'c': 3})''') + self.assertInferDict(ast_node, {'a': 1, 'b': 2, 'c': 3}) + + @test_utils.require_version('3.5') + def test_dict_inference_for_multiple_starred(self): + pairs = [ + ('dict(a=1, **{"b": 2}, **{"c":3})', {'a':1, 'b':2, 'c':3}), + ('dict(a=1, **{"b": 2}, d=4, **{"c":3})', {'a':1, 'b':2, 'c':3, 'd':4}), + ('dict({"a":1}, b=2, **{"c":3})', {'a':1, 'b':2, 'c':3}), + ] + for code, expected_value in pairs: + node = test_utils.extract_node(code) + self.assertInferDict(node, expected_value) + + def test_dict_invalid_args(self): + invalid_values = [ + 'dict(*1)', + 'dict(**lala)', + 'dict(**[])', + ] + for invalid in invalid_values: + ast_node = test_utils.extract_node(invalid) + inferred = next(ast_node.infer()) + self.assertIsInstance(inferred, Instance) + self.assertEqual(inferred.qname(), "{}.dict".format(BUILTINS)) def test_str_methods(self): code = """ |