We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
AnsibleParseError generate full traceback dumps which break lint output consumers.
It seems that exceptions like the one documented on https://github.com/mschuchard/linter-ansible-linting/issues/3 do make almost impossible to integrate it with other apps, like the atom-linter.

I do agree the traceback dumps are very useful for debugging, they are not what you would expect from a normal tool execution.

Maybe adding a parameter for disabling them would sort this issue?

<img width="448" alt="screenshot 2016-03-21 10 23 54" src="https://cloud.githubusercontent.com/assets/102495/13921342/4a7fe96a-ef6f-11e5-92fc-6262d5c76944.png">


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lib/ansiblelint/utils.py`
Content:
```
1 # Copyright (c) 2013-2014 Will Thames <will@thames.id.au>
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a copy
4 # of this software and associated documentation files (the "Software"), to deal
5 # in the Software without restriction, including without limitation the rights
6 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 # copies of the Software, and to permit persons to whom the Software is
8 # furnished to do so, subject to the following conditions:
9 #
10 # The above copyright notice and this permission notice shall be included in
11 # all copies or substantial portions of the Software.
12 #
13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 # THE SOFTWARE.
20 
21 import glob
22 import imp
23 import os
24 
25 import ansible.constants as C
26 from ansible.module_utils.splitter import split_args
27 
28 import yaml
29 from yaml.composer import Composer
30 from yaml.constructor import Constructor
31 
32 try:
33     from ansible.utils import parse_yaml_from_file
34     from ansible.utils import path_dwim
35     from ansible.utils.template import template
36 except ImportError:
37     from ansible.parsing.dataloader import DataLoader
38     from ansible.template import Templar
39 
40     def parse_yaml_from_file(filepath):
41         dl = DataLoader()
42         return dl.load_from_file(filepath)
43 
44     def path_dwim(basedir, given):
45         dl = DataLoader()
46         dl.set_basedir(basedir)
47         return dl.path_dwim(given)
48 
49     def template(basedir, varname, templatevars, **kwargs):
50         dl = DataLoader()
51         dl.set_basedir(basedir)
52         templar = Templar(dl, variables=templatevars)
53         return templar.template(varname, **kwargs)
54 
55 LINE_NUMBER_KEY = '__line__'
56 
57 VALID_KEYS = [
58     'name', 'meta', 'action', 'when', 'async', 'poll', 'notify',
59     'first_available_file', 'include', 'tags', 'register', 'ignore_errors',
60     'delegate_to', 'local_action', 'transport', 'remote_user', 'sudo', 'sudo_user',
61     'sudo_pass', 'when', 'connection', 'environment', 'args',
62     'any_errors_fatal', 'changed_when', 'failed_when', 'always_run', 'delay', 'retries', 'until',
63     'su', 'su_user', 'su_pass', 'no_log', 'run_once',
64     'become', 'become_user', 'become_method',
65 ]
66 
67 
68 def load_plugins(directory):
69     result = []
70     fh = None
71 
72     for pluginfile in glob.glob(os.path.join(directory, '[A-Za-z]*.py')):
73 
74         pluginname = os.path.basename(pluginfile.replace('.py', ''))
75         try:
76             fh, filename, desc = imp.find_module(pluginname, [directory])
77             mod = imp.load_module(pluginname, fh, filename, desc)
78             obj = getattr(mod, pluginname)()
79             result.append(obj)
80         finally:
81             if fh:
82                 fh.close()
83     return result
84 
85 
86 def tokenize(line):
87     tokens = line.lstrip().split(" ")
88     if tokens[0] == '-':
89         tokens = tokens[1:]
90     if tokens[0] == 'action:' or tokens[0] == 'local_action:':
91         tokens = tokens[1:]
92     command = tokens[0].replace(":", "")
93 
94     args = list()
95     kwargs = dict()
96     for arg in tokens[1:]:
97         if "=" in arg:
98             kv = arg.split("=", 1)
99             kwargs[kv[0]] = kv[1]
100         else:
101             args.append(arg)
102     return (command, args, kwargs)
103 
104 
105 def _playbook_items(pb_data):
106     if isinstance(pb_data, dict):
107         return pb_data.items()
108     elif not pb_data:
109         return []
110     else:
111         return [item for play in pb_data for item in play.items()]
112 
113 
114 def find_children(playbook):
115     if not os.path.exists(playbook[0]):
116         return []
117     results = []
118     basedir = os.path.dirname(playbook[0])
119     pb_data = parse_yaml_from_file(playbook[0])
120     items = _playbook_items(pb_data)
121     for item in items:
122         for child in play_children(basedir, item, playbook[1]):
123             if "$" in child['path'] or "{{" in child['path']:
124                 continue
125             valid_tokens = list()
126             for token in split_args(child['path']):
127                 if '=' in token:
128                     break
129                 valid_tokens.append(token)
130             path = ' '.join(valid_tokens)
131             results.append({
132                 'path': path_dwim(basedir, path),
133                 'type': child['type']
134             })
135     return results
136 
137 
138 def play_children(basedir, item, parent_type):
139     delegate_map = {
140         'tasks': _taskshandlers_children,
141         'pre_tasks': _taskshandlers_children,
142         'post_tasks': _taskshandlers_children,
143         'include': _include_children,
144         'roles': _roles_children,
145         'dependencies': _roles_children,
146         'handlers': _taskshandlers_children,
147     }
148     (k, v) = item
149     if k in delegate_map:
150         if v:
151             v = template(basedir, v, dict(playbook_dir=os.path.abspath(basedir)), fail_on_undefined=False)
152             return delegate_map[k](basedir, k, v, parent_type)
153     return []
154 
155 
156 def _include_children(basedir, k, v, parent_type):
157     # handle include: filename.yml tags=blah
158     (command, args, kwargs) = tokenize("{0}: {1}".format(k, v))
159 
160     result = path_dwim(basedir, args[0])
161     if not os.path.exists(result) and not basedir.endswith('tasks'):
162         result = path_dwim(os.path.join(basedir, '..', 'tasks'), v)
163     return [{'path': result, 'type': parent_type}]
164 
165 
166 def _taskshandlers_children(basedir, k, v, parent_type):
167     return [{'path': path_dwim(basedir, th['include']),
168              'type': 'tasks'}
169             for th in v if 'include' in th]
170 
171 
172 def _roles_children(basedir, k, v, parent_type):
173     results = []
174     for role in v:
175         if isinstance(role, dict):
176             results.extend(_look_for_role_files(basedir, role['role']))
177         else:
178             results.extend(_look_for_role_files(basedir, role))
179     return results
180 
181 
182 def _rolepath(basedir, role):
183     role_path = None
184 
185     possible_paths = [
186         # if included from a playbook
187         path_dwim(basedir, os.path.join('roles', role)),
188         path_dwim(basedir, role),
189         # if included from roles/[role]/meta/main.yml
190         path_dwim(
191             basedir, os.path.join('..', '..', '..', 'roles', role)
192         ),
193         path_dwim(basedir, os.path.join('..', '..', role))
194     ]
195 
196     if C.DEFAULT_ROLES_PATH:
197         search_locations = C.DEFAULT_ROLES_PATH.split(os.pathsep)
198         for loc in search_locations:
199             loc = os.path.expanduser(loc)
200             possible_paths.append(path_dwim(loc, role))
201 
202     for path_option in possible_paths:
203         if os.path.isdir(path_option):
204             role_path = path_option
205             break
206 
207     return role_path
208 
209 
210 def _look_for_role_files(basedir, role):
211     role_path = _rolepath(basedir, role)
212     if not role_path:
213         return []
214 
215     results = []
216 
217     for th in ['tasks', 'handlers', 'meta']:
218         for ext in ('.yml', '.yaml'):
219             thpath = os.path.join(role_path, th, 'main' + ext)
220             if os.path.exists(thpath):
221                 results.append({'path': thpath, 'type': th})
222                 break
223     return results
224 
225 
226 def rolename(filepath):
227     idx = filepath.find('roles/')
228     if idx < 0:
229         return ''
230     role = filepath[idx+6:]
231     role = role[:role.find('/')]
232     return role
233 
234 
235 def _kv_to_dict(v):
236     (command, args, kwargs) = tokenize(v)
237     return (dict(module=command, module_arguments=args, **kwargs))
238 
239 
240 def normalize_task(task):
241     '''Ensures tasks have an action key and strings are converted to python objects'''
242 
243     result = dict()
244     for (k, v) in task.items():
245         if k in VALID_KEYS or k.startswith('with_'):
246             if k == 'local_action' or k == 'action':
247                 if not isinstance(v, dict):
248                     v = _kv_to_dict(v)
249                 v['module_arguments'] = v.get('module_arguments', list())
250                 result['action'] = v
251             else:
252                 result[k] = v
253         else:
254             if isinstance(v, basestring):
255                 v = _kv_to_dict(k + ' ' + v)
256             elif not v:
257                 v = dict(module=k)
258             else:
259                 if isinstance(v, dict):
260                     v.update(dict(module=k))
261                 else:
262                     if k == '__line__':
263                         # Keep the line number stored
264                         result[k] = v
265                         continue
266 
267                     else:
268                         # Should not get here!
269                         raise RuntimeError("Was not expecting value %s of type %s for key %s\nTask: %s" % (str(v), type(v), k), str(task))  # noqa
270             v['module_arguments'] = v.get('module_arguments', list())
271             result['action'] = v
272     return result
273 
274 
275 def task_to_str(task):
276     name = task.get("name")
277     if name:
278         return name
279     action = task.get("action")
280     args = " ".join(["{0}={1}".format(k, v) for (k, v) in action.items()
281                     if k not in ["module", "module_arguments"]] +
282                     action.get("module_arguments"))
283     return "{0} {1}".format(action["module"], args)
284 
285 
286 def extract_from_list(blocks, candidates):
287     results = list()
288     for block in blocks:
289         for candidate in candidates:
290             if candidate in block:
291                 if isinstance(block[candidate], list):
292                     results.extend(block[candidate])
293                 elif block[candidate] is not None:
294                     raise RuntimeError(
295                             "Key '%s' defined, but bad value: '%s'" % (candidate, str(block[candidate])))
296     return results
297 
298 
299 def get_action_tasks(yaml, file):
300     tasks = list()
301     if file['type'] in ['tasks', 'handlers']:
302         tasks = yaml
303     else:
304         tasks.extend(extract_from_list(yaml, ['tasks', 'handlers', 'pre_tasks', 'post_tasks']))
305 
306     # Add sub-elements of block/rescue/always to tasks list
307     tasks.extend(extract_from_list(tasks, ['block', 'rescue', 'always']))
308     # Remove block/rescue/always elements from tasks list
309     tasks[:] = [task for task in tasks if all(k not in task for k in ('block', 'rescue', 'always'))]
310 
311     return [normalize_task(task) for task in tasks
312             if 'include' not in task.keys()]
313 
314 
315 def parse_yaml_linenumbers(data):
316     """Parses yaml as ansible.utils.parse_yaml but with linenumbers.
317 
318     The line numbers are stored in each node's LINE_NUMBER_KEY key.
319     """
320     loader = yaml.Loader(data)
321 
322     def compose_node(parent, index):
323         # the line number where the previous token has ended (plus empty lines)
324         line = loader.line
325         node = Composer.compose_node(loader, parent, index)
326         node.__line__ = line + 1
327         return node
328 
329     def construct_mapping(node, deep=False):
330         mapping = Constructor.construct_mapping(loader, node, deep=deep)
331         mapping[LINE_NUMBER_KEY] = node.__line__
332         return mapping
333 
334     loader.compose_node = compose_node
335     loader.construct_mapping = construct_mapping
336     data = loader.get_single_data()
337     return data
338
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lib/ansiblelint/utils.py b/lib/ansiblelint/utils.py
--- a/lib/ansiblelint/utils.py
+++ b/lib/ansiblelint/utils.py
@@ -23,6 +23,7 @@
 import os
 
 import ansible.constants as C
