Skip to content

Commit

Permalink
Merge pull request #829 from hdoupe/cpi_822_cleanup
Browse files Browse the repository at this point in the history
Merged #829
  • Loading branch information
hdoupe committed Mar 1, 2018
2 parents b280f58 + 8278eee commit 96d113d
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 110 deletions.
3 changes: 2 additions & 1 deletion RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Go
[here](https://github.com/OpenSourcePolicyCenter/PolicyBrain/pulls?q=is%3Apr+is%3Aclosed)
for a complete commit history.

Release 1.4.2 on 2018-02-28
Release 1.4.2 on 2018-03-01
----------------------------
**Major Changes**
- None
Expand All @@ -14,6 +14,7 @@ Release 1.4.2 on 2018-02-28

**Bug Fixes**
- [#827](https://github.com/OpenSourcePolicyCenter/PolicyBrain/pull/827) - Remove errors for un-displayed parameters and save input data for warning/error message page - Hank Doupe
- [#829](https://github.com/OpenSourcePolicyCenter/PolicyBrain/pull/829) - Generate new form data for each page load - Hank Doupe


Release 1.4.1 on 2018-02-27
Expand Down
63 changes: 28 additions & 35 deletions webapp/apps/dynamic/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _

from ..constants import START_YEAR
from .models import (DynamicSaveInputs, DynamicBehaviorSaveInputs,
DynamicElasticitySaveInputs)
from ..taxbrain.helpers import (TaxCalcField, TaxCalcParam,
Expand All @@ -15,9 +16,9 @@ def bool_like(x):
b = True if x == 'True' or x == True else False
return b

OGUSA_DEFAULT_PARAMS = default_parameters(2015)
BEHAVIOR_DEFAULT_PARAMS = default_behavior_parameters(2015)
ELASTICITY_DEFAULT_PARAMS = default_elasticity_parameters(2015)
OGUSA_DEFAULT_PARAMS = default_parameters(int(START_YEAR))
BEHAVIOR_DEFAULT_PARAMS = default_behavior_parameters(int(START_YEAR))
ELASTICITY_DEFAULT_PARAMS = default_elasticity_parameters(int(START_YEAR))

class DynamicElasticityInputsModelForm(ModelForm):

Expand Down Expand Up @@ -217,25 +218,28 @@ class Meta:
class DynamicBehavioralInputsModelForm(PolicyBrainForm, ModelForm):

def __init__(self, first_year, *args, **kwargs):
if first_year is None:
first_year = START_YEAR
self._first_year = int(first_year)
# reset form data; form data from the `Meta` class is not updated each
# time a new `TaxBrainForm` instance is created
self.set_form_data(self._first_year)
# move parameter fields into `raw_fields` JSON object
args = self.add_fields(args)
# this seems to update the saved data in the appropriate way
# Override `initial` with `instance`. The only relevant field
# in `instance` is `raw_input_fields` which contains all of the user
# input data from the stored run. By overriding the `initial` kw
# argument we are making all of the user input from the previous run
# as stored in the `raw_input_fields` field of `instance` available
# to the fields attribute in django forms. This front-end data is
# derived from this fields attribute.
# Take a look at the source code for more info:
# https://github.com/django/django/blob/1.9/django/forms/models.py#L284-L285
if "instance" in kwargs:
kwargs["initial"] = kwargs["instance"].raw_input_fields

self._first_year = int(first_year)
self._default_params = default_behavior_parameters(self._first_year)
# Defaults are set in the Meta, but we need to swap
# those outs here in the init because the user may
# have chosen a different start year
all_defaults = []
for param in self._default_params.values():
for field in param.col_fields:
all_defaults.append((field.id, field.default_value))

for _id, default in all_defaults:
self._meta.widgets[_id].attrs['placeholder'] = default

super(DynamicBehavioralInputsModelForm, self).__init__(*args, **kwargs)

# update fields in a similar way as
# https://www.pydanny.com/overloading-form-fields.html
self.fields.update(self.Meta.update_fields)
Expand All @@ -254,30 +258,19 @@ def clean(self):
self.do_taxcalc_validations()
self.add_errors_on_extra_inputs()

def set_form_data(self, start_year):
defaults = default_behavior_parameters(start_year)
(self.widgets, self.labels,
self.update_fields) = PolicyBrainForm.set_form(defaults)


class Meta:
model = DynamicBehaviorSaveInputs
# we are only updating the "first_year", "raw_fields", and "fields"
# fields
fields = ['first_year', 'raw_input_fields', 'input_fields']
widgets = {}
labels = {}
update_fields = {}
for param in BEHAVIOR_DEFAULT_PARAMS.values():
for field in param.col_fields:
attrs = {
'class': 'form-control',
'placeholder': field.default_value,
}

widgets[field.id] = forms.TextInput(attrs=attrs)
update_fields[field.id] = forms.BooleanField(
label='',
widget=widgets[field.id],
required=False
)

labels[field.id] = field.label
(widgets, labels,
update_fields) = PolicyBrainForm.set_form(BEHAVIOR_DEFAULT_PARAMS)


class DynamicInputsModelForm(ModelForm):
Expand Down
165 changes: 91 additions & 74 deletions webapp/apps/taxbrain/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def expand_unless_empty(param_values, param_name, param_column_name, form, new_l
return param_values



class PolicyBrainForm:

def add_fields(self, args):
Expand Down Expand Up @@ -127,17 +128,79 @@ def do_taxcalc_validations(self):
("Operator '<' can only be used "
"at the beginning")
)

else:
assert isinstance(value, bool) or len(value) == 0

@staticmethod
def set_form(defaults):
"""
Setup all of the form fields and widgets with the the 2016 default data
"""
widgets = {}
labels = {}
update_fields = {}
boolean_fields = []

TAXCALC_DEFAULTS_2016 = default_policy(2016)
for param in defaults.values():
for field in param.col_fields:
attrs = {
'class': 'form-control',
'placeholder': field.default_value,
}

if param.coming_soon:
attrs['disabled'] = True

if param.tc_id in boolean_fields:
checkbox = forms.CheckboxInput(attrs=attrs, check_test=bool_like)
widgets[field.id] = checkbox
update_fields[field.id] = forms.BooleanField(
label='',
widget=widgets[field.id],
required=False
)
else:
widgets[field.id] = forms.TextInput(attrs=attrs)
update_fields[field.id] = forms.fields.CharField(
label='',
widget=widgets[field.id],
required=False
)

labels[field.id] = field.label

if getattr(param, "inflatable", False):
field = param.cpi_field
attrs = {
'class': 'form-control sr-only',
'placeholder': bool(field.default_value),
}

if param.coming_soon:
attrs['disabled'] = True

widgets[field.id] = forms.NullBooleanSelect(attrs=attrs)
update_fields[field.id] = forms.NullBooleanField(
label='',
widget=widgets[field.id],
required=False
)
return widgets, labels, update_fields


TAXCALC_DEFAULTS = {int(START_YEAR): default_policy(int(START_YEAR))}


class TaxBrainForm(PolicyBrainForm, ModelForm):

def __init__(self, first_year, *args, **kwargs):
if first_year is None:
first_year = START_YEAR
self._first_year = int(first_year)

# reset form data; form data from the `Meta` class is not updated each
# time a new `TaxBrainForm` instance is created
self.set_form_data(self._first_year)
# move parameter fields into `raw_fields` JSON object
args = self.add_fields(args)
# Override `initial` with `instance`. The only relevant field
Expand All @@ -151,6 +214,12 @@ def __init__(self, first_year, *args, **kwargs):
# https://github.com/django/django/blob/1.9/django/forms/models.py#L284-L285
if "instance" in kwargs:
kwargs["initial"] = kwargs["instance"].raw_input_fields

# Update CPI flags if either
# 1. initial is specified in `kwargs` (reform has warning/error msgs)
# 2. if `instance` is specified and `initial` is added above
# (edit parameters page)
if kwargs.get("initial", False):
for k, v in kwargs["initial"].iteritems():
if k.endswith("cpi") and v:
# raw data is stored as choices 1, 2, 3 with the following
Expand All @@ -160,36 +229,20 @@ def __init__(self, first_year, *args, **kwargs):
# '3': False
# value_from_datadict unpacks this data:
# https://github.com/django/django/blob/1.9/django/forms/widgets.py#L582-L589
django_val = self._meta.widgets[k].value_from_datadict(
if v == '1':
continue
django_val = self.widgets[k].value_from_datadict(
kwargs["initial"],
None,
k
)
self._meta.widgets[k].attrs["placeholder"] = django_val
if first_year is None:
first_year = START_YEAR
self._first_year = int(first_year)
self._default_params = default_policy(self._first_year)

# Defaults are set in the Meta, but we need to swap
# those out here in the init because the user may
# have chosen a different start year
all_defaults = []
for param in self._default_params.values():
for field in param.col_fields:
all_defaults.append((field.id, field.default_value))

for _id, default in all_defaults:
self._meta.widgets[_id].attrs['placeholder'] = default
self.widgets[k].attrs["placeholder"] = django_val

super(TaxBrainForm, self).__init__(*args, **kwargs)

# update fields in a similar way as
# https://www.pydanny.com/overloading-form-fields.html
self.fields.update(self.Meta.update_fields)

print('SS_Earnings_c_cpi field', self.fields['SS_Earnings_c_cpi'].__dict__)
print('SS_Earnings_c_cpi widget', self.fields['SS_Earnings_c_cpi'].widget.__dict__)
print('SS_Earnings_c_cpi meta widget', self._meta.widgets['SS_Earnings_c_cpi'].__dict__)
self.fields.update(self.update_fields.copy())

def clean(self):
"""
Expand All @@ -215,61 +268,25 @@ def add_error(self, field, error):
self.cleaned_data = {}
ModelForm.add_error(self, field, error)

class Meta:
def set_form_data(self, start_year):
if start_year not in TAXCALC_DEFAULTS:
TAXCALC_DEFAULTS[start_year] = default_policy(start_year)
defaults = TAXCALC_DEFAULTS[start_year]
(self.widgets, self.labels,
self.update_fields) = PolicyBrainForm.set_form(defaults)

class Meta:
model = TaxSaveInputs
# we are only updating the "first_year", "raw_fields", and "fields"
# fields
fields = ['first_year', 'raw_input_fields', 'input_fields']
widgets = {}
labels = {}
update_fields = {}
boolean_fields = []

for param in TAXCALC_DEFAULTS_2016.values():
for field in param.col_fields:
attrs = {
'class': 'form-control',
'placeholder': field.default_value,
}

if param.coming_soon:
attrs['disabled'] = True

if param.tc_id in boolean_fields:
checkbox = forms.CheckboxInput(attrs=attrs, check_test=bool_like)
widgets[field.id] = checkbox
update_fields[field.id] = forms.BooleanField(
label='',
widget=widgets[field.id],
required=False
)
else:
widgets[field.id] = forms.TextInput(attrs=attrs)
update_fields[field.id] = forms.fields.CharField(
label='',
widget=widgets[field.id],
required=False
)

labels[field.id] = field.label

if param.inflatable:
field = param.cpi_field
attrs = {
'class': 'form-control sr-only',
'placeholder': bool(field.default_value),
}

if param.coming_soon:
attrs['disabled'] = True

widgets[field.id] = forms.NullBooleanSelect(attrs=attrs)
update_fields[field.id] = forms.NullBooleanField(
label='',
widget=widgets[field.id],
required=False
)
start_year = int(START_YEAR)
if start_year not in TAXCALC_DEFAULTS:
TAXCALC_DEFAULTS[start_year] = default_policy(start_year)
(widgets, labels,
update_fields) = PolicyBrainForm.set_form(
TAXCALC_DEFAULTS[start_year]
)

def has_field_errors(form, include_parse_errors=False):
"""
Expand Down

0 comments on commit 96d113d

Please sign in to comment.