Skip to content

Commit

Permalink
Merge pull request #2856 from martinholmer/flexible-last-budget-year
Browse files Browse the repository at this point in the history
Make a Policy object's last budget year be flexible
  • Loading branch information
jdebacker authored Dec 18, 2024
2 parents 57e0f62 + 43464dd commit 870db89
Show file tree
Hide file tree
Showing 17 changed files with 205 additions and 102 deletions.
8 changes: 4 additions & 4 deletions conda.recipe/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ build:
requirements:
build:
- "python>=3.10, <3.13"
- "numpy>=1.26,<1.27"
- "numpy>=1.26"
- "pandas>=2.2"
- "bokeh>=2.4"
- "paramtools>=0.18.3"
- "paramtools>=0.19.0"
- numba
- curl
- openpyxl
- behresp

run:
- "python>=3.10, <3.13"
- "numpy>=1.26,<1.27"
- "numpy>=1.26"
- "pandas>=2.2"
- "bokeh>=2.4"
- "paramtools>=0.18.3"
- "paramtools>=0.19.0"
- numba
- curl
- openpyxl
Expand Down
5 changes: 3 additions & 2 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ channels:
- conda-forge
dependencies:
- "python>=3.10, <3.13"
- "numpy>=1.26,<1.27"
- "numpy>=1.26"
- "pandas>=2.2"
- "bokeh>=2.4"
- numba
- curl
- setuptools
- pytest
- pytest-xdist
- pycodestyle
Expand All @@ -18,4 +19,4 @@ dependencies:
- pip
- pip:
- jupyter-book
- "paramtools>=0.18.3"
- "paramtools>=0.19.0"
10 changes: 4 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@
"include_package_data": True,
"name": "taxcalc",
"install_requires": [
"setuptools",
"numpy",
"pandas",
"bokeh",
"numpy>=1.26",
"pandas>=2.2",
"bokeh>=2.4",
"numba",
"requests",
"paramtools>=0.18.3",
"paramtools>=0.19.0",
],
"classifiers": [
"Development Status :: 4 - Beta",
Expand Down
12 changes: 5 additions & 7 deletions taxcalc.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: taxcalc
Version: 4.3.4
Version: 4.3.5
Summary: taxcalc
Home-page: https://github.com/PSLmodels/Tax-Calculator
Download-URL: https://github.com/PSLmodels/Tax-Calculator
Expand All @@ -18,13 +18,11 @@ Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: setuptools
Requires-Dist: numpy
Requires-Dist: pandas
Requires-Dist: bokeh
Requires-Dist: numpy>=1.26
Requires-Dist: pandas>=2.2
Requires-Dist: bokeh>=2.4
Requires-Dist: numba
Requires-Dist: requests
Requires-Dist: paramtools>=0.18.3
Requires-Dist: paramtools>=0.19.0

| | |
| --- | --- |
Expand Down
10 changes: 4 additions & 6 deletions taxcalc.egg-info/requires.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
setuptools
numpy
pandas
bokeh
numpy>=1.26
pandas>=2.2
bokeh>=2.4
numba
requests
paramtools>=0.18.3
paramtools>=0.19.0
2 changes: 1 addition & 1 deletion taxcalc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
from taxcalc.utils import *
from taxcalc.cli import *

__version__ = '4.3.5'
__version__ = '4.3.5a'
__min_python3_version__ = 10
__max_python3_version__ = 12
10 changes: 5 additions & 5 deletions taxcalc/consumption.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,22 @@ class Consumption(Parameters):
Parameters
----------
none
last_budget_year: integer
user-defined last parameter extrapolation year
Returns
-------
class instance: Consumption
"""

JSON_START_YEAR = Policy.JSON_START_YEAR
DEFAULT_NUM_YEARS = Policy.DEFAULT_NUM_YEARS
DEFAULTS_FILE_NAME = 'consumption.json'
DEFAULTS_FILE_PATH = os.path.abspath(os.path.dirname(__file__))

def __init__(self):
def __init__(self, last_budget_year=Policy.LAST_BUDGET_YEAR):
super().__init__()
self.initialize(Consumption.JSON_START_YEAR,
Consumption.DEFAULT_NUM_YEARS)
nyrs = Policy.number_of_years(last_budget_year)
self.initialize(Consumption.JSON_START_YEAR, nyrs)

@staticmethod
def read_json_update(obj):
Expand Down
15 changes: 5 additions & 10 deletions taxcalc/growdiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,22 @@ class GrowDiff(Parameters):
Parameters
----------
none
last_budget_year: integer
user-defined last parameter extrapolation year
Returns
-------
class instance: GrowDiff
"""

JSON_START_YEAR = Policy.JSON_START_YEAR
DEFAULT_NUM_YEARS = Policy.DEFAULT_NUM_YEARS
DEFAULTS_FILE_NAME = 'growdiff.json'
DEFAULTS_FILE_PATH = os.path.abspath(os.path.dirname(__file__))

def __init__(self):
def __init__(self, last_budget_year=Policy.LAST_BUDGET_YEAR):
super().__init__()
self.initialize(GrowDiff.JSON_START_YEAR,
GrowDiff.DEFAULT_NUM_YEARS)
nyrs = Policy.number_of_years(last_budget_year)
self.initialize(GrowDiff.JSON_START_YEAR, nyrs)

@staticmethod
def read_json_update(obj, topkey):
Expand Down Expand Up @@ -81,8 +81,3 @@ def apply_to(self, growfactors):
cyr = i + self.start_year
diff_array = getattr(self, _gfvn)
growfactors.update(gfvn, cyr, diff_array[i])

def set_rates(self):
"""
Unimplemented base class method that is not used here.
"""
13 changes: 7 additions & 6 deletions taxcalc/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,26 +98,27 @@ def __init__(self, start_year=None, num_years=None, last_known_year=None,
self.DEFAULTS_FILE_PATH,
self.DEFAULTS_FILE_NAME
)

last_budget_year = start_year + num_years - 1
if last_known_year is None:
self._last_known_year = start_year
else:
assert last_known_year >= start_year
assert last_known_year <= self.LAST_BUDGET_YEAR
assert last_known_year <= last_budget_year
self._last_known_year = last_known_year

self._removed_params = removed or self.REMOVED_PARAMS
self._redefined_params = redefined or self.REDEFINED_PARAMS

self._wage_indexed = wage_indexed or self.WAGE_INDEXED_PARAMS

if (
(start_year or self.JSON_START_YEAR) and
"initial_state" not in kwargs
):
kwargs["initial_state"] = {
"year": start_year or self.JSON_START_YEAR
}
# update defaults to correspond to user-defined parameter years
self.defaults = super().get_defaults()
label = self.defaults["schema"]["labels"]["year"]
label["validators"]["range"]["max"] = last_budget_year
super().__init__(**kwargs)

def adjust(
Expand Down Expand Up @@ -774,7 +775,7 @@ def __getattr__(self, attr):
attr[1:], year=list(range(self.start_year, self.end_year + 1))
)
else:
raise AttributeError(f"{attr} not definied.")
raise AttributeError(f"{attr} is not defined.")


TaxcalcReform = Union[str, Mapping[int, Any]]
Expand Down
28 changes: 22 additions & 6 deletions taxcalc/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ class Policy(Parameters):
gfactors: GrowFactors class instance
containing price inflation rates and wage growth rates
last_budget_year: integer
user-defined last parameter extrapolation year
Raises
------
ValueError:
Expand All @@ -39,9 +42,16 @@ class instance: Policy
JSON_START_YEAR = 2013 # remains the same unless earlier data added
LAST_KNOWN_YEAR = 2025 # last year for which indexed param vals are known
# should increase LAST_KNOWN_YEAR by one every calendar year
LAST_BUDGET_YEAR = 2034 # last extrapolation year
LAST_BUDGET_YEAR = 2034 # default value of last extrapolation year
# should increase LAST_BUDGET_YEAR by one every calendar year
DEFAULT_NUM_YEARS = LAST_BUDGET_YEAR - JSON_START_YEAR + 1

@staticmethod
def number_of_years(last_budget_year=LAST_BUDGET_YEAR):
"""
Static method returns number of policy parameters years given
user-defined last_budget_year.
"""
return last_budget_year - Policy.JSON_START_YEAR + 1

# NOTE: the following three data structures use internal parameter names:
# (1) specify which Policy parameters have been removed or renamed
Expand Down Expand Up @@ -80,7 +90,10 @@ class instance: Policy
# (3) specify which Policy parameters are wage (rather than price) indexed
WAGE_INDEXED_PARAMS = ['SS_Earnings_c', 'SS_Earnings_thd']

def __init__(self, gfactors=None, **kwargs):
def __init__(self,
gfactors=None,
last_budget_year=LAST_BUDGET_YEAR,
**kwargs):
# put JSON contents of DEFAULTS_FILE_NAME into self._vals dictionary
super().__init__()
# handle gfactors argument
Expand All @@ -92,7 +105,7 @@ def __init__(self, gfactors=None, **kwargs):
raise ValueError('gfactors is not None or a GrowFactors instance')
# read default parameters and initialize
syr = Policy.JSON_START_YEAR
nyrs = Policy.DEFAULT_NUM_YEARS
nyrs = Policy.number_of_years(last_budget_year)
self._inflation_rates = None
self._wage_growth_rates = None
self.initialize(syr, nyrs, Policy.LAST_KNOWN_YEAR,
Expand All @@ -101,7 +114,10 @@ def __init__(self, gfactors=None, **kwargs):
Policy.WAGE_INDEXED_PARAMS, **kwargs)

@staticmethod
def tmd_constructor(growfactors: Path | GrowFactors): # pragma: no cover
def tmd_constructor(
growfactors: Path | GrowFactors,
last_budget_year=LAST_BUDGET_YEAR,
): # pragma: no cover
"""
Static method returns a Policy object instantiated with TMD
input data. This convenience method works in a analogous way
Expand All @@ -112,7 +128,7 @@ def tmd_constructor(growfactors: Path | GrowFactors): # pragma: no cover
growfactors = GrowFactors(growfactors_filename=str(growfactors))
else:
assert isinstance(growfactors, GrowFactors)
return Policy(gfactors=growfactors)
return Policy(gfactors=growfactors, last_budget_year=last_budget_year)

@staticmethod
def read_json_reform(obj):
Expand Down
Loading

0 comments on commit 870db89

Please sign in to comment.