diff --git a/MANIFEST.in b/MANIFEST.in
index 9c4cf171e..ea4f9918c 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -6,7 +6,7 @@ include taxcalc/puf_weights.csv.gz
include taxcalc/puf_ratios.csv
include taxcalc/current_law_policy.json
include taxcalc/behavior.json
-include taxcalc/growth.json
+include taxcalc/growmodel.json
include taxcalc/consumption.json
include taxcalc/records_variables.json
include taxcalc/cps.csv.gz
diff --git a/docs/index.html b/docs/index.html
index 1452fec00..7a7113507 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1249,7 +1249,7 @@
Consumption Parameters
Behavior Parameters
-Behavior — Taxable Income
tc Name: _BE_sub
TB Name: Substitution elasticity of taxable income
Description: Defined as proportional change in taxable income divided by proportional change in marginal net-of-tax rate (1-MTR) on taxpayer earnings caused by the reform. Must be zero or positive.
Default Value:
2013: 0.0
Behavior — Taxable Income
tc Name: _BE_inc
TB Name: Income elasticity of taxable income
Description: Defined as dollar change in taxable income divided by dollar change in after-tax income caused by the reform. Must be zero or negative.
Default Value:
2013: 0.0
Behavior — Taxable Income
tc Name: _BE_subinc_wrt_earnings
TB Name: Income and substitution elasticities apply to earnings
Description: False implies elasticities apply to taxable income; true implies they are both computed as proportional changes and applied to taxpayer earnings only. Note: must be false if both _BE_sub and _BE_inc are zero.
Default Value:
2013: False
Behavior — Capital Gains
tc Name: _BE_cg
TB Name: Semi-elasticity of long-term capital gains
Description: Defined as change in logarithm of long-term capital gains divided by change in marginal tax rate (MTR) on long-term capital gains caused by the reform. Must be zero or negative. Read Behavior.response documentation for discussion of appropriate values.
Default Value:
2013: 0.0
Response Parameter — Behavior
tc Name: _BE_charity
Long Name: Elasticity of charitable contributions
Description: Defined as proportional change in cash and non-cash charitable contributions divided by proportional change in the after-tax price of charitable contributions caused by the reform. Must be zero or negative.
Default Value:
for: [AGI < 50k, 50k <= AGI < 100k, 100k <= AGI]
2013: [0.0, 0.0, 0.0]
+Behavior — Taxable Income
tc Name: _BE_sub
TB Name: Substitution elasticity of taxable income
Description: Defined as proportional change in taxable income divided by proportional change in marginal net-of-tax rate (1-MTR) on taxpayer earnings caused by the reform. Must be zero or positive.
Default Value:
2013: 0.0
Behavior — Taxable Income
tc Name: _BE_inc
TB Name: Income elasticity of taxable income
Description: Defined as dollar change in taxable income divided by dollar change in after-tax income caused by the reform. Must be zero or negative.
Default Value:
2013: 0.0
Behavior — Capital Gains
tc Name: _BE_cg
TB Name: Semi-elasticity of long-term capital gains
Description: Defined as change in logarithm of long-term capital gains divided by change in marginal tax rate (MTR) on long-term capital gains caused by the reform. Must be zero or negative. Read Behavior.response documentation for discussion of appropriate values.
Default Value:
2013: 0.0
Back to Section Contents
diff --git a/docs/index.htmx b/docs/index.htmx
index 0e92d4ac3..77a982d0a 100644
--- a/docs/index.htmx
+++ b/docs/index.htmx
@@ -78,7 +78,8 @@ via the command line
Policy Parameters that specify tax reforms
Input Variables that specify tax filing units
Output Variables that describe tax results
-Response Parameters that specify reform responses
+Assumption Parameters that specify economic
+assumptions
TaxBrain GUI
@@ -197,8 +198,8 @@ relationship between tax policy and the macro economy to predict the
effect of tax reforms on economic growth.
Clicking on one of these choices will allow you to specify some
-addition economic response parameters and initiate the dynamic
-analysis using your response parameter assumptions.
+additional economic assumption parameters and initiate the dynamic
+analysis using your economic assumptions.
Back to Section Contents
Back to Document Contents
@@ -334,26 +335,26 @@ part.
Specify Analysis Assumptions
-This part explains how to specify response assumption files used in
+
This part explains how to specify economic assumption files used in
non-static tax analysis. If you want to start out doing static
analysis, you can skip this part now and come back to read it whenever
you want to go beyond static analysis.
The next part of this section discusses
filing-unit input files.
-The details of economic response assumptions are contained in a
+
The details of economic assumptions are contained in a
text file that you write with a text editor. The assumptions are
-expressed by specifying which response parameters are changed from
+expressed by specifying which parameters are changed from
their default values, all of which are zero. The timing and magnitude of
-these response parameter changes are written in JSON, a simple and
+these parameter changes are written in JSON, a simple and
widely-used data-specification language.
-For examples of response assumption files and the general rules for
+
For examples of economic assumption files and the general rules for
writing JSON assumption files, go
-to this
+to this
page.
-If you want to upload policy reform and response assumption files
+
If you want to upload policy reform and economic assumption files
to TaxBrain, you can go directly to this
section's last part, which
discusses uploading files to TaxBrain. If you want to analyze your
@@ -407,7 +408,7 @@ analyzing reforms that change the tax treatment of high-income filers.
Third, when you want to estimate how your reform affects
total tax liabilities and/or the distribution of tax liabilities, you
-can always upload your policy reform and response assumption files
+can always upload your policy reform and economic assumption files
to TaxBrain. Combining this option with the first option provides a
complete tax analysis capability.
The last part of this section
@@ -490,7 +491,7 @@ using its own set of three age-count input variables.
one or more filing units. A baseline file is optional; no baseline
file implies the policy baseline is current-law policy. A policy
reform file is optional; no reform file implies no reform (that is,
-you want to analyze current-law policy). A response assumption file
+you want to analyze current-law policy). An economic assumption file
is also optional; no assumption file implies you want to conduct
static analysis. The output files written by tc are built-up from
the name of the input file, baseline file, reform file, and
@@ -516,7 +517,7 @@ projected to 2020. The name of the CSV-formatted output file is
test-20-#-#-#.csv. The first # symbol indicates
we did not specify a baseline file and the second # symbol
indicates we did not specify a policy reform file and the
-third # symbol indicates we did not specify a response
+third # symbol indicates we did not specify an economic
assumption file.
The variables included in the minimal output file include:
RECID (of filing unit in the input file),
@@ -640,7 +641,7 @@ The above command generates an output file named
Example (6) produces 2021 output for the filing units in the
test.csv file using the policy reform specified in
-the ref3.json file and the response assumptions
+the ref3.json file and the economic assumptions
specified in the res1.json file. The output results
produced by this non-static analysis are written to the
test-21-#-ref3-res1.csv file.
@@ -947,7 +948,7 @@ available in your SQLite tabulation session.
Upload Files to TaxBrain
-Any policy reform or response assumption files you can use with tc
+
Any policy reform or economic assumption files you can use with tc
can be uploaded to trigger a TaxBrain run. As mentioned above the
main advantages of doing this is getting access to the proprietary
puf.csv input file, getting fast execution of both reform
@@ -1201,7 +1202,7 @@ output variables that Tax-Calculator is programmed to calculate.
Back to Document Contents
-Response Parameters
+Assumption Parameters
This section contains documentation of several sets of parameters
that characterize responses to a tax reform. Consumption
@@ -1212,31 +1213,26 @@ tax reform in a partial-equilibrium setting. Growdiff parameters are
used to specify baseline differences and/or reform responses in the
annual rate of growth in economic variables.
-All the response parameters can be used by the tc CLI, but only
+
All the assumption parameters can be used by the tc CLI, but only
those with a TB Name appear in the TaxBrain GUI. All these
-dynamic response parameters control advanced features of
-Tax-Calculator, so understanding the
+assumption parameters control advanced features of Tax-Calculator, so
+understanding the
source
-code that uses them is essential. Default response parameter values are
-zero and are projected into the future at that value, which implies no
-response to the reform. Using the default no-reform-response
-assumption for all the response parameters generates a static analysis
-of the tax reform. The benefit value consumption parameters have a
-default value of one, which implies the consumption value of the
-in-kind benefits is equal to the government cost of providing the
-benefits.
-
-Note that some of the response parameters are incompatible with
-each other, and therefore, cannot be used together. The behavior
-parameters can not have non-zero values with specifying non-zero
-growdiff response parameters.
-
+code that uses them is essential. Default values of most
+assumption parameters are zero and are projected into the future at
+that value, which implies no response to the reform. Using the
+default no-reform-response assumption for all the response parameters
+generates a static analysis of the tax reform. The benefit value
+consumption parameters have a default value of one, which implies the
+consumption value of the in-kind benefits is equal to the government
+cost of providing the benefits.
Section Contents
Consumption Parameters
Behavior Parameters
Growdiff Parameters
+Growmodel Parameters
Consumption Parameters
@@ -1257,6 +1253,11 @@ growdiff response parameters.
+
+Growmodel Parameters
+
+
+
Back to Section Contents
Back to Document Contents
diff --git a/docs/make_index.py b/docs/make_index.py
index 1dadc3b29..da15dc971 100644
--- a/docs/make_index.py
+++ b/docs/make_index.py
@@ -28,6 +28,7 @@
CONSUMPTION_PATH = os.path.join(TAXCALC_PATH, 'consumption.json')
BEHAVIOR_PATH = os.path.join(TAXCALC_PATH, 'behavior.json')
GROWDIFF_PATH = os.path.join(TAXCALC_PATH, 'growdiff.json')
+GROWMODEL_PATH = os.path.join(TAXCALC_PATH, 'growmodel.json')
OUTPUT_PATH = os.path.join(CURDIR_PATH, OUTPUT_FILENAME)
@@ -49,9 +50,10 @@ def main():
text = policy_params(POLICY_PATH, text)
text = io_variables('read', IOVARS_PATH, text)
text = io_variables('calc', IOVARS_PATH, text)
- text = response_params('consumption', CONSUMPTION_PATH, text)
- text = response_params('behavior', BEHAVIOR_PATH, text)
- text = response_params('growdiff', GROWDIFF_PATH, text)
+ text = assumption_params('consumption', CONSUMPTION_PATH, text)
+ text = assumption_params('behavior', BEHAVIOR_PATH, text)
+ text = assumption_params('growdiff', GROWDIFF_PATH, text)
+ text = assumption_params('growmodel', GROWMODEL_PATH, text)
# write text variable to OUTPUT file
with open(OUTPUT_PATH, 'w') as ofile:
@@ -222,7 +224,7 @@ def io_variables(iotype, path, text):
return text
-def response_param_text(pname, ptype, param):
+def assumption_param_text(pname, ptype, param):
"""
Extract info from param for pname of ptype and return as HTML string.
"""
@@ -231,7 +233,7 @@ def response_param_text(pname, ptype, param):
if len(sec1) > 0:
txt = '{} — {}'.format(sec1, param['section_2'])
else:
- txt = '
{} — {}'.format('Response Parameter',
+ txt = '
{} — {}'.format('Assumption Parameter',
ptype.capitalize())
txt += '
tc Name: {}'.format(pname)
if len(sec1) > 0:
@@ -251,9 +253,9 @@ def response_param_text(pname, ptype, param):
return txt
-def response_params(ptype, path, text):
+def assumption_params(ptype, path, text):
"""
- Read response parameters of ptype from path, integrate them into text,
+ Read assumption parameters of ptype from path, integrate them into text,
and return the integrated text.
"""
with open(path) as pfile:
@@ -263,7 +265,7 @@ def response_params(ptype, path, text):
ptext = ''
for pname in params:
param = params[pname]
- ptext += response_param_text(pname, ptype, param)
+ ptext += assumption_param_text(pname, ptype, param)
# integrate parameter text into text
old = ''.format(ptype)
text = text.replace(old, ptext)
diff --git a/taxcalc/__init__.py b/taxcalc/__init__.py
index 58cdaf03d..346ba9cf8 100755
--- a/taxcalc/__init__.py
+++ b/taxcalc/__init__.py
@@ -8,6 +8,7 @@
from taxcalc.filings import *
from taxcalc.growfactors import *
from taxcalc.growdiff import *
+from taxcalc.growmodel import *
from taxcalc.records import *
from taxcalc.simpletaxio import *
from taxcalc.taxcalcio import *
diff --git a/taxcalc/assumptions/ASSUMPTIONS.md b/taxcalc/assumptions/ASSUMPTIONS.md
index 130df852a..1605349a1 100644
--- a/taxcalc/assumptions/ASSUMPTIONS.md
+++ b/taxcalc/assumptions/ASSUMPTIONS.md
@@ -61,6 +61,24 @@ Any key can have an empty value like the growdiff_baseline key above.
Empty values mean that the default assumption parameter values are
used.
+Including just these four key:value pairs in the assumption file indicates
+that the GrowModel is inactive. To activate the GrowModel, simply add a
+fifth key:value pair like this when you want to use the default parameter
+values of the GrowModel:
+```
+ ,
+ "growmodel": {
+ }
+```
+or add fifth key:value pair like this when you want to customize the
+GrowModel parameter values:
+```
+ ,
+ "growmodel": {
+ : {: }
+ }
+```
+
The rules about structuring a non-empty value for a top-level key are
the same as for policy reform files, which are described
[here](../reforms/REFORMS.md). The assumption parameter names
diff --git a/taxcalc/assumptions/economic_assumptions_template.json b/taxcalc/assumptions/economic_assumptions_template.json
index d4256a23a..9f0db4cdc 100644
--- a/taxcalc/assumptions/economic_assumptions_template.json
+++ b/taxcalc/assumptions/economic_assumptions_template.json
@@ -60,5 +60,8 @@
"_ATXPY": {"2017": [0.0]},
"_AUCOMP": {"2017": [0.0]},
"_AWAGE": {"2017": [0.0]}
+ },
+ "growmodel": {
+ "_active": {"2017": [false]}
}
}
diff --git a/taxcalc/calculate.py b/taxcalc/calculate.py
index 001b11577..ec2978ba9 100644
--- a/taxcalc/calculate.py
+++ b/taxcalc/calculate.py
@@ -1112,42 +1112,50 @@ def decile_graph(self, calc,
del dt2
return fig
+ REQUIRED_REFORM_KEYS = set(['policy'])
+ REQUIRED_ASSUMP_KEYS = set(['consumption', 'behavior',
+ 'growdiff_baseline', 'growdiff_response',
+ 'growmodel'])
+
@staticmethod
def read_json_param_objects(reform, assump):
"""
Read JSON reform and assump objects and
- return a single dictionary containing five key:dict pairs:
+ return a single dictionary containing six key:dict pairs:
'policy':dict, 'consumption':dict, 'behavior':dict,
- 'growdiff_baseline':dict and 'growdiff_response':dict.
+ 'growdiff_baseline':dict, 'growdiff_response':dict, and
+ 'growmodel':dict.
- Note that either of the two parameters may be None.
+ Note that either of the two function arguments can be None.
If reform is None, the dict in the 'policy':dict pair is empty.
- If assump is None, the dict in the 'consumption':dict pair,
- in the 'behavior':dict pair, in the 'growdiff_baseline':dict pair,
- and in the 'growdiff_response':dict pair, are all empty.
+ If assump is None, the dict in the all the key:dict pairs is empty.
- Also note that either of the first two parameters can be strings
+ Also note that either of the two function arguments can be strings
containing a valid JSON string (rather than a filename),
in which case the file reading is skipped and the appropriate
read_json_*_text method is called.
The reform file contents or JSON string must be like this:
{"policy": {...}}
- and the assump file contents or JSON string must be like:
+ and the assump file contents or JSON string must be like this:
{"consumption": {...},
"behavior": {...},
"growdiff_baseline": {...},
- "growdiff_response": {...}
- }
+ "growdiff_response": {...},
+ "growmodel": {...}}
+ The {...} should be empty like this {} if not specifying a policy
+ reform or if not specifying any economic assumptions of that type.
The returned dictionary contains parameter lists (not arrays).
"""
+ # pylint: disable=too-many-branches
# first process second assump parameter
if assump is None:
cons_dict = dict()
behv_dict = dict()
gdiff_base_dict = dict()
gdiff_resp_dict = dict()
+ growmodel_dict = dict()
elif isinstance(assump, six.string_types):
if os.path.isfile(assump):
txt = open(assump, 'r').read()
@@ -1156,7 +1164,8 @@ def read_json_param_objects(reform, assump):
(cons_dict,
behv_dict,
gdiff_base_dict,
- gdiff_resp_dict) = Calculator._read_json_econ_assump_text(txt)
+ gdiff_resp_dict,
+ growmodel_dict) = Calculator._read_json_econ_assump_text(txt)
else:
raise ValueError('assump is neither None nor string')
# next process first reform parameter
@@ -1174,23 +1183,17 @@ def read_json_param_objects(reform, assump):
)
else:
raise ValueError('reform is neither None nor string')
- # raise error if specifying both behavior and growdiff_response
- if behv_dict and gdiff_resp_dict:
- msg = 'both behavior and growdiff_response are specified'
- raise ValueError('ERROR: ' + msg + '\n')
- # finally construct and return single composite dictionary
+ # construct single composite dictionary
param_dict = dict()
param_dict['policy'] = rpol_dict
param_dict['consumption'] = cons_dict
param_dict['behavior'] = behv_dict
param_dict['growdiff_baseline'] = gdiff_base_dict
param_dict['growdiff_response'] = gdiff_resp_dict
+ param_dict['growmodel'] = growmodel_dict
+ # return the composite dictionary
return param_dict
- REQUIRED_REFORM_KEYS = set(['policy'])
- REQUIRED_ASSUMP_KEYS = set(['consumption', 'behavior',
- 'growdiff_baseline', 'growdiff_response'])
-
@staticmethod
def reform_documentation(params, policy_dicts=None):
"""
@@ -1204,7 +1207,7 @@ def reform_documentation(params, policy_dicts=None):
policy_dicts : list of dict or None
each dictionary in list is a params['policy'] dictionary
- representing second or subsequent elements of a compound
+ representing second and subsequent elements of a compound
reform; None implies no compound reform with the simple
reform characterized in the params['policy'] dictionary
@@ -1222,7 +1225,7 @@ def param_doc(years, change, base):
----------
years: list of change years
change: dictionary of parameter changes
- base: Policy or Growdiff object with baseline values
+ base: Policy or GrowDiff object with baseline values
syear: parameter start calendar year
Returns
@@ -1318,8 +1321,8 @@ def lines(text, num_indent_spaces, max_line_length=77):
elif basevals[param]['boolean_value']:
bval = bool(bval)
doc += ' baseline_value: {}\n'.format(bval)
- else: # if basex is Growdiff object
- # all Growdiff parameters have zero as default value
+ else: # if basex is GrowDiff object
+ # all GrowDiff parameters have zero as default value
doc += ' baseline_value: 0.0\n'
return doc
@@ -1328,7 +1331,7 @@ def lines(text, num_indent_spaces, max_line_length=77):
# ... create gdiff_baseline object
gdb = GrowDiff()
gdb.update_growdiff(params['growdiff_baseline'])
- # ... create Growfactors clp object that incorporates gdiff_baseline
+ # ... create GrowFactors object that will incorporate gdiff_baseline
gfactors_clp = GrowFactors()
gdb.apply_to(gfactors_clp)
# ... create Policy object containing pre-reform parameter values
@@ -1486,12 +1489,11 @@ def _read_json_policy_reform_text(text_string,
"""
Strip //-comments from text_string and return 1 dict based on the JSON.
- Specified text is JSON with at least 1 high-level string:object pair:
+ Specified text is JSON with at least 1 high-level key:object pair:
a "policy": {...} pair.
- Other high-level pairs will be ignored by this method, except
- that a "consumption", "behavior", "growdiff_baseline" or
- "growdiff_response" key will raise a ValueError.
+ Other keys such as "consumption", "behavior", "growdiff_baseline",
+ "growdiff_response" or "growmodel" will raise a ValueError.
The {...} object may be empty (that is, be {}), or
may contain one or more pairs with parameter string primary keys
@@ -1523,15 +1525,15 @@ def _read_json_policy_reform_text(text_string,
msg += bline + '\n'
raise ValueError(msg)
# check key contents of dictionary
- actual_keys = raw_dict.keys()
- for rkey in Calculator.REQUIRED_REFORM_KEYS:
- if rkey not in actual_keys:
- msg = 'key "{}" is not in policy reform file'
- raise ValueError(msg.format(rkey))
- for rkey in actual_keys:
- if rkey in Calculator.REQUIRED_ASSUMP_KEYS:
- msg = 'key "{}" should be in economic assumption file'
- raise ValueError(msg.format(rkey))
+ actual_keys = set(raw_dict.keys())
+ missing_keys = Calculator.REQUIRED_REFORM_KEYS - actual_keys
+ if missing_keys:
+ msg = 'required key(s) "{}" missing from policy reform file'
+ raise ValueError(msg.format(missing_keys))
+ illegal_keys = actual_keys - Calculator.REQUIRED_REFORM_KEYS
+ if illegal_keys:
+ msg = 'illegal key(s) "{}" in policy reform file'
+ raise ValueError(msg.format(illegal_keys))
# convert raw_dict['policy'] dictionary into prdict
tdict = Policy.translate_json_reform_suffixes(raw_dict['policy'],
growdiff_baseline_dict,
@@ -1542,16 +1544,16 @@ def _read_json_policy_reform_text(text_string,
@staticmethod
def _read_json_econ_assump_text(text_string):
"""
- Strip //-comments from text_string and return 4 dict based on the JSON.
+ Strip //-comments from text_string and return 5 dict based on the JSON.
- Specified text is JSON with at least 4 high-level string:object pairs:
+ Specified text is JSON with at least 5 high-level key:value pairs:
a "consumption": {...} pair,
a "behavior": {...} pair,
- a "growdiff_baseline": {...} pair, and
- a "growdiff_response": {...} pair.
+ a "growdiff_baseline": {...} pair,
+ a "growdiff_response": {...} pair, and
+ a "growmodel": {...} pair.
- Other high-level pairs will be ignored by this method, except that
- a "policy" key will raise a ValueError.
+ Other keys such as "policy" will raise a ValueError.
The {...} object may be empty (that is, be {}), or
may contain one or more pairs with parameter string primary keys
@@ -1560,16 +1562,17 @@ def _read_json_econ_assump_text(text_string):
that can be read by this method.
Note that an example is shown in the ASSUMP_CONTENTS string in
- tests/test_calculate.py file.
+ the tests/test_calculate.py file.
Returned dictionaries (cons_dict, behv_dict, gdiff_baseline_dict,
- gdiff_respose_dict) have integer years as primary keys and
- string parameters as secondary keys.
+ gdiff_respose_dict, growmodel_dict) have integer years as primary
+ keys and string parameters as secondary keys.
These returned dictionaries are suitable as the arguments to
the Consumption.update_consumption(cons_dict) method, or
the Behavior.update_behavior(behv_dict) method, or
- the Growdiff.update_growdiff(gdiff_dict) method.
+ the GrowDiff.update_growdiff(gdiff_dict) method, or
+ the GrowModel.update_growmodel(growmodel_dict) method.
"""
# pylint: disable=too-many-locals
# strip out //-comments without changing line numbers
@@ -1592,15 +1595,15 @@ def _read_json_econ_assump_text(text_string):
msg += bline + '\n'
raise ValueError(msg)
# check key contents of dictionary
- actual_keys = raw_dict.keys()
- for rkey in Calculator.REQUIRED_ASSUMP_KEYS:
- if rkey not in actual_keys:
- msg = 'key "{}" is not in economic assumption file'
- raise ValueError(msg.format(rkey))
- for rkey in actual_keys:
- if rkey in Calculator.REQUIRED_REFORM_KEYS:
- msg = 'key "{}" should be in policy reform file'
- raise ValueError(msg.format(rkey))
+ actual_keys = set(raw_dict.keys())
+ missing_keys = Calculator.REQUIRED_ASSUMP_KEYS - actual_keys
+ if missing_keys:
+ msg = 'required key(s) "{}" missing from economic assumption file'
+ raise ValueError(msg.format(missing_keys))
+ illegal_keys = actual_keys - Calculator.REQUIRED_ASSUMP_KEYS
+ if illegal_keys:
+ msg = 'illegal key(s) "{}" in economic assumption file'
+ raise ValueError(msg.format(illegal_keys))
# convert the assumption dictionaries in raw_dict
key = 'consumption'
cons_dict = Calculator._convert_parameter_dict(raw_dict[key])
@@ -1610,7 +1613,10 @@ def _read_json_econ_assump_text(text_string):
gdiff_base_dict = Calculator._convert_parameter_dict(raw_dict[key])
key = 'growdiff_response'
gdiff_resp_dict = Calculator._convert_parameter_dict(raw_dict[key])
- return (cons_dict, behv_dict, gdiff_base_dict, gdiff_resp_dict)
+ key = 'growmodel'
+ growmodel_dict = Calculator._convert_parameter_dict(raw_dict[key])
+ return (cons_dict, behv_dict, gdiff_base_dict, gdiff_resp_dict,
+ growmodel_dict)
@staticmethod
def _convert_parameter_dict(param_key_dict):
@@ -1620,7 +1626,8 @@ def _convert_parameter_dict(param_key_dict):
the Policy.implement_reform() method, or
the Consumption.update_consumption() method, or
the Behavior.update_behavior() method, or
- the Growdiff.update_growdiff() method.
+ the GrowDiff.update_growdiff() method, or
+ the GrowModel.update_growmodel() method.
Specified input dictionary has string parameter primary keys and
string years as secondary keys.
diff --git a/taxcalc/cli/tc.py b/taxcalc/cli/tc.py
index d79fd8ccf..1afb6d457 100644
--- a/taxcalc/cli/tc.py
+++ b/taxcalc/cli/tc.py
@@ -21,7 +21,8 @@ def cli_tc_main():
"""
Contains command-line interface (CLI) to Tax-Calculator TaxCalcIO class.
"""
- # pylint: disable=too-many-statements
+ # pylint: disable=too-many-statements,too-many-branches
+ # pylint: disable=too-many-return-statements
# parse command-line arguments:
usage_str = 'tc INPUT TAXYEAR {}{}{}{}{}{}{}'.format(
'[--baseline BASELINE]\n',
@@ -137,7 +138,7 @@ def cli_tc_main():
default=False,
action="store_true")
args = parser.parse_args()
- # show Tsx-Calculator version and quit if --version option specified
+ # show Tax-Calculator version and quit if --version option specified
if args.version:
sys.stdout.write('Tax-Calculator {}\n'.format(tc.__version__))
return 0
@@ -149,7 +150,7 @@ def cli_tc_main():
else:
inputfn = args.INPUT
taxyear = args.TAXYEAR
- # instantiate taxcalcio object and do tax analysis
+ # instantiate TaxCalcIO object and do tax analysis
tcio = tc.TaxCalcIO(input_data=inputfn, tax_year=taxyear,
baseline=args.baseline,
reform=args.reform, assump=args.assump,
@@ -162,7 +163,7 @@ def cli_tc_main():
tcio.init(input_data=inputfn, tax_year=taxyear,
baseline=args.baseline,
reform=args.reform, assump=args.assump,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=aging,
exact_calculations=args.exact)
if tcio.errmsg:
@@ -184,20 +185,36 @@ def cli_tc_main():
sys.stderr.write(msg.format(args.dvars))
sys.stderr.write('USAGE: tc --help\n')
return 1
- tcio.analyze(writing_output_file=True,
- output_tables=args.tables,
- output_graphs=args.graphs,
- output_ceeu=args.ceeu,
- dump_varset=dumpvar_set,
- output_dump=args.dump,
- output_sqldb=args.sqldb)
+ # conduct tax analysis
+ if tcio.growmodel.is_ever_active():
+ del tcio
+ tc.TaxCalcIO.growmodel_analysis(input_data=inputfn,
+ tax_year=taxyear,
+ baseline=args.baseline,
+ reform=args.reform,
+ assump=args.assump,
+ aging_input_data=aging,
+ exact_calculations=args.exact,
+ writing_output_file=True,
+ output_tables=args.tables,
+ output_graphs=args.graphs,
+ output_ceeu=args.ceeu,
+ dump_varset=dumpvar_set,
+ output_dump=args.dump,
+ output_sqldb=args.sqldb)
+ else:
+ tcio.analyze(writing_output_file=True,
+ output_tables=args.tables,
+ output_graphs=args.graphs,
+ output_ceeu=args.ceeu,
+ dump_varset=dumpvar_set,
+ output_dump=args.dump,
+ output_sqldb=args.sqldb)
# compare test output with expected test output if --test option specified
if args.test:
retcode = _compare_test_output_files()
- else:
- retcode = 0
- # return exit code
- return retcode
+ return retcode
+ return 0
# end of cli_tc_main function code
diff --git a/taxcalc/growdiff.py b/taxcalc/growdiff.py
index fbe611808..aab278a8c 100644
--- a/taxcalc/growdiff.py
+++ b/taxcalc/growdiff.py
@@ -1,5 +1,5 @@
"""
-Tax-Calculator GrowDiff class.
+Tax-Calculator GrowDiff class that is used to modify GrowFactors.
"""
# CODING-STYLE CHECKS:
# pycodestyle growdiff.py
@@ -14,7 +14,7 @@ class GrowDiff(ParametersBase):
GrowDiff is a subclass of the abstract ParametersBase class, and
therefore, inherits its methods (none of which are shown here).
- Constructor for growth difference class.
+ Constructor for GrowDiff class.
Parameters
----------
@@ -111,7 +111,7 @@ def has_any_response(self):
def apply_to(self, growfactors):
"""
- Apply updated growdiff values to specified Growfactors instance.
+ Apply updated GrowDiff values to specified GrowFactors instance.
"""
# pylint: disable=no-member
for i in range(0, self.num_years):
diff --git a/taxcalc/growmodel.json b/taxcalc/growmodel.json
new file mode 100644
index 000000000..7b63b5c88
--- /dev/null
+++ b/taxcalc/growmodel.json
@@ -0,0 +1,20 @@
+{
+ "_active": {
+ "long_name": "GrowModel is active",
+ "description": "True in any year implies GrowModel is active in all years.",
+ "section_1": "",
+ "section_2": "",
+ "notes": "",
+ "row_var": "FLPDYR",
+ "row_label": ["2013"],
+ "start_year": 2013,
+ "cpi_inflatable": false,
+ "cpi_inflated": false,
+ "col_var": "",
+ "col_label": "",
+ "boolean_value": true,
+ "integer_value": false,
+ "value": [false],
+ "range": {"min": false, "max": true}
+ }
+}
diff --git a/taxcalc/growmodel.py b/taxcalc/growmodel.py
new file mode 100644
index 000000000..c77d51d77
--- /dev/null
+++ b/taxcalc/growmodel.py
@@ -0,0 +1,176 @@
+"""
+Simple macroeconomic growth model embedded in Tax-Calculator.
+"""
+# CODING-STYLE CHECKS:
+# pycodestyle growmodel.py
+# pylint --disable=locally-disabled growmodel.py
+
+from __future__ import print_function
+import numpy as np
+from taxcalc.policy import Policy
+from taxcalc.parameters import ParametersBase
+
+
+class GrowModel(ParametersBase):
+ """
+ GrowModel is a subclass of the abstract ParametersBase class, and
+ therefore, inherits its methods (none of which are shown here).
+
+ Constructor for simple macroeconomic growth model.
+
+ Parameters
+ ----------
+ start_year: integer
+ first calendar year for GrowModel parameters.
+
+ num_years: integer
+ number of calendar years for which to specify parameter
+ values beginning with start_year.
+
+ Raises
+ ------
+ ValueError:
+ if start_year is less than Policy.JSON_START_YEAR
+ if num_years is less than one.
+
+ Returns
+ -------
+ class instance: GrowModel
+ """
+
+ JSON_START_YEAR = Policy.JSON_START_YEAR
+ DEFAULTS_FILENAME = 'growmodel.json'
+ DEFAULT_NUM_YEARS = Policy.DEFAULT_NUM_YEARS
+
+ def __init__(self,
+ start_year=JSON_START_YEAR,
+ num_years=DEFAULT_NUM_YEARS):
+ super(GrowModel, self).__init__()
+ self._vals = self._params_dict_from_json_file()
+ if start_year < Policy.JSON_START_YEAR:
+ raise ValueError('start_year < Policy.JSON_START_YEAR')
+ if num_years < 1:
+ raise ValueError('num_years < 1')
+ self.initialize(start_year, num_years)
+ self.parameter_errors = ''
+
+ def update_growmodel(self, revision):
+ """
+ Implement multi-year parameter revision leaving current_year unchanged.
+
+ Parameters
+ ----------
+ revision: dictionary of one or more YEAR:MODS pairs
+ see Notes to Parameters _update method for info on MODS structure
+
+ Raises
+ ------
+ ValueError:
+ if revision is not a dictionary.
+ if each YEAR in revision is not an integer.
+ if minimum YEAR in the YEAR:MODS pairs is less than start_year.
+ if minimum YEAR in the YEAR:MODS pairs is less than current_year.
+ if maximum YEAR in the YEAR:MODS pairs is greater than end_year.
+ if _validate_assump_parameter_names_types generates errors.
+ if _validate_assump_parameter_values generates errors.
+
+ Returns
+ -------
+ nothing: void
+
+ Notes
+ -----
+ Given a revision dictionary, typical usage of the GrowModel class
+ is as follows::
+
+ gmodel = GrowModel()
+ gmodel.update_growmodel(revision)
+
+ In the above statements, the GrowModel() call instantiates a
+ GrowModel object (gmodel) containing default parameter values,
+ and the update_growmodel(revision) call applies the (possibly
+ multi-year) revision specified in revision and then sets the
+ current_year to the value of current_year when update_growmodel
+ was called with parameters set for that pre-call year.
+
+ An example of a multi-year, multi-parameter revision is as follows::
+
+ revision = {
+ 2018: {
+ '_active': [True]
+ },
+ 2019: {
+ '_active': [False]
+ }
+ }
+
+ Notice that each of the YEAR:MODS pairs is specified as
+ required by the private _update method, whose documentation
+ provides several MODS dictionary examples.
+
+ IMPORTANT NOTICE: when specifying a revision dictionary always group
+ all revision provisions for a specified year into one YEAR:MODS pair.
+ If you make the mistake of specifying two or more YEAR:MODS pairs
+ with the same YEAR value, all but the last one will be overwritten,
+ and therefore, not part of the revision. This is because Python
+ expects unique (not multiple) dictionary keys. There is no way to
+ catch this error, so be careful to specify revision dictionaries
+ correctly.
+ """
+ # check that all revisions dictionary keys are integers
+ if not isinstance(revision, dict):
+ raise ValueError('ERROR: revision is not a dictionary')
+ if not revision:
+ return # no revision to implement
+ revision_years = sorted(list(revision.keys()))
+ for year in revision_years:
+ if not isinstance(year, int):
+ msg = 'ERROR: {} KEY {}'
+ details = 'KEY in revision is not an integer calendar year'
+ raise ValueError(msg.format(year, details))
+ # check range of remaining revision_years
+ first_revision_year = min(revision_years)
+ if first_revision_year < self.start_year:
+ msg = 'ERROR: {} YEAR revision provision in YEAR < start_year={}'
+ raise ValueError(msg.format(first_revision_year, self.start_year))
+ if first_revision_year < self.current_year:
+ msg = 'ERROR: {} YEAR revision provision in YEAR < current_year={}'
+ raise ValueError(
+ msg.format(first_revision_year, self.current_year)
+ )
+ last_revision_year = max(revision_years)
+ if last_revision_year > self.end_year:
+ msg = 'ERROR: {} YEAR revision provision in YEAR > end_year={}'
+ raise ValueError(msg.format(last_revision_year, self.end_year))
+ # validate revision parameter names and types
+ self._validate_assump_parameter_names_types(revision)
+ if self.parameter_errors:
+ raise ValueError(self.parameter_errors)
+ # implement the revision year by year
+ precall_current_year = self.current_year
+ revision_parameters = set()
+ for year in revision_years:
+ self.set_year(year)
+ revision_parameters.update(revision[year].keys())
+ self._update({year: revision[year]})
+ self.set_year(precall_current_year)
+ # validate revision parameter values
+ self._validate_assump_parameter_values(revision_parameters)
+ if self.parameter_errors:
+ raise ValueError('\n' + self.parameter_errors)
+
+ def is_active(self):
+ """
+ Returns true if GrowModel is active in the current_year;
+ returns false if GrowModel is inactive in the current_year.
+ """
+ return self.active # pylint: disable=no-member
+
+ def is_ever_active(self):
+ """
+ Returns true if GrowModel is active in any year;
+ returns false if GrowModel is inactive in all years.
+ """
+ return np.any(getattr(self, '_active'))
+
+ # ----- begin private methods of GrowModel class -----
diff --git a/taxcalc/parameters.py b/taxcalc/parameters.py
index 1fb126c8f..af07c30ef 100644
--- a/taxcalc/parameters.py
+++ b/taxcalc/parameters.py
@@ -15,7 +15,7 @@
class ParametersBase(object):
"""
- Inherit from this class for Policy, Behavior, Consumption, Growdiff, and
+ Inherit from this class for Policy, Behavior, Consumption, GrowDiff, and
other groups of parameters that need to have a set_year method.
Override this __init__ method and DEFAULTS_FILENAME.
"""
diff --git a/taxcalc/taxcalcio.py b/taxcalc/taxcalcio.py
index 2fe4a0a33..bb5d94a4b 100644
--- a/taxcalc/taxcalcio.py
+++ b/taxcalc/taxcalcio.py
@@ -5,6 +5,7 @@
# pycodestyle taxcalcio.py
# pylint --disable=locally-disabled taxcalcio.py
+from __future__ import print_function
import os
import gc
import copy
@@ -19,6 +20,7 @@
from taxcalc.growdiff import GrowDiff
from taxcalc.growfactors import GrowFactors
from taxcalc.calculate import Calculator
+from taxcalc.growmodel import GrowModel
from taxcalc.utils import (delete_file, write_graph_file,
add_quantile_table_row_variable,
unweighted_sum, weighted_sum)
@@ -72,6 +74,7 @@ def __init__(self, input_data, tax_year, baseline, reform, assump,
self.errmsg = ''
# check name and existence of INPUT file
inp = 'x'
+ self.cps_input_data = False
if isinstance(input_data, six.string_types):
# remove any leading directory path from INPUT filename
fname = os.path.basename(input_data)
@@ -202,11 +205,12 @@ def __init__(self, input_data, tax_year, baseline, reform, assump,
self.behavior_has_any_response = False
self.calc = None
self.calc_base = None
+ self.growmodel = None
self.param_dict = None
self.policy_dicts = list()
def init(self, input_data, tax_year, baseline, reform, assump,
- growdiff_response,
+ growdiff_growmodel,
aging_input_data,
exact_calculations):
"""
@@ -217,10 +221,9 @@ def init(self, input_data, tax_year, baseline, reform, assump,
First five are same as the first five of the TaxCalcIO constructor:
input_data, tax_year, baseline, reform, assump.
- growdiff_response: GrowDiff object or None
- growdiff_response GrowDiff object is used only by the
- TaxCalcIO.growmodel_analysis method;
- must be None in all other cases.
+ growdiff_growmodel: GrowDiff object or None
+ growdiff_growmodel GrowDiff object is used only in the
+ TaxCalcIO.growmodel_analysis method.
aging_input_data: boolean
whether or not to extrapolate Records data from data year to
@@ -233,55 +236,49 @@ def init(self, input_data, tax_year, baseline, reform, assump,
# pylint: disable=too-many-arguments,too-many-locals
# pylint: disable=too-many-statements,too-many-branches
self.errmsg = ''
- # get parameter dictionary from --baseline file
+ # get policy parameter dictionary from --baseline file
basedict = Calculator.read_json_param_objects(baseline, None)
- # get parameter dictionaries from --reform file(s) and --assump file
+ # get assumption sub-dictionaries
+ paramdict = Calculator.read_json_param_objects(None, assump)
+ # get policy parameter dictionaries from --reform file(s)
+ policydicts = list()
if self.specified_reform:
reforms = reform.split('+')
- paramdict = Calculator.read_json_param_objects(reforms[0], assump)
- policydicts = [paramdict['policy']]
- if len(reforms) > 1: # simulating a compound reform
- for ref in reforms[1:]:
- pdict = Calculator.read_json_param_objects(ref, None)
- policydicts.append(pdict['policy'])
- else:
- paramdict = Calculator.read_json_param_objects(reform, assump)
- policydicts = [paramdict['policy']]
+ for ref in reforms:
+ pdict = Calculator.read_json_param_objects(ref, None)
+ policydicts.append(pdict['policy'])
+ paramdict['policy'] = policydicts[0]
# remember parameters for reform documentation
self.param_dict = paramdict
self.policy_dicts = policydicts
# create Behavior object
beh = Behavior()
- beh.update_behavior(paramdict['behavior'])
+ try:
+ beh.update_behavior(paramdict['behavior'])
+ except ValueError as valerr_msg:
+ self.errmsg += valerr_msg.__str__()
self.behavior_has_any_response = beh.has_any_response()
# create gdiff_baseline object
gdiff_baseline = GrowDiff()
- gdiff_baseline.update_growdiff(paramdict['growdiff_baseline'])
+ try:
+ gdiff_baseline.update_growdiff(paramdict['growdiff_baseline'])
+ except ValueError as valerr_msg:
+ self.errmsg += valerr_msg.__str__()
# create GrowFactors base object that incorporates gdiff_baseline
gfactors_base = GrowFactors()
gdiff_baseline.apply_to(gfactors_base)
# specify gdiff_response object
- if growdiff_response is None:
- gdiff_response = GrowDiff()
+ gdiff_response = GrowDiff()
+ try:
gdiff_response.update_growdiff(paramdict['growdiff_response'])
- elif isinstance(growdiff_response, GrowDiff):
- gdiff_response = growdiff_response
- else:
- gdiff_response = None
- msg = 'TaxCalcIO.more_init: growdiff_response is neither None '
- msg += 'nor a GrowDiff object'
- self.errmsg += 'ERROR: {}\n'.format(msg)
- if gdiff_response is not None:
- some_gdiff_response = gdiff_response.has_any_response()
- if self.behavior_has_any_response and some_gdiff_response:
- msg = 'ASSUMP file cannot specify any "behavior" when using '
- msg += 'GrowModel or when ASSUMP file has "growdiff_response"'
- self.errmsg += 'ERROR: {}\n'.format(msg)
- # create GrowFactors ref object that has both gdiff objects applied
+ except ValueError as valerr_msg:
+ self.errmsg += valerr_msg.__str__()
+ # create GrowFactors ref object that has all gdiff objects applied
gfactors_ref = GrowFactors()
gdiff_baseline.apply_to(gfactors_ref)
- if gdiff_response is not None:
- gdiff_response.apply_to(gfactors_ref)
+ gdiff_response.apply_to(gfactors_ref)
+ if growdiff_growmodel:
+ growdiff_growmodel.apply_to(gfactors_ref)
# create Policy objects:
# ... the baseline Policy object
base = Policy(gfactors=gfactors_base)
@@ -305,6 +302,18 @@ def init(self, input_data, tax_year, baseline, reform, assump,
self.errmsg += valerr_msg.__str__()
else:
pol = Policy(gfactors=gfactors_base)
+ # create Consumption object
+ con = Consumption()
+ try:
+ con.update_consumption(paramdict['consumption'])
+ except ValueError as valerr_msg:
+ self.errmsg += valerr_msg.__str__()
+ # create GrowModel object
+ self.growmodel = GrowModel()
+ try:
+ self.growmodel.update_growmodel(paramdict['growmodel'])
+ except ValueError as valerr_msg:
+ self.errmsg += valerr_msg.__str__()
# check for valid tax_year value
if tax_year < pol.start_year:
msg = 'tax_year {} less than policy.start_year {}'
@@ -323,15 +332,18 @@ def init(self, input_data, tax_year, baseline, reform, assump,
# read input file contents into Records objects
if aging_input_data:
if self.cps_input_data:
+ nobenefits = self.growmodel.is_ever_active()
recs = Records.cps_constructor(
gfactors=gfactors_ref,
+ no_benefits=nobenefits,
exact_calculations=exact_calculations
)
recs_base = Records.cps_constructor(
gfactors=gfactors_base,
+ no_benefits=nobenefits,
exact_calculations=exact_calculations
)
- else: # if not cps_input_data
+ else: # if not cps_input_data but aging_input_data
recs = Records(
data=input_data,
gfactors=gfactors_ref,
@@ -355,8 +367,6 @@ def init(self, input_data, tax_year, baseline, reform, assump,
msg = msg.format(tax_year, recs.data_year)
self.errmsg += 'ERROR: {}\n'.format(msg)
# create Calculator objects
- con = Consumption()
- con.update_consumption(paramdict['consumption'])
self.calc = Calculator(policy=pol, records=recs,
verbose=True,
consumption=con,
@@ -453,7 +463,6 @@ def analyze(self, writing_output_file=False,
Nothing
"""
# pylint: disable=too-many-arguments,too-many-branches
- # in order to use print(), pylint: disable=superfluous-parens
if self.calc.reform_warnings:
warn = 'PARAMETER VALUE WARNING(S): {}\n{}{}'
print(warn.format('(read documentation for each parameter)',
@@ -823,15 +832,15 @@ def growmodel_analysis(input_data, tax_year,
progress = 'STARTING ANALYSIS FOR YEAR {}'
gdiff_dict = {Policy.JSON_START_YEAR: {}}
for year in range(Policy.JSON_START_YEAR, tax_year + 1):
- print(progress.format(year)) # pylint: disable=superfluous-parens
- # specify growdiff_response using gdiff_dict
- growdiff_response = GrowDiff()
- growdiff_response.update_growdiff(gdiff_dict)
+ print(progress.format(year))
+ # specify growdiff_growmodel using gdiff_dict
+ growdiff_growmodel = GrowDiff()
+ growdiff_growmodel.update_growdiff(gdiff_dict)
gd_dict = TaxCalcIO.annual_analysis(input_data, tax_year,
baseline, reform, assump,
aging_input_data,
exact_calculations,
- growdiff_response, year,
+ growdiff_growmodel, year,
writing_output_file,
output_tables,
output_graphs,
@@ -844,7 +853,7 @@ def growmodel_analysis(input_data, tax_year,
@staticmethod
def annual_analysis(input_data, tax_year, baseline, reform, assump,
aging_input_data, exact_calculations,
- growdiff_response, year,
+ growdiff_growmodel, year,
writing_output_file,
output_tables,
output_graphs,
@@ -853,7 +862,7 @@ def annual_analysis(input_data, tax_year, baseline, reform, assump,
output_dump,
output_sqldb):
"""
- Conduct static analysis for specifed year and growdiff_response.
+ Conduct static analysis for specifed growdiff_growmodel and year.
Parameters
----------
@@ -868,7 +877,7 @@ def annual_analysis(input_data, tax_year, baseline, reform, assump,
gd_dict: GrowDiff sub-dictionary for year+1
"""
# pylint: disable=too-many-arguments,too-many-locals
- # instantiate TaxCalcIO object for specified year and growdiff_response
+ # instantiate TaxCalcIO object for specified growdiff_growmodel & year
tcio = TaxCalcIO(input_data=input_data,
tax_year=year,
baseline=baseline,
@@ -879,7 +888,7 @@ def annual_analysis(input_data, tax_year, baseline, reform, assump,
baseline=baseline,
reform=reform,
assump=assump,
- growdiff_response=growdiff_response,
+ growdiff_growmodel=growdiff_growmodel,
aging_input_data=aging_input_data,
exact_calculations=exact_calculations)
if year == tax_year:
@@ -902,5 +911,5 @@ def annual_analysis(input_data, tax_year, baseline, reform, assump,
# >>>>> add logic here <<<<<
# ... extract next year GrowModel results for next year gdiff_dict
# >>>>> add logic here <<<<<
- gd_dict = {} # TEMPORARY CODE
+ gd_dict = {} # remove temporary code after GrowModel working
return gd_dict
diff --git a/taxcalc/tbi/__init__.py b/taxcalc/tbi/__init__.py
index 2730759f7..a743058f6 100644
--- a/taxcalc/tbi/__init__.py
+++ b/taxcalc/tbi/__init__.py
@@ -1,3 +1,3 @@
-from taxcalc.tbi.tbi import (run_nth_year_tax_calc_model,
+from taxcalc.tbi.tbi import (run_nth_year_taxcalc_model,
run_nth_year_gdp_elast_model,
reform_warnings_errors)
diff --git a/taxcalc/tbi/tbi.py b/taxcalc/tbi/tbi.py
index 813a50906..4ebda9089 100644
--- a/taxcalc/tbi/tbi.py
+++ b/taxcalc/tbi/tbi.py
@@ -1,5 +1,5 @@
"""
-The public API of the TaxBrain Interface (tbi).
+The public API of the TaxBrain Interface (tbi) to Tax-Calculator.
The tbi functions are used by TaxBrain to call Tax-Calculator in order
to do distributed processing of TaxBrain runs and in order to maintain
@@ -94,13 +94,13 @@ def reform_warnings_errors(user_mods):
return rtn_dict
-def run_nth_year_tax_calc_model(year_n, start_year,
- use_puf_not_cps,
- use_full_sample,
- user_mods,
- return_dict=True):
+def run_nth_year_taxcalc_model(year_n, start_year,
+ use_puf_not_cps,
+ use_full_sample,
+ user_mods,
+ return_dict=True):
"""
- The run_nth_year_tax_calc_model function assumes user_mods is a dictionary
+ The run_nth_year_taxcalc_model function assumes user_mods is a dictionary
returned by the Calculator.read_json_param_objects() function.
Setting use_puf_not_cps=True implies use puf.csv input file;
otherwise, use cps.csv input file.
diff --git a/taxcalc/tbi/tbi_utils.py b/taxcalc/tbi/tbi_utils.py
index 4f31d01f1..2f4bcdf2e 100644
--- a/taxcalc/tbi/tbi_utils.py
+++ b/taxcalc/tbi/tbi_utils.py
@@ -52,7 +52,8 @@ def check_user_mods(user_mods):
raise ValueError('user_mods is not a dictionary')
actual_keys = set(list(user_mods.keys()))
expected_keys = set(['policy', 'consumption', 'behavior',
- 'growdiff_baseline', 'growdiff_response'])
+ 'growdiff_baseline', 'growdiff_response',
+ 'growmodel'])
if actual_keys != expected_keys:
msg = 'actual user_mod keys not equal to expected keys\n'
msg += ' actual: {}\n'.format(actual_keys)
diff --git a/taxcalc/tests/tbi_puf_expect.txt b/taxcalc/tests/tbi_puf_expect.txt
index ec17c66eb..0f92787c2 100644
--- a/taxcalc/tests/tbi_puf_expect.txt
+++ b/taxcalc/tests/tbi_puf_expect.txt
@@ -6,15 +6,15 @@ TABLE aggr_1 RESULTS:
}
TABLE aggr_2 RESULTS:
{
- "combined_tax_2": "3071027632959.20",
- "ind_tax_2": "1866238300205.21",
- "payroll_tax_2": "1204789332753.99"
+ "combined_tax_2": "3070999456514.60",
+ "ind_tax_2": "1866196763220.19",
+ "payroll_tax_2": "1204802693294.41"
}
TABLE aggr_d RESULTS:
{
- "combined_tax_2": "199676418947.41",
- "ind_tax_2": "218413568743.71",
- "payroll_tax_2": "-18737149796.30"
+ "combined_tax_2": "199648242502.82",
+ "ind_tax_2": "218372031758.70",
+ "payroll_tax_2": "-18723789255.88"
}
TABLE diff_comb_xbin RESULTS:
{
@@ -48,13 +48,13 @@ TABLE diff_comb_xbin RESULTS:
],
"$100-200K_2": [
"26217794.11",
- "4636046.17",
- "17.68",
- "15544580.98",
- "59.29",
- "1784.99",
- "46798475834.63",
- "23.46",
+ "4625480.54",
+ "17.64",
+ "15551284.79",
+ "59.32",
+ "1785.30",
+ "46806700988.98",
+ "23.48",
"0.00",
"167887806119.11",
"167887806119.11",
@@ -78,11 +78,11 @@ TABLE diff_comb_xbin RESULTS:
"10571744.15",
"301633.95",
"2.85",
- "9662525.48",
- "91.40",
- "9855.55",
- "104190317230.43",
- "52.22",
+ "9666172.27",
+ "91.43",
+ "9849.75",
+ "104128988953.30",
+ "52.23",
"0.00",
"76102546814.29",
"76102546814.29",
@@ -118,27 +118,27 @@ TABLE diff_comb_xbin RESULTS:
],
"$50-75K_2": [
"25494993.05",
- "3739143.70",
- "14.67",
- "2446836.67",
- "9.60",
- "-11.42",
- "-291057055.77",
- "-0.15",
+ "3714287.97",
+ "14.57",
+ "2493034.17",
+ "9.78",
+ "-10.14",
+ "-258502857.71",
+ "-0.13",
"0.00",
"221912654249.11",
"221912654249.11",
- "-0.94"
+ "-0.95"
],
"$500-1000K_2": [
"1563773.67",
"26290.26",
"1.68",
- "1449099.68",
- "92.67",
- "18495.80",
- "28923245391.79",
- "14.50",
+ "1447715.95",
+ "92.58",
+ "18502.87",
+ "28934296226.34",
+ "14.51",
"0.00",
"10171962362.54",
"10171962362.54",
@@ -146,31 +146,31 @@ TABLE diff_comb_xbin RESULTS:
],
"$75-100K_2": [
"15007692.35",
- "982346.40",
- "6.55",
- "5292161.41",
- "35.26",
- "452.05",
- "6784153526.62",
- "3.40",
+ "1014286.60",
+ "6.76",
+ "5237382.86",
+ "34.90",
+ "443.49",
+ "6655746655.13",
+ "3.34",
"0.00",
"121577992977.43",
"121577992977.43",
- "-2.32"
+ "-2.31"
],
"<$0K_2": [
"1291545.69",
- "344.89",
- "0.03",
- "17957.25",
- "1.39",
- "169.57",
- "219012869.34",
+ "629.11",
+ "0.05",
+ "17510.76",
+ "1.36",
+ "176.94",
+ "228526025.71",
"0.11",
"0.00",
"8349168320.57",
"8349168320.57",
- "0.18"
+ "0.19"
],
"=$0K_2": [
"3638985.32",
@@ -190,10 +190,10 @@ TABLE diff_comb_xbin RESULTS:
"735015.66",
"28043.59",
"3.82",
- "622142.63",
+ "622117.72",
"84.64",
- "17531.76",
- "12886117483.61",
+ "17527.11",
+ "12882696837.73",
"6.46",
"0.00",
"5974366397.29",
@@ -202,12 +202,12 @@ TABLE diff_comb_xbin RESULTS:
],
"ALL_2": [
"177669696.77",
- "9713848.96",
+ "9710652.02",
"5.47",
- "35035304.10",
+ "35035218.52",
"19.72",
- "1122.93",
- "199510265280.64",
+ "1122.19",
+ "199378452829.47",
"100.00",
"0.00",
"1124550420249.70",
@@ -235,15 +235,15 @@ TABLE diff_comb_xdec RESULTS:
"17756353.90",
"629.11",
"0.00",
- "48439.41",
- "0.27",
- "13.43",
- "238480821.82",
- "0.12",
+ "46868.90",
+ "0.26",
+ "10.68",
+ "189604401.10",
+ "0.10",
"0.00",
"14301319109.95",
"14301319109.95",
- "0.31"
+ "0.27"
],
"0-10z_2": [
"0.00",
@@ -317,41 +317,41 @@ TABLE diff_comb_xdec RESULTS:
],
"50-60_2": [
"17763938.42",
- "93566.25",
- "0.53",
- "22361.82",
- "0.13",
- "1.90",
- "33726400.47",
+ "70624.93",
+ "0.40",
+ "39098.60",
+ "0.22",
+ "2.71",
+ "48165942.75",
"0.02",
"0.00",
"164240886768.18",
"164240886768.18",
- "-0.03"
+ "-0.04"
],
"60-70_2": [
"17774068.83",
- "3599333.12",
- "20.25",
- "2706772.37",
- "15.23",
- "-5.11",
- "-90785994.49",
- "-0.05",
+ "3635998.68",
+ "20.46",
+ "2637969.75",
+ "14.84",
+ "-8.06",
+ "-143182077.48",
+ "-0.07",
"0.00",
"148349191499.97",
"148349191499.97",
- "-1.33"
+ "-1.32"
],
"70-80_2": [
"17766155.43",
- "1074883.10",
- "6.05",
- "6228785.65",
- "35.06",
- "529.05",
- "9399176563.95",
- "4.73",
+ "1081301.50",
+ "6.09",
+ "6218483.09",
+ "35.00",
+ "525.49",
+ "9335967794.17",
+ "4.70",
"0.00",
"144044351221.75",
"144044351221.75",
@@ -359,27 +359,27 @@ TABLE diff_comb_xdec RESULTS:
],
"80-90_2": [
"17758301.12",
- "4283846.13",
- "24.12",
- "9832938.80",
- "55.37",
- "1418.05",
- "25182135855.38",
- "12.67",
+ "4295808.93",
+ "24.19",
+ "9864229.53",
+ "55.55",
+ "1418.93",
+ "25197759194.80",
+ "12.68",
"0.00",
"120586584970.06",
"120586584970.06",
- "-4.52"
+ "-4.54"
],
"90-100_2": [
"17781787.75",
"625472.39",
"3.52",
- "16109083.12",
- "90.59",
- "9221.98",
- "163983334828.74",
- "82.51",
+ "16145503.99",
+ "90.80",
+ "9232.21",
+ "164165115048.99",
+ "82.58",
"0.00",
"111391848966.64",
"111391848966.64",
@@ -389,38 +389,38 @@ TABLE diff_comb_xdec RESULTS:
"8889233.24",
"405402.56",
"4.56",
- "8073179.21",
- "90.82",
- "5002.97",
- "44472534592.78",
- "22.38",
+ "8093119.26",
+ "91.04",
+ "5014.97",
+ "44579219402.60",
+ "22.42",
"0.00",
"47506446768.10",
"47506446768.10",
- "-7.01"
+ "-7.03"
],
"95-99_2": [
"7115702.98",
"172530.31",
"2.42",
- "6452221.03",
- "90.68",
- "12279.56",
- "87377710751.45",
- "43.96",
+ "6470139.73",
+ "90.93",
+ "12294.98",
+ "87487434001.11",
+ "44.01",
"0.00",
"50761464897.83",
"50761464897.83",
- "-6.88"
+ "-6.89"
],
"ALL_2": [
"177669696.77",
- "9677730.10",
- "5.45",
- "34948381.17",
+ "9709835.54",
+ "5.47",
+ "34952153.86",
"19.67",
- "1118.63",
- "198746068475.86",
+ "1118.89",
+ "198793430304.33",
"100.00",
"0.00",
"1124550420249.70",
@@ -431,11 +431,11 @@ TABLE diff_comb_xdec RESULTS:
"1776851.53",
"47539.52",
"2.68",
- "1583682.89",
- "89.13",
- "18084.28",
- "32133089484.52",
- "16.17",
+ "1582245.00",
+ "89.05",
+ "18064.80",
+ "32098461645.28",
+ "16.15",
"0.00",
"13123937300.71",
"13123937300.71",
@@ -476,11 +476,11 @@ TABLE diff_itax_xbin RESULTS:
"26217794.11",
"3203478.90",
"12.22",
- "16977148.25",
- "64.75",
- "2170.96",
- "56917758095.76",
- "26.09",
+ "16973286.42",
+ "64.74",
+ "2171.03",
+ "56919602570.21",
+ "26.11",
"0.00",
"167887806119.11",
"167887806119.11",
@@ -504,10 +504,10 @@ TABLE diff_itax_xbin RESULTS:
"10571744.15",
"279091.68",
"2.64",
- "9685067.76",
- "91.61",
- "10314.41",
- "109041291125.43",
+ "9688714.55",
+ "91.65",
+ "10308.57",
+ "108979584743.40",
"49.98",
"0.00",
"76102546814.29",
@@ -544,27 +544,27 @@ TABLE diff_itax_xbin RESULTS:
],
"$50-75K_2": [
"25494993.05",
- "2502390.99",
- "9.82",
- "3683589.39",
- "14.45",
- "47.02",
- "1198847118.11",
- "0.55",
+ "2497072.10",
+ "9.79",
+ "3710250.04",
+ "14.55",
+ "48.44",
+ "1234923284.78",
+ "0.57",
"0.00",
"221912654249.11",
"221912654249.11",
- "-0.94"
+ "-0.95"
],
"$500-1000K_2": [
"1563773.67",
"22566.38",
"1.44",
- "1452823.55",
- "92.90",
- "18579.31",
- "29053841996.90",
- "13.32",
+ "1451439.82",
+ "92.82",
+ "18586.38",
+ "29064892831.47",
+ "13.33",
"0.00",
"10171962362.54",
"10171962362.54",
@@ -572,31 +572,31 @@ TABLE diff_itax_xbin RESULTS:
],
"$75-100K_2": [
"15007692.35",
- "704043.33",
- "4.69",
- "5570464.47",
- "37.12",
- "587.62",
- "8818825713.59",
- "4.04",
+ "735983.54",
+ "4.90",
+ "5515685.92",
+ "36.75",
+ "579.33",
+ "8694464595.34",
+ "3.99",
"0.00",
"121577992977.43",
"121577992977.43",
- "-2.32"
+ "-2.31"
],
"<$0K_2": [
"1291545.69",
- "344.89",
- "0.03",
- "17957.25",
- "1.39",
- "171.95",
- "222076490.28",
- "0.10",
+ "629.11",
+ "0.05",
+ "17510.76",
+ "1.36",
+ "179.33",
+ "231608918.68",
+ "0.11",
"0.00",
"8349168320.57",
"8349168320.57",
- "0.18"
+ "0.19"
],
"=$0K_2": [
"3638985.32",
@@ -616,10 +616,10 @@ TABLE diff_itax_xbin RESULTS:
"735015.66",
"27542.75",
"3.75",
- "622643.46",
+ "622618.56",
"84.71",
- "17573.71",
- "12916955312.92",
+ "17569.06",
+ "12913534667.04",
"5.92",
"0.00",
"5974366397.29",
@@ -628,12 +628,12 @@ TABLE diff_itax_xbin RESULTS:
],
"ALL_2": [
"177669696.77",
- "6739458.94",
- "3.79",
- "38009694.13",
- "21.39",
- "1227.95",
- "218169595852.99",
+ "6766364.47",
+ "3.81",
+ "37979506.06",
+ "21.38",
+ "1227.21",
+ "218038611610.93",
"100.00",
"0.00",
"1124550420249.70",
@@ -661,15 +661,15 @@ TABLE diff_itax_xdec RESULTS:
"17756353.90",
"629.11",
"0.00",
- "48439.41",
- "0.27",
- "14.23",
- "252651956.95",
- "0.12",
+ "46868.90",
+ "0.26",
+ "11.48",
+ "203775536.24",
+ "0.09",
"0.00",
"14301319109.95",
"14301319109.95",
- "0.31"
+ "0.27"
],
"0-10z_2": [
"0.00",
@@ -743,41 +743,41 @@ TABLE diff_itax_xdec RESULTS:
],
"50-60_2": [
"17763938.42",
- "93566.25",
- "0.53",
- "22361.82",
- "0.13",
- "3.20",
- "56893672.67",
+ "70624.93",
+ "0.40",
+ "39098.60",
+ "0.22",
+ "3.95",
+ "70245130.08",
"0.03",
"0.00",
"164240886768.18",
"164240886768.18",
- "-0.03"
+ "-0.04"
],
"60-70_2": [
"17774068.83",
- "2344426.10",
- "13.19",
- "3961679.39",
- "22.29",
- "81.74",
- "1452826926.04",
- "0.67",
+ "2381091.66",
+ "13.40",
+ "3892876.77",
+ "21.90",
+ "78.29",
+ "1391606013.70",
+ "0.64",
"0.00",
"148349191499.97",
"148349191499.97",
- "-1.33"
+ "-1.32"
],
"70-80_2": [
"17766155.43",
- "756202.27",
- "4.26",
- "6547466.49",
- "36.85",
- "667.76",
- "11863607822.21",
- "5.46",
+ "762620.67",
+ "4.29",
+ "6537163.92",
+ "36.80",
+ "664.01",
+ "11796920665.86",
+ "5.43",
"0.00",
"144044351221.75",
"144044351221.75",
@@ -785,27 +785,27 @@ TABLE diff_itax_xdec RESULTS:
],
"80-90_2": [
"17758301.12",
- "2967874.19",
- "16.71",
- "11148910.74",
- "62.78",
- "1790.06",
- "31788410909.76",
- "14.63",
+ "2995311.79",
+ "16.87",
+ "11164726.67",
+ "62.87",
+ "1791.97",
+ "31822268905.17",
+ "14.64",
"0.00",
"120586584970.06",
"120586584970.06",
- "-4.52"
+ "-4.54"
],
"90-100_2": [
"17781787.75",
"508916.20",
"2.86",
- "16225639.31",
- "91.25",
- "9668.85",
- "171929351383.94",
- "79.10",
+ "16262060.18",
+ "91.45",
+ "9680.73",
+ "172140600895.45",
+ "79.17",
"0.00",
"111391848966.64",
"111391848966.64",
@@ -815,38 +815,38 @@ TABLE diff_itax_xdec RESULTS:
"8889233.24",
"312420.95",
"3.51",
- "8166160.82",
- "91.87",
- "5578.13",
- "49585337268.87",
- "22.81",
+ "8186100.87",
+ "92.09",
+ "5592.15",
+ "49709963239.92",
+ "22.86",
"0.00",
"47506446768.10",
"47506446768.10",
- "-7.01"
+ "-7.03"
],
"95-99_2": [
"7115702.98",
"149924.40",
"2.11",
- "6474826.94",
- "90.99",
- "12662.00",
- "90099017780.09",
- "41.45",
+ "6492745.65",
+ "91.25",
+ "12679.04",
+ "90220269159.79",
+ "41.49",
"0.00",
"50761464897.83",
"50761464897.83",
- "-6.88"
+ "-6.89"
],
"ALL_2": [
"177669696.77",
- "6671614.12",
- "3.76",
- "37954497.15",
+ "6719194.35",
+ "3.78",
+ "37942795.05",
"21.36",
- "1223.30",
- "217343742671.57",
+ "1223.76",
+ "217425417146.49",
"100.00",
"0.00",
"1124550420249.70",
@@ -857,11 +857,11 @@ TABLE diff_itax_xdec RESULTS:
"1776851.53",
"46570.85",
"2.62",
- "1584651.56",
- "89.18",
- "18147.27",
- "32244996334.98",
- "14.84",
+ "1583213.67",
+ "89.10",
+ "18127.78",
+ "32210368495.73",
+ "14.81",
"0.00",
"13123937300.71",
"13123937300.71",
@@ -900,13 +900,13 @@ TABLE diff_ptax_xbin RESULTS:
],
"$100-200K_2": [
"26217794.11",
- "18582269.15",
- "70.88",
+ "18580412.45",
+ "70.87",
"0.00",
"0.00",
- "-385.97",
- "-10119282261.13",
- "54.23",
+ "-385.73",
+ "-10112901581.24",
+ "54.20",
"0.00",
"167887806119.11",
"167887806119.11",
@@ -928,13 +928,13 @@ TABLE diff_ptax_xbin RESULTS:
],
"$200-500K_2": [
"10571744.15",
- "7222035.27",
- "68.31",
+ "7219164.83",
+ "68.29",
"1287.47",
"0.01",
- "-458.86",
- "-4850973894.99",
- "26.00",
+ "-458.83",
+ "-4850595790.10",
+ "25.99",
"0.00",
"76102546814.29",
"76102546814.29",
@@ -970,17 +970,17 @@ TABLE diff_ptax_xbin RESULTS:
],
"$50-75K_2": [
"25494993.05",
- "5399736.31",
- "21.18",
+ "5421078.07",
+ "21.26",
"0.00",
"0.00",
- "-58.44",
- "-1489904173.88",
- "7.98",
+ "-58.58",
+ "-1493426142.49",
+ "8.00",
"0.00",
"221912654249.11",
"221912654249.11",
- "-0.94"
+ "-0.95"
],
"$500-1000K_2": [
"1563773.67",
@@ -989,7 +989,7 @@ TABLE diff_ptax_xbin RESULTS:
"15562.36",
"1.00",
"-83.51",
- "-130596605.11",
+ "-130596605.13",
"0.70",
"0.00",
"10171962362.54",
@@ -998,31 +998,31 @@ TABLE diff_ptax_xbin RESULTS:
],
"$75-100K_2": [
"15007692.35",
- "5365349.82",
- "35.75",
+ "5342505.55",
+ "35.60",
"0.00",
"0.00",
- "-135.58",
- "-2034672186.97",
- "10.90",
+ "-135.84",
+ "-2038717940.21",
+ "10.93",
"0.00",
"121577992977.43",
"121577992977.43",
- "-2.32"
+ "-2.31"
],
"<$0K_2": [
"1291545.69",
- "5278.77",
+ "5351.89",
"0.41",
"0.00",
"0.00",
- "-2.37",
- "-3063620.94",
+ "-2.39",
+ "-3082892.97",
"0.02",
"0.00",
"8349168320.57",
"8349168320.57",
- "0.18"
+ "0.19"
],
"=$0K_2": [
"3638985.32",
@@ -1054,12 +1054,12 @@ TABLE diff_ptax_xbin RESULTS:
],
"ALL_2": [
"177669696.77",
- "36899080.93",
- "20.77",
+ "36892924.41",
+ "20.76",
"35691.35",
"0.02",
- "-105.02",
- "-18659330572.35",
+ "-105.03",
+ "-18660158781.46",
"100.00",
"0.00",
"1124550420249.70",
@@ -1090,12 +1090,12 @@ TABLE diff_ptax_xdec RESULTS:
"0.00",
"0.00",
"-0.80",
- "-14171135.13",
+ "-14171135.14",
"0.08",
"0.00",
"14301319109.95",
"14301319109.95",
- "0.31"
+ "0.27"
],
"0-10z_2": [
"0.00",
@@ -1169,41 +1169,41 @@ TABLE diff_ptax_xdec RESULTS:
],
"50-60_2": [
"17763938.42",
- "103839.17",
- "0.58",
+ "95172.53",
+ "0.54",
"0.00",
"0.00",
- "-1.30",
- "-23167272.20",
+ "-1.24",
+ "-22079187.33",
"0.12",
"0.00",
"164240886768.18",
"164240886768.18",
- "-0.03"
+ "-0.04"
],
"60-70_2": [
"17774068.83",
- "5521670.68",
- "31.07",
+ "5487176.28",
+ "30.87",
"0.00",
"0.00",
- "-86.85",
- "-1543612920.53",
- "8.30",
+ "-86.35",
+ "-1534788091.18",
+ "8.24",
"0.00",
"148349191499.97",
"148349191499.97",
- "-1.33"
+ "-1.32"
],
"70-80_2": [
"17766155.43",
- "6237994.83",
- "35.11",
+ "6234110.67",
+ "35.09",
"0.00",
"0.00",
- "-138.71",
- "-2464431258.26",
- "13.25",
+ "-138.52",
+ "-2460952871.69",
+ "13.21",
"0.00",
"144044351221.75",
"144044351221.75",
@@ -1211,27 +1211,27 @@ TABLE diff_ptax_xdec RESULTS:
],
"80-90_2": [
"17758301.12",
- "13066057.69",
- "73.58",
+ "13079493.55",
+ "73.65",
"0.00",
"0.00",
- "-372.01",
- "-6606275054.39",
- "35.52",
+ "-373.04",
+ "-6624509710.37",
+ "35.55",
"0.00",
"120586584970.06",
"120586584970.06",
- "-4.52"
+ "-4.54"
],
"90-100_2": [
"17781787.75",
- "11866585.61",
- "66.73",
+ "11882409.45",
+ "66.82",
"35691.35",
"0.20",
- "-446.86",
- "-7946016555.19",
- "42.73",
+ "-448.52",
+ "-7975485846.46",
+ "42.81",
"0.00",
"111391848966.64",
"111391848966.64",
@@ -1239,40 +1239,40 @@ TABLE diff_ptax_xdec RESULTS:
],
"90-95_2": [
"8889233.24",
- "7434400.41",
- "83.63",
+ "7443944.80",
+ "83.74",
"0.00",
"0.00",
- "-575.17",
- "-5112802676.09",
- "27.49",
+ "-577.19",
+ "-5130743837.32",
+ "27.54",
"0.00",
"47506446768.10",
"47506446768.10",
- "-7.01"
+ "-7.03"
],
"95-99_2": [
"7115702.98",
- "4203090.39",
- "59.07",
+ "4209369.84",
+ "59.16",
"1287.47",
"0.02",
- "-382.44",
- "-2721307028.64",
- "14.63",
+ "-384.06",
+ "-2732835158.68",
+ "14.67",
"0.00",
"50761464897.83",
"50761464897.83",
- "-6.88"
+ "-6.89"
],
"ALL_2": [
"177669696.77",
- "36832526.35",
- "20.73",
+ "36814740.86",
+ "20.72",
"35691.35",
"0.02",
- "-104.68",
- "-18597674195.70",
+ "-104.87",
+ "-18631986842.16",
"100.00",
"0.00",
"1124550420249.70",
@@ -2136,29 +2136,29 @@ TABLE dist2_xbin RESULTS:
],
"$100-200K_2": [
"26217794.11",
- "3215113684241.75",
+ "3215152793539.49",
"19846861.08",
"462020298143.30",
"6370933.02",
- "180170532833.10",
+ "180172864932.59",
"0.00",
- "2547387197976.15",
- "445024720779.98",
- "3090134273314.42",
+ "2547423975174.41",
+ "445022684609.62",
+ "3090170504113.48",
"104686.68",
"1256608536.93",
- "446281329316.91",
- "39785551431.75",
+ "446279293146.54",
+ "39781670786.94",
"1496464129.54",
"3134840112.24",
- "404857401902.45",
- "389314973943.23",
- "794172375845.68",
+ "404859246376.90",
+ "389321354623.12",
+ "794180601000.02",
"0.00",
"167887806119.11",
"167887806119.11",
- "3546669243395.81",
- "2752496867550.13"
+ "3546711543033.50",
+ "2752530942033.48"
],
"$20-30K_2": [
"18322948.33",
@@ -2188,29 +2188,29 @@ TABLE dist2_xbin RESULTS:
],
"$200-500K_2": [
"10571744.15",
- "2585968885681.84",
+ "2585966230528.22",
"5164580.25",
"125903906541.97",
"5407163.90",
- "193383634420.80",
- "0.00",
- "2226290557299.72",
- "547957022614.81",
- "2442078280110.95",
- "56033.42",
- "1051182724.38",
- "549008205339.19",
+ "193386889020.85",
+ "0.00",
+ "2226285259543.83",
+ "547900297072.76",
+ "2442072370357.27",
+ "53665.40",
+ "1046204510.83",
+ "548946501583.59",
"17427204251.29",
- "5361380602.58",
+ "5361377976.16",
"261177438.90",
- "536681204251.58",
- "251286957218.92",
- "787968161470.50",
+ "536619497869.56",
+ "251287335323.81",
+ "787906833193.37",
"0.00",
"76102546814.29",
"76102546814.29",
- "2935880501462.48",
- "2147912339991.98"
+ "2935878025942.52",
+ "2147971192749.14"
],
"$30-40K_2": [
"17705590.16",
@@ -2266,107 +2266,107 @@ TABLE dist2_xbin RESULTS:
],
"$50-75K_2": [
"25494993.05",
- "1318973782611.88",
+ "1318940845005.52",
"23581012.42",
"451910838182.52",
"1913980.64",
- "41889656935.04",
+ "41909560007.98",
"0.00",
- "833132568140.50",
- "98000902608.09",
- "1287650491322.55",
+ "833079727461.20",
+ "98036978774.76",
+ "1287597650643.25",
"221774.34",
"700357427.20",
- "98701260035.29",
+ "98737336201.96",
"21423256957.90",
"859058787.08",
"7867773679.96",
- "70269288184.51",
- "148447267717.55",
- "218716555902.06",
+ "70305364351.18",
+ "148443745748.94",
+ "218749110100.12",
"0.00",
"221912654249.11",
"221912654249.11",
- "1554864584037.43",
- "1336148028135.37"
+ "1554829885446.77",
+ "1336080775346.65"
],
"$500-1000K_2": [
"1563773.67",
- "891958252480.78",
+ "891962108087.02",
"566354.49",
"13614279236.82",
"996751.53",
- "49635644435.69",
+ "49636422654.50",
"0.00",
- "815119983545.76",
- "233887631475.85",
- "862491503688.15",
+ "815123060933.20",
+ "233898421260.75",
+ "862494581075.58",
"30770.13",
"1762705795.79",
- "235650337271.64",
- "6502373274.22",
- "4613266548.35",
+ "235661127056.55",
+ "6502258737.59",
+ "4613413061.38",
"3221873.67",
- "233758008672.09",
- "53409722610.38",
- "287167731282.47",
+ "233769059506.66",
+ "53409722610.36",
+ "287178782117.02",
"0.00",
"10171962362.54",
"10171962362.54",
- "1059969922925.92",
- "772802191643.45"
+ "1059973778532.15",
+ "772794996415.13"
],
"$75-100K_2": [
"15007692.35",
- "1161677935944.12",
+ "1161651688927.14",
"12749049.15",
"266719087487.81",
"2258400.89",
- "54311978295.86",
+ "54308558398.59",
"0.00",
- "830503718879.66",
- "117552561239.18",
- "1120074867132.31",
+ "830480891759.95",
+ "117484654700.57",
+ "1120052040012.60",
"29188.56",
"132971281.87",
- "117685532521.05",
- "14694380685.50",
+ "117617625982.44",
+ "14728253433.28",
"1148450344.86",
- "1651641922.55",
- "102487960257.87",
- "124047363133.48",
- "226535323391.35",
+ "1674223754.41",
+ "102363599139.62",
+ "124043317380.24",
+ "226406916519.85",
"0.00",
"121577992977.43",
"121577992977.43",
- "1275658367425.65",
- "1049123044034.30"
+ "1275630097532.05",
+ "1049223181012.20"
],
"<$0K_2": [
"1291545.69",
- "-41339747933.75",
+ "-41349033835.13",
"1272676.70",
"22455810794.64",
"16680.45",
- "1077012957.75",
- "0.00",
- "20496895200.13",
- "3790739671.67",
- "-44372733677.56",
- "1505.48",
- "614748880.70",
- "4405488552.37",
+ "1073854667.37",
+ "0.00",
+ "20490767589.12",
+ "3800770792.04",
+ "-44378861288.56",
+ "1272.06",
+ "614418347.03",
+ "4415189139.07",
"265524412.88",
- "264948115.34",
+ "264779957.05",
"283060233.20",
- "4121852021.63",
- "3499954796.19",
- "7621806817.82",
+ "4131384450.03",
+ "3499935524.16",
+ "7631319974.19",
"0.00",
"8349168320.57",
"8349168320.57",
- "-161739518978.85",
- "-169361325796.67"
+ "-161748815528.54",
+ "-169380135502.72"
],
"=$0K_2": [
"3638985.32",
@@ -2403,48 +2403,48 @@ TABLE dist2_xbin RESULTS:
"65351143335.80",
"0.00",
"1830214491659.21",
- "540588125933.45",
+ "540584705287.57",
"1955115787734.10",
"70596.07",
"25593495506.21",
- "566181621439.66",
+ "566178200793.78",
"12570071595.02",
"29645599089.13",
"3335962.21",
- "583253812971.57",
+ "583250392325.69",
"39058114640.14",
- "622311927611.71",
+ "622308506965.83",
"0.00",
"5974366397.29",
"5974366397.29",
"2178462090550.57",
- "1556150162938.86"
+ "1556153583584.74"
],
"ALL_2": [
"177669696.77",
- "12588267809400.07",
+ "12588239648625.71",
"158949593.31",
"2806682758281.83",
"18714665.39",
- "607334679334.53",
- "0.00",
- "9655183451655.38",
- "2044555069538.27",
- "12223065647422.22",
- "761515.42",
- "31618342198.52",
- "2076173411736.79",
- "132053613902.55",
- "44219562691.71",
- "122345033211.46",
- "1865994327314.49",
- "1204867151977.94",
- "3070861479292.43",
+ "607354369138.17",
+ "0.00",
+ "9655136213075.18",
+ "2044481877713.30",
+ "12223017250445.04",
+ "758913.99",
+ "31613033451.30",
+ "2076094911164.61",
+ "132083491468.89",
+ "44219538420.03",
+ "122367615043.32",
+ "1865863343072.42",
+ "1204866323768.83",
+ "3070729666841.26",
"0.00",
"1124550420249.70",
"1124550420249.70",
- "14513625842311.35",
- "11442764363018.92"
+ "14513597257001.36",
+ "11442867590160.10"
]
}
TABLE dist2_xdec RESULTS:
@@ -2477,29 +2477,29 @@ TABLE dist2_xdec RESULTS:
],
"0-10p_2": [
"17756353.90",
- "-8143858122.11",
+ "-8143858122.16",
"17737484.90",
"200468106646.10",
"16680.45",
"1075733386.67",
"0.00",
- "22656666026.37",
- "4104817254.03",
- "-11177952238.75",
+ "22656666026.32",
+ "4055940833.31",
+ "-11177952238.82",
"1505.48",
"614646029.18",
- "4719463283.21",
+ "4670586862.50",
"265636070.37",
"268157309.03",
"3750046624.14",
- "971937897.73",
+ "923061477.01",
"8368520700.81",
- "9340458598.54",
+ "9291582177.82",
"0.00",
"14301319109.95",
"14301319109.95",
- "-125284725674.48",
- "-134625184273.02"
+ "-125284725674.53",
+ "-134576307852.35"
],
"0-10z_2": [
"0.00",
@@ -2633,211 +2633,211 @@ TABLE dist2_xdec RESULTS:
],
"50-60_2": [
"17763938.42",
- "705504004611.70",
+ "705505379722.52",
"16814575.80",
"312164956793.88",
"948694.96",
- "22478890701.47",
+ "22477552166.21",
"0.00",
- "398484339485.56",
- "42322832357.42",
- "688085825786.56",
+ "398487053131.64",
+ "42336183814.84",
+ "688088539432.64",
"105132.77",
"214449231.89",
- "42537281589.32",
+ "42550633046.73",
"12006393824.95",
"593756811.65",
"9648501950.75",
- "21476142625.27",
- "78958579151.26",
- "100434721776.53",
+ "21489494082.68",
+ "78959667236.13",
+ "100449161318.81",
"0.00",
"164240886768.18",
"164240886768.18",
- "887642173361.41",
- "787207451584.89"
+ "887644092514.67",
+ "787194931195.85"
],
"60-70_2": [
"17774068.83",
- "1001273820368.86",
+ "1001328276328.25",
"16420923.78",
"318435445395.73",
"1353145.06",
- "27371615731.89",
+ "27343910110.81",
"0.00",
- "653807523590.97",
- "80097789061.61",
- "981020751352.90",
+ "653889685171.44",
+ "80036568149.27",
+ "981102912933.38",
"123667.35",
"529406160.21",
- "80627195221.83",
+ "80565974309.49",
"16237359444.81",
"475097780.36",
"4046860327.91",
- "60818073229.47",
- "114922534829.43",
- "175740608058.90",
+ "60756852317.13",
+ "114931359658.77",
+ "175688211975.90",
"0.00",
"148349191499.97",
"148349191499.97",
- "1159257099292.82",
- "983516491233.93"
+ "1159315967666.89",
+ "983627755690.99"
],
"70-80_2": [
"17766155.43",
- "1437963418964.47",
- "14746849.25",
- "311886228743.76",
- "3019063.86",
- "73636464127.32",
- "0.00",
- "1038528413067.45",
- "148433995771.72",
- "1382874275415.32",
+ "1437968133981.88",
+ "14753267.65",
+ "311976963091.74",
+ "3012645.46",
+ "73545182244.43",
+ "0.00",
+ "1038533675619.78",
+ "148367308615.37",
+ "1382920805820.68",
"29188.56",
"132971281.87",
- "148566967053.59",
+ "148500279897.24",
"18880140613.57",
"1265307859.34",
"2060178829.65",
- "128891955469.71",
- "156788096662.34",
- "285680052132.05",
+ "128825268313.36",
+ "156791575048.91",
+ "285616843362.28",
"0.00",
"144044351221.75",
"144044351221.75",
- "1581805507828.29",
- "1296125455696.24"
+ "1581811962038.99",
+ "1296195118676.72"
],
"80-90_2": [
"17758301.12",
- "2103018595978.72",
+ "2102823759666.52",
"13559924.62",
"315613454394.17",
"4198376.50",
- "117176729681.31",
+ "117170197738.04",
"0.00",
- "1653981579788.75",
- "277608993412.97",
- "2017080676145.75",
+ "1653793275419.82",
+ "277642851408.37",
+ "2016888616683.06",
"60655.99",
"70730709.27",
- "277679724122.23",
+ "277713582117.64",
"24619007046.40",
"1228440860.01",
"1625767475.72",
- "252663390460.12",
- "251832999150.71",
- "504496389610.84",
+ "252697248455.53",
+ "251814764494.73",
+ "504512012950.26",
"0.00",
"120586584970.06",
"120586584970.06",
- "2312152459505.38",
- "1807656069894.55"
+ "2311948505865.19",
+ "1807436492914.93"
],
"90-100_2": [
"17781787.75",
- "6190647669967.61",
+ "6190392294133.41",
"9417467.29",
"228587143371.83",
"8362648.56",
- "352008583992.56",
+ "351961839701.98",
"0.00",
- "5522478564699.55",
- "1453442687911.73",
- "6018420695096.28",
+ "5522269933155.94",
+ "1453653576024.11",
+ "6018212063552.66",
"199062.29",
"29588283640.50",
- "1483030971552.23",
- "46610218165.73",
- "39770822167.71",
- "1197312053.68",
- "1474994263500.53",
- "442216200265.63",
- "1917210463766.16",
+ "1483241859664.61",
+ "46609827026.96",
+ "39770618147.37",
+ "1197137772.99",
+ "1475205513012.03",
+ "442186730974.37",
+ "1917392243986.40",
"0.00",
"111391848966.64",
"111391848966.64",
- "7044440850075.64",
- "5127230386309.48"
+ "7044171054426.22",
+ "5126778810439.82"
],
"90-95_2": [
"8889233.24",
- "1531624201822.30",
+ "1531443182306.27",
"5868858.39",
"142853779498.47",
"3020374.85",
- "96858491254.20",
+ "96819614550.70",
"0.00",
- "1276963834416.31",
- "272067199249.98",
- "1466261146009.15",
+ "1276821691603.78",
+ "272191389519.29",
+ "1466119003196.63",
"49564.22",
"1252991660.62",
- "273320190910.60",
- "16023169328.34",
+ "273444381179.91",
+ "16022907907.30",
"920821558.61",
- "970216507.57",
- "257247626633.30",
- "181820499190.05",
- "439068125823.34",
+ "970042226.87",
+ "257372252604.34",
+ "181802558028.82",
+ "439174810633.17",
"0.00",
"47506446768.10",
"47506446768.10",
- "1721269194055.49",
- "1282201068232.15"
+ "1721079203958.86",
+ "1281904393325.69"
],
"95-99_2": [
"7115702.98",
- "2072167937087.10",
+ "2072093580768.93",
"2997955.91",
"72462342288.25",
"4117747.06",
- "153665723721.73",
+ "153657856134.65",
"0.00",
- "1811785870447.72",
- "465817233873.38",
- "1960571011860.26",
+ "1811719381716.64",
+ "465938559555.69",
+ "1960504523129.18",
"51811.08",
"1366906032.25",
- "467184139905.63",
- "12609914734.53",
- "5399634524.96",
+ "467305465587.94",
+ "12609785016.81",
+ "5399430504.62",
"223738110.37",
- "459750121585.68",
- "184385269555.50",
- "644135391141.18",
+ "459871372965.39",
+ "184373741425.45",
+ "644245114390.84",
"0.00",
"50761464897.83",
"50761464897.83",
- "2364912285402.01",
- "1720776894260.83"
+ "2364832479849.22",
+ "1720587365458.38"
],
"ALL_2": [
"177669696.77",
- "12588888577727.71",
- "158943174.91",
- "2806592023933.85",
- "18721083.79",
- "607495151542.31",
- "0.00",
- "9655734482123.21",
- "2043791448670.83",
- "12223579165130.80",
+ "12588498911668.88",
+ "158949593.31",
+ "2806682758281.83",
+ "18714665.39",
+ "607321549269.23",
+ "0.00",
+ "9655427683989.49",
+ "2043872761746.62",
+ "12223309879756.34",
"758913.99",
"31613033451.30",
- "2075404482122.13",
- "132087486650.34",
- "44219093704.58",
- "122367615043.32",
- "1865168474133.06",
- "1204928808354.59",
- "3070097282487.65",
+ "2075485795197.93",
+ "132087095511.57",
+ "44218889684.24",
+ "122367440762.62",
+ "1865250148607.98",
+ "1204894495708.13",
+ "3070144644316.11",
"0.00",
"1124550420249.70",
"1124550420249.70",
- "14514277111713.36",
- "11444179829225.71"
+ "14513870604161.71",
+ "11443725959845.60"
],
"Top 1%_2": [
"1776851.53",
@@ -2848,21 +2848,21 @@ TABLE dist2_xdec RESULTS:
"101484369016.63",
"0.00",
"2433728859835.52",
- "715558254788.38",
+ "715523626949.14",
"2591588537226.86",
"97687.00",
"26968385947.62",
- "742526640736.00",
+ "742492012896.76",
"17977134102.85",
"33450366084.14",
"3357435.74",
- "757996515281.55",
+ "757961887442.30",
"76010431520.09",
- "834006946801.64",
+ "833972318962.40",
"0.00",
"13123937300.71",
"13123937300.71",
"2958259370618.14",
- "2124252423816.50"
+ "2124287051655.74"
]
}
diff --git a/taxcalc/tests/test_calculate.py b/taxcalc/tests/test_calculate.py
index 17f74748f..a45e2d7ab 100644
--- a/taxcalc/tests/test_calculate.py
+++ b/taxcalc/tests/test_calculate.py
@@ -442,7 +442,8 @@ def fixture_reform_file():
"consumption": { "_MPC_e18400": {"2018": [0.05]} },
"behavior": {},
"growdiff_baseline": {},
- "growdiff_response": {}
+ "growdiff_response": {},
+ "growmodel": {}
}
"""
@@ -575,6 +576,10 @@ def test_read_bad_json_reform_file(bad1reformfile, bad2reformfile,
Calculator.read_json_param_objects(bad3reformfile.name, None)
with pytest.raises(ValueError):
Calculator.read_json_param_objects(list(), None)
+ with pytest.raises(ValueError):
+ Calculator.read_json_param_objects(None, 'unknown_file_name')
+ with pytest.raises(ValueError):
+ Calculator.read_json_param_objects(None, list())
@pytest.fixture(scope='module', name='bad1assumpfile')
@@ -587,7 +592,8 @@ def fixture_bad1assumpfile():
'x': {"2014": [0.25]}
},
"growdiff_baseline": {},
- "growdiff_response": {}
+ "growdiff_response": {},
+ "growmodel": {}
}
"""
f = tempfile.NamedTemporaryFile(mode='a', delete=False)
@@ -606,7 +612,8 @@ def fixture_bad2assumpfile():
"consumption": {},
"behaviorx": {}, // example of assump file not containing "behavior" key
"growdiff_baseline": {},
- "growdiff_response": {}
+ "growdiff_response": {},
+ "growmodel": {}
}
"""
f = tempfile.NamedTemporaryFile(mode='a', delete=False)
@@ -628,27 +635,8 @@ def fixture_bad3assumpfile():
"growdiff_response": {},
"policy": { // example of misplaced policy key
"_SS_Earnings_c": {"2018": [9e99]}
- }
- }
- """
- f = tempfile.NamedTemporaryFile(mode='a', delete=False)
- f.write(txt + '\n')
- f.close()
- # Must close and then yield for Windows platform
- yield f
- os.remove(f.name)
-
-
-@pytest.fixture(scope='module', name='bad4assumpfile')
-def fixture_bad4assumpfile():
- # specify JSON text for assump
- txt = """
- {
- "consumption": {},
- "behavior": {},
- "behavior": {"_BE_sub": {"2014": [0.25]}},
- "growdiff_baseline": {},
- "growdiff_response": {"_ABOOK": {"2022": [0.01]}}
+ },
+ "growmodel": {}
}
"""
f = tempfile.NamedTemporaryFile(mode='a', delete=False)
@@ -660,15 +648,13 @@ def fixture_bad4assumpfile():
def test_read_bad_json_assump_file(bad1assumpfile, bad2assumpfile,
- bad3assumpfile, bad4assumpfile):
+ bad3assumpfile):
with pytest.raises(ValueError):
Calculator.read_json_param_objects(None, bad1assumpfile.name)
with pytest.raises(ValueError):
Calculator.read_json_param_objects(None, bad2assumpfile.name)
with pytest.raises(ValueError):
Calculator.read_json_param_objects(None, bad3assumpfile.name)
- with pytest.raises(ValueError):
- Calculator.read_json_param_objects(None, bad4assumpfile.name)
with pytest.raises(ValueError):
Calculator.read_json_param_objects(None, 'unknown_file_name')
with pytest.raises(ValueError):
@@ -847,7 +833,8 @@ def test_noreform_documentation():
"consumption": {},
"behavior": {},
"growdiff_baseline": {},
- "growdiff_response": {}
+ "growdiff_response": {},
+ "growmodel": {}
}
"""
params = Calculator.read_json_param_objects(reform_json, assump_json)
@@ -891,7 +878,8 @@ def test_reform_documentation():
// increase baseline inflation rate by one percentage point in 2014+
// (has no effect on known policy parameter values)
"growdiff_baseline": {"_ACPIU": {"2014": [0.01]}},
- "growdiff_response": {}
+ "growdiff_response": {},
+ "growmodel": {}
}
"""
params = Calculator.read_json_param_objects(reform_json, assump_json)
diff --git a/taxcalc/tests/test_cpscsv.py b/taxcalc/tests/test_cpscsv.py
index cf2c13c8c..8461a776e 100644
--- a/taxcalc/tests/test_cpscsv.py
+++ b/taxcalc/tests/test_cpscsv.py
@@ -20,7 +20,7 @@
import pandas as pd
# pylint: disable=import-error
from taxcalc import Policy, Records, Calculator, nonsmall_diffs
-from taxcalc import run_nth_year_tax_calc_model
+from taxcalc import run_nth_year_taxcalc_model
def test_agg(tests_path, cps_fullsample):
@@ -135,9 +135,9 @@ def test_ubi_n_variables(cps_path):
assert 'XTOT' == '(nu18+n1820+n21)'
-def test_run_tax_calc_model(tests_path):
+def test_run_taxcalc_model(tests_path):
"""
- Test tbi.run_nth_year_tax_calc_model function using CPS data.
+ Test tbi.run_nth_year_taxcalc_model function using CPS data.
"""
user_modifications = {
'policy': {
@@ -155,13 +155,15 @@ def test_run_tax_calc_model(tests_path):
'growdiff_baseline': {
},
'growdiff_response': {
+ },
+ 'growmodel': {
}
}
- res = run_nth_year_tax_calc_model(year_n=2, start_year=2018,
- use_puf_not_cps=False,
- use_full_sample=False,
- user_mods=user_modifications,
- return_dict=True)
+ res = run_nth_year_taxcalc_model(year_n=2, start_year=2018,
+ use_puf_not_cps=False,
+ use_full_sample=False,
+ user_mods=user_modifications,
+ return_dict=True)
assert isinstance(res, dict)
# put actual results in a multiline string
actual_results = ''
diff --git a/taxcalc/tests/test_growmodel.py b/taxcalc/tests/test_growmodel.py
new file mode 100644
index 000000000..4665d7d1e
--- /dev/null
+++ b/taxcalc/tests/test_growmodel.py
@@ -0,0 +1,131 @@
+# CODING-STYLE CHECKS:
+# pycodestyle test_growmodel.py
+
+import os
+import json
+import numpy as np
+import pytest
+from taxcalc import GrowModel
+
+
+def test_incorrect_growmodel_instantiation():
+ with pytest.raises(ValueError):
+ GrowModel(start_year=2012)
+ with pytest.raises(ValueError):
+ GrowModel(num_years=0)
+ with pytest.raises(FloatingPointError):
+ np.divide(1., 0.)
+
+
+def test_correct_update_growmodel():
+ gmod = GrowModel()
+ gmod.update_growmodel({})
+ assert not gmod.is_ever_active()
+ start_cyr = gmod.start_year
+ active_cyr = 2018
+ gmod.update_growmodel({active_cyr: {'_active': [True]}})
+ for cyr in range(start_cyr, active_cyr):
+ assert not gmod._active[cyr - start_cyr]
+ for cyr in range(active_cyr, gmod.end_year + 1):
+ assert gmod._active[cyr - start_cyr]
+ assert gmod.is_ever_active()
+ gmod.set_year(active_cyr - 1)
+ assert not gmod.is_active()
+
+
+def test_incorrect_update_growmodel():
+ with pytest.raises(ValueError):
+ GrowModel().update_growmodel([])
+ with pytest.raises(ValueError):
+ GrowModel().update_growmodel({2013: {'_active': [2]}})
+ with pytest.raises(ValueError):
+ GrowModel().update_growmodel({2013: {'_active': [0.2]}})
+ with pytest.raises(ValueError):
+ GrowModel().update_growmodel({2013: {'_activexxx': [True]}})
+ # year in update must be no less than start year
+ gmod = GrowModel(start_year=2014)
+ with pytest.raises(ValueError):
+ gmod.update_growmodel({2013: {'_active': [True]}})
+ # year in update must be no less than current year
+ gmod = GrowModel(start_year=2014)
+ gmod.set_year(2015)
+ with pytest.raises(ValueError):
+ gmod.update_growmodel({2014: {'_active': [True]}})
+ # year in update must be no greater than end_year
+ with pytest.raises(ValueError):
+ GrowModel().update_growmodel({2040: {'_active': [True]}})
+ # invalid start year
+ with pytest.raises(ValueError):
+ GrowModel().update_growmodel({'notayear': {'_active': [True]}})
+
+
+"""
+def test_validate_param_values_errors():
+ behv0 = GrowModel()
+ specs0 = {2020: {'_BE_cg': [0.2]}}
+ with pytest.raises(ValueError):
+ behv0.update_growmodel(specs0)
+ behv1 = GrowModel()
+ specs1 = {2022: {'_BE_sub': [-0.2]}}
+ with pytest.raises(ValueError):
+ behv1.update_growmodel(specs1)
+ behv2 = GrowModel()
+ specs2 = {
+ 2020: {
+ '_BE_subinc_wrt_earnings': [True],
+ '_BE_cg': [-0.2],
+ '_BE_sub': [0.3]
+ }
+ }
+ behv2.update_growmodel(specs2)
+"""
+
+
+"""
+def test_future_update_growmodel():
+ behv = GrowModel()
+ assert behv.current_year == behv.start_year
+ assert behv.has_response() is False
+ assert behv.has_any_response() is False
+ cyr = 2020
+ behv.set_year(cyr)
+ behv.update_growmodel({cyr: {'_BE_cg': [-1.0]}})
+ assert behv.current_year == cyr
+ assert behv.has_response() is True
+ behv.set_year(cyr - 1)
+ assert behv.has_response() is False
+ assert behv.has_any_response() is True
+"""
+
+
+def test_growmodel_default_data():
+ paramdata = GrowModel.default_data()
+ assert paramdata['_active'] == [False]
+
+
+def test_boolean_value_infomation(tests_path):
+ """
+ Check consistency of boolean_value in growmodel.json file.
+ """
+ # read growmodel.json file into a dictionary
+ path = os.path.join(tests_path, '..', 'growmodel.json')
+ with open(path, 'r') as behfile:
+ beh = json.load(behfile)
+ for param in beh.keys():
+ val = beh[param]['value']
+ if isinstance(val, list):
+ val = val[0]
+ if isinstance(val, list):
+ val = val[0]
+ valstr = str(val)
+ if valstr == 'True' or valstr == 'False':
+ val_is_boolean = True
+ else:
+ val_is_boolean = False
+ if beh[param]['boolean_value'] != val_is_boolean:
+ print('param,boolean_value,val,val_is_boolean=',
+ str(param),
+ beh[param]['boolean_value'],
+ val,
+ val_is_boolean)
+ assert beh[param]['boolean_value'] == val_is_boolean
diff --git a/taxcalc/tests/test_pufcsv.py b/taxcalc/tests/test_pufcsv.py
index dda8bf20f..b510f8e14 100644
--- a/taxcalc/tests/test_pufcsv.py
+++ b/taxcalc/tests/test_pufcsv.py
@@ -24,7 +24,7 @@
import pandas as pd
# pylint: disable=import-error
from taxcalc import Policy, Records, Calculator, nonsmall_diffs
-from taxcalc import run_nth_year_tax_calc_model
+from taxcalc import run_nth_year_taxcalc_model
@pytest.mark.requires_pufcsv
@@ -362,9 +362,9 @@ def test_ubi_n_variables(puf_path):
@pytest.mark.requires_pufcsv
-def test_run_tax_calc_model(tests_path):
+def test_run_taxcalc_model(tests_path):
"""
- Test tbi.run_nth_year_tax_calc_model function using PUF data.
+ Test tbi.run_nth_year_taxcalc_model function using PUF data.
"""
user_modifications = {
'policy': {
@@ -382,13 +382,15 @@ def test_run_tax_calc_model(tests_path):
'growdiff_baseline': {
},
'growdiff_response': {
+ },
+ 'growmodel': {
}
}
- res = run_nth_year_tax_calc_model(year_n=2, start_year=2018,
- use_puf_not_cps=True,
- use_full_sample=False,
- user_mods=user_modifications,
- return_dict=True)
+ res = run_nth_year_taxcalc_model(year_n=2, start_year=2018,
+ use_puf_not_cps=True,
+ use_full_sample=False,
+ user_mods=user_modifications,
+ return_dict=True)
assert isinstance(res, dict)
# put actual results in a multiline string
actual_results = ''
diff --git a/taxcalc/tests/test_responses.py b/taxcalc/tests/test_responses.py
index c7ffc1e60..ab82c8631 100644
--- a/taxcalc/tests/test_responses.py
+++ b/taxcalc/tests/test_responses.py
@@ -7,8 +7,9 @@
import os
import glob
+import pytest # pylint: disable=unused-import
# pylint: disable=import-error
-from taxcalc import Calculator, Consumption, Behavior, GrowDiff
+from taxcalc import Calculator, Consumption, Behavior, GrowDiff, GrowModel
def test_response_json(tests_path):
@@ -16,6 +17,7 @@ def test_response_json(tests_path):
Check that each JSON file can be converted into dictionaries that
can be used to construct objects needed for a Calculator object.
"""
+ # pylint: disable=too-many-locals
responses_path = os.path.join(tests_path, '..', 'responses', '*.json')
for jpf in glob.glob(responses_path):
# read contents of jpf (JSON parameter filename)
@@ -25,11 +27,12 @@ def test_response_json(tests_path):
response_file = ('"consumption"' in jpf_text and
'"behavior"' in jpf_text and
'"growdiff_baseline"' in jpf_text and
- '"growdiff_response"' in jpf_text)
+ '"growdiff_response"' in jpf_text and
+ '"growmodel"' in jpf_text)
if response_file:
# pylint: disable=protected-access
- (con, beh, gdiff_base,
- gdiff_resp) = Calculator._read_json_econ_assump_text(jpf_text)
+ (con, beh, gdiff_base, gdiff_resp,
+ grow_model) = Calculator._read_json_econ_assump_text(jpf_text)
cons = Consumption()
cons.update_consumption(con)
behv = Behavior()
@@ -38,7 +41,34 @@ def test_response_json(tests_path):
growdiff_baseline.update_growdiff(gdiff_base)
growdiff_response = GrowDiff()
growdiff_response.update_growdiff(gdiff_resp)
+ growmodel = GrowModel()
+ growmodel.update_growmodel(grow_model)
else: # jpf_text is not a valid JSON response assumption file
print('test-failing-filename: ' +
jpf)
assert False
+
+
+def test_growmodel_json():
+ """
+ Check dictionaries returned by Calculator._read_json_econ_assump_text(txt)
+ when txt includes a "growmodel":value pair.
+ """
+ txt = """
+ {
+ "consumption": {},
+ "behavior": {},
+ "growdiff_baseline": {},
+ "growdiff_response": {},
+ "growmodel": {}
+ }
+ """
+ # pylint: disable=protected-access
+ (con, beh, gdiff_base, gdiff_resp,
+ growmod) = Calculator._read_json_econ_assump_text(txt)
+ empty_dict = dict()
+ assert con == empty_dict
+ assert beh == empty_dict
+ assert gdiff_base == empty_dict
+ assert gdiff_resp == empty_dict
+ assert growmod == empty_dict
diff --git a/taxcalc/tests/test_taxcalcio.py b/taxcalc/tests/test_taxcalcio.py
index f36e0b160..4db73e676 100644
--- a/taxcalc/tests/test_taxcalcio.py
+++ b/taxcalc/tests/test_taxcalcio.py
@@ -4,12 +4,14 @@
# CODING-STYLE CHECKS:
# pycodestyle test_taxcalcio.py
# pylint --disable=locally-disabled test_taxcalcio.py
+#
+# pylint: disable=too-many-lines
import os
import tempfile
import pytest
import pandas as pd
-from taxcalc import TaxCalcIO, GrowDiff # pylint: disable=import-error
+from taxcalc import TaxCalcIO # pylint: disable=import-error
@pytest.fixture(scope='module', name='rawinputfile')
@@ -72,7 +74,8 @@ def fixture_assumpfile0():
"consumption": {},
"behavior": {"_BE_sub": {"2020": [0.05]}},
"growdiff_baseline": {"_ABOOK": {"2015": [-0.01]}},
- "growdiff_response": {}
+ "growdiff_response": {},
+ "growmodel": {}
}
"""
afile.write(contents)
@@ -93,7 +96,7 @@ def fixture_reformfile1():
"""
rfile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False)
contents = """
- { "policy": {
+ {"policy": {
"_AMT_brk1": { // top of first AMT tax bracket
"2015": [200000],
"2017": [300000]},
@@ -148,13 +151,13 @@ def fixture_baselinebad():
pass # sometimes we can't remove a generated temporary file
-@pytest.fixture(scope='module', name='reformfilex1')
-def fixture_reformfilex1():
+@pytest.fixture(scope='module', name='errorreformfile')
+def fixture_errorreformfile():
"""
Temporary reform file with .json extension.
"""
rfile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False)
- contents = '{ "policy": {"_AMT_brk1": {"2015": [-1]}}}'
+ contents = '{ "policy": {"_xxx": {"2015": [0]}}}'
rfile.write(contents)
rfile.close()
# must close and then yield for Windows platform
@@ -166,31 +169,21 @@ def fixture_reformfilex1():
pass # sometimes we can't remove a generated temporary file
-@pytest.fixture(scope='module', name='reformfilex2')
-def fixture_reformfilex2():
+@pytest.fixture(scope='module', name='errorassumpfile')
+def fixture_errorassumpfile():
"""
- Temporary reform file with .json extension.
+ Temporary assumption file with .json extension.
"""
rfile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False)
- contents = '{ "policy": {"_AMT_bxk1": {"2015": [0]}}}'
- rfile.write(contents)
- rfile.close()
- # must close and then yield for Windows platform
- yield rfile
- if os.path.isfile(rfile.name):
- try:
- os.remove(rfile.name)
- except OSError:
- pass # sometimes we can't remove a generated temporary file
-
-
-@pytest.fixture(scope='module', name='errorreformfile')
-def fixture_errorreformfile():
- """
- Temporary reform file with .json extension.
+ contents = """
+ {
+ "consumption": {"_MPC_e18400": {"2018": [-9]}},
+ "behavior": {"_BE_inc": {"2018": [0.4]}},
+ "growdiff_baseline": {"_ABOOKxx": {"2017": [0.02]}},
+ "growdiff_response": {"_ABOOKxx": {"2017": [0.02]}},
+ "growmodel": {"_activexx": {"2018": [true]}}
+ }
"""
- rfile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False)
- contents = '{ "policy": {"_xxx": {"2015": [0]}}}'
rfile.write(contents)
rfile.close()
# must close and then yield for Windows platform
@@ -209,10 +202,12 @@ def fixture_assumpfile1():
"""
afile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False)
contents = """
- { "consumption": { "_MPC_e18400": {"2018": [0.05]} },
- "behavior": {},
- "growdiff_baseline": {},
- "growdiff_response": {}
+ {
+ "consumption": { "_MPC_e18400": {"2018": [0.05]} },
+ "behavior": {},
+ "growdiff_baseline": {},
+ "growdiff_response": {},
+ "growmodel": {}
}
"""
afile.write(contents)
@@ -232,11 +227,7 @@ def fixture_lumpsumreformfile():
Temporary reform file without .json extension.
"""
rfile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False)
- lumpsum_reform_contents = """
- {
- "policy": {"_LST": {"2013": [200]}}
- }
- """
+ lumpsum_reform_contents = '{"policy": {"_LST": {"2013": [200]}}}'
rfile.write(lumpsum_reform_contents)
rfile.close()
# must close and then yield for Windows platform
@@ -259,7 +250,8 @@ def fixture_assumpfile2():
"consumption": {},
"behavior": {"_BE_sub": {"2020": [0.05]}},
"growdiff_baseline": {},
- "growdiff_response": {}
+ "growdiff_response": {},
+ "growmodel": {}
}
"""
afile.write(assump2_contents)
@@ -290,17 +282,14 @@ def test_ctor_errors(input_data, baseline, reform, assump, outdir):
assert tcio.errmsg
-@pytest.mark.parametrize('year, base, ref, asm, gdr', [
- (2000, 'reformfile0', 'reformfile0', None, list()),
- (2099, 'reformfile0', 'reformfile0', None, GrowDiff()),
- (2020, 'errorreformfile', 'errorreformfile', None, GrowDiff()),
- (2020, 'reformfile0', 'reformfile0', 'assumpfile0', 'has_gdiff_response'),
- (2020, 'reformfile0', 'reformfile0', 'assumpfile0', GrowDiff()),
- (2020, 'reformfile0', 'reformfilex1', 'assumpfile0', GrowDiff()),
- (2020, 'reformfile0', 'reformfilex2', 'assumpfile0', GrowDiff())
+@pytest.mark.parametrize('year, base, ref, asm', [
+ (2000, 'reformfile0', 'reformfile0', None),
+ (2099, 'reformfile0', 'reformfile0', None),
+ (2020, 'reformfile0', 'reformfile0', 'errorassumpfile'),
+ (2020, 'errorreformfile', 'errorreformfile', None)
])
-def test_init_errors(reformfile0, reformfilex1, reformfilex2, errorreformfile,
- assumpfile0, year, base, ref, asm, gdr):
+def test_init_errors(reformfile0, errorreformfile, errorassumpfile,
+ year, base, ref, asm):
"""
Ensure error messages generated correctly by TaxCalcIO.init method.
"""
@@ -316,23 +305,15 @@ def test_init_errors(reformfile0, reformfilex1, reformfilex2, errorreformfile,
baseline = base
if ref == 'reformfile0':
reform = reformfile0.name
- elif ref == 'reformfilex1':
- reform = reformfilex1.name
- elif ref == 'reformfilex2': # specify compound reform
- reform = '{}+{}'.format(reformfilex1.name, reformfilex2.name)
elif ref == 'errorreformfile':
reform = errorreformfile.name
else:
reform = ref
- if asm == 'assumpfile0':
- assump = assumpfile0.name
+ if asm == 'errorassumpfile':
+ assump = errorassumpfile.name
else:
assump = asm
- if gdr == 'has_gdiff_response':
- gdiff_resp = GrowDiff()
- gdiff_resp.update_growdiff({2015: {"_ABOOK": [-0.01]}})
- else:
- gdiff_resp = gdr
+ # call TaxCalcIO constructor
tcio = TaxCalcIO(input_data=recdf,
tax_year=year,
baseline=baseline,
@@ -340,13 +321,12 @@ def test_init_errors(reformfile0, reformfilex1, reformfilex2, errorreformfile,
assump=assump)
assert not tcio.errmsg
# test TaxCalcIO.init method
- if asm is None or gdr == 'has_gdiff_response':
- tcio.init(input_data=recdf, tax_year=year,
- baseline=baseline, reform=reform, assump=assump,
- growdiff_response=gdiff_resp,
- aging_input_data=False,
- exact_calculations=True)
- assert tcio.errmsg
+ tcio.init(input_data=recdf, tax_year=year,
+ baseline=baseline, reform=reform, assump=assump,
+ growdiff_growmodel=None,
+ aging_input_data=False,
+ exact_calculations=True)
+ assert tcio.errmsg
def test_creation_with_aging(rawinputfile, reformfile0):
@@ -365,7 +345,7 @@ def test_creation_with_aging(rawinputfile, reformfile0):
baseline=None,
reform=reformfile0.name,
assump=None,
- growdiff_response=GrowDiff(),
+ growdiff_growmodel=None,
aging_input_data=True,
exact_calculations=False)
assert not tcio.errmsg
@@ -382,7 +362,7 @@ def test_creation_with_aging(rawinputfile, reformfile0):
baseline=None,
reform=None,
assump=None,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=True,
exact_calculations=False)
assert not tcio.errmsg
@@ -397,7 +377,7 @@ def test_ctor_init_with_cps_files():
txyr = 2020
tcio = TaxCalcIO('cps.csv', txyr, None, None, None)
tcio.init('cps.csv', txyr, None, None, None,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=True,
exact_calculations=False)
assert not tcio.errmsg
@@ -406,13 +386,13 @@ def test_ctor_init_with_cps_files():
txyr = 2013
tcio = TaxCalcIO('cps.csv', txyr, None, None, None)
tcio.init('cps.csv', txyr, None, None, None,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=True,
exact_calculations=False)
assert tcio.errmsg
-@pytest.mark.parametrize('dumpvar_str, str_valid, num_vars', [
+@pytest.mark.parametrize("dumpvar_str, str_valid, num_vars", [
("""
MARS;iitax payrolltax|combined,
c00100
@@ -438,7 +418,7 @@ def test_custom_dump_variables(dumpvar_str, str_valid, num_vars):
assert not tcio.errmsg
tcio.init(input_data=recdf, tax_year=year,
baseline=None, reform=None, assump=None,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=False,
exact_calculations=False)
assert not tcio.errmsg
@@ -466,7 +446,7 @@ def test_output_options(rawinputfile, reformfile1, assumpfile1):
baseline=None,
reform=reformfile1.name,
assump=assumpfile1.name,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=False,
exact_calculations=False)
assert not tcio.errmsg
@@ -529,7 +509,7 @@ def test_write_doc_file(rawinputfile, reformfile1, assumpfile1):
baseline=None,
reform=compound_reform,
assump=assumpfile1.name,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=False,
exact_calculations=False)
assert not tcio.errmsg
@@ -556,7 +536,7 @@ def test_sqldb_option(rawinputfile, reformfile1, assumpfile1):
baseline=None,
reform=reformfile1.name,
assump=assumpfile1.name,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=False,
exact_calculations=False)
assert not tcio.errmsg
@@ -603,7 +583,7 @@ def test_no_tables_or_graphs(reformfile1):
baseline=None,
reform=reformfile1.name,
assump=None,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=False,
exact_calculations=False)
assert not tcio.errmsg
@@ -652,7 +632,7 @@ def test_tables(reformfile1):
baseline=None,
reform=reformfile1.name,
assump=None,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=False,
exact_calculations=False)
assert not tcio.errmsg
@@ -690,7 +670,7 @@ def test_graphs(reformfile1):
baseline=None,
reform=reformfile1.name,
assump=None,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=False,
exact_calculations=False)
assert not tcio.errmsg
@@ -726,7 +706,7 @@ def test_ceeu_output1(lumpsumreformfile):
baseline=None,
reform=lumpsumreformfile.name,
assump=None,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=False,
exact_calculations=False)
assert not tcio.errmsg
@@ -752,7 +732,7 @@ def test_ceeu_output2():
baseline=None,
reform=None,
assump=None,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=False,
exact_calculations=False)
assert not tcio.errmsg
@@ -778,7 +758,7 @@ def test_ceeu_with_behavior(lumpsumreformfile, assumpfile2):
baseline=None,
reform=lumpsumreformfile.name,
assump=assumpfile2.name,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=False,
exact_calculations=False)
assert not tcio.errmsg
@@ -792,7 +772,7 @@ def fixture_warnreformfile():
Temporary reform file with .json extension.
"""
rfile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False)
- contents = '{ "policy": {"_STD_Dep": {"2015": [0]}}}'
+ contents = '{"policy": {"_STD_Dep": {"2015": [0]}}}'
rfile.write(contents)
rfile.close()
# must close and then yield for Windows platform
@@ -822,7 +802,7 @@ def test_analyze_warnings_print(warnreformfile):
baseline=None,
reform=warnreformfile.name,
assump=None,
- growdiff_response=None,
+ growdiff_growmodel=None,
aging_input_data=False,
exact_calculations=False)
assert not tcio.errmsg
@@ -830,21 +810,75 @@ def test_analyze_warnings_print(warnreformfile):
assert tcio.tax_year() == taxyear
-def test_growmodel_analysis(reformfile1, assumpfile1):
+@pytest.fixture(scope='module', name='reformfile9')
+def fixture_reformfile9():
+ """
+ Temporary reform file with .json extension.
+ """
+ rfile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False)
+ contents = """
+ { "policy": {
+ "_SS_Earnings_c": {
+ "2014": [300000],
+ "2015": [500000],
+ "2016": [700000]}
+ }
+ }
+ """
+ rfile.write(contents)
+ rfile.close()
+ # must close and then yield for Windows platform
+ yield rfile
+ if os.path.isfile(rfile.name):
+ try:
+ os.remove(rfile.name)
+ except OSError:
+ pass # sometimes we can't remove a generated temporary file
+
+
+@pytest.fixture(scope='module', name='assumpfile3')
+def fixture_assumpfile3():
"""
- Test TaxCalcIO.growmodel_analysis method with no output.
+ Temporary assumption file with .json extension.
+ """
+ afile = tempfile.NamedTemporaryFile(suffix='.json', mode='a', delete=False)
+ contents = """
+ {
+ "consumption": {},
+ "behavior": {},
+ "growdiff_baseline": {},
+ "growdiff_response": {},
+ "growmodel": {"_active": {"2019": [true]}}
+ }
+ """
+ afile.write(contents)
+ afile.close()
+ # must close and then yield for Windows platform
+ yield afile
+ if os.path.isfile(afile.name):
+ try:
+ os.remove(afile.name)
+ except OSError:
+ pass # sometimes we can't remove a generated temporary file
+
+
+def test_growmodel_analysis(reformfile9, assumpfile3):
+ """
+ Test TaxCalcIO.growmodel_analysis logic.
"""
- taxyear = 2015
recdict = {'RECID': 1, 'MARS': 1, 'e00300': 100000, 's006': 1e8}
recdf = pd.DataFrame(data=recdict, index=[0])
- # test growmodel_analysis with legal assumptions
- try:
- TaxCalcIO.growmodel_analysis(input_data=recdf,
- tax_year=taxyear,
- baseline=None,
- reform=reformfile1.name,
- assump=assumpfile1.name,
- aging_input_data=False,
- exact_calculations=False)
- except Exception: # pylint: disable=broad-except
- assert 'TaxCalcIO.growmodel_analysis_ok' == 'no'
+ TaxCalcIO.growmodel_analysis(input_data=recdf,
+ tax_year=2019,
+ baseline=None,
+ reform=reformfile9.name,
+ assump=assumpfile3.name,
+ aging_input_data=True,
+ exact_calculations=False,
+ writing_output_file=False,
+ output_tables=False,
+ output_graphs=False,
+ output_ceeu=False,
+ dump_varset=None,
+ output_dump=False,
+ output_sqldb=False)
diff --git a/taxcalc/tests/test_tbi.py b/taxcalc/tests/test_tbi.py
index 144808697..771485b02 100644
--- a/taxcalc/tests/test_tbi.py
+++ b/taxcalc/tests/test_tbi.py
@@ -31,6 +31,8 @@
},
'growdiff_response': {
},
+ 'growmodel': {
+ }
}
@@ -171,8 +173,9 @@ def test_with_pufcsv(puf_fullsample):
usermods['behavior'] = {}
usermods['growdiff_baseline'] = {}
usermods['growdiff_response'] = {}
+ usermods['growmodel'] = {}
seed = random_seed(usermods)
- assert seed == 1574318062
+ assert seed == 580419828
# create a Policy object (pol) containing reform policy parameters
pol = Policy()
pol.implement_reform(usermods['policy'])
@@ -188,11 +191,11 @@ def test_with_pufcsv(puf_fullsample):
assert taxes_fullsample is not None
fulls_reform_revenue = float(taxes_fullsample.loc[analysis_year])
# call run_nth_year_tax_calc_model function
- resdict = run_nth_year_tax_calc_model(year_n, start_year,
- use_puf_not_cps=True,
- use_full_sample=True,
- user_mods=usermods,
- return_dict=True)
+ resdict = run_nth_year_taxcalc_model(year_n, start_year,
+ use_puf_not_cps=True,
+ use_full_sample=True,
+ user_mods=usermods,
+ return_dict=True)
total = resdict['aggr_2']
tbi_reform_revenue = float(total['combined_tax_9']) * 1e-9
# assert that tbi revenue is similar to the fullsample calculation
@@ -214,7 +217,8 @@ def test_reform_warnings_errors():
'consumption': {},
'behavior': {},
'growdiff_baseline': {},
- 'growdiff_response': {}
+ 'growdiff_response': {},
+ 'growmodel': {}
}
msg_dict = reform_warnings_errors(bad1_mods)
assert len(msg_dict['policy']['warnings']) > 0
@@ -224,7 +228,8 @@ def test_reform_warnings_errors():
'consumption': {},
'behavior': {},
'growdiff_baseline': {},
- 'growdiff_response': {}
+ 'growdiff_response': {},
+ 'growmodel': {}
}
msg_dict = reform_warnings_errors(bad2_mods)
assert len(msg_dict['policy']['warnings']) == 0
@@ -244,7 +249,7 @@ def test_behavioral_response(puf_subsample):
"""
Test that behavioral-response results are the same
when generated from standard Tax-Calculator calls and
- when generated from tbi.run_nth_year_tax_calc_model() calls
+ when generated from tbi.run_nth_year_taxcalc_model() calls
"""
# specify reform and assumptions
reform_json = """
@@ -262,7 +267,8 @@ def test_behavioral_response(puf_subsample):
{"behavior": {"_BE_sub": {"2013": [0.25]}},
"growdiff_baseline": {},
"growdiff_response": {},
- "consumption": {}
+ "consumption": {},
+ "growmodel": {}
}
"""
params = Calculator.read_json_param_objects(reform_json, assump_json)
@@ -277,7 +283,8 @@ def test_behavioral_response(puf_subsample):
'behavior': params['behavior'],
'growdiff_baseline': params['growdiff_baseline'],
'growdiff_response': params['growdiff_response'],
- 'consumption': params['consumption']
+ 'consumption': params['consumption'],
+ 'growmodel': params['growmodel']
},
'return_dict': False
}
@@ -290,7 +297,7 @@ def test_behavioral_response(puf_subsample):
cyr = year + kwargs['start_year']
if using_tbi:
kwargs['year_n'] = year
- tables = run_nth_year_tax_calc_model(**kwargs)
+ tables = run_nth_year_taxcalc_model(**kwargs)
tbi_res[cyr] = dict()
for tbl in ['aggr_1', 'aggr_2', 'aggr_d']:
tbi_res[cyr][tbl] = tables[tbl]