Repository: ansible/ansible

Issue:
Fix byte-compiled module loading failure for six compatible libraries
##### SUMMARY
When ansible.compat.six.__init__.py is only support to load six.py file. If an environment only has byte-compiled file(.pyc or .pyo) in PYTHONPATH, it will not work.

##### ISSUE TYPE
 - Bugfix Pull Request

##### COMPONENT NAME
- Ansible

##### ANSIBLE VERSION

- Ansible <= v2.3.x
```
ansible 2.3.3.0
  config file =
  configured module search path = Default w/o overrides
  python version = 2.7.14 (default, Nov  3 2017, 20:18:15) [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.38)]
(py2.7-develop)
```

##### ADDITIONAL INFORMATION

1. I have `/usr/bin/six.pyc` and there is no `six.py` file (it is created by VMware-vSphere-Perl-SDK-6.5.0-4566394.x86_64.tar.gz):
```
# ls -l /usr/bin/six.*
-r--r--r--. 1 root root 31988 Nov  4 06:56 /usr/bin/six.pyc
```
2. Launch ansible command but it does not work with IOError:
```
# ansible --version
Traceback (most recent call last):
  File "/bin/ansible", line 43, in <module>
    import ansible.constants as C
  File "/usr/lib/python2.7/site-packages/ansible/constants.py", line 26, in <module>
    from ansible.compat.six import string_types
  File "/usr/lib/python2.7/site-packages/ansible/compat/six/__init__.py", line 54, in <module>
    exec(open(six_py_file, 'rb').read())
IOError: [Errno 2] No such file or directory: '/usr/bin/six.py'
```


Discussion:
<!-- job_id: 59fdbb7ced9676070017d576 -->
<!-- job_id: 59fdbb7df0f1af08009f1ed4 -->
<!-- job_id: /testresults/ansible-test-failure.json -->

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: shippable_test_result --->
@saito-hideki Does this work in devel? If so, we should find the patch that fixed it and cherry pick it to 2.3/2.4
@jctanner ansible/lib/ansible/compat/six/ does not exist on devel and 2.4.x repos. It seems that this problem occurs between 2.0.x and 2.3.x.
Is it possible to merge this PR to the latest version of 2.3 ? It worked in 2.3.
In this case, devel and 2.4.[01] work without errors, but it occurs IOError in versions 2.3.x and earlier.
<!-- job_id: 5a006e9f8c080007006287e3 -->
<!-- job_id: 5a006ea063fdfa080026ee43 -->
<!-- job_id: /testresults/ansible-test-failure.json -->

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: shippable_test_result --->
Looking over the way this PR is written, it seems a little kludgey to use marshal and omit the first 8 bytes.  This is relying on the internal format of the byte compiled files so it's possible future versions of python would break it.  I think a better way to do it is to check for the .py file and if it doesn't exist, fallback to the bundled copy.  I'll work up an alternate that does that.

Resolving patch:
diff --git a/lib/ansible/compat/six/__init__.py b/lib/ansible/compat/six/__init__.py
--- a/lib/ansible/compat/six/__init__.py
+++ b/lib/ansible/compat/six/__init__.py
@@ -50,5 +50,12 @@
     six = _system_six
 else:
     from . import _six as six
+
 six_py_file = '{0}.py'.format(os.path.splitext(six.__file__)[0])
+if not os.path.exists(six_py_file):
+    # Only the .pyc/.pyo version of six was installed but we need a .py file
+    # Fallback to the bundled copy
+    from . import _six as six
+    six_py_file = '{0}.py'.format(os.path.splitext(six.__file__)[0])
+
 exec(open(six_py_file, 'rb').read())


Test patch: