We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
If raw_env_vars contains a var whose value is not a string, molecule silently fails to execute Ansible
# Issue Type

- Bug report

# Molecule and Ansible details

```
ansible --version
2.2.0.0

molecule --version

1.14.1.dev37
```

Sha256 of commit is 8eed3f539f0b30b04d98f8ab418a2a5d55cce01f, molecule --version for source checkout seems to be stuck on 1.14

- Molecule installation method: source

# Desired Behaviour

There is no possible key value pair in the ``ansible: {raw_env_vars: {}}`` section that prevents Ansible from getting executed


# Actual Behaviour (Bug report only)

Except from molecule.yml:

```
  raw_env_vars:
    RETRY_FILES_ENABLED: 0
```

```
molecule --debug syntax; echo $?
--> Checking playbook's syntax...
DEBUG: COMMAND
/usr/bin/ansible-playbook tests/test.yml -vvvv --inventory-file=localhost, --syntax-check --limit=all --timeout=30 --diff
255
```

```
$ /usr/bin/ansible-playbook tests/test.yml -vvvv --inventory-file=localhost, --syntax-check --limit=all --timeout=30 --diff; echo $?
Using $ROLE_DIR/ansible.cfg as config file
Set default localhost to localhost
3 plays in tests/test.yml

playbook: tests/test.yml
0
```
The same happens with ``molecule converge``.

This is especially bad since that one is really hard to debug, because there is no error message at all.

I am not even sure if this is the fault of molecule, because [the doc to sh.pys `_env` arg only mentions it must be a dict, not that all values must be string types](https://amoffat.github.io/sh/sections/special_arguments.html?highlight=_env#env).

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `molecule/ansible_playbook.py`
Content:
```
1 #  Copyright (c) 2015-2016 Cisco Systems, Inc.
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
5 #  deal in the Software without restriction, including without limitation the
6 #  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 #  sell 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
18 #  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 #  DEALINGS IN THE SOFTWARE.
20 
21 import os
22 import sh
23 
24 from molecule import util
25 
26 
27 class AnsiblePlaybook(object):
28     def __init__(self,
29                  args,
30                  connection_params,
31                  raw_ansible_args=None,
32                  _env=None,
33                  _out=util.callback_info,
34                  _err=util.callback_error,
35                  debug=False):
36         """
37         Sets up requirements for ansible-playbook and returns None.
38 
39         :param args: A dict containing arguments to pass to ansible-playbook.
40         :param connection_params: A dict containing driver specific connection
41          params to pass to ansible-playbook.
42         :param _env: An optional environment to pass to underlying :func:`sh`
43          call.
44         :param _out: An optional function to process STDOUT for underlying
45          :func:`sh` call.
46         :param _err: An optional function to process STDERR for underlying
47          :func:`sh` call.
48         :param debug: An optional bool to toggle debug output.
49         :return: None
50         """
51         self._playbook = None
52         self._ansible = None
53         self._cli = {}
54         self._cli_pos = []
55         self._raw_ansible_args = raw_ansible_args
56         self._env = _env if _env else os.environ.copy()
57         self._debug = debug
58 
59         for k, v in args.iteritems():
60             self.parse_arg(k, v)
61 
62         for k, v in connection_params.items():
63             self.add_cli_arg(k, v)
64 
65         self.add_env_arg('PYTHONUNBUFFERED', '1')
66         self.add_env_arg('ANSIBLE_FORCE_COLOR', 'true')
67 
68         self.add_cli_arg('_out', _out)
69         self.add_cli_arg('_err', _err)
70 
71     @property
72     def env(self):
73         return self._env
74 
75     def bake(self):
76         """
77         Bake ansible-playbook command so it's ready to execute and returns
78         None.
79 
80         :return: None
81         """
82         self._ansible = sh.ansible_playbook.bake(
83             self._playbook, *self._cli_pos, _env=self._env, **self._cli)
84         if self._raw_ansible_args:
85             self._ansible = self._ansible.bake(self._raw_ansible_args)
86 
87     def parse_arg(self, name, value):
88         """
89         Adds argument to CLI or environment and returns None.
90 
91         :param name: A string containing the name of argument to be added.
92         :param value: The value of argument to be added.
93         :return: None
94         """
95 
96         if name == 'raw_env_vars':
97             for k, v in value.iteritems():
98                 self.add_env_arg(k, v)
99             return
100 
101         if name == 'host_key_checking':
102             self.add_env_arg('ANSIBLE_HOST_KEY_CHECKING', str(value).lower())
103             return
104 
105         if name == 'raw_ssh_args':
106             self.add_env_arg('ANSIBLE_SSH_ARGS', ' '.join(value))
107             return
108 
109         if name == 'config_file':
110             self.add_env_arg('ANSIBLE_CONFIG', value)
111             return
112 
113         if name == 'playbook':
114             self._playbook = value
115             return
116 
117         if name == 'host_vars' or name == 'group_vars':
118             return
119 
120         # verbose is weird, must be -vvvv not verbose=vvvv
121         if name == 'verbose' and value:
122             # for cases where someone passes in verbose: True
123             if value is True:
124                 value = 'vvvv'
125             self._cli_pos.append('-' + value)
126             return
127 
128         self.add_cli_arg(name, value)
129 
130     def add_cli_arg(self, name, value):
131         """
132         Adds argument to CLI passed to ansible-playbook and returns None.
133 
134         :param name: A string containing the name of argument to be added.
135         :param value: The value of argument to be added.
136         :return: None
137         """
138         if value:
139             self._cli[name] = value
140 
141     def remove_cli_arg(self, name):
142         """
143         Removes CLI argument and returns None.
144 
145         :param name: A string containing the name of argument to be removed.
146         :return: None
147         """
148         self._cli.pop(name, None)
149 
150     def add_env_arg(self, name, value):
151         """
152         Adds argument to environment passed to ansible-playbook and returns
153         None.
154 
155         :param name: A string containing the name of argument to be added.
156         :param value: The value of argument to be added.
157         :return: None
158         """
159         self._env[name] = value
160 
161     def remove_env_arg(self, name):
162         """
163         Removes environment argument and returns None.
164 
165         :param name: A string containing the name of argument to be removed.
166         :return: None
167         """
168         self._env.pop(name, None)
169 
170     def execute(self, hide_errors=False):
171         """
172         Executes ansible-playbook and returns command's stdout.
173 
174         :param hide_errors: An optional bool to toggle output of errors.
175         :return: The command's output, otherwise sys.exit on command failure.
176         """
177         if self._ansible is None:
178             self.bake()
179 
180         try:
181             return None, util.run_command(
182                 self._ansible, debug=self._debug).stdout
183         except sh.ErrorReturnCode as e:
184             if not hide_errors:
185                 util.print_error(str(e))
186 
187             return e.exit_code, None
188
```
--- 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/molecule/ansible_playbook.py b/molecule/ansible_playbook.py
--- a/molecule/ansible_playbook.py
+++ b/molecule/ansible_playbook.py
@@ -95,6 +95,8 @@
 
         if name == 'raw_env_vars':
             for k, v in value.iteritems():
+                if not isinstance(v, basestring):
+                    v = unicode(v)
                 self.add_env_arg(k, v)
             return

{"golden_diff": "diff --git a/molecule/ansible_playbook.py b/molecule/ansible_playbook.py\n--- a/molecule/ansible_playbook.py\n+++ b/molecule/ansible_playbook.py\n@@ -95,6 +95,8 @@\n \n         if name == 'raw_env_vars':\n             for k, v in value.iteritems():\n+                if not isinstance(v, basestring):\n+                    v = unicode(v)\n                 self.add_env_arg(k, v)\n             return\n", "issue": "If raw_env_vars contains a var whose value is not a string, molecule silently fails to execute Ansible\n# Issue Type\r\n\r\n- Bug report\r\n\r\n# Molecule and Ansible details\r\n\r\n```\r\nansible --version\r\n2.2.0.0\r\n\r\nmolecule --version\r\n\r\n1.14.1.dev37\r\n```\r\n\r\nSha256 of commit is 8eed3f539f0b30b04d98f8ab418a2a5d55cce01f, molecule --version for source checkout seems to be stuck on 1.14\r\n\r\n- Molecule installation method: source\r\n\r\n# Desired Behaviour\r\n\r\nThere is no possible key value pair in the ``ansible: {raw_env_vars: {}}`` section that prevents Ansible from getting executed\r\n\r\n\r\n# Actual Behaviour (Bug report only)\r\n\r\nExcept from molecule.yml:\r\n\r\n```\r\n  raw_env_vars:\r\n    RETRY_FILES_ENABLED: 0\r\n```\r\n\r\n```\r\nmolecule --debug syntax; echo $?\r\n--> Checking playbook's syntax...\r\nDEBUG: COMMAND\r\n/usr/bin/ansible-playbook tests/test.yml -vvvv --inventory-file=localhost, --syntax-check --limit=all --timeout=30 --diff\r\n255\r\n```\r\n\r\n```\r\n$ /usr/bin/ansible-playbook tests/test.yml -vvvv --inventory-file=localhost, --syntax-check --limit=all --timeout=30 --diff; echo $?\r\nUsing $ROLE_DIR/ansible.cfg as config file\r\nSet default localhost to localhost\r\n3 plays in tests/test.yml\r\n\r\nplaybook: tests/test.yml\r\n0\r\n```\r\nThe same happens with ``molecule converge``.\r\n\r\nThis is especially bad since that one is really hard to debug, because there is no error message at all.\r\n\r\nI am not even sure if this is the fault of molecule, because [the doc to sh.pys `_env` arg only mentions it must be a dict, not that all values must be string types](https://amoffat.github.io/sh/sections/special_arguments.html?highlight=_env#env).\n", "before_files": [{"content": "#  Copyright (c) 2015-2016 Cisco Systems, Inc.\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\n#  deal in the Software without restriction, including without limitation the\n#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n#  sell 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\n#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n#  DEALINGS IN THE SOFTWARE.\n\nimport os\nimport sh\n\nfrom molecule import util\n\n\nclass AnsiblePlaybook(object):\n    def __init__(self,\n                 args,\n                 connection_params,\n                 raw_ansible_args=None,\n                 _env=None,\n                 _out=util.callback_info,\n                 _err=util.callback_error,\n                 debug=False):\n        \"\"\"\n        Sets up requirements for ansible-playbook and returns None.\n\n        :param args: A dict containing arguments to pass to ansible-playbook.\n        :param connection_params: A dict containing driver specific connection\n         params to pass to ansible-playbook.\n        :param _env: An optional environment to pass to underlying :func:`sh`\n         call.\n        :param _out: An optional function to process STDOUT for underlying\n         :func:`sh` call.\n        :param _err: An optional function to process STDERR for underlying\n         :func:`sh` call.\n        :param debug: An optional bool to toggle debug output.\n        :return: None\n        \"\"\"\n        self._playbook = None\n        self._ansible = None\n        self._cli = {}\n        self._cli_pos = []\n        self._raw_ansible_args = raw_ansible_args\n        self._env = _env if _env else os.environ.copy()\n        self._debug = debug\n\n        for k, v in args.iteritems():\n            self.parse_arg(k, v)\n\n        for k, v in connection_params.items():\n            self.add_cli_arg(k, v)\n\n        self.add_env_arg('PYTHONUNBUFFERED', '1')\n        self.add_env_arg('ANSIBLE_FORCE_COLOR', 'true')\n\n        self.add_cli_arg('_out', _out)\n        self.add_cli_arg('_err', _err)\n\n    @property\n    def env(self):\n        return self._env\n\n    def bake(self):\n        \"\"\"\n        Bake ansible-playbook command so it's ready to execute and returns\n        None.\n\n        :return: None\n        \"\"\"\n        self._ansible = sh.ansible_playbook.bake(\n            self._playbook, *self._cli_pos, _env=self._env, **self._cli)\n        if self._raw_ansible_args:\n            self._ansible = self._ansible.bake(self._raw_ansible_args)\n\n    def parse_arg(self, name, value):\n        \"\"\"\n        Adds argument to CLI or environment and returns None.\n\n        :param name: A string containing the name of argument to be added.\n        :param value: The value of argument to be added.\n        :return: None\n        \"\"\"\n\n        if name == 'raw_env_vars':\n            for k, v in value.iteritems():\n                self.add_env_arg(k, v)\n            return\n\n        if name == 'host_key_checking':\n            self.add_env_arg('ANSIBLE_HOST_KEY_CHECKING', str(value).lower())\n            return\n\n        if name == 'raw_ssh_args':\n            self.add_env_arg('ANSIBLE_SSH_ARGS', ' '.join(value))\n            return\n\n        if name == 'config_file':\n            self.add_env_arg('ANSIBLE_CONFIG', value)\n            return\n\n        if name == 'playbook':\n            self._playbook = value\n            return\n\n        if name == 'host_vars' or name == 'group_vars':\n            return\n\n        # verbose is weird, must be -vvvv not verbose=vvvv\n        if name == 'verbose' and value:\n            # for cases where someone passes in verbose: True\n            if value is True:\n                value = 'vvvv'\n            self._cli_pos.append('-' + value)\n            return\n\n        self.add_cli_arg(name, value)\n\n    def add_cli_arg(self, name, value):\n        \"\"\"\n        Adds argument to CLI passed to ansible-playbook and returns None.\n\n        :param name: A string containing the name of argument to be added.\n        :param value: The value of argument to be added.\n        :return: None\n        \"\"\"\n        if value:\n            self._cli[name] = value\n\n    def remove_cli_arg(self, name):\n        \"\"\"\n        Removes CLI argument and returns None.\n\n        :param name: A string containing the name of argument to be removed.\n        :return: None\n        \"\"\"\n        self._cli.pop(name, None)\n\n    def add_env_arg(self, name, value):\n        \"\"\"\n        Adds argument to environment passed to ansible-playbook and returns\n        None.\n\n        :param name: A string containing the name of argument to be added.\n        :param value: The value of argument to be added.\n        :return: None\n        \"\"\"\n        self._env[name] = value\n\n    def remove_env_arg(self, name):\n        \"\"\"\n        Removes environment argument and returns None.\n\n        :param name: A string containing the name of argument to be removed.\n        :return: None\n        \"\"\"\n        self._env.pop(name, None)\n\n    def execute(self, hide_errors=False):\n        \"\"\"\n        Executes ansible-playbook and returns command's stdout.\n\n        :param hide_errors: An optional bool to toggle output of errors.\n        :return: The command's output, otherwise sys.exit on command failure.\n        \"\"\"\n        if self._ansible is None:\n            self.bake()\n\n        try:\n            return None, util.run_command(\n                self._ansible, debug=self._debug).stdout\n        except sh.ErrorReturnCode as e:\n            if not hide_errors:\n                util.print_error(str(e))\n\n            return e.exit_code, None\n", "path": "molecule/ansible_playbook.py"}], "after_files": [{"content": "#  Copyright (c) 2015-2016 Cisco Systems, Inc.\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\n#  deal in the Software without restriction, including without limitation the\n#  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n#  sell 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\n#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n#  DEALINGS IN THE SOFTWARE.\n\nimport os\nimport sh\n\nfrom molecule import util\n\n\nclass AnsiblePlaybook(object):\n    def __init__(self,\n                 args,\n                 connection_params,\n                 raw_ansible_args=None,\n                 _env=None,\n                 _out=util.callback_info,\n                 _err=util.callback_error,\n                 debug=False):\n        \"\"\"\n        Sets up requirements for ansible-playbook and returns None.\n\n        :param args: A dict containing arguments to pass to ansible-playbook.\n        :param connection_params: A dict containing driver specific connection\n         params to pass to ansible-playbook.\n        :param _env: An optional environment to pass to underlying :func:`sh`\n         call.\n        :param _out: An optional function to process STDOUT for underlying\n         :func:`sh` call.\n        :param _err: An optional function to process STDERR for underlying\n         :func:`sh` call.\n        :param debug: An optional bool to toggle debug output.\n        :return: None\n        \"\"\"\n        self._playbook = None\n        self._ansible = None\n        self._cli = {}\n        self._cli_pos = []\n        self._raw_ansible_args = raw_ansible_args\n        self._env = _env if _env else os.environ.copy()\n        self._debug = debug\n\n        for k, v in args.iteritems():\n            self.parse_arg(k, v)\n\n        for k, v in connection_params.items():\n            self.add_cli_arg(k, v)\n\n        self.add_env_arg('PYTHONUNBUFFERED', '1')\n        self.add_env_arg('ANSIBLE_FORCE_COLOR', 'true')\n\n        self.add_cli_arg('_out', _out)\n        self.add_cli_arg('_err', _err)\n\n    @property\n    def env(self):\n        return self._env\n\n    def bake(self):\n        \"\"\"\n        Bake ansible-playbook command so it's ready to execute and returns\n        None.\n\n        :return: None\n        \"\"\"\n        self._ansible = sh.ansible_playbook.bake(\n            self._playbook, *self._cli_pos, _env=self._env, **self._cli)\n        if self._raw_ansible_args:\n            self._ansible = self._ansible.bake(self._raw_ansible_args)\n\n    def parse_arg(self, name, value):\n        \"\"\"\n        Adds argument to CLI or environment and returns None.\n\n        :param name: A string containing the name of argument to be added.\n        :param value: The value of argument to be added.\n        :return: None\n        \"\"\"\n\n        if name == 'raw_env_vars':\n            for k, v in value.iteritems():\n                if not isinstance(v, basestring):\n                    v = unicode(v)\n                self.add_env_arg(k, v)\n            return\n\n        if name == 'host_key_checking':\n            self.add_env_arg('ANSIBLE_HOST_KEY_CHECKING', str(value).lower())\n            return\n\n        if name == 'raw_ssh_args':\n            self.add_env_arg('ANSIBLE_SSH_ARGS', ' '.join(value))\n            return\n\n        if name == 'config_file':\n            self.add_env_arg('ANSIBLE_CONFIG', value)\n            return\n\n        if name == 'playbook':\n            self._playbook = value\n            return\n\n        if name == 'host_vars' or name == 'group_vars':\n            return\n\n        # verbose is weird, must be -vvvv not verbose=vvvv\n        if name == 'verbose' and value:\n            # for cases where someone passes in verbose: True\n            if value is True:\n                value = 'vvvv'\n            self._cli_pos.append('-' + value)\n            return\n\n        self.add_cli_arg(name, value)\n\n    def add_cli_arg(self, name, value):\n        \"\"\"\n        Adds argument to CLI passed to ansible-playbook and returns None.\n\n        :param name: A string containing the name of argument to be added.\n        :param value: The value of argument to be added.\n        :return: None\n        \"\"\"\n        if value:\n            self._cli[name] = value\n\n    def remove_cli_arg(self, name):\n        \"\"\"\n        Removes CLI argument and returns None.\n\n        :param name: A string containing the name of argument to be removed.\n        :return: None\n        \"\"\"\n        self._cli.pop(name, None)\n\n    def add_env_arg(self, name, value):\n        \"\"\"\n        Adds argument to environment passed to ansible-playbook and returns\n        None.\n\n        :param name: A string containing the name of argument to be added.\n        :param value: The value of argument to be added.\n        :return: None\n        \"\"\"\n        self._env[name] = value\n\n    def remove_env_arg(self, name):\n        \"\"\"\n        Removes environment argument and returns None.\n\n        :param name: A string containing the name of argument to be removed.\n        :return: None\n        \"\"\"\n        self._env.pop(name, None)\n\n    def execute(self, hide_errors=False):\n        \"\"\"\n        Executes ansible-playbook and returns command's stdout.\n\n        :param hide_errors: An optional bool to toggle output of errors.\n        :return: The command's output, otherwise sys.exit on command failure.\n        \"\"\"\n        if self._ansible is None:\n            self.bake()\n\n        try:\n            return None, util.run_command(\n                self._ansible, debug=self._debug).stdout\n        except sh.ErrorReturnCode as e:\n            if not hide_errors:\n                util.print_error(str(e))\n\n            return e.exit_code, None\n", "path": "molecule/ansible_playbook.py"}]}