Repository: ansible/ansible

Issue:
'dict' lookup does not work explicitly, i.e. with lookup('dict', ...)
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
dict plugin

##### ANSIBLE VERSION
devel-9d6fd4ebcc10188274eca5971e9ac2ec0d806676
```
ansible 2.5.0
  config file = /mnt/delphi/kwohlfahrt/computer_setup/ansible.cfg
  configured module search path = ['/mnt/delphi/kwohlfahrt/computer_setup/library']
  ansible python module location = /home/kwohlfahrt/.pip/lib/python3.5/site-packages/ansible
  executable location = /home/kwohlfahrt/.pip/bin/ansible
  python version = 3.5.4 (default, Aug 12 2017, 14:08:14) [GCC 7.1.0]
```

##### CONFIGURATION
```
DEFAULT_HOST_LIST(/mnt/delphi/kjw53/computer_setup/ansible.cfg) = ['/mnt/delphi/kwohlfahrt/computer_setup/hosts
DEFAULT_MODULE_PATH(/mnt/delphi/kjw53/computer_setup/ansible.cfg) = ['/mnt/delphi/kwohlfahrt/computer_setup/library
```
##### OS / ENVIRONMENT
N/A

##### SUMMARY
When called with the `lookup` function, `'dict'` plugin errors.

##### STEPS TO REPRODUCE
```
ansible localhost -m debug -a msg="{{ lookup('dict', {'foo': 'bar', 'thing': 'other'}) }}"
```

##### EXPECTED RESULTS
Something like the example below, so it can work with the `loop` keyword.

```
localhost | SUCCESS => {
    "changed": false,
    "msg": [
        {
            "key": "foo",
            "value": "bar"
        }, {
            "key": "thing",
            "value": "other"
        }
    ]
}
```

##### ACTUAL RESULTS
Output is below. Some more debugging [here](https://gist.github.com/halberom/c78b8bb51714cdce8deff128b9af5bc9) shows the parameter is passed as a list containing the dict as its only element.

```
localhost | FAILED! => {
    "msg": "An unhandled exception occurred while running the lookup plugin 'dict'. Error was a <class 'ansible.errors.AnsibleError'>, original message: with_dict expects a dict, not <class 'list'> ([{'foo': 'bar'}])"
}
```



Discussion:

Resolving patch:
diff --git a/lib/ansible/plugins/lookup/dict.py b/lib/ansible/plugins/lookup/dict.py
--- a/lib/ansible/plugins/lookup/dict.py
+++ b/lib/ansible/plugins/lookup/dict.py
@@ -7,14 +7,14 @@
 DOCUMENTATION = """
     lookup: dict
     version_added: "1.5"
-    short_description: returns key/value pair items from a dictionary
+    short_description: returns key/value pair items from dictionaries
     description:
-        - Takes a dictionary as input and returns a list with each item in the list being a dictionary with 'key' and 'value' as
+        - Takes dictionaries as input and returns a list with each item in the list being a dictionary with 'key' and 'value' as
           keys to the previous dictionary's structure.
     options:
-        _raw:
+        _terms:
             description:
-                - A dictionary
+                - A list of dictionaries
             required: True
 """
 
@@ -37,7 +37,7 @@
   - name: Print phone records
     debug:
       msg: "User {{ item.key }} is {{ item.value.name }} ({{ item.value.telephone }})"
-    with_dict: "{{ users }}"
+    loop: "{{ lookup('dict', users) }}"
 """
 
 RETURN = """
@@ -56,8 +56,15 @@ class LookupModule(LookupBase):
 
     def run(self, terms, variables=None, **kwargs):
 
-        # Expect any type of Mapping, notably hostvars
-        if not isinstance(terms, collections.Mapping):
-            raise AnsibleError("with_dict expects a dict")
+        # FIXME: can remove once with_ special case is removed
+        if not isinstance(terms, list):
+            terms = [terms]
 
-        return self._flatten_hash_to_list(terms)
+        results = []
+        for term in terms:
+            # Expect any type of Mapping, notably hostvars
+            if not isinstance(term, collections.Mapping):
+                raise AnsibleError("with_dict expects a dict")
+
+            results.extend(self._flatten_hash_to_list(term))
+        return results


Test patch: