Repository: easybuilders/easybuild-easyblocks

Issue:
Tkinter easyblock does not work with `--module-only`
```
== sanity checking...
ERROR: Traceback (most recent call last):
  File "/project/def-sponsor00/ocaisa/easybuild/software/EasyBuild/4.3.4/lib/python3.8/site-packages/easybuild/main.py", line 117, in build_and_install_software
    (ec_res['success'], app_log, err) = build_and_install_one(ec, init_env)
  File "/project/def-sponsor00/ocaisa/easybuild/software/EasyBuild/4.3.4/lib/python3.8/site-packages/easybuild/framework/easyblock.py", line 3412, in build_and_install_one
    result = app.run_all_steps(run_test_cases=run_test_cases)
  File "/project/def-sponsor00/ocaisa/easybuild/software/EasyBuild/4.3.4/lib/python3.8/site-packages/easybuild/framework/easyblock.py", line 3311, in run_all_steps
    self.run_step(step_name, step_methods)
  File "/project/def-sponsor00/ocaisa/easybuild/software/EasyBuild/4.3.4/lib/python3.8/site-packages/easybuild/framework/easyblock.py", line 3166, in run_step
    step_method(self)()
  File "/project/def-sponsor00/ocaisa/easybuild/software/EasyBuild/4.3.4/lib/python3.8/site-packages/easybuild/easyblocks/t/tkinter.py", line 101, in sanity_check_step
    'files': [os.path.join(os.path.dirname(det_pylibdir()), self.tkinter_so_basename)],
AttributeError: 'EB_Tkinter' object has no attribute 'tkinter_so_basename'
```


Discussion:

Resolving patch:
diff --git a/easybuild/easyblocks/t/tkinter.py b/easybuild/easyblocks/t/tkinter.py
--- a/easybuild/easyblocks/t/tkinter.py
+++ b/easybuild/easyblocks/t/tkinter.py
@@ -39,6 +39,7 @@
 from easybuild.easyblocks.generic.pythonpackage import det_pylibdir
 from easybuild.easyblocks.python import EB_Python
 from easybuild.tools.build_log import EasyBuildError
+from easybuild.tools.config import build_option
 from easybuild.tools.filetools import copy, move_file, remove_dir
 from easybuild.tools.modules import get_software_root
 from easybuild.tools.systemtools import get_shared_lib_ext
@@ -50,6 +51,11 @@ class EB_Tkinter(EB_Python):
     but only install the Tkinter bits.
     """
 
+    def __init__(self, *args, **kwargs):
+        """Initialize Tkinter-specific variables."""
+        super(EB_Tkinter, self).__init__(*args, **kwargs)
+        self.tkinter_so_basename = ''
+
     def configure_step(self):
         """Check for Tk before configuring"""
         tk = get_software_root('Tk')
@@ -69,18 +75,14 @@ def install_step(self):
 
         tmpdir = tempfile.mkdtemp(dir=self.builddir)
 
-        pylibdir = os.path.join(self.installdir, os.path.dirname(det_pylibdir()))
-        shlib_ext = get_shared_lib_ext()
-        tkinter_so = os.path.join(pylibdir, 'lib-dynload', '_tkinter*.' + shlib_ext)
-        tkinter_so_hits = glob.glob(tkinter_so)
-        if len(tkinter_so_hits) != 1:
-            raise EasyBuildError("Expected to find exactly one _tkinter*.so: %s", tkinter_so_hits)
-        self.tkinter_so_basename = os.path.basename(tkinter_so_hits[0])
+        if not self.tkinter_so_basename:
+            self.tkinter_so_basename = self.get_tkinter_so_basename()
         if LooseVersion(self.version) >= LooseVersion('3'):
             tkparts = ["tkinter", os.path.join("lib-dynload", self.tkinter_so_basename)]
         else:
             tkparts = ["lib-tk", os.path.join("lib-dynload", self.tkinter_so_basename)]
 
+        pylibdir = os.path.join(self.installdir, os.path.dirname(det_pylibdir()))
         copy([os.path.join(pylibdir, x) for x in tkparts], tmpdir)
 
         remove_dir(self.installdir)
@@ -89,6 +91,21 @@ def install_step(self):
         tkinter_so = os.path.basename(tkparts[1])
         move_file(os.path.join(tmpdir, tkinter_so), os.path.join(pylibdir, tkinter_so))
 
+    def get_tkinter_so_basename(self):
+        pylibdir = os.path.join(self.installdir, os.path.dirname(det_pylibdir()))
+        shlib_ext = get_shared_lib_ext()
+        if build_option('module_only'):
+            # The build has already taken place so the file will have been moved into the final pylibdir
+            tkinter_so = os.path.join(pylibdir, '_tkinter*.' + shlib_ext)
+        else:
+            tkinter_so = os.path.join(pylibdir, 'lib-dynload', '_tkinter*.' + shlib_ext)
+        tkinter_so_hits = glob.glob(tkinter_so)
+        if len(tkinter_so_hits) != 1:
+            raise EasyBuildError("Expected to find exactly one _tkinter*.so: %s", tkinter_so_hits)
+        tkinter_so_basename = os.path.basename(tkinter_so_hits[0])
+
+        return tkinter_so_basename
+
     def sanity_check_step(self):
         """Custom sanity check for Python."""
         if LooseVersion(self.version) >= LooseVersion('3'):
@@ -97,6 +114,9 @@ def sanity_check_step(self):
             tkinter = 'Tkinter'
         custom_commands = ["python -c 'import %s'" % tkinter]
 
+        if not self.tkinter_so_basename:
+            self.tkinter_so_basename = self.get_tkinter_so_basename()
+
         custom_paths = {
             'files': [os.path.join(os.path.dirname(det_pylibdir()), self.tkinter_so_basename)],
             'dirs': ['lib']


Test patch: