taxcalc 4.4.0__py3-none-any.whl → 4.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. taxcalc/__init__.py +1 -1
  2. taxcalc/calcfunctions.py +326 -171
  3. taxcalc/calculator.py +35 -34
  4. taxcalc/cli/tc.py +6 -7
  5. taxcalc/consumption.json +1 -1
  6. taxcalc/consumption.py +9 -4
  7. taxcalc/cps_weights.csv.gz +0 -0
  8. taxcalc/data.py +8 -8
  9. taxcalc/decorators.py +3 -3
  10. taxcalc/growdiff.json +1 -1
  11. taxcalc/growdiff.py +5 -0
  12. taxcalc/growfactors.csv +26 -25
  13. taxcalc/growfactors.py +1 -1
  14. taxcalc/parameters.py +85 -42
  15. taxcalc/policy.py +2 -2
  16. taxcalc/policy_current_law.json +87 -87
  17. taxcalc/puf_ratios.csv +15 -14
  18. taxcalc/puf_weights.csv.gz +0 -0
  19. taxcalc/records.py +1 -0
  20. taxcalc/records_variables.json +6 -0
  21. taxcalc/reforms/ext.json +21 -21
  22. taxcalc/taxcalcio.py +49 -44
  23. taxcalc/tests/cmpi_cps_expect.txt +6 -6
  24. taxcalc/tests/cmpi_puf_expect.txt +6 -6
  25. taxcalc/tests/conftest.py +43 -42
  26. taxcalc/tests/cpscsv_agg_expect.csv +22 -22
  27. taxcalc/tests/puf_var_wght_means_by_year.csv +70 -70
  28. taxcalc/tests/pufcsv_agg_expect.csv +22 -22
  29. taxcalc/tests/test_4package.py +9 -7
  30. taxcalc/tests/test_benefits.py +9 -8
  31. taxcalc/tests/test_calcfunctions.py +55 -38
  32. taxcalc/tests/test_calculator.py +11 -6
  33. taxcalc/tests/test_compare.py +45 -51
  34. taxcalc/tests/test_compatible_data.py +9 -7
  35. taxcalc/tests/test_consumption.py +38 -18
  36. taxcalc/tests/test_cpscsv.py +33 -31
  37. taxcalc/tests/test_data.py +31 -24
  38. taxcalc/tests/test_decorators.py +84 -32
  39. taxcalc/tests/test_growdiff.py +16 -13
  40. taxcalc/tests/test_growfactors.py +8 -8
  41. taxcalc/tests/test_parameters.py +55 -59
  42. taxcalc/tests/test_policy.py +14 -12
  43. taxcalc/tests/test_puf_var_stats.py +14 -14
  44. taxcalc/tests/test_pufcsv.py +40 -40
  45. taxcalc/tests/test_records.py +73 -60
  46. taxcalc/tests/test_reforms.py +35 -32
  47. taxcalc/tests/test_responses.py +4 -4
  48. taxcalc/tests/test_taxcalcio.py +76 -62
  49. taxcalc/tests/test_utils.py +78 -46
  50. taxcalc/utils.py +49 -42
  51. taxcalc/validation/taxsim35/taxsim_emulation.json +1 -5
  52. {taxcalc-4.4.0.dist-info → taxcalc-4.5.0.dist-info}/METADATA +19 -5
  53. {taxcalc-4.4.0.dist-info → taxcalc-4.5.0.dist-info}/RECORD +57 -57
  54. {taxcalc-4.4.0.dist-info → taxcalc-4.5.0.dist-info}/WHEEL +1 -1
  55. {taxcalc-4.4.0.dist-info → taxcalc-4.5.0.dist-info}/LICENSE +0 -0
  56. {taxcalc-4.4.0.dist-info → taxcalc-4.5.0.dist-info}/entry_points.txt +0 -0
  57. {taxcalc-4.4.0.dist-info → taxcalc-4.5.0.dist-info}/top_level.txt +0 -0
@@ -8,10 +8,10 @@ Tests for Tax-Calculator calcfunctions.py logic.
8
8
  import os
9
9
  import re
10
10
  import ast
11
- from taxcalc import Records # pylint: disable=import-error
12
- from taxcalc import calcfunctions
13
11
  import numpy as np
14
12
  import pytest
13
+ from taxcalc.records import Records
14
+ from taxcalc import calcfunctions
15
15
 
16
16
 
17
17
  class GetFuncDefs(ast.NodeVisitor):
@@ -23,10 +23,10 @@ class GetFuncDefs(ast.NodeVisitor):
23
23
  GetFuncDefs class constructor
24
24
  """
25
25
  self.fname = ''
26
- self.fnames = list() # function name (fname) list
27
- self.fargs = dict() # lists of function arguments indexed by fname
28
- self.cvars = dict() # lists of calc vars in function indexed by fname
29
- self.rvars = dict() # lists of function return vars indexed by fname
26
+ self.fnames = [] # function name (fname) list
27
+ self.fargs = {} # lists of function arguments indexed by fname
28
+ self.cvars = {} # lists of calc vars in function indexed by fname
29
+ self.rvars = {} # lists of function return vars indexed by fname
30
30
 
31
31
  def visit_Module(self, node): # pylint: disable=invalid-name
32
32
  """
@@ -41,10 +41,10 @@ class GetFuncDefs(ast.NodeVisitor):
41
41
  """
42
42
  self.fname = node.name
43
43
  self.fnames.append(self.fname)
44
- self.fargs[self.fname] = list()
44
+ self.fargs[self.fname] = []
45
45
  for anode in ast.iter_child_nodes(node.args):
46
46
  self.fargs[self.fname].append(anode.arg)
47
- self.cvars[self.fname] = list()
47
+ self.cvars[self.fname] = []
48
48
  for bodynode in node.body:
49
49
  if isinstance(bodynode, ast.Return):
50
50
  continue # skip function's Return node
@@ -84,8 +84,10 @@ def test_calc_and_used_vars(tests_path):
84
84
  """
85
85
  # pylint: disable=too-many-locals
86
86
  funcpath = os.path.join(tests_path, '..', 'calcfunctions.py')
87
+ with open(funcpath, 'r', encoding='utf-8') as funcfile:
88
+ funcfile_text = funcfile.read()
87
89
  gfd = GetFuncDefs()
88
- fnames, fargs, cvars, rvars = gfd.visit(ast.parse(open(funcpath).read()))
90
+ fnames, fargs, cvars, rvars = gfd.visit(ast.parse(funcfile_text))
89
91
  # Test (1):
90
92
  # .. create set of vars that are actually calculated in calcfunctions.py
91
93
  all_cvars = set()
@@ -106,7 +108,7 @@ def test_calc_and_used_vars(tests_path):
106
108
  'in calcfunctions.py\n')
107
109
  for var in records_varinfo.CALCULATED_VARS - all_cvars:
108
110
  found_error1 = True
109
- msg1 += 'VAR NOT CALCULATED: {}\n'.format(var)
111
+ msg1 += f'VAR NOT CALCULATED: {var}\n'
110
112
  # Test (2):
111
113
  faux_functions = ['EITCamount', 'ComputeBenefit', 'BenefitPrograms',
112
114
  'BenefitSurtax', 'BenefitLimitation']
@@ -119,10 +121,10 @@ def test_calc_and_used_vars(tests_path):
119
121
  if not crvars_set <= set(fargs[fname]):
120
122
  found_error2 = True
121
123
  for var in crvars_set - set(fargs[fname]):
122
- msg2 += 'FUNCTION,VARIABLE: {} {}\n'.format(fname, var)
124
+ msg2 += f'FUNCTION,VARIABLE: {fname} {var}\n'
123
125
  # Report errors for the two tests:
124
126
  if found_error1 and found_error2:
125
- raise ValueError('{}\n{}'.format(msg1, msg2))
127
+ raise ValueError(f'{msg1}\n{msg2}')
126
128
  if found_error1:
127
129
  raise ValueError(msg1)
128
130
  if found_error2:
@@ -135,7 +137,7 @@ def test_function_args_usage(tests_path):
135
137
  function body.
136
138
  """
137
139
  funcfilename = os.path.join(tests_path, '..', 'calcfunctions.py')
138
- with open(funcfilename, 'r') as funcfile:
140
+ with open(funcfilename, 'r', encoding='utf-8') as funcfile:
139
141
  fcontent = funcfile.read()
140
142
  fcontent = re.sub('#.*', '', fcontent) # remove all '#...' comments
141
143
  fcontent = re.sub('\n', ' ', fcontent) # replace EOL character with space
@@ -149,7 +151,7 @@ def test_function_args_usage(tests_path):
149
151
  msg = ('Could not find function name, arguments, '
150
152
  'and code portions in the following text:\n')
151
153
  msg += '--------------------------------------------------------\n'
152
- msg += '{}\n'.format(fcode)
154
+ msg += f'{fcode}\n'
153
155
  msg += '--------------------------------------------------------\n'
154
156
  raise ValueError(msg)
155
157
  fname = match.group(1)
@@ -161,11 +163,14 @@ def test_function_args_usage(tests_path):
161
163
  arg = farg.strip()
162
164
  if fbody.find(arg) < 0:
163
165
  found_error = True
164
- msg += 'FUNCTION,ARGUMENT= {} {}\n'.format(fname, arg)
166
+ msg += f'FUNCTION,ARGUMENT= {fname} {arg}\n'
165
167
  if found_error:
166
168
  raise ValueError(msg)
167
169
 
168
170
 
171
+ # pylint: disable=invalid-name,unused-argument
172
+
173
+
169
174
  def test_DependentCare(skip_jit):
170
175
  """
171
176
  Tests the DependentCare function
@@ -199,7 +204,7 @@ tuple7 = (0, 1000, STD_in, 44, 0, STD_Aged_in, 1000, 3, 1, 0, 0, 2,
199
204
  tuple8 = (1, 200, STD_in, 44, 0, STD_Aged_in, 1000, 3, 0, 0, 0, 2,
200
205
  True, 0, 100000, 1, Charity_max_in)
201
206
  tuple9 = (1, 1000, STD_in, 44, 0, STD_Aged_in, 1000, 3, 0, 0, 0, 2,
202
- True, 0,100000, 1, Charity_max_in)
207
+ True, 0, 100000, 1, Charity_max_in)
203
208
  expected = [12000, 15800, 13800, 14400, 6000, 6000, 0, 1000, 1350]
204
209
 
205
210
 
@@ -224,22 +229,28 @@ def test_StdDed(test_tuple, expected_value, skip_jit):
224
229
  assert np.allclose(avalue, expected_value), f"{avalue} != {expected_value}"
225
230
 
226
231
 
