Skip to content

Commit 652cef3

Browse files
Refactoring FOBT + Surveillance regression tests
Refactoring Investigation dataset ui app to accomodate new changes Refactoring Subject assertion to givebetter error messages Fixing incossistend KIT logging
1 parent c07e405 commit 652cef3

21 files changed

+2114
-1223
lines changed

classes/repositories/kit_service_management_repository.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import logging
2-
from typing import Optional
2+
from typing import Optional, Any
33
from utils.oracle.oracle import OracleDB
44
from classes.kits.kit_service_management_record import KitServiceManagementRecord
55
from classes.entities.kit_service_management_entity import KitServiceManagementEntity
6+
import numpy as np
7+
from decimal import Decimal
68

79

810
class KitServiceManagementRepository:
@@ -284,6 +286,22 @@ def update_kit_service_management_entity(
284286
if entity.put_attempts is not None:
285287
params["put_attempts"] = entity.put_attempts
286288

289+
params = {k: _sanitize_param(v) for k, v in params.items()}
287290
self.oracle_db.update_or_insert_data_to_table(sql_query, params)
288291
except Exception as ex:
289292
raise RuntimeError(f"Error updating KIT_QUEUE record: {ex}")
293+
294+
295+
def _sanitize_param(val: Any) -> Any:
296+
"""
297+
Sanitizes a parameter value for database operations.
298+
Args:
299+
val: The parameter value to sanitize.
300+
Returns:
301+
The sanitized parameter value.
302+
"""
303+
if isinstance(val, np.generic):
304+
return val.item()
305+
if isinstance(val, Decimal):
306+
return float(val)
307+
return val

docs/InvestigationDatasetBuilderApplication.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ Examples include `"yes_no"` and `"therapeutic_diagnostic"`, which are handled as
329329

330330
1. Choose a unique string for `"type"` (e.g., `"yes_no"`, `"therapeutic_diagnostic"`).
331331
2. In your JSON field definition, set `"type"` to this string.
332-
3. Ensure your `render_field` function in `investigation_dataset_ui.py` has a case for your custom type, rendering the appropriate widget (usually a dropdown/selectbox).
332+
3. Ensure your `render_field` function in `investigation_dataset_ui.py` has a case for your custom type, rendering the appropriate widget (dropdown, radio, etc.).
333333
- For `"yes_no"`, the UI will show a dropdown with "yes" and "no".
334334
- For `"therapeutic_diagnostic"`, the UI will show a dropdown with "therapeutic" and "diagnostic".
335335
4. You can add more custom types by extending the `render_field` function with new cases in the `match-case` or `if` dispatch.

investigation_dataset_ui.py

Lines changed: 88 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,23 @@ def show_section_with_imports(section_name: str) -> None:
546546
)
547547
else:
548548
import_block = ""
549-
st.code(f"{import_block}{section_name} = {pretty_dict(result)}", language="python")
549+
# Map section to correct fill method
550+
fill_methods = {
551+
"general_information": "fill_out_general_information",
552+
"drug_information": "fill_out_drug_information",
553+
"endoscopy_information": "fill_endoscopy_information",
554+
"completion_information": "fill_out_completion_information",
555+
"failure_information": "fill_out_failure_information",
556+
"radiology_information": "fill_out_radiology_information",
557+
"suspected_findings": "fill_out_suspected_findings",
558+
}
559+
method = fill_methods.get(section_name, f"fill_{section_name}")
560+
st.code(
561+
f"InvestigationDatasetCompletion(page).{method}({pretty_dict(result)})",
562+
language="python",
563+
)
564+
if import_block:
565+
st.code(import_block, language="python")
550566

551567

552568
def show_drug_group_section_with_imports(section_name: str) -> None:
@@ -569,14 +585,28 @@ def show_drug_group_section_with_imports(section_name: str) -> None:
569585
all_fields.extend(group["fields"])
570586
_render_drug_group(section_name, group, result)
571587

