torch/config: fix mock behaviour (#140779)

Mock only replaces the value that was removed, if after deletion, it
does not see the attribute.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/140779
Approved by: https://github.com/ezyang
This commit is contained in:
Colin L. Rice
2024-11-19 17:16:27 -07:00
committed by PyTorch MergeBot
parent 878a849c92
commit 241d2259d3
2 changed files with 26 additions and 0 deletions

View File

@ -213,6 +213,18 @@ class _ConfigEntry:
# environment variables are read at install time
env_value_force: Any = _UNSET_SENTINEL
env_value_default: Any = _UNSET_SENTINEL
# Used to work arounds bad assumptions in unittest.mock.patch
# The code to blame is
# https://github.com/python/cpython/blob/94a7a4e22fb8f567090514785c69e65298acca42/Lib/unittest/mock.py#L1637
# Essentially, mock.patch requires, that if __dict__ isn't accessible
# (which it isn't), that after delattr is called on the object, the
# object must throw when hasattr is called. Otherwise, it doesn't call
# setattr again.
# Technically we'll have an intermediate state of hiding the config while
# mock.patch is unpatching itself, but it calls setattr after the delete
# call so the final state is correct. It's just very unintuitive.
# upstream bug - python/cpython#126886
hide: bool = False
def __init__(self, config: Config):
self.default = config.default
@ -253,11 +265,15 @@ class ConfigModule(ModuleType):
else:
self._config[name].user_override = value
self._is_dirty = True
self._config[name].hide = False
def __getattr__(self, name: str) -> Any:
try:
config = self._config[name]
if config.hide:
raise AttributeError(f"{self.__name__}.{name} does not exist")
if config.env_value_force is not _UNSET_SENTINEL:
return config.env_value_force
@ -288,6 +304,7 @@ class ConfigModule(ModuleType):
# must support delete because unittest.mock.patch deletes
# then recreate things
self._config[name].user_override = _UNSET_SENTINEL
self._config[name].hide = True
def _is_default(self, name: str) -> bool:
return self._config[name].user_override is _UNSET_SENTINEL