-
Notifications
You must be signed in to change notification settings - Fork 32
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
Resolve more backwards compatibility issues related to old taxcalc tables #814
Conversation
webapp/apps/dynamic/models.py
Outdated
return self.tax_result | ||
else: | ||
return rename_keys(self.tax_result, PRE_TC_0130_RES_MAP) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codekansas I would prefer to not copy this method from the taxbrain models code. Do you have any ideas for a cleaner solution?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'll probably want to put this in a utils.py
file in the parent directory. Hmm... If you do this, you'll probably also want to include
from __future__ import absolute_import
in the top of the file, so that importing is consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codekansas thanks for the advice. That makes sense.
Another solution would be to create an abstract model class with this method. Then, the TaxSaveInputs
and DynamicSaveInputs
classes could inherit this class. It is likely that we will have to add a get_fields
method in a separate PR that resolves #811. This would be like the base class approach described here. An example that is similar to our situation is described here.
#812 was caused because I added a decorator for the This PR uses a method to do the table formatting instead of a decorator. I'd be interested in hearing feedback on this approach and ideas for other approaches. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See noted changes
webapp/apps/dynamic/models.py
Outdated
""" | ||
outputurl = OutputUrl.objects.get(unique_inputs__pk=self.pk) | ||
taxcalc_vers = outputurl.taxcalc_vers | ||
taxcalc_vers = taxcalc_vers.split('.') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can simplify to
taxcalc_vers = outputurl.taxcalc_vers.split('.')
But probably the best solution would be to use some versioning comparison standard library, i.e. distutils.version.StrictVersion
or distutils.version.LooseVersion
so that you don't have to mess around with this version comparison stuff.
webapp/apps/dynamic/models.py
Outdated
return self.tax_result | ||
else: | ||
return rename_keys(self.tax_result, PRE_TC_0130_RES_MAP) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'll probably want to put this in a utils.py
file in the parent directory. Hmm... If you do this, you'll probably also want to include
from __future__ import absolute_import
in the top of the file, so that importing is consistent.
|
||
@property | ||
def tax_result(self): | ||
def get_tax_result(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a good idea - I think the best "logic" for deciding if something should be a property is if:
- It is computationally light, or
- It is cached (i.e. the result is only computed once)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, that makes sense. Thanks for the info. I also couldn't get the property approach to work without deleting the column in the database.
webapp/apps/taxbrain/models.py
Outdated
""" | ||
If taxcalc version is greater than or equal to 0.13.0, return table | ||
If taxcalc version is less than 0.13.0, then rename keys to new names | ||
and then return table | ||
""" | ||
outputurl = OutputUrl.objects.get(unique_inputs__pk=self.pk) | ||
taxcalc_vers = outputurl.taxcalc_vers | ||
taxcalc_vers = tuple(map(int, taxcalc_vers.split('.'))) | ||
taxcalc_vers = taxcalc_vers.split('.') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See earlier comment about using distutils
for version parsing instead
@@ -1014,7 +1014,7 @@ def csv_output(request, pk): | |||
filename = "taxbrain_outputs_" + suffix + ".csv" | |||
response['Content-Disposition'] = 'attachment; filename="' + filename + '"' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is probably better to use the following:
filename = 'taxbrain_outputs_{}.csv'.format(suffix)
response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
Also: For debugging purposes, it is a good idea to log things (the response filename, for example).
webapp/apps/dynamic/models.py
Outdated
taxcalc_vers = outputurl.taxcalc_vers | ||
# only the older (pre 0.13.0) taxcalc versions are null | ||
if taxcalc_vers: | ||
taxcalc_vers = LooseVersion(taxcalc_vers) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this should break something because LooseVersion isn't imported... Maybe I'm missing something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, thanks for catching that. I added the import statement and a test for testing this method on the dynamic behavioral side.
webapp/apps/dynamic/models.py
Outdated
|
||
# older PB versions stored commit reference too | ||
# e.g. taxcalc_vers = "0.9.0.d79abf" | ||
if taxcalc_vers >= LooseVersion("0.13.0"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could put this in a constant somewhere, like "taxcalc_min_compat_version" or something... Might be a bit clearer where this number comes from, so that people looking at it in the future are less confused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, thanks.
webapp/apps/taxbrain/models.py
Outdated
self._tax_result = result | ||
# older PB versions stored commit reference too | ||
# e.g. taxcalc_vers = "0.9.0.d79abf" | ||
if taxcalc_vers >= LooseVersion("0.13.0"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment above... Might also be a good idea to make a utils.py
file for this commit anyway?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I moved this method to the bottom of taxbrain/helpers.py
. The utility and helper functions need to be refactored and re-organzied. See issue #816
assert (res["table_label_0"]["bin_0"] == [0, 1, 2] and | ||
res["table_label_0"]["bin_1"] == [2, 1, 0] and | ||
res["table_label_1"]["bin_0"] == [0, 1, 2] and | ||
res["table_label_1"]["bin_1"] == [2, 1, 0]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this could be changed into four assert statements so it's clearer where something breaks
if error_msgs: | ||
error_msg = error_msgs[0] | ||
else: | ||
error_msg = "Error: stack trace for this error is unavailable" | ||
val_err_idx = error_msg.rfind("Error") | ||
error = ErrorMessageTaxCalculator() | ||
error_contents = error_msg[val_err_idx:].replace(" "," ") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This chunk of code seems pretty suspect... Ideally I guess there would be some easily-viewable logs, and you wouldn't need to store error messages in a database. Could to comment on the logic behind this? I.e. if the error messages aren't designed to be read by users easily, what's the purpose of storing them in the database / showing them to the user instead of logging them on the server side and presenting a more generic error message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This error message is supposed to be a stack trace that is returned by the policy model (e.g. Tax-Calculator). When you hit previous runs that did not complete, you see the saved error message:
The stack trace is logged on the server side, too.
So, saving the error message in the database is more for the user than for us to introspect. The logs are a better source of info for that.
@codekansas do you have any more suggestions before #814 is merged? |
LGTM |
Resolves #813
[EDIT] Also resolves #812