Source code for openfisca_core.tracers.flat_trace
from __future__ import annotations
import numpy
from openfisca_core import types as t
from openfisca_core.indexed_enums import EnumArray
[docs]
class FlatTrace:
_full_tracer: t.FullTracer
def __init__(self, full_tracer: t.FullTracer) -> None:
self._full_tracer = full_tracer
def get_trace(self) -> t.FlatNodeMap:
trace: t.FlatNodeMap = {}
for node in self._full_tracer.browse_trace():
# We don't want cache read to overwrite data about the initial
# calculation.
#
# We therefore use a non-overwriting update.
trace.update(
{
key: node_trace
for key, node_trace in self._get_flat_trace(node).items()
if key not in trace
},
)
return trace
def get_serialized_trace(self) -> t.SerializedNodeMap:
return {
key: {**flat_trace, "value": self.serialize(flat_trace["value"])}
for key, flat_trace in self.get_trace().items()
}
def _get_flat_trace(
self,
node: t.TraceNode,
) -> t.FlatNodeMap:
key = self.key(node)
return {
key: {
"dependencies": [self.key(child) for child in node.children],
"parameters": {
self.key(parameter): self.serialize(parameter.value)
for parameter in node.parameters
},
"value": node.value,
"calculation_time": node.calculation_time(),
"formula_time": node.formula_time(),
},
}
[docs]
@staticmethod
def key(node: t.TraceNode) -> t.NodeKey:
"""Return the key of a node."""
name = node.name
period = node.period
return t.NodeKey(f"{name}<{period}>")
@staticmethod
def serialize(
value: None | t.VarArray | t.ArrayLike[object],
) -> None | t.ArrayLike[object]:
if value is None:
return None
if isinstance(value, EnumArray):
return value.decode_to_str().tolist()
if isinstance(value, numpy.ndarray) and numpy.issubdtype(
value.dtype,
numpy.dtype(bytes),
):
return value.astype(numpy.dtype(str)).tolist()
if isinstance(value, numpy.ndarray):
return value.tolist()
return value
__all__ = ["FlatTrace"]