227
- tuple1 = (120000, 10000, 15000, 100, 2000, 0.06, 0.06, 0.015, 0.015, 0, 99999999999,
228
- 400, 0, 0, 0, 0, 0, 0, None, None, None, None, None, None,
232
+ tuple1 = (120000, 10000, 15000, 100, 2000,
233
+ 0.06, 0.06, 0.015, 0.015, 0, 99999999999,
234
+ 400, 0, 0, 0, 0, 0, 0, None, None, None, None, None, None,
229
235
  None, None, None, None, None)
230
- tuple2 = (120000, 10000, 15000, 100, 2000, 0.06, 0.06, 0.015, 0.015, 0, 99999999999,
236
+ tuple2 = (120000, 10000, 15000, 100, 2000,
237
+ 0.06, 0.06, 0.015, 0.015, 0, 99999999999,
231
238
  400, 2000, 0, 10000, 0, 0, 3000, None, None, None, None, None,
232
239
  None, None, None, None, None, None)
233
- tuple3 = (120000, 150000, 15000, 100, 2000, 0.06, 0.06, 0.015, 0.015, 0, 99999999999,
240
+ tuple3 = (120000, 150000, 15000, 100, 2000,
241
+ 0.06, 0.06, 0.015, 0.015, 0, 99999999999,
234
242
  400, 2000, 0, 10000, 0, 0, 3000, None, None, None, None, None,
235
243
  None, None, None, None, None, None)
236
- tuple4 = (120000, 500000, 15000, 100, 2000, 0.06, 0.06, 0.015, 0.015, 0, 400000,
244
+ tuple4 = (120000, 500000, 15000, 100, 2000,
245
+ 0.06, 0.06, 0.015, 0.015, 0, 400000,
237
246
  400, 2000, 0, 10000, 0, 0, 3000, None, None, None, None, None,
238
247
  None, None, None, None, None, None)
239
- tuple5 = (120000, 10000, 15000, 100, 2000, 0.06, 0.06, 0.015, 0.015, 0, 99999999999,
248
+ tuple5 = (120000, 10000, 15000, 100, 2000,
249
+ 0.06, 0.06, 0.015, 0.015, 0, 99999999999,
240
250
  400, 300, 0, 0, 0, 0, 0, None, None, None, None, None,
241
251
  None, None, None, None, None, None)
242
- tuple6 = (120000, 10000, 15000, 100, 2000, 0.06, 0.06, 0.015, 0.015, 0, 99999999999,
252
+ tuple6 = (120000, 10000, 15000, 100, 2000,
253
+ 0.06, 0.06, 0.015, 0.015, 0, 99999999999,
243
254
  400, 0, 0, 0, 0, -40000, 0, None, None, None, None, None,
244
255
  None, None, None, None, None, None)
245
256
  expected1 = (0, 4065, 4065, 0, 0, 3252, 25000, 10000, 15000, 10100,
@@ -254,6 +265,7 @@ expected5 = (300, 4065, 4065, 0, 0, 3285.3, 25300, 10279.1875, 15000,
254
265
  10382, 17000)
255
266
  expected6 = (-40000, 4065, 4065, 0, 0, 3252, 0, 0, 15000, 10100, 17000)
256
267
 
268
+
257
269
  @pytest.mark.parametrize(
258
270
  'test_input, expected_output', [
259
271
  (tuple1, expected1),
@@ -272,7 +284,8 @@ def test_EI_PayrollTax(test_input, expected_output, skip_jit):
272
284
  print('*INPUT:', test_input)
273
285
  print('ACTUAL:', actual_output)
274
286
  print('EXPECT:', expected_output)
275
- assert 1 == 2, 'ACTUAL != EXPECT'
287
+ assert False, 'ERROR: ACTUAL != EXPECT'
288
+
276
289
 
277
290
  def test_AfterTaxIncome(skip_jit):
278
291
  '''
@@ -655,7 +668,7 @@ CTC_refundable = True
655
668
  CTC_include17 = True
656
669
  c07220 = 0 # actual value will be returned from function
657
670
  odc = 0 # actual value will be returned from function
658
- codtc_limited = 0 # actual value will be returned from function
671
+ codtc_limited = 0 # actual value will be returned from function
659
672
  tuple0 = (
660
673
  age_head, age_spouse, nu18, n24, MARS, c00100, XTOT, num,
661
674
  c05800, e07260, CR_ResidentialEnergy_hc,
@@ -673,8 +686,8 @@ expected0 = (0, 1000, 0)
673
686
 
674
687
 
675
688
  @pytest.mark.parametrize(
676
- 'test_tuple,expected_value', [
677
- (tuple0, expected0)])
689
+ 'test_tuple,expected_value', [(tuple0, expected0)]
690
+ )
678
691
  def test_ChildDepTaxCredit_2021(test_tuple, expected_value, skip_jit):
679
692
  """
680
693
  Tests the ChildDepTaxCredit function
@@ -682,6 +695,7 @@ def test_ChildDepTaxCredit_2021(test_tuple, expected_value, skip_jit):
682
695
  test_value = calcfunctions.ChildDepTaxCredit(*test_tuple)
683
696
  assert np.allclose(test_value, expected_value)
684
697
 
698
+
685
699
  # parameterization represents 2022 law
686
700
  age_head = 45
687
701
  age_spouse = 0
@@ -712,7 +726,7 @@ CTC_refundable = False
712
726
  CTC_include17 = False
713
727
  c07220 = 0 # actual value will be returned from function
714
728
  odc = 0 # actual value will be returned from function
715
- codtc_limited = 0 # actual value will be returned from function
729
+ codtc_limited = 0 # actual value will be returned from function
716
730
  tuple0 = (
717
731
  age_head, age_spouse, nu18, n24, MARS, c00100, XTOT, num,
718
732
  c05800, e07260, CR_ResidentialEnergy_hc,
@@ -739,6 +753,7 @@ def test_ChildDepTaxCredit_2022(test_tuple, expected_value, skip_jit):
739
753
  test_value = calcfunctions.ChildDepTaxCredit(*test_tuple)
740
754
  assert np.allclose(test_value, expected_value)
741
755
 
756
+
742
757
  # parameterization represents 2021 law
743
758
  CTC_new_c = 1000
744
759
  CTC_new_rt = 0
@@ -762,7 +777,7 @@ c00100 = 1000
762
777
  MARS = 4
763
778
  ptax_oasdi = 0
764
779
  c09200 = 0
765
- ctc_new = 0 # actual value will be returned from function
780
+ ctc_new = 0 # actual value will be returned from function
766
781
  tuple0 = (
767
782
  CTC_new_c, CTC_new_rt, CTC_new_c_under6_bonus,
768
783
  CTC_new_ps, CTC_new_prt, CTC_new_for_all, CTC_include17,
@@ -771,7 +786,8 @@ tuple0 = (
771
786
  n24, nu06, age_head, age_spouse, nu18, c00100, MARS, ptax_oasdi,
772
787
  c09200, ctc_new)
773
788
  # output tuple is : (ctc_new)
774
- expected0 = (0)
789
+ expected0 = 0
790
+
775
791
 
776
792
  @pytest.mark.parametrize(
777
793
  'test_tuple,expected_value', [
@@ -783,6 +799,7 @@ def test_CTCnew_2021(test_tuple, expected_value, skip_jit):
783
799
  test_value = calcfunctions.CTC_new(*test_tuple)
784
800
  assert np.allclose(test_value, expected_value)
785
801
 
802
+
786
803
  # parameterization represents 2022 law
787
804
  CTC_new_c = 0
788
805
  CTC_new_rt = 0
@@ -806,7 +823,7 @@ c00100 = 1000
806
823
  MARS = 4
807
824
  ptax_oasdi = 0
808
825
  c09200 = 0
809
- ctc_new = 0 # actual value will be returned from function
826
+ ctc_new = 0 # actual value will be returned from function
810
827
  tuple0 = (
811
828
  CTC_new_c, CTC_new_rt, CTC_new_c_under6_bonus,
812
829
  CTC_new_ps, CTC_new_prt, CTC_new_for_all, CTC_include17,
@@ -815,11 +832,12 @@ tuple0 = (
815
832
  n24, nu06, age_head, age_spouse, nu18, c00100, MARS, ptax_oasdi,
816
833
  c09200, ctc_new)
817
834
  # output tuple is : (ctc_new)
818
- expected0 = (0)
835
+ expected0 = 0
836
+
819
837
 
820
838
  @pytest.mark.parametrize(
821
- 'test_tuple,expected_value', [
822
- (tuple0, expected0)])
839
+ 'test_tuple,expected_value', [(tuple0, expected0)]
840
+ )
823
841
  def test_CTCnew_2022(test_tuple, expected_value, skip_jit):
824
842
  """
825
843
  Tests the CTCnew function
@@ -828,7 +846,7 @@ def test_CTCnew_2022(test_tuple, expected_value, skip_jit):
828
846
  assert np.allclose(test_value, expected_value)
829
847
 
830
848
 
831
-
849
+ # parameters for next test
832
850
  ymod1 = 19330 + 10200
833
851
  c02500 = 0
834
852
  c02900 = 0
@@ -859,8 +877,8 @@ expected0 = (19330, 0, 0)
859
877
 
860
878
 
861
879
  @pytest.mark.parametrize(
862
- 'test_tuple,expected_value', [
863
- (tuple0, expected0)])
880
+ 'test_tuple,expected_value', [(tuple0, expected0)]
881
+ )
864
882
  def test_AGI(test_tuple, expected_value, skip_jit):
865
883
  """
866
884
  Tests the TaxInc function
@@ -868,4 +886,3 @@ def test_AGI(test_tuple, expected_value, skip_jit):
868
886
  test_value = calcfunctions.AGI(*test_tuple)
869
887
  print('Returned from agi function: ', test_value)
870
888
  assert np.allclose(test_value, expected_value)
871
-
@@ -38,7 +38,7 @@ def test_make_calculator(cps_subsample):
38
38
  with pytest.raises(ValueError):
39
39
  Calculator(policy=pol, records=None)
40
40
  with pytest.raises(ValueError):
41
- Calculator(policy=pol, records=rec, consumption=list())
41
+ Calculator(policy=pol, records=rec, consumption=[])
42
42
 
43
43
 
44
44
  def test_make_calculator_deepcopy(cps_subsample):
@@ -522,7 +522,7 @@ def test_read_bad_json_assump_file():
522
522
  with pytest.raises(ValueError):
523
523
  Calculator.read_json_param_objects(None, 'unknown_file_name')
524
524
  with pytest.raises(TypeError):
525
- Calculator.read_json_param_objects(None, list())
525
+ Calculator.read_json_param_objects(None, [])
526
526
 
527
527
 
528
528
  def test_json_doesnt_exist():
@@ -629,7 +629,7 @@ def test_reform_documentation():
629
629
  dump = False # set to True to print documentation and force test failure
630
630
  if dump:
631
631
  print(doc)
632
- assert 1 == 2
632
+ assert False, 'ERROR: reform_documentation above'
633
633
 
634
634
 
635
635
  def test_distribution_tables(cps_subsample):
@@ -827,7 +827,7 @@ def test_itemded_component_amounts(year, cvname, hcname, puf_fullsample):
827
827
  itmded1 = calc1.weighted_total('c04470') * 1e-9
828
828
  itmded2 = calc2.weighted_total('c04470') * 1e-9
829
829
  else:
830
- raise ValueError('illegal year value = {}'.format(year))
830
+ raise ValueError(f'illegal year value = {year}')
831
831
  difference_in_total_itmded = itmded1 - itmded2
832
832
  # calculate itemized component amount
833
833
  component_amt = calc1.weighted_total(cvname) * 1e-9
@@ -841,8 +841,11 @@ def test_itemded_component_amounts(year, cvname, hcname, puf_fullsample):
841
841
  else:
842
842
  atol = 0.00001
843
843
  if not np.allclose(component_amt, difference_in_total_itmded, atol=atol):
844
- txt = '\n{}={:.3f} != {:.3f}=difference_in_total_itemized_deductions'
845
- msg = txt.format(cvname, component_amt, difference_in_total_itmded)
844
+ msg = (
845
+ f'\n{cvname}={component_amt:.3f} != '
846
+ f'{difference_in_total_itmded:.3f}='
847
+ 'difference_in_total_itemized_deductions'
848
+ )
846
849
  raise ValueError(msg)
847
850
 
848
851
 
@@ -928,6 +931,8 @@ def test_cg_top_rate():
928
931
  """
929
932
  Test top CG bracket and rate.
930
933
  """
934
+ # pylint: disable=too-many-locals
935
+
931
936
  cy = 2019
932
937
 
933
938
  # set NIIT and STD to zero to isolate CG tax rates
@@ -8,22 +8,21 @@ Compares Tax-Calculator PUF and CPS results with historical information.
8
8
  import os
9
9
  import pytest
10
10
  import numpy as np
11
- # pylint: disable=import-error,pointless-string-statement
12
- from taxcalc import Policy, Records, Calculator
13
- from taxcalc import add_income_table_row_variable, SOI_AGI_BINS
11
+ from taxcalc.policy import Policy
12
+ from taxcalc.records import Records
13
+ from taxcalc.calculator import Calculator
14
+ from taxcalc.utils import add_income_table_row_variable, SOI_AGI_BINS
14
15
 
15
16
 
16
- """
17
- 2015 IRS-SOI amounts by AGI category are from "Table 3.3 All Returns: Tax
18
- Liability, Tax Credits, and Tax Payments by Size of Adjusted Gross Income,
19
- Tax Year 2015" which is available as a spreadsheet at this URL:
20
- <https://www.irs.gov/statistics/soi-tax-stats-individual-
21
- statistical-tables-by-size-of-adjusted-gross-income>
22
- The IRS-SOI amounts are from 19 rows in the spreadsheet numbered from
23
- 11 (AGI under one dollar) through 29 (AGI $10M or more).
24
- Dollar IRS-SOI amounts are expressed in billions of dollars and rounded
25
- to the nearest one-tenth of a million dollars.
26
- """
17
+ # 2015 IRS-SOI amounts by AGI category are from "Table 3.3 All Returns: Tax
18
+ # Liability, Tax Credits, and Tax Payments by Size of Adjusted Gross Income,
19
+ # Tax Year 2015" which is available as a spreadsheet at this URL:
20
+ # <https://www.irs.gov/statistics/soi-tax-stats-individual-
21
+ # statistical-tables-by-size-of-adjusted-gross-income>
22
+ # The IRS-SOI amounts are from 19 rows in the spreadsheet numbered from
23
+ # 11 (AGI under one dollar) through 29 (AGI $10M or more).
24
+ # Dollar IRS-SOI amounts are expressed in billions of dollars and rounded
25
+ # to the nearest one-tenth of a million dollars.
27
26
  ITAX = {
28
27
  '0:EITC': {
29
28
  # Full earned income credit
@@ -203,12 +202,13 @@ def comparison(cname, calc, cmpdata, ofile):
203
202
  vardf['cvar'] = cvar
204
203
  # construct AGI table
205
204
  vardf = add_income_table_row_variable(vardf, 'c00100', SOI_AGI_BINS)
206
- gbydf = vardf.groupby('table_row', as_index=False)
207
- # write AGI table with ALL row at bottom to ofile
208
- ofile.write('TABLE for {}\n'.format(cname.split(':')[1]))
205
+ gbydf = vardf.groupby('table_row', as_index=False, observed=True)
206
+ # write AGI table with ALL row at bottom of ofile
207
+ ofile.write(f'TABLE for {cname.split(":")[1]}\n')
209
208
  results = '{:23s}\t{:8.3f}\t{:8.3f}\t{:+6.1f}\n'
210
- colhead = '{:23s}\t{:>8s}\t{:>8s}\t{:>6s}\n'
211
- ofile.write(colhead.format('AGI category', 'T-C', 'SOI', '%diff'))
209
+ colhead = f'{"AGIcategory":23s}\t{"T-C":>8s}\t{"SOI":>8s}\t{"%diff":>6s}\n'
210
+ ofile.write(colhead)
211
+ # pylint: disable=consider-using-f-string
212
212
  txc_tot = 0.
213
213
  soi_tot = 0.
214
214
  idx = 0
@@ -221,12 +221,12 @@ def comparison(cname, calc, cmpdata, ofile):
221
221
  pct_diff = 100. * ((txc / soi) - 1.)
222
222
  else:
223
223
  pct_diff = np.nan
224
- glabel = '[{:.8g}, {:.8g})'.format(grp_interval.left,
225
- grp_interval.right)
224
+ glabel = f'[{grp_interval.left:.8g}, {grp_interval.right:.8g})'
226
225
  ofile.write(results.format(glabel, txc, soi, pct_diff))
227
226
  idx += 1
228
227
  pct_diff = 100. * ((txc_tot / soi_tot) - 1.)
229
228
  ofile.write(results.format('ALL', txc_tot, soi_tot, pct_diff))
229
+ # pylint: enable=consider-using-f-string
230
230
 
231
231
 
232
232
  def nonsmall_diffs(linelist1, linelist2, small=0.0):
@@ -256,24 +256,20 @@ def nonsmall_diffs(linelist1, linelist2, small=0.0):
256
256
  for line1, line2 in zip(linelist1, linelist2):
257
257
  if line1 == line2:
258
258
  continue
259
- else:
260
- tokens1 = line1.replace(',', '').split()
261
- tokens2 = line2.replace(',', '').split()
262
- for tok1, tok2 in zip(tokens1, tokens2):
263
- tok1_isfloat = isfloat(tok1)
264
- tok2_isfloat = isfloat(tok2)
265
- if tok1_isfloat and tok2_isfloat:
266
- if abs(float(tok1) - float(tok2)) <= smallamt:
267
- continue
268
- else:
269
- return True
270
- elif not tok1_isfloat and not tok2_isfloat:
271
- if tok1 == tok2:
272
- continue
273
- else:
274
- return True
275
- else:
276
- return True
259
+ tokens1 = line1.replace(',', '').split()
260
+ tokens2 = line2.replace(',', '').split()
261
+ for tok1, tok2 in zip(tokens1, tokens2):
262
+ tok1_isfloat = isfloat(tok1)
263
+ tok2_isfloat = isfloat(tok2)
264
+ if tok1_isfloat and tok2_isfloat:
265
+ if abs(float(tok1) - float(tok2)) <= smallamt:
266
+ continue
267
+ return True
268
+ if not tok1_isfloat and not tok2_isfloat:
269
+ if tok1 == tok2:
270
+ continue
271
+ return True
272
+ return True
277
273
  return False
278
274
 
279
275
 
@@ -281,9 +277,9 @@ def differences(afilename, efilename):
281
277
  """
282
278
  Check for differences between results in afilename and efilename files.
283
279
  """
284
- with open(afilename, 'r') as afile:
280
+ with open(afilename, 'r', encoding='utf-8') as afile:
285
281
  actres = afile.read()
286
- with open(efilename, 'r') as efile:
282
+ with open(efilename, 'r', encoding='utf-8') as efile:
287
283
  expres = efile.read()
288
284
  diffs = nonsmall_diffs(actres.splitlines(True),
289
285
  expres.splitlines(True), 0.0)
@@ -292,12 +288,12 @@ def differences(afilename, efilename):
292
288
  efname = os.path.basename(efilename)
293
289
  msg = 'COMPARE RESULTS DIFFER\n'
294
290
  msg += '-------------------------------------------------\n'
295
- msg += '--- NEW RESULTS IN {} FILE ---\n'
296
- msg += '--- if new OK, copy {} to ---\n'
297
- msg += '--- {} ---\n'
291
+ msg += f'--- NEW RESULTS IN {afname} FILE ---\n'
292
+ msg += f'--- if new OK, copy {afname} to ---\n'
293
+ msg += f'--- {efname} ---\n'
298
294
  msg += '--- and rerun test. ---\n'
299
295
  msg += '-------------------------------------------------\n'
300
- raise ValueError(msg.format(afname, afname, efname))
296
+ raise ValueError(msg)
301
297
  os.remove(afilename)
302
298
 
303
299
 
@@ -325,12 +321,10 @@ def test_itax_compare(tests_path, using_puf, puf_fullsample, cps_fullsample):
325
321
  afilename = os.path.join(tests_path, 'cmpi_puf_actual.txt')
326
322
  else:
327
323
  afilename = os.path.join(tests_path, 'cmpi_cps_actual.txt')
328
- afile = open(afilename, 'w')
329
- # write compare results to afile
330
- for cname in sorted(ITAX.keys()):
331
- comparison(cname, calc, ITAX, afile)
332
- # close actual output file
333
- afile.close()
324
+ with open(afilename, 'w', encoding='utf-8') as afile:
325
+ # write compare results to afile
326
+ for cname in sorted(ITAX.keys()):
327
+ comparison(cname, calc, ITAX, afile)
334
328
  # check for differences between actual and expect output files
335
329
  efilename = afilename.replace('actual', 'expect')
336
330
  differences(afilename, efilename)
@@ -12,7 +12,9 @@ plug-in pytest-xdist is able to run all parametrized functions in parallel
12
12
  import copy
13
13
  import pytest
14
14
  import numpy as np
15
- from taxcalc import Policy, Records, Calculator # pylint: disable=import-error
15
+ from taxcalc.policy import Policy
16
+ from taxcalc.records import Records
17
+ from taxcalc.calculator import Calculator
16
18
 
17
19
 
18
20
  @pytest.fixture(scope='module', name='allparams')
@@ -49,7 +51,7 @@ def test_compatible_data_presence(allparams):
49
51
  return True
50
52
 
51
53
  # Main logic of test_compatible_data_presence function
52
- problem_pnames = list()
54
+ problem_pnames = []
53
55
  for pname in allparams:
54
56
  if 'compatible_data' in allparams[pname]:
55
57
  compatible_data = allparams[pname]['compatible_data']
@@ -61,7 +63,7 @@ def test_compatible_data_presence(allparams):
61
63
  msg = '{} has no or invalid compatible_data field'
62
64
  for pname in problem_pnames:
63
65
  print(msg.format(pname))
64
- assert 'list of problem_pnames' == 'empty list'
66
+ assert False, 'ERROR: list of problem_pnames is above'
65
67
 
66
68
 
67
69
  XX_YEAR = 2019
@@ -142,7 +144,7 @@ BATCHES = int(np.floor(NPARAMS / BATCHSIZE)) + 1
142
144
 
143
145
 
144
146
  @pytest.fixture(scope='module', name='allparams_batch',
145
- params=[i for i in range(0, BATCHES)])
147
+ params=list(range(0, BATCHES)))
146
148
  def fixture_allparams_batch(request, allparams, sorted_param_names):
147
149
  """
148
150
  Fixture for grouping Tax-Calculator parameters
@@ -229,8 +231,8 @@ def test_compatible_data(cps_subsample, puf_subsample,
229
231
  at least one of these reforms when using datasets marked compatible
230
232
  and does not differ when using datasets marked as incompatible.
231
233
  """
232
- # pylint: disable=too-many-arguments,too-many-locals
233
- # pylint: disable=too-many-statements,too-many-branches
234
+ # pylint: disable=too-many-arguments,too-many-positional-arguments
235
+ # pylint: disable=too-many-statements,too-many-branches,too-many-locals
234
236
 
235
237
  # Check NPARAMS value
236
238
  assert NPARAMS == len(allparams)
@@ -335,4 +337,4 @@ def test_compatible_data(cps_subsample, puf_subsample,
335
337
  # test failure if any errors
336
338
  if errors:
337
339
  print(errors)
338
- assert 'compatible_data' == 'invalid'
340
+ assert False, 'ERROR: compatible_data is invalid; see errors above'