Skip to content

Conversation

@CodyCBakerPhD
Copy link
Collaborator

As requested as further enhancement after #176

@CodyCBakerPhD CodyCBakerPhD self-assigned this Nov 18, 2025
@CodyCBakerPhD CodyCBakerPhD added the enhancement New feature or request label Nov 18, 2025
Base automatically changed from fix_label_notification to main November 19, 2025 19:17
@codecov
Copy link

codecov bot commented Nov 19, 2025

Codecov Report

❌ Patch coverage is 28.00000% with 36 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.25%. Comparing base (8db95f4) to head (1fec0f7).
⚠️ Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
src/nwb2bids/_command_line_interface/_main.py 0.00% 33 Missing ⚠️
src/nwb2bids/_tools/_pluralize.py 0.00% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            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     
Flag Coverage Δ
unittests 84.25% <28.00%> (-1.54%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/nwb2bids/bids_models/_bids_session_metadata.py 92.77% <100.00%> (ø)
src/nwb2bids/bids_models/_probes.py 100.00% <100.00%> (ø)
src/nwb2bids/_tools/_pluralize.py 0.00% <0.00%> (ø)
src/nwb2bids/_command_line_interface/_main.py 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@candleindark
Copy link
Contributor

The tests are failing, so I guess more adjustments are needed?

@CodyCBakerPhD
Copy link
Collaborator Author

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

@CodyCBakerPhD CodyCBakerPhD marked this pull request as ready for review November 26, 2025 19:10
@CodyCBakerPhD
Copy link
Collaborator Author

@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)

@CodyCBakerPhD CodyCBakerPhD added the minor Increment the minor version when merged label Dec 1, 2025
@CodyCBakerPhD
Copy link
Collaborator Author

@candleindark Can you take a look at this soon (today or tomorrow)?

@candleindark
Copy link
Contributor

@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
Copy link
Contributor

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?

Copy link
Collaborator Author

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")
Copy link
Contributor

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.

Copy link
Collaborator Author

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'

Copy link
Contributor

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.

Copy link
Collaborator Author

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

Comment on lines 127 to 156
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
Copy link
Contributor

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).

Copy link
Collaborator Author

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

Comment on lines 38 to 46
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()
Copy link
Contributor

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?

Copy link
Collaborator Author

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

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 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

Copy link
Contributor

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 mutated

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 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

Copy link
Contributor

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.

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 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

Comment on lines +125 to +126
"sub-fCamk1_ses-fCamk1_200827_sess9_no_raw_data_probes.json",
"sub-fCamk1_ses-fCamk1_200827_sess9_no_raw_data_probes.tsv",
Copy link
Collaborator Author

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

@CodyCBakerPhD CodyCBakerPhD merged commit f5cc02c into main Dec 7, 2025
27 checks passed
@CodyCBakerPhD CodyCBakerPhD deleted the enhance_error_notifications branch December 7, 2025 18:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request minor Increment the minor version when merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants