prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN 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'
  ```
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `easybuild/easyblocks/t/tkinter.py`
  Content:
  ```
  1 ##
  2 # Copyright 2009-2021 Ghent University
  3 #
  4 # This file is part of EasyBuild,
  5 # originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
  6 # with support of Ghent University (http://ugent.be/hpc),
  7 # the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
  8 # Flemish Research Foundation (FWO) (http://www.fwo.be/en)
  9 # and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
  10 #
  11 # https://github.com/easybuilders/easybuild
  12 #
  13 # EasyBuild is free software: you can redistribute it and/or modify
  14 # it under the terms of the GNU General Public License as published by
  15 # the Free Software Foundation v2.
  16 #
  17 # EasyBuild is distributed in the hope that it will be useful,
  18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 # GNU General Public License for more details.
  21 #
  22 # You should have received a copy of the GNU General Public License
  23 # along with EasyBuild.  If not, see <http://www.gnu.org/licenses/>.
  24 ##
  25 """
  26 EasyBuild support for building and installing Tkinter. This is the Python core
  27 module to use Tcl/Tk.
  28 
  29 @author: Adam Huffman (The Francis Crick Institute)
  30 @author: Ward Poelmans (Free University of Brussels)
  31 @author: Kenneth Hoste (HPC-UGent)
  32 """
  33 import glob
  34 import os
  35 import tempfile
  36 from distutils.version import LooseVersion
  37 
  38 import easybuild.tools.environment as env
  39 from easybuild.easyblocks.generic.pythonpackage import det_pylibdir
  40 from easybuild.easyblocks.python import EB_Python
  41 from easybuild.tools.build_log import EasyBuildError
  42 from easybuild.tools.filetools import copy, move_file, remove_dir
  43 from easybuild.tools.modules import get_software_root
  44 from easybuild.tools.systemtools import get_shared_lib_ext
  45 
  46 
  47 class EB_Tkinter(EB_Python):
  48     """Support for building/installing the Python Tkinter module
  49     based on the normal Python module. We build a normal python
  50     but only install the Tkinter bits.
  51     """
  52 
  53     def configure_step(self):
  54         """Check for Tk before configuring"""
  55         tk = get_software_root('Tk')
  56         if not tk:
  57             raise EasyBuildError("Tk is mandatory to build Tkinter")
  58 
  59         # avoid that pip (ab)uses $HOME/.cache/pip
  60         # cfr. https://pip.pypa.io/en/stable/reference/pip_install/#caching
  61         env.setvar('XDG_CACHE_HOME', tempfile.gettempdir())
  62         self.log.info("Using %s as pip cache directory", os.environ['XDG_CACHE_HOME'])
  63 
  64         super(EB_Tkinter, self).configure_step()
  65 
  66     def install_step(self):
  67         """Install python but only keep the bits we need"""
  68         super(EB_Tkinter, self).install_step()
  69 
  70         tmpdir = tempfile.mkdtemp(dir=self.builddir)
  71 
  72         pylibdir = os.path.join(self.installdir, os.path.dirname(det_pylibdir()))
  73         shlib_ext = get_shared_lib_ext()
  74         tkinter_so = os.path.join(pylibdir, 'lib-dynload', '_tkinter*.' + shlib_ext)
  75         tkinter_so_hits = glob.glob(tkinter_so)
  76         if len(tkinter_so_hits) != 1:
  77             raise EasyBuildError("Expected to find exactly one _tkinter*.so: %s", tkinter_so_hits)
  78         self.tkinter_so_basename = os.path.basename(tkinter_so_hits[0])
  79         if LooseVersion(self.version) >= LooseVersion('3'):
  80             tkparts = ["tkinter", os.path.join("lib-dynload", self.tkinter_so_basename)]
  81         else:
  82             tkparts = ["lib-tk", os.path.join("lib-dynload", self.tkinter_so_basename)]
  83 
  84         copy([os.path.join(pylibdir, x) for x in tkparts], tmpdir)
  85 
  86         remove_dir(self.installdir)
  87 
  88         move_file(os.path.join(tmpdir, tkparts[0]), os.path.join(pylibdir, tkparts[0]))
  89         tkinter_so = os.path.basename(tkparts[1])
  90         move_file(os.path.join(tmpdir, tkinter_so), os.path.join(pylibdir, tkinter_so))
  91 
  92     def sanity_check_step(self):
  93         """Custom sanity check for Python."""
  94         if LooseVersion(self.version) >= LooseVersion('3'):
  95             tkinter = 'tkinter'
  96         else:
  97             tkinter = 'Tkinter'
  98         custom_commands = ["python -c 'import %s'" % tkinter]
  99 
  100         custom_paths = {
  101             'files': [os.path.join(os.path.dirname(det_pylibdir()), self.tkinter_so_basename)],
  102             'dirs': ['lib']
  103         }
  104         super(EB_Python, self).sanity_check_step(custom_commands=custom_commands, custom_paths=custom_paths)
  105 
  106     def make_module_extra(self):
  107         """Set PYTHONPATH"""
  108         txt = super(EB_Tkinter, self).make_module_extra()
  109         pylibdir = os.path.dirname(det_pylibdir())
  110         txt += self.module_generator.prepend_paths('PYTHONPATH', pylibdir)
  111 
  112         return txt
  113
  ```
  --- 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()
  
  ```
  
