Repository: easybuilders/easybuild-easyblocks

Issue:
Python fails to install in OpenSuse 15.1
Python fails to install with this error

```
== 2020-02-12 15:59:50,754 build_log.py:169 ERROR EasyBuild crashed with an error (at easybuild/opensuse-leap/15.1/x86_64/software/EasyBuild/4.1.1/lib/python2.7/site-packages/easybuild/base/exceptions.py:124 in __init__): cmd " ulimit -s unlimited &&   /shared/earth/easybuild/opensuse-leap/15.1/x86_64/software/Python/2.7.16-GCCcore-8.3.0/bin/python setup.py build " exited with exit code 1 and output:
Could not find platform dependent libraries <exec_prefix>
Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
Traceback (most recent call last):
  File "setup.py", line 9, in <module>
    import setuptools
  File "/tmp/eb-build/Python/2.7.16/GCCcore-8.3.0/setuptools/setuptools-41.2.0/setuptools/__init__.py", line 5, in <module>
    import functools
  File "/shared/earth/easybuild/opensuse-leap/15.1/x86_64/software/Python/2.7.16-GCCcore-8.3.0/lib/python2.7/functools.py", line 10, in <module>
    from _functools import partial, reduce
ImportError: No module named _functools
 (at easybuild/opensuse-leap/15.1/x86_64/software/EasyBuild/4.1.1/lib/python2.7/site-packages/easybuild/tools/run.py:529 in parse_cmd_output)
```
The error is related to this [bug](https://bugs.python.org/issue34058).

Workaround from @boegel and @omula 
```
installopts = " && cd %(installdir)s && ln -s ../../lib64/python2.7/lib-dynload lib/python2.7/lib-dynload"
```




Discussion:

Resolving patch:
diff --git a/easybuild/easyblocks/p/python.py b/easybuild/easyblocks/p/python.py
--- a/easybuild/easyblocks/p/python.py
+++ b/easybuild/easyblocks/p/python.py
@@ -46,7 +46,7 @@
 from easybuild.tools.build_log import EasyBuildError, print_warning
 from easybuild.tools.config import log_path
 from easybuild.tools.modules import get_software_libdir, get_software_root, get_software_version
-from easybuild.tools.filetools import symlink, write_file
+from easybuild.tools.filetools import change_dir, mkdir, symlink, write_file
 from easybuild.tools.run import run_cmd
 from easybuild.tools.systemtools import get_shared_lib_ext
 import easybuild.tools.toolchain as toolchain
@@ -279,6 +279,22 @@ def install_step(self):
         if self.cfg['ebpythonprefixes']:
             write_file(os.path.join(self.installdir, self.pythonpath, 'sitecustomize.py'), SITECUSTOMIZE)
 
+        # symlink lib/python*/lib-dynload to lib64/python*/lib-dynload if it doesn't exist;
+        # see https://github.com/easybuilders/easybuild-easyblocks/issues/1957
+        lib_dynload = 'lib-dynload'
+        python_lib_dynload = os.path.join('python%s' % self.pyshortver, lib_dynload)
+        lib_dynload_path = os.path.join(self.installdir, 'lib', python_lib_dynload)
+        if not os.path.exists(lib_dynload_path):
+            lib64_dynload_path = os.path.join('lib64', python_lib_dynload)
+            if os.path.exists(os.path.join(self.installdir, lib64_dynload_path)):
+                lib_dynload_parent = os.path.dirname(lib_dynload_path)
+                mkdir(lib_dynload_parent, parents=True)
+                cwd = change_dir(lib_dynload_parent)
+                # use relative path as target, to avoid hardcoding path to install directory
+                target_lib_dynload = os.path.join('..', '..', lib64_dynload_path)
+                symlink(target_lib_dynload, lib_dynload)
+                change_dir(cwd)
+
     def sanity_check_step(self):
         """Custom sanity check for Python."""
 
@@ -313,7 +329,7 @@ def sanity_check_step(self):
         pyver = 'python' + self.pyshortver
         custom_paths = {
             'files': [os.path.join('bin', pyver), os.path.join('lib', 'lib' + pyver + abiflags + '.' + shlib_ext)],
-            'dirs': [os.path.join('include', pyver + abiflags), os.path.join('lib', pyver)],
+            'dirs': [os.path.join('include', pyver + abiflags), os.path.join('lib', pyver, 'lib-dynload')],
         }
 
         # cleanup


Test patch: