Repository navigation
Store schedule and pulse history details from output for post processing - #240
Conversation
add more logic more logic store output combine multiple commits into one
gonuke
left a comment
There was a problem hiding this comment.
There is a repeated suggestion here to use a while loop instead of a for loop when looking through the lines. This is a typical design pattern for a parser.
A "design pattern" is typical and usually well-tested algorithm pattern for accomplishing a given task. Design patterns transcend languages and when you use them, others can quickly grasp what the intent of the code is and not worry about understanding the high level algorithm, but quickly focus on the details.
A "parser" is a typical pattern for moving through a stream of tokens (lines in your case) with two primary things that can happen at each line:
- change the "state"
- take action depending on the state
Zero, one, or both of these things can happen at each new token.
The most common action is to process the value of a token into some other data structure.
|
|
||
| def read_out(output_path): | ||
| with open(output_path, "r") as output_file: | ||
| lines = output_file.readlines() |
There was a problem hiding this comment.
Just learned that this might make life easier by stripping all the lines when you read:
| lines = output_file.readlines() | |
| lines = output_file.read().striplines() |
There was a problem hiding this comment.
Hmm...output_file.read() returns a string that has no method called striplines(). I also can't seem to find any documentation on this method?
There was a problem hiding this comment.
My bad... it's splitlines https://www.w3schools.com/python/ref_string_splitlines.asp
| matches = [] | ||
| for key, value in top_dict.items(): | ||
|
|
||
| if key.startswith(search_str): |
There was a problem hiding this comment.
At this point, haven't you parsed things such that this should be an equality test rather than a startswith() test?
There was a problem hiding this comment.
This is because of the schedule ... lines. Because the name of the schedule is not known beforehand, it is not possible to find an exact match. At first, I set each key to be just "schedule" without the name, but in that case make_nested_dict() will only store the last schedule line.
| } | ||
| search_fields = ["schedule", "pulse_entry:"] | ||
| for search_field in search_fields: | ||
| matches = search_for_match(sch_dict, search_field) |
There was a problem hiding this comment.
search_for_match seems to be designed to return a list, but this method seems to assume that only value will be found. Is that right?
There was a problem hiding this comment.
Initially I set this up such that the list was essentially a dummy list with only one entry, but this was not correctly capturing all of the entries. The list now contains multiple entries, which are values corresponding to each of the search field keys. The loop also iterates over each of the entries in the list.
Co-authored-by: Paul Wilson <paul.wilson@wisc.edu>
Co-authored-by: Paul Wilson <paul.wilson@wisc.edu>
Co-authored-by: Paul Wilson <paul.wilson@wisc.edu>
Co-authored-by: Paul Wilson <paul.wilson@wisc.edu>
change order of multiplication fix indentation modify logic for counter further modify counter correctly increment counter when pulse_entry is on the same indentation level as schedule combine similar changes into one commit
8694e69 to
76d8f9d
Compare
|
I realized that the counter I had originally wasn't correctly keeping track of pulse entries when they were on the same indentation level as the schedule lines. The new counter should be able to account for those cases. |
gonuke
left a comment
There was a problem hiding this comment.
I think make_nested_dict is more complicated than necessary- see my comments
| unit_multipliers = make_unit_multipliers() | ||
| while not lines[line_idx].startswith("pulse_history:"): # next section of output | ||
| child_level = lines[line_idx].count('\t') | ||
| newline_name = lines[line_idx].strip().split() |
There was a problem hiding this comment.
This variable name doesn't really seem to express what this data is...
| last_upper_indent_level[child_level][f"pulse_entry num_{counter}_in_sched"] = make_pe_sub_dict(newline_name, | ||
| unit_multipliers) | ||
| last_upper_indent_level[child_level + 1] = last_upper_indent_level[child_level][f"pulse_entry num_{counter}_in_sched"] | ||
| counter = counter_dict[child_level] = counter + 1 |
There was a problem hiding this comment.
I don't think you need to set counter here... you never use it before it gets reassigned
| last_upper_indent_level[child_level + 1] = last_upper_indent_level[child_level][newline_name[1].strip("':")] | ||
| line_idx += 1 | ||
| new_child_level = lines[line_idx].count('\t') | ||
| counter = counter_dict[new_child_level] = 1 |
There was a problem hiding this comment.
You don't need counter here... you never use it before it gets reassigned
| last_upper_indent_level[child_level + 1] = last_upper_indent_level[child_level][f'schedule {newline_name[1]}'] | ||
| line_idx += 1 | ||
| new_child_level = lines[line_idx].count('\t') | ||
| counter = counter_dict[new_child_level] = 1 |
There was a problem hiding this comment.
Is this based on the assumption that this will be the first time we encounter this child_level such that we are initializing this counter for the first time? Or are we also resetting this counter under some circumstances?
I think it's the latter, in which case I would do this elsewhere. Also - why not initialize with 0?
| counter_dict = {} | ||
| unit_multipliers = make_unit_multipliers() | ||
| while not lines[line_idx].startswith("pulse_history:"): # next section of output | ||
| child_level = lines[line_idx].count('\t') |
There was a problem hiding this comment.
If my understanding about the counters is correct, you can initialize new counters here by seeing whether a counter already exists at this child_level and initializing one if it doesn't, and then avoid doing it in two places below.
|
To explain the idea behind the counters further...I'm initializing it to 1 instead of 0 so that we can track the order of the pulse entries belonging to a schedule in a way that's perhaps more human readable. There are a few different scenarios where this counter needs to be set/reset. a) The resetting the counter at the 3rd line would mean that the last pulse entry is incorrectly counted as the 1st pulse in the top schedule. This did take some trial and error to figure out, and would probably be a good discussion topic for hacker-within. |
New design structure for nested dictionary in svalinn#240 (svalinn/ALARA)
gonuke
left a comment
There was a problem hiding this comment.
Here is a coordinated set of changes to streamline the algorithm. It is designed to always initialize things correctly rather than have to check later to do that.
- always put a "children" entry in the dictionary when we make it
- initialize
ancestorsrather than wait to find "top_schedule"
Co-authored-by: Paul Wilson <paul.wilson@wisc.edu>
Co-authored-by: Paul Wilson <paul.wilson@wisc.edu>
Co-authored-by: Paul Wilson <paul.wilson@wisc.edu>
Co-authored-by: Paul Wilson <paul.wilson@wisc.edu>
Co-authored-by: Paul Wilson <paul.wilson@wisc.edu>
gonuke
left a comment
There was a problem hiding this comment.
This seems OK now, but still probably a little unusual in the way the parsing is put together.
This script writes the schedule and pulsing history related output to dictionaries so that they can be accessed and manipulated in other scripts. The schedule details are written in a nested dictionary to accommodate sub-schedules.
fixes #220