golden_diff: 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 @@
       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 @@
   
           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 @@
           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 @@
               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']
  
verification_info: {"golden_diff": "diff --git a/easybuild/easyblocks/t/tkinter.py b/easybuild/easyblocks/t/tkinter.py\n--- a/easybuild/easyblocks/t/tkinter.py\n+++ b/easybuild/easyblocks/t/tkinter.py\n@@ -39,6 +39,7 @@\n from easybuild.easyblocks.generic.pythonpackage import det_pylibdir\n from easybuild.easyblocks.python import EB_Python\n from easybuild.tools.build_log import EasyBuildError\n+from easybuild.tools.config import build_option\n from easybuild.tools.filetools import copy, move_file, remove_dir\n from easybuild.tools.modules import get_software_root\n from easybuild.tools.systemtools import get_shared_lib_ext\n@@ -50,6 +51,11 @@\n     but only install the Tkinter bits.\n     \"\"\"\n \n+    def __init__(self, *args, **kwargs):\n+        \"\"\"Initialize Tkinter-specific variables.\"\"\"\n+        super(EB_Tkinter, self).__init__(*args, **kwargs)\n+        self.tkinter_so_basename = ''\n+\n     def configure_step(self):\n         \"\"\"Check for Tk before configuring\"\"\"\n         tk = get_software_root('Tk')\n@@ -69,18 +75,14 @@\n \n         tmpdir = tempfile.mkdtemp(dir=self.builddir)\n \n-        pylibdir = os.path.join(self.installdir, os.path.dirname(det_pylibdir()))\n-        shlib_ext = get_shared_lib_ext()\n-        tkinter_so = os.path.join(pylibdir, 'lib-dynload', '_tkinter*.' + shlib_ext)\n-        tkinter_so_hits = glob.glob(tkinter_so)\n-        if len(tkinter_so_hits) != 1:\n-            raise EasyBuildError(\"Expected to find exactly one _tkinter*.so: %s\", tkinter_so_hits)\n-        self.tkinter_so_basename = os.path.basename(tkinter_so_hits[0])\n+        if not self.tkinter_so_basename:\n+            self.tkinter_so_basename = self.get_tkinter_so_basename()\n         if LooseVersion(self.version) >= LooseVersion('3'):\n             tkparts = [\"tkinter\", os.path.join(\"lib-dynload\", self.tkinter_so_basename)]\n         else:\n             tkparts = [\"lib-tk\", os.path.join(\"lib-dynload\", self.tkinter_so_basename)]\n \n+        pylibdir = os.path.join(self.installdir, os.path.dirname(det_pylibdir()))\n         copy([os.path.join(pylibdir, x) for x in tkparts], tmpdir)\n \n         remove_dir(self.installdir)\n@@ -89,6 +91,21 @@\n         tkinter_so = os.path.basename(tkparts[1])\n         move_file(os.path.join(tmpdir, tkinter_so), os.path.join(pylibdir, tkinter_so))\n \n+    def get_tkinter_so_basename(self):\n+        pylibdir = os.path.join(self.installdir, os.path.dirname(det_pylibdir()))\n+        shlib_ext = get_shared_lib_ext()\n+        if build_option('module_only'):\n+            # The build has already taken place so the file will have been moved into the final pylibdir\n+            tkinter_so = os.path.join(pylibdir, '_tkinter*.' + shlib_ext)\n+        else:\n+            tkinter_so = os.path.join(pylibdir, 'lib-dynload', '_tkinter*.' + shlib_ext)\n+        tkinter_so_hits = glob.glob(tkinter_so)\n+        if len(tkinter_so_hits) != 1:\n+            raise EasyBuildError(\"Expected to find exactly one _tkinter*.so: %s\", tkinter_so_hits)\n+        tkinter_so_basename = os.path.basename(tkinter_so_hits[0])\n+\n+        return tkinter_so_basename\n+\n     def sanity_check_step(self):\n         \"\"\"Custom sanity check for Python.\"\"\"\n         if LooseVersion(self.version) >= LooseVersion('3'):\n@@ -97,6 +114,9 @@\n             tkinter = 'Tkinter'\n         custom_commands = [\"python -c 'import %s'\" % tkinter]\n \n+        if not self.tkinter_so_basename:\n+            self.tkinter_so_basename = self.get_tkinter_so_basename()\n+\n         custom_paths = {\n             'files': [os.path.join(os.path.dirname(det_pylibdir()), self.tkinter_so_basename)],\n             'dirs': ['lib']\n", "issue": "Tkinter easyblock does not work with `--module-only`\n```\r\n== sanity checking...\r\nERROR: Traceback (most recent call last):\r\n  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\r\n    (ec_res['success'], app_log, err) = build_and_install_one(ec, init_env)\r\n  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\r\n    result = app.run_all_steps(run_test_cases=run_test_cases)\r\n  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\r\n    self.run_step(step_name, step_methods)\r\n  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\r\n    step_method(self)()\r\n  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\r\n    'files': [os.path.join(os.path.dirname(det_pylibdir()), self.tkinter_so_basename)],\r\nAttributeError: 'EB_Tkinter' object has no attribute 'tkinter_so_basename'\r\n```\n", "before_files": [{"content": "##\n# Copyright 2009-2021 Ghent University\n#\n# This file is part of EasyBuild,\n# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),\n# with support of Ghent University (http://ugent.be/hpc),\n# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),\n# Flemish Research Foundation (FWO) (http://www.fwo.be/en)\n# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).\n#\n# https://github.com/easybuilders/easybuild\n#\n# EasyBuild is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation v2.\n#\n# EasyBuild is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with EasyBuild.  If not, see <http://www.gnu.org/licenses/>.\n##\n\"\"\"\nEasyBuild support for building and installing Tkinter. This is the Python core\nmodule to use Tcl/Tk.\n\n@author: Adam Huffman (The Francis Crick Institute)\n@author: Ward Poelmans (Free University of Brussels)\n@author: Kenneth Hoste (HPC-UGent)\n\"\"\"\nimport glob\nimport os\nimport tempfile\nfrom distutils.version import LooseVersion\n\nimport easybuild.tools.environment as env\nfrom easybuild.easyblocks.generic.pythonpackage import det_pylibdir\nfrom easybuild.easyblocks.python import EB_Python\nfrom easybuild.tools.build_log import EasyBuildError\nfrom easybuild.tools.filetools import copy, move_file, remove_dir\nfrom easybuild.tools.modules import get_software_root\nfrom easybuild.tools.systemtools import get_shared_lib_ext\n\n\nclass EB_Tkinter(EB_Python):\n    \"\"\"Support for building/installing the Python Tkinter module\n    based on the normal Python module. We build a normal python\n    but only install the Tkinter bits.\n    \"\"\"\n\n    def configure_step(self):\n        \"\"\"Check for Tk before configuring\"\"\"\n        tk = get_software_root('Tk')\n        if not tk:\n            raise EasyBuildError(\"Tk is mandatory to build Tkinter\")\n\n        # avoid that pip (ab)uses $HOME/.cache/pip\n        # cfr. https://pip.pypa.io/en/stable/reference/pip_install/#caching\n        env.setvar('XDG_CACHE_HOME', tempfile.gettempdir())\n        self.log.info(\"Using %s as pip cache directory\", os.environ['XDG_CACHE_HOME'])\n\n        super(EB_Tkinter, self).configure_step()\n\n    def install_step(self):\n        \"\"\"Install python but only keep the bits we need\"\"\"\n        super(EB_Tkinter, self).install_step()\n\n        tmpdir = tempfile.mkdtemp(dir=self.builddir)\n\n        pylibdir = os.path.join(self.installdir, os.path.dirname(det_pylibdir()))\n        shlib_ext = get_shared_lib_ext()\n        tkinter_so = os.path.join(pylibdir, 'lib-dynload', '_tkinter*.' + shlib_ext)\n        tkinter_so_hits = glob.glob(tkinter_so)\n        if len(tkinter_so_hits) != 1:\n            raise EasyBuildError(\"Expected to find exactly one _tkinter*.so: %s\", tkinter_so_hits)\n        self.tkinter_so_basename = os.path.basename(tkinter_so_hits[0])\n        if LooseVersion(self.version) >= LooseVersion('3'):\n            tkparts = [\"tkinter\", os.path.join(\"lib-dynload\", self.tkinter_so_basename)]\n        else:\n            tkparts = [\"lib-tk\", os.path.join(\"lib-dynload\", self.tkinter_so_basename)]\n\n        copy([os.path.join(pylibdir, x) for x in tkparts], tmpdir)\n\n        remove_dir(self.installdir)\n\n        move_file(os.path.join(tmpdir, tkparts[0]), os.path.join(pylibdir, tkparts[0]))\n        tkinter_so = os.path.basename(tkparts[1])\n        move_file(os.path.join(tmpdir, tkinter_so), os.path.join(pylibdir, tkinter_so))\n\n    def sanity_check_step(self):\n        \"\"\"Custom sanity check for Python.\"\"\"\n        if LooseVersion(self.version) >= LooseVersion('3'):\n            tkinter = 'tkinter'\n        else:\n            tkinter = 'Tkinter'\n        custom_commands = [\"python -c 'import %s'\" % tkinter]\n\n        custom_paths = {\n            'files': [os.path.join(os.path.dirname(det_pylibdir()), self.tkinter_so_basename)],\n            'dirs': ['lib']\n        }\n        super(EB_Python, self).sanity_check_step(custom_commands=custom_commands, custom_paths=custom_paths)\n\n    def make_module_extra(self):\n        \"\"\"Set PYTHONPATH\"\"\"\n        txt = super(EB_Tkinter, self).make_module_extra()\n        pylibdir = os.path.dirname(det_pylibdir())\n        txt += self.module_generator.prepend_paths('PYTHONPATH', pylibdir)\n\n        return txt\n", "path": "easybuild/easyblocks/t/tkinter.py"}], "after_files": [{"content": "##\n# Copyright 2009-2021 Ghent University\n#\n# This file is part of EasyBuild,\n# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),\n# with support of Ghent University (http://ugent.be/hpc),\n# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),\n# Flemish Research Foundation (FWO) (http://www.fwo.be/en)\n# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).\n#\n# https://github.com/easybuilders/easybuild\n#\n# EasyBuild is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation v2.\n#\n# EasyBuild is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with EasyBuild.  If not, see <http://www.gnu.org/licenses/>.\n##\n\"\"\"\nEasyBuild support for building and installing Tkinter. This is the Python core\nmodule to use Tcl/Tk.\n\n@author: Adam Huffman (The Francis Crick Institute)\n@author: Ward Poelmans (Free University of Brussels)\n@author: Kenneth Hoste (HPC-UGent)\n\"\"\"\nimport glob\nimport os\nimport tempfile\nfrom distutils.version import LooseVersion\n\nimport easybuild.tools.environment as env\nfrom easybuild.easyblocks.generic.pythonpackage import det_pylibdir\nfrom easybuild.easyblocks.python import EB_Python\nfrom easybuild.tools.build_log import EasyBuildError\nfrom easybuild.tools.config import build_option\nfrom easybuild.tools.filetools import copy, move_file, remove_dir\nfrom easybuild.tools.modules import get_software_root\nfrom easybuild.tools.systemtools import get_shared_lib_ext\n\n\nclass EB_Tkinter(EB_Python):\n    \"\"\"Support for building/installing the Python Tkinter module\n    based on the normal Python module. We build a normal python\n    but only install the Tkinter bits.\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Initialize Tkinter-specific variables.\"\"\"\n        super(EB_Tkinter, self).__init__(*args, **kwargs)\n        self.tkinter_so_basename = ''\n\n    def configure_step(self):\n        \"\"\"Check for Tk before configuring\"\"\"\n        tk = get_software_root('Tk')\n        if not tk:\n            raise EasyBuildError(\"Tk is mandatory to build Tkinter\")\n\n        # avoid that pip (ab)uses $HOME/.cache/pip\n        # cfr. https://pip.pypa.io/en/stable/reference/pip_install/#caching\n        env.setvar('XDG_CACHE_HOME', tempfile.gettempdir())\n        self.log.info(\"Using %s as pip cache directory\", os.environ['XDG_CACHE_HOME'])\n\n        super(EB_Tkinter, self).configure_step()\n\n    def install_step(self):\n        \"\"\"Install python but only keep the bits we need\"\"\"\n        super(EB_Tkinter, self).install_step()\n\n        tmpdir = tempfile.mkdtemp(dir=self.builddir)\n\n        if not self.tkinter_so_basename:\n            self.tkinter_so_basename = self.get_tkinter_so_basename()\n        if LooseVersion(self.version) >= LooseVersion('3'):\n            tkparts = [\"tkinter\", os.path.join(\"lib-dynload\", self.tkinter_so_basename)]\n        else:\n            tkparts = [\"lib-tk\", os.path.join(\"lib-dynload\", self.tkinter_so_basename)]\n\n        pylibdir = os.path.join(self.installdir, os.path.dirname(det_pylibdir()))\n        copy([os.path.join(pylibdir, x) for x in tkparts], tmpdir)\n\n        remove_dir(self.installdir)\n\n        move_file(os.path.join(tmpdir, tkparts[0]), os.path.join(pylibdir, tkparts[0]))\n        tkinter_so = os.path.basename(tkparts[1])\n        move_file(os.path.join(tmpdir, tkinter_so), os.path.join(pylibdir, tkinter_so))\n\n    def get_tkinter_so_basename(self):\n        pylibdir = os.path.join(self.installdir, os.path.dirname(det_pylibdir()))\n        shlib_ext = get_shared_lib_ext()\n        if build_option('module_only'):\n            # The build has already taken place so the file will have been moved into the final pylibdir\n            tkinter_so = os.path.join(pylibdir, '_tkinter*.' + shlib_ext)\n        else:\n            tkinter_so = os.path.join(pylibdir, 'lib-dynload', '_tkinter*.' + shlib_ext)\n        tkinter_so_hits = glob.glob(tkinter_so)\n        if len(tkinter_so_hits) != 1:\n            raise EasyBuildError(\"Expected to find exactly one _tkinter*.so: %s\", tkinter_so_hits)\n        tkinter_so_basename = os.path.basename(tkinter_so_hits[0])\n\n        return tkinter_so_basename\n\n    def sanity_check_step(self):\n        \"\"\"Custom sanity check for Python.\"\"\"\n        if LooseVersion(self.version) >= LooseVersion('3'):\n            tkinter = 'tkinter'\n        else:\n            tkinter = 'Tkinter'\n        custom_commands = [\"python -c 'import %s'\" % tkinter]\n\n        if not self.tkinter_so_basename:\n            self.tkinter_so_basename = self.get_tkinter_so_basename()\n\n        custom_paths = {\n            'files': [os.path.join(os.path.dirname(det_pylibdir()), self.tkinter_so_basename)],\n            'dirs': ['lib']\n        }\n        super(EB_Python, self).sanity_check_step(custom_commands=custom_commands, custom_paths=custom_paths)\n\n    def make_module_extra(self):\n        \"\"\"Set PYTHONPATH\"\"\"\n        txt = super(EB_Tkinter, self).make_module_extra()\n        pylibdir = os.path.dirname(det_pylibdir())\n        txt += self.module_generator.prepend_paths('PYTHONPATH', pylibdir)\n\n        return txt\n", "path": "easybuild/easyblocks/t/tkinter.py"}]}