From 4548be9d21c980639b0e32dd025d5363caaf8bae Mon Sep 17 00:00:00 2001 From: Alon Grinberg Dana Date: Sat, 4 Jul 2026 20:06:32 +0300 Subject: [PATCH 1/2] fix: replace removed distutils.spawn with shutil.which (Python 3.12+) `distutils` was removed from the Python standard library in 3.12, so `from distutils.spawn import find_executable` raises ModuleNotFoundError on Python 3.14 (it only works where setuptools happens to install its distutils compatibility shim). This breaks importing `arc.main`, which in turn breaks every downstream import of ARC (e.g. the T3 test suite fails at collection with `No module named 'distutils'`). Replace the single stdlib usage with `shutil.which`, the documented drop-in for `distutils.spawn.find_executable` (both return the path to the executable on PATH, or None). `shutil` is already imported. Note: ARC's own `arc.settings.settings.find_executable` is a different function (finds the python of a named conda env) and is unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) --- arc/main.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/arc/main.py b/arc/main.py index ca18bbbf3a..fc66a197be 100644 --- a/arc/main.py +++ b/arc/main.py @@ -13,7 +13,6 @@ import os import shutil import time -from distutils.spawn import find_executable from IPython.display import display from arc.common import (VERSION, @@ -788,25 +787,25 @@ def determine_ess_settings(self, diagnostics=False): # first look for ESS locally (e.g., when running ARC itself on a server) if 'SSH_CONNECTION' in os.environ and diagnostics: logger.info('Found "SSH_CONNECTION" in the os.environ dictionary, ' - 'using distutils.spawn.find_executable() to find ESS') + 'using shutil.which() to find ESS') if 'local' in servers: - g03 = find_executable('g03') - g09 = find_executable('g09') - g16 = find_executable('g16') + g03 = shutil.which('g03') + g09 = shutil.which('g09') + g16 = shutil.which('g16') if g03 or g09 or g16: if diagnostics: logger.info(f'Found Gaussian: g03={g03}, g09={g09}, g16={g16}') self.ess_settings['gaussian'] = ['local'] - qchem = find_executable('qchem') + qchem = shutil.which('qchem') if qchem: self.ess_settings['qchem'] = ['local'] - orca = find_executable('orca') + orca = shutil.which('orca') if orca: self.ess_settings['orca'] = ['local'] - molpro = find_executable('molpro') + molpro = shutil.which('molpro') if molpro: self.ess_settings['molpro'] = ['local'] - terachem = find_executable('terachem') + terachem = shutil.which('terachem') if terachem: self.ess_settings['molpro'] = ['local'] if any([val for val in self.ess_settings.values()]): From c62bdbba1b473110ec0bedd8dceab6353b1ba0dc Mon Sep 17 00:00:00 2001 From: Alon Grinberg Dana Date: Sat, 4 Jul 2026 20:47:53 +0300 Subject: [PATCH 2/2] fix: correct local ESS detection bugs (terachem key + found/not-found log) Two pre-existing bugs in ARC.check_ess_settings's local-ESS scan, surfaced by review of the surrounding block: 1. When a local TeraChem executable is found, availability was recorded under `self.ess_settings['molpro']` instead of `['terachem']` (copy-paste error), so TeraChem was mis-registered and Molpro could be falsely reported as available. 2. The "Did not find ESS on the local machine" log was nested under the `if diagnostics:` branch, so it fired as the `else` of `diagnostics` rather than the `else` of `if any(ESS found)`. As written, whenever ESS *were* found but `diagnostics` was False, it logged the opposite ("Did not find ESS"). Dedent the `else` to pair with the `any(...)` check so the not-found message only fires when nothing was found. Co-Authored-By: Claude Opus 4.8 (1M context) --- arc/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arc/main.py b/arc/main.py index fc66a197be..099f27e526 100644 --- a/arc/main.py +++ b/arc/main.py @@ -807,14 +807,14 @@ def determine_ess_settings(self, diagnostics=False): self.ess_settings['molpro'] = ['local'] terachem = shutil.which('terachem') if terachem: - self.ess_settings['molpro'] = ['local'] + self.ess_settings['terachem'] = ['local'] if any([val for val in self.ess_settings.values()]): if diagnostics: logger.info('Found the following ESS on the local machine:') logger.info([software for software, val in self.ess_settings.items() if val]) logger.info('\n') - else: - logger.info('Did not find ESS on the local machine\n\n') + else: + logger.info('Did not find ESS on the local machine\n\n') else: logger.info("\nNot searching for ESS locally ('local' wasn't specified in the servers dictionary)\n")