Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert DependentCredit_before_CTC from bool to int #782

Merged
merged 8 commits into from
Dec 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions webapp/apps/btax/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
from django.utils.translation import ugettext_lazy as _

from .models import BTaxSaveInputs
from .helpers import (BTaxField, BTaxParam, get_btax_defaults)
from .helpers import (BTaxField, BTaxParam, get_btax_defaults,
convert_val, make_bool)
from ..taxbrain.helpers import (is_number, int_to_nth,
is_string, string_to_float_array,
check_wildcards, expand_list,
propagate_user_list, convert_val,
make_bool)
propagate_user_list)
import taxcalc

from ..taxbrain.forms import (has_field_errors,
Expand Down
14 changes: 14 additions & 0 deletions webapp/apps/btax/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,17 @@ def group_args_to_btax_depr(btax_default_params, asset_yr_str):

)
return depr_argument_groups


def make_bool(x):
b = True if x == 'True' else False
return b


def convert_val(x):
if is_wildcard(x):
return x
try:
return float(x)
except ValueError:
return make_bool(x)
7 changes: 3 additions & 4 deletions webapp/apps/btax/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,10 @@
from .helpers import (get_btax_defaults,
BTAX_BITR, BTAX_DEPREC,
BTAX_OTHER, BTAX_ECON,
group_args_to_btax_depr, hover_args_to_btax_depr)
group_args_to_btax_depr, hover_args_to_btax_depr,
make_bool, convert_val)
from ..taxbrain.helpers import (format_csv,
is_wildcard,
convert_val,
make_bool)
is_wildcard)
from ..taxbrain.views import (benefit_switch_fixup,
denormalize, normalize)
from .compute import DropqComputeBtax, MockComputeBtax, JobFailError
Expand Down
1 change: 0 additions & 1 deletion webapp/apps/taxbrain/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,6 @@ class Meta:
"_CTC_new_refund_limited_all_payroll",
"_PT_wages_active_income",
"_PT_top_stacking",
"_DependentCredit_before_CTC"
]

for param in TAXCALC_DEFAULTS_2016.values():
Expand Down
46 changes: 40 additions & 6 deletions webapp/apps/taxbrain/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
import numbers
import os
import pandas as pd
import numpy as np
import pyparsing as pp
import sys
import time
import six
import re

#Mock some module for imports because we can't fit them on Heroku slugs
from mock import Mock
Expand All @@ -23,7 +25,11 @@
SPECIAL_NON_INFLATABLE_PARAMS = {'_ACTC_ChildNum', '_EITC_MinEligAge',
'_EITC_MaxEligAge'}

BOOL_PARAMS = ['DependentCredit_before_CTC']

# Grammar for Field inputs
TRUE = pp.CaselessKeyword('true')
FALSE = pp.CaselessKeyword('false')
WILDCARD = pp.Word('*')
INT_LIT = pp.Word(pp.nums)
NEG_DASH = pp.Word('-', exact=1)
Expand All @@ -34,8 +40,13 @@

VALUE = WILDCARD | NEG_DASH | FLOAT_LIT_FULL | FLOAT_LIT | INT_LIT
MORE_VALUES = COMMON + VALUE
INPUT = VALUE + pp.ZeroOrMore(MORE_VALUES)

BOOL = WILDCARD | TRUE | FALSE
MORE_BOOLS = COMMON + BOOL
INPUT = BOOL + pp.ZeroOrMore(MORE_BOOLS) | VALUE + pp.ZeroOrMore(MORE_VALUES)

TRUE_REGEX = re.compile('(?i)true')
FALSE_REGEX = re.compile('(?i)false')

def is_wildcard(x):
if isinstance(x, six.string_types):
Expand All @@ -51,9 +62,28 @@ def check_wildcards(x):


def make_bool(x):
b = True if x == 'True' else False
return b

"""
Find exact match for case insensitive true or false
Returns True for True or 1
Returns False for False or 0
If x is wildcard then simply return x
"""
if is_wildcard(x):
return x
elif x in (True, '1', '1.0', 1, 1.0):
return True
elif x in (False, '0', '0.0', 0, 0.0):
return False
elif TRUE_REGEX.match(x, endpos=4):
return True
elif FALSE_REGEX.match(x, endpos=5):
return False
else:
# this should be caught much earlier either in model validation or in
# form validation
raise ValueError(
"Expected case insensitive 'true' or 'false' but got {}".format(x)
)

def convert_val(x):
if is_wildcard(x):
Expand All @@ -68,8 +98,12 @@ def parse_fields(param_dict):
if v == u'' or v is None or v == []:
del param_dict[k]
continue
if type(v) == type(unicode()): #TODO: isinstance(value, unicode)
param_dict[k] = [convert_val(x) for x in v.split(',') if x]
if isinstance(v, six.string_types):
if k in BOOL_PARAMS:
converter = make_bool
else:
converter = convert_val
param_dict[k] = [converter(x) for x in v.split(',') if x]
return param_dict

def int_to_nth(x):
Expand Down
20 changes: 20 additions & 0 deletions webapp/apps/taxbrain/migrations/0060_auto_20171219_2153.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
import webapp.apps.taxbrain.models


class Migration(migrations.Migration):

dependencies = [
('taxbrain', '0059_auto_20171216_2123'),
]

operations = [
migrations.AlterField(
model_name='taxsaveinputs',
name='DependentCredit_before_CTC',
field=webapp.apps.taxbrain.models.CommaSeparatedField(default=None, max_length=200, null=True, blank=True),
),
]
6 changes: 4 additions & 2 deletions webapp/apps/taxbrain/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ def numberfy(x):
attrs = vars(tsi)
return { k:numberfy(v) for k,v in attrs.items() if v}

# digit or true/false (case insensitive)
COMMASEP_REGEX = "(\\d*\\.\\d+|\\d+)|((?i)(true|false))"

class CommaSeparatedField(models.CharField):
default_validators = [validators.RegexValidator(regex='\d*\.\d+|\d+')]
default_validators = [validators.RegexValidator(regex="(\\d*\\.\\d+|\\d+)|((?i)(true|false))")]
description = "A comma separated field that allows multiple floats."

def __init__(self, verbose_name=None, name=None, **kwargs):
Expand Down Expand Up @@ -553,7 +555,7 @@ class TaxSaveInputs(models.Model):
CTC_new_c = CommaSeparatedField(default=None, blank=True, null=True)
CTC_new_c_under5_bonus = CommaSeparatedField(default=None, blank=True, null=True)
CTC_new_for_all = models.CharField(default="False", blank=True, null=True, max_length=50)
DependentCredit_before_CTC = models.CharField(default="False", blank=True, null=True, max_length=50)
DependentCredit_before_CTC = CommaSeparatedField(default=None, blank=True, null=True)
ACTC_rt = CommaSeparatedField(default=None, blank=True, null=True)
ACTC_ChildNum = CommaSeparatedField(default=None, blank=True, null=True)
ACTC_rt_bonus_under5family = CommaSeparatedField(default=None, blank=True, null=True)
Expand Down
40 changes: 39 additions & 1 deletion webapp/apps/taxbrain/tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import json
import numpy as np
import taxcalc
from ..helpers import nested_form_parameters, rename_keys
import pyparsing as pp
from ..helpers import nested_form_parameters, rename_keys, INPUT, make_bool

CURRENT_LAW_POLICY = """
{
Expand Down Expand Up @@ -126,3 +127,40 @@ def test_rename_keys(monkeypatch):
}
act = rename_keys(a, map_dict)
np.testing.assert_equal(act, exp)

@pytest.mark.parametrize(
'item',
['1', '2.0', '8.01', '23',
'-4', '-3.0', '-2.02', '-46',
'*', '1,*', '1,*,1,1,*',
'-2,*', '-7,*,*,2,*',
'True', 'true', 'TRUE', 'tRue',
'False', 'false', 'FALSE','faLSe',
'true,*', '*, true', '*,*,false',
'true,*,false,*,*,true',
'1,*,False', '0.0,True', '1.0,False']
)
def test_parsing_pass(item):
INPUT.parseString(item)

def test_parsing_fail():
with pytest.raises(pp.ParseException):
INPUT.parseString('abc')

@pytest.mark.parametrize(
'item,exp',
[('True', True), ('true', True), ('TRUE', True), (True, True),
('tRue', True), (1.0, True), (1, True), ('1.0', True), ('1', True),
('False', False), ('false', False), ('FALSE', False), (False, False),
('faLSe', False), (0.0, False), (0, False), ('0.0', False), ('0', False)]
)
def test_make_bool(item, exp):
assert make_bool(item) is exp

@pytest.mark.parametrize(
'item',
['abc', 10, '10', '00', 2]
)
def test_make_bool_fail(item):
with pytest.raises((ValueError, TypeError)):
make_bool(item)
20 changes: 20 additions & 0 deletions webapp/apps/taxbrain/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,26 @@ def test_taxbrain_wildcard_in_validation_params_gives_error(self):
self.assertEqual(response.status_code, 200)
assert response.context['has_errors'] is True

def test_taxbrain_bool_separated_values(self):
"""
Test _DependentCredit_before_CTC can be posted as comma separated
string
"""
data = get_post_data(2018, _ID_BenefitSurtax_Switches=False)
data['DependentCredit_before_CTC'] = [u'True,*,FALSE,tRUe,*,0']

result = do_micro_sim(self.client, data)

# Check that data was submitted properly
truth_mods = {
2018: {'_DependentCredit_before_CTC': [True]},
2020: {'_DependentCredit_before_CTC': [False]},
2021: {'_DependentCredit_before_CTC': [True]},
2023: {'_DependentCredit_before_CTC': [False]}
}
check_posted_params(result['tb_dropq_compute'], truth_mods,
str(2018))


def test_taxbrain_rt_capital_gain_goes_to_amt(self):
"""
Expand Down