From 597042bec6648da227f51c6b4a2abb1c97caceef Mon Sep 17 00:00:00 2001 From: sgerson Date: Wed, 14 Aug 2024 10:11:51 -0400 Subject: [PATCH 1/3] Removed old input_mapper file --- input_mapper.py | 434 ------------------------------------------------ 1 file changed, 434 deletions(-) delete mode 100644 input_mapper.py diff --git a/input_mapper.py b/input_mapper.py deleted file mode 100644 index 5bc0abf..0000000 --- a/input_mapper.py +++ /dev/null @@ -1,434 +0,0 @@ -from policyengine_us import Simulation -from policyengine_us import parameters -from policyengine_us.model_api import * - -import pandas as pd - -import argparse - - -import os - -from TaxsimInputReader import InputReader - -import importlib.metadata - -# Example simulation imported from policyengine.org -# Single 40 year old parent with $100,000 income, 2 kids (10 years old), living in CA -situation1 = { - "people": { - "you": { - "age": { - "2024": 40 - }, - "employment_income": { - "2024": 100000 - } - }, - "your first dependent": { - "age": { - "2024": 10 - }, - "employment_income": { - "2024": 0 - } - }, - "your second dependent": { - "age": { - "2024": 10 - }, - "employment_income": { - "2024": 0 - } - } - }, - "families": { - "your family": { - "members": [ - "you", - "your first dependent", - "your second dependent" - ] - } - }, - "marital_units": { - "your marital unit": { - "members": [ - "you" - ] - }, - "your first dependent's marital unit": { - "members": [ - "your first dependent" - ], - "marital_unit_id": { - "2024": 1 - } - }, - "your second dependent's marital unit": { - "members": [ - "your second dependent" - ], - "marital_unit_id": { - "2024": 2 - } - } - }, - "tax_units": { - "your tax unit": { - "members": [ - "you", - "your first dependent", - "your second dependent" - ] - } - }, - "spm_units": { - "your household": { - "members": [ - "you", - "your first dependent", - "your second dependent" - ] - } - }, - "households": { - "your household": { - "members": [ - "you", - "your first dependent", - "your second dependent" - ], - "state_name": { - "2024": "CA" - } - } - } -} - -situation2 = { - "people": { - "you": { - "age": { - "2024": 40 - }, - "employment_income": { - "2024": 100000 - } - }, - "your partner": { - "age": { - "2024": 40 - }, - "employment_income": { - "2024": 50000 - } - } - }, - "families": { - "your family": { - "members": [ - "you", - "your partner" - ] - } - }, - "marital_units": { - "your marital unit": { - "members": [ - "you", - "your partner" - ] - } - }, - "tax_units": { - "your tax unit": { - "members": [ - "you", - "your partner" - ] - } - }, - "spm_units": { - "your household": { - "members": [ - "you", - "your partner" - ] - } - }, - "households": { - "your household": { - "members": [ - "you", - "your partner" - ], - "state_name": { - "2024": "AL" - } - } - } -} - -def read_input_file(input_file): - reader = InputReader(input_file) - return (reader.situations) - - - -# input a list of situations and convert each situation into a simulation object -def make_simulation(list_of_households): - list_of_simulations = [] - for situation in list_of_households: - list_of_simulations.append(Simulation(situation = situation,)) - return(list_of_simulations) - - -# Return true if the string is a date -def is_date(string): - try: - pd.to_datetime(string, format='%Y') - return True - except Exception: - return False - -# Return true if the string can create a StateCode instance -def is_state_code(string): - try: - StateCode[string] - return True - except Exception: - return False - -# Get the user's state -def get_state(situation): - year_and_state = list(situation["households"]["your household"]["state_name"].items()) - for item in year_and_state: - for string in item: - if is_state_code(string): - return(string) - -# Get the tax filing year -def get_year(situation): - year_and_state = list(situation["households"]["your household"]["state_name"].items()) - for item in year_and_state: - for string in item: - if is_date(string): - return(string) - -# Returns the itemized_deduction function for the user's state -def state_itemized_deductions(situation): - state = get_state(situation).lower() - return(state + "_itemized_deductions") - -# Returns the standard_deduction function for the user's state -def state_standard_deduction(situation): - state = get_state(situation).lower() - return(state + "_standard_deduction") - -# Returns the function that computes Child and Dependent Care Credit for the user's state -def state_child_care_credit(situation): - state = get_state(situation).lower() - return(state + "_cdcc") - -# Returns the function that computes the user's AGI based on filing state -def state_adjusted_gross_income(situation): - state = get_state(situation).lower() - return(state + "_agi") - -# Returns the function that computes the user's state taxable income -def state_taxable_income(situation): - state = get_state(situation).lower() - return(state + "_taxable_income") - -# Returns the function that computes state income tax -def state_income_tax(situation): - state = get_state(situation).lower() - return(state + "_income_tax") - -# Return the function that computes total state exemptions -def state_exemptions(situation): - state = get_state(situation).lower() - #try to calculate state_exemption, if error, return 0 --> NEED TO ADD Feature - return(state + "_exemptions") - -def state_agi(situation): - state = get_state(situation).lower() - return(state + "_agi") - -def placeholder(): - return("placeholder") - -# List of variables that aren't mapped in Policy Engine -placeholder_variables = ["fica", "frate", "srate", "ficar", "tfica","exemption_phaseout","deduction_phaseout", - "income_tax19","exemption_surtax","general_tax_credit","FICA","state_rent_expense", - "state_property_tax_credit","state_eic","state_total_credits","state_bracket_rate", "state_exemptions", "state_cdcc"] - - -# list of variables that match Taxsim output variables -variables = ["get_year","get_state","income_tax","state_income_tax","fica", "frate", "srate", "ficar","tfica", - "adjusted_gross_income","tax_unit_taxable_unemployment_compensation","tax_unit_taxable_social_security", - "basic_standard_deduction","exemptions","exemption_phaseout","deduction_phaseout","taxable_income_deductions", - "taxable_income","income_tax19","exemption_surtax","general_tax_credit","ctc","refundable_ctc","cdcc", - "eitc", "amt_income","alternative_minimum_tax","income_tax_before_refundable_credits","FICA","household_net_income", - "state_rent_expense","state_agi","state_exemptions","state_standard_deduction","state_itemized_deductions", - "state_taxable_income","state_property_tax_credit","state_child_care_credit","state_eic","state_total_credits", - "state_bracket_rate","self_employment_income","net_investment_income_tax","employee_medicare_tax","rrc_cares"] - - -# list of dictiionaries where each Policy Engine variable is mapped to the Taxsim name. -# Booleans indicate whether the variable is a placeholder, a local variable, or a local variable that doesn't return a function (only get_year and state) -# list of variables mapped to taxsim "2" input (full variables) -full_variables = [ - {'variable': 'get_year', 'taxsim_name': 'year', 'is_placeholder': False, 'is_local': True, 'is_local_getter': True}, - {'variable': 'get_state', 'taxsim_name': 'state', 'is_placeholder': False, 'is_local': True, 'is_local_getter': True}, - {'variable': 'income_tax', 'taxsim_name': 'fiitax', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'state_income_tax', 'taxsim_name': 'siitax', 'is_placeholder': False, 'is_local': True, 'is_local_getter': False}, - {'variable': 'fica', 'taxsim_name': 'fica', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'frate', 'taxsim_name': 'frate', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'srate', 'taxsim_name': 'srate', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'ficar', 'taxsim_name': 'ficar', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'tfica', 'taxsim_name': 'tfica', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'adjusted_gross_income', 'taxsim_name': 'v10', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'tax_unit_taxable_unemployment_compensation', 'taxsim_name': 'v11', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'tax_unit_taxable_social_security', 'taxsim_name': 'v12', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'basic_standard_deduction', 'taxsim_name': 'v13', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'exemptions', 'taxsim_name': 'v14', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'exemption_phaseout', 'taxsim_name': 'v15', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'deduction_phaseout', 'taxsim_name': 'v16', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'taxable_income_deductions', 'taxsim_name': 'v17', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'taxable_income', 'taxsim_name': 'v18', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'income_tax19', 'taxsim_name': 'v19', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'exemption_surtax', 'taxsim_name': 'v20', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'general_tax_credit', 'taxsim_name': 'v21', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'ctc', 'taxsim_name': 'v22', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'refundable_ctc', 'taxsim_name': 'v23', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'cdcc', 'taxsim_name': 'v24', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'eitc', 'taxsim_name': 'v25', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'amt_income', 'taxsim_name': 'v26', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'alternative_minimum_tax', 'taxsim_name': 'v27', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'income_tax_before_refundable_credits', 'taxsim_name': 'v28', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'FICA', 'taxsim_name': 'v29', 'is_placeholder': True, 'is_local': True, 'is_local_getter': False}, - {'variable': 'household_net_income', 'taxsim_name': 'v30', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'state_rent_expense', 'taxsim_name': 'v31', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'state_agi', 'taxsim_name': 'v32', 'is_placeholder': False, 'is_local': True, 'is_local_getter': False}, - {'variable': 'state_exemptions', 'taxsim_name': 'v33', 'is_placeholder': True, 'is_local': True, 'is_local_getter': False}, - {'variable': 'state_standard_deduction', 'taxsim_name': 'v34', 'is_placeholder': False, 'is_local': True, 'is_local_getter': False}, - {'variable': 'state_itemized_deductions', 'taxsim_name': 'v35', 'is_placeholder': False, 'is_local': True, 'is_local_getter': False}, - {'variable': 'state_taxable_income', 'taxsim_name': 'v36', 'is_placeholder': False, 'is_local': True, 'is_local_getter': False}, - {'variable': 'state_property_tax_credit', 'taxsim_name': 'v37', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'state_child_care_credit', 'taxsim_name': 'v38', 'is_placeholder': True, 'is_local': True, 'is_local_getter': False}, - {'variable': 'state_eic', 'taxsim_name': 'v39', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'state_total_credits', 'taxsim_name': 'v40', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'state_bracket_rate', 'taxsim_name': 'v41', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'self_employment_income', 'taxsim_name': 'v42', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'net_investment_income_tax', 'taxsim_name': 'v43', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'employee_medicare_tax', 'taxsim_name': 'v44', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'rrc_cares', 'taxsim_name': 'v45', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False} -] - -# variables mapped to taxsim "0" input (standard) -standard_variables = [ - {'variable': 'get_year', 'taxsim_name': 'year', 'is_placeholder': False, 'is_local': True, 'is_local_getter': True}, - {'variable': 'get_state', 'taxsim_name': 'state', 'is_placeholder': False, 'is_local': True, 'is_local_getter': True}, - {'variable': 'income_tax', 'taxsim_name': 'fiitax', 'is_placeholder': False, 'is_local': False, 'is_local_getter': False}, - {'variable': 'state_income_tax', 'taxsim_name': 'siitax', 'is_placeholder': False, 'is_local': True, 'is_local_getter': False}, - {'variable': 'fica', 'taxsim_name': 'fica', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'frate', 'taxsim_name': 'frate', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'srate', 'taxsim_name': 'srate', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'ficar', 'taxsim_name': 'ficar', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, - {'variable': 'tfica', 'taxsim_name': 'tfica', 'is_placeholder': True, 'is_local': False, 'is_local_getter': False}, -] - -# Calculate the variables based on the user's information and save them to a dataframe - -# input a list of simulations, a list of households, and a variable_dict. -# variable dict will be switched to either 0, 2, 5 to correspond with taxsim inputs --> to be implemented - -# seperate iteration into one single household output -def single_household(household): - row = [] - - simulation = Simulation(situation = household,) - - variable_dict = full_variables - - for variable_info in variable_dict: - variable = variable_info['variable'] - taxsim_name = variable_info['taxsim_name'] - is_placeholder = variable_info['is_placeholder'] - is_local = variable_info['is_local'] - is_local_getter = variable_info["is_local_getter"] - - # if the variable is a placeholder, append "placeholder" - if is_placeholder: - row.append(placeholder()) - else: - # if the variable is local, return the value of the local function (returns a to policyenginge function name) - if is_local: - function = globals()[variable] - result = function(household) - # if the variable is a local getter, just return the value of the local function - if is_local_getter: - calculation = result - # otherwise, run policy engine calculation using the function name - else: - calculation = simulation.calculate(result) - # if the variable is not local, just run policy engine calculation - else: - calculation = simulation.calculate(variable) - - row.append(calculation) - - return row - -# second function that calls the single household for each in the list -def multiple_households(list_of_households): - output = [] - - list_of_simulations = make_simulation(list_of_households) - - for simulation, household in zip(list_of_simulations, list_of_households): - row = single_household(household) - output.append(row) - - # Create DataFrame from the output with taxsim_names as columns - return output - -def make_dataframe(input_file, variable_dict, is_multiple_households: bool): - if not is_multiple_households: - household = input_file[0] - output = [single_household(household)] - df = pd.DataFrame(output, columns=[var['taxsim_name'] for var in variable_dict], index=pd.RangeIndex(start=1, stop=len(output)+1, name='taxsimid')) - return df - else: - output = multiple_households(input_file) - df = pd.DataFrame(output, columns=[var['taxsim_name'] for var in variable_dict], index=pd.RangeIndex(start=1, stop=len(output)+1, name='taxsimid')) - return df - -# return true if the input file contains more than one household -def is_multiple_households(list): - if len(list) > 1: - return(True) - return(False) - -# run main with an input file to execute the methods in the correct order -def main(input_file): - print("running script") - - - list_of_households = read_input_file(input_file) - print(list_of_households) - variable_dict = full_variables # going to use a condition to set the correct variable list depending on the input - - output = make_dataframe(list_of_households, variable_dict, is_multiple_households(list_of_households)) - - output.to_csv('output.csv', index=True) - print("script finished") - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Process input file and generate output.') - parser.add_argument('input_file', type=str, help='Path to the input CSV file') - args = parser.parse_args() - - main(args.input_file) \ No newline at end of file From 65e481b22a5c5163b4d1d80e43df6f6027ee873e Mon Sep 17 00:00:00 2001 From: sgerson Date: Wed, 14 Aug 2024 10:17:04 -0400 Subject: [PATCH 2/3] Added text description output functionality --- README.md | 10 ++- TaxsimInputReader.py | 13 ++- TextDescriptionWriter.py | 181 +++++++++++++++++++++++++++++++++++++++ taxsim_emulator.py | 67 +++++++++------ 4 files changed, 237 insertions(+), 34 deletions(-) create mode 100644 TextDescriptionWriter.py diff --git a/README.md b/README.md index bd32bdb..9ab7f80 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ python3 taxsim_emulator.py taxsim_input.raw 8. age1 (age of first dependent) 9. age2 (age of second dependent) 10. age3 (age of third dependent) +11. idtl (determines the level of output. 0 = standard, 2 = full, 5 = full with text descriptions) ### Income: ### 1. pwages (wage of primary taxpayer) @@ -38,6 +39,9 @@ python3 taxsim_emulator.py taxsim_input.raw 6. intrec (taxable interest received) 7. stcg (short-term capital gains) 8. ltcg (long-term capital gains) -9. pui (primary taxpayer unemployment compensation received) -10. sui (spouse unemployment compensation received) -11. proptax (real estate taxes paid) +9. otherprop (other property incomes) +10. nonprop (other non-property incomes) +11. pensions (taxable pensions and IRA distributions) +12. pui (primary taxpayer unemployment compensation received) +13. sui (spouse unemployment compensation received) +14. proptax (real estate taxes paid) diff --git a/TaxsimInputReader.py b/TaxsimInputReader.py index 677c5e1..fab424f 100644 --- a/TaxsimInputReader.py +++ b/TaxsimInputReader.py @@ -86,13 +86,20 @@ def add_variables(self, situation, row, year): "intrec": "taxable_interest_income", "stcg": "short_term_capital_gains", "ltcg": "long_term_capital_gains", + "nonprop": "alimony_income", + "otherprop": "partnership_s_corp_income", + "pensions": "pension_income", "pui": "unemployment_compensation", "sui": "unemployment_compensation", - "proptax": "real_estate_taxes" + "proptax": "real_estate_taxes", + "scorp": "s_corp_self_employment_income", + "pbusinc": "qualified_business_income", + "sbusinc": "qualified_business_income" } - primary_variables = ["pwages","psemp","dividends","intrec","stcg","ltcg","pui","proptax"] - spouse_variables = ["swages","ssemp","sui"] + primary_variables = ["pwages","psemp","dividends","intrec","stcg","ltcg","pui","proptax","pbusinc","nonprop","otherprop", + "scorp","pensions"] + spouse_variables = ["swages","ssemp","sui","sbusinc"] primary_taxpayer = "you" spouse_taxpayer = "your partner" diff --git a/TextDescriptionWriter.py b/TextDescriptionWriter.py new file mode 100644 index 0000000..b1048b3 --- /dev/null +++ b/TextDescriptionWriter.py @@ -0,0 +1,181 @@ +import pandas as pd + +from TaxsimInputReader import InputReader + + +class TextDescriptionWriter: + def __init__(self, input_data, InputReader): + self.input_data = input_data + self.reader = InputReader + self.output = self.format_data() + self.write_to_file() + + # return the full name of the state corresponding to the state number + def get_state_name(self, state_number): + state_mapping = { + 1: "Alabama", 2: "Alaska", 3: "Arizona", 4: "Arkansas", 5: "California", 6: "Colorado", 7: "Connecticut", + 8: "Delaware", 9: "District of Columbia", 10: "Florida", 11: "Georgia", 12: "Hawaii", 13: "Idaho", + 14: "Illinois", 15: "Indiana", 16: "Iowa", 17: "Kansas", 18: "Kentucky", 19: "Louisiana", 20: "Maine", + 21: "Maryland", 22: "Massachusetts", 23: "Michigan", 24: "Minnesota", 25: "Mississippi", 26: "Missouri", + 27: "Montana", 28: "Nebraska", 29: "Nevada", 30: "New Hampshire", 31: "New Jersey", 32: "New Mexico", + 33: "New York", 34: "North Carolina", 35: "North Dakota", 36: "Ohio", 37: "Oklahoma", 38: "Oregon", + 39: "Pennsylvania", 40: "Rhode Island", 41: "South Carolina", 42: "South Dakota", 43: "Tennessee", + 44: "Texas", 45: "Utah", 46: "Vermont", 47: "Virginia", 48: "Washington", 49: "West Virginia", + 50: "Wisconsin", 51: "Wyoming" + } + return state_mapping.get(state_number) + + # return filing status. Taxsim leaves 6 and 5 as blank () + def get_filing_status(self, mstat): + filing_status_map = { + 1: "Single", + 2: "Joint", + 6: "", + 8: "Single", + 5: "" + } + return filing_status_map.get(mstat, f"Unknown filing status: {mstat}") + + # convert the input data and the output data to dictionaries and get the values corresponding to the left column. Returns 0 if none + def format_data(self): + output_df = self.input_data.iloc[0].to_dict() + input_df = self.reader.df.iloc[0].to_dict() + + state_number = input_df['state'] + + state_name = self.get_state_name(state_number) + + mstat = input_df['mstat'] + marital_status = self.get_filing_status(mstat) + + + placeholder = "placeholder" + + + formatted_output = f""" +Input Data: + 1. Record ID: {input_df.get('taxsimid', 0):>5.0f}. + 2. Tax Year: {input_df.get('year', 0):>4.2f} + 3. State Code: {state_number:>2.0f}.{state_name:<20} + 4. Marital Status: {input_df.get('mstat', 0):>7.2f} {marital_status:<10} + 5-6. Age (Txpyr/Spouse): {input_df.get('page', 0):>7.2f}{input_df.get('sage', 0):>11.2f} + 7. Dependent Exemptions: {placeholder} + 8-10. #deps for CCC/CTC/EIC: {input_df.get('depx', 0):>7.2f} +11-12. Wages (Txpyr/Spouse): {input_df.get('pwages', 0):>10.2f}{input_df.get('swages', 0):>11.2f} +11a12a Self-employment income: {input_df.get('psemp', 0):>10.2f}{input_df.get('ssemp', 0):>11.2f} + 13. Dividend Income: {input_df.get('dividends', 0):>7.2f} + 14. Interest Received: {input_df.get('intrec', 0):>7.2f} + 15. Short Term Gains: {input_df.get('stcg', 0):>7.2f} + 16. Long Term Gains: {input_df.get('ltcg', 0):>7.2f} + 17. Other Property: {input_df.get('otherprop', 0):>7.2f} + 18. Other Non-Property: {input_df.get('nonprop', 0):>7.2f} + 19. Taxable Pensions: {input_df.get('pensions', 0):>7.2f} + 20. Gross Social Security: {input_df.get('gssi', 0):>7.2f} +21-22. Tot/Txpy/Spouse UI: {placeholder} + 23. Non-taxable Transfers: {input_df.get('transfers', 0):>7.2f} + 24. Rent Paid: {input_df.get('rentpaid', 0):>7.2f} + 25. Property Taxes Paid: {input_df.get('proptax', 0):>7.2f} + 26. Other Itemized Deds: {input_df.get('otheritem', 0):>7.2f} + 27. Child Care Expenses: {input_df.get('childcare', 0):>7.2f} + 28. Mortgage Interest: {input_df.get('mortgage', 0):>7.2f} + 29. S-Corp profits: {input_df.get('scorp', 0):>7.2f} +29 31. Txpy/Spouse QBI w/o PO: {input_df.get('pbusinc', 0):>7.2f}{input_df.get('sbusinc', 0):>11.2f} +30 32. Txpy/Spouse SSTB w PO: {input_df.get('pprofinc', 0):>7.2f}{input_df.get('sprofinc', 0):>11.2f} + +Basic Output: + 1. Record ID: {input_df['taxsimid']:>3.0f}. + 2. Year: {output_df['year']:>8} + 3. State (SOI code): {state_number:>10.0f}{state_name:>15} + 4. Federal IIT Liability: {output_df['fiitax']:>8} + 5. State IIT Liability: {output_df['siitax']:>8} + 6. SS Payroll Tax Liability: {output_df['fica']:>8} +Marginal Rates wrt Weighted Average Earnings + 7. Federal Marginal Rate: {output_df['frate']:>8} + 8. State Marginal Rate: {output_df['srate']:>8} + 9. Weighed Payroll Tax Rate: {output_df['tfica']:>8} + +Federal Tax Calculation: Base + 10. Federal AGI {output_df['v10']:>9} + 11. UI in AGI 1979+ {output_df['v11']:>9} + 12. Social Security in AGI 84 {output_df['v12']:>9} + 13. Zero Bracket Amount {output_df['v13']:>9} + 14. Personal Exemptions {output_df['v14']:>9} + 15. Exemption Phaseout 1991+ {output_df['v15']:>9} + 16. Deduction Phaseout 1991+ {output_df['v16']:>9} + 17. Deductions allowed {output_df['v17']:>9} + QBI deduction {placeholder:>9} + 18. Federal Taxable Income {output_df['v18']:>9} + 19. Federal Regular Tax {output_df['v19']:>9} + 20. Exemption Surtax 1988-96 {output_df['v20']:>9} + 21. General Tax Credit 1975-8 {output_df['v21']:>9} + 22. Child Tax Credit*17/22 98 {output_df['v22']:>9} + 23. Refundable Part {output_df['v23']:>9} + 24. Child Care Credit 1076+ {output_df['v24']:>9} + 25. Earned Income Credit 1975 {output_df['v25']:>9} + 26. Alternative Min Income: {output_df['v26']:>9} + 27. AMT {output_df['v27']:>9} + 28. Income Tax Before Credits {output_df['v28']:>9} + Total Credits {placeholder:>9} + 29. FICA {output_df['v29']:>9} + Taxpayer share of FICA {placeholder:>9} + +State Tax Calculation: + 30. Household Income {output_df['v30']:>9} + 31. Imputed Rent {output_df['v31']:>9} + 32. AGI {output_df['v32']:>9} + 33. Exemptions {output_df['v33']:>9} + 34. Standard Deduction {output_df['v34']:>9} + 35. Itemized Deductions {output_df['v35']:>9} + 36. Taxable Income {output_df['v36']:>9} + Tax before credits {placeholder:>9} + 37. Property Tax Credit {output_df['v37']:>9} + 38. Child Care Credit {output_df['v38']:>9} + 39. EIC {output_df['v39']:>9} + Energy|Fuel Credit {placeholder:>9} + Child Tax Credit {placeholder:>9} + 40. Total Credits {output_df['v40']:>9} + 41. Bracket Rate {output_df['v41']:>9} + State Tax after Credits {placeholder:>9} + + 42. QBI Deduction {placeholder:>9} + +Decomposition of Federal Marginal Rate + (taxpayer earned income) + +Regular Income Tax + Bracket rate from X,Y or Z {placeholder:>9} + Deduction Phaseout: {placeholder:>9} + Exemption Phaseout: {placeholder:>9} + Social Security Phasein: {placeholder:>9} + Child Tax Credit: {placeholder:>9} + Child Care Credit: {placeholder:>9} + Refundable Part of CTC: {placeholder:>9} + Earned Income Credit: {placeholder:>9} + Surtax on 15% bracket: {placeholder:>9} + Exemption Surtax: {placeholder:>9} + Unemployment Insurance: {placeholder:>9} + Max Tax on Earned Income: {placeholder:>9} + Elderly Credit: {placeholder:>9} + Dependent Care Credit: {placeholder:>9} + Percentage Std Deduction: {placeholder:>9} + Medicare tax on Unearned Income:{output_df['v43']:>9} + Cares Recovery Rebates: {output_df['v45']:>9} + +Alternative Minimum Income Tax + AMT Bracket Rate {placeholder:>9} + AMT Phaseout {placeholder:>9} + +Only Regular Tax Relevant + Total Marginal Rate: {placeholder:>9} + FICA w Medicare (t,s): {placeholder:>9}{placeholder:>12} +""" + + return formatted_output + + # create a new file called text_description_output.txt with the f string + def write_to_file(self, file_path = "text_description_output.txt"): + formatted_output = self.format_data() + with open(file_path, 'w') as file: + file.write(formatted_output) + + \ No newline at end of file diff --git a/taxsim_emulator.py b/taxsim_emulator.py index 6e80671..c47d5f6 100644 --- a/taxsim_emulator.py +++ b/taxsim_emulator.py @@ -11,26 +11,31 @@ from TaxsimInputReader import InputReader -import importlib.metadata +from TextDescriptionWriter import TextDescriptionWriter +import importlib.metadata +# instantiate an InputReader class with the input file def read_input_file(input_file): reader = InputReader(input_file) return (reader) +# get the list of situations from the InputReader def get_situations(reader): return(reader.situations) +# get the level of output from the InputReader def get_output_level(reader): return(reader.output_level) +# return the chosen output level's corresponding list of variables def get_variables(output_level): if output_level == "standard": return standard_variables elif output_level == "full": return full_variables elif output_level == "text_descriptions": - raise ValueError("Emulator does not support the text description option yet. Please use standard or full output levels") + return full_variables # input a list of situations and convert each situation into a simulation object def make_simulation(list_of_households): @@ -39,12 +44,10 @@ def make_simulation(list_of_households): list_of_simulations.append(Simulation(situation = situation,)) return(list_of_simulations) +# format as an f string with two decimal places def convert_to_number(arr): - # Access the element (assuming it's a single-element array) value = arr[0] - # Round to two decimal places rounded_value = round(value, 2) - # Format as string with two decimal places and trailing zeros formatted_value = f"{rounded_value:.2f}" return(formatted_value) @@ -129,10 +132,21 @@ def state_exemptions(situation): #try to calculate state_exemption, if error, return 0 --> NEED TO ADD Feature return(state + "_exemptions") +# Returns the function that computes state adjusted gross income def state_agi(situation): state = get_state(situation).lower() return(state + "_agi") +# Returns the function that computes state property tax credit +def state_property_tax_credit(situation): + state = get_state(situation).lower() + return(state + "_property_tax_credit") + +# Returns the function that computes state earned income tax credit +def state_eitc(situation): + state = get_state(situation).lower() + return(state + "_eitc") + def placeholder(situation): return("placeholder") @@ -153,11 +167,7 @@ def placeholder(situation): "state_bracket_rate","self_employment_income","net_investment_income_tax","employee_medicare_tax","rrc_cares"] -# list of dictiionaries where each Policy Engine variable is mapped to the Taxsim name. -# Booleans indicate whether the variable is a placeholder, a local variable, or a local variable that doesn't return a function (only get_year and state) -# list of variables mapped to taxsim "2" input (full variables) - - +# list of dictiionaries where each taxim output variable is mapped to the PolicyEngine calculation full_variables = [ {'taxsim_name': 'year', 'calculation': 'get_year'}, @@ -198,7 +208,7 @@ def placeholder(situation): {'taxsim_name': 'v36', 'calculation': lambda household: globals()['state_taxable_income'](household)}, {'taxsim_name': 'v37', 'calculation': 'placeholder'}, {'taxsim_name': 'v38', 'calculation': 'placeholder'}, - {'taxsim_name': 'v39', 'calculation': 'placeholder'}, + {'taxsim_name': 'v39', 'calculation': lambda household: globals()['state_eitc'](household)}, {'taxsim_name': 'v40', 'calculation': 'placeholder'}, {'taxsim_name': 'v41', 'calculation': 'placeholder'}, {'taxsim_name': 'v42', 'calculation': 'self_employment_income'}, @@ -220,12 +230,6 @@ def placeholder(situation): {'taxsim_name': 'tfica', 'calculation': 'placeholder'} ] -# Calculate the variables based on the user's information and save them to a dataframe - -# input a list of simulations, a list of households, and a variable_dict. -# variable dict will be switched to either 0, 2, 5 to correspond with taxsim inputs --> to be implemented - - # seperate iteration into one single household output def single_household(household, variable_dict): row = [] @@ -264,20 +268,27 @@ def multiple_households(list_of_households, variable_dict): row = single_household(household, variable_dict) output.append(row) - # Create DataFrame from the output with taxsim_names as columns return output -def make_dataframe(input_file, variable_dict, is_multiple_households: bool): +# Creates DataFrame from the output with taxsim_names as columns +def make_dataframe(list_of_households, variable_dict, is_multiple_households: bool): if not is_multiple_households: - household = input_file[0] + household = list_of_households[0] output = [single_household(household, variable_dict)] df = pd.DataFrame(output, columns=[var['taxsim_name'] for var in variable_dict], index=pd.RangeIndex(start=1, stop=len(output)+1, name='taxsimid')) return df else: - output = multiple_households(input_file, variable_dict) + output = multiple_households(list_of_households, variable_dict) df = pd.DataFrame(output, columns=[var['taxsim_name'] for var in variable_dict], index=pd.RangeIndex(start=1, stop=len(output)+1, name='taxsimid')) return df +# Instantiates a new TextDescriptionWriter class using the first household's information if output level 5 is chosen +def make_text_description_file(list_of_households, variable_dict, reader): + household = [list_of_households[0]] + output = make_dataframe(household, variable_dict, is_multiple_households(household)) + return(TextDescriptionWriter(output, reader)) + + # return true if the input file contains more than one household def is_multiple_households(list): if len(list) > 1: @@ -294,13 +305,13 @@ def main(input_file): variable_dict = get_variables(output_level) print("Chosen Output Level: " + output_level) - - - - - output = make_dataframe(list_of_households, variable_dict, is_multiple_households(list_of_households)) - - output.to_csv('output.csv', index=True) + + + if output_level == "text_descriptions": + output = make_text_description_file(list_of_households, variable_dict, reader) + else: + output = make_dataframe(list_of_households, variable_dict, is_multiple_households(list_of_households)) + output.to_csv('output.csv', index=True) print("script finished") From 6d11ce63eab7306274cea30747cd003c415c11ab Mon Sep 17 00:00:00 2001 From: sgerson Date: Wed, 14 Aug 2024 12:22:20 -0400 Subject: [PATCH 3/3] Fixed standard output variables --- taxsim_emulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taxsim_emulator.py b/taxsim_emulator.py index c47d5f6..4587a4d 100644 --- a/taxsim_emulator.py +++ b/taxsim_emulator.py @@ -220,7 +220,7 @@ def placeholder(situation): # variables mapped to taxsim "0" input (standard) standard_variables = [ {'taxsim_name': 'year', 'calculation': 'get_year'}, - {'taxsim_name': 'state', 'calculation': 'get_state'}, + {'taxsim_name': 'state', 'calculation': 'get_state_code'}, {'taxsim_name': 'fiitax', 'calculation': 'income_tax'}, {'taxsim_name': 'siitax', 'calculation': lambda household: globals()['state_income_tax'](household)}, {'taxsim_name': 'fica', 'calculation': 'placeholder'},