diff --git a/pyomo/common/config.py b/pyomo/common/config.py index b01236bafaf..f8e43135a8e 100644 --- a/pyomo/common/config.py +++ b/pyomo/common/config.py @@ -1600,7 +1600,12 @@ def __call__( # ... and set the value, if appropriate if value is not NOTSET: + # Note that because we are *creating* a new Config object, + # we do not want set_value() to change the current (default) + # userSet flag for this object/container (see #3721). + tmp = ans._userSet ans.set_value(value) + ans._userSet = tmp return ans def name(self, fully_qualified=False): diff --git a/pyomo/common/tests/test_config.py b/pyomo/common/tests/test_config.py index b1c4d341b2d..193f8ab340d 100644 --- a/pyomo/common/tests/test_config.py +++ b/pyomo/common/tests/test_config.py @@ -1599,6 +1599,24 @@ def test_UserValues_declare_subBlock(self): test = '\n'.join(x.name(True) for x in self.config.user_values()) self.assertEqual(test, "") + def test_userValues_call_nonempty(self): + # See bug report in Pyomo/pyomo#3721 + default = ConfigDict() + default.declare("filename", ConfigValue(default=None, domain=str)) + cfg = default(value={"filename": "example.txt"}) + names = [x.name(True) for x in cfg.user_values()] + self.assertEqual(names, ["filename"]) + self.assertTrue(all(x is not cfg for x in cfg.user_values())) + + def test_userValues_call_empty_then_set(self): + # See bug report in Pyomo/pyomo#3721 + default = ConfigDict() + default.declare("filename", ConfigValue(default=None, domain=str)) + cfg = default({}) + cfg["filename"] = "example.txt" + names = [x.name(True) for x in cfg.user_values()] + self.assertEqual(names, ["filename"]) + @unittest.skipIf(not yaml_available, "Test requires PyYAML") def test_parseDisplayAndValue_default(self): test = _display(self.config)