Source code for aiida_vasp.workchains.v2.common.dictwrap

"""
Wrapper class to simply updating an Node when configuring inputs of a calculation.

This module is currently not used in the code, but kept here for future reference.
It is not clear such wrapper for Dict would truly benefit the usability of the code.
"""

from collections import UserDict
from typing import Any

from aiida.orm.nodes.data.dict import Dict


[docs] class DictWrapper(UserDict): """ Wrapper class for a dict Wraps around an Dict node, saved or not, to allow python dict-like in place modifications. """ def __init__(self, node, namespace=None, port=None): """ Wrapper around a ``Dict`` node. Optionally also include a namespace and a port that the underlying Node should be assigned to. The wrapped ``Dict`` node is never update in practice and only used as an initial reference data. If there is no change, the same Dict node will be passed as it is under the ``node`` property. :param node: The node to be wrapped. :param namespace: The namespace that the node should be assigned to. :param port: The port under the namespace. A new node is created whenever necessary. """ super().__init__() self._stored_node = node self._unstored_node = None # A new node to be used self.namespace = namespace self.port = port self.data = node.get_dict() if namespace is not None: namespace[port] = node
[docs] def __getattr__(self, name: str) -> Any: return getattr(self.node, name)
@property def is_updated(self): return self.data != self._stored_node.get_dict() @property def node(self): """ Returns a node object that represents the stored data. This can be a stored node (if no update) or an unstore node """ if self.is_updated: if self._unstored_node is None: self._unstored_node = Dict(dict=self.data) return self._unstored_node return self._stored_node
[docs] def __setitem__(self, key, value): """ Set the value of a key """ update = False if key in self.data: if self.data[key] != value: update = True else: update = True self._ensure_unstored() super().__setitem__(key, value) # If we have updated the value of a key if update: if self._unstored_node is None: self._unstored_node = Dict(dict=self.data) else: self._unstored_node.base.attributes.set(key, value) if self.namespace is not None: self.namespace[self.port] = self.node
[docs] def _ensure_unstored(self): """ Ensure that self._unstored_node is indeed unstored If it is not the case - we move it to self._stored_node an create a new unstored node. """ if self._unstored_node and self._unstored_node.is_stored: self._stored_node = self._unstored_node self._unstored_node = Dict(dict=self.data)
[docs] def __delitem__(self, key) -> None: """ Delete an item Delete from both the python dictionary and the underlying node """ self._ensure_unstored() super().__delitem__(key) if self._unstored_node is None: self._unstored_node = Dict(dict=self.data) else: self._unstored_node.delete_attribute(key) if self.namespace is not None: self.namespace[self.port] = self.node
[docs] def validate(self): """Validate the consistency between the node and the python dictionary""" assert self.data == self.node.get_dict()
[docs] @classmethod def serializer(cls, data, port=None): """ The `serializer` function can be used for `ProcessSpec.input`. Returns a Dict node for the given data. """ _ = port if isinstance(data, DictWrapper): return data.node return Dict(dict=data)