Source code for openfisca_core.reforms.reform

from __future__ import annotations

import copy

from openfisca_core.parameters import ParameterNode
from openfisca_core.taxbenefitsystems import TaxBenefitSystem


[docs] class Reform(TaxBenefitSystem): """A modified TaxBenefitSystem. All reforms must subclass `Reform` and implement a method `apply()`. In this method, the reform can add or replace variables and call `modify_parameters` to modify the parameters of the legislation. Example: >>> from openfisca_core import reforms >>> from openfisca_core.parameters import load_parameter_file >>> >>> def modify_my_parameters(parameters): >>> # Add new parameters >>> new_parameters = load_parameter_file(name='reform_name', file_path='path_to_yaml_file.yaml') >>> parameters.add_child('reform_name', new_parameters) >>> >>> # Update a value >>> parameters.taxes.some_tax.some_param.update(period=some_period, value=1000.0) >>> >>> return parameters >>> >>> class MyReform(reforms.Reform): >>> def apply(self): >>> self.add_variable(some_variable) >>> self.update_variable(some_other_variable) >>> self.modify_parameters(modifier_function = modify_my_parameters) """ name = None def __init__(self, baseline) -> None: """:param baseline: Baseline TaxBenefitSystem.""" super().__init__(baseline.entities) self.baseline = baseline self.parameters = baseline.parameters self._parameters_at_instant_cache = baseline._parameters_at_instant_cache self.variables = baseline.variables.copy() self.decomposition_file_path = baseline.decomposition_file_path self.key = self.__class__.__name__ if not hasattr(self, "apply"): msg = f"Reform {self.key} must define an `apply` function" raise Exception(msg) self.apply() def __getattr__(self, attribute): return getattr(self.baseline, attribute) @property def full_key(self): key = self.key assert ( key is not None ), f"key was not set for reform {self} (name: {self.name!r})" if self.baseline is not None and hasattr(self.baseline, "key"): baseline_full_key = self.baseline.full_key key = f"{baseline_full_key}.{key}" return key
[docs] def modify_parameters(self, modifier_function): """Make modifications on the parameters of the legislation. Call this function in `apply()` if the reform asks for legislation parameter modifications. Args: modifier_function: A function that takes a :obj:`.ParameterNode` and should return an object of the same type. """ baseline_parameters = self.baseline.parameters baseline_parameters_copy = copy.deepcopy(baseline_parameters) reform_parameters = modifier_function(baseline_parameters_copy) if not isinstance(reform_parameters, ParameterNode): return ValueError( f"modifier_function {modifier_function.__name__} in module {modifier_function.__module__} must return a ParameterNode", ) self.parameters = reform_parameters self._parameters_at_instant_cache = {} return None