588+
# No special merging; each section is handled independently
589+
572590
enums = get_enums_used(all_fields)
573591
if enums:
574592
import_block = (
575593
enum_import_string + new_indented_line_string.join(sorted(enums)) + "\n)\n"
576594
)
577595
else:
578596
import_block = ""
579-
st.code(f"{import_block}{section_name} = {pretty_dict(result)}", language="python")
597+
# Map section to correct fill method
598+
fill_methods = {
599+
"drug_information": "fill_out_drug_information",
600+
"contrast_tagging_and_drug": "fill_out_contrast_tagging_and_drug_information",
601+
"tagging_agent_given_drug_information": "fill_out_tagging_agent_given_drug_information",
602+
}
603+
method = fill_methods.get(section_name, f"fill_{section_name}")
604+
st.code(
605+
f"InvestigationDatasetCompletion(page).{method}({pretty_dict(result)})",
606+
language="python",
607+
)
608+
if import_block:
609+
st.code(import_block, language="python")
580610

581611

582612
def _render_single_entry_fields(fields: list, result: dict) -> None:
@@ -662,29 +692,63 @@ def show_polyp_information_and_intervention_and_histology() -> None:
662692
num_polyps = st.number_input(
663693
"Number of polyps", min_value=0, max_value=20, value=1, step=1
664694
)
665-
polyp_information = []
666-
polyp_intervention = []
667-
polyp_histology = []
695+
polyp_info_dicts = {}
696+
polyp_histology_dicts = {}
697+
polyp_interventions_dicts = {}
668698

669699
for pi in range(1, num_polyps + 1):
670700
st.markdown(f"### Polyp {pi}")
671-
polyp_information.append(_render_polyp_info(polyp_info_fields, pi))
672-
polyp_intervention.append(_render_interventions(polyp_intervention_fields, pi))
673-
polyp_histology.append(_render_histology(polyp_histology_fields, pi))
701+
polyp_info = _render_polyp_info(polyp_info_fields, pi)
702+
polyp_info_dicts[pi] = polyp_info
703+
interventions = _render_interventions(polyp_intervention_fields, pi)
704+
# If interventions is a list of length 1, store as dict, else as list
705+
if isinstance(interventions, list) and len(interventions) == 1:
706+
polyp_interventions_dicts[pi] = interventions[0]
707+
else:
708+
polyp_interventions_dicts[pi] = interventions
709+
polyp_histology = _render_histology(polyp_histology_fields, pi)
710+
polyp_histology_dicts[pi] = polyp_histology
674711

675712
st.markdown("#### Output")
676-
st.code(
677-
f"{import_block}polyp_information = {pretty_list(polyp_information)}",
678-
language="python",
679-
)
680-
st.code(
681-
f"polyp_intervention = {pretty_list(polyp_intervention)}",
682-
language="python",
683-
)
684-
st.code(
685-
f"polyp_histology = {pretty_list(polyp_histology)}",
686-
language="python",
687-
)
713+
output_blocks = []
714+
for pi in range(1, num_polyps + 1):
715+
info_dict = polyp_info_dicts[pi]
716+
hist_dict = polyp_histology_dicts[pi]
717+
intervention = polyp_interventions_dicts[pi]
718+
code_lines = []
719+
# Information
720+
code_lines.append(
721+
f"InvestigationDatasetCompletion(page).fill_polyp_x_information({pretty_dict(info_dict)}, {pi})"
722+
)
723+
# Intervention
724+
if isinstance(intervention, list):
725+
if len(intervention) > 1:
726+
code_lines.append(
727+
f"InvestigationDatasetCompletion(page).fill_polyp_x_multiple_interventions({pretty_list(intervention)}, {pi})"
728+
)
729+
elif len(intervention) == 1 and isinstance(intervention[0], dict):
730+
code_lines.append(
731+
f"InvestigationDatasetCompletion(page).fill_polyp_x_intervention({pretty_dict(intervention[0])}, {pi})"
732+
)
733+
else:
734+
code_lines.append(f"# No intervention for polyp {pi}")
735+
elif isinstance(intervention, dict):
736+
code_lines.append(
737+
f"InvestigationDatasetCompletion(page).fill_polyp_x_intervention({pretty_dict(intervention)}, {pi})"
738+
)
739+
else:
740+
code_lines.append(f"# No intervention for polyp {pi}")
741+
# Histology
742+
if not hist_dict:
743+
code_lines.append(f"# No histology for polyp {pi}")
744+
else:
745+
code_lines.append(
746+
f"InvestigationDatasetCompletion(page).fill_polyp_x_histology({pretty_dict(hist_dict)}, {pi})"
747+
)
748+
output_blocks.append("\n".join(code_lines))
749+
st.code("\n".join(code_lines), language="python")
750+
if import_block:
751+
st.code(import_block, language="python")
688752

