Skip to content

Commit

Permalink
Merge pull request #2401 from hdoupe/use-paramtools
Browse files Browse the repository at this point in the history
Use ParamTools
  • Loading branch information
MattHJensen authored May 7, 2020
2 parents 5e9a4b0 + a892c37 commit 72f5de9
Show file tree
Hide file tree
Showing 21 changed files with 17,705 additions and 6,935 deletions.
125 changes: 88 additions & 37 deletions docs/make_uguide.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import os
import sys
from collections import OrderedDict
from taxcalc import Policy, json_to_dict
from taxcalc import *


INPUT_FILENAME = 'uguide.htmx'
Expand All @@ -20,6 +20,7 @@
TAXCALC_PATH = os.path.join(CURDIR_PATH, '..', 'taxcalc')

INPUT_PATH = os.path.join(CURDIR_PATH, INPUT_FILENAME)
TCJA_PATH = os.path.join(CURDIR_PATH,'../taxcalc/reforms/TCJA.json')
POLICY_PATH = os.path.join(TAXCALC_PATH, 'policy_current_law.json')
IOVARS_PATH = os.path.join(TAXCALC_PATH, 'records_variables.json')
CONSUMPTION_PATH = os.path.join(TAXCALC_PATH, 'consumption.json')
Expand Down Expand Up @@ -48,8 +49,9 @@ def main():
old = '<!-- #TOP# -->'
text = text.replace(old, topbtn)

params_dict = reformat_params()
# augment text variable with information from JSON files
text = policy_params(POLICY_PATH, text)
text = policy_params(POLICY_PATH, text, params_dict)
text = io_variables('read', IOVARS_PATH, text)
text = io_variables('calc', IOVARS_PATH, text)
text = assumption_params('consumption', CONSUMPTION_PATH, text)
Expand All @@ -64,22 +66,59 @@ def main():
# end of main function code


def policy_param_text(pname, param):
def reformat_params():
"""
Translates ParamTools-style policy_current_law.json
to a dictionary that resembles the old Tax-Calculator
parameter schema
"""
# Parameters that were changed by TCJA will be extended through
# 2026 in the uguide
tcja = Policy.read_json_reform(TCJA_PATH)

pol = Policy()
pol.clear_state()
years_short = list(range(2013, 2020))
years_long = list(range(2013, 2027))
pol.set_year(years_long)
params = pol.specification(serializable=True, sort_values=True)

# Create parameter dictionary that resembles old Tax-Calculator
# paramter schema
params_dict = {}
for param in params.keys():
if param in tcja.keys():
years = years_long
else:
years = years_short
params_dict[param] = {}
params_dict[param]['years'] = years
list_vals2 = []
for year in years:
list_vals1 = []
for idx in range(0, len(params[param])):
if params[param][idx]['year'] == year:
list_vals1.append(params[param][idx]['value'])
if params[param][idx]['year'] != params[param][idx - 1]['year']:
list_vals2.append(list_vals1)
params_dict[param]['values'] = list_vals2
return params_dict


def policy_param_text(pname, param, params_dict):
"""
Extract info from param for pname and return as HTML string.
"""
# pylint: disable=too-many-statements,too-many-branches

sec1 = param['section_1']
if sec1:
txt = '<p><b>{} &mdash; {}</b>'.format(sec1, param['section_2'])
else:
txt = '<p><b>{} &mdash; {}</b>'.format('Other Parameters',
'Not in Tax-Brain webapp')
txt += '<br><i>tc Name:</i> {}'.format(pname)
if sec1:
txt += '<br><i>TB Name:</i> {}'.format(param['long_name'])
else:
txt += '<br><i>Long Name:</i> {}'.format(param['long_name'])
txt += '<br><i>Title:</i> {}'.format(param['title'])
txt += '<br><i>Description:</i> {}'.format(param['description'])
if param.get('notes', ''):
txt += '<br><i>Notes:</i> {}'.format(param['notes'])
Expand All @@ -104,32 +143,32 @@ def policy_param_text(pname, param):
txt += 'True'
else:
txt += 'False'
txt += '<br><i>Value Type:</i> {}'.format(param['value_type'])
txt += '<br><i>Value Type:</i> {}'.format(param['type'])
txt += '<br><i>Known Values:</i>'
if param.get('vi_vals', []):
cols = ', '.join(param['vi_vals'])
txt += '<br>&nbsp;&nbsp; for: [{}]'.format(cols)
for cyr, val in zip(param['value_yrs'], param['value']):
final_cyr = cyr
final_val = val
txt += '<br>{}: {}'.format(cyr, val)
if not param['indexed']:
fcyr = int(final_cyr)
if fcyr < Policy.LAST_KNOWN_YEAR:
# extrapolate final_val thru Policy.LAST_KNOWN_YEAR if not indexed
for cyr in range(fcyr + 1, Policy.LAST_KNOWN_YEAR + 1):
txt += '<br>{}: {}'.format(cyr, final_val)
if len(params_dict[pname]['values'][0]) == 5:
txt += '<br>&nbsp;&nbsp; for: [single, mjoint, mseparate, headhh, widow]'
elif len(params_dict[pname]['values'][0]) == 4:
txt += '<br>&nbsp;&nbsp; for: [0kids, 1kid, 2kids, 3+kids]'
elif len(params_dict[pname]['values'][0]) == 7:
txt += '<br>&nbsp;&nbsp; for: [med, sltx, retx, cas, misc, int, char]'
for cyr, val in zip(params_dict[pname]['years'], params_dict[pname]['values']):
if len(params_dict[pname]['values'][0]) == 1:
txt += '<br>{}: {}'.format(cyr, val[0])
else:
txt += '<br>{}: {}'.format(cyr, val)
txt += '<br><i>Valid Range:</i>'
minval = param['valid_values']['min']
maxval = param['valid_values']['max']
txt += ' min = {} and max = {}'.format(minval, maxval)
invalid_action = param.get('invalid_action', 'stop')
txt += '<br><i>Out-of-Range Action:</i> {}'.format(invalid_action)
validators = param.get("validators", None)
if validators:
minval = validators['range']['min']
maxval = validators['range']['max']
txt += ' min = {} and max = {}'.format(minval, maxval)
invalid_action = validators["range"].get('level', 'error')
txt += '<br><i>Out-of-Range Action:</i> {}'.format(invalid_action)
txt += '</p>'
return txt


