prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Regression with versionsuffix types
  Commit https://github.com/easybuilders/easybuild-framework/commit/0e5ba5c858
  introduced a check for string-type for `versionsuffix`, while `None` used to be an accepted value for `versionsuffix`. Our hooks replace many version suffixes with `None`. 
  
  --- 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/tools/module_naming_scheme/utilities.py`
  Content:
  ```
  1 ##
  2 # Copyright 2009-2023 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 Utility functions for implementating module naming schemes.
  27 
  28 Authors:
  29 
  30 * Stijn De Weirdt (Ghent University)
  31 * Dries Verdegem (Ghent University)
  32 * Kenneth Hoste (Ghent University)
  33 * Pieter De Baets (Ghent University)
  34 * Jens Timmerman (Ghent University)
  35 * Fotis Georgatos (Uni.Lu, NTUA)
  36 """
  37 import os
  38 import string
  39 
  40 from easybuild.base import fancylogger
  41 from easybuild.tools.build_log import EasyBuildError
  42 from easybuild.tools.module_naming_scheme.mns import ModuleNamingScheme
  43 from easybuild.tools.py2vs3 import string_type
  44 from easybuild.tools.toolchain.toolchain import SYSTEM_TOOLCHAIN_NAME, is_system_toolchain
  45 from easybuild.tools.utilities import get_subclasses, import_available_modules
  46 
  47 _log = fancylogger.getLogger('module_naming_scheme.utilities', fname=False)
  48 
  49 
  50 def det_full_ec_version(ec):
  51     """
  52     Determine exact install version, based on supplied easyconfig.
  53     e.g. 1.2.3-goalf-1.1.0-no-OFED or 1.2.3 (for system toolchains)
  54     """
  55 
  56     ecver = None
  57     toolchain = ec.get('toolchain', {'name': SYSTEM_TOOLCHAIN_NAME})
  58 
  59     # determine main install version based on toolchain
  60     if is_system_toolchain(toolchain['name']):
  61         ecver = ec['version']
  62     else:
  63         ecver = "%s-%s-%s" % (ec['version'], toolchain['name'], toolchain['version'])
  64 
  65     # prepend/append version prefix/suffix
  66     versionprefix = ec.get('versionprefix', '')
  67     if not isinstance(versionprefix, string_type):
  68         raise EasyBuildError("versionprefix value should be a string, found '%s': %s (full spec: %s)",
  69                              type(versionprefix).__name__, versionprefix, ec)
  70 
  71     versionsuffix = ec.get('versionsuffix', '')
  72     if not isinstance(versionsuffix, string_type):
  73         raise EasyBuildError("versionsuffix value should be a string, found '%s': %s (full spec: %s)",
  74                              type(versionsuffix).__name__, versionsuffix, ec)
  75 
  76     ecver = ''.join([x for x in [versionprefix, ecver, versionsuffix] if x])
  77 
  78     return ecver
  79 
  80 
  81 def avail_module_naming_schemes():
  82     """
  83     Returns a list of available module naming schemes.
  84     """
  85     # all ModuleNamingScheme subclasses available in easybuild.tools.module_naming_scheme namespace are eligible
  86     import_available_modules('easybuild.tools.module_naming_scheme')
  87 
  88     # construct name-to-class dict of available module naming scheme
  89     avail_mnss = dict([(x.__name__, x) for x in get_subclasses(ModuleNamingScheme)])
  90 
  91     return avail_mnss
  92 
  93 
  94 def is_valid_module_name(mod_name):
  95     """Check whether the specified value is a valid module name."""
  96     # module name must be a string
  97     if not isinstance(mod_name, string_type):
  98         _log.warning("Wrong type for module name %s (%s), should be a string" % (mod_name, type(mod_name)))
  99         return False
  100     # module name must be relative path
  101     elif mod_name.startswith(os.path.sep):
  102         _log.warning("Module name (%s) should be a relative file path" % mod_name)
  103         return False
  104     # module name should not be empty
  105     elif not len(mod_name) > 0:
  106         _log.warning("Module name (%s) should have length > 0." % mod_name)
  107         return False
  108     else:
  109         # check whether module name only contains printable characters, since it's used as a filename
  110         # (except for carriage-control characters \r, \x0b and \xoc)
  111         invalid_chars = [x for x in mod_name if x not in string.printable or x in '\r\x0b\x0c']
  112         if len(invalid_chars) > 0:
  113             _log.warning("Module name %s contains invalid characters: %s" % (mod_name, invalid_chars))
  114             return False
  115     _log.debug("Module name %s validated" % mod_name)
  116     return True
  117 
  118 
  119 def det_hidden_modname(modname):
  120     """Determine the hidden equivalent of the specified module name."""
  121     moddir = os.path.dirname(modname)
  122     modfile = os.path.basename(modname)
  123     return os.path.join(moddir, '.%s' % modfile).lstrip(os.path.sep)
  124
  ```
  --- 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/tools/module_naming_scheme/utilities.py b/easybuild/tools/module_naming_scheme/utilities.py
  --- a/easybuild/tools/module_naming_scheme/utilities.py
  +++ b/easybuild/tools/module_naming_scheme/utilities.py
  @@ -64,16 +64,16 @@
   
       # prepend/append version prefix/suffix
       versionprefix = ec.get('versionprefix', '')
  -    if not isinstance(versionprefix, string_type):
  +    if versionprefix and not isinstance(versionprefix, string_type):
           raise EasyBuildError("versionprefix value should be a string, found '%s': %s (full spec: %s)",
                                type(versionprefix).__name__, versionprefix, ec)
   
       versionsuffix = ec.get('versionsuffix', '')
  -    if not isinstance(versionsuffix, string_type):
  +    if versionsuffix and not isinstance(versionsuffix, string_type):
           raise EasyBuildError("versionsuffix value should be a string, found '%s': %s (full spec: %s)",
                                type(versionsuffix).__name__, versionsuffix, ec)
   
  -    ecver = ''.join([x for x in [versionprefix, ecver, versionsuffix] if x])
  +    ecver = ''.join([x for x in [versionprefix or '', ecver, versionsuffix or ''] if x])
   
       return ecver
  
verification_info: {"golden_diff": "diff --git a/easybuild/tools/module_naming_scheme/utilities.py b/easybuild/tools/module_naming_scheme/utilities.py\n--- a/easybuild/tools/module_naming_scheme/utilities.py\n+++ b/easybuild/tools/module_naming_scheme/utilities.py\n@@ -64,16 +64,16 @@\n \n     # prepend/append version prefix/suffix\n     versionprefix = ec.get('versionprefix', '')\n-    if not isinstance(versionprefix, string_type):\n+    if versionprefix and not isinstance(versionprefix, string_type):\n         raise EasyBuildError(\"versionprefix value should be a string, found '%s': %s (full spec: %s)\",\n                              type(versionprefix).__name__, versionprefix, ec)\n \n     versionsuffix = ec.get('versionsuffix', '')\n-    if not isinstance(versionsuffix, string_type):\n+    if versionsuffix and not isinstance(versionsuffix, string_type):\n         raise EasyBuildError(\"versionsuffix value should be a string, found '%s': %s (full spec: %s)\",\n                              type(versionsuffix).__name__, versionsuffix, ec)\n \n-    ecver = ''.join([x for x in [versionprefix, ecver, versionsuffix] if x])\n+    ecver = ''.join([x for x in [versionprefix or '', ecver, versionsuffix or ''] if x])\n \n     return ecver\n", "issue": "Regression with versionsuffix types\nCommit https://github.com/easybuilders/easybuild-framework/commit/0e5ba5c858\r\nintroduced a check for string-type for `versionsuffix`, while `None` used to be an accepted value for `versionsuffix`. Our hooks replace many version suffixes with `None`. \n", "before_files": [{"content": "##\n# Copyright 2009-2023 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\"\"\"\nUtility functions for implementating module naming schemes.\n\nAuthors:\n\n* Stijn De Weirdt (Ghent University)\n* Dries Verdegem (Ghent University)\n* Kenneth Hoste (Ghent University)\n* Pieter De Baets (Ghent University)\n* Jens Timmerman (Ghent University)\n* Fotis Georgatos (Uni.Lu, NTUA)\n\"\"\"\nimport os\nimport string\n\nfrom easybuild.base import fancylogger\nfrom easybuild.tools.build_log import EasyBuildError\nfrom easybuild.tools.module_naming_scheme.mns import ModuleNamingScheme\nfrom easybuild.tools.py2vs3 import string_type\nfrom easybuild.tools.toolchain.toolchain import SYSTEM_TOOLCHAIN_NAME, is_system_toolchain\nfrom easybuild.tools.utilities import get_subclasses, import_available_modules\n\n_log = fancylogger.getLogger('module_naming_scheme.utilities', fname=False)\n\n\ndef det_full_ec_version(ec):\n    \"\"\"\n    Determine exact install version, based on supplied easyconfig.\n    e.g. 1.2.3-goalf-1.1.0-no-OFED or 1.2.3 (for system toolchains)\n    \"\"\"\n\n    ecver = None\n    toolchain = ec.get('toolchain', {'name': SYSTEM_TOOLCHAIN_NAME})\n\n    # determine main install version based on toolchain\n    if is_system_toolchain(toolchain['name']):\n        ecver = ec['version']\n    else:\n        ecver = \"%s-%s-%s\" % (ec['version'], toolchain['name'], toolchain['version'])\n\n    # prepend/append version prefix/suffix\n    versionprefix = ec.get('versionprefix', '')\n    if not isinstance(versionprefix, string_type):\n        raise EasyBuildError(\"versionprefix value should be a string, found '%s': %s (full spec: %s)\",\n                             type(versionprefix).__name__, versionprefix, ec)\n\n    versionsuffix = ec.get('versionsuffix', '')\n    if not isinstance(versionsuffix, string_type):\n        raise EasyBuildError(\"versionsuffix value should be a string, found '%s': %s (full spec: %s)\",\n                             type(versionsuffix).__name__, versionsuffix, ec)\n\n    ecver = ''.join([x for x in [versionprefix, ecver, versionsuffix] if x])\n\n    return ecver\n\n\ndef avail_module_naming_schemes():\n    \"\"\"\n    Returns a list of available module naming schemes.\n    \"\"\"\n    # all ModuleNamingScheme subclasses available in easybuild.tools.module_naming_scheme namespace are eligible\n    import_available_modules('easybuild.tools.module_naming_scheme')\n\n    # construct name-to-class dict of available module naming scheme\n    avail_mnss = dict([(x.__name__, x) for x in get_subclasses(ModuleNamingScheme)])\n\n    return avail_mnss\n\n\ndef is_valid_module_name(mod_name):\n    \"\"\"Check whether the specified value is a valid module name.\"\"\"\n    # module name must be a string\n    if not isinstance(mod_name, string_type):\n        _log.warning(\"Wrong type for module name %s (%s), should be a string\" % (mod_name, type(mod_name)))\n        return False\n    # module name must be relative path\n    elif mod_name.startswith(os.path.sep):\n        _log.warning(\"Module name (%s) should be a relative file path\" % mod_name)\n        return False\n    # module name should not be empty\n    elif not len(mod_name) > 0:\n        _log.warning(\"Module name (%s) should have length > 0.\" % mod_name)\n        return False\n    else:\n        # check whether module name only contains printable characters, since it's used as a filename\n        # (except for carriage-control characters \\r, \\x0b and \\xoc)\n        invalid_chars = [x for x in mod_name if x not in string.printable or x in '\\r\\x0b\\x0c']\n        if len(invalid_chars) > 0:\n            _log.warning(\"Module name %s contains invalid characters: %s\" % (mod_name, invalid_chars))\n            return False\n    _log.debug(\"Module name %s validated\" % mod_name)\n    return True\n\n\ndef det_hidden_modname(modname):\n    \"\"\"Determine the hidden equivalent of the specified module name.\"\"\"\n    moddir = os.path.dirname(modname)\n    modfile = os.path.basename(modname)\n    return os.path.join(moddir, '.%s' % modfile).lstrip(os.path.sep)\n", "path": "easybuild/tools/module_naming_scheme/utilities.py"}], "after_files": [{"content": "##\n# Copyright 2009-2023 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\"\"\"\nUtility functions for implementating module naming schemes.\n\nAuthors:\n\n* Stijn De Weirdt (Ghent University)\n* Dries Verdegem (Ghent University)\n* Kenneth Hoste (Ghent University)\n* Pieter De Baets (Ghent University)\n* Jens Timmerman (Ghent University)\n* Fotis Georgatos (Uni.Lu, NTUA)\n\"\"\"\nimport os\nimport string\n\nfrom easybuild.base import fancylogger\nfrom easybuild.tools.build_log import EasyBuildError\nfrom easybuild.tools.module_naming_scheme.mns import ModuleNamingScheme\nfrom easybuild.tools.py2vs3 import string_type\nfrom easybuild.tools.toolchain.toolchain import SYSTEM_TOOLCHAIN_NAME, is_system_toolchain\nfrom easybuild.tools.utilities import get_subclasses, import_available_modules\n\n_log = fancylogger.getLogger('module_naming_scheme.utilities', fname=False)\n\n\ndef det_full_ec_version(ec):\n    \"\"\"\n    Determine exact install version, based on supplied easyconfig.\n    e.g. 1.2.3-goalf-1.1.0-no-OFED or 1.2.3 (for system toolchains)\n    \"\"\"\n\n    ecver = None\n    toolchain = ec.get('toolchain', {'name': SYSTEM_TOOLCHAIN_NAME})\n\n    # determine main install version based on toolchain\n    if is_system_toolchain(toolchain['name']):\n        ecver = ec['version']\n    else:\n        ecver = \"%s-%s-%s\" % (ec['version'], toolchain['name'], toolchain['version'])\n\n    # prepend/append version prefix/suffix\n    versionprefix = ec.get('versionprefix', '')\n    if versionprefix and not isinstance(versionprefix, string_type):\n        raise EasyBuildError(\"versionprefix value should be a string, found '%s': %s (full spec: %s)\",\n                             type(versionprefix).__name__, versionprefix, ec)\n\n    versionsuffix = ec.get('versionsuffix', '')\n    if versionsuffix and not isinstance(versionsuffix, string_type):\n        raise EasyBuildError(\"versionsuffix value should be a string, found '%s': %s (full spec: %s)\",\n                             type(versionsuffix).__name__, versionsuffix, ec)\n\n    ecver = ''.join([x for x in [versionprefix or '', ecver, versionsuffix or ''] if x])\n\n    return ecver\n\n\ndef avail_module_naming_schemes():\n    \"\"\"\n    Returns a list of available module naming schemes.\n    \"\"\"\n    # all ModuleNamingScheme subclasses available in easybuild.tools.module_naming_scheme namespace are eligible\n    import_available_modules('easybuild.tools.module_naming_scheme')\n\n    # construct name-to-class dict of available module naming scheme\n    avail_mnss = dict([(x.__name__, x) for x in get_subclasses(ModuleNamingScheme)])\n\n    return avail_mnss\n\n\ndef is_valid_module_name(mod_name):\n    \"\"\"Check whether the specified value is a valid module name.\"\"\"\n    # module name must be a string\n    if not isinstance(mod_name, string_type):\n        _log.warning(\"Wrong type for module name %s (%s), should be a string\" % (mod_name, type(mod_name)))\n        return False\n    # module name must be relative path\n    elif mod_name.startswith(os.path.sep):\n        _log.warning(\"Module name (%s) should be a relative file path\" % mod_name)\n        return False\n    # module name should not be empty\n    elif not len(mod_name) > 0:\n        _log.warning(\"Module name (%s) should have length > 0.\" % mod_name)\n        return False\n    else:\n        # check whether module name only contains printable characters, since it's used as a filename\n        # (except for carriage-control characters \\r, \\x0b and \\xoc)\n        invalid_chars = [x for x in mod_name if x not in string.printable or x in '\\r\\x0b\\x0c']\n        if len(invalid_chars) > 0:\n            _log.warning(\"Module name %s contains invalid characters: %s\" % (mod_name, invalid_chars))\n            return False\n    _log.debug(\"Module name %s validated\" % mod_name)\n    return True\n\n\ndef det_hidden_modname(modname):\n    \"\"\"Determine the hidden equivalent of the specified module name.\"\"\"\n    moddir = os.path.dirname(modname)\n    modfile = os.path.basename(modname)\n    return os.path.join(moddir, '.%s' % modfile).lstrip(os.path.sep)\n", "path": "easybuild/tools/module_naming_scheme/utilities.py"}]}