689753

690754
def _render_polyp_info(fields: list, pi: int) -> dict:
@@ -718,7 +782,7 @@ def _render_interventions(fields: list, pi: int) -> list:
718782
f"Add interventions for polyp {pi}?", key=f"add_interventions_{pi}"
719783
)
720784
if not add_interventions:
721-
return interventions
785+
return []
722786
num_int = st.number_input(
723787
f"Number of interventions for polyp {pi}",
724788
min_value=0,
@@ -735,6 +799,8 @@ def _render_interventions(fields: list, pi: int) -> list:
735799
if val is not None:
736800
int_dict[field["key"]] = val
737801
interventions.append(int_dict)
802+
if len(interventions) == 1:
803+
return interventions[0]
738804
return interventions
739805

740806

@@ -799,7 +865,7 @@ def _render_histology(fields: list, pi: int) -> dict:
799865
"endoscopy_information": show_section_with_imports,
800866
"completion_information": show_section_with_imports,
801867
"failure_information": show_section_with_imports,
802-
"polyp_information_and_intervention_and_histology": lambda _: show_polyp_information_and_intervention_and_histology(), # If you want imports here, update similarly
868+
"polyp_information_and_intervention_and_histology": lambda _: show_polyp_information_and_intervention_and_histology(),
803869
"contrast_tagging_and_drug": show_drug_group_section_with_imports,
804870
"tagging_agent_given_drug_information": show_drug_group_section_with_imports,
805871
"radiology_information": show_section_with_imports,

pages/contacts_list/maintain_contacts_page.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,14 @@ def click_person_link_from_forename(self, forename: str) -> None:
6565
forename (str): The forename of the subject
6666
"""
6767
self.click(self.page.get_by_role("link", name=forename).last)
68+
69+
def select_person_by_id(self, person_id: int) -> None:
70+
"""
71+
Selects a person by their unique person ID by clicking the corresponding link.
72+
Requires a search to have been conducted and returned at least one result.
73+
Args:
74+
person_id (int): The unique ID of the person to select
75+
"""
76+
href_selector = f"a[href*='{person_id}']"
77+
person_link = self.page.locator(href_selector).first
78+
self.click(person_link)

pages/datasets/investigation_dataset_page.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ def click_save_dataset_button(self) -> None:
419419
It clicks on the save dataset button.
420420
"""
421421
self.safe_accept_dialog(self.save_dataset_button)
422+
self.page.wait_for_timeout(3000) # 3 second timeout to allow page to update
422423

423424
def click_save_dataset_button_assert_dialog(self, expected_text: str) -> None:
424425
"""
@@ -427,7 +428,7 @@ def click_save_dataset_button_assert_dialog(self, expected_text: str) -> None:
427428
Args:
428429
expected_text (str): The expected text in the resultant dialog
429430
"""
430-
self.assert_dialog_text("High-risk findings")
431+
self.assert_dialog_text(expected_text)
431432
self.click(self.save_dataset_button)
432433

433434
def expect_text_to_be_visible(self, text: str) -> None:

0 commit comments

Comments
 (0)