"""Every adapter's source_digest must cover every local file it executes. Each *-adapter.py is imported in a fresh interpreter with importlib.util.spec_from_file_location instrumented; the local .py files actually loaded (sys.modules __file__ under the repo plus every spec_from_file_location target) must be a subset of its SOURCE_FILES. """ import json import os from pathlib import Path import subprocess import sys import unittest ROOT = Path(__file__).resolve().parent REPO = ROOT.parents[2] PROBE = r''' import importlib.util, json, sys from pathlib import Path root, repo, adapter = Path(sys.argv[1]), Path(sys.argv[2]), sys.argv[3] seen = set() _orig = importlib.util.spec_from_file_location def _spy(name, location=None, *a, **k): if location is not None: seen.add(str(Path(location).resolve())) return _orig(name, location, *a, **k) importlib.util.spec_from_file_location = _spy spec = _orig('adapter_under_probe', root / adapter) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) for m in list(sys.modules.values()): f = getattr(m, '__file__', None) if f: seen.add(str(Path(f).resolve())) local = sorted(p for p in seen if p.endswith('.py') and Path(p).is_relative_to(repo) and '.venv' not in Path(p).parts and 'site-packages' not in Path(p).parts) local.append(str((root / adapter).resolve())) pinned = [] for entry in mod.SOURCE_FILES: pinned.append(str((repo / entry[0] / entry[1]).resolve()) if isinstance(entry, tuple) else str((root / entry).resolve())) print(json.dumps({'loaded': sorted(set(local)), 'pinned': sorted(pinned)})) ''' # Adapters outside this fix's scope that fail the check (reported, not fixed). KNOWN_FAILING = set() def _probe_env(): # The probe runs with cwd=ROOT, so a relative PYTHONPATH entry would stop # pointing where the caller meant it to; resolve entries against our cwd. env = dict(os.environ) if env.get('PYTHONPATH'): env['PYTHONPATH'] = os.pathsep.join( str(Path(p).resolve()) for p in env['PYTHONPATH'].split(os.pathsep) if p) return env def probe(adapter): out = subprocess.run([sys.executable, '-c', PROBE, str(ROOT), str(REPO), adapter], capture_output=True, text=True, env=_probe_env(), cwd=ROOT) if out.returncode: raise AssertionError(f'{adapter} probe failed: {out.stderr[-2000:]}') return json.loads(out.stdout.strip().splitlines()[-1]) def unpinned(adapter): r = probe(adapter) return sorted(set(r['loaded']) - set(r['pinned'])) class AdapterSourceClosure(unittest.TestCase): pass def _make(adapter): def test(self): missing = unpinned(adapter) self.assertEqual(missing, [], f'{adapter} loads files its source_digest does not pin') if adapter in KNOWN_FAILING: test = unittest.expectedFailure(test) return test for _p in sorted(ROOT.glob('*-adapter.py')): setattr(AdapterSourceClosure, 'test_' + _p.stem.replace('-', '_'), _make(_p.name)) if __name__ == '__main__': unittest.main()