-
Notifications
You must be signed in to change notification settings - Fork 4
Enhance error notifications #193
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
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #193 +/- ##
==========================================
- Coverage 85.79% 84.25% -1.54%
==========================================
Files 33 33
Lines 1119 1156 +37
==========================================
+ Hits 960 974 +14
- Misses 159 182 +23
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
The tests are failing, so I guess more adjustments are needed? |
It is in draft, and missing any form of tests. Will ping when ready for eyes |
|
@candleindark OK this is ready for eyes now Had to add new notification and new fixture to showcase the lowest level of printout The tests showcase the new printout behavior A follow-up will automatically dump full logs and uncomment those pointers to the file that has full information (I just don't want to overwhelm the CLI window with too much info in any of the cases) |
|
@candleindark Can you take a look at this soon (today or tomorrow)? |
I will do that as well. |
| ) | ||
| console_notification = rich_click.style(text=text, fg="red") | ||
| rich_click.echo(message=console_notification) | ||
| return |
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.
If you return here, what if the len(criticals) > 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.
Errors take priority over criticals. Both will show up in the full logs (next PR)
| "\nBIDS dataset was successfully created, but may not be valid!\n" | ||
| # TODO: "Please review the full notifications report at {run_config.log_file_path}\n\n" | ||
| ) | ||
| console_notification = rich_click.style(text=text, fg="yellow") |
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.
The color coding seems a bit unconventional here. The why coding a message related to critical issues in yellow while coding a message related to error issues in red in line 145.
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.
'yellow' akin to 'warning'
'red' akin to breaking 'error'
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 tend to think critical as more severe than error.
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.
Yes, the naming convention needs a revamp for clarity
| if errors: | ||
| number_of_errors = len(errors) | ||
|
|
||
| top_three = errors[:3] | ||
| number_to_print = len(top_three) | ||
|
|
||
| if console_notification != "" and not silent: | ||
| text = ( | ||
| "\nBIDS dataset was not successfully created!\n" | ||
| f'{_pluralize(n=number_to_print, phrase="An error was", plural="Some errors were")} ' | ||
| "encountered during conversion.\n" | ||
| ) | ||
| if number_to_print > 1 and number_of_errors > 3: | ||
| error_text = "".join(f"\n\t- {error.reason}" for error in top_three) | ||
| text += ( | ||
| f"The first {number_to_print} of {number_of_errors} are shown below:\n\n" | ||
| f"{error_text}\n\n" | ||
| # TODO: "The full log file can be found at {run_config.log_file_path}\n" | ||
| ) | ||
| console_notification = rich_click.style(text=text, fg="red") | ||
| rich_click.echo(message=console_notification) | ||
| return | ||
|
|
||
| not_any_failures = not any(notification.severity == Severity.ERROR for notification in notifications) | ||
| if not_any_failures and not silent: | ||
| text = "\nBIDS dataset was successfully created!\n\n" | ||
| console_notification = rich_click.style(text=text, fg="green") | ||
| if criticals: | ||
| text = ( | ||
| "\nBIDS dataset was successfully created, but may not be valid!\n" | ||
| # TODO: "Please review the full notifications report at {run_config.log_file_path}\n\n" | ||
| ) | ||
| console_notification = rich_click.style(text=text, fg="yellow") | ||
| rich_click.echo(message=console_notification) | ||
| return |
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.
These two if statements seem to assume that errors and criticals can not be both nonempty. I think that's a false assumption.
If no such assumption is made, the intent of the block of code is to ignore any elements in criticals if errors is nonempty. Such arrangement binds the Severity.ERROR to "BIDS dataset was not successfully created" and Severity.CRITICAL to "BIDS dataset was successfully created, but may not be valid" when there is no issue with the severity of Severity.ERROR. This kind of binding that I suggested to avoid in #176 (comment).
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's an order of precedence
If any errors, those and only those take priority as information back to the user
If not any errors but some critical, those are then displayed in a less scary manner
Overall trying to limit the amount of output the CLI can flood in these events
All notifications will be included in the linked log dump, so if user checks that they will know all
| messages += self._internal_messages.copy() | ||
| if self.events is not None: | ||
| messages += self.events.messages | ||
| messages += self.events.messages.copy() | ||
| if self.probe_table is not None: | ||
| messages += self.probe_table.messages | ||
| messages += self.probe_table.messages.copy() | ||
| if self.channel_table is not None: | ||
| messages += self.channel_table.messages | ||
| messages += self.channel_table.messages.copy() | ||
| if self.electrode_table is not None: | ||
| messages += self.electrode_table.messages | ||
| messages += self.electrode_table.messages.copy() |
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.
Why do we need any of these .copy method call at all?
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.
To avoid any potential mutation of upstream attributes
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 see - many of these (but not all) are computed fields so meaningless to copy (though I guess doesn't harm anything either way)
Will do a holistic review in an upcoming standardization of notification handling
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.
The copy method calls are not needed at all in any field, computed or not since the += does not mutate its right operand as demo in the following script.
l1 = [1, 2, 3]
l2 = l1
l3 = [4, 5, 6]
l1 += l3
print(f"l1: {l1}")
print(f"l2: {l2}")
print(f"l3: {l3}")
for idx in range(len(l1)):
l1[idx] += 10
print("=== After modification ===")
print(f"l1: {l1}")
print(f"l2: {l2}") # This shows that l1 has been mutated in place, affecting l2
print(f"l3: {l3}") # l3 remains unchanged, showing right operand of `+=` was not mutatedThere 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 mean mutation of deeper elements (the inspection results themselves are mutable)
Def not an issue with computed fields since no underlying attribute to mutatate (fresh every time)
Haven't verified that a simple list copy also copies the models it contains however, that was simply an assumption on my part
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 mean mutation of deeper elements (the inspection results themselves are mutable)
Def not an issue with computed fields since no underlying attribute to mutatate (fresh every time)
Haven't verified that a simple list copy also copies the models it contains however, that was simply an assumption on my part
If you want copies of the elements with in the lists as well, the copy method calls are not going to do it since the method only does shallow copy. You can look into https://docs.python.org/3/library/copy.html#copy.deepcopy though. Why are you concerned about mutation of InspectionResult objects, aren't they supposed to be "read-only" once they are created? I don't think any code should attempt to modify one once its is created.
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 do think the sanitization does mutate the severity of certain things from higher to lower after sanitization is performed
Might be better ways of doing that in conjunction with frozen models tho
| "sub-fCamk1_ses-fCamk1_200827_sess9_no_raw_data_probes.json", | ||
| "sub-fCamk1_ses-fCamk1_200827_sess9_no_raw_data_probes.tsv", |
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.
😜 That's fun - while debugging the new test case for this PR also fixed a separate issue about faulty skipping of probe metadata
As requested as further enhancement after #176