taxcalc 4.4.0__py3-none-any.whl → 4.4.1__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.
- taxcalc/__init__.py +1 -1
- taxcalc/calcfunctions.py +326 -171
- taxcalc/calculator.py +35 -34
- taxcalc/cli/tc.py +6 -7
- taxcalc/consumption.py +9 -4
- taxcalc/data.py +8 -8
- taxcalc/decorators.py +3 -3
- taxcalc/growdiff.py +5 -0
- taxcalc/growfactors.py +1 -1
- taxcalc/parameters.py +85 -42
- taxcalc/policy.py +1 -1
- taxcalc/records.py +1 -0
- taxcalc/records_variables.json +6 -0
- taxcalc/taxcalcio.py +49 -44
- taxcalc/tests/cmpi_cps_expect.txt +6 -6
- taxcalc/tests/cmpi_puf_expect.txt +6 -6
- taxcalc/tests/conftest.py +42 -41
- taxcalc/tests/test_4package.py +9 -7
- taxcalc/tests/test_benefits.py +9 -8
- taxcalc/tests/test_calcfunctions.py +55 -38
- taxcalc/tests/test_calculator.py +11 -6
- taxcalc/tests/test_compare.py +44 -50
- taxcalc/tests/test_compatible_data.py +9 -7
- taxcalc/tests/test_consumption.py +38 -18
- taxcalc/tests/test_cpscsv.py +33 -31
- taxcalc/tests/test_data.py +31 -24
- taxcalc/tests/test_decorators.py +84 -32
- taxcalc/tests/test_growdiff.py +16 -13
- taxcalc/tests/test_growfactors.py +8 -8
- taxcalc/tests/test_parameters.py +54 -58
- taxcalc/tests/test_policy.py +14 -12
- taxcalc/tests/test_puf_var_stats.py +14 -14
- taxcalc/tests/test_pufcsv.py +40 -40
- taxcalc/tests/test_records.py +73 -60
- taxcalc/tests/test_reforms.py +34 -31
- taxcalc/tests/test_responses.py +4 -4
- taxcalc/tests/test_taxcalcio.py +76 -62
- taxcalc/tests/test_utils.py +78 -46
- taxcalc/utils.py +49 -42
- taxcalc/validation/taxsim35/taxsim_emulation.json +1 -5
- {taxcalc-4.4.0.dist-info → taxcalc-4.4.1.dist-info}/METADATA +19 -5
- {taxcalc-4.4.0.dist-info → taxcalc-4.4.1.dist-info}/RECORD +46 -46
- {taxcalc-4.4.0.dist-info → taxcalc-4.4.1.dist-info}/WHEEL +1 -1
- {taxcalc-4.4.0.dist-info → taxcalc-4.4.1.dist-info}/LICENSE +0 -0
- {taxcalc-4.4.0.dist-info → taxcalc-4.4.1.dist-info}/entry_points.txt +0 -0
- {taxcalc-4.4.0.dist-info → taxcalc-4.4.1.dist-info}/top_level.txt +0 -0
taxcalc/parameters.py
CHANGED
@@ -1,13 +1,14 @@
|
|
1
|
+
"""
|
2
|
+
Tax-Calculator abstract base parameter class based on paramtools package.
|
3
|
+
"""
|
4
|
+
|
1
5
|
import os
|
2
6
|
import copy
|
3
7
|
from collections import defaultdict
|
4
8
|
from typing import Union, Mapping, Any, List
|
5
|
-
|
9
|
+
import numpy as np
|
6
10
|
import marshmallow as ma
|
7
11
|
import paramtools as pt
|
8
|
-
import numpy as np
|
9
|
-
|
10
|
-
from taxcalc.growfactors import GrowFactors
|
11
12
|
|
12
13
|
|
13
14
|
class CompatibleDataSchema(ma.Schema):
|
@@ -64,8 +65,8 @@ class Parameters(pt.Parameters):
|
|
64
65
|
Check out the ParamTools
|
65
66
|
`documentation <https://paramtools.dev/api/reference.html>`_
|
66
67
|
for more information on these inherited methods.
|
67
|
-
|
68
68
|
"""
|
69
|
+
# pylint: disable=too-many-instance-attributes
|
69
70
|
defaults = None
|
70
71
|
array_first = True
|
71
72
|
label_to_extend = "year"
|
@@ -83,6 +84,8 @@ class Parameters(pt.Parameters):
|
|
83
84
|
|
84
85
|
def __init__(self, start_year=None, num_years=None, last_known_year=None,
|
85
86
|
removed=None, redefined=None, wage_indexed=None, **kwargs):
|
87
|
+
# pylint: disable=too-many-arguments,too-many-positional-arguments
|
88
|
+
|
86
89
|
# In case we need to wait for this to be called from the
|
87
90
|
# initialize method for legacy reasons.
|
88
91
|
if not start_year or not num_years:
|
@@ -121,8 +124,12 @@ class Parameters(pt.Parameters):
|
|
121
124
|
label["validators"]["range"]["max"] = last_budget_year
|
122
125
|
super().__init__(**kwargs)
|
123
126
|
|
124
|
-
def adjust(
|
125
|
-
|
127
|
+
def adjust( # pylint: disable=arguments-differ
|
128
|
+
# pylint warning W0221 is:
|
129
|
+
# Number of parameters was 6 in 'Parameters.adjust' and
|
130
|
+
# is now 5 in overriding 'Parameters.adjust' method
|
131
|
+
self, params_or_path,
|
132
|
+
print_warnings=True, raise_errors=True, **kwargs
|
126
133
|
):
|
127
134
|
"""
|
128
135
|
Update parameter values using a ParamTools styled adjustment.
|
@@ -136,8 +143,10 @@ class Parameters(pt.Parameters):
|
|
136
143
|
|
137
144
|
{
|
138
145
|
"standard_deduction": [
|
139
|
-
{"year": 2024, "marital_status": "single",
|
140
|
-
|
146
|
+
{"year": 2024, "marital_status": "single",
|
147
|
+
"value": 10000.0},
|
148
|
+
{"year": 2024, "marital_status": "joint",
|
149
|
+
"value": 10000.0}
|
141
150
|
],
|
142
151
|
"ss_rate": [{"year": 2024, "value": 0.2}]}
|
143
152
|
}
|
@@ -154,7 +163,7 @@ class Parameters(pt.Parameters):
|
|
154
163
|
adjustment : Dict
|
155
164
|
Parsed paremeter dictionary
|
156
165
|
|
157
|
-
"""
|
166
|
+
"""
|
158
167
|
if print_warnings:
|
159
168
|
_data = copy.deepcopy(self._data)
|
160
169
|
kwargs["ignore_warnings"] = False
|
@@ -177,13 +186,15 @@ class Parameters(pt.Parameters):
|
|
177
186
|
except pt.ValidationError as ve:
|
178
187
|
if self.errors and raise_errors:
|
179
188
|
raise ve
|
180
|
-
|
189
|
+
if self.errors and not raise_errors:
|
181
190
|
return {}
|
182
191
|
if print_warnings:
|
183
192
|
print("WARNING:")
|
184
193
|
print(self.warnings)
|
185
194
|
kwargs["ignore_warnings"] = True
|
195
|
+
# pylint: disable=possibly-used-before-assignment
|
186
196
|
self._data = _data
|
197
|
+
# pylint: enable=possibly-used-before-assignment
|
187
198
|
_warnings = copy.deepcopy(self._warnings)
|
188
199
|
self._warnings = {}
|
189
200
|
self._errors = {}
|
@@ -242,6 +253,8 @@ class Parameters(pt.Parameters):
|
|
242
253
|
wiped out after the year in which the value is adjusted for the
|
243
254
|
same hard-coding reason.
|
244
255
|
"""
|
256
|
+
# pylint: disable=too-many-statements,too-many-locals,too-many-branches
|
257
|
+
|
245
258
|
# Temporarily turn off extra ops during the intermediary adjustments
|
246
259
|
# so that expensive and unnecessary operations are not run.
|
247
260
|
label_to_extend = self.label_to_extend
|
@@ -310,7 +323,7 @@ class Parameters(pt.Parameters):
|
|
310
323
|
self.delete(to_delete, **kwargs)
|
311
324
|
|
312
325
|
# 1.b For all others, these are years after last_known_year.
|
313
|
-
last_known_year
|
326
|
+
# last_known_year=max(cpi_min_year["year"],self._last_known_year)
|
314
327
|
# calculate 2026 value, using new inflation rates, for parameters
|
315
328
|
# that revert to their pre-TCJA values.
|
316
329
|
long_params = ['II_brk7', 'II_brk6', 'II_brk5', 'II_brk4',
|
@@ -362,7 +375,15 @@ class Parameters(pt.Parameters):
|
|
362
375
|
):
|
363
376
|
continue
|
364
377
|
if self._data[param].get("indexed", False):
|
365
|
-
|
378
|
+
# pylint: disable=singleton-comparison
|
379
|
+
to_delete[param] = self.sel[param]["_auto"] == True
|
380
|
+
# pylint warning message:
|
381
|
+
# Comparison 'self.sel[param]['_auto'] == True' should
|
382
|
+
# be 'self.sel[param]['_auto'] is True' if checking for
|
383
|
+
# the singleton value True, or
|
384
|
+
# 'bool(self.sel[param]['_auto'])' if testing for
|
385
|
+
# truthiness
|
386
|
+
# pylint: enable=singleton-comparison
|
366
387
|
needs_reset.append(param)
|
367
388
|
|
368
389
|
self.delete(to_delete, **kwargs)
|
@@ -405,13 +426,14 @@ class Parameters(pt.Parameters):
|
|
405
426
|
min_index_change_year, strict=False
|
406
427
|
)
|
407
428
|
|
408
|
-
if
|
429
|
+
if list(vos):
|
409
430
|
min_adj_year = min(vos, key=lambda vo: vo["year"])[
|
410
431
|
"year"
|
411
432
|
]
|
412
433
|
self.delete(
|
413
434
|
{
|
414
|
-
base_param:
|
435
|
+
base_param:
|
436
|
+
self.sel[base_param]["year"] > min_adj_year
|
415
437
|
}
|
416
438
|
)
|
417
439
|
super().adjust({base_param: vos}, **kwargs)
|
@@ -482,40 +504,45 @@ class Parameters(pt.Parameters):
|
|
482
504
|
)
|
483
505
|
return adj
|
484
506
|
|
485
|
-
def get_index_rate(self, param,
|
507
|
+
def get_index_rate(self, param, lte_val):
|
486
508
|
"""
|
487
509
|
Initalize indexing data and return the indexing rate value
|
488
|
-
depending on the parameter name and
|
489
|
-
label_to_extend.
|
510
|
+
depending on the parameter name and lte_val (that is, the
|
511
|
+
label_to_extend_val), the value of label_to_extend.
|
490
512
|
Returns: rate to use for indexing.
|
491
513
|
"""
|
492
514
|
if not self._inflation_rates or not self._wage_growth_rates:
|
493
515
|
self.set_rates()
|
494
516
|
if param in self._wage_indexed:
|
495
|
-
return self.wage_growth_rates(year=
|
496
|
-
|
497
|
-
return self.inflation_rates(year=label_to_extend_val)
|
517
|
+
return self.wage_growth_rates(year=lte_val)
|
518
|
+
return self.inflation_rates(year=lte_val)
|
498
519
|
|
499
520
|
def set_rates(self):
|
500
521
|
"""
|
501
|
-
This method is implemented by classes inheriting
|
502
|
-
Parameters.
|
522
|
+
This method is implemented by classes inheriting Parameters.
|
503
523
|
"""
|
504
524
|
raise NotImplementedError()
|
505
525
|
|
506
526
|
def wage_growth_rates(self, year=None):
|
527
|
+
"""
|
528
|
+
Return wage growth rates used in parameter indexing.
|
529
|
+
"""
|
507
530
|
if year is not None:
|
508
531
|
syr = max(self.start_year, self._gfactors.first_year)
|
509
532
|
return self._wage_growth_rates[year - syr]
|
510
533
|
return self._wage_growth_rates or []
|
511
534
|
|
512
535
|
def inflation_rates(self, year=None):
|
536
|
+
"""
|
537
|
+
Return price inflation rates used in parameter indexing.
|
538
|
+
"""
|
513
539
|
if year is not None:
|
514
540
|
syr = max(self.start_year, self._gfactors.first_year)
|
515
541
|
return self._inflation_rates[year - syr]
|
516
542
|
return self._inflation_rates or []
|
517
543
|
|
518
|
-
# alias methods below
|
544
|
+
# alias methods below:
|
545
|
+
|
519
546
|
def initialize(self, start_year, num_years, last_known_year=None,
|
520
547
|
removed=None, redefined=None, wage_indexed=None,
|
521
548
|
**kwargs):
|
@@ -523,13 +550,15 @@ class Parameters(pt.Parameters):
|
|
523
550
|
Legacy method for initializing a Parameters instance. Projects
|
524
551
|
should use the __init__ method in the future.
|
525
552
|
"""
|
526
|
-
#
|
553
|
+
# pylint: disable=too-many-arguments,too-many-positional-arguments
|
554
|
+
# Handle case where project hasn't been initialized yet
|
527
555
|
if getattr(self, "_data", None) is None:
|
528
556
|
return Parameters.__init__(
|
529
557
|
self, start_year, num_years, last_known_year=last_known_year,
|
530
558
|
removed=removed, redefined=redefined,
|
531
559
|
wage_indexed=wage_indexed, **kwargs
|
532
560
|
)
|
561
|
+
return None # pragma: no cover
|
533
562
|
|
534
563
|
def _update(self, revision, print_warnings, raise_errors):
|
535
564
|
"""
|
@@ -553,13 +582,16 @@ class Parameters(pt.Parameters):
|
|
553
582
|
|
554
583
|
{
|
555
584
|
"standard_deduction": [
|
556
|
-
{"year": 2024, "marital_status": "single",
|
557
|
-
|
585
|
+
{"year": 2024, "marital_status": "single",
|
586
|
+
"value": 10000.0},
|
587
|
+
{"year": 2024, "marital_status": "joint",
|
588
|
+
"value": 10000.0}
|
558
589
|
],
|
559
590
|
"ss_rate": [{"year": 2024, "value": 0.2}]}
|
560
591
|
}
|
561
592
|
|
562
|
-
"""
|
593
|
+
"""
|
594
|
+
# pylint: disable=too-many-branches
|
563
595
|
if not isinstance(revision, dict):
|
564
596
|
raise pt.ValidationError(
|
565
597
|
{"errors": {"schema": "Revision must be a dictionary."}},
|
@@ -651,30 +683,37 @@ class Parameters(pt.Parameters):
|
|
651
683
|
)
|
652
684
|
|
653
685
|
def set_year(self, year):
|
686
|
+
"""Specify parameter year"""
|
654
687
|
self.set_state(year=year)
|
655
688
|
|
656
689
|
@property
|
657
690
|
def current_year(self):
|
691
|
+
"""Propery docstring"""
|
658
692
|
return self.label_grid["year"][0]
|
659
693
|
|
660
694
|
@property
|
661
695
|
def start_year(self):
|
696
|
+
"""Propery docstring"""
|
662
697
|
return self._stateless_label_grid["year"][0]
|
663
698
|
|
664
699
|
@property
|
665
700
|
def end_year(self):
|
701
|
+
"""Propery docstring"""
|
666
702
|
return self._stateless_label_grid["year"][-1]
|
667
703
|
|
668
704
|
@property
|
669
705
|
def num_years(self):
|
706
|
+
"""Propery docstring"""
|
670
707
|
return self.end_year - self.start_year + 1
|
671
708
|
|
672
709
|
@property
|
673
710
|
def parameter_warnings(self):
|
711
|
+
"""Propery docstring"""
|
674
712
|
return self.errors or {}
|
675
713
|
|
676
714
|
@property
|
677
715
|
def parameter_errors(self):
|
716
|
+
"""Propery docstring"""
|
678
717
|
return self.errors or {}
|
679
718
|
|
680
719
|
@staticmethod
|
@@ -698,14 +737,17 @@ class Parameters(pt.Parameters):
|
|
698
737
|
|
699
738
|
Some examples of valid links are:
|
700
739
|
|
701
|
-
- HTTP: ``https://raw.githubusercontent.com/PSLmodels/Tax-Calculator/
|
740
|
+
- HTTP: ``https://raw.githubusercontent.com/PSLmodels/Tax-Calculator/
|
741
|
+
master/taxcalc/reforms/2017_law.json``
|
702
742
|
|
703
|
-
- Github API: ``github://PSLmodels:Tax-Calculator@master/taxcalc/
|
743
|
+
- Github API: ``github://PSLmodels:Tax-Calculator@master/taxcalc/
|
744
|
+
reforms/2017_law.json``
|
704
745
|
|
705
746
|
Checkout the ParamTools
|
706
|
-
`docs <https://paramtools.dev/_modules/paramtools/
|
747
|
+
`docs <https://paramtools.dev/_modules/paramtools/
|
748
|
+
parameters.html#Parameters.read_params>`_
|
707
749
|
for more information on valid file URLs.
|
708
|
-
"""
|
750
|
+
"""
|
709
751
|
# embedded function used only in _read_json_revision staticmethod
|
710
752
|
def convert_year_to_int(syr_dict):
|
711
753
|
"""
|
@@ -713,10 +755,10 @@ class Parameters(pt.Parameters):
|
|
713
755
|
keys, into a dictionary with the same structure but having integer
|
714
756
|
years as secondary keys.
|
715
757
|
"""
|
716
|
-
iyr_dict =
|
758
|
+
iyr_dict = {}
|
717
759
|
for pkey, sdict in syr_dict.items():
|
718
760
|
assert isinstance(pkey, str)
|
719
|
-
iyr_dict[pkey] =
|
761
|
+
iyr_dict[pkey] = {}
|
720
762
|
assert isinstance(sdict, dict)
|
721
763
|
for skey, val in sdict.items():
|
722
764
|
assert isinstance(skey, str)
|
@@ -726,7 +768,7 @@ class Parameters(pt.Parameters):
|
|
726
768
|
# end of embedded function
|
727
769
|
# process the main function arguments
|
728
770
|
if obj is None:
|
729
|
-
return
|
771
|
+
return {}
|
730
772
|
|
731
773
|
full_dict = pt.read_json(obj)
|
732
774
|
|
@@ -743,6 +785,9 @@ class Parameters(pt.Parameters):
|
|
743
785
|
return convert_year_to_int(single_dict)
|
744
786
|
|
745
787
|
def metadata(self):
|
788
|
+
"""
|
789
|
+
Return parameter specification.
|
790
|
+
"""
|
746
791
|
return self.specification(meta_data=True, use_state=False)
|
747
792
|
|
748
793
|
@staticmethod
|
@@ -752,7 +797,7 @@ class Parameters(pt.Parameters):
|
|
752
797
|
assumed to have a param:year:value format.
|
753
798
|
"""
|
754
799
|
assert isinstance(revision, dict)
|
755
|
-
years =
|
800
|
+
years = []
|
756
801
|
for _, paramdata in revision.items():
|
757
802
|
assert isinstance(paramdata, dict)
|
758
803
|
for year, _ in paramdata.items():
|
@@ -774,8 +819,7 @@ class Parameters(pt.Parameters):
|
|
774
819
|
return self.to_array(
|
775
820
|
attr[1:], year=list(range(self.start_year, self.end_year + 1))
|
776
821
|
)
|
777
|
-
|
778
|
-
raise AttributeError(f"{attr} is not defined.")
|
822
|
+
raise AttributeError(f"{attr} is not defined.")
|
779
823
|
|
780
824
|
|
781
825
|
TaxcalcReform = Union[str, Mapping[int, Any]]
|
@@ -815,7 +859,6 @@ def is_paramtools_format(params: Union[TaxcalcReform, ParamToolsAdjustment]):
|
|
815
859
|
for data in params.values():
|
816
860
|
if isinstance(data, dict):
|
817
861
|
return False # taxcalc reform
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
return True
|
862
|
+
# Not doing a specific check to see if the value is a list
|
863
|
+
# since it could be a list or just a scalar value.
|
864
|
+
return True
|
taxcalc/policy.py
CHANGED
@@ -158,7 +158,7 @@ class Policy(Parameters):
|
|
158
158
|
Policy.DEFAULTS_FILE_PATH,
|
159
159
|
Policy.DEFAULTS_FILE_NAME
|
160
160
|
)
|
161
|
-
with open(path, 'r',
|
161
|
+
with open(path, 'r', encoding='utf-8') as f:
|
162
162
|
defaults = json.loads(f.read()) # pylint: disable=protected-access
|
163
163
|
return [k for k in defaults if k != "schema"]
|
164
164
|
|
taxcalc/records.py
CHANGED
@@ -136,6 +136,7 @@ class Records(Data):
|
|
136
136
|
adjust_ratios=PUF_RATIOS_FILENAME,
|
137
137
|
exact_calculations=False,
|
138
138
|
weights_scale=0.01):
|
139
|
+
# pylint: disable=too-many-positional-arguments
|
139
140
|
# pylint: disable=no-member,too-many-branches
|
140
141
|
if isinstance(weights, str):
|
141
142
|
weights = os.path.join(Records.CODE_PATH, weights)
|
taxcalc/records_variables.json
CHANGED
@@ -842,6 +842,12 @@
|
|
842
842
|
"form": {"2013-2013": "1040 line 46 minus 1040 line 55",
|
843
843
|
"2014-2016": "1040 line 47 minus 1040 line 56"}
|
844
844
|
},
|
845
|
+
"c32800": {
|
846
|
+
"type": "float",
|
847
|
+
"desc": "Child and dependent care expenses capped by policy (not by earnings)",
|
848
|
+
"form": {"2013-2013": "1040 line 48",
|
849
|
+
"2014-2016": "1040 line 49"}
|
850
|
+
},
|
845
851
|
"c07180": {
|
846
852
|
"type": "float",
|
847
853
|
"desc": "Nonrefundable credit for child and dependent care expenses from Form 2441",
|
taxcalc/taxcalcio.py
CHANGED
@@ -66,8 +66,8 @@ class TaxCalcIO():
|
|
66
66
|
|
67
67
|
def __init__(self, input_data, tax_year, baseline, reform, assump,
|
68
68
|
outdir=None):
|
69
|
-
# pylint: disable=too-many-arguments,too-many-
|
70
|
-
# pylint: disable=too-many-branches,too-many-statements
|
69
|
+
# pylint: disable=too-many-arguments,too-many-positional-arguments
|
70
|
+
# pylint: disable=too-many-branches,too-many-statements,too-many-locals
|
71
71
|
self.gf_reform = None
|
72
72
|
self.errmsg = ''
|
73
73
|
# check name and existence of INPUT file
|
@@ -82,17 +82,17 @@ class TaxCalcIO():
|
|
82
82
|
fname = os.path.basename(input_data)
|
83
83
|
# check if fname ends with ".csv"
|
84
84
|
if fname.endswith('.csv'):
|
85
|
-
inp = '{
|
85
|
+
inp = f'{fname[:-4]}-{str(tax_year)[2:]}'
|
86
86
|
else:
|
87
87
|
msg = 'INPUT file name does not end in .csv'
|
88
|
-
self.errmsg += 'ERROR: {}\n'
|
88
|
+
self.errmsg += f'ERROR: {msg}\n'
|
89
89
|
# check existence of INPUT file
|
90
90
|
self.puf_input_data = input_data.endswith('puf.csv')
|
91
91
|
self.cps_input_data = input_data.endswith('cps.csv')
|
92
92
|
self.tmd_input_data = input_data.endswith('tmd.csv')
|
93
93
|
if not self.cps_input_data and not os.path.isfile(input_data):
|
94
94
|
msg = 'INPUT file could not be found'
|
95
|
-
self.errmsg += 'ERROR: {}\n'
|
95
|
+
self.errmsg += f'ERROR: {msg}\n'
|
96
96
|
# if tmd_input_data is True, construct weights and gfactor paths
|
97
97
|
if self.tmd_input_data: # pragma: no cover
|
98
98
|
tmd_dir = os.path.dirname(input_data)
|
@@ -106,15 +106,15 @@ class TaxCalcIO():
|
|
106
106
|
self.tmd_gfactor = os.path.join(tmd_dir, 'tmd_growfactors.csv')
|
107
107
|
if not os.path.isfile(self.tmd_weights):
|
108
108
|
msg = f'weights file {self.tmd_weights} could not be found'
|
109
|
-
self.errmsg += 'ERROR: {}\n'
|
109
|
+
self.errmsg += f'ERROR: {msg}\n'
|
110
110
|
if not os.path.isfile(self.tmd_gfactor):
|
111
111
|
msg = f'gfactor file {self.tmd_gfactor} could not be found'
|
112
|
-
self.errmsg += 'ERROR: {}\n'
|
112
|
+
self.errmsg += f'ERROR: {msg}\n'
|
113
113
|
elif isinstance(input_data, pd.DataFrame):
|
114
|
-
inp = 'df-{
|
114
|
+
inp = f'df-{str(tax_year)[2:]}'
|
115
115
|
else:
|
116
116
|
msg = 'INPUT is neither string nor Pandas DataFrame'
|
117
|
-
self.errmsg += 'ERROR: {}\n'
|
117
|
+
self.errmsg += f'ERROR: {msg}\n'
|
118
118
|
# check name and existence of BASELINE file
|
119
119
|
bas = '-x'
|
120
120
|
if baseline is None:
|
@@ -124,17 +124,17 @@ class TaxCalcIO():
|
|
124
124
|
fname = os.path.basename(baseline)
|
125
125
|
# check if fname ends with ".json"
|
126
126
|
if fname.endswith('.json'):
|
127
|
-
bas = '-{
|
127
|
+
bas = f'-{fname[:-5]}'
|
128
128
|
else:
|
129
129
|
msg = 'BASELINE file name does not end in .json'
|
130
|
-
self.errmsg += 'ERROR: {}\n'
|
130
|
+
self.errmsg += f'ERROR: {msg}\n'
|
131
131
|
# check existence of BASELINE file
|
132
132
|
if not os.path.isfile(baseline):
|
133
133
|
msg = 'BASELINE file could not be found'
|
134
|
-
self.errmsg += 'ERROR: {}\n'
|
134
|
+
self.errmsg += f'ERROR: {msg}\n'
|
135
135
|
else:
|
136
136
|
msg = 'TaxCalcIO.ctor: baseline is neither None nor str'
|
137
|
-
self.errmsg += 'ERROR: {}\n'
|
137
|
+
self.errmsg += f'ERROR: {msg}\n'
|
138
138
|
# check name(s) and existence of REFORM file(s)
|
139
139
|
ref = '-x'
|
140
140
|
if reform is None:
|
@@ -150,12 +150,12 @@ class TaxCalcIO():
|
|
150
150
|
fname = os.path.basename(rfm)
|
151
151
|
# check if fname ends with ".json"
|
152
152
|
if not fname.endswith('.json'):
|
153
|
-
msg = '{} does not end in .json'
|
154
|
-
self.errmsg += 'ERROR: REFORM file name {}\n'
|
153
|
+
msg = f'{fname} does not end in .json'
|
154
|
+
self.errmsg += f'ERROR: REFORM file name {msg}\n'
|
155
155
|
# check existence of REFORM file
|
156
156
|
if not os.path.isfile(rfm):
|
157
|
-
msg = '{} could not be found'
|
158
|
-
self.errmsg += 'ERROR: REFORM file {}\n'
|
157
|
+
msg = f'{rfm} could not be found'
|
158
|
+
self.errmsg += f'ERROR: REFORM file {msg}\n'
|
159
159
|
# add fname to list of refnames used in output file names
|
160
160
|
refnames.append(fname)
|
161
161
|
# create (possibly compound) reform name for output file names
|
@@ -165,10 +165,10 @@ class TaxCalcIO():
|
|
165
165
|
num_refnames += 1
|
166
166
|
if num_refnames > 1:
|
167
167
|
ref += '+'
|
168
|
-
ref += '{
|
168
|
+
ref += f'{refname[:-5]}'
|
169
169
|
else:
|
170
170
|
msg = 'TaxCalcIO.ctor: reform is neither None nor str'
|
171
|
-
self.errmsg += 'ERROR: {}\n'
|
171
|
+
self.errmsg += f'ERROR: {msg}\n'
|
172
172
|
# check name and existence of ASSUMP file
|
173
173
|
asm = '-x'
|
174
174
|
if assump is None:
|
@@ -178,17 +178,17 @@ class TaxCalcIO():
|
|
178
178
|
fname = os.path.basename(assump)
|
179
179
|
# check if fname ends with ".json"
|
180
180
|
if fname.endswith('.json'):
|
181
|
-
asm = '-{
|
181
|
+
asm = f'-{fname[:-5]}'
|
182
182
|
else:
|
183
183
|
msg = 'ASSUMP file name does not end in .json'
|
184
|
-
self.errmsg += 'ERROR: {}\n'
|
184
|
+
self.errmsg += f'ERROR: {msg}\n'
|
185
185
|
# check existence of ASSUMP file
|
186
186
|
if not os.path.isfile(assump):
|
187
187
|
msg = 'ASSUMP file could not be found'
|
188
|
-
self.errmsg += 'ERROR: {}\n'
|
188
|
+
self.errmsg += f'ERROR: {msg}\n'
|
189
189
|
else:
|
190
190
|
msg = 'TaxCalcIO.ctor: assump is neither None nor str'
|
191
|
-
self.errmsg += 'ERROR: {}\n'
|
191
|
+
self.errmsg += f'ERROR: {msg}\n'
|
192
192
|
# check name and existence of OUTDIR
|
193
193
|
if outdir is None:
|
194
194
|
valid_outdir = True
|
@@ -199,13 +199,13 @@ class TaxCalcIO():
|
|
199
199
|
else:
|
200
200
|
valid_outdir = False
|
201
201
|
msg = 'OUTDIR could not be found'
|
202
|
-
self.errmsg += 'ERROR: {}\n'
|
202
|
+
self.errmsg += f'ERROR: {msg}\n'
|
203
203
|
else:
|
204
204
|
valid_outdir = False
|
205
205
|
msg = 'TaxCalcIO.ctor: outdir is neither None nor str'
|
206
|
-
self.errmsg += 'ERROR: {}\n'
|
206
|
+
self.errmsg += f'ERROR: {msg}\n'
|
207
207
|
# create OUTPUT file name and delete any existing output files
|
208
|
-
output_filename = '{}{}{}{}.csv'
|
208
|
+
output_filename = f'{inp}{bas}{ref}{asm}.csv'
|
209
209
|
if outdir is None:
|
210
210
|
self._output_filename = output_filename
|
211
211
|
delete_old_files = True
|
@@ -246,8 +246,8 @@ class TaxCalcIO():
|
|
246
246
|
specifies whether or not exact tax calculations are done without
|
247
247
|
any smoothing of "stair-step" provisions in the tax law.
|
248
248
|
"""
|
249
|
-
# pylint: disable=too-many-arguments,too-many-
|
250
|
-
# pylint: disable=too-many-statements,too-many-branches
|
249
|
+
# pylint: disable=too-many-arguments,too-many-positional-arguments
|
250
|
+
# pylint: disable=too-many-statements,too-many-branches,too-many-locals
|
251
251
|
self.errmsg = ''
|
252
252
|
# instantiate base and reform GrowFactors objects
|
253
253
|
if self.tmd_input_data:
|
@@ -300,7 +300,7 @@ class TaxCalcIO():
|
|
300
300
|
try:
|
301
301
|
gdiff_baseline.update_growdiff(paramdict['growdiff_baseline'])
|
302
302
|
except paramtools.ValidationError as valerr_msg:
|
303
|
-
self.errmsg += valerr_msg
|
303
|
+
self.errmsg += str(valerr_msg)
|
304
304
|
# apply gdiff_baseline to gfactor_base
|
305
305
|
gdiff_baseline.apply_to(gfactors_base)
|
306
306
|
# specify gdiff_response object
|
@@ -308,7 +308,7 @@ class TaxCalcIO():
|
|
308
308
|
try:
|
309
309
|
gdiff_response.update_growdiff(paramdict['growdiff_response'])
|
310
310
|
except paramtools.ValidationError as valerr_msg:
|
311
|
-
self.errmsg += valerr_msg
|
311
|
+
self.errmsg += str(valerr_msg)
|
312
312
|
# apply gdiff_baseline and gdiff_response to gfactor_ref
|
313
313
|
gdiff_baseline.apply_to(gfactors_ref)
|
314
314
|
gdiff_response.apply_to(gfactors_ref)
|
@@ -323,7 +323,7 @@ class TaxCalcIO():
|
|
323
323
|
for _, errors in base.parameter_errors.items():
|
324
324
|
self.errmsg += "\n".join(errors)
|
325
325
|
except paramtools.ValidationError as valerr_msg:
|
326
|
-
self.errmsg += valerr_msg
|
326
|
+
self.errmsg += str(valerr_msg)
|
327
327
|
# ... the reform Policy object
|
328
328
|
if self.specified_reform:
|
329
329
|
pol = Policy(gfactors=gfactors_ref, last_budget_year=last_b_year)
|
@@ -337,7 +337,7 @@ class TaxCalcIO():
|
|
337
337
|
for _, errors in pol.parameter_errors.items():
|
338
338
|
self.errmsg += "\n".join(errors)
|
339
339
|
except paramtools.ValidationError as valerr_msg:
|
340
|
-
self.errmsg += valerr_msg
|
340
|
+
self.errmsg += str(valerr_msg)
|
341
341
|
else:
|
342
342
|
pol = Policy(gfactors=gfactors_base, last_budget_year=last_b_year)
|
343
343
|
# create Consumption object
|
@@ -345,7 +345,7 @@ class TaxCalcIO():
|
|
345
345
|
try:
|
346
346
|
con.update_consumption(paramdict['consumption'])
|
347
347
|
except paramtools.ValidationError as valerr_msg:
|
348
|
-
self.errmsg += valerr_msg
|
348
|
+
self.errmsg += str(valerr_msg)
|
349
349
|
# any errors imply cannot proceed with calculations
|
350
350
|
if self.errmsg:
|
351
351
|
return
|
@@ -431,9 +431,8 @@ class TaxCalcIO():
|
|
431
431
|
valid_set = recs_vinfo.USABLE_READ_VARS | recs_vinfo.CALCULATED_VARS
|
432
432
|
for var in dump_vars_list:
|
433
433
|
if var not in valid_set:
|
434
|
-
msg = 'invalid variable name in tcdumpvars file: {}'
|
435
|
-
|
436
|
-
self.errmsg += 'ERROR: {}\n'.format(msg)
|
434
|
+
msg = f'invalid variable name in tcdumpvars file: {var}'
|
435
|
+
self.errmsg += f'ERROR: {msg}\n'
|
437
436
|
# add essential variables even if not on custom list
|
438
437
|
if 'RECID' not in dump_vars_list:
|
439
438
|
dump_vars_list.append('RECID')
|
@@ -494,7 +493,8 @@ class TaxCalcIO():
|
|
494
493
|
-------
|
495
494
|
Nothing
|
496
495
|
"""
|
497
|
-
# pylint: disable=too-many-arguments,too-many-
|
496
|
+
# pylint: disable=too-many-arguments,too-many-positional-arguments
|
497
|
+
# pylint: disable=too-many-branches,too-many-locals
|
498
498
|
if self.puf_input_data and self.calc.reform_warnings:
|
499
499
|
warn = 'PARAMETER VALUE WARNING(S): {}\n{}{}' # pragma: no cover
|
500
500
|
print( # pragma: no cover
|
@@ -599,6 +599,7 @@ class TaxCalcIO():
|
|
599
599
|
"""
|
600
600
|
Write dump output to SQLite3 database table dump.
|
601
601
|
"""
|
602
|
+
# pylint: disable=too-many-arguments,too-many-positional-arguments
|
602
603
|
db_fname = self._output_filename.replace('.csv', '.db')
|
603
604
|
dbcon = sqlite3.connect(db_fname)
|
604
605
|
# write baseline table
|
@@ -685,8 +686,9 @@ class TaxCalcIO():
|
|
685
686
|
weighted_sum, 'combined', include_groups=False
|
686
687
|
).values[:, 1]
|
687
688
|
# write decile table to text file
|
688
|
-
row = 'Weighted Tax {} by Baseline Expanded-Income Decile\n'
|
689
|
-
tfile.write(row
|
689
|
+
row = f'Weighted Tax {tkind} by Baseline Expanded-Income Decile\n'
|
690
|
+
tfile.write(row)
|
691
|
+
# pylint: disable=consider-using-f-string
|
690
692
|
rowfmt = '{}{}{}{}{}{}\n'
|
691
693
|
row = rowfmt.format(' Returns',
|
692
694
|
' ExpInc',
|
@@ -704,7 +706,7 @@ class TaxCalcIO():
|
|
704
706
|
tfile.write(row)
|
705
707
|
rowfmt = '{:9.2f}{:10.1f}{:10.1f}{:10.1f}{:10.1f}{:10.1f}\n'
|
706
708
|
for decile in range(0, 10):
|
707
|
-
row = '{:2d}'
|
709
|
+
row = f'{decile:2d}'
|
708
710
|
row += rowfmt.format(rtns_series[decile] * 1e-6,
|
709
711
|
xinc_series[decile] * 1e-9,
|
710
712
|
itax_series[decile] * 1e-9,
|
@@ -720,6 +722,7 @@ class TaxCalcIO():
|
|
720
722
|
htax_series.sum() * 1e-9,
|
721
723
|
ctax_series.sum() * 1e-9)
|
722
724
|
tfile.write(row)
|
725
|
+
# pylint: enable=consider-using-f-string
|
723
726
|
del gdfx
|
724
727
|
del rtns_series
|
725
728
|
del xinc_series
|
@@ -776,10 +779,12 @@ class TaxCalcIO():
|
|
776
779
|
"""
|
777
780
|
Write HTML graph file with title but no graph for specified reason.
|
778
781
|
"""
|
779
|
-
txt = (
|
780
|
-
|
781
|
-
|
782
|
-
|
782
|
+
txt = (
|
783
|
+
'<html>\n'
|
784
|
+
f'<head><title>{title}</title></head>\n'
|
785
|
+
f'<body><center<h1>{reason}</h1></center></body>\n'
|
786
|
+
'</html>\n'
|
787
|
+
)
|
783
788
|
with open(fname, 'w', encoding='utf-8') as gfile:
|
784
789
|
gfile.write(txt)
|
785
790
|
|