Repository: PSLmodels/Tax-Calculator

Issue:
Incorrect variable name in docstring
Hey guys. Was looking at the AMT logic while validating my own AMT tax calculation function. Found a labeling error: e00700 is described as sole prop income rather than state refunds:


```
    e00700: float
        Schedule C business net profit/loss for filing unit
```

Discussion:
@martinholmer: @ricco-budget-lab,  Thanks for pointing out the error in the documentation of the AMT function.
This has been fixed as part of PR #2888 in commit [2c7debb](https://github.com/PSLmodels/Tax-Calculator/pull/2888/commits/2c7debb79e329a1f033fd0336b633a630a62cbcf).

Please raise other issues if you find problems with the documentation or with the tax logic.@martinholmer: Resolved by the merge of PR #2888.

Solution patch:
diff --git a/taxcalc/calcfunctions.py b/taxcalc/calcfunctions.py
index f5509149..39974921 100644
--- a/taxcalc/calcfunctions.py
+++ b/taxcalc/calcfunctions.py
@@ -2059,7 +2059,7 @@ def AMT(e07300, dwks13, standard, f6251, c00100, c18300, taxbc,
     e62900: float
         Alternative Minimum Tax foreign tax credit from Form 6251
     e00700: float
-        Schedule C business net profit/loss for filing unit
+        Taxable refunds of state and local income taxes
     dwks10: float
         Sum of dwks6 + dwks9
     age_head: int
diff --git a/taxcalc/cli/tc.py b/taxcalc/cli/tc.py
index b2228d07..c2eae595 100644
--- a/taxcalc/cli/tc.py
+++ b/taxcalc/cli/tc.py
@@ -30,14 +30,24 @@ def cli_tc_main():
     # parse command-line arguments:
     usage_str = 'tc INPUT TAXYEAR {}{}{}{}{}'.format(
         '[--help]\n',
-        ('          '
-         '[--baseline BASELINE] [--reform REFORM] [--assump  ASSUMP]\n'),
-        ('          '
-         '[--exact] [--tables] [--graphs]\n'),
-        ('          '
-         '[--dump] [--dvars DVARS] [--sqldb] [--outdir OUTDIR]\n'),
-        ('          '
-         '[--silent] [--test] [--version]'))
+        (
+            '          '
+            '[--baseline BASELINE] [--reform REFORM] [--assump  ASSUMP] '
+            '[--exact]\n'
+        ),
+        (
+            '          '
+            '[--params] [--tables] [--graphs]\n'
+        ),
+        (
+            '          '
+            '[--dump] [--dvars DVARS] [--sqldb] [--outdir OUTDIR]\n'
+        ),
+        (
+            '          '
+            '[--silent] [--test] [--version]'
+        )
+    )
     parser = argparse.ArgumentParser(
         prog='',
         usage=usage_str,
@@ -82,6 +92,12 @@ def cli_tc_main():
                               'complicate marginal-tax-rate calculations.'),
                         default=False,
                         action="store_true")
+    parser.add_argument('--params',
+                        help=('optional flag that causes policy parameter '
+                              'values for baseline and reform to be written '
+                              'to separate text files.'),
+                        default=False,
+                        action="store_true")
     parser.add_argument('--tables',
                         help=('optional flag that causes distributional '
                               'tables to be written to a text file.'),
@@ -214,6 +230,7 @@ def cli_tc_main():
             return 1
     # conduct tax analysis
     tcio.analyze(writing_output_file=True,
+                 output_params=args.params,
                  output_tables=args.tables,
                  output_graphs=args.graphs,
                  dump_varset=dumpvar_set,
diff --git a/taxcalc/taxcalcio.py b/taxcalc/taxcalcio.py
index 25f82887..89501dcc 100644
--- a/taxcalc/taxcalcio.py
+++ b/taxcalc/taxcalcio.py
@@ -220,12 +220,17 @@ class TaxCalcIO():
             delete_old_files = False
         if delete_old_files:
             delete_file(self._output_filename)
-            delete_file(self._output_filename.replace('.csv', '.db'))
-            delete_file(self._output_filename.replace('.csv', '-doc.text'))
-            delete_file(self._output_filename.replace('.csv', '-tab.text'))
-            delete_file(self._output_filename.replace('.csv', '-atr.html'))
-            delete_file(self._output_filename.replace('.csv', '-mtr.html'))
-            delete_file(self._output_filename.replace('.csv', '-pch.html'))
+            extensions = [
+                '.db',
+                '-params.bas',
+                '-params.ref',
+                '-tables.text',
+                '-atr.html',
+                '-mtr.html',
+                '-pch.html',
+            ]
+            for ext in extensions:
+                delete_file(self._output_filename.replace('.csv', ext))
         # initialize variables whose values are set in init method
         self.calc = None
         self.calc_base = None
@@ -458,7 +463,9 @@ class TaxCalcIO():
         dirpath = os.path.abspath(os.path.dirname(__file__))
         return os.path.join(dirpath, self._output_filename)
 
-    def analyze(self, writing_output_file=False,
+    def analyze(self,
+                writing_output_file=False,
+                output_params=False,
                 output_tables=False,
                 output_graphs=False,
                 dump_varset=None,
@@ -472,6 +479,10 @@ class TaxCalcIO():
         writing_output_file: boolean
            whether or not to generate and write output file
 
+        output_params: boolean
+           whether or not to write baseline and reform policy parameter
+           values to separate text files
+
         output_tables: boolean
            whether or not to generate and write distributional tables
            to a text file
@@ -528,13 +539,15 @@ class TaxCalcIO():
         if writing_output_file:
             self.write_output_file(output_dump, dump_varset,
                                    mtr_paytax, mtr_inctax)
-            self.write_doc_file()
         # optionally write --sqldb output to SQLite3 database
         if output_sqldb:
             self.write_sqldb_file(
                 dump_varset, mtr_paytax, mtr_inctax,
                 mtr_paytax_base, mtr_inctax_base
             )
+        # optionally write --params output to text files
+        if output_params:
+            self.write_policy_params_files()
         # optionally write --tables output to text file
         if output_tables:
             if not calc_base_calculated:
@@ -586,24 +599,28 @@ class TaxCalcIO():
                 f'Write tax-unit output to file {self._output_filename}'
             )
 
-    def write_doc_file(self):
+    def write_policy_params_files(self):
         """
-        Write reform documentation to text file.
+        Write baseline and reform policy parameter values to separate files.
         """
-        if len(self.policy_dicts) <= 1:
-            doc = Calculator.reform_documentation(
-                self.param_dict, self.gf_reform
-            )
-        else:
-            doc = Calculator.reform_documentation(
-                self.param_dict, self.gf_reform, self.policy_dicts[1:]
+        param_names = Policy.parameter_list()
+        fname = self._output_filename.replace('.csv', '-params.bas')
+        with open(fname, 'w', encoding='utf-8') as pfile:
+            for pname in param_names:
+                pval = self.calc_base.policy_param(pname)
+                pfile.write(f'{pname} {pval}\n')
+        if not self.silent:
+            print(  # pragma: no cover
+                f'Write baseline policy parameter values to file {fname}'
             )
-        doc_fname = self._output_filename.replace('.csv', '-doc.text')
-        with open(doc_fname, 'w', encoding='utf-8') as dfile:
-            dfile.write(doc)
+        fname = self._output_filename.replace('.csv', '-params.ref')
+        with open(fname, 'w', encoding='utf-8') as pfile:
+            for pname in param_names:
+                pval = self.calc.policy_param(pname)
+                pfile.write(f'{pname} {pval}\n')
         if not self.silent:
             print(  # pragma: no cover
-                f'Write reform documentation to file {doc_fname}'
+                f'Write reform policy parameter values to file {fname}'
             )
 
     def write_sqldb_file(self, dump_varset, mtr_paytax, mtr_inctax,
@@ -639,7 +656,7 @@ class TaxCalcIO():
         Write tables to text file.
         """
         # pylint: disable=too-many-locals
-        tab_fname = self._output_filename.replace('.csv', '-tab.text')
+        tab_fname = self._output_filename.replace('.csv', '-tables.text')
         # skip tables if there are not some positive weights
         if self.calc_base.total_weight() <= 0.:
             with open(tab_fname, 'w', encoding='utf-8') as tfile:


Test patch:
diff --git a/taxcalc/tests/test_taxcalcio.py b/taxcalc/tests/test_taxcalcio.py
index 605122b0..62c9fc85 100644
--- a/taxcalc/tests/test_taxcalcio.py
+++ b/taxcalc/tests/test_taxcalcio.py
@@ -456,39 +456,39 @@ def test_output_options(reformfile1, assumpfile1):
             except OSError:
                 pass  # sometimes we can't remove a generated temporary file
         assert False, 'TaxCalcIO.analyze(partial_dump_output) failed'
-    # if tries were successful, remove doc file and output file
-    docfilepath = outfilepath.replace('.csv', '-doc.text')
-    if os.path.isfile(docfilepath):
-        os.remove(docfilepath)
+    # if tries were successful, remove output file
     if os.path.isfile(outfilepath):
         os.remove(outfilepath)
 
 
-def test_write_doc_file(reformfile1, assumpfile1):
+def test_write_policy_param_files(reformfile1):
     """
-    Test write_doc_file with compound reform.
+    Test write_policy_params_files with compound reform.
     """
     taxyear = 2021
     compound_reform = f'{reformfile1.name}+{reformfile1.name}'
-    tcio = TaxCalcIO(input_data=pd.read_csv(StringIO(RAWINPUT)),
-                     tax_year=taxyear,
-                     baseline=None,
-                     reform=compound_reform,
-                     assump=assumpfile1.name)
+    tcio = TaxCalcIO(
+        input_data=pd.read_csv(StringIO(RAWINPUT)),
+        tax_year=taxyear,
+        baseline=None,
+        reform=compound_reform,
+        assump=None,
+    )
     assert not tcio.errmsg
     tcio.init(input_data=pd.read_csv(StringIO(RAWINPUT)),
               tax_year=taxyear,
               baseline=None,
               reform=compound_reform,
-              assump=assumpfile1.name,
+              assump=None,
               aging_input_data=False,
               exact_calculations=False)
     assert not tcio.errmsg
-    tcio.write_doc_file()
+    tcio.write_policy_params_files()
     outfilepath = tcio.output_filepath()
-    docfilepath = outfilepath.replace('.csv', '-doc.text')
-    if os.path.isfile(docfilepath):
-        os.remove(docfilepath)
+    for ext in ['-params.bas', '-params.ref']:
+        filepath = outfilepath.replace('.csv', ext)
+        if os.path.isfile(filepath):
+            os.remove(filepath)
 
 
 def test_sqldb_option(reformfile1, assumpfile1):
@@ -529,8 +529,8 @@ def test_sqldb_option(reformfile1, assumpfile1):
 
 def test_no_tables_or_graphs(reformfile1):
     """
-    Test TaxCalcIO with output_tables=True and output_graphs=True but
-    INPUT has zero weights.
+    Test TaxCalcIO with output_params=True and output_tables=True and
+    output_graphs=True but INPUT has zero weights.
     """
     # create input sample that cannot output tables or graphs
     nobs = 10
@@ -556,24 +556,25 @@ def test_no_tables_or_graphs(reformfile1):
               aging_input_data=False,
               exact_calculations=False)
     assert not tcio.errmsg
-    # create TaxCalcIO tables file
+    # create several TaxCalcIO output files
     tcio.analyze(writing_output_file=False,
+                 output_params=True,
                  output_tables=True,
                  output_graphs=True)
     # delete tables and graph files
     output_filename = tcio.output_filepath()
-    fname = output_filename.replace('.csv', '-tab.text')
-    if os.path.isfile(fname):
-        os.remove(fname)
-    fname = output_filename.replace('.csv', '-atr.html')
-    if os.path.isfile(fname):
-        os.remove(fname)
-    fname = output_filename.replace('.csv', '-mtr.html')
-    if os.path.isfile(fname):
-        os.remove(fname)
-    fname = output_filename.replace('.csv', '-pch.html')
-    if os.path.isfile(fname):
-        os.remove(fname)
+    extensions = [
+        '-params.bas',
+        '-params.ref',
+        '-tables.text',
+        '-atr.html',
+        '-mtr.html',
+        '-pch.html',
+    ]
+    for ext in extensions:
+        fname = output_filename.replace('.csv', ext)
+        if os.path.isfile(fname):
+            os.remove(fname)
 
 
 def test_tables(reformfile1):
@@ -608,7 +609,7 @@ def test_tables(reformfile1):
     tcio.analyze(writing_output_file=False, output_tables=True)
     # delete tables file
     output_filename = tcio.output_filepath()
-    fname = output_filename.replace('.csv', '-tab.text')
+    fname = output_filename.replace('.csv', '-tables.text')
     if os.path.isfile(fname):
         os.remove(fname)