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

Refactor warning/error parsing #800

Merged
merged 7 commits into from Jan 18, 2018
Merged

Conversation

hdoupe
Copy link
Collaborator

@hdoupe hdoupe commented Jan 11, 2018

This PR refactors the warning/error parsing logic. This reduces duplicated code and puts the warning/error parsing logic under test.

cc @codekansas

Copy link
Contributor

@codekansas codekansas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's very late here so don't take my comments seriously. I just added some pointers here. I should go to bed.

msg_parse = msg_spl[2:]
if year not in parsed[action]:
parsed[action][year] = {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use a defaultdict here instead, i.e.

from collections import defaultdict  # at the top
...
parsed = {'errors': defaultdict(dict), 'warnings': defaultdict(dict)}

Then you can get rid of the year not in check. This is a common build pattern which is why defaultdict was added.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh nice. defaultdict is pretty nifty. I wish I'd known about defaultdict earlier.

@@ -151,6 +151,36 @@ def normalize(x):
return ans


def append_ew_file_input(error_list, msg, *args):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems redundant, since you only use this function once... Probably a cleaner way to do this would be to make the third argument of append_errors_warnings be a method with two arguments, msg and param

# line 619
append_errors_warnings(
    errors_warnings,
    errors,
    lambda msg, _: errors.append(msg))

# line 500
append_errors_warnings(
    errors_warnings,
    personal_inputs,
    lambda msg, param: personal_inputs.add_error(param, msg))

Then the append_errors_warnings function would be

def append_errors_warnings(errors_warnings, append_obj, append_func):
    ...
    append_func(msg, param)

Admittedly lambdas are frowned upon by some people but I think it makes for less redundant code here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have any aversion to lambdas. I think this looks a little cleaner.

Out of curiosity, why do some people frown upon lambda functions?

@@ -3,7 +3,10 @@
import taxcalc
import numpy as np

from ..taxbrain.views import read_json_reform, parse_errors_warnings
from ..taxbrain.views import (read_json_reform, parse_errors_warnings,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One handy software engineering tool you might be interested in is "blame". Basically, it's a tool that shows the last person to make changes to each line of code. GitHub has a more thorough explanation here. This isn't a review comment per se, but one thing to keep in mind when using that tool is writing code in a way that "preserves blame", in other words, so that you don't make changes to lines that you don't edit. In this case, the best way to "preserve blame" would be to write each import on a new line, so that if you add your own import, it doesn't update the blame on someone else's import, so you know the last person who thought that import was important to change. i.e.

from ..taxbrain.views import (
   read_json_reform,
   parse_errors_warnings,
   ...
)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hadn't thought about preserving "blame" before. That makes a lot of sense. Thanks for the pointer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check out the blame tool, it is useful for figuring out who wrote something if you're trying to figure out why it was done that way (i.e. poorly documented code)

'2025': 'WARNING: _STD_3 value 168.81 < min value 11154.96 for 2025',
'2026': 'WARNING: _STD_3 value 172.83 < min value 11422.83 for 2026',
'2027': 'WARNING: _STD_3 value 176.98 < min value 11699.38 for 2027'
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One software engineering practice you might want to consider is separating "code" from "data". In this case the "data" is these warnings, which could be saved as like a separate JSON file somewhere and loaded into Python (using the default import json library). The main goal is to abstract away this kind stuff from the core code logic, which makes your code much more readable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I see. I'll open a follow up PR to clean up test_reform.py. There are plenty of data there that need to be moved into JSON files.

@hdoupe
Copy link
Collaborator Author

hdoupe commented Jan 11, 2018

@codekansas Thanks for the review. Let me know what you think of the changes.

@codekansas
Copy link
Contributor

@hdoupe LGTM

@hdoupe
Copy link
Collaborator Author

hdoupe commented Jan 18, 2018

Thanks for the review @codekansas

@hdoupe hdoupe merged commit ecb46da into ospc-org:master Jan 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants