fix(win32): populate distributed c10d stub with dummy symbols

torch.distributed tries to `from torch._C._distributed_c10d import
FakeProcessGroup` (and ProcessGroup, Work, Store, etc.).  The previous
empty ModuleType stub caused an AttributeError on those names.

Populate every stub with a _Dummy class for each known symbol so the
import chain completes silently on Windows ROCm where torch._C is a
compiled extension and its _distributed_c10d submodule doesn't exist.

Adds four new tests in TestServerStartupRocmFixes covering FakeProcessGroup,
ProcessGroup, setattr population, and all three _distributed_* siblings.
This commit is contained in:
LeoBorcherding 2026-05-16 16:43:38 -05:00
commit 6831c2aed4
2 changed files with 46 additions and 1 deletions

View file

@ -955,13 +955,36 @@ def _determine_attention_impl_for_gpu_estimate(config) -> str:
import types as _types
if _sys.platform == "win32":
# Dummy class for any name torch.distributed tries to import from these stubs
class _Dummy:
pass
for _c10d_name in (
"torch._C._distributed_c10d",
"torch._C._distributed_autograd",
"torch._C._distributed_rpc",
):
if _c10d_name not in _sys.modules:
_sys.modules[_c10d_name] = _types.ModuleType(_c10d_name)
_stub = _types.ModuleType(_c10d_name)
# torch.distributed imports these names from _distributed_c10d;
# provide no-op dummies so the import doesn't raise AttributeError.
for _sym in (
"FakeProcessGroup",
"ProcessGroup",
"Work",
"Store",
"PrefixStore",
"FileStore",
"TCPStore",
"HashStore",
"Reducer",
"Logger",
"DistributedDebugLevel",
"GradBucket",
"BuiltinCommHookType",
):
setattr(_stub, _sym, _Dummy)
_sys.modules[_c10d_name] = _stub
try:
import torch.distributed as _td

View file

@ -2417,6 +2417,28 @@ class TestServerStartupRocmFixes:
source = _HARDWARE_PY_PATH.read_text(encoding = "utf-8")
assert 'platform == "win32"' in source or "win32" in source
def test_hardware_py_stub_exposes_fake_process_group(self):
"""hardware.py stub must set FakeProcessGroup so torch.distributed doesn't raise AttributeError."""
source = _HARDWARE_PY_PATH.read_text(encoding = "utf-8")
assert "FakeProcessGroup" in source
def test_hardware_py_stub_exposes_process_group(self):
"""hardware.py stub must set ProcessGroup on the c10d stub."""
source = _HARDWARE_PY_PATH.read_text(encoding = "utf-8")
assert "ProcessGroup" in source
def test_hardware_py_stub_uses_setattr_for_symbols(self):
"""hardware.py must use setattr to populate stub symbols dynamically."""
source = _HARDWARE_PY_PATH.read_text(encoding = "utf-8")
assert "setattr" in source
def test_hardware_py_stub_all_c10d_siblings_covered(self):
"""hardware.py must stub all three torch._C._distributed_* submodules."""
source = _HARDWARE_PY_PATH.read_text(encoding = "utf-8")
assert "_distributed_c10d" in source
assert "_distributed_autograd" in source
assert "_distributed_rpc" in source
if __name__ == "__main__":
pytest.main([__file__, "-v"])