You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
openscm_runner.adapters cannot be imported on Python 3.12+ without setuptools (distutils removed) #110
import openscm_runner.adapters fails on Python 3.12 and later unless setuptools happens to be installed, because the CICERO-SCM adapter imports distutils, which was removed from the standard library in 3.12 (PEP 632).
Cause
adapters/__init__.py eagerly imports every adapter:
from .ciceroscm_adapterimportCICEROSCM
and adapters/ciceroscm_adapter/ciceroscm_wrapper.py:10 does:
fromdistutilsimportdir_util
So importing the package at all pulls in distutils, regardless of which climate model the caller intends to use. On 3.12+ that only resolves through the _distutils_hack shim that setuptools installs.
Reproducing
Verified against v0.13.0 (current release) on Python 3.13:
>>> import openscm_runner.adapters
ModuleNotFoundError: No module named 'distutils'
File ".../openscm_runner/adapters/__init__.py", line 6, in <module>
from .ciceroscm_adapter import CICEROSCM
File ".../ciceroscm_adapter/ciceroscm_wrapper.py", line 10, in <module>
from distutils import dir_util
Why this bites in practice
setuptools is present in most environments by accident rather than by declaration, so the failure is environment-dependent and surfaces late. Tools such as uv do not install it into a project environment at all, so the same lockfile works on one machine and not another. In our case it made a downstream pipeline unable to run its climate stage on one checkout while an otherwise identical one worked, with nothing in either lockfile to explain the difference.
Possible fixes
dir_util.copy_tree is the only usage as far as I can see, and shutil.copytree(..., dirs_exist_ok=True) covers it on all supported versions. shutil is already imported in that module.
Alternatively, import the adapters lazily in adapters/__init__.py, so a distutils dependency in one adapter does not break users of the others.
Happy to open a PR for either if you have a preference.
Thanks @karla-spiller ! I'll have a look at that now, see if I can possibly fix with either one of your suggestions, or seeing if we can do without distutils entirely...
@karla-spiller : Actually we've solved this with various updates included in PR #97 , once that comes in it should be solved. Maybe we can go back and do a rereview of that @znicholls ? I'll, go over and close all the outdated comments and reping you for a new review over there.
Thanks @maritsandstad! Glad to hear it has already been solved. Sorry, I didn't actually mean to bother you with this - this was Claude getting a bit over enthusiastic.
No worries @karla-spiller, well defined issues are always welcome, in fact, interest at all here is kind of once in a blue moon, and always nice to see :-)
Activity
maritsandstad commentedon Aug 6, 2026
Thanks @karla-spiller ! I'll have a look at that now, see if I can possibly fix with either one of your suggestions, or seeing if we can do without distutils entirely...
maritsandstad commentedon Aug 6, 2026
@karla-spiller : Actually we've solved this with various updates included in PR #97 , once that comes in it should be solved. Maybe we can go back and do a rereview of that @znicholls ? I'll, go over and close all the outdated comments and reping you for a new review over there.
karla-spiller commentedon Aug 6, 2026
Thanks @maritsandstad! Glad to hear it has already been solved. Sorry, I didn't actually mean to bother you with this - this was Claude getting a bit over enthusiastic.
maritsandstad commentedon Aug 6, 2026
No worries @karla-spiller, well defined issues are always welcome, in fact, interest at all here is kind of once in a blue moon, and always nice to see :-)