start removing lots of print

This commit is contained in:
Ross
2025-06-30 10:39:42 +01:00
parent afa3b0c0ef
commit bc26209f07
14 changed files with 328 additions and 406 deletions
-2
View File
@@ -113,8 +113,6 @@ def get_exam_user_status_cid_user(request, exam_id: int, cid: int):
if not exam.check_user_can_edit(request.user): if not exam.check_user_can_edit(request.user):
raise HttpError(HTTPStatus.UNAUTHORIZED,"Exam author required") raise HttpError(HTTPStatus.UNAUTHORIZED,"Exam author required")
print(exam_id, cid)
return exam.exam_user_status.filter(cid_user_exam__cid_user__cid=cid) return exam.exam_user_status.filter(cid_user_exam__cid_user__cid=cid)
@router.get('/exam/{exam_id}/user_status/{user_id}/user', response=List[ExamStatusSchema]) @router.get('/exam/{exam_id}/user_status/{user_id}/user', response=List[ExamStatusSchema])
-1
View File
@@ -492,7 +492,6 @@ class Exam(ExamBase):
return answer return answer
def get_question_user_user_answer(self, question_index, user): def get_question_user_user_answer(self, question_index, user):
print(user)
question = self.get_question_by_index(question_index) question = self.get_question_by_index(question_index)
answer = UserAnswer.objects.filter(question=question, user=user.pk, exam=self) answer = UserAnswer.objects.filter(question=question, user=user.pk, exam=self)
-2
View File
@@ -194,8 +194,6 @@ def test_exams(db, client):
exam.save() exam.save()
res = client.get(exam_metadata["url"]) res = client.get(exam_metadata["url"])
print("PRE ERRER", exam_metadata["url"])
print(res.content)
assert res.status_code == 404 assert res.status_code == 404
exam.active = True exam.active = True
-17
View File
@@ -646,22 +646,6 @@ class AnatomyQuestionUpdate(UpdateQuestionMixin):
context = self.get_context_data(form=form) context = self.get_context_data(form=form)
#formset = context["answer_formset"] #formset = context["answer_formset"]
return super().form_valid(form) return super().form_valid(form)
## logger.debug(formset.is_valid())
#if formset.is_valid():
# response = super().form_valid(form)
# formset.instance = self.object
# formset.save()
# # restore exam orders
# #for exam in self.object.exams.all():
# # if exam in exam_orders and self.object in exam_orders[exam]:
# # print(exam_orders[exam])
# # exam.exam_questions.set(exam_orders[exam])
# # exam.save()
# return response
#else:
# return super().form_invalid(form)
class QuestionClone(AnatomyQuestionCreateBase): class QuestionClone(AnatomyQuestionCreateBase):
@@ -797,7 +781,6 @@ def question_save_annotation(request, pk):
question = get_object_or_404(AnatomyQuestion, pk=pk) question = get_object_or_404(AnatomyQuestion, pk=pk)
question.image_annotations = request.POST.get("annotation") question.image_annotations = request.POST.get("annotation")
print(question.image_annotations)
question.save() question.save()
data = {"status": "success"} data = {"status": "success"}
+23 -37
View File
@@ -128,15 +128,10 @@ def uncategorised_dicoms(request):
def import_dicoms_helper(request, case_id: int | None = None): def import_dicoms_helper(request, case_id: int | None = None):
# TODO: move this out of the api (would be better with HTMX)
# dicoms = UncategorisedDicom.objects.filter(user=request.user)
if "selection" in request.POST: if "selection" in request.POST:
dicoms = UncategorisedDicom.objects.filter( dicoms = UncategorisedDicom.objects.filter(
series_instance_uid__in=request.POST.getlist("selection") series_instance_uid__in=request.POST.getlist("selection")
) )
else: else:
dicoms = UncategorisedDicom.objects.filter(user=request.user) dicoms = UncategorisedDicom.objects.filter(user=request.user)
@@ -145,33 +140,30 @@ def import_dicoms_helper(request, case_id: int | None = None):
else: else:
order = None order = None
data = defaultdict(list) # Group dicoms by SeriesInstanceUID, but don't keep all tags in memory
for d in dicoms: series_map = {}
for d in dicoms.iterator(): # Use iterator() to avoid loading all at once
tags = d.basic_dicom_tags tags = d.basic_dicom_tags
series_uid = tags["SeriesInstanceUID"]
data[tags["SeriesInstanceUID"]].append((d, tags)) if series_uid not in series_map:
# Get or create Series and related objects as needed
series_list = []
for series_uid in data:
# Hmm probably not a good idea to blinding create a modality...
try: try:
modality = Modality.objects.get(short_code=tags["Modality"]) modality = Modality.objects.get(short_code=tags["Modality"])
except Modality.DoesNotExist: except Modality.DoesNotExist:
modality = Modality.objects.create(short_code=tags["Modality"], modality=tags["Modality"]) modality = Modality.objects.create(short_code=tags["Modality"], modality=tags["Modality"])
series_tags = tags # Save the first tag for this series
tags = data[series_uid][0][1]
try: try:
with transaction.atomic(): with transaction.atomic():
series, created = Series.objects.get_or_create( series, created = Series.objects.get_or_create(
series_instance_uid=tags["SeriesInstanceUID"], series_instance_uid=series_uid,
defaults={ defaults={
"modality": modality, "modality": modality,
"description": tags["SeriesDescription"], "description": tags.get("SeriesDescription", ""),
} }
) )
if created and tags["StudyDescription"]: if created and tags.get("StudyDescription"):
examination, created_exam = Examination.objects.get_or_create( examination, created_exam = Examination.objects.get_or_create(
examination=tags["StudyDescription"] examination=tags["StudyDescription"]
) )
@@ -181,37 +173,33 @@ def import_dicoms_helper(request, case_id: int | None = None):
series.examination = examination series.examination = examination
series.save() series.save()
except IntegrityError: except IntegrityError:
# If a race condition still occurs, fetch the existing series series = Series.objects.get(series_instance_uid=series_uid)
pass
# Add author and case if needed
if 'series' not in locals():
series = Series.objects.get(series_instance_uid=tags["SeriesInstanceUID"])
# We might only want to add the author during creation....
series.author.add(request.user) series.author.add(request.user)
if case_id is not None: if case_id is not None:
case_object = get_object_or_404(Case, pk=case_id) case_object = get_object_or_404(Case, pk=case_id)
try: try:
series.case.add(case_object) series.case.add(case_object)
except IntegrityError: except IntegrityError:
# The relation already exists, safe to ignore
pass pass
for dicom, dicom_tags in data[series_uid]: series_map[series_uid] = series
else:
series = series_map[series_uid]
# Create and save SeriesImage immediately
series_image = SeriesImage( series_image = SeriesImage(
image=dicom.image, image=d.image,
series=series, series=series,
is_dicom=True, is_dicom=True,
image_blake3_hash=dicom.image_blake3_hash, image_blake3_hash=d.image_blake3_hash,
) )
series_image.save() series_image.save()
# dicom.image.delete() d.delete() # Remove UncategorisedDicom immediately
dicom.delete()
# Optionally, re-order series if needed
for series in series_map.values():
match order: match order:
case "order-series-instance-number": case "order-series-instance-number":
series.order_by_dicom("InstanceNumber") series.order_by_dicom("InstanceNumber")
@@ -220,9 +208,7 @@ def import_dicoms_helper(request, case_id: int | None = None):
case _: case _:
pass pass
series_list.append((series, series.get_link())) return [(series, series.get_link()) for series in series_map.values()]
return series_list
@router.post( @router.post(
-10
View File
@@ -84,9 +84,6 @@ class CaseSelect(Select):
def create_option(self, *args, **kwargs): def create_option(self, *args, **kwargs):
option = super().create_option(*args, **kwargs) option = super().create_option(*args, **kwargs)
print(option)
return option return option
def get_context(self, name: str, value, attrs) -> dict[str, Any]: def get_context(self, name: str, value, attrs) -> dict[str, Any]:
@@ -694,7 +691,6 @@ class CidReportAnswerMarkForm(ModelForm):
# #
# def __init__(self, *args, user, **kwargs): # def __init__(self, *args, user, **kwargs):
# super(AddCollectionToCaseForm, self).__init__(*args, **kwargs) # super(AddCollectionToCaseForm, self).__init__(*args, **kwargs)
# print("INIT", args, kwargs)
# #
# if not user.groups.filter(name="atlas_editor").exists(): # if not user.groups.filter(name="atlas_editor").exists():
# queryset = CaseCollection.objects.filter(author__id=user.id) # queryset = CaseCollection.objects.filter(author__id=user.id)
@@ -736,7 +732,6 @@ class AddCollectionToCaseForm(Form):
def __init__(self, *args, user, **kwargs): def __init__(self, *args, user, **kwargs):
super(AddCollectionToCaseForm, self).__init__(*args, **kwargs) super(AddCollectionToCaseForm, self).__init__(*args, **kwargs)
print("INIT", args, kwargs)
if not user.groups.filter(name="atlas_editor").exists(): if not user.groups.filter(name="atlas_editor").exists():
queryset = CaseCollection.objects.filter(author__id=user.id) queryset = CaseCollection.objects.filter(author__id=user.id)
@@ -752,21 +747,16 @@ class AddCollectionToCaseForm(Form):
) )
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
print("SAVE", args, kwargs)
instance = super(AddCollectionToCaseForm, self).save(*args, **kwargs) instance = super(AddCollectionToCaseForm, self).save(*args, **kwargs)
# Here we save the modified project selection back into the database # Here we save the modified project selection back into the database
instance.casecollection_set.set(self.cleaned_data['casecollection']) instance.casecollection_set.set(self.cleaned_data['casecollection'])
print(f"{instance=}")
return instance return instance
def clean_casecollection(self): def clean_casecollection(self):
collection_set = self.cleaned_data["casecollection"] collection_set = self.cleaned_data["casecollection"]
print(f"{collection_set=}")
for col in collection_set: for col in collection_set:
if col not in self.valid_collections: if col not in self.valid_collections:
raise ValidationError("Invalid collection") raise ValidationError("Invalid collection")
-10
View File
@@ -1215,10 +1215,7 @@ class BaseReportAnswer(models.Model):
if self.question.question_schema is None or not "properties" in self.question.question_schema: if self.question.question_schema is None or not "properties" in self.question.question_schema:
return [] return []
answers = [] answers = []
print("1", self.json_answer)
print("2", self.question.question_answers)
for name, value in self.question.question_schema["properties"].items(): for name, value in self.question.question_schema["properties"].items():
print(name, value)
try: try:
user_answer = self.json_answer[name] user_answer = self.json_answer[name]
@@ -1229,11 +1226,8 @@ class BaseReportAnswer(models.Model):
except KeyError: # If the schema has changed? except KeyError: # If the schema has changed?
correct_answer = "" correct_answer = ""
print(correct_answer)
match value: match value:
case {"type": "string", "enum": _}: case {"type": "string", "enum": _}:
print("YES", value)
automark = True automark = True
answer_is_correct = user_answer == correct_answer answer_is_correct = user_answer == correct_answer
case {"type": "string"}: case {"type": "string"}:
@@ -1366,8 +1360,6 @@ class UncategorisedDicom(models.Model):
# duplicate = obj # duplicate = obj
return obj return obj
print(image_hash)
if obj := SeriesImage.objects.filter(image_blake3_hash=image_hash).first(): if obj := SeriesImage.objects.filter(image_blake3_hash=image_hash).first():
duplicate = obj duplicate = obj
@@ -1409,8 +1401,6 @@ class UncategorisedDicom(models.Model):
ds = pydicom.dcmread(self.image) ds = pydicom.dcmread(self.image)
return ds return ds
except pydicom.errors.InvalidDicomError: except pydicom.errors.InvalidDicomError:
print("Error getting dicom dataset")
print(self.image)
return {"SeriesInstanceUID": "1234"} return {"SeriesInstanceUID": "1234"}
def get_basic_dicom_tags(self, dataset=None): def get_basic_dicom_tags(self, dataset=None):
-5
View File
@@ -196,11 +196,6 @@ class PopupLinkColumn(tables.Column):
return obj.get_thumbnail()[0] return obj.get_thumbnail()[0]
def create_link(test):
print(test)
return "Hello"
class SeriesTable(tables.Table): class SeriesTable(tables.Table):
edit = tables.LinkColumn( edit = tables.LinkColumn(
"atlas:series_update", text="Edit", args=[A("pk")], orderable=False "atlas:series_update", text="Edit", args=[A("pk")], orderable=False
+35 -33
View File
@@ -69,12 +69,12 @@
title="Deleted selected uploads" title="Deleted selected uploads"
>Delete Uploads</button> >Delete Uploads</button>
<button id="import-dicoms-sequential-button" <button id="import-dicoms-sequential-button"
type="button" type="button"
class="btn btn-primary" class="btn btn-primary"
>Import {% if case %}into case{% endif %} (one at a time)</button> >Import {% if case %}into case{% endif %} (one at a time)</button>
<div id="import-status"></div> <div id="import-status"></div>
<div class="indicator"><div class="loader"></div>Loading...</div> <div class="indicator"><div class="loader"></div>Loading...</div>
<div id="import-status"></div> <div id="import-status"></div>
@@ -89,8 +89,10 @@
<p><a href="{% url 'atlas:series_view' %}?case=null&sort=-modified_date">View orphan series</a></p> <p><a href="{% url 'atlas:series_view' %}?case=null&sort=-modified_date">View orphan series</a></p>
<script> <script>
document.getElementById('import-dicoms-sequential-button').addEventListener('click', async function() { const importButton = document.getElementById('import-dicoms-sequential-button');
if (importButton) {
document.getElementById('import-dicoms-sequential-button').addEventListener('click', async function() {
const checkboxes = Array.from(document.querySelectorAll('input[name="selection"]:checked')); const checkboxes = Array.from(document.querySelectorAll('input[name="selection"]:checked'));
const allCheckboxes = Array.from(document.querySelectorAll('input[name="selection"]')); const allCheckboxes = Array.from(document.querySelectorAll('input[name="selection"]'));
// Only include checkboxes that are not disabled (i.e., not already imported) // Only include checkboxes that are not disabled (i.e., not already imported)
@@ -152,29 +154,30 @@ document.getElementById('import-dicoms-sequential-button').addEventListener('cli
} }
} }
statusDiv.innerHTML += "<div>All done.</div>"; statusDiv.innerHTML += "<div>All done.</div>";
}); });
</script> }
</script>
{% endblock %} {% endblock %}
{% block css %} {% block css %}
<style> <style>
.indicator { .indicator {
display: none; display: none;
} }
.indicator.htmx-request { .indicator.htmx-request {
display: block; display: block;
} }
.loader { .loader {
width: 50px; width: 50px;
aspect-ratio: 1; aspect-ratio: 1;
display: grid; display: grid;
} }
.loader::before, .loader::before,
.loader::after { .loader::after {
content:""; content:"";
grid-area: 1/1; grid-area: 1/1;
--c:no-repeat radial-gradient(farthest-side,#25b09b 92%,#0000); --c:no-repeat radial-gradient(farthest-side,#25b09b 92%,#0000);
@@ -185,40 +188,39 @@ document.getElementById('import-dicoms-sequential-button').addEventListener('cli
var(--c) 0 50%; var(--c) 0 50%;
background-size: 12px 12px; background-size: 12px 12px;
animation: l12 1s infinite; animation: l12 1s infinite;
} }
.loader::before { .loader::before {
margin: 4px; margin: 4px;
filter: hue-rotate(45deg); filter: hue-rotate(45deg);
background-size: 8px 8px; background-size: 8px 8px;
animation-timing-function: linear animation-timing-function: linear
} }
@keyframes l12 { @keyframes l12 {
100%{transform: rotate(.5turn)} 100%{transform: rotate(.5turn)}
} }
#series-list { #series-list {
user-select: none; user-select: none;
cursor: pointer; cursor: pointer;
} }
#series-list li { #series-list li {
} }
#series-list .selected { #series-list .selected {
color: white; color: white;
border: 1px solid #52057b; border: 1px solid #52057b;
user-select: none; user-select: none;
margin: -1px; margin: -1px;
} }
.series-block-popup-link { .series-block-popup-link {
float: right; float: right;
} }
#series-list li.imported { #series-list li.imported {
border-color: #e6ffe6; border-color: #e6ffe6;
opacity: 0.7; opacity: 0.7;
} }
</style> </style>
{% endblock css %} {% endblock css %}
-1
View File
@@ -37,7 +37,6 @@ def test_condition_tree_structure(db):
assert len(child2.get_parents()) == 1 assert len(child2.get_parents()) == 1
assert parent in child2.get_parents() assert parent in child2.get_parents()
print(parent.get_descendents())
#@pytest.fixture #@pytest.fixture
#def create_basic_user(db, django_user_model): #def create_basic_user(db, django_user_model):
-7
View File
@@ -568,7 +568,6 @@ class SeriesBase(models.Model):
n = n + 1 n = n + 1
def order_by_dicom(self, field="SliceLocation"): def order_by_dicom(self, field="SliceLocation"):
print(f"Ordering by dicom field {field}")
images = self.images.filter(removed=False) images = self.images.filter(removed=False)
@@ -577,9 +576,6 @@ class SeriesBase(models.Model):
for i in images: for i in images:
files.append((i, pydicom.dcmread(i.image.path))) files.append((i, pydicom.dcmread(i.image.path)))
print("images to order")
print(files)
# print("file count: {}".format(len(files))) # print("file count: {}".format(len(files)))
# skip files with no SliceLocation (eg scout views) # skip files with no SliceLocation (eg scout views)
@@ -594,8 +590,6 @@ class SeriesBase(models.Model):
else: else:
skipcount = skipcount + 1 skipcount = skipcount + 1
print("skipped, no {}: {}".format(field, skipcount))
if not slices: if not slices:
return return
@@ -607,7 +601,6 @@ class SeriesBase(models.Model):
for f in slices: for f in slices:
i = map[f[field].value] i = map[f[field].value]
i.position = n i.position = n
print(f"Setting position {n} for {i}")
i.save() i.save()
n = n + 1 n = n + 1
+1 -11
View File
@@ -93,38 +93,29 @@ def get_dicom_order(path):
files = [] files = []
for fname in glob.glob(path, recursive=False): for fname in glob.glob(path, recursive=False):
print("loading: {}".format(fname))
files.append((fname, pydicom.dcmread(fname))) files.append((fname, pydicom.dcmread(fname)))
print("file count: {}".format(len(files)))
# skip files with no SliceLocation (eg scout views) # skip files with no SliceLocation (eg scout views)
slices = [] slices = []
map = {} map = {}
skipcount = 0 skipcount = 0
for fname, f in files: for fname, f in files:
print(dir(f))
print(fname)
if hasattr(f, 'SliceLocation'): if hasattr(f, 'SliceLocation'):
slices.append(f) slices.append(f)
map[f.SliceLocation] = fname map[f.SliceLocation] = fname
else: else:
skipcount = skipcount + 1 skipcount = skipcount + 1
print("skipped, no SliceLocation: {}".format(skipcount))
# ensure they are in the correct order # ensure they are in the correct order
slices = sorted(slices, key=lambda s: s.SliceLocation) slices = sorted(slices, key=lambda s: s.SliceLocation)
#print(slices) return slices
for i in slices:
print(map[i.SliceLocation])
#get_dicom_order("/home/ross/Downloads/DICOM HEAD/STD4/SER1/*.dcm") #get_dicom_order("/home/ross/Downloads/DICOM HEAD/STD4/SER1/*.dcm")
def pretty_print_dicom(dataset, indent=0): def pretty_print_dicom(dataset, indent=0):
l = print_dicom(dataset, indent) l = print_dicom(dataset, indent)
print(l)
return "".join(l) return "".join(l)
@@ -183,7 +174,6 @@ def get_image_dicom_hash(img, dataset=None, hash_type="md5", direct_pixel_data=T
hasher.update(dataset.PixelData) hasher.update(dataset.PixelData)
except AttributeError as e: except AttributeError as e:
print("Error getting pixel data hash from dataset") print("Error getting pixel data hash from dataset")
print(dataset)
raise InvalidDicomError("Error getting pixel data hash from dataset") raise InvalidDicomError("Error getting pixel data hash from dataset")
else: else:
-1
View File
@@ -11,7 +11,6 @@ if __name__ == "__main__":
if os.environ.get('RUN_MAIN'): if os.environ.get('RUN_MAIN'):
if settings.DEBUG_CONTAINER: if settings.DEBUG_CONTAINER:
import debugpy import debugpy
print("DEBUG LISTEN")
debugpy.listen(("0.0.0.0", 3459)) debugpy.listen(("0.0.0.0", 3459))
try: try:
+146 -146
View File
File diff suppressed because one or more lines are too long