You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Trying to change a top-level key of a stored Dict node raises (as expected):
In [1]: d=Dict({'a': 1})
...: d['b'] =2
...: print(d.get_dict())
{'a': 1, 'b': 2}
In [2]: d.store()
...: d['c'] =3
...: print(d.get_dict())
---------------------------------------------------------------------------ModificationNotAllowedTraceback (mostrecentcalllast)
CellIn[2], line21d.store()
---->2d['c'] =33print(d.get_dict())
File~/envs/aiida-dev/code/aiida-core/aiida/orm/nodes/data/dict.py:71, inDict.__setitem__(self, key, value)
70def__setitem__(self, key, value):
--->71self.base.attributes.set(key, value)
File~/envs/aiida-dev/code/aiida-core/aiida/orm/nodes/attributes.py:118, inNodeAttributes.set(self, key, value)
110defset(self, key: str, value: Any) ->None:
111"""Set an attribute to the given value. 112 113 :param key: name of the attribute (...) 116 :raise aiida.common.ModificationNotAllowed: if the entity is stored 117 """-->118self._node._check_mutability_attributes([key]) # pylint: disable=protected-access119self._backend_node.set_attribute(key, value)
File~/envs/aiida-dev/code/aiida-core/aiida/orm/nodes/node.py:209, inNode._check_mutability_attributes(self, keys)
202"""Check if the entity is mutable and raise an exception if not. 203 204 This is called from `NodeAttributes` methods that modify the attributes. 205 206 :param keys: the keys that will be mutated, or all if None 207 """208ifself.is_stored:
-->209raiseexceptions.ModificationNotAllowed('the attributes of a stored entity are immutable')
ModificationNotAllowed: theattributesofastoredentityareimmutable
But trying to change nested content of the Dict node fails silently:
In the context of setting QE input parameters. A fairly common use case where this would come up is when trying to use the get_restart_builder() and changing one of the inputs:
@sphuber already gave an extensive answer to why this problem is somewhat tricky to solve. I'll add it below for reference.
From @sphuber: I definitely remember writing about this in an issue and basically coming to the conclusion that it will be very difficult to come up with a solution for this. Essentially what is happening with the following code:
this will get the attribute from the database with that name and return it. The return type is a plain Python dictionary, let's call it d. So next, the code calls d['restart_mode'] = 'restart , which will indeed set the restart_mode key to restart, but that is of the Python dictionary d and not of the node attributes.
The only "solution" I see here is to have Dict.__getitem__ not return a plain dict but some custom class that implements all dict methods, but overrides all setters and delete attributes (and potentially others) and either raises or emits a warning. Now while this may be possible, I see many potential pitfalls that will be difficult to foresee.
The text was updated successfully, but these errors were encountered:
Describe the bug
Trying to change a top-level key of a stored
Dict
node raises (as expected):But trying to change nested content of the
Dict
node fails silently:Expected behavior
Trying to change the nested content of a stored
Dict
node should raise.Your environment
Additional context
This came up here:
aiidateam/aiida-quantumespresso#902 (comment)
In the context of setting QE input parameters. A fairly common use case where this would come up is when trying to use the
get_restart_builder()
and changing one of the inputs:@sphuber already gave an extensive answer to why this problem is somewhat tricky to solve. I'll add it below for reference.
From @sphuber: I definitely remember writing about this in an issue and basically coming to the conclusion that it will be very difficult to come up with a solution for this. Essentially what is happening with the following code:
First
restart_builder.pw.parameters['CONTROL']
calls_getitem__
withCONTROL
as key. As the implementation shows:this will get the attribute from the database with that name and return it. The return type is a plain Python dictionary, let's call it
d
. So next, the code callsd['restart_mode'] = 'restart
, which will indeed set therestart_mode
key torestart
, but that is of the Python dictionaryd
and not of the node attributes.The only "solution" I see here is to have
Dict.__getitem__
not return a plaindict
but some custom class that implements alldict
methods, but overrides all setters and delete attributes (and potentially others) and either raises or emits a warning. Now while this may be possible, I see many potential pitfalls that will be difficult to foresee.The text was updated successfully, but these errors were encountered: