Variable.clone() re-runs self.__class__() with baseline_variable=None (policyengine_core/variables/variable.py, clone), so cloning any variable that was registered through a reform's update_variable drops every attribute it inherited from the baseline variable. A label-only or adds-only reform override then fails to clone with Missing attribute 'value_type'.
Reproduce:
from policyengine_core.country_template import CountryTaxBenefitSystem
from policyengine_core.model_api import Reform, Variable
class disposable_income(Variable):
label = "Updated label only"
class reform(Reform):
def apply(self):
self.update_variable(disposable_income)
system = reform(CountryTaxBenefitSystem())
system.get_variable("disposable_income").clone() # ValueError: Missing attribute 'value_type'
This predates #501 (reproduced identically on the commit before it) and does not bite the normal flow because TaxBenefitSystem.clone() happens on the baseline system before reforms apply, or reforms re-apply on the clone. But any code path that clones a reformed system's variables directly will crash.
Suggested fix: decouple clone() from re-running __init__ — e.g. an empty_clone + __dict__ copy, the same pattern TaxBenefitSystem.clone() uses — so a cloned variable preserves its merged (baseline + override) state.
Found during the review of #501.
Variable.clone()re-runsself.__class__()withbaseline_variable=None(policyengine_core/variables/variable.py,clone), so cloning any variable that was registered through a reform'supdate_variabledrops every attribute it inherited from the baseline variable. A label-only or adds-only reform override then fails to clone withMissing attribute 'value_type'.Reproduce:
This predates #501 (reproduced identically on the commit before it) and does not bite the normal flow because
TaxBenefitSystem.clone()happens on the baseline system before reforms apply, or reforms re-apply on the clone. But any code path that clones a reformed system's variables directly will crash.Suggested fix: decouple
clone()from re-running__init__— e.g. anempty_clone+__dict__copy, the same patternTaxBenefitSystem.clone()uses — so a cloned variable preserves its merged (baseline + override) state.Found during the review of #501.