def policy_params(path, text):
def policy_params(path, text, params_dict):
"""
Read policy parameters from path, integrate them into text, and
return the integrated text.
Expand All @@ -144,6 +183,8 @@ def policy_params(path, text):
section = OrderedDict()
using_other_params_section = False
for pname in params:
if pname == "schema":
continue
param = params[pname]
sec1_sec2 = '{}{}{}'.format(param['section_1'],
concat_str,
Expand All @@ -161,9 +202,11 @@ def policy_params(path, text):
sec2 = split_list[1]
ptext = ''
for pname in params:
if pname == "schema":
continue
param = params[pname]
if sec1 == param['section_1'] and sec2 == param['section_2']:
ptext += policy_param_text(pname, param)
ptext += policy_param_text(pname, param, params_dict)
# integrate parameter text into text
old = '<!-- {} -->'.format(sec1_sec2)
text = text.replace(old, ptext)
Expand Down Expand Up @@ -233,24 +276,30 @@ def assumption_param_text(pname, ptype, param):
ptype.capitalize())
txt += '<br><i>tc Name:</i> {}'.format(pname)
if sec1:
txt += '<br><i>TB Name:</i> {}'.format(param['long_name'])
txt += '<br><i>TB Name:</i> {}'.format(param['title'])
else:
txt += '<br><i>Long Name:</i> {}'.format(param['long_name'])
txt += '<br><i>Long Name:</i> {}'.format(param['title'])
txt += '<br><i>Description:</i> {}'.format(param['description'])
if param.get('notes', ''):
txt += '<br><i>Notes:</i> {}'.format(param['notes'])
txt += '<br><i>Default Value:</i>'
if param.get('vi_vals', []):
cols = ', '.join(param['vi_vals'])
txt += '<br>&nbsp;&nbsp; for: [{}]'.format(cols)
for cyr, val in zip(param['value_yrs'], param['value']):
txt += '<br>{}: {}'.format(cyr, val)
for vo in param["value"]:
labels = " ".join(
f"{label}={value}" for label, value in vo.items()
if label not in ("year", "value")
)
txt += f"<br>{vo['year']}: {vo['value']} {labels}"
txt += '<br><i>Valid Range:</i>'
minval = param['valid_values']['min']
maxval = param['valid_values']['max']
txt += ' min = {} and max = {}'.format(minval, maxval)
invalid_action = param.get('invalid_action', 'stop')
txt += '<br><i>Out-of-Range Action:</i> {}'.format(invalid_action)
validators = param.get("validators", None)
if validators:
minval = validators['range']['min']
maxval = validators['range']['max']
txt += ' min = {} and max = {}'.format(minval, maxval)
invalid_action = validators["range"].get('level', 'error')
txt += '<br><i>Out-of-Range Action:</i> {}'.format(invalid_action)
txt += '</p>'
return txt

Expand All @@ -267,6 +316,8 @@ def assumption_params(ptype, path, text):
# construct parameter text for each param
ptext = ''
for pname in params:
if pname == "schema":
continue
param = params[pname]
ptext += assumption_param_text(pname, ptype, param)
# integrate parameter text into text
Expand Down
Loading

0 comments on commit 72f5de9

Please sign in to comment.