labscript-suite / labscript-utils

Shared modules used by the 𝘭𝘒𝘣𝘴𝘀𝘳π˜ͺ𝘱𝘡 𝘴𝘢π˜ͺ𝘡𝘦. Includes a graphical exception handler, debug tools, configuration management, cross platform filepath conversions, unit conversions and custom GUI widgets.
http://labscriptsuite.org
Other
2 stars 45 forks source link

Distutils double import for setuptools>=60.0.0 #85

Closed dihm closed 2 years ago

dihm commented 2 years ago

It appears that setuptools is shipping a distutils hack that has begun to trigger double import warnings from the double import denier.

Easiest method to reproduce is to have setuptools>=60.0.0 and run the following two commands (from labscript_utils.ls_zprocess):

import labscript_utils  # engages the double import denier, maybe other things
from distutils.version import LooseVersion

With setuptools=60.0.5, the error is

Traceback (most recent call last):
  File "c:\users\naqsl\src\labscript-suite\labscript-utils\labscript_utils\double_import_denier.py", line 72, in find_spec
    self._raise_error(path, fullname, tb, other_name, other_tb)
  File "c:\users\naqsl\src\labscript-suite\labscript-utils\labscript_utils\double_import_denier.py", line 136, in _raise_error
    raise RuntimeError(msg) from None
RuntimeError: Double import! The same file has been imported under two different names, resulting in two copies of the module. This is almost certainly a mistake. If you are running a script from within a package and want to import another submodule of that package, import it by its full path: 'import module.submodule' instead of just 'import submodule.'

Path imported: C:\Users\naqsL\Miniconda3\envs\labscript2\Lib\site-packages\setuptools\_distutils\dir_util.py

Traceback (first time imported, as setuptools._distutils.dir_util):
------------
  File "<stdin>", line 1, in <module>
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\__init__.py", line 92, in create_module
    return importlib.import_module('setuptools._distutils')
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\setuptools\__init__.py", line 8, in <module>
    import _distutils_hack.override  # noqa: F401
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\override.py", line 1, in <module>
    __import__('_distutils_hack').do_override()
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\__init__.py", line 73, in do_override
    ensure_local_distutils()
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\__init__.py", line 60, in ensure_local_distutils
    core = importlib.import_module('distutils.core')
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\setuptools\_distutils\core.py", line 18, in <module>
    from distutils.cmd import Command
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\setuptools\_distutils\cmd.py", line 9, in <module>
    from distutils import util, dir_util, file_util, archive_util, dep_util
------------

Traceback (second time imported, as distutils.dir_util):
------------
  File "<stdin>", line 1, in <module>
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\__init__.py", line 92, in create_module
    return importlib.import_module('setuptools._distutils')
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\setuptools\__init__.py", line 8, in <module>
    import _distutils_hack.override  # noqa: F401
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\override.py", line 1, in <module>
    __import__('_distutils_hack').do_override()
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\__init__.py", line 73, in do_override
    ensure_local_distutils()
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\__init__.py", line 60, in ensure_local_distutils
    core = importlib.import_module('distutils.core')
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\setuptools\_distutils\core.py", line 18, in <module>
    from distutils.cmd import Command
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\setuptools\_distutils\cmd.py", line 9, in <module>
    from distutils import util, dir_util, file_util, archive_util, dep_util
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\setuptools\_distutils\archive_util.py", line 18, in <module>
    from distutils.dir_util import mkpath
------------

Under setuptools=60.9.3, (most recent release), the message changes slightly and becomes decidedly less helpful.

Traceback (most recent call last):
  File "c:\users\naqsl\src\labscript-suite\labscript-utils\labscript_utils\double_import_denier.py", line 72, in find_spec
    self._raise_error(path, fullname, tb, other_name, other_tb)
  File "c:\users\naqsl\src\labscript-suite\labscript-utils\labscript_utils\double_import_denier.py", line 136, in _raise_error
    raise RuntimeError(msg) from None
RuntimeError: Double import! The same file has been imported under two different names, resulting in two copies of the module. This is almost certainly a mistake. If you are running a script from within a package and want to import another submodule of that package, import it by its full path: 'import module.submodule' instead of just 'import submodule.'

Path imported: C:\Users\naqsL\Miniconda3\envs\labscript2\Lib\site-packages\setuptools\_distutils\__init__.py

Traceback (first time imported, as setuptools._distutils):
------------
  File "<stdin>", line 1, in <module>
  File "c:\users\naqsl\src\labscript-suite\labscript-utils\labscript_utils\double_import_denier.py", line 57, in find_spec
    spec = importlib.util.find_spec(fullname, path)
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\importlib\util.py", line 103, in find_spec
    return _find_spec(fullname, parent_path)
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\__init__.py", line 90, in find_spec
    return method()
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\__init__.py", line 101, in spec_for_distutils
    mod = importlib.import_module('setuptools._distutils')
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\setuptools\__init__.py", line 8, in <module>
    import _distutils_hack.override  # noqa: F401
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\override.py", line 1, in <module>
    __import__('_distutils_hack').do_override()
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\__init__.py", line 72, in do_override
    ensure_local_distutils()
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\__init__.py", line 55, in ensure_local_distutils
    importlib.import_module('distutils')
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\__init__.py", line 90, in find_spec
    return method()
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\site-packages\_distutils_hack\__init__.py", line 101, in spec_for_distutils
    mod = importlib.import_module('setuptools._distutils')
  File "C:\Users\naqsL\Miniconda3\envs\labscript2\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
------------

Traceback (second time imported, as distutils):
------------
------------

While I suppose we could whitelist distutils, I think the more correct solution is to remove calls to distutils (seeing as it will be fully deprecated in python 3.12). It appears the equivalent function for this present problem is now packaging.version.Version. If we go this route, it's probably worth checking the whole suite for random distutils calls and updating them as well.

dihm commented 2 years ago

Thanks to @josiahsinclair for pointing out this issue and helping me track down its source.

dihm commented 2 years ago

Looks like labscript-utils is the only part of the suite that has direct distutils imports (based on github searches of the repos).

image