+from ansible.errors import AnsibleError
 from ansible.module_utils.splitter import split_args
 
 import yaml
@@ -116,7 +117,10 @@
         return []
     results = []
     basedir = os.path.dirname(playbook[0])
-    pb_data = parse_yaml_from_file(playbook[0])
+    try:
+        pb_data = parse_yaml_from_file(playbook[0])
+    except AnsibleError, e:
+        raise SystemExit(str(e))
     items = _playbook_items(pb_data)
     for item in items:
         for child in play_children(basedir, item, playbook[1]):
@@ -173,7 +177,10 @@
     results = []
     for role in v:
         if isinstance(role, dict):
-            results.extend(_look_for_role_files(basedir, role['role']))
+            if 'role' in role:
+                results.extend(_look_for_role_files(basedir, role['role']))
+            else:
+                raise SystemExit('role dict {0} does not contain a "role" key'.format(role))
         else:
             results.extend(_look_for_role_files(basedir, role))
     return results

{"golden_diff": "diff --git a/lib/ansiblelint/utils.py b/lib/ansiblelint/utils.py\n--- a/lib/ansiblelint/utils.py\n+++ b/lib/ansiblelint/utils.py\n@@ -23,6 +23,7 @@\n import os\n \n import ansible.constants as C\n+from ansible.errors import AnsibleError\n from ansible.module_utils.splitter import split_args\n \n import yaml\n@@ -116,7 +117,10 @@\n         return []\n     results = []\n     basedir = os.path.dirname(playbook[0])\n-    pb_data = parse_yaml_from_file(playbook[0])\n+    try:\n+        pb_data = parse_yaml_from_file(playbook[0])\n+    except AnsibleError, e:\n+        raise SystemExit(str(e))\n     items = _playbook_items(pb_data)\n     for item in items:\n         for child in play_children(basedir, item, playbook[1]):\n@@ -173,7 +177,10 @@\n     results = []\n     for role in v:\n         if isinstance(role, dict):\n-            results.extend(_look_for_role_files(basedir, role['role']))\n+            if 'role' in role:\n+                results.extend(_look_for_role_files(basedir, role['role']))\n+            else:\n+                raise SystemExit('role dict {0} does not contain a \"role\" key'.format(role))\n         else:\n             results.extend(_look_for_role_files(basedir, role))\n     return results\n", "issue": "AnsibleParseError generate full traceback dumps which break lint output consumers.\nIt seems that exceptions like the one documented on https://github.com/mschuchard/linter-ansible-linting/issues/3 do make almost impossible to integrate it with other apps, like the atom-linter.\n\nI do agree the traceback dumps are very useful for debugging, they are not what you would expect from a normal tool execution.\n\nMaybe adding a parameter for disabling them would sort this issue?\n\n<img width=\"448\" alt=\"screenshot 2016-03-21 10 23 54\" src=\"https://cloud.githubusercontent.com/assets/102495/13921342/4a7fe96a-ef6f-11e5-92fc-6262d5c76944.png\">\n\n", "before_files": [{"content": "# Copyright (c) 2013-2014 Will Thames <will@thames.id.au>\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\nimport glob\nimport imp\nimport os\n\nimport ansible.constants as C\nfrom ansible.module_utils.splitter import split_args\n\nimport yaml\nfrom yaml.composer import Composer\nfrom yaml.constructor import Constructor\n\ntry:\n    from ansible.utils import parse_yaml_from_file\n    from ansible.utils import path_dwim\n    from ansible.utils.template import template\nexcept ImportError:\n    from ansible.parsing.dataloader import DataLoader\n    from ansible.template import Templar\n\n    def parse_yaml_from_file(filepath):\n        dl = DataLoader()\n        return dl.load_from_file(filepath)\n\n    def path_dwim(basedir, given):\n        dl = DataLoader()\n        dl.set_basedir(basedir)\n        return dl.path_dwim(given)\n\n    def template(basedir, varname, templatevars, **kwargs):\n        dl = DataLoader()\n        dl.set_basedir(basedir)\n        templar = Templar(dl, variables=templatevars)\n        return templar.template(varname, **kwargs)\n\nLINE_NUMBER_KEY = '__line__'\n\nVALID_KEYS = [\n    'name', 'meta', 'action', 'when', 'async', 'poll', 'notify',\n    'first_available_file', 'include', 'tags', 'register', 'ignore_errors',\n    'delegate_to', 'local_action', 'transport', 'remote_user', 'sudo', 'sudo_user',\n    'sudo_pass', 'when', 'connection', 'environment', 'args',\n    'any_errors_fatal', 'changed_when', 'failed_when', 'always_run', 'delay', 'retries', 'until',\n    'su', 'su_user', 'su_pass', 'no_log', 'run_once',\n    'become', 'become_user', 'become_method',\n]\n\n\ndef load_plugins(directory):\n    result = []\n    fh = None\n\n    for pluginfile in glob.glob(os.path.join(directory, '[A-Za-z]*.py')):\n\n        pluginname = os.path.basename(pluginfile.replace('.py', ''))\n        try:\n            fh, filename, desc = imp.find_module(pluginname, [directory])\n            mod = imp.load_module(pluginname, fh, filename, desc)\n            obj = getattr(mod, pluginname)()\n            result.append(obj)\n        finally:\n            if fh:\n                fh.close()\n    return result\n\n\ndef tokenize(line):\n    tokens = line.lstrip().split(\" \")\n    if tokens[0] == '-':\n        tokens = tokens[1:]\n    if tokens[0] == 'action:' or tokens[0] == 'local_action:':\n        tokens = tokens[1:]\n    command = tokens[0].replace(\":\", \"\")\n\n    args = list()\n    kwargs = dict()\n    for arg in tokens[1:]:\n        if \"=\" in arg:\n            kv = arg.split(\"=\", 1)\n            kwargs[kv[0]] = kv[1]\n        else:\n            args.append(arg)\n    return (command, args, kwargs)\n\n\ndef _playbook_items(pb_data):\n    if isinstance(pb_data, dict):\n        return pb_data.items()\n    elif not pb_data:\n        return []\n    else:\n        return [item for play in pb_data for item in play.items()]\n\n\ndef find_children(playbook):\n    if not os.path.exists(playbook[0]):\n        return []\n    results = []\n    basedir = os.path.dirname(playbook[0])\n    pb_data = parse_yaml_from_file(playbook[0])\n    items = _playbook_items(pb_data)\n    for item in items:\n        for child in play_children(basedir, item, playbook[1]):\n            if \"$\" in child['path'] or \"{{\" in child['path']:\n                continue\n            valid_tokens = list()\n            for token in split_args(child['path']):\n                if '=' in token:\n                    break\n                valid_tokens.append(token)\n            path = ' '.join(valid_tokens)\n            results.append({\n                'path': path_dwim(basedir, path),\n                'type': child['type']\n            })\n    return results\n\n\ndef play_children(basedir, item, parent_type):\n    delegate_map = {\n        'tasks': _taskshandlers_children,\n        'pre_tasks': _taskshandlers_children,\n        'post_tasks': _taskshandlers_children,\n        'include': _include_children,\n        'roles': _roles_children,\n        'dependencies': _roles_children,\n        'handlers': _taskshandlers_children,\n    }\n    (k, v) = item\n    if k in delegate_map:\n        if v:\n            v = template(basedir, v, dict(playbook_dir=os.path.abspath(basedir)), fail_on_undefined=False)\n            return delegate_map[k](basedir, k, v, parent_type)\n    return []\n\n\ndef _include_children(basedir, k, v, parent_type):\n    # handle include: filename.yml tags=blah\n    (command, args, kwargs) = tokenize(\"{0}: {1}\".format(k, v))\n\n    result = path_dwim(basedir, args[0])\n    if not os.path.exists(result) and not basedir.endswith('tasks'):\n        result = path_dwim(os.path.join(basedir, '..', 'tasks'), v)\n    return [{'path': result, 'type': parent_type}]\n\n\ndef _taskshandlers_children(basedir, k, v, parent_type):\n    return [{'path': path_dwim(basedir, th['include']),\n             'type': 'tasks'}\n            for th in v if 'include' in th]\n\n\ndef _roles_children(basedir, k, v, parent_type):\n    results = []\n    for role in v:\n        if isinstance(role, dict):\n            results.extend(_look_for_role_files(basedir, role['role']))\n        else:\n            results.extend(_look_for_role_files(basedir, role))\n    return results\n\n\ndef _rolepath(basedir, role):\n    role_path = None\n\n    possible_paths = [\n        # if included from a playbook\n        path_dwim(basedir, os.path.join('roles', role)),\n        path_dwim(basedir, role),\n        # if included from roles/[role]/meta/main.yml\n        path_dwim(\n            basedir, os.path.join('..', '..', '..', 'roles', role)\n        ),\n        path_dwim(basedir, os.path.join('..', '..', role))\n    ]\n\n    if C.DEFAULT_ROLES_PATH:\n        search_locations = C.DEFAULT_ROLES_PATH.split(os.pathsep)\n        for loc in search_locations:\n            loc = os.path.expanduser(loc)\n            possible_paths.append(path_dwim(loc, role))\n\n    for path_option in possible_paths:\n        if os.path.isdir(path_option):\n            role_path = path_option\n            break\n\n    return role_path\n\n\ndef _look_for_role_files(basedir, role):\n    role_path = _rolepath(basedir, role)\n    if not role_path:\n        return []\n\n    results = []\n\n    for th in ['tasks', 'handlers', 'meta']:\n        for ext in ('.yml', '.yaml'):\n            thpath = os.path.join(role_path, th, 'main' + ext)\n            if os.path.exists(thpath):\n                results.append({'path': thpath, 'type': th})\n                break\n    return results\n\n\ndef rolename(filepath):\n    idx = filepath.find('roles/')\n    if idx < 0:\n        return ''\n    role = filepath[idx+6:]\n    role = role[:role.find('/')]\n    return role\n\n\ndef _kv_to_dict(v):\n    (command, args, kwargs) = tokenize(v)\n    return (dict(module=command, module_arguments=args, **kwargs))\n\n\ndef normalize_task(task):\n    '''Ensures tasks have an action key and strings are converted to python objects'''\n\n    result = dict()\n    for (k, v) in task.items():\n        if k in VALID_KEYS or k.startswith('with_'):\n            if k == 'local_action' or k == 'action':\n                if not isinstance(v, dict):\n                    v = _kv_to_dict(v)\n                v['module_arguments'] = v.get('module_arguments', list())\n                result['action'] = v\n            else:\n                result[k] = v\n        else:\n            if isinstance(v, basestring):\n                v = _kv_to_dict(k + ' ' + v)\n            elif not v:\n                v = dict(module=k)\n            else:\n                if isinstance(v, dict):\n                    v.update(dict(module=k))\n                else:\n                    if k == '__line__':\n                        # Keep the line number stored\n                        result[k] = v\n                        continue\n\n                    else:\n                        # Should not get here!\n                        raise RuntimeError(\"Was not expecting value %s of type %s for key %s\\nTask: %s\" % (str(v), type(v), k), str(task))  # noqa\n            v['module_arguments'] = v.get('module_arguments', list())\n            result['action'] = v\n    return result\n\n\ndef task_to_str(task):\n    name = task.get(\"name\")\n    if name:\n        return name\n    action = task.get(\"action\")\n    args = \" \".join([\"{0}={1}\".format(k, v) for (k, v) in action.items()\n                    if k not in [\"module\", \"module_arguments\"]] +\n                    action.get(\"module_arguments\"))\n    return \"{0} {1}\".format(action[\"module\"], args)\n\n\ndef extract_from_list(blocks, candidates):\n    results = list()\n    for block in blocks:\n        for candidate in candidates:\n            if candidate in block:\n                if isinstance(block[candidate], list):\n                    results.extend(block[candidate])\n                elif block[candidate] is not None:\n                    raise RuntimeError(\n                            \"Key '%s' defined, but bad value: '%s'\" % (candidate, str(block[candidate])))\n    return results\n\n\ndef get_action_tasks(yaml, file):\n    tasks = list()\n    if file['type'] in ['tasks', 'handlers']:\n        tasks = yaml\n    else:\n        tasks.extend(extract_from_list(yaml, ['tasks', 'handlers', 'pre_tasks', 'post_tasks']))\n\n    # Add sub-elements of block/rescue/always to tasks list\n    tasks.extend(extract_from_list(tasks, ['block', 'rescue', 'always']))\n    # Remove block/rescue/always elements from tasks list\n    tasks[:] = [task for task in tasks if all(k not in task for k in ('block', 'rescue', 'always'))]\n\n    return [normalize_task(task) for task in tasks\n            if 'include' not in task.keys()]\n\n\ndef parse_yaml_linenumbers(data):\n    \"\"\"Parses yaml as ansible.utils.parse_yaml but with linenumbers.\n\n    The line numbers are stored in each node's LINE_NUMBER_KEY key.\n    \"\"\"\n    loader = yaml.Loader(data)\n\n    def compose_node(parent, index):\n        # the line number where the previous token has ended (plus empty lines)\n        line = loader.line\n        node = Composer.compose_node(loader, parent, index)\n        node.__line__ = line + 1\n        return node\n\n    def construct_mapping(node, deep=False):\n        mapping = Constructor.construct_mapping(loader, node, deep=deep)\n        mapping[LINE_NUMBER_KEY] = node.__line__\n        return mapping\n\n    loader.compose_node = compose_node\n    loader.construct_mapping = construct_mapping\n    data = loader.get_single_data()\n    return data\n", "path": "lib/ansiblelint/utils.py"}], "after_files": [{"content": "# Copyright (c) 2013-2014 Will Thames <will@thames.id.au>\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\nimport glob\nimport imp\nimport os\n\nimport ansible.constants as C\nfrom ansible.errors import AnsibleError\nfrom ansible.module_utils.splitter import split_args\n\nimport yaml\nfrom yaml.composer import Composer\nfrom yaml.constructor import Constructor\n\ntry:\n    from ansible.utils import parse_yaml_from_file\n    from ansible.utils import path_dwim\n    from ansible.utils.template import template\nexcept ImportError:\n    from ansible.parsing.dataloader import DataLoader\n    from ansible.template import Templar\n\n    def parse_yaml_from_file(filepath):\n        dl = DataLoader()\n        return dl.load_from_file(filepath)\n\n    def path_dwim(basedir, given):\n        dl = DataLoader()\n        dl.set_basedir(basedir)\n        return dl.path_dwim(given)\n\n    def template(basedir, varname, templatevars, **kwargs):\n        dl = DataLoader()\n        dl.set_basedir(basedir)\n        templar = Templar(dl, variables=templatevars)\n        return templar.template(varname, **kwargs)\n\nLINE_NUMBER_KEY = '__line__'\n\nVALID_KEYS = [\n    'name', 'meta', 'action', 'when', 'async', 'poll', 'notify',\n    'first_available_file', 'include', 'tags', 'register', 'ignore_errors',\n    'delegate_to', 'local_action', 'transport', 'remote_user', 'sudo', 'sudo_user',\n    'sudo_pass', 'when', 'connection', 'environment', 'args',\n    'any_errors_fatal', 'changed_when', 'failed_when', 'always_run', 'delay', 'retries', 'until',\n    'su', 'su_user', 'su_pass', 'no_log', 'run_once',\n    'become', 'become_user', 'become_method',\n]\n\n\ndef load_plugins(directory):\n    result = []\n    fh = None\n\n    for pluginfile in glob.glob(os.path.join(directory, '[A-Za-z]*.py')):\n\n        pluginname = os.path.basename(pluginfile.replace('.py', ''))\n        try:\n            fh, filename, desc = imp.find_module(pluginname, [directory])\n            mod = imp.load_module(pluginname, fh, filename, desc)\n            obj = getattr(mod, pluginname)()\n            result.append(obj)\n        finally:\n            if fh:\n                fh.close()\n    return result\n\n\ndef tokenize(line):\n    tokens = line.lstrip().split(\" \")\n    if tokens[0] == '-':\n        tokens = tokens[1:]\n    if tokens[0] == 'action:' or tokens[0] == 'local_action:':\n        tokens = tokens[1:]\n    command = tokens[0].replace(\":\", \"\")\n\n    args = list()\n    kwargs = dict()\n    for arg in tokens[1:]:\n        if \"=\" in arg:\n            kv = arg.split(\"=\", 1)\n            kwargs[kv[0]] = kv[1]\n        else:\n            args.append(arg)\n    return (command, args, kwargs)\n\n\ndef _playbook_items(pb_data):\n    if isinstance(pb_data, dict):\n        return pb_data.items()\n    elif not pb_data:\n        return []\n    else:\n        return [item for play in pb_data for item in play.items()]\n\n\ndef find_children(playbook):\n    if not os.path.exists(playbook[0]):\n        return []\n    results = []\n    basedir = os.path.dirname(playbook[0])\n    try:\n        pb_data = parse_yaml_from_file(playbook[0])\n    except AnsibleError, e:\n        raise SystemExit(str(e))\n    items = _playbook_items(pb_data)\n    for item in items:\n        for child in play_children(basedir, item, playbook[1]):\n            if \"$\" in child['path'] or \"{{\" in child['path']:\n                continue\n            valid_tokens = list()\n            for token in split_args(child['path']):\n                if '=' in token:\n                    break\n                valid_tokens.append(token)\n            path = ' '.join(valid_tokens)\n            results.append({\n                'path': path_dwim(basedir, path),\n                'type': child['type']\n            })\n    return results\n\n\ndef play_children(basedir, item, parent_type):\n    delegate_map = {\n        'tasks': _taskshandlers_children,\n        'pre_tasks': _taskshandlers_children,\n        'post_tasks': _taskshandlers_children,\n        'include': _include_children,\n        'roles': _roles_children,\n        'dependencies': _roles_children,\n        'handlers': _taskshandlers_children,\n    }\n    (k, v) = item\n    if k in delegate_map:\n        if v:\n            v = template(basedir, v, dict(playbook_dir=os.path.abspath(basedir)), fail_on_undefined=False)\n            return delegate_map[k](basedir, k, v, parent_type)\n    return []\n\n\ndef _include_children(basedir, k, v, parent_type):\n    # handle include: filename.yml tags=blah\n    (command, args, kwargs) = tokenize(\"{0}: {1}\".format(k, v))\n\n    result = path_dwim(basedir, args[0])\n    if not os.path.exists(result) and not basedir.endswith('tasks'):\n        result = path_dwim(os.path.join(basedir, '..', 'tasks'), v)\n    return [{'path': result, 'type': parent_type}]\n\n\ndef _taskshandlers_children(basedir, k, v, parent_type):\n    return [{'path': path_dwim(basedir, th['include']),\n             'type': 'tasks'}\n            for th in v if 'include' in th]\n\n\ndef _roles_children(basedir, k, v, parent_type):\n    results = []\n    for role in v:\n        if isinstance(role, dict):\n            if 'role' in role:\n                results.extend(_look_for_role_files(basedir, role['role']))\n            else:\n                raise SystemExit('role dict {0} does not contain a \"role\" key'.format(role))\n        else:\n            results.extend(_look_for_role_files(basedir, role))\n    return results\n\n\ndef _rolepath(basedir, role):\n    role_path = None\n\n    possible_paths = [\n        # if included from a playbook\n        path_dwim(basedir, os.path.join('roles', role)),\n        path_dwim(basedir, role),\n        # if included from roles/[role]/meta/main.yml\n        path_dwim(\n            basedir, os.path.join('..', '..', '..', 'roles', role)\n        ),\n        path_dwim(basedir, os.path.join('..', '..', role))\n    ]\n\n    if C.DEFAULT_ROLES_PATH:\n        search_locations = C.DEFAULT_ROLES_PATH.split(os.pathsep)\n        for loc in search_locations:\n            loc = os.path.expanduser(loc)\n            possible_paths.append(path_dwim(loc, role))\n\n    for path_option in possible_paths:\n        if os.path.isdir(path_option):\n            role_path = path_option\n            break\n\n    return role_path\n\n\ndef _look_for_role_files(basedir, role):\n    role_path = _rolepath(basedir, role)\n    if not role_path:\n        return []\n\n    results = []\n\n    for th in ['tasks', 'handlers', 'meta']:\n        for ext in ('.yml', '.yaml'):\n            thpath = os.path.join(role_path, th, 'main' + ext)\n            if os.path.exists(thpath):\n                results.append({'path': thpath, 'type': th})\n                break\n    return results\n\n\ndef rolename(filepath):\n    idx = filepath.find('roles/')\n    if idx < 0:\n        return ''\n    role = filepath[idx+6:]\n    role = role[:role.find('/')]\n    return role\n\n\ndef _kv_to_dict(v):\n    (command, args, kwargs) = tokenize(v)\n    return (dict(module=command, module_arguments=args, **kwargs))\n\n\ndef normalize_task(task):\n    '''Ensures tasks have an action key and strings are converted to python objects'''\n\n    result = dict()\n    for (k, v) in task.items():\n        if k in VALID_KEYS or k.startswith('with_'):\n            if k == 'local_action' or k == 'action':\n                if not isinstance(v, dict):\n                    v = _kv_to_dict(v)\n                v['module_arguments'] = v.get('module_arguments', list())\n                result['action'] = v\n            else:\n                result[k] = v\n        else:\n            if isinstance(v, basestring):\n                v = _kv_to_dict(k + ' ' + v)\n            elif not v:\n                v = dict(module=k)\n            else:\n                if isinstance(v, dict):\n                    v.update(dict(module=k))\n                else:\n                    if k == '__line__':\n                        # Keep the line number stored\n                        result[k] = v\n                        continue\n\n                    else:\n                        # Should not get here!\n                        raise RuntimeError(\"Was not expecting value %s of type %s for key %s\\nTask: %s\" % (str(v), type(v), k), str(task))  # noqa\n            v['module_arguments'] = v.get('module_arguments', list())\n            result['action'] = v\n    return result\n\n\ndef task_to_str(task):\n    name = task.get(\"name\")\n    if name:\n        return name\n    action = task.get(\"action\")\n    args = \" \".join([\"{0}={1}\".format(k, v) for (k, v) in action.items()\n                    if k not in [\"module\", \"module_arguments\"]] +\n                    action.get(\"module_arguments\"))\n    return \"{0} {1}\".format(action[\"module\"], args)\n\n\ndef extract_from_list(blocks, candidates):\n    results = list()\n    for block in blocks:\n        for candidate in candidates:\n            if candidate in block:\n                if isinstance(block[candidate], list):\n                    results.extend(block[candidate])\n                elif block[candidate] is not None:\n                    raise RuntimeError(\n                            \"Key '%s' defined, but bad value: '%s'\" % (candidate, str(block[candidate])))\n    return results\n\n\ndef get_action_tasks(yaml, file):\n    tasks = list()\n    if file['type'] in ['tasks', 'handlers']:\n        tasks = yaml\n    else:\n        tasks.extend(extract_from_list(yaml, ['tasks', 'handlers', 'pre_tasks', 'post_tasks']))\n\n    # Add sub-elements of block/rescue/always to tasks list\n    tasks.extend(extract_from_list(tasks, ['block', 'rescue', 'always']))\n    # Remove block/rescue/always elements from tasks list\n    tasks[:] = [task for task in tasks if all(k not in task for k in ('block', 'rescue', 'always'))]\n\n    return [normalize_task(task) for task in tasks\n            if 'include' not in task.keys()]\n\n\ndef parse_yaml_linenumbers(data):\n    \"\"\"Parses yaml as ansible.utils.parse_yaml but with linenumbers.\n\n    The line numbers are stored in each node's LINE_NUMBER_KEY key.\n    \"\"\"\n    loader = yaml.Loader(data)\n\n    def compose_node(parent, index):\n        # the line number where the previous token has ended (plus empty lines)\n        line = loader.line\n        node = Composer.compose_node(loader, parent, index)\n        node.__line__ = line + 1\n        return node\n\n    def construct_mapping(node, deep=False):\n        mapping = Constructor.construct_mapping(loader, node, deep=deep)\n        mapping[LINE_NUMBER_KEY] = node.__line__\n        return mapping\n\n    loader.compose_node = compose_node\n    loader.construct_mapping = construct_mapping\n    data = loader.get_single_data()\n    return data\n", "path": "lib/ansiblelint/utils.py"}]}