summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2015-10-08 02:07:59 +0300
committerClaudiu Popa <pcmanticore@gmail.com>2015-10-08 02:07:59 +0300
commit57fe8b8721a1463a44d7542b2b002603b1b66ab2 (patch)
tree76c2318a578a25f52f7095d967e1b67fe6c5fc1a
parentb6455a5aeb20e868c24094d6f6b9962bb52f8127 (diff)
downloadastroid-57fe8b8721a1463a44d7542b2b002603b1b66ab2.tar.gz
Support PEP 448 unpackings in dict calls.
-rw-r--r--astroid/brain/builtin_inference.py32
-rw-r--r--astroid/tests/unittest_inference.py26
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 = """