Source code for policyengine_core.parameters.parameter_scale_bracket

from typing import Iterable, Optional
from policyengine_core.parameters import Parameter, ParameterNode
from policyengine_core.parameters.config import COMMON_KEYS


[docs]class ParameterScaleBracket(ParameterNode): """ A parameter scale bracket. """ # The tax-scale components a bracket can hold as children. _component_keys = ("amount", "threshold", "rate", "average_rate", "base") # Keys accepted on a bracket node. Beyond the components, brackets may carry # the common ``description``/``metadata``/``documentation`` keys (metadata is # used to route uprating to the components; see issue #390). Any other key is # flagged by the loader (issue #505). _allowed_keys = frozenset(_component_keys).union(COMMON_KEYS) # The component that carries the bracket's threshold, versus the components # that carry its "value" (amount/rate/base). A bare ``uprating`` applies to # the value side; the threshold is opted in separately (issue #390). _threshold_key = "threshold" _value_keys = ("amount", "rate", "average_rate", "base")
[docs] @staticmethod def allowed_unit_keys(): return [key + "_unit" for key in ParameterScaleBracket._component_keys]
[docs] def get_descendants(self) -> Iterable[Parameter]: for key in self._component_keys: if key in self.children: yield self.children[key]
[docs] def propagate_uprating( self, uprating: str, threshold: bool = False, threshold_uprating: Optional[str] = None, ) -> None: """Route uprating metadata down onto the bracket's component leaves. Uprating is applied by reading each leaf ``Parameter``'s ``metadata["uprating"]``. Scale parameters carry their uprating intent on the scale, the bracket, or the individual component, so this method resolves all of those into per-leaf ``uprating`` entries. See issue #390. Resolution order for a component (highest priority first): 1. the component leaf's own ``metadata.uprating`` (per-leaf form, e.g. ``brackets[i].threshold.metadata.uprating``); 2. a bracket-level per-component override (``brackets[i].metadata.threshold.uprating``); 3. a bracket-level default: ``brackets[i].metadata.uprating`` for the value side, and for the threshold either ``brackets[i].metadata.threshold_uprating`` or the bare bracket ``uprating`` when ``brackets[i].metadata.uprate_thresholds`` is set; 4. the scale-level default passed in by :class:`ParameterScale` (``uprating`` for the value side, gated by ``uprate_thresholds`` for the threshold; ``threshold_uprating`` for the threshold). Args: uprating: Scale-level default uprating for the value side (may be ``None``). threshold: Whether the scale-level ``uprating`` should also apply to thresholds (the scale's ``uprate_thresholds`` flag). threshold_uprating: Scale-level uprating dedicated to thresholds (may be ``None``). """ bracket_meta = self.metadata # Bracket-level defaults, falling back to the scale-level ones. bracket_value_uprating = bracket_meta.get("uprating", uprating) bracket_threshold_uprating = bracket_meta.get( "threshold_uprating", threshold_uprating ) bracket_uprate_thresholds = bracket_meta.get("uprate_thresholds", threshold) for key in self._component_keys: if key not in self.children: continue child = self.children[key] # (2) bracket-level per-component override, e.g. metadata.threshold. component_override = None component_meta = bracket_meta.get(key) if isinstance(component_meta, dict): component_override = component_meta.get("uprating") if key == self._threshold_key: # Threshold: dedicated index, else bare bracket uprating when the # bracket/scale opts thresholds in. default = bracket_threshold_uprating if default is None and bracket_uprate_thresholds: default = bracket_value_uprating else: # Value side (amount/rate/base/average_rate). default = bracket_value_uprating resolved = ( child.metadata.get("uprating") # (1) per-leaf wins or component_override # (2) or default # (3)/(4) ) if resolved is not None: child.metadata["uprating"] = resolved