Pix 49 log skip error in db - #658
Conversation
…ailure_reason() within pixl_dcmd and orthanc-anon calls that func before raising PIXLDiscardError
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #658 +/- ##
==========================================
- Coverage 88.09% 85.25% -2.85%
==========================================
Files 81 77 -4
Lines 3890 3656 -234
==========================================
- Hits 3427 3117 -310
- Misses 463 539 +76 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
HChughtai
left a comment
There was a problem hiding this comment.
Nice, looks like it's almost there. The database aspects all look good, and I've left a bunch of comments that I think are worth sorting.
The only other thing to think about is about updating the system tests so that its tested end-to-end.
(And as mentioned in the meeting earlier this week, let's get @stefpiatek's review too whilst we're getting up to speed)
| update_db_with_skip_failure_reason( | ||
| project_name=project_name, | ||
| study_info=study_info, | ||
| skip_reasons=dict(skipped_instance_counts), | ||
| ) |
There was a problem hiding this comment.
If this fails (e.g due to a db issue), the wrong message gets passed on back to the calling def _anonymise_study_and_upload(
Right now, I think it'll fallback to except DBAPIError as e: which isn't catastrophic but means PixlDiscardError doesn't get raised and the wrong failure reason is recorded and sent via telemetry. Or if another error is raised it could get handled by the except Exception as e: with whatever error gets passed back. That means we lose the info saying "all instances have been skipped" entirely.
So I think worth wrapping in a try-except so that even if the database write has an issue, the current run and metrics aren't affected.
|
|
||
|
|
||
| def _filter_exported_messages( | ||
| def _filter_exported_or_skipped_messages( |
There was a problem hiding this comment.
Good that we're making it clear here that there are now two reasons why a study may not be added to the imaging queue. However, we should propagate that change back up to def populate_queue_and_db( where it currently says logger.info("Filtering out exported images and uploading new ones to the database"), as well as to functions and docstrings in between.
And possibly out of scope for this PR, I think some additional logging about what studies are skipped and why may be useful - e.g. this study was skipped because it was exported already, or has been skipped for x reason. Or in this function just log the overall numbers for each reason.
| PixlSession = sessionmaker(engine) | ||
| with PixlSession() as pixl_session, pixl_session.begin(): | ||
| existing_image = get_unexported_image(project_slug, study_info, pixl_session) | ||
| existing_image.skip_reasons = skip_reasons |
There was a problem hiding this comment.
We should keep in mind for #659 that this is currently set, and then never unset. So when we allow skipped studies to be retried, we should ensure that the column in the database can be cleared.
| assert np.all(compare_clean_region_with_zeros) | ||
|
|
||
|
|
||
| def test_clean_dicom_image_pixels_encapsulates_compressed_pixel_data( |
| # Filtering-level: previously skipped images are not queued again, | ||
| # nor are already-exported images | ||
| assert "234" not in output.accession_number.to_numpy() | ||
| assert "123" not in output.accession_number.to_numpy() |
There was a problem hiding this comment.
This would pass even if "345" was dropped too - e.g. if output was empty and everything was dropped. So worth asserting that the non-skipped case is retained and the length of output is what you expect.
| extract = rows_in_session.query(Extract).one() | ||
| previously_skipped_image = ( | ||
| rows_in_session.query(Image) | ||
| .filter(Image.extract == extract, Image.accession_number == "234") | ||
| .one() | ||
| ) | ||
| skip_reasons = {"DICOM instance discarded as series has too few instances": 3} | ||
| previously_skipped_image.skip_reasons = skip_reasons | ||
| rows_in_session.commit() |
There was a problem hiding this comment.
I think setting up the data here is OK for this test, but if we start having multiple tests that need it (e.g. as part of #659) then we should look at moving this to a fixture that builds on def rows_in_session(db_session) -> Session:
|
|
||
| update_db_with_skip_failure_reason("test-project", study_info, skip_reasons) | ||
|
|
||
| assert recorded_calls == [("test-project", study_info, skip_reasons)] |
There was a problem hiding this comment.
This isn't really testing anything as you're mocking the only function that update_db_with_skip_failure_reason is calling so no database calls are actually getting made. The assertion is just testing that the args are forwarded.
I'm assuming the function was set up like that to follow the existing structure in the code, and the test is here to improve reported coverage? My thoughts are that this test can be removed as you're doing the actual testing in def test_record_skip_reasons_for_study
Description
Fixes #651: Replace
_filter_exported_messageswith_filter_exported_or_skipped_messagesin the CLI.Updated the database model to add skip_reasons column with JSONB and autogenerated alembic migration.
In
orthanc-anon, pass skip_reasons toupdate_db_with_skip_failure_reasonwithinpixl_dcmdwhich then callsrecord_skip_reasons_for_studyinpixl_dcmd_database.py.Added
test_reimport_of_previously_skipped_image,test_update_db_with_skip_failure_reasonandtest_record_skip_reasons_for_studyas well astest_clean_dicom_image_pixels_encapsulates_compressed_pixel_data(to increase code coverage)Type of change
Please delete options accordingly to the description.
Suggested Checklist
mainbranch